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_METHOD2(OnStreamPadding
, void(SpdyStreamId stream_id
, size_t len
));
40 MOCK_METHOD3(OnControlFrameHeaderData
, bool(SpdyStreamId stream_id
,
41 const char* header_data
,
43 MOCK_METHOD5(OnSynStream
, void(SpdyStreamId stream_id
,
44 SpdyStreamId associated_stream_id
,
45 SpdyPriority priority
,
47 bool unidirectional
));
48 MOCK_METHOD2(OnSynReply
, void(SpdyStreamId stream_id
, bool fin
));
49 MOCK_METHOD2(OnRstStream
, void(SpdyStreamId stream_id
,
50 SpdyRstStreamStatus status
));
51 MOCK_METHOD1(OnSettings
, void(bool clear_persisted
));
52 MOCK_METHOD3(OnSetting
, void(SpdySettingsIds id
, uint8 flags
, uint32 value
));
53 MOCK_METHOD0(OnSettingsAck
, void());
54 MOCK_METHOD0(OnSettingsEnd
, void());
55 MOCK_METHOD2(OnPing
, void(SpdyPingId unique_id
, bool is_ack
));
56 MOCK_METHOD2(OnGoAway
, void(SpdyStreamId last_accepted_stream_id
,
57 SpdyGoAwayStatus status
));
58 MOCK_METHOD5(OnHeaders
, void(SpdyStreamId stream_id
, bool has_priority
,
59 SpdyPriority priority
, bool fin
, bool end
));
60 MOCK_METHOD2(OnWindowUpdate
, void(SpdyStreamId stream_id
,
61 uint32 delta_window_size
));
62 MOCK_METHOD2(OnCredentialFrameData
, bool(const char* credential_data
,
64 MOCK_METHOD1(OnBlocked
, void(SpdyStreamId stream_id
));
65 MOCK_METHOD3(OnPushPromise
, void(SpdyStreamId stream_id
,
66 SpdyStreamId promised_stream_id
,
68 MOCK_METHOD2(OnContinuation
, void(SpdyStreamId stream_id
, bool end
));
69 MOCK_METHOD6(OnAltSvc
, void(SpdyStreamId stream_id
,
72 StringPiece protocol_id
,
75 MOCK_METHOD2(OnUnknownFrame
, bool(SpdyStreamId stream_id
, int frame_type
));
78 // Run all tests with each version, and client or server
80 TestParams(QuicVersion version
, Perspective perspective
)
81 : version(version
), perspective(perspective
) {}
83 friend ostream
& operator<<(ostream
& os
, const TestParams
& p
) {
84 os
<< "{ version: " << QuicVersionToString(p
.version
);
85 os
<< ", perspective: " << p
.perspective
<< " }";
90 Perspective perspective
;
93 // Constructs various test permutations.
94 vector
<TestParams
> GetTestParams() {
95 vector
<TestParams
> params
;
96 QuicVersionVector all_supported_versions
= QuicSupportedVersions();
97 for (const QuicVersion version
: all_supported_versions
) {
98 params
.push_back(TestParams(version
, Perspective::IS_CLIENT
));
99 params
.push_back(TestParams(version
, Perspective::IS_SERVER
));
104 class QuicHeadersStreamTest
: public ::testing::TestWithParam
<TestParams
> {
106 QuicHeadersStreamTest()
108 new StrictMock
<MockConnection
>(perspective(), GetVersion())),
109 session_(connection_
),
110 headers_stream_(QuicSessionPeer::GetHeadersStream(&session_
)),
111 body_("hello world"),
112 framer_(version() > QUIC_VERSION_23
? SPDY4
: SPDY3
) {
113 headers_
[":version"] = "HTTP/1.1";
114 headers_
[":status"] = "200 Ok";
115 headers_
["content-length"] = "11";
116 framer_
.set_visitor(&visitor_
);
117 EXPECT_EQ(version(), session_
.connection()->version());
118 EXPECT_TRUE(headers_stream_
!= nullptr);
119 VLOG(1) << GetParam();
122 QuicConsumedData
SaveIov(const IOVector
& data
) {
123 const iovec
* iov
= data
.iovec();
124 int count
= data
.Capacity();
125 for (int i
= 0 ; i
< count
; ++i
) {
126 saved_data_
.append(static_cast<char*>(iov
[i
].iov_base
), iov
[i
].iov_len
);
128 return QuicConsumedData(saved_data_
.length(), false);
131 bool SaveHeaderData(const char* data
, int len
) {
132 saved_header_data_
.append(data
, len
);
136 void SaveHeaderDataStringPiece(StringPiece data
) {
137 saved_header_data_
.append(data
.data(), data
.length());
140 void WriteHeadersAndExpectSynStream(QuicStreamId stream_id
,
142 QuicPriority priority
) {
143 WriteHeadersAndCheckData(stream_id
, fin
, priority
, SYN_STREAM
);
146 void WriteHeadersAndExpectSynReply(QuicStreamId stream_id
,
148 WriteHeadersAndCheckData(stream_id
, fin
, 0, SYN_REPLY
);
151 void WriteHeadersAndCheckData(QuicStreamId stream_id
,
153 QuicPriority priority
,
154 SpdyFrameType type
) {
155 // Write the headers and capture the outgoing data
156 EXPECT_CALL(session_
, WritevData(kHeadersStreamId
, _
, _
, false, _
, nullptr))
157 .WillOnce(WithArgs
<1>(Invoke(this, &QuicHeadersStreamTest::SaveIov
)));
158 headers_stream_
->WriteHeaders(stream_id
, headers_
, fin
, priority
, nullptr);
160 // Parse the outgoing data and check that it matches was was written.
161 if (type
== SYN_STREAM
) {
162 if (version() > QUIC_VERSION_23
) {
163 EXPECT_CALL(visitor_
, OnHeaders(stream_id
, kHasPriority
, priority
, fin
,
166 EXPECT_CALL(visitor_
,
167 OnSynStream(stream_id
, kNoAssociatedStream
,
168 /*priority=*/0, fin
, kNotUnidirectional
));
171 if (version() > QUIC_VERSION_23
) {
172 EXPECT_CALL(visitor_
, OnHeaders(stream_id
, !kHasPriority
,
173 /*priority=*/0, fin
, kFrameComplete
));
175 EXPECT_CALL(visitor_
, OnSynReply(stream_id
, fin
));
178 EXPECT_CALL(visitor_
, OnControlFrameHeaderData(stream_id
, _
, _
))
179 .WillRepeatedly(WithArgs
<1, 2>(
180 Invoke(this, &QuicHeadersStreamTest::SaveHeaderData
)));
182 EXPECT_CALL(visitor_
, OnStreamFrameData(stream_id
, nullptr, 0, true));
184 framer_
.ProcessInput(saved_data_
.data(), saved_data_
.length());
185 EXPECT_FALSE(framer_
.HasError())
186 << SpdyFramer::ErrorCodeToString(framer_
.error_code());
192 void CheckHeaders() {
193 SpdyHeaderBlock headers
;
194 EXPECT_EQ(saved_header_data_
.length(),
195 framer_
.ParseHeaderBlockInBuffer(saved_header_data_
.data(),
196 saved_header_data_
.length(),
198 EXPECT_EQ(headers_
, headers
);
199 saved_header_data_
.clear();
202 Perspective
perspective() { return GetParam().perspective
; }
204 QuicVersion
version() { return GetParam().version
; }
206 QuicVersionVector
GetVersion() {
207 QuicVersionVector versions
;
208 versions
.push_back(version());
212 void CloseConnection() {
213 QuicConnectionPeer::CloseConnection(connection_
);
216 static const bool kFrameComplete
= true;
217 static const bool kHasPriority
= true;
218 static const bool kNotUnidirectional
= false;
219 static const bool kNoAssociatedStream
= false;
221 StrictMock
<MockConnection
>* connection_
;
222 StrictMock
<MockSession
> session_
;
223 QuicHeadersStream
* headers_stream_
;
224 SpdyHeaderBlock headers_
;
227 string saved_header_data_
;
229 StrictMock
<MockVisitor
> visitor_
;
232 INSTANTIATE_TEST_CASE_P(Tests
,
233 QuicHeadersStreamTest
,
234 ::testing::ValuesIn(GetTestParams()));
236 TEST_P(QuicHeadersStreamTest
, StreamId
) {
237 EXPECT_EQ(3u, headers_stream_
->id());
240 TEST_P(QuicHeadersStreamTest
, EffectivePriority
) {
241 EXPECT_EQ(0u, headers_stream_
->EffectivePriority());
244 TEST_P(QuicHeadersStreamTest
, WriteHeaders
) {
245 for (QuicStreamId stream_id
= kClientDataStreamId1
;
246 stream_id
< kClientDataStreamId3
; stream_id
+= 2) {
247 for (int count
= 0; count
< 2; ++count
) {
248 bool fin
= (count
== 0);
249 if (perspective() == Perspective::IS_SERVER
) {
250 WriteHeadersAndExpectSynReply(stream_id
, fin
);
252 for (QuicPriority priority
= 0; priority
< 7; ++priority
) {
253 // TODO(rch): implement priorities correctly.
254 WriteHeadersAndExpectSynStream(stream_id
, fin
, 0);
261 TEST_P(QuicHeadersStreamTest
, ProcessRawData
) {
262 for (QuicStreamId stream_id
= kClientDataStreamId1
;
263 stream_id
< kClientDataStreamId3
; stream_id
+= 2) {
264 for (int count
= 0; count
< 2; ++count
) {
265 bool fin
= (count
== 0);
266 for (QuicPriority priority
= 0; priority
< 7; ++priority
) {
267 // Replace with "WriteHeadersAndSaveData"
268 scoped_ptr
<SpdySerializedFrame
> frame
;
269 if (perspective() == Perspective::IS_SERVER
) {
270 if (version() > QUIC_VERSION_23
) {
271 SpdyHeadersIR
headers_frame(stream_id
);
272 headers_frame
.set_name_value_block(headers_
);
273 headers_frame
.set_fin(fin
);
274 headers_frame
.set_has_priority(true);
275 frame
.reset(framer_
.SerializeFrame(headers_frame
));
277 SpdySynStreamIR
syn_stream(stream_id
);
278 syn_stream
.set_name_value_block(headers_
);
279 syn_stream
.set_fin(fin
);
280 frame
.reset(framer_
.SerializeSynStream(syn_stream
));
282 EXPECT_CALL(session_
, OnStreamHeadersPriority(stream_id
, 0));
284 if (version() > QUIC_VERSION_23
) {
285 SpdyHeadersIR
headers_frame(stream_id
);
286 headers_frame
.set_name_value_block(headers_
);
287 headers_frame
.set_fin(fin
);
288 frame
.reset(framer_
.SerializeFrame(headers_frame
));
290 SpdySynReplyIR
syn_reply(stream_id
);
291 syn_reply
.set_name_value_block(headers_
);
292 syn_reply
.set_fin(fin
);
293 frame
.reset(framer_
.SerializeSynReply(syn_reply
));
296 EXPECT_CALL(session_
, OnStreamHeaders(stream_id
, _
))
297 .WillRepeatedly(WithArgs
<1>(
299 &QuicHeadersStreamTest::SaveHeaderDataStringPiece
)));
300 EXPECT_CALL(session_
,
301 OnStreamHeadersComplete(stream_id
, fin
, frame
->size()));
302 headers_stream_
->ProcessRawData(frame
->data(), frame
->size());
309 TEST_P(QuicHeadersStreamTest
, ProcessLargeRawData
) {
310 // We want to create a frame that is more than the SPDY Framer's max control
311 // frame size, which is 16K, but less than the HPACK decoders max decode
312 // buffer size, which is 32K.
313 headers_
["key0"] = string(1 << 13, '.');
314 headers_
["key1"] = string(1 << 13, '.');
315 headers_
["key2"] = string(1 << 13, '.');
316 for (QuicStreamId stream_id
= kClientDataStreamId1
;
317 stream_id
< kClientDataStreamId3
; stream_id
+= 2) {
318 for (int count
= 0; count
< 2; ++count
) {
319 bool fin
= (count
== 0);
320 for (QuicPriority priority
= 0; priority
< 7; ++priority
) {
321 // Replace with "WriteHeadersAndSaveData"
322 scoped_ptr
<SpdySerializedFrame
> frame
;
323 if (perspective() == Perspective::IS_SERVER
) {
324 if (version() > QUIC_VERSION_23
) {
325 SpdyHeadersIR
headers_frame(stream_id
);
326 headers_frame
.set_name_value_block(headers_
);
327 headers_frame
.set_fin(fin
);
328 headers_frame
.set_has_priority(true);
329 frame
.reset(framer_
.SerializeFrame(headers_frame
));
331 SpdySynStreamIR
syn_stream(stream_id
);
332 syn_stream
.set_name_value_block(headers_
);
333 syn_stream
.set_fin(fin
);
334 frame
.reset(framer_
.SerializeSynStream(syn_stream
));
336 EXPECT_CALL(session_
, OnStreamHeadersPriority(stream_id
, 0));
338 if (version() > QUIC_VERSION_23
) {
339 SpdyHeadersIR
headers_frame(stream_id
);
340 headers_frame
.set_name_value_block(headers_
);
341 headers_frame
.set_fin(fin
);
342 frame
.reset(framer_
.SerializeFrame(headers_frame
));
344 SpdySynReplyIR
syn_reply(stream_id
);
345 syn_reply
.set_name_value_block(headers_
);
346 syn_reply
.set_fin(fin
);
347 frame
.reset(framer_
.SerializeSynReply(syn_reply
));
350 EXPECT_CALL(session_
, OnStreamHeaders(stream_id
, _
))
351 .WillRepeatedly(WithArgs
<1>(Invoke(
352 this, &QuicHeadersStreamTest::SaveHeaderDataStringPiece
)));
353 EXPECT_CALL(session_
,
354 OnStreamHeadersComplete(stream_id
, fin
, frame
->size()));
355 headers_stream_
->ProcessRawData(frame
->data(), frame
->size());
362 TEST_P(QuicHeadersStreamTest
, ProcessBadData
) {
363 const char kBadData
[] = "blah blah blah";
364 EXPECT_CALL(*connection_
, SendConnectionCloseWithDetails(
365 QUIC_INVALID_HEADERS_STREAM_DATA
, _
))
366 .Times(::testing::AnyNumber());
367 headers_stream_
->ProcessRawData(kBadData
, strlen(kBadData
));
370 TEST_P(QuicHeadersStreamTest
, ProcessSpdyDataFrame
) {
371 SpdyDataIR
data(2, "");
372 scoped_ptr
<SpdySerializedFrame
> frame(framer_
.SerializeFrame(data
));
373 EXPECT_CALL(*connection_
,
374 SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA
,
375 "SPDY DATA frame received."))
376 .WillOnce(InvokeWithoutArgs(this,
377 &QuicHeadersStreamTest::CloseConnection
));
378 headers_stream_
->ProcessRawData(frame
->data(), frame
->size());
381 TEST_P(QuicHeadersStreamTest
, ProcessSpdyRstStreamFrame
) {
382 SpdyRstStreamIR
data(2, RST_STREAM_PROTOCOL_ERROR
, "");
383 scoped_ptr
<SpdySerializedFrame
> frame(framer_
.SerializeFrame(data
));
384 EXPECT_CALL(*connection_
,
385 SendConnectionCloseWithDetails(
386 QUIC_INVALID_HEADERS_STREAM_DATA
,
387 "SPDY RST_STREAM frame received."))
388 .WillOnce(InvokeWithoutArgs(this,
389 &QuicHeadersStreamTest::CloseConnection
));
390 headers_stream_
->ProcessRawData(frame
->data(), frame
->size());
393 TEST_P(QuicHeadersStreamTest
, ProcessSpdySettingsFrame
) {
395 if (version() > QUIC_VERSION_23
) {
396 data
.AddSetting(SETTINGS_HEADER_TABLE_SIZE
, true, true, 0);
398 data
.AddSetting(SETTINGS_UPLOAD_BANDWIDTH
, true, true, 0);
400 scoped_ptr
<SpdySerializedFrame
> frame(framer_
.SerializeFrame(data
));
401 EXPECT_CALL(*connection_
,
402 SendConnectionCloseWithDetails(
403 QUIC_INVALID_HEADERS_STREAM_DATA
,
404 "SPDY SETTINGS frame received."))
405 .WillOnce(InvokeWithoutArgs(this,
406 &QuicHeadersStreamTest::CloseConnection
));
407 headers_stream_
->ProcessRawData(frame
->data(), frame
->size());
410 TEST_P(QuicHeadersStreamTest
, ProcessSpdyPingFrame
) {
412 scoped_ptr
<SpdySerializedFrame
> frame(framer_
.SerializeFrame(data
));
413 EXPECT_CALL(*connection_
,
414 SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA
,
415 "SPDY PING frame received."))
416 .WillOnce(InvokeWithoutArgs(this,
417 &QuicHeadersStreamTest::CloseConnection
));
418 headers_stream_
->ProcessRawData(frame
->data(), frame
->size());
421 TEST_P(QuicHeadersStreamTest
, ProcessSpdyGoAwayFrame
) {
422 SpdyGoAwayIR
data(1, GOAWAY_PROTOCOL_ERROR
, "go away");
423 scoped_ptr
<SpdySerializedFrame
> frame(framer_
.SerializeFrame(data
));
424 EXPECT_CALL(*connection_
,
425 SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA
,
426 "SPDY GOAWAY frame received."))
427 .WillOnce(InvokeWithoutArgs(this,
428 &QuicHeadersStreamTest::CloseConnection
));
429 headers_stream_
->ProcessRawData(frame
->data(), frame
->size());
432 TEST_P(QuicHeadersStreamTest
, ProcessSpdyHeadersFrame
) {
433 if (version() > QUIC_VERSION_23
) {
434 // HEADERS frames are an error when using SPDY/3, but
435 // when using SPDY/4 they're the "normal" way of sending headers
436 // so we test their handling in the ProcessRawData test.
439 SpdyHeadersIR
data(1);
440 scoped_ptr
<SpdySerializedFrame
> frame(framer_
.SerializeFrame(data
));
441 EXPECT_CALL(*connection_
,
442 SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA
,
443 "SPDY HEADERS frame received."))
444 .WillOnce(InvokeWithoutArgs(this,
445 &QuicHeadersStreamTest::CloseConnection
));
446 headers_stream_
->ProcessRawData(frame
->data(), frame
->size());
449 TEST_P(QuicHeadersStreamTest
, ProcessSpdyWindowUpdateFrame
) {
450 SpdyWindowUpdateIR
data(1, 1);
451 scoped_ptr
<SpdySerializedFrame
> frame(framer_
.SerializeFrame(data
));
452 EXPECT_CALL(*connection_
,
453 SendConnectionCloseWithDetails(
454 QUIC_INVALID_HEADERS_STREAM_DATA
,
455 "SPDY WINDOW_UPDATE frame received."))
456 .WillOnce(InvokeWithoutArgs(this,
457 &QuicHeadersStreamTest::CloseConnection
));
458 headers_stream_
->ProcessRawData(frame
->data(), frame
->size());
461 TEST_P(QuicHeadersStreamTest
, NoConnectionLevelFlowControl
) {
462 EXPECT_FALSE(ReliableQuicStreamPeer::StreamContributesToConnectionFlowControl(