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_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" 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}; 72 73class QuicHeadersStreamTest : public ::testing::TestWithParam<bool> { 74 public: 75 static QuicVersionVector GetVersions() { 76 QuicVersionVector versions; 77 versions.push_back(QuicVersionMax()); 78 return versions; 79 } 80 81 QuicHeadersStreamTest() 82 : connection_(new StrictMock<MockConnection>(is_server(), GetVersions())), 83 session_(connection_), 84 headers_stream_(QuicSessionPeer::GetHeadersStream(&session_)), 85 body_("hello world"), 86 framer_(SPDY3) { 87 headers_[":version"] = "HTTP/1.1"; 88 headers_[":status"] = "200 Ok"; 89 headers_["content-length"] = "11"; 90 framer_.set_visitor(&visitor_); 91 EXPECT_EQ(QuicVersionMax(), session_.connection()->version()); 92 EXPECT_TRUE(headers_stream_ != NULL); 93 } 94 95 QuicConsumedData SaveIov(const IOVector& data) { 96 const iovec* iov = data.iovec(); 97 int count = data.Capacity(); 98 for (int i = 0 ; i < count; ++i) { 99 saved_data_.append(static_cast<char*>(iov[i].iov_base), iov[i].iov_len); 100 } 101 return QuicConsumedData(saved_data_.length(), false); 102 } 103 104 bool SaveHeaderData(const char* data, int len) { 105 saved_header_data_.append(data, len); 106 return true; 107 } 108 109 void SaveHeaderDataStringPiece(StringPiece data) { 110 saved_header_data_.append(data.data(), data.length()); 111 } 112 113 void WriteHeadersAndExpectSynStream(QuicStreamId stream_id, 114 bool fin, 115 QuicPriority priority) { 116 WriteHeadersAndCheckData(stream_id, fin, priority, SYN_STREAM); 117 } 118 119 void WriteHeadersAndExpectSynReply(QuicStreamId stream_id, 120 bool fin) { 121 WriteHeadersAndCheckData(stream_id, fin, 0, SYN_REPLY); 122 } 123 124 void WriteHeadersAndCheckData(QuicStreamId stream_id, 125 bool fin, 126 QuicPriority priority, 127 SpdyFrameType type) { 128 // Write the headers and capture the outgoing data 129 EXPECT_CALL(session_, WritevData(kHeadersStreamId, _, _, false, _, NULL)) 130 .WillOnce(WithArgs<1>(Invoke(this, &QuicHeadersStreamTest::SaveIov))); 131 headers_stream_->WriteHeaders(stream_id, headers_, fin, NULL); 132 133 // Parse the outgoing data and check that it matches was was written. 134 if (type == SYN_STREAM) { 135 EXPECT_CALL(visitor_, OnSynStream(stream_id, kNoAssociatedStream, 0, 136 // priority, 137 fin, kNotUnidirectional)); 138 } else { 139 EXPECT_CALL(visitor_, OnSynReply(stream_id, fin)); 140 } 141 EXPECT_CALL(visitor_, OnControlFrameHeaderData(stream_id, _, _)) 142 .WillRepeatedly(WithArgs<1, 2>( 143 Invoke(this, &QuicHeadersStreamTest::SaveHeaderData))); 144 if (fin) { 145 EXPECT_CALL(visitor_, OnStreamFrameData(stream_id, NULL, 0, true)); 146 } 147 framer_.ProcessInput(saved_data_.data(), saved_data_.length()); 148 EXPECT_FALSE(framer_.HasError()) << framer_.error_code(); 149 150 CheckHeaders(); 151 saved_data_.clear(); 152 } 153 154 void CheckHeaders() { 155 SpdyHeaderBlock headers; 156 EXPECT_EQ(saved_header_data_.length(), 157 framer_.ParseHeaderBlockInBuffer(saved_header_data_.data(), 158 saved_header_data_.length(), 159 &headers)); 160 EXPECT_EQ(headers_, headers); 161 saved_header_data_.clear(); 162 } 163 164 bool is_server() { 165 return GetParam(); 166 } 167 168 void CloseConnection() { 169 QuicConnectionPeer::CloseConnection(connection_); 170 } 171 172 static const bool kNotUnidirectional = false; 173 static const bool kNoAssociatedStream = false; 174 175 StrictMock<MockConnection>* connection_; 176 StrictMock<MockSession> session_; 177 QuicHeadersStream* headers_stream_; 178 SpdyHeaderBlock headers_; 179 string body_; 180 string saved_data_; 181 string saved_header_data_; 182 SpdyFramer framer_; 183 StrictMock<MockVisitor> visitor_; 184}; 185 186INSTANTIATE_TEST_CASE_P(Tests, QuicHeadersStreamTest, testing::Bool()); 187 188TEST_P(QuicHeadersStreamTest, StreamId) { 189 EXPECT_EQ(3u, headers_stream_->id()); 190} 191 192TEST_P(QuicHeadersStreamTest, EffectivePriority) { 193 EXPECT_EQ(0u, headers_stream_->EffectivePriority()); 194} 195 196TEST_P(QuicHeadersStreamTest, WriteHeaders) { 197 for (QuicStreamId stream_id = kClientDataStreamId1; 198 stream_id < kClientDataStreamId3; stream_id += 2) { 199 for (int count = 0; count < 2; ++count) { 200 bool fin = (count == 0); 201 if (is_server()) { 202 WriteHeadersAndExpectSynReply(stream_id, fin); 203 } else { 204 for (QuicPriority priority = 0; priority < 7; ++priority) { 205 WriteHeadersAndExpectSynStream(stream_id, fin, priority); 206 } 207 } 208 } 209 } 210} 211 212TEST_P(QuicHeadersStreamTest, ProcessRawData) { 213 for (QuicStreamId stream_id = kClientDataStreamId1; 214 stream_id < kClientDataStreamId3; stream_id += 2) { 215 for (int count = 0; count < 2; ++count) { 216 bool fin = (count == 0); 217 for (QuicPriority priority = 0; priority < 7; ++priority) { 218 // Replace with "WriteHeadersAndSaveData" 219 scoped_ptr<SpdySerializedFrame> frame; 220 if (is_server()) { 221 SpdySynStreamIR syn_stream(stream_id); 222 syn_stream.set_name_value_block(headers_); 223 syn_stream.set_fin(fin); 224 frame.reset(framer_.SerializeSynStream(syn_stream)); 225 EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0)); 226 } else { 227 SpdySynReplyIR syn_reply(stream_id); 228 syn_reply.set_name_value_block(headers_); 229 syn_reply.set_fin(fin); 230 frame.reset(framer_.SerializeSynReply(syn_reply)); 231 } 232 EXPECT_CALL(session_, OnStreamHeaders(stream_id, _)) 233 .WillRepeatedly(WithArgs<1>( 234 Invoke(this, 235 &QuicHeadersStreamTest::SaveHeaderDataStringPiece))); 236 EXPECT_CALL(session_, 237 OnStreamHeadersComplete(stream_id, fin, frame->size())); 238 headers_stream_->ProcessRawData(frame->data(), frame->size()); 239 240 CheckHeaders(); 241 } 242 } 243 } 244} 245 246TEST_P(QuicHeadersStreamTest, ProcessSpdyDataFrame) { 247 SpdyDataIR data(2, ""); 248 scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data)); 249 EXPECT_CALL(*connection_, 250 SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA, 251 "SPDY DATA frame received.")) 252 .WillOnce(InvokeWithoutArgs(this, 253 &QuicHeadersStreamTest::CloseConnection)); 254 headers_stream_->ProcessRawData(frame->data(), frame->size()); 255} 256 257TEST_P(QuicHeadersStreamTest, ProcessSpdyRstStreamFrame) { 258 SpdyRstStreamIR data(2, RST_STREAM_PROTOCOL_ERROR, ""); 259 scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data)); 260 EXPECT_CALL(*connection_, 261 SendConnectionCloseWithDetails( 262 QUIC_INVALID_HEADERS_STREAM_DATA, 263 "SPDY RST_STREAM frame received.")) 264 .WillOnce(InvokeWithoutArgs(this, 265 &QuicHeadersStreamTest::CloseConnection)); 266 headers_stream_->ProcessRawData(frame->data(), frame->size()); 267} 268 269TEST_P(QuicHeadersStreamTest, ProcessSpdySettingsFrame) { 270 SpdySettingsIR data; 271 data.AddSetting(SETTINGS_UPLOAD_BANDWIDTH, true, true, 0); 272 scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data)); 273 EXPECT_CALL(*connection_, 274 SendConnectionCloseWithDetails( 275 QUIC_INVALID_HEADERS_STREAM_DATA, 276 "SPDY SETTINGS frame received.")) 277 .WillOnce(InvokeWithoutArgs(this, 278 &QuicHeadersStreamTest::CloseConnection)); 279 headers_stream_->ProcessRawData(frame->data(), frame->size()); 280} 281 282TEST_P(QuicHeadersStreamTest, ProcessSpdyPingFrame) { 283 SpdyPingIR data(1); 284 scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data)); 285 EXPECT_CALL(*connection_, 286 SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA, 287 "SPDY PING frame received.")) 288 .WillOnce(InvokeWithoutArgs(this, 289 &QuicHeadersStreamTest::CloseConnection)); 290 headers_stream_->ProcessRawData(frame->data(), frame->size()); 291} 292 293TEST_P(QuicHeadersStreamTest, ProcessSpdyGoAwayFrame) { 294 SpdyGoAwayIR data(1, GOAWAY_PROTOCOL_ERROR, "go away"); 295 scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data)); 296 EXPECT_CALL(*connection_, 297 SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA, 298 "SPDY GOAWAY frame received.")) 299 .WillOnce(InvokeWithoutArgs(this, 300 &QuicHeadersStreamTest::CloseConnection)); 301 headers_stream_->ProcessRawData(frame->data(), frame->size()); 302} 303 304TEST_P(QuicHeadersStreamTest, ProcessSpdyHeadersFrame) { 305 SpdyHeadersIR data(1); 306 scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data)); 307 EXPECT_CALL(*connection_, 308 SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA, 309 "SPDY HEADERS frame received.")) 310 .WillOnce(InvokeWithoutArgs(this, 311 &QuicHeadersStreamTest::CloseConnection)); 312 headers_stream_->ProcessRawData(frame->data(), frame->size()); 313} 314 315TEST_P(QuicHeadersStreamTest, ProcessSpdyWindowUpdateFrame) { 316 SpdyWindowUpdateIR data(1, 1); 317 scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data)); 318 EXPECT_CALL(*connection_, 319 SendConnectionCloseWithDetails( 320 QUIC_INVALID_HEADERS_STREAM_DATA, 321 "SPDY WINDOW_UPDATE frame received.")) 322 .WillOnce(InvokeWithoutArgs(this, 323 &QuicHeadersStreamTest::CloseConnection)); 324 headers_stream_->ProcessRawData(frame->data(), frame->size()); 325} 326 327TEST_P(QuicHeadersStreamTest, NoFlowControl) { 328 ValueRestore<bool> old_flag(&FLAGS_enable_quic_stream_flow_control_2, true); 329 EXPECT_FALSE(headers_stream_->flow_controller()->IsEnabled()); 330} 331 332} // namespace 333} // namespace test 334} // namespace net 335