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
;
20 using testing::Invoke
;
21 using testing::StrictMock
;
22 using testing::WithArgs
;
29 class MockVisitor
: public SpdyFramerVisitorInterface
{
31 MOCK_METHOD1(OnError
, void(SpdyFramer
* framer
));
32 MOCK_METHOD3(OnDataFrameHeader
, void(SpdyStreamId stream_id
,
35 MOCK_METHOD4(OnStreamFrameData
, void(SpdyStreamId stream_id
,
39 MOCK_METHOD3(OnControlFrameHeaderData
, bool(SpdyStreamId stream_id
,
40 const char* header_data
,
42 MOCK_METHOD5(OnSynStream
, void(SpdyStreamId stream_id
,
43 SpdyStreamId associated_stream_id
,
44 SpdyPriority priority
,
46 bool unidirectional
));
47 MOCK_METHOD2(OnSynReply
, void(SpdyStreamId stream_id
, bool fin
));
48 MOCK_METHOD2(OnRstStream
, void(SpdyStreamId stream_id
,
49 SpdyRstStreamStatus status
));
50 MOCK_METHOD1(OnSettings
, void(bool clear_persisted
));
51 MOCK_METHOD3(OnSetting
, void(SpdySettingsIds id
, uint8 flags
, uint32 value
));
52 MOCK_METHOD0(OnSettingsAck
, void());
53 MOCK_METHOD0(OnSettingsEnd
, void());
54 MOCK_METHOD2(OnPing
, void(SpdyPingId unique_id
, bool is_ack
));
55 MOCK_METHOD2(OnGoAway
, void(SpdyStreamId last_accepted_stream_id
,
56 SpdyGoAwayStatus status
));
57 MOCK_METHOD5(OnHeaders
, void(SpdyStreamId stream_id
, bool has_priority
,
58 SpdyPriority priority
, bool fin
, bool end
));
59 MOCK_METHOD2(OnWindowUpdate
, void(SpdyStreamId stream_id
,
60 uint32 delta_window_size
));
61 MOCK_METHOD2(OnCredentialFrameData
, bool(const char* credential_data
,
63 MOCK_METHOD1(OnBlocked
, void(SpdyStreamId stream_id
));
64 MOCK_METHOD3(OnPushPromise
, void(SpdyStreamId stream_id
,
65 SpdyStreamId promised_stream_id
,
67 MOCK_METHOD2(OnContinuation
, void(SpdyStreamId stream_id
, bool end
));
68 MOCK_METHOD6(OnAltSvc
, void(SpdyStreamId stream_id
,
71 StringPiece protocol_id
,
74 MOCK_METHOD2(OnUnknownFrame
, bool(SpdyStreamId stream_id
, int frame_type
));
77 // Run all tests with each version, and client or server
79 TestParams(QuicVersion version
, bool is_server
)
80 : version(version
), is_server(is_server
) {}
82 friend ostream
& operator<<(ostream
& os
, const TestParams
& p
) {
83 os
<< "{ version: " << QuicVersionToString(p
.version
);
84 os
<< ", is_server: " << p
.is_server
<< " }";
92 // Constructs various test permutations.
93 vector
<TestParams
> GetTestParams() {
94 vector
<TestParams
> params
;
95 QuicVersionVector all_supported_versions
= QuicSupportedVersions();
96 for (const QuicVersion version
: all_supported_versions
) {
97 params
.push_back(TestParams(version
, false));
98 params
.push_back(TestParams(version
, true));
103 class QuicHeadersStreamTest
: public ::testing::TestWithParam
<TestParams
> {
105 QuicHeadersStreamTest()
106 : connection_(new StrictMock
<MockConnection
>(is_server(), GetVersion())),
107 session_(connection_
),
108 headers_stream_(QuicSessionPeer::GetHeadersStream(&session_
)),
109 body_("hello world"),
110 framer_(version() > QUIC_VERSION_23
? SPDY4
: SPDY3
) {
111 headers_
[":version"] = "HTTP/1.1";
112 headers_
[":status"] = "200 Ok";
113 headers_
["content-length"] = "11";
114 framer_
.set_visitor(&visitor_
);
115 EXPECT_EQ(version(), session_
.connection()->version());
116 EXPECT_TRUE(headers_stream_
!= nullptr);
117 VLOG(1) << GetParam();
120 QuicConsumedData
SaveIov(const IOVector
& data
) {
121 const iovec
* iov
= data
.iovec();
122 int count
= data
.Capacity();
123 for (int i
= 0 ; i
< count
; ++i
) {
124 saved_data_
.append(static_cast<char*>(iov
[i
].iov_base
), iov
[i
].iov_len
);
126 return QuicConsumedData(saved_data_
.length(), false);
129 bool SaveHeaderData(const char* data
, int len
) {
130 saved_header_data_
.append(data
, len
);
134 void SaveHeaderDataStringPiece(StringPiece data
) {
135 saved_header_data_
.append(data
.data(), data
.length());
138 void WriteHeadersAndExpectSynStream(QuicStreamId stream_id
,
140 QuicPriority priority
) {
141 WriteHeadersAndCheckData(stream_id
, fin
, priority
, SYN_STREAM
);
144 void WriteHeadersAndExpectSynReply(QuicStreamId stream_id
,
146 WriteHeadersAndCheckData(stream_id
, fin
, 0, SYN_REPLY
);
149 void WriteHeadersAndCheckData(QuicStreamId stream_id
,
151 QuicPriority priority
,
152 SpdyFrameType type
) {
153 // Write the headers and capture the outgoing data
154 EXPECT_CALL(session_
, WritevData(kHeadersStreamId
, _
, _
, false, _
, nullptr))
155 .WillOnce(WithArgs
<1>(Invoke(this, &QuicHeadersStreamTest::SaveIov
)));
156 headers_stream_
->WriteHeaders(stream_id
, headers_
, fin
, priority
, nullptr);
158 // Parse the outgoing data and check that it matches was was written.
159 if (type
== SYN_STREAM
) {
160 if (version() > QUIC_VERSION_23
) {
161 EXPECT_CALL(visitor_
, OnHeaders(stream_id
, kHasPriority
, priority
, fin
,
164 EXPECT_CALL(visitor_
,
165 OnSynStream(stream_id
, kNoAssociatedStream
,
166 /*priority=*/0, fin
, kNotUnidirectional
));
169 if (version() > QUIC_VERSION_23
) {
170 EXPECT_CALL(visitor_
, OnHeaders(stream_id
, !kHasPriority
,
171 /*priority=*/0, fin
, kFrameComplete
));
173 EXPECT_CALL(visitor_
, OnSynReply(stream_id
, fin
));
176 EXPECT_CALL(visitor_
, OnControlFrameHeaderData(stream_id
, _
, _
))
177 .WillRepeatedly(WithArgs
<1, 2>(
178 Invoke(this, &QuicHeadersStreamTest::SaveHeaderData
)));
180 EXPECT_CALL(visitor_
, OnStreamFrameData(stream_id
, nullptr, 0, true));
182 framer_
.ProcessInput(saved_data_
.data(), saved_data_
.length());
183 EXPECT_FALSE(framer_
.HasError())
184 << SpdyFramer::ErrorCodeToString(framer_
.error_code());
190 void CheckHeaders() {
191 SpdyHeaderBlock headers
;
192 EXPECT_EQ(saved_header_data_
.length(),
193 framer_
.ParseHeaderBlockInBuffer(saved_header_data_
.data(),
194 saved_header_data_
.length(),
196 EXPECT_EQ(headers_
, headers
);
197 saved_header_data_
.clear();
200 bool is_server() { return GetParam().is_server
; }
202 QuicVersion
version() { return GetParam().version
; }
204 QuicVersionVector
GetVersion() {
205 QuicVersionVector versions
;
206 versions
.push_back(version());
210 void CloseConnection() {
211 QuicConnectionPeer::CloseConnection(connection_
);
214 static const bool kFrameComplete
= true;
215 static const bool kHasPriority
= true;
216 static const bool kNotUnidirectional
= false;
217 static const bool kNoAssociatedStream
= false;
219 StrictMock
<MockConnection
>* connection_
;
220 StrictMock
<MockSession
> session_
;
221 QuicHeadersStream
* headers_stream_
;
222 SpdyHeaderBlock headers_
;
225 string saved_header_data_
;
227 StrictMock
<MockVisitor
> visitor_
;
230 INSTANTIATE_TEST_CASE_P(Tests
,
231 QuicHeadersStreamTest
,
232 ::testing::ValuesIn(GetTestParams()));
234 TEST_P(QuicHeadersStreamTest
, StreamId
) {
235 EXPECT_EQ(3u, headers_stream_
->id());
238 TEST_P(QuicHeadersStreamTest
, EffectivePriority
) {
239 EXPECT_EQ(0u, headers_stream_
->EffectivePriority());
242 TEST_P(QuicHeadersStreamTest
, WriteHeaders
) {
243 for (QuicStreamId stream_id
= kClientDataStreamId1
;
244 stream_id
< kClientDataStreamId3
; stream_id
+= 2) {
245 for (int count
= 0; count
< 2; ++count
) {
246 bool fin
= (count
== 0);
248 WriteHeadersAndExpectSynReply(stream_id
, fin
);
250 for (QuicPriority priority
= 0; priority
< 7; ++priority
) {
251 // TODO(rch): implement priorities correctly.
252 WriteHeadersAndExpectSynStream(stream_id
, fin
, 0);
259 TEST_P(QuicHeadersStreamTest
, ProcessRawData
) {
260 for (QuicStreamId stream_id
= kClientDataStreamId1
;
261 stream_id
< kClientDataStreamId3
; stream_id
+= 2) {
262 for (int count
= 0; count
< 2; ++count
) {
263 bool fin
= (count
== 0);
264 for (QuicPriority priority
= 0; priority
< 7; ++priority
) {
265 // Replace with "WriteHeadersAndSaveData"
266 scoped_ptr
<SpdySerializedFrame
> frame
;
268 if (version() > QUIC_VERSION_23
) {
269 SpdyHeadersIR
headers_frame(stream_id
);
270 headers_frame
.set_name_value_block(headers_
);
271 headers_frame
.set_fin(fin
);
272 headers_frame
.set_has_priority(true);
273 frame
.reset(framer_
.SerializeFrame(headers_frame
));
275 SpdySynStreamIR
syn_stream(stream_id
);
276 syn_stream
.set_name_value_block(headers_
);
277 syn_stream
.set_fin(fin
);
278 frame
.reset(framer_
.SerializeSynStream(syn_stream
));
280 EXPECT_CALL(session_
, OnStreamHeadersPriority(stream_id
, 0));
282 if (version() > QUIC_VERSION_23
) {
283 SpdyHeadersIR
headers_frame(stream_id
);
284 headers_frame
.set_name_value_block(headers_
);
285 headers_frame
.set_fin(fin
);
286 frame
.reset(framer_
.SerializeFrame(headers_frame
));
288 SpdySynReplyIR
syn_reply(stream_id
);
289 syn_reply
.set_name_value_block(headers_
);
290 syn_reply
.set_fin(fin
);
291 frame
.reset(framer_
.SerializeSynReply(syn_reply
));
294 EXPECT_CALL(session_
, OnStreamHeaders(stream_id
, _
))
295 .WillRepeatedly(WithArgs
<1>(
297 &QuicHeadersStreamTest::SaveHeaderDataStringPiece
)));
298 EXPECT_CALL(session_
,
299 OnStreamHeadersComplete(stream_id
, fin
, frame
->size()));
300 headers_stream_
->ProcessRawData(frame
->data(), frame
->size());
307 TEST_P(QuicHeadersStreamTest
, ProcessLargeRawData
) {
308 // We want to create a frame that is more than the SPDY Framer's max control
309 // frame size, which is 16K, but less than the HPACK decoders max decode
310 // buffer size, which is 32K.
311 headers_
["key0"] = string(1 << 13, '.');
312 headers_
["key1"] = string(1 << 13, '.');
313 headers_
["key2"] = string(1 << 13, '.');
314 for (QuicStreamId stream_id
= kClientDataStreamId1
;
315 stream_id
< kClientDataStreamId3
; stream_id
+= 2) {
316 for (int count
= 0; count
< 2; ++count
) {
317 bool fin
= (count
== 0);
318 for (QuicPriority priority
= 0; priority
< 7; ++priority
) {
319 // Replace with "WriteHeadersAndSaveData"
320 scoped_ptr
<SpdySerializedFrame
> frame
;
322 if (version() > QUIC_VERSION_23
) {
323 SpdyHeadersIR
headers_frame(stream_id
);
324 headers_frame
.set_name_value_block(headers_
);
325 headers_frame
.set_fin(fin
);
326 headers_frame
.set_has_priority(true);
327 frame
.reset(framer_
.SerializeFrame(headers_frame
));
329 SpdySynStreamIR
syn_stream(stream_id
);
330 syn_stream
.set_name_value_block(headers_
);
331 syn_stream
.set_fin(fin
);
332 frame
.reset(framer_
.SerializeSynStream(syn_stream
));
334 EXPECT_CALL(session_
, OnStreamHeadersPriority(stream_id
, 0));
336 if (version() > QUIC_VERSION_23
) {
337 SpdyHeadersIR
headers_frame(stream_id
);
338 headers_frame
.set_name_value_block(headers_
);
339 headers_frame
.set_fin(fin
);
340 frame
.reset(framer_
.SerializeFrame(headers_frame
));
342 SpdySynReplyIR
syn_reply(stream_id
);
343 syn_reply
.set_name_value_block(headers_
);
344 syn_reply
.set_fin(fin
);
345 frame
.reset(framer_
.SerializeSynReply(syn_reply
));
348 EXPECT_CALL(session_
, OnStreamHeaders(stream_id
, _
))
349 .WillRepeatedly(WithArgs
<1>(Invoke(
350 this, &QuicHeadersStreamTest::SaveHeaderDataStringPiece
)));
351 EXPECT_CALL(session_
,
352 OnStreamHeadersComplete(stream_id
, fin
, frame
->size()));
353 headers_stream_
->ProcessRawData(frame
->data(), frame
->size());
360 TEST_P(QuicHeadersStreamTest
, ProcessBadData
) {
361 const char kBadData
[] = "blah blah blah";
362 EXPECT_CALL(*connection_
, SendConnectionCloseWithDetails(
363 QUIC_INVALID_HEADERS_STREAM_DATA
, _
))
364 .Times(::testing::AnyNumber());
365 headers_stream_
->ProcessRawData(kBadData
, strlen(kBadData
));
368 TEST_P(QuicHeadersStreamTest
, ProcessSpdyDataFrame
) {
369 SpdyDataIR
data(2, "");
370 scoped_ptr
<SpdySerializedFrame
> frame(framer_
.SerializeFrame(data
));
371 EXPECT_CALL(*connection_
,
372 SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA
,
373 "SPDY DATA frame received."))
374 .WillOnce(InvokeWithoutArgs(this,
375 &QuicHeadersStreamTest::CloseConnection
));
376 headers_stream_
->ProcessRawData(frame
->data(), frame
->size());
379 TEST_P(QuicHeadersStreamTest
, ProcessSpdyRstStreamFrame
) {
380 SpdyRstStreamIR
data(2, RST_STREAM_PROTOCOL_ERROR
, "");
381 scoped_ptr
<SpdySerializedFrame
> frame(framer_
.SerializeFrame(data
));
382 EXPECT_CALL(*connection_
,
383 SendConnectionCloseWithDetails(
384 QUIC_INVALID_HEADERS_STREAM_DATA
,
385 "SPDY RST_STREAM frame received."))
386 .WillOnce(InvokeWithoutArgs(this,
387 &QuicHeadersStreamTest::CloseConnection
));
388 headers_stream_
->ProcessRawData(frame
->data(), frame
->size());
391 TEST_P(QuicHeadersStreamTest
, ProcessSpdySettingsFrame
) {
393 if (version() > QUIC_VERSION_23
) {
394 data
.AddSetting(SETTINGS_HEADER_TABLE_SIZE
, true, true, 0);
396 data
.AddSetting(SETTINGS_UPLOAD_BANDWIDTH
, true, true, 0);
398 scoped_ptr
<SpdySerializedFrame
> frame(framer_
.SerializeFrame(data
));
399 EXPECT_CALL(*connection_
,
400 SendConnectionCloseWithDetails(
401 QUIC_INVALID_HEADERS_STREAM_DATA
,
402 "SPDY SETTINGS frame received."))
403 .WillOnce(InvokeWithoutArgs(this,
404 &QuicHeadersStreamTest::CloseConnection
));
405 headers_stream_
->ProcessRawData(frame
->data(), frame
->size());
408 TEST_P(QuicHeadersStreamTest
, ProcessSpdyPingFrame
) {
410 scoped_ptr
<SpdySerializedFrame
> frame(framer_
.SerializeFrame(data
));
411 EXPECT_CALL(*connection_
,
412 SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA
,
413 "SPDY PING frame received."))
414 .WillOnce(InvokeWithoutArgs(this,
415 &QuicHeadersStreamTest::CloseConnection
));
416 headers_stream_
->ProcessRawData(frame
->data(), frame
->size());
419 TEST_P(QuicHeadersStreamTest
, ProcessSpdyGoAwayFrame
) {
420 SpdyGoAwayIR
data(1, GOAWAY_PROTOCOL_ERROR
, "go away");
421 scoped_ptr
<SpdySerializedFrame
> frame(framer_
.SerializeFrame(data
));
422 EXPECT_CALL(*connection_
,
423 SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA
,
424 "SPDY GOAWAY frame received."))
425 .WillOnce(InvokeWithoutArgs(this,
426 &QuicHeadersStreamTest::CloseConnection
));
427 headers_stream_
->ProcessRawData(frame
->data(), frame
->size());
430 TEST_P(QuicHeadersStreamTest
, ProcessSpdyHeadersFrame
) {
431 if (version() > QUIC_VERSION_23
) {
432 // HEADERS frames are an error when using SPDY/3, but
433 // when using SPDY/4 they're the "normal" way of sending headers
434 // so we test their handling in the ProcessRawData test.
437 SpdyHeadersIR
data(1);
438 scoped_ptr
<SpdySerializedFrame
> frame(framer_
.SerializeFrame(data
));
439 EXPECT_CALL(*connection_
,
440 SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA
,
441 "SPDY HEADERS frame received."))
442 .WillOnce(InvokeWithoutArgs(this,
443 &QuicHeadersStreamTest::CloseConnection
));
444 headers_stream_
->ProcessRawData(frame
->data(), frame
->size());
447 TEST_P(QuicHeadersStreamTest
, ProcessSpdyWindowUpdateFrame
) {
448 SpdyWindowUpdateIR
data(1, 1);
449 scoped_ptr
<SpdySerializedFrame
> frame(framer_
.SerializeFrame(data
));
450 EXPECT_CALL(*connection_
,
451 SendConnectionCloseWithDetails(
452 QUIC_INVALID_HEADERS_STREAM_DATA
,
453 "SPDY WINDOW_UPDATE frame received."))
454 .WillOnce(InvokeWithoutArgs(this,
455 &QuicHeadersStreamTest::CloseConnection
));
456 headers_stream_
->ProcessRawData(frame
->data(), frame
->size());
459 TEST_P(QuicHeadersStreamTest
, NoConnectionLevelFlowControl
) {
460 EXPECT_TRUE(headers_stream_
->flow_controller()->IsEnabled());
461 EXPECT_FALSE(ReliableQuicStreamPeer::StreamContributesToConnectionFlowControl(