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. 4 5#include "net/quic/quic_headers_stream.h" 6 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" 15 16using base::StringPiece; 17using std::string; 18using testing::Invoke; 19using testing::StrictMock; 20using testing::WithArgs; 21using testing::_; 22 23namespace net { 24namespace test { 25namespace { 26 27class MockVisitor : public SpdyFramerVisitorInterface { 28 public: 29 MOCK_METHOD1(OnError, void(SpdyFramer* framer)); 30 MOCK_METHOD3(OnDataFrameHeader, void(SpdyStreamId stream_id, 31 size_t length, 32 bool fin)); 33 MOCK_METHOD4(OnStreamFrameData, void(SpdyStreamId stream_id, 34 const char* data, 35 size_t len, 36 bool fin)); 37 MOCK_METHOD3(OnControlFrameHeaderData, bool(SpdyStreamId stream_id, 38 const char* header_data, 39 size_t len)); 40 MOCK_METHOD5(OnSynStream, void(SpdyStreamId stream_id, 41 SpdyStreamId associated_stream_id, 42 SpdyPriority priority, 43 bool fin, 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, 59 size_t len)); 60 MOCK_METHOD1(OnBlocked, void(SpdyStreamId stream_id)); 61 MOCK_METHOD3(OnPushPromise, void(SpdyStreamId stream_id, 62 SpdyStreamId promised_stream_id, 63 bool end)); 64 MOCK_METHOD2(OnContinuation, void(SpdyStreamId stream_id, bool end)); 65 MOCK_METHOD6(OnAltSvc, void(SpdyStreamId stream_id, 66 uint32 max_age, 67 uint16 port, 68 StringPiece protocol_id, 69 StringPiece host, 70 StringPiece origin)); 71 MOCK_METHOD2(OnUnknownFrame, bool(SpdyStreamId stream_id, int frame_type)); 72}; 73 74class QuicHeadersStreamTest : public ::testing::TestWithParam<bool> { 75 public: 76 static QuicVersionVector GetVersions() { 77 QuicVersionVector versions; 78 versions.push_back(QuicVersionMax()); 79 return versions; 80 } 81 82 QuicHeadersStreamTest() 83 : connection_(new StrictMock<MockConnection>(is_server(), GetVersions())), 84 session_(connection_), 85 headers_stream_(QuicSessionPeer::GetHeadersStream(&session_)), 86 body_("hello world"), 87 framer_(SPDY3) { 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); 94 } 95 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); 101 } 102 return QuicConsumedData(saved_data_.length(), false); 103 } 104 105 bool SaveHeaderData(const char* data, int len) { 106 saved_header_data_.append(data, len); 107 return true; 108 } 109 110 void SaveHeaderDataStringPiece(StringPiece data) { 111 saved_header_data_.append(data.data(), data.length()); 112 } 113 114 void WriteHeadersAndExpectSynStream(QuicStreamId stream_id, 115 bool fin, 116 QuicPriority priority) { 117 WriteHeadersAndCheckData(stream_id, fin, priority, SYN_STREAM); 118 } 119 120 void WriteHeadersAndExpectSynReply(QuicStreamId stream_id, 121 bool fin) { 122 WriteHeadersAndCheckData(stream_id, fin, 0, SYN_REPLY); 123 } 124 125 void WriteHeadersAndCheckData(QuicStreamId stream_id, 126 bool fin, 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); 133 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, 137 // priority, 138 fin, kNotUnidirectional)); 139 } else { 140 EXPECT_CALL(visitor_, OnSynReply(stream_id, fin)); 141 } 142 EXPECT_CALL(visitor_, OnControlFrameHeaderData(stream_id, _, _)) 143 .WillRepeatedly(WithArgs<1, 2>( 144 Invoke(this, &QuicHeadersStreamTest::SaveHeaderData))); 145 if (fin) { 146 EXPECT_CALL(visitor_, OnStreamFrameData(stream_id, NULL, 0, true)); 147 } 148 framer_.ProcessInput(saved_data_.data(), saved_data_.length()); 149 EXPECT_FALSE(framer_.HasError()) << framer_.error_code(); 150 151 CheckHeaders(); 152 saved_data_.clear(); 153 } 154 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(), 160 &headers)); 161 EXPECT_EQ(headers_, headers); 162 saved_header_data_.clear(); 163 } 164 165 bool is_server() { 166 return GetParam(); 167 } 168 169 void CloseConnection() { 170 QuicConnectionPeer::CloseConnection(connection_); 171 } 172 173 static const bool kNotUnidirectional = false; 174 static const bool kNoAssociatedStream = false; 175 176 StrictMock<MockConnection>* connection_; 177 StrictMock<MockSession> session_; 178 QuicHeadersStream* headers_stream_; 179 SpdyHeaderBlock headers_; 180 string body_; 181 string saved_data_; 182 string saved_header_data_; 183 SpdyFramer framer_; 184 StrictMock<MockVisitor> visitor_; 185}; 186 187INSTANTIATE_TEST_CASE_P(Tests, QuicHeadersStreamTest, testing::Bool()); 188 189TEST_P(QuicHeadersStreamTest, StreamId) { 190 EXPECT_EQ(3u, headers_stream_->id()); 191} 192 193TEST_P(QuicHeadersStreamTest, EffectivePriority) { 194 EXPECT_EQ(0u, headers_stream_->EffectivePriority()); 195} 196 197TEST_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); 202 if (is_server()) { 203 WriteHeadersAndExpectSynReply(stream_id, fin); 204 } else { 205 for (QuicPriority priority = 0; priority < 7; ++priority) { 206 WriteHeadersAndExpectSynStream(stream_id, fin, priority); 207 } 208 } 209 } 210 } 211} 212 213TEST_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; 221 if (is_server()) { 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)); 227 } else { 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)); 232 } 233 EXPECT_CALL(session_, OnStreamHeaders(stream_id, _)) 234 .WillRepeatedly(WithArgs<1>( 235 Invoke(this, 236 &QuicHeadersStreamTest::SaveHeaderDataStringPiece))); 237 EXPECT_CALL(session_, 238 OnStreamHeadersComplete(stream_id, fin, frame->size())); 239 headers_stream_->ProcessRawData(frame->data(), frame->size()); 240 241 CheckHeaders(); 242 } 243 } 244 } 245} 246 247TEST_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()); 256} 257 258TEST_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()); 268} 269 270TEST_P(QuicHeadersStreamTest, ProcessSpdySettingsFrame) { 271 SpdySettingsIR data; 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()); 281} 282 283TEST_P(QuicHeadersStreamTest, ProcessSpdyPingFrame) { 284 SpdyPingIR data(1); 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()); 292} 293 294TEST_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()); 303} 304 305TEST_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()); 314} 315 316TEST_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()); 326} 327 328TEST_P(QuicHeadersStreamTest, NoConnectionLevelFlowControl) { 329 if (connection_->version() < QUIC_VERSION_21) { 330 EXPECT_FALSE(headers_stream_->flow_controller()->IsEnabled()); 331 } else { 332 EXPECT_TRUE(headers_stream_->flow_controller()->IsEnabled()); 333 } 334 EXPECT_FALSE(ReliableQuicStreamPeer::StreamContributesToConnectionFlowControl( 335 headers_stream_)); 336} 337 338} // namespace 339} // namespace test 340} // namespace net 341