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_flags.h"
8 #include "net/quic/quic_utils.h"
9 #include "net/quic/spdy_utils.h"
10 #include "net/quic/test_tools/quic_connection_peer.h"
11 #include "net/quic/test_tools/quic_session_peer.h"
12 #include "net/quic/test_tools/quic_test_utils.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));
67 class QuicHeadersStreamTest : public ::testing::TestWithParam<bool> {
69 static QuicVersionVector GetVersions() {
70 QuicVersionVector versions;
71 versions.push_back(QuicVersionMax());
75 QuicHeadersStreamTest()
76 : connection_(new StrictMock<MockConnection>(is_server(), GetVersions())),
77 session_(connection_),
78 headers_stream_(QuicSessionPeer::GetHeadersStream(&session_)),
81 headers_[":version"] = "HTTP/1.1";
82 headers_[":status"] = "200 Ok";
83 headers_["content-length"] = "11";
84 framer_.set_visitor(&visitor_);
85 EXPECT_EQ(QuicVersionMax(), session_.connection()->version());
86 EXPECT_TRUE(headers_stream_ != NULL);
89 QuicConsumedData SaveIov(const IOVector& data) {
90 const iovec* iov = data.iovec();
91 int count = data.Capacity();
92 for (int i = 0 ; i < count; ++i) {
93 saved_data_.append(static_cast<char*>(iov[i].iov_base), iov[i].iov_len);
95 return QuicConsumedData(saved_data_.length(), false);
98 bool SaveHeaderData(const char* data, int len) {
99 saved_header_data_.append(data, len);
103 void SaveHeaderDataStringPiece(StringPiece data) {
104 saved_header_data_.append(data.data(), data.length());
107 void WriteHeadersAndExpectSynStream(QuicStreamId stream_id,
109 QuicPriority priority) {
110 WriteHeadersAndCheckData(stream_id, fin, priority, SYN_STREAM);
113 void WriteHeadersAndExpectSynReply(QuicStreamId stream_id,
115 WriteHeadersAndCheckData(stream_id, fin, 0, SYN_REPLY);
118 void WriteHeadersAndCheckData(QuicStreamId stream_id,
120 QuicPriority priority,
121 SpdyFrameType type) {
122 // Write the headers and capture the outgoing data
123 EXPECT_CALL(session_, WritevData(kHeadersStreamId, _, _, false, NULL))
124 .WillOnce(WithArgs<1>(Invoke(this, &QuicHeadersStreamTest::SaveIov)));
125 headers_stream_->WriteHeaders(stream_id, headers_, fin, NULL);
127 // Parse the outgoing data and check that it matches was was written.
128 if (type == SYN_STREAM) {
129 EXPECT_CALL(visitor_, OnSynStream(stream_id, kNoAssociatedStream, 0,
131 fin, kNotUnidirectional));
133 EXPECT_CALL(visitor_, OnSynReply(stream_id, fin));
135 EXPECT_CALL(visitor_, OnControlFrameHeaderData(stream_id, _, _))
136 .WillRepeatedly(WithArgs<1, 2>(
137 Invoke(this, &QuicHeadersStreamTest::SaveHeaderData)));
139 EXPECT_CALL(visitor_, OnStreamFrameData(stream_id, NULL, 0, true));
141 framer_.ProcessInput(saved_data_.data(), saved_data_.length());
142 EXPECT_FALSE(framer_.HasError()) << framer_.error_code();
148 void CheckHeaders() {
149 SpdyHeaderBlock headers;
150 EXPECT_EQ(saved_header_data_.length(),
151 framer_.ParseHeaderBlockInBuffer(saved_header_data_.data(),
152 saved_header_data_.length(),
154 EXPECT_EQ(headers_, headers);
155 saved_header_data_.clear();
162 void CloseConnection() {
163 QuicConnectionPeer::CloseConnection(connection_);
166 static const bool kNotUnidirectional = false;
167 static const bool kNoAssociatedStream = false;
169 StrictMock<MockConnection>* connection_;
170 StrictMock<MockSession> session_;
171 QuicHeadersStream* headers_stream_;
172 SpdyHeaderBlock headers_;
175 string saved_header_data_;
177 StrictMock<MockVisitor> visitor_;
180 INSTANTIATE_TEST_CASE_P(Tests, QuicHeadersStreamTest, testing::Bool());
182 TEST_P(QuicHeadersStreamTest, StreamId) {
183 EXPECT_EQ(3u, headers_stream_->id());
186 TEST_P(QuicHeadersStreamTest, EffectivePriority) {
187 EXPECT_EQ(0u, headers_stream_->EffectivePriority());
190 TEST_P(QuicHeadersStreamTest, WriteHeaders) {
191 for (QuicStreamId stream_id = 5; stream_id < 9; stream_id +=2) {
192 for (int count = 0; count < 2; ++count) {
193 bool fin = (count == 0);
195 WriteHeadersAndExpectSynReply(stream_id, fin);
197 for (QuicPriority priority = 0; priority < 7; ++priority) {
198 WriteHeadersAndExpectSynStream(stream_id, fin, priority);
205 TEST_P(QuicHeadersStreamTest, ProcessRawData) {
206 for (QuicStreamId stream_id = 5; stream_id < 9; stream_id +=2) {
207 for (int count = 0; count < 2; ++count) {
208 bool fin = (count == 0);
209 for (QuicPriority priority = 0; priority < 7; ++priority) {
210 // Replace with "WriteHeadersAndSaveData"
211 scoped_ptr<SpdySerializedFrame> frame;
213 SpdySynStreamIR syn_stream(stream_id);
214 syn_stream.set_name_value_block(headers_);
215 syn_stream.set_fin(fin);
216 frame.reset(framer_.SerializeSynStream(syn_stream));
217 EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0));
219 SpdySynReplyIR syn_reply(stream_id);
220 syn_reply.set_name_value_block(headers_);
221 syn_reply.set_fin(fin);
222 frame.reset(framer_.SerializeSynReply(syn_reply));
224 EXPECT_CALL(session_, OnStreamHeaders(stream_id, _))
225 .WillRepeatedly(WithArgs<1>(
227 &QuicHeadersStreamTest::SaveHeaderDataStringPiece)));
228 EXPECT_CALL(session_,
229 OnStreamHeadersComplete(stream_id, fin, frame->size()));
230 headers_stream_->ProcessRawData(frame->data(), frame->size());
238 TEST_P(QuicHeadersStreamTest, ProcessSpdyDataFrame) {
239 SpdyDataIR data(2, "");
240 scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
241 EXPECT_CALL(*connection_,
242 SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
243 "SPDY DATA frame received."))
244 .WillOnce(InvokeWithoutArgs(this,
245 &QuicHeadersStreamTest::CloseConnection));
246 headers_stream_->ProcessRawData(frame->data(), frame->size());
249 TEST_P(QuicHeadersStreamTest, ProcessSpdyRstStreamFrame) {
250 SpdyRstStreamIR data(2, RST_STREAM_PROTOCOL_ERROR, "");
251 scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
252 EXPECT_CALL(*connection_,
253 SendConnectionCloseWithDetails(
254 QUIC_INVALID_HEADERS_STREAM_DATA,
255 "SPDY RST_STREAM frame received."))
256 .WillOnce(InvokeWithoutArgs(this,
257 &QuicHeadersStreamTest::CloseConnection));
258 headers_stream_->ProcessRawData(frame->data(), frame->size());
261 TEST_P(QuicHeadersStreamTest, ProcessSpdySettingsFrame) {
263 data.AddSetting(SETTINGS_UPLOAD_BANDWIDTH, true, true, 0);
264 scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
265 EXPECT_CALL(*connection_,
266 SendConnectionCloseWithDetails(
267 QUIC_INVALID_HEADERS_STREAM_DATA,
268 "SPDY SETTINGS frame received."))
269 .WillOnce(InvokeWithoutArgs(this,
270 &QuicHeadersStreamTest::CloseConnection));
271 headers_stream_->ProcessRawData(frame->data(), frame->size());
274 TEST_P(QuicHeadersStreamTest, ProcessSpdyPingFrame) {
276 scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
277 EXPECT_CALL(*connection_,
278 SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
279 "SPDY PING frame received."))
280 .WillOnce(InvokeWithoutArgs(this,
281 &QuicHeadersStreamTest::CloseConnection));
282 headers_stream_->ProcessRawData(frame->data(), frame->size());
285 TEST_P(QuicHeadersStreamTest, ProcessSpdyGoAwayFrame) {
286 SpdyGoAwayIR data(1, GOAWAY_PROTOCOL_ERROR, "go away");
287 scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
288 EXPECT_CALL(*connection_,
289 SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
290 "SPDY GOAWAY frame received."))
291 .WillOnce(InvokeWithoutArgs(this,
292 &QuicHeadersStreamTest::CloseConnection));
293 headers_stream_->ProcessRawData(frame->data(), frame->size());
296 TEST_P(QuicHeadersStreamTest, ProcessSpdyHeadersFrame) {
297 SpdyHeadersIR data(1);
298 scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
299 EXPECT_CALL(*connection_,
300 SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
301 "SPDY HEADERS frame received."))
302 .WillOnce(InvokeWithoutArgs(this,
303 &QuicHeadersStreamTest::CloseConnection));
304 headers_stream_->ProcessRawData(frame->data(), frame->size());
307 TEST_P(QuicHeadersStreamTest, ProcessSpdyWindowUpdateFrame) {
308 SpdyWindowUpdateIR data(1, 1);
309 scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
310 EXPECT_CALL(*connection_,
311 SendConnectionCloseWithDetails(
312 QUIC_INVALID_HEADERS_STREAM_DATA,
313 "SPDY WINDOW_UPDATE frame received."))
314 .WillOnce(InvokeWithoutArgs(this,
315 &QuicHeadersStreamTest::CloseConnection));
316 headers_stream_->ProcessRawData(frame->data(), frame->size());
319 TEST_P(QuicHeadersStreamTest, NoFlowControl) {
320 ValueRestore<bool> old_flag(&FLAGS_enable_quic_stream_flow_control_2, true);
321 EXPECT_FALSE(headers_stream_->flow_controller()->IsEnabled());