| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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 "base/memory/ref_counted.h" | |
| 6 #include "net/base/completion_callback.h" | |
| 7 #include "net/base/net_log_unittest.h" | |
| 8 #include "net/spdy/spdy_stream.h" | |
| 9 #include "net/spdy/spdy_http_utils.h" | |
| 10 #include "net/spdy/spdy_session.h" | |
| 11 #include "net/spdy/spdy_test_util.h" | |
| 12 #include "testing/gtest/include/gtest/gtest.h" | |
| 13 | |
| 14 // TODO(ukai): factor out common part with spdy_http_stream_unittest.cc | |
| 15 // | |
| 16 namespace net { | |
| 17 | |
| 18 namespace { | |
| 19 | |
| 20 class TestSpdyStreamDelegate : public SpdyStream::Delegate { | |
| 21 public: | |
| 22 TestSpdyStreamDelegate(SpdyStream* stream, | |
| 23 IOBufferWithSize* buf, | |
| 24 const CompletionCallback& callback) | |
| 25 : stream_(stream), | |
| 26 buf_(buf), | |
| 27 callback_(callback), | |
| 28 send_headers_completed_(false), | |
| 29 response_(new spdy::SpdyHeaderBlock), | |
| 30 data_sent_(0), | |
| 31 closed_(false) {} | |
| 32 virtual ~TestSpdyStreamDelegate() {} | |
| 33 | |
| 34 virtual bool OnSendHeadersComplete(int status) { | |
| 35 send_headers_completed_ = true; | |
| 36 return true; | |
| 37 } | |
| 38 virtual int OnSendBody() { | |
| 39 ADD_FAILURE() << "OnSendBody should not be called"; | |
| 40 return ERR_UNEXPECTED; | |
| 41 } | |
| 42 virtual int OnSendBodyComplete(int /*status*/, bool* /*eof*/) { | |
| 43 ADD_FAILURE() << "OnSendBodyComplete should not be called"; | |
| 44 return ERR_UNEXPECTED; | |
| 45 } | |
| 46 | |
| 47 virtual int OnResponseReceived(const spdy::SpdyHeaderBlock& response, | |
| 48 base::Time response_time, | |
| 49 int status) { | |
| 50 EXPECT_TRUE(send_headers_completed_); | |
| 51 *response_ = response; | |
| 52 if (buf_) { | |
| 53 EXPECT_EQ(ERR_IO_PENDING, | |
| 54 stream_->WriteStreamData(buf_.get(), buf_->size(), | |
| 55 spdy::DATA_FLAG_NONE)); | |
| 56 } | |
| 57 return status; | |
| 58 } | |
| 59 virtual void OnDataReceived(const char* buffer, int bytes) { | |
| 60 received_data_ += std::string(buffer, bytes); | |
| 61 } | |
| 62 virtual void OnDataSent(int length) { | |
| 63 data_sent_ += length; | |
| 64 } | |
| 65 virtual void OnClose(int status) { | |
| 66 closed_ = true; | |
| 67 CompletionCallback callback = callback_; | |
| 68 callback_.Reset(); | |
| 69 callback.Run(OK); | |
| 70 } | |
| 71 virtual void set_chunk_callback(net::ChunkCallback *) {} | |
| 72 | |
| 73 bool send_headers_completed() const { return send_headers_completed_; } | |
| 74 const linked_ptr<spdy::SpdyHeaderBlock>& response() const { | |
| 75 return response_; | |
| 76 } | |
| 77 const std::string& received_data() const { return received_data_; } | |
| 78 int data_sent() const { return data_sent_; } | |
| 79 bool closed() const { return closed_; } | |
| 80 | |
| 81 private: | |
| 82 SpdyStream* stream_; | |
| 83 scoped_refptr<IOBufferWithSize> buf_; | |
| 84 CompletionCallback callback_; | |
| 85 bool send_headers_completed_; | |
| 86 linked_ptr<spdy::SpdyHeaderBlock> response_; | |
| 87 std::string received_data_; | |
| 88 int data_sent_; | |
| 89 bool closed_; | |
| 90 }; | |
| 91 | |
| 92 spdy::SpdyFrame* ConstructSpdyBodyFrame(const char* data, int length) { | |
| 93 spdy::SpdyFramer framer; | |
| 94 return framer.CreateDataFrame(1, data, length, spdy::DATA_FLAG_NONE); | |
| 95 } | |
| 96 | |
| 97 } // anonymous namespace | |
| 98 | |
| 99 class SpdyStreamTest : public testing::Test { | |
| 100 protected: | |
| 101 SpdyStreamTest() { | |
| 102 } | |
| 103 | |
| 104 scoped_refptr<SpdySession> CreateSpdySession() { | |
| 105 spdy::SpdyFramer::set_enable_compression_default(false); | |
| 106 HostPortPair host_port_pair("www.google.com", 80); | |
| 107 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct()); | |
| 108 scoped_refptr<SpdySession> session( | |
| 109 session_->spdy_session_pool()->Get(pair, BoundNetLog())); | |
| 110 return session; | |
| 111 } | |
| 112 | |
| 113 virtual void TearDown() { | |
| 114 MessageLoop::current()->RunAllPending(); | |
| 115 } | |
| 116 | |
| 117 scoped_refptr<HttpNetworkSession> session_; | |
| 118 }; | |
| 119 | |
| 120 TEST_F(SpdyStreamTest, SendDataAfterOpen) { | |
| 121 SpdySessionDependencies session_deps; | |
| 122 | |
| 123 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps); | |
| 124 SpdySessionPoolPeer pool_peer_(session_->spdy_session_pool()); | |
| 125 | |
| 126 const SpdyHeaderInfo kSynStartHeader = { | |
| 127 spdy::SYN_STREAM, | |
| 128 1, | |
| 129 0, | |
| 130 net::ConvertRequestPriorityToSpdyPriority(LOWEST), | |
| 131 spdy::CONTROL_FLAG_NONE, | |
| 132 false, | |
| 133 spdy::INVALID, | |
| 134 NULL, | |
| 135 0, | |
| 136 spdy::DATA_FLAG_NONE | |
| 137 }; | |
| 138 static const char* const kGetHeaders[] = { | |
| 139 "method", | |
| 140 "GET", | |
| 141 "scheme", | |
| 142 "http", | |
| 143 "host", | |
| 144 "www.google.com", | |
| 145 "path", | |
| 146 "/", | |
| 147 "version", | |
| 148 "HTTP/1.1", | |
| 149 }; | |
| 150 scoped_ptr<spdy::SpdyFrame> req( | |
| 151 ConstructSpdyPacket( | |
| 152 kSynStartHeader, NULL, 0, kGetHeaders, arraysize(kGetHeaders) / 2)); | |
| 153 scoped_ptr<spdy::SpdyFrame> msg( | |
| 154 ConstructSpdyBodyFrame("\0hello!\xff", 8)); | |
| 155 MockWrite writes[] = { | |
| 156 CreateMockWrite(*req), | |
| 157 CreateMockWrite(*msg), | |
| 158 }; | |
| 159 writes[0].sequence_number = 0; | |
| 160 writes[1].sequence_number = 2; | |
| 161 | |
| 162 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 163 scoped_ptr<spdy::SpdyFrame> echo( | |
| 164 ConstructSpdyBodyFrame("\0hello!\xff", 8)); | |
| 165 MockRead reads[] = { | |
| 166 CreateMockRead(*resp), | |
| 167 CreateMockRead(*echo), | |
| 168 MockRead(ASYNC, 0, 0), // EOF | |
| 169 }; | |
| 170 reads[0].sequence_number = 1; | |
| 171 reads[1].sequence_number = 3; | |
| 172 reads[2].sequence_number = 4; | |
| 173 | |
| 174 scoped_ptr<OrderedSocketData> data( | |
| 175 new OrderedSocketData(reads, arraysize(reads), | |
| 176 writes, arraysize(writes))); | |
| 177 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 178 data->set_connect_data(connect_data); | |
| 179 | |
| 180 session_deps.socket_factory->AddSocketDataProvider(data.get()); | |
| 181 SpdySession::SetSSLMode(false); | |
| 182 | |
| 183 scoped_refptr<SpdySession> session(CreateSpdySession()); | |
| 184 const char* kStreamUrl = "http://www.google.com/"; | |
| 185 GURL url(kStreamUrl); | |
| 186 | |
| 187 HostPortPair host_port_pair("www.google.com", 80); | |
| 188 scoped_refptr<TransportSocketParams> transport_params( | |
| 189 new TransportSocketParams(host_port_pair, LOWEST, false, false)); | |
| 190 | |
| 191 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); | |
| 192 EXPECT_EQ(OK, connection->Init(host_port_pair.ToString(), transport_params, | |
| 193 LOWEST, CompletionCallback(), | |
| 194 session_->GetTransportSocketPool(), | |
| 195 BoundNetLog())); | |
| 196 session->InitializeWithSocket(connection.release(), false, OK); | |
| 197 | |
| 198 scoped_refptr<SpdyStream> stream; | |
| 199 ASSERT_EQ( | |
| 200 OK, | |
| 201 session->CreateStream(url, LOWEST, &stream, BoundNetLog(), | |
| 202 CompletionCallback())); | |
| 203 scoped_refptr<IOBufferWithSize> buf(new IOBufferWithSize(8)); | |
| 204 memcpy(buf->data(), "\0hello!\xff", 8); | |
| 205 TestCompletionCallback callback; | |
| 206 | |
| 207 scoped_ptr<TestSpdyStreamDelegate> delegate( | |
| 208 new TestSpdyStreamDelegate(stream.get(), buf.get(), callback.callback())); | |
| 209 stream->SetDelegate(delegate.get()); | |
| 210 | |
| 211 EXPECT_FALSE(stream->HasUrl()); | |
| 212 | |
| 213 linked_ptr<spdy::SpdyHeaderBlock> headers(new spdy::SpdyHeaderBlock); | |
| 214 (*headers)["method"] = "GET"; | |
| 215 (*headers)["scheme"] = url.scheme(); | |
| 216 (*headers)["host"] = url.host(); | |
| 217 (*headers)["path"] = url.path(); | |
| 218 (*headers)["version"] = "HTTP/1.1"; | |
| 219 stream->set_spdy_headers(headers); | |
| 220 EXPECT_TRUE(stream->HasUrl()); | |
| 221 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec()); | |
| 222 | |
| 223 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequest(true)); | |
| 224 | |
| 225 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 226 | |
| 227 EXPECT_TRUE(delegate->send_headers_completed()); | |
| 228 EXPECT_EQ("200", (*delegate->response())["status"]); | |
| 229 EXPECT_EQ("HTTP/1.1", (*delegate->response())["version"]); | |
| 230 EXPECT_EQ(std::string("\0hello!\xff", 8), delegate->received_data()); | |
| 231 EXPECT_EQ(8, delegate->data_sent()); | |
| 232 EXPECT_TRUE(delegate->closed()); | |
| 233 } | |
| 234 | |
| 235 TEST_F(SpdyStreamTest, PushedStream) { | |
| 236 const char kStreamUrl[] = "http://www.google.com/"; | |
| 237 | |
| 238 SpdySessionDependencies session_deps; | |
| 239 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps); | |
| 240 SpdySessionPoolPeer pool_peer_(session_->spdy_session_pool()); | |
| 241 scoped_refptr<SpdySession> spdy_session(CreateSpdySession()); | |
| 242 BoundNetLog net_log; | |
| 243 | |
| 244 // Conjure up a stream. | |
| 245 scoped_refptr<SpdyStream> stream = new SpdyStream(spdy_session, | |
| 246 2, | |
| 247 true, | |
| 248 net_log); | |
| 249 EXPECT_FALSE(stream->response_received()); | |
| 250 EXPECT_FALSE(stream->HasUrl()); | |
| 251 | |
| 252 // Set a couple of headers. | |
| 253 spdy::SpdyHeaderBlock response; | |
| 254 response["url"] = kStreamUrl; | |
| 255 stream->OnResponseReceived(response); | |
| 256 | |
| 257 // Send some basic headers. | |
| 258 spdy::SpdyHeaderBlock headers; | |
| 259 response["status"] = "200"; | |
| 260 response["version"] = "OK"; | |
| 261 stream->OnHeaders(headers); | |
| 262 | |
| 263 stream->set_response_received(); | |
| 264 EXPECT_TRUE(stream->response_received()); | |
| 265 EXPECT_TRUE(stream->HasUrl()); | |
| 266 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec()); | |
| 267 } | |
| 268 | |
| 269 TEST_F(SpdyStreamTest, StreamError) { | |
| 270 SpdySessionDependencies session_deps; | |
| 271 | |
| 272 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps); | |
| 273 SpdySessionPoolPeer pool_peer_(session_->spdy_session_pool()); | |
| 274 | |
| 275 const SpdyHeaderInfo kSynStartHeader = { | |
| 276 spdy::SYN_STREAM, | |
| 277 1, | |
| 278 0, | |
| 279 net::ConvertRequestPriorityToSpdyPriority(LOWEST), | |
| 280 spdy::CONTROL_FLAG_NONE, | |
| 281 false, | |
| 282 spdy::INVALID, | |
| 283 NULL, | |
| 284 0, | |
| 285 spdy::DATA_FLAG_NONE | |
| 286 }; | |
| 287 static const char* const kGetHeaders[] = { | |
| 288 "method", | |
| 289 "GET", | |
| 290 "scheme", | |
| 291 "http", | |
| 292 "host", | |
| 293 "www.google.com", | |
| 294 "path", | |
| 295 "/", | |
| 296 "version", | |
| 297 "HTTP/1.1", | |
| 298 }; | |
| 299 scoped_ptr<spdy::SpdyFrame> req( | |
| 300 ConstructSpdyPacket( | |
| 301 kSynStartHeader, NULL, 0, kGetHeaders, arraysize(kGetHeaders) / 2)); | |
| 302 scoped_ptr<spdy::SpdyFrame> msg( | |
| 303 ConstructSpdyBodyFrame("\0hello!\xff", 8)); | |
| 304 MockWrite writes[] = { | |
| 305 CreateMockWrite(*req), | |
| 306 CreateMockWrite(*msg), | |
| 307 }; | |
| 308 writes[0].sequence_number = 0; | |
| 309 writes[1].sequence_number = 2; | |
| 310 | |
| 311 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 312 scoped_ptr<spdy::SpdyFrame> echo( | |
| 313 ConstructSpdyBodyFrame("\0hello!\xff", 8)); | |
| 314 MockRead reads[] = { | |
| 315 CreateMockRead(*resp), | |
| 316 CreateMockRead(*echo), | |
| 317 MockRead(ASYNC, 0, 0), // EOF | |
| 318 }; | |
| 319 reads[0].sequence_number = 1; | |
| 320 reads[1].sequence_number = 3; | |
| 321 reads[2].sequence_number = 4; | |
| 322 | |
| 323 net::CapturingBoundNetLog log(net::CapturingNetLog::kUnbounded); | |
| 324 | |
| 325 scoped_ptr<OrderedSocketData> data( | |
| 326 new OrderedSocketData(reads, arraysize(reads), | |
| 327 writes, arraysize(writes))); | |
| 328 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 329 data->set_connect_data(connect_data); | |
| 330 | |
| 331 session_deps.socket_factory->AddSocketDataProvider(data.get()); | |
| 332 SpdySession::SetSSLMode(false); | |
| 333 | |
| 334 scoped_refptr<SpdySession> session(CreateSpdySession()); | |
| 335 const char* kStreamUrl = "http://www.google.com/"; | |
| 336 GURL url(kStreamUrl); | |
| 337 | |
| 338 HostPortPair host_port_pair("www.google.com", 80); | |
| 339 scoped_refptr<TransportSocketParams> transport_params( | |
| 340 new TransportSocketParams(host_port_pair, LOWEST, false, false)); | |
| 341 | |
| 342 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); | |
| 343 EXPECT_EQ(OK, connection->Init(host_port_pair.ToString(), transport_params, | |
| 344 LOWEST, CompletionCallback(), | |
| 345 session_->GetTransportSocketPool(), | |
| 346 log.bound())); | |
| 347 session->InitializeWithSocket(connection.release(), false, OK); | |
| 348 | |
| 349 scoped_refptr<SpdyStream> stream; | |
| 350 ASSERT_EQ( | |
| 351 OK, | |
| 352 session->CreateStream(url, LOWEST, &stream, log.bound(), | |
| 353 CompletionCallback())); | |
| 354 scoped_refptr<IOBufferWithSize> buf(new IOBufferWithSize(8)); | |
| 355 memcpy(buf->data(), "\0hello!\xff", 8); | |
| 356 TestCompletionCallback callback; | |
| 357 | |
| 358 scoped_ptr<TestSpdyStreamDelegate> delegate( | |
| 359 new TestSpdyStreamDelegate(stream.get(), buf.get(), callback.callback())); | |
| 360 stream->SetDelegate(delegate.get()); | |
| 361 | |
| 362 EXPECT_FALSE(stream->HasUrl()); | |
| 363 | |
| 364 linked_ptr<spdy::SpdyHeaderBlock> headers(new spdy::SpdyHeaderBlock); | |
| 365 (*headers)["method"] = "GET"; | |
| 366 (*headers)["scheme"] = url.scheme(); | |
| 367 (*headers)["host"] = url.host(); | |
| 368 (*headers)["path"] = url.path(); | |
| 369 (*headers)["version"] = "HTTP/1.1"; | |
| 370 stream->set_spdy_headers(headers); | |
| 371 EXPECT_TRUE(stream->HasUrl()); | |
| 372 EXPECT_EQ(kStreamUrl, stream->GetUrl().spec()); | |
| 373 | |
| 374 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequest(true)); | |
| 375 | |
| 376 const spdy::SpdyStreamId stream_id = stream->stream_id(); | |
| 377 | |
| 378 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 379 | |
| 380 EXPECT_TRUE(delegate->send_headers_completed()); | |
| 381 EXPECT_EQ("200", (*delegate->response())["status"]); | |
| 382 EXPECT_EQ("HTTP/1.1", (*delegate->response())["version"]); | |
| 383 EXPECT_EQ(std::string("\0hello!\xff", 8), delegate->received_data()); | |
| 384 EXPECT_EQ(8, delegate->data_sent()); | |
| 385 EXPECT_TRUE(delegate->closed()); | |
| 386 | |
| 387 // Check that the NetLog was filled reasonably. | |
| 388 net::CapturingNetLog::EntryList entries; | |
| 389 log.GetEntries(&entries); | |
| 390 EXPECT_LT(0u, entries.size()); | |
| 391 | |
| 392 // Check that we logged SPDY_STREAM_ERROR correctly. | |
| 393 int pos = net::ExpectLogContainsSomewhere( | |
| 394 entries, 0, | |
| 395 net::NetLog::TYPE_SPDY_STREAM_ERROR, | |
| 396 net::NetLog::PHASE_NONE); | |
| 397 | |
| 398 CapturingNetLog::Entry entry = entries[pos]; | |
| 399 NetLogSpdyStreamErrorParameter* request_params = | |
| 400 static_cast<NetLogSpdyStreamErrorParameter*>( | |
| 401 entry.extra_parameters.get()); | |
| 402 EXPECT_EQ(stream_id, request_params->stream_id()); | |
| 403 } | |
| 404 | |
| 405 } // namespace net | |
| OLD | NEW |