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/spdy/spdy_protocol.h"
13 #include "testing/gtest/include/gtest/gtest.h"
15 using base::StringPiece;
17 using testing::Invoke;
18 using testing::Return;
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_METHOD1(OnPing, void(SpdyPingId unique_id));
51 MOCK_METHOD2(OnGoAway, void(SpdyStreamId last_accepted_stream_id,
52 SpdyGoAwayStatus status));
53 MOCK_METHOD2(OnHeaders, void(SpdyStreamId stream_id, bool fin));
54 MOCK_METHOD2(OnWindowUpdate, void(SpdyStreamId stream_id,
55 uint32 delta_window_size));
56 MOCK_METHOD2(OnCredentialFrameData, bool(const char* credential_data,
58 MOCK_METHOD1(OnBlocked, void(SpdyStreamId stream_id));
59 MOCK_METHOD2(OnPushPromise, void(SpdyStreamId stream_id,
60 SpdyStreamId promised_stream_id));
63 class QuicHeadersStreamTest : public ::testing::TestWithParam<bool> {
65 static QuicVersionVector GetVersions() {
66 QuicVersionVector versions;
67 versions.push_back(QUIC_VERSION_13);
71 QuicHeadersStreamTest()
72 : connection_(new StrictMock<MockConnection>(is_server(), GetVersions())),
73 session_(connection_),
74 headers_stream_(QuicSessionPeer::GetHeadersStream(&session_)),
77 headers_[":version"] = "HTTP/1.1";
78 headers_[":status"] = "200 Ok";
79 headers_["content-length"] = "11";
80 framer_.set_visitor(&visitor_);
81 EXPECT_EQ(QUIC_VERSION_13, session_.connection()->version());
82 EXPECT_TRUE(headers_stream_ != NULL);
85 QuicConsumedData SaveIov(const struct iovec* iov, int count) {
86 for (int i = 0 ; i < count; ++i) {
87 saved_data_.append(static_cast<char*>(iov[i].iov_base), iov[i].iov_len);
89 return QuicConsumedData(saved_data_.length(), false);
92 bool SaveHeaderData(const char* data, int len) {
93 saved_header_data_.append(data, len);
97 void SaveHeaderDataStringPiece(StringPiece data) {
98 saved_header_data_.append(data.data(), data.length());
101 void WriteHeadersAndExpectSynStream(QuicStreamId stream_id,
103 QuicPriority priority) {
104 WriteHeadersAndCheckData(stream_id, fin, priority, SYN_STREAM);
107 void WriteHeadersAndExpectSynReply(QuicStreamId stream_id,
109 WriteHeadersAndCheckData(stream_id, fin, 0, SYN_REPLY);
112 void WriteHeadersAndCheckData(QuicStreamId stream_id,
114 QuicPriority priority,
115 SpdyFrameType type) {
116 // Write the headers and capture the outgoing data
117 EXPECT_CALL(session_, WritevData(kHeadersStreamId, _, _, _, false, NULL))
118 .WillOnce(WithArgs<1, 2>(
119 Invoke(this, &QuicHeadersStreamTest::SaveIov)));
120 headers_stream_->WriteHeaders(stream_id, headers_, fin);
122 // Parse the outgoing data and check that it matches was was written.
123 if (type == SYN_STREAM) {
124 EXPECT_CALL(visitor_, OnSynStream(stream_id, kNoAssociatedStream, 0,
126 fin, kNotUnidirectional));
128 EXPECT_CALL(visitor_, OnSynReply(stream_id, fin));
130 EXPECT_CALL(visitor_, OnControlFrameHeaderData(stream_id, _, _))
131 .WillRepeatedly(WithArgs<1, 2>(
132 Invoke(this, &QuicHeadersStreamTest::SaveHeaderData)));
134 EXPECT_CALL(visitor_, OnStreamFrameData(stream_id, NULL, 0, true));
136 framer_.ProcessInput(saved_data_.data(), saved_data_.length());
137 EXPECT_FALSE(framer_.HasError()) << framer_.error_code();
143 void CheckHeaders() {
144 SpdyHeaderBlock headers;
145 EXPECT_EQ(saved_header_data_.length(),
146 framer_.ParseHeaderBlockInBuffer(saved_header_data_.data(),
147 saved_header_data_.length(),
149 EXPECT_EQ(headers_, headers);
150 saved_header_data_.clear();
157 void CloseConnection() {
158 QuicConnectionPeer::CloseConnection(connection_);
161 static const bool kNotUnidirectional = false;
162 static const bool kNoAssociatedStream = false;
164 StrictMock<MockConnection>* connection_;
165 StrictMock<MockSession> session_;
166 QuicHeadersStream* headers_stream_;
167 SpdyHeaderBlock headers_;
170 string saved_header_data_;
172 StrictMock<MockVisitor> visitor_;
175 INSTANTIATE_TEST_CASE_P(Tests, QuicHeadersStreamTest, testing::Bool());
177 TEST_P(QuicHeadersStreamTest, StreamId) {
178 EXPECT_EQ(3u, headers_stream_->id());
181 TEST_P(QuicHeadersStreamTest, EffectivePriority) {
182 EXPECT_EQ(0u, headers_stream_->EffectivePriority());
185 TEST_P(QuicHeadersStreamTest, WriteHeaders) {
186 for (QuicStreamId stream_id = 5; stream_id < 9; stream_id +=2) {
187 for (int count = 0; count < 2; ++count) {
188 bool fin = (count == 0);
190 WriteHeadersAndExpectSynReply(stream_id, fin);
192 for (QuicPriority priority = 0; priority < 7; ++priority) {
193 WriteHeadersAndExpectSynStream(stream_id, fin, priority);
200 TEST_P(QuicHeadersStreamTest, ProcessRawData) {
201 for (QuicStreamId stream_id = 5; stream_id < 9; stream_id +=2) {
202 for (int count = 0; count < 2; ++count) {
203 bool fin = (count == 0);
204 for (QuicPriority priority = 0; priority < 7; ++priority) {
205 // Replace with "WriteHeadersAndSaveData"
206 scoped_ptr<SpdySerializedFrame> frame;
208 SpdySynStreamIR syn_stream(stream_id);
209 syn_stream.set_name_value_block(headers_);
210 syn_stream.set_fin(fin);
211 frame.reset(framer_.SerializeSynStream(syn_stream));
212 EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0));
214 SpdySynReplyIR syn_reply(stream_id);
215 syn_reply.set_name_value_block(headers_);
216 syn_reply.set_fin(fin);
217 frame.reset(framer_.SerializeSynReply(syn_reply));
219 EXPECT_CALL(session_, OnStreamHeaders(stream_id, _))
220 .WillRepeatedly(WithArgs<1>(
222 &QuicHeadersStreamTest::SaveHeaderDataStringPiece)));
223 EXPECT_CALL(session_,
224 OnStreamHeadersComplete(stream_id, fin, frame->size()));
225 headers_stream_->ProcessRawData(frame->data(), frame->size());
233 TEST_P(QuicHeadersStreamTest, ProcessSpdyDataFrame) {
234 SpdyDataIR data(2, "");
235 scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
236 EXPECT_CALL(*connection_,
237 SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
238 "SPDY DATA frame recevied."))
239 .WillOnce(InvokeWithoutArgs(this,
240 &QuicHeadersStreamTest::CloseConnection));
241 headers_stream_->ProcessRawData(frame->data(), frame->size());
244 TEST_P(QuicHeadersStreamTest, ProcessSpdyRstStreamFrame) {
245 SpdyRstStreamIR data(2, RST_STREAM_PROTOCOL_ERROR, "");
246 scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
247 EXPECT_CALL(*connection_,
248 SendConnectionCloseWithDetails(
249 QUIC_INVALID_HEADERS_STREAM_DATA,
250 "SPDY RST_STREAM frame recevied."))
251 .WillOnce(InvokeWithoutArgs(this,
252 &QuicHeadersStreamTest::CloseConnection));
253 headers_stream_->ProcessRawData(frame->data(), frame->size());
256 TEST_P(QuicHeadersStreamTest, ProcessSpdySettingsFrame) {
258 data.AddSetting(SETTINGS_UPLOAD_BANDWIDTH, true, true, 0);
259 scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
260 EXPECT_CALL(*connection_,
261 SendConnectionCloseWithDetails(
262 QUIC_INVALID_HEADERS_STREAM_DATA,
263 "SPDY SETTINGS frame recevied."))
264 .WillOnce(InvokeWithoutArgs(this,
265 &QuicHeadersStreamTest::CloseConnection));
266 headers_stream_->ProcessRawData(frame->data(), frame->size());
269 TEST_P(QuicHeadersStreamTest, ProcessSpdyPingFrame) {
271 scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
272 EXPECT_CALL(*connection_,
273 SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
274 "SPDY PING frame recevied."))
275 .WillOnce(InvokeWithoutArgs(this,
276 &QuicHeadersStreamTest::CloseConnection));
277 headers_stream_->ProcessRawData(frame->data(), frame->size());
280 TEST_P(QuicHeadersStreamTest, ProcessSpdyGoAwayFrame) {
281 SpdyGoAwayIR data(1, GOAWAY_PROTOCOL_ERROR, "go away");
282 scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
283 EXPECT_CALL(*connection_,
284 SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
285 "SPDY GOAWAY frame recevied."))
286 .WillOnce(InvokeWithoutArgs(this,
287 &QuicHeadersStreamTest::CloseConnection));
288 headers_stream_->ProcessRawData(frame->data(), frame->size());
291 TEST_P(QuicHeadersStreamTest, ProcessSpdyHeadersFrame) {
292 SpdyHeadersIR data(1);
293 scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
294 EXPECT_CALL(*connection_,
295 SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
296 "SPDY HEADERS frame recevied."))
297 .WillOnce(InvokeWithoutArgs(this,
298 &QuicHeadersStreamTest::CloseConnection));
299 headers_stream_->ProcessRawData(frame->data(), frame->size());
302 TEST_P(QuicHeadersStreamTest, ProcessSpdyWindowUpdateFrame) {
303 SpdyWindowUpdateIR data(1, 1);
304 scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
305 EXPECT_CALL(*connection_,
306 SendConnectionCloseWithDetails(
307 QUIC_INVALID_HEADERS_STREAM_DATA,
308 "SPDY WINDOW_UPDATE frame recevied."))
309 .WillOnce(InvokeWithoutArgs(this,
310 &QuicHeadersStreamTest::CloseConnection));
311 headers_stream_->ProcessRawData(frame->data(), frame->size());