1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/quic/quic_headers_stream.h"
7 #include "net/quic/quic_utils.h"
8 #include "net/quic/spdy_utils.h"
9 #include "net/quic/test_tools/quic_connection_peer.h"
10 #include "net/quic/test_tools/quic_session_peer.h"
11 #include "net/quic/test_tools/quic_test_utils.h"
12 #include "net/quic/test_tools/reliable_quic_stream_peer.h"
13 #include "net/spdy/spdy_protocol.h"
14 #include "testing/gtest/include/gtest/gtest.h"
16 using base::StringPiece
;
18 using testing::Invoke
;
19 using testing::StrictMock
;
20 using testing::WithArgs
;
27 class MockVisitor
: public SpdyFramerVisitorInterface
{
29 MOCK_METHOD1(OnError
, void(SpdyFramer
* framer
));
30 MOCK_METHOD3(OnDataFrameHeader
, void(SpdyStreamId stream_id
,
33 MOCK_METHOD4(OnStreamFrameData
, void(SpdyStreamId stream_id
,
37 MOCK_METHOD3(OnControlFrameHeaderData
, bool(SpdyStreamId stream_id
,
38 const char* header_data
,
40 MOCK_METHOD5(OnSynStream
, void(SpdyStreamId stream_id
,
41 SpdyStreamId associated_stream_id
,
42 SpdyPriority priority
,
44 bool unidirectional
));
45 MOCK_METHOD2(OnSynReply
, void(SpdyStreamId stream_id
, bool fin
));
46 MOCK_METHOD2(OnRstStream
, void(SpdyStreamId stream_id
,
47 SpdyRstStreamStatus status
));
48 MOCK_METHOD1(OnSettings
, void(bool clear_persisted
));
49 MOCK_METHOD3(OnSetting
, void(SpdySettingsIds id
, uint8 flags
, uint32 value
));
50 MOCK_METHOD0(OnSettingsAck
, void());
51 MOCK_METHOD0(OnSettingsEnd
, void());
52 MOCK_METHOD2(OnPing
, void(SpdyPingId unique_id
, bool is_ack
));
53 MOCK_METHOD2(OnGoAway
, void(SpdyStreamId last_accepted_stream_id
,
54 SpdyGoAwayStatus status
));
55 MOCK_METHOD3(OnHeaders
, void(SpdyStreamId stream_id
, bool fin
, bool end
));
56 MOCK_METHOD2(OnWindowUpdate
, void(SpdyStreamId stream_id
,
57 uint32 delta_window_size
));
58 MOCK_METHOD2(OnCredentialFrameData
, bool(const char* credential_data
,
60 MOCK_METHOD1(OnBlocked
, void(SpdyStreamId stream_id
));
61 MOCK_METHOD3(OnPushPromise
, void(SpdyStreamId stream_id
,
62 SpdyStreamId promised_stream_id
,
64 MOCK_METHOD2(OnContinuation
, void(SpdyStreamId stream_id
, bool end
));
65 MOCK_METHOD6(OnAltSvc
, void(SpdyStreamId stream_id
,
68 StringPiece protocol_id
,
71 MOCK_METHOD2(OnUnknownFrame
, bool(SpdyStreamId stream_id
, int frame_type
));
74 class QuicHeadersStreamTest
: public ::testing::TestWithParam
<bool> {
76 static QuicVersionVector
GetVersions() {
77 QuicVersionVector versions
;
78 versions
.push_back(QuicVersionMax());
82 QuicHeadersStreamTest()
83 : connection_(new StrictMock
<MockConnection
>(is_server(), GetVersions())),
84 session_(connection_
),
85 headers_stream_(QuicSessionPeer::GetHeadersStream(&session_
)),
88 headers_
[":version"] = "HTTP/1.1";
89 headers_
[":status"] = "200 Ok";
90 headers_
["content-length"] = "11";
91 framer_
.set_visitor(&visitor_
);
92 EXPECT_EQ(QuicVersionMax(), session_
.connection()->version());
93 EXPECT_TRUE(headers_stream_
!= NULL
);
96 QuicConsumedData
SaveIov(const IOVector
& data
) {
97 const iovec
* iov
= data
.iovec();
98 int count
= data
.Capacity();
99 for (int i
= 0 ; i
< count
; ++i
) {
100 saved_data_
.append(static_cast<char*>(iov
[i
].iov_base
), iov
[i
].iov_len
);
102 return QuicConsumedData(saved_data_
.length(), false);
105 bool SaveHeaderData(const char* data
, int len
) {
106 saved_header_data_
.append(data
, len
);
110 void SaveHeaderDataStringPiece(StringPiece data
) {
111 saved_header_data_
.append(data
.data(), data
.length());
114 void WriteHeadersAndExpectSynStream(QuicStreamId stream_id
,
116 QuicPriority priority
) {
117 WriteHeadersAndCheckData(stream_id
, fin
, priority
, SYN_STREAM
);
120 void WriteHeadersAndExpectSynReply(QuicStreamId stream_id
,
122 WriteHeadersAndCheckData(stream_id
, fin
, 0, SYN_REPLY
);
125 void WriteHeadersAndCheckData(QuicStreamId stream_id
,
127 QuicPriority priority
,
128 SpdyFrameType type
) {
129 // Write the headers and capture the outgoing data
130 EXPECT_CALL(session_
, WritevData(kHeadersStreamId
, _
, _
, false, _
, NULL
))
131 .WillOnce(WithArgs
<1>(Invoke(this, &QuicHeadersStreamTest::SaveIov
)));
132 headers_stream_
->WriteHeaders(stream_id
, headers_
, fin
, NULL
);
134 // Parse the outgoing data and check that it matches was was written.
135 if (type
== SYN_STREAM
) {
136 EXPECT_CALL(visitor_
, OnSynStream(stream_id
, kNoAssociatedStream
, 0,
138 fin
, kNotUnidirectional
));
140 EXPECT_CALL(visitor_
, OnSynReply(stream_id
, fin
));
142 EXPECT_CALL(visitor_
, OnControlFrameHeaderData(stream_id
, _
, _
))
143 .WillRepeatedly(WithArgs
<1, 2>(
144 Invoke(this, &QuicHeadersStreamTest::SaveHeaderData
)));
146 EXPECT_CALL(visitor_
, OnStreamFrameData(stream_id
, NULL
, 0, true));
148 framer_
.ProcessInput(saved_data_
.data(), saved_data_
.length());
149 EXPECT_FALSE(framer_
.HasError()) << framer_
.error_code();
155 void CheckHeaders() {
156 SpdyHeaderBlock headers
;
157 EXPECT_EQ(saved_header_data_
.length(),
158 framer_
.ParseHeaderBlockInBuffer(saved_header_data_
.data(),
159 saved_header_data_
.length(),
161 EXPECT_EQ(headers_
, headers
);
162 saved_header_data_
.clear();
169 void CloseConnection() {
170 QuicConnectionPeer::CloseConnection(connection_
);
173 static const bool kNotUnidirectional
= false;
174 static const bool kNoAssociatedStream
= false;
176 StrictMock
<MockConnection
>* connection_
;
177 StrictMock
<MockSession
> session_
;
178 QuicHeadersStream
* headers_stream_
;
179 SpdyHeaderBlock headers_
;
182 string saved_header_data_
;
184 StrictMock
<MockVisitor
> visitor_
;
187 INSTANTIATE_TEST_CASE_P(Tests
, QuicHeadersStreamTest
, testing::Bool());
189 TEST_P(QuicHeadersStreamTest
, StreamId
) {
190 EXPECT_EQ(3u, headers_stream_
->id());
193 TEST_P(QuicHeadersStreamTest
, EffectivePriority
) {
194 EXPECT_EQ(0u, headers_stream_
->EffectivePriority());
197 TEST_P(QuicHeadersStreamTest
, WriteHeaders
) {
198 for (QuicStreamId stream_id
= kClientDataStreamId1
;
199 stream_id
< kClientDataStreamId3
; stream_id
+= 2) {
200 for (int count
= 0; count
< 2; ++count
) {
201 bool fin
= (count
== 0);
203 WriteHeadersAndExpectSynReply(stream_id
, fin
);
205 for (QuicPriority priority
= 0; priority
< 7; ++priority
) {
206 WriteHeadersAndExpectSynStream(stream_id
, fin
, priority
);
213 TEST_P(QuicHeadersStreamTest
, ProcessRawData
) {
214 for (QuicStreamId stream_id
= kClientDataStreamId1
;
215 stream_id
< kClientDataStreamId3
; stream_id
+= 2) {
216 for (int count
= 0; count
< 2; ++count
) {
217 bool fin
= (count
== 0);
218 for (QuicPriority priority
= 0; priority
< 7; ++priority
) {
219 // Replace with "WriteHeadersAndSaveData"
220 scoped_ptr
<SpdySerializedFrame
> frame
;
222 SpdySynStreamIR
syn_stream(stream_id
);
223 syn_stream
.set_name_value_block(headers_
);
224 syn_stream
.set_fin(fin
);
225 frame
.reset(framer_
.SerializeSynStream(syn_stream
));
226 EXPECT_CALL(session_
, OnStreamHeadersPriority(stream_id
, 0));
228 SpdySynReplyIR
syn_reply(stream_id
);
229 syn_reply
.set_name_value_block(headers_
);
230 syn_reply
.set_fin(fin
);
231 frame
.reset(framer_
.SerializeSynReply(syn_reply
));
233 EXPECT_CALL(session_
, OnStreamHeaders(stream_id
, _
))
234 .WillRepeatedly(WithArgs
<1>(
236 &QuicHeadersStreamTest::SaveHeaderDataStringPiece
)));
237 EXPECT_CALL(session_
,
238 OnStreamHeadersComplete(stream_id
, fin
, frame
->size()));
239 headers_stream_
->ProcessRawData(frame
->data(), frame
->size());
247 TEST_P(QuicHeadersStreamTest
, ProcessSpdyDataFrame
) {
248 SpdyDataIR
data(2, "");
249 scoped_ptr
<SpdySerializedFrame
> frame(framer_
.SerializeFrame(data
));
250 EXPECT_CALL(*connection_
,
251 SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA
,
252 "SPDY DATA frame received."))
253 .WillOnce(InvokeWithoutArgs(this,
254 &QuicHeadersStreamTest::CloseConnection
));
255 headers_stream_
->ProcessRawData(frame
->data(), frame
->size());
258 TEST_P(QuicHeadersStreamTest
, ProcessSpdyRstStreamFrame
) {
259 SpdyRstStreamIR
data(2, RST_STREAM_PROTOCOL_ERROR
, "");
260 scoped_ptr
<SpdySerializedFrame
> frame(framer_
.SerializeFrame(data
));
261 EXPECT_CALL(*connection_
,
262 SendConnectionCloseWithDetails(
263 QUIC_INVALID_HEADERS_STREAM_DATA
,
264 "SPDY RST_STREAM frame received."))
265 .WillOnce(InvokeWithoutArgs(this,
266 &QuicHeadersStreamTest::CloseConnection
));
267 headers_stream_
->ProcessRawData(frame
->data(), frame
->size());
270 TEST_P(QuicHeadersStreamTest
, ProcessSpdySettingsFrame
) {
272 data
.AddSetting(SETTINGS_UPLOAD_BANDWIDTH
, true, true, 0);
273 scoped_ptr
<SpdySerializedFrame
> frame(framer_
.SerializeFrame(data
));
274 EXPECT_CALL(*connection_
,
275 SendConnectionCloseWithDetails(
276 QUIC_INVALID_HEADERS_STREAM_DATA
,
277 "SPDY SETTINGS frame received."))
278 .WillOnce(InvokeWithoutArgs(this,
279 &QuicHeadersStreamTest::CloseConnection
));
280 headers_stream_
->ProcessRawData(frame
->data(), frame
->size());
283 TEST_P(QuicHeadersStreamTest
, ProcessSpdyPingFrame
) {
285 scoped_ptr
<SpdySerializedFrame
> frame(framer_
.SerializeFrame(data
));
286 EXPECT_CALL(*connection_
,
287 SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA
,
288 "SPDY PING frame received."))
289 .WillOnce(InvokeWithoutArgs(this,
290 &QuicHeadersStreamTest::CloseConnection
));
291 headers_stream_
->ProcessRawData(frame
->data(), frame
->size());
294 TEST_P(QuicHeadersStreamTest
, ProcessSpdyGoAwayFrame
) {
295 SpdyGoAwayIR
data(1, GOAWAY_PROTOCOL_ERROR
, "go away");
296 scoped_ptr
<SpdySerializedFrame
> frame(framer_
.SerializeFrame(data
));
297 EXPECT_CALL(*connection_
,
298 SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA
,
299 "SPDY GOAWAY frame received."))
300 .WillOnce(InvokeWithoutArgs(this,
301 &QuicHeadersStreamTest::CloseConnection
));
302 headers_stream_
->ProcessRawData(frame
->data(), frame
->size());
305 TEST_P(QuicHeadersStreamTest
, ProcessSpdyHeadersFrame
) {
306 SpdyHeadersIR
data(1);
307 scoped_ptr
<SpdySerializedFrame
> frame(framer_
.SerializeFrame(data
));
308 EXPECT_CALL(*connection_
,
309 SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA
,
310 "SPDY HEADERS frame received."))
311 .WillOnce(InvokeWithoutArgs(this,
312 &QuicHeadersStreamTest::CloseConnection
));
313 headers_stream_
->ProcessRawData(frame
->data(), frame
->size());
316 TEST_P(QuicHeadersStreamTest
, ProcessSpdyWindowUpdateFrame
) {
317 SpdyWindowUpdateIR
data(1, 1);
318 scoped_ptr
<SpdySerializedFrame
> frame(framer_
.SerializeFrame(data
));
319 EXPECT_CALL(*connection_
,
320 SendConnectionCloseWithDetails(
321 QUIC_INVALID_HEADERS_STREAM_DATA
,
322 "SPDY WINDOW_UPDATE frame received."))
323 .WillOnce(InvokeWithoutArgs(this,
324 &QuicHeadersStreamTest::CloseConnection
));
325 headers_stream_
->ProcessRawData(frame
->data(), frame
->size());
328 TEST_P(QuicHeadersStreamTest
, NoConnectionLevelFlowControl
) {
329 if (connection_
->version() <= QUIC_VERSION_20
) {
330 EXPECT_FALSE(headers_stream_
->flow_controller()->IsEnabled());
332 EXPECT_TRUE(headers_stream_
->flow_controller()->IsEnabled());
334 EXPECT_FALSE(ReliableQuicStreamPeer::StreamContributesToConnectionFlowControl(