1 // Copyright (c) 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/tools/quic/quic_spdy_server_stream.h" 6 7 #include "base/strings/string_number_conversions.h" 8 #include "base/strings/string_piece.h" 9 #include "net/quic/quic_connection.h" 10 #include "net/quic/quic_protocol.h" 11 #include "net/quic/quic_utils.h" 12 #include "net/quic/test_tools/quic_test_utils.h" 13 #include "net/tools/epoll_server/epoll_server.h" 14 #include "net/tools/quic/quic_in_memory_cache.h" 15 #include "net/tools/quic/spdy_utils.h" 16 #include "net/tools/quic/test_tools/quic_in_memory_cache_peer.h" 17 #include "net/tools/quic/test_tools/quic_test_utils.h" 18 #include "testing/gmock/include/gmock/gmock.h" 19 #include "testing/gtest/include/gtest/gtest.h" 20 21 using base::StringPiece; 22 using net::test::MockSession; 23 using net::test::SupportedVersions; 24 using net::tools::test::MockConnection; 25 using std::string; 26 using testing::_; 27 using testing::AnyNumber; 28 using testing::Invoke; 29 using testing::InvokeArgument; 30 using testing::InSequence; 31 using testing::Return; 32 using testing::StrictMock; 33 using testing::WithArgs; 34 35 namespace net { 36 namespace tools { 37 namespace test { 38 39 class QuicSpdyServerStreamPeer : public QuicSpdyServerStream { 40 public: 41 QuicSpdyServerStreamPeer(QuicStreamId stream_id, QuicSession* session) 42 : QuicSpdyServerStream(stream_id, session) { 43 } 44 45 using QuicSpdyServerStream::SendResponse; 46 using QuicSpdyServerStream::SendErrorResponse; 47 48 BalsaHeaders* mutable_headers() { 49 return &headers_; 50 } 51 52 static void SendResponse(QuicSpdyServerStream* stream) { 53 stream->SendResponse(); 54 } 55 56 static void SendErrorResponse(QuicSpdyServerStream* stream) { 57 stream->SendResponse(); 58 } 59 60 static const string& body(QuicSpdyServerStream* stream) { 61 return stream->body_; 62 } 63 64 static const BalsaHeaders& headers(QuicSpdyServerStream* stream) { 65 return stream->headers_; 66 } 67 }; 68 69 namespace { 70 71 class QuicSpdyServerStreamTest : public ::testing::TestWithParam<QuicVersion> { 72 public: 73 QuicSpdyServerStreamTest() 74 : connection_(new StrictMock<MockConnection>( 75 true, SupportedVersions(GetParam()))), 76 session_(connection_), 77 body_("hello world") { 78 BalsaHeaders request_headers; 79 request_headers.SetRequestFirstlineFromStringPieces( 80 "POST", "https://www.google.com/", "HTTP/1.1"); 81 request_headers.ReplaceOrAppendHeader("content-length", "11"); 82 83 headers_string_ = SpdyUtils::SerializeRequestHeaders(request_headers); 84 85 // New streams rely on having the peer's flow control receive window 86 // negotiated in the config. 87 session_.config()->SetInitialFlowControlWindowToSend( 88 kInitialSessionFlowControlWindowForTest); 89 session_.config()->SetInitialStreamFlowControlWindowToSend( 90 kInitialStreamFlowControlWindowForTest); 91 session_.config()->SetInitialSessionFlowControlWindowToSend( 92 kInitialSessionFlowControlWindowForTest); 93 stream_.reset(new QuicSpdyServerStreamPeer(3, &session_)); 94 } 95 96 static void SetUpTestCase() { 97 QuicInMemoryCachePeer::ResetForTests(); 98 } 99 100 virtual void SetUp() OVERRIDE { 101 QuicInMemoryCache* cache = QuicInMemoryCache::GetInstance(); 102 103 BalsaHeaders request_headers, response_headers; 104 StringPiece body("Yum"); 105 request_headers.SetRequestFirstlineFromStringPieces( 106 "GET", 107 "https://www.google.com/foo", 108 "HTTP/1.1"); 109 response_headers.SetRequestFirstlineFromStringPieces("HTTP/1.1", 110 "200", 111 "OK"); 112 response_headers.AppendHeader("content-length", 113 base::IntToString(body.length())); 114 115 // Check if response already exists and matches. 116 const QuicInMemoryCache::Response* cached_response = 117 cache->GetResponse(request_headers); 118 if (cached_response != NULL) { 119 string cached_response_headers_str, response_headers_str; 120 cached_response->headers().DumpToString(&cached_response_headers_str); 121 response_headers.DumpToString(&response_headers_str); 122 CHECK_EQ(cached_response_headers_str, response_headers_str); 123 CHECK_EQ(cached_response->body(), body); 124 return; 125 } 126 127 cache->AddResponse(request_headers, response_headers, body); 128 } 129 130 const string& StreamBody() { 131 return QuicSpdyServerStreamPeer::body(stream_.get()); 132 } 133 134 const BalsaHeaders& StreamHeaders() { 135 return QuicSpdyServerStreamPeer::headers(stream_.get()); 136 } 137 138 BalsaHeaders response_headers_; 139 EpollServer eps_; 140 StrictMock<MockConnection>* connection_; 141 StrictMock<MockSession> session_; 142 scoped_ptr<QuicSpdyServerStreamPeer> stream_; 143 string headers_string_; 144 string body_; 145 }; 146 147 QuicConsumedData ConsumeAllData( 148 QuicStreamId id, 149 const IOVector& data, 150 QuicStreamOffset offset, 151 bool fin, 152 FecProtection /*fec_protection_*/, 153 QuicAckNotifier::DelegateInterface* /*ack_notifier_delegate*/) { 154 return QuicConsumedData(data.TotalBufferSize(), fin); 155 } 156 157 INSTANTIATE_TEST_CASE_P(Tests, QuicSpdyServerStreamTest, 158 ::testing::ValuesIn(QuicSupportedVersions())); 159 160 TEST_P(QuicSpdyServerStreamTest, TestFraming) { 161 EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)).Times(AnyNumber()). 162 WillRepeatedly(Invoke(ConsumeAllData)); 163 164 EXPECT_EQ(headers_string_.size(), stream_->ProcessData( 165 headers_string_.c_str(), headers_string_.size())); 166 EXPECT_EQ(body_.size(), stream_->ProcessData(body_.c_str(), body_.size())); 167 EXPECT_EQ(11u, StreamHeaders().content_length()); 168 EXPECT_EQ("https://www.google.com/", StreamHeaders().request_uri()); 169 EXPECT_EQ("POST", StreamHeaders().request_method()); 170 EXPECT_EQ(body_, StreamBody()); 171 } 172 173 TEST_P(QuicSpdyServerStreamTest, TestFramingOnePacket) { 174 EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)).Times(AnyNumber()). 175 WillRepeatedly(Invoke(ConsumeAllData)); 176 177 string message = headers_string_ + body_; 178 179 EXPECT_EQ(message.size(), stream_->ProcessData( 180 message.c_str(), message.size())); 181 EXPECT_EQ(11u, StreamHeaders().content_length()); 182 EXPECT_EQ("https://www.google.com/", StreamHeaders().request_uri()); 183 EXPECT_EQ("POST", StreamHeaders().request_method()); 184 EXPECT_EQ(body_, StreamBody()); 185 } 186 187 TEST_P(QuicSpdyServerStreamTest, TestFramingExtraData) { 188 string large_body = "hello world!!!!!!"; 189 190 // We'll automatically write out an error (headers + body) 191 EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)).Times(AnyNumber()). 192 WillRepeatedly(Invoke(ConsumeAllData)); 193 194 EXPECT_EQ(headers_string_.size(), stream_->ProcessData( 195 headers_string_.c_str(), headers_string_.size())); 196 // Content length is still 11. This will register as an error and we won't 197 // accept the bytes. 198 stream_->ProcessData(large_body.c_str(), large_body.size()); 199 EXPECT_EQ(11u, StreamHeaders().content_length()); 200 EXPECT_EQ("https://www.google.com/", StreamHeaders().request_uri()); 201 EXPECT_EQ("POST", StreamHeaders().request_method()); 202 } 203 204 TEST_P(QuicSpdyServerStreamTest, TestSendResponse) { 205 BalsaHeaders* request_headers = stream_->mutable_headers(); 206 request_headers->SetRequestFirstlineFromStringPieces( 207 "GET", 208 "https://www.google.com/foo", 209 "HTTP/1.1"); 210 211 response_headers_.SetResponseFirstlineFromStringPieces( 212 "HTTP/1.1", "200", "OK"); 213 response_headers_.ReplaceOrAppendHeader("content-length", "3"); 214 215 InSequence s; 216 EXPECT_CALL(session_, 217 WritevData(kHeadersStreamId, _, 0, false, _, NULL)); 218 EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)).Times(1). 219 WillOnce(Return(QuicConsumedData(3, true))); 220 221 QuicSpdyServerStreamPeer::SendResponse(stream_.get()); 222 EXPECT_TRUE(stream_->read_side_closed()); 223 EXPECT_TRUE(stream_->write_side_closed()); 224 } 225 226 TEST_P(QuicSpdyServerStreamTest, TestSendErrorResponse) { 227 response_headers_.SetResponseFirstlineFromStringPieces( 228 "HTTP/1.1", "500", "Server Error"); 229 response_headers_.ReplaceOrAppendHeader("content-length", "3"); 230 231 InSequence s; 232 EXPECT_CALL(session_, 233 WritevData(kHeadersStreamId, _, 0, false, _, NULL)); 234 EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)).Times(1). 235 WillOnce(Return(QuicConsumedData(3, true))); 236 237 QuicSpdyServerStreamPeer::SendErrorResponse(stream_.get()); 238 EXPECT_TRUE(stream_->read_side_closed()); 239 EXPECT_TRUE(stream_->write_side_closed()); 240 } 241 242 TEST_P(QuicSpdyServerStreamTest, InvalidHeadersWithFin) { 243 char arr[] = { 244 0x3a, 0x68, 0x6f, 0x73, // :hos 245 0x74, 0x00, 0x00, 0x00, // t... 246 0x00, 0x00, 0x00, 0x00, // .... 247 0x07, 0x3a, 0x6d, 0x65, // .:me 248 0x74, 0x68, 0x6f, 0x64, // thod 249 0x00, 0x00, 0x00, 0x03, // .... 250 0x47, 0x45, 0x54, 0x00, // GET. 251 0x00, 0x00, 0x05, 0x3a, // ...: 252 0x70, 0x61, 0x74, 0x68, // path 253 0x00, 0x00, 0x00, 0x04, // .... 254 0x2f, 0x66, 0x6f, 0x6f, // /foo 255 0x00, 0x00, 0x00, 0x07, // .... 256 0x3a, 0x73, 0x63, 0x68, // :sch 257 0x65, 0x6d, 0x65, 0x00, // eme. 258 0x00, 0x00, 0x00, 0x00, // .... 259 0x00, 0x00, 0x08, 0x3a, // ...: 260 0x76, 0x65, 0x72, 0x73, // vers 261 '\x96', 0x6f, 0x6e, 0x00, // <i(69)>on. 262 0x00, 0x00, 0x08, 0x48, // ...H 263 0x54, 0x54, 0x50, 0x2f, // TTP/ 264 0x31, 0x2e, 0x31, // 1.1 265 }; 266 StringPiece data(arr, arraysize(arr)); 267 QuicStreamFrame frame(stream_->id(), true, 0, MakeIOVector(data)); 268 // Verify that we don't crash when we get a invalid headers in stream frame. 269 stream_->OnStreamFrame(frame); 270 } 271 272 } // namespace 273 } // namespace test 274 } // namespace tools 275 } // namespace net 276