| 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 "net/spdy/spdy_proxy_client_socket.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/bind_helpers.h" | |
| 9 #include "base/strings/utf_string_conversions.h" | |
| 10 #include "net/base/address_list.h" | |
| 11 #include "net/base/capturing_net_log.h" | |
| 12 #include "net/base/net_log.h" | |
| 13 #include "net/base/net_log_unittest.h" | |
| 14 #include "net/base/test_completion_callback.h" | |
| 15 #include "net/base/winsock_init.h" | |
| 16 #include "net/dns/mock_host_resolver.h" | |
| 17 #include "net/http/http_response_headers.h" | |
| 18 #include "net/http/http_response_info.h" | |
| 19 #include "net/socket/client_socket_factory.h" | |
| 20 #include "net/socket/next_proto.h" | |
| 21 #include "net/socket/socket_test_util.h" | |
| 22 #include "net/socket/tcp_client_socket.h" | |
| 23 #include "net/spdy/buffered_spdy_framer.h" | |
| 24 #include "net/spdy/spdy_http_utils.h" | |
| 25 #include "net/spdy/spdy_protocol.h" | |
| 26 #include "net/spdy/spdy_session_pool.h" | |
| 27 #include "net/spdy/spdy_test_util_common.h" | |
| 28 #include "testing/gtest/include/gtest/gtest.h" | |
| 29 #include "testing/platform_test.h" | |
| 30 | |
| 31 //----------------------------------------------------------------------------- | |
| 32 | |
| 33 namespace { | |
| 34 | |
| 35 static const char kRequestUrl[] = "https://www.google.com/"; | |
| 36 static const char kOriginHost[] = "www.google.com"; | |
| 37 static const int kOriginPort = 443; | |
| 38 static const char kOriginHostPort[] = "www.google.com:443"; | |
| 39 static const char kProxyUrl[] = "https://myproxy:6121/"; | |
| 40 static const char kProxyHost[] = "myproxy"; | |
| 41 static const int kProxyPort = 6121; | |
| 42 static const char kUserAgent[] = "Mozilla/1.0"; | |
| 43 | |
| 44 static const int kStreamId = 1; | |
| 45 | |
| 46 static const char kMsg1[] = "\0hello!\xff"; | |
| 47 static const int kLen1 = 8; | |
| 48 static const char kMsg2[] = "\0a2345678\0"; | |
| 49 static const int kLen2 = 10; | |
| 50 static const char kMsg3[] = "bye!"; | |
| 51 static const int kLen3 = 4; | |
| 52 static const char kMsg33[] = "bye!bye!"; | |
| 53 static const int kLen33 = kLen3 + kLen3; | |
| 54 static const char kMsg333[] = "bye!bye!bye!"; | |
| 55 static const int kLen333 = kLen3 + kLen3 + kLen3; | |
| 56 | |
| 57 static const char kRedirectUrl[] = "https://example.com/"; | |
| 58 | |
| 59 } // anonymous namespace | |
| 60 | |
| 61 namespace net { | |
| 62 | |
| 63 class SpdyProxyClientSocketTest | |
| 64 : public PlatformTest, | |
| 65 public testing::WithParamInterface<NextProto> { | |
| 66 public: | |
| 67 SpdyProxyClientSocketTest(); | |
| 68 | |
| 69 void TearDown() override; | |
| 70 | |
| 71 protected: | |
| 72 void Initialize(MockRead* reads, size_t reads_count, MockWrite* writes, | |
| 73 size_t writes_count); | |
| 74 void PopulateConnectRequestIR(SpdyHeaderBlock* syn_ir); | |
| 75 void PopulateConnectReplyIR(SpdyHeaderBlock* block, const char* status); | |
| 76 SpdyFrame* ConstructConnectRequestFrame(); | |
| 77 SpdyFrame* ConstructConnectAuthRequestFrame(); | |
| 78 SpdyFrame* ConstructConnectReplyFrame(); | |
| 79 SpdyFrame* ConstructConnectAuthReplyFrame(); | |
| 80 SpdyFrame* ConstructConnectRedirectReplyFrame(); | |
| 81 SpdyFrame* ConstructConnectErrorReplyFrame(); | |
| 82 SpdyFrame* ConstructBodyFrame(const char* data, int length); | |
| 83 scoped_refptr<IOBufferWithSize> CreateBuffer(const char* data, int size); | |
| 84 void AssertConnectSucceeds(); | |
| 85 void AssertConnectFails(int result); | |
| 86 void AssertConnectionEstablished(); | |
| 87 void AssertSyncReadEquals(const char* data, int len); | |
| 88 void AssertAsyncReadEquals(const char* data, int len); | |
| 89 void AssertReadStarts(const char* data, int len); | |
| 90 void AssertReadReturns(const char* data, int len); | |
| 91 void AssertAsyncWriteSucceeds(const char* data, int len); | |
| 92 void AssertWriteReturns(const char* data, int len, int rv); | |
| 93 void AssertWriteLength(int len); | |
| 94 void AssertAsyncWriteWithReadsSucceeds(const char* data, int len, | |
| 95 int num_reads); | |
| 96 | |
| 97 void AddAuthToCache() { | |
| 98 const base::string16 kFoo(base::ASCIIToUTF16("foo")); | |
| 99 const base::string16 kBar(base::ASCIIToUTF16("bar")); | |
| 100 session_->http_auth_cache()->Add(GURL(kProxyUrl), | |
| 101 "MyRealm1", | |
| 102 HttpAuth::AUTH_SCHEME_BASIC, | |
| 103 "Basic realm=MyRealm1", | |
| 104 AuthCredentials(kFoo, kBar), | |
| 105 "/"); | |
| 106 } | |
| 107 | |
| 108 void Run(int steps) { | |
| 109 data_->StopAfter(steps); | |
| 110 data_->Run(); | |
| 111 } | |
| 112 | |
| 113 void CloseSpdySession(net::Error error, const std::string& description) { | |
| 114 spdy_session_->CloseSessionOnError(error, description); | |
| 115 } | |
| 116 | |
| 117 SpdyTestUtil spdy_util_; | |
| 118 scoped_ptr<SpdyProxyClientSocket> sock_; | |
| 119 TestCompletionCallback read_callback_; | |
| 120 TestCompletionCallback write_callback_; | |
| 121 scoped_ptr<DeterministicSocketData> data_; | |
| 122 CapturingBoundNetLog net_log_; | |
| 123 | |
| 124 private: | |
| 125 scoped_refptr<HttpNetworkSession> session_; | |
| 126 scoped_refptr<IOBuffer> read_buf_; | |
| 127 SpdySessionDependencies session_deps_; | |
| 128 MockConnect connect_data_; | |
| 129 base::WeakPtr<SpdySession> spdy_session_; | |
| 130 BufferedSpdyFramer framer_; | |
| 131 | |
| 132 std::string user_agent_; | |
| 133 GURL url_; | |
| 134 HostPortPair proxy_host_port_; | |
| 135 HostPortPair endpoint_host_port_pair_; | |
| 136 ProxyServer proxy_; | |
| 137 SpdySessionKey endpoint_spdy_session_key_; | |
| 138 | |
| 139 DISALLOW_COPY_AND_ASSIGN(SpdyProxyClientSocketTest); | |
| 140 }; | |
| 141 | |
| 142 INSTANTIATE_TEST_CASE_P( | |
| 143 NextProto, | |
| 144 SpdyProxyClientSocketTest, | |
| 145 testing::Values(kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15)); | |
| 146 | |
| 147 SpdyProxyClientSocketTest::SpdyProxyClientSocketTest() | |
| 148 : spdy_util_(GetParam()), | |
| 149 session_(NULL), | |
| 150 read_buf_(NULL), | |
| 151 session_deps_(GetParam()), | |
| 152 connect_data_(SYNCHRONOUS, OK), | |
| 153 framer_(spdy_util_.spdy_version(), false), | |
| 154 user_agent_(kUserAgent), | |
| 155 url_(kRequestUrl), | |
| 156 proxy_host_port_(kProxyHost, kProxyPort), | |
| 157 endpoint_host_port_pair_(kOriginHost, kOriginPort), | |
| 158 proxy_(ProxyServer::SCHEME_HTTPS, proxy_host_port_), | |
| 159 endpoint_spdy_session_key_(endpoint_host_port_pair_, | |
| 160 proxy_, | |
| 161 PRIVACY_MODE_DISABLED) { | |
| 162 session_deps_.net_log = net_log_.bound().net_log(); | |
| 163 } | |
| 164 | |
| 165 void SpdyProxyClientSocketTest::TearDown() { | |
| 166 if (session_.get() != NULL) | |
| 167 session_->spdy_session_pool()->CloseAllSessions(); | |
| 168 | |
| 169 // Empty the current queue. | |
| 170 base::MessageLoop::current()->RunUntilIdle(); | |
| 171 PlatformTest::TearDown(); | |
| 172 } | |
| 173 | |
| 174 void SpdyProxyClientSocketTest::Initialize(MockRead* reads, | |
| 175 size_t reads_count, | |
| 176 MockWrite* writes, | |
| 177 size_t writes_count) { | |
| 178 data_.reset(new DeterministicSocketData(reads, reads_count, | |
| 179 writes, writes_count)); | |
| 180 data_->set_connect_data(connect_data_); | |
| 181 data_->SetStop(2); | |
| 182 | |
| 183 session_deps_.deterministic_socket_factory->AddSocketDataProvider( | |
| 184 data_.get()); | |
| 185 session_deps_.host_resolver->set_synchronous_mode(true); | |
| 186 | |
| 187 session_ = SpdySessionDependencies::SpdyCreateSessionDeterministic( | |
| 188 &session_deps_); | |
| 189 | |
| 190 // Creates the SPDY session and stream. | |
| 191 spdy_session_ = | |
| 192 CreateInsecureSpdySession( | |
| 193 session_, endpoint_spdy_session_key_, BoundNetLog()); | |
| 194 base::WeakPtr<SpdyStream> spdy_stream( | |
| 195 CreateStreamSynchronously( | |
| 196 SPDY_BIDIRECTIONAL_STREAM, spdy_session_, url_, LOWEST, | |
| 197 net_log_.bound())); | |
| 198 ASSERT_TRUE(spdy_stream.get() != NULL); | |
| 199 | |
| 200 // Create the SpdyProxyClientSocket. | |
| 201 sock_.reset( | |
| 202 new SpdyProxyClientSocket(spdy_stream, user_agent_, | |
| 203 endpoint_host_port_pair_, url_, | |
| 204 proxy_host_port_, net_log_.bound(), | |
| 205 session_->http_auth_cache(), | |
| 206 session_->http_auth_handler_factory())); | |
| 207 } | |
| 208 | |
| 209 scoped_refptr<IOBufferWithSize> SpdyProxyClientSocketTest::CreateBuffer( | |
| 210 const char* data, int size) { | |
| 211 scoped_refptr<IOBufferWithSize> buf(new IOBufferWithSize(size)); | |
| 212 memcpy(buf->data(), data, size); | |
| 213 return buf; | |
| 214 } | |
| 215 | |
| 216 void SpdyProxyClientSocketTest::AssertConnectSucceeds() { | |
| 217 ASSERT_EQ(ERR_IO_PENDING, sock_->Connect(read_callback_.callback())); | |
| 218 data_->Run(); | |
| 219 ASSERT_EQ(OK, read_callback_.WaitForResult()); | |
| 220 } | |
| 221 | |
| 222 void SpdyProxyClientSocketTest::AssertConnectFails(int result) { | |
| 223 ASSERT_EQ(ERR_IO_PENDING, sock_->Connect(read_callback_.callback())); | |
| 224 data_->Run(); | |
| 225 ASSERT_EQ(result, read_callback_.WaitForResult()); | |
| 226 } | |
| 227 | |
| 228 void SpdyProxyClientSocketTest::AssertConnectionEstablished() { | |
| 229 const HttpResponseInfo* response = sock_->GetConnectResponseInfo(); | |
| 230 ASSERT_TRUE(response != NULL); | |
| 231 ASSERT_EQ(200, response->headers->response_code()); | |
| 232 } | |
| 233 | |
| 234 void SpdyProxyClientSocketTest::AssertSyncReadEquals(const char* data, | |
| 235 int len) { | |
| 236 scoped_refptr<IOBuffer> buf(new IOBuffer(len)); | |
| 237 ASSERT_EQ(len, sock_->Read(buf.get(), len, CompletionCallback())); | |
| 238 ASSERT_EQ(std::string(data, len), std::string(buf->data(), len)); | |
| 239 ASSERT_TRUE(sock_->IsConnected()); | |
| 240 } | |
| 241 | |
| 242 void SpdyProxyClientSocketTest::AssertAsyncReadEquals(const char* data, | |
| 243 int len) { | |
| 244 data_->StopAfter(1); | |
| 245 // Issue the read, which will be completed asynchronously | |
| 246 scoped_refptr<IOBuffer> buf(new IOBuffer(len)); | |
| 247 ASSERT_EQ(ERR_IO_PENDING, | |
| 248 sock_->Read(buf.get(), len, read_callback_.callback())); | |
| 249 EXPECT_TRUE(sock_->IsConnected()); | |
| 250 data_->Run(); | |
| 251 | |
| 252 EXPECT_TRUE(sock_->IsConnected()); | |
| 253 | |
| 254 // Now the read will return | |
| 255 EXPECT_EQ(len, read_callback_.WaitForResult()); | |
| 256 ASSERT_EQ(std::string(data, len), std::string(buf->data(), len)); | |
| 257 } | |
| 258 | |
| 259 void SpdyProxyClientSocketTest::AssertReadStarts(const char* data, | |
| 260 int len) { | |
| 261 data_->StopAfter(1); | |
| 262 // Issue the read, which will be completed asynchronously | |
| 263 read_buf_ = new IOBuffer(len); | |
| 264 ASSERT_EQ(ERR_IO_PENDING, | |
| 265 sock_->Read(read_buf_.get(), len, read_callback_.callback())); | |
| 266 EXPECT_TRUE(sock_->IsConnected()); | |
| 267 } | |
| 268 | |
| 269 void SpdyProxyClientSocketTest::AssertReadReturns(const char* data, | |
| 270 int len) { | |
| 271 EXPECT_TRUE(sock_->IsConnected()); | |
| 272 | |
| 273 // Now the read will return | |
| 274 EXPECT_EQ(len, read_callback_.WaitForResult()); | |
| 275 ASSERT_EQ(std::string(data, len), std::string(read_buf_->data(), len)); | |
| 276 } | |
| 277 | |
| 278 void SpdyProxyClientSocketTest::AssertAsyncWriteSucceeds(const char* data, | |
| 279 int len) { | |
| 280 AssertWriteReturns(data, len, ERR_IO_PENDING); | |
| 281 data_->RunFor(1); | |
| 282 AssertWriteLength(len); | |
| 283 } | |
| 284 | |
| 285 void SpdyProxyClientSocketTest::AssertWriteReturns(const char* data, | |
| 286 int len, | |
| 287 int rv) { | |
| 288 scoped_refptr<IOBufferWithSize> buf(CreateBuffer(data, len)); | |
| 289 EXPECT_EQ(rv, | |
| 290 sock_->Write(buf.get(), buf->size(), write_callback_.callback())); | |
| 291 } | |
| 292 | |
| 293 void SpdyProxyClientSocketTest::AssertWriteLength(int len) { | |
| 294 EXPECT_EQ(len, write_callback_.WaitForResult()); | |
| 295 } | |
| 296 | |
| 297 void SpdyProxyClientSocketTest::AssertAsyncWriteWithReadsSucceeds( | |
| 298 const char* data, int len, int num_reads) { | |
| 299 scoped_refptr<IOBufferWithSize> buf(CreateBuffer(data, len)); | |
| 300 | |
| 301 EXPECT_EQ(ERR_IO_PENDING, | |
| 302 sock_->Write(buf.get(), buf->size(), write_callback_.callback())); | |
| 303 | |
| 304 for (int i = 0; i < num_reads; i++) { | |
| 305 Run(1); | |
| 306 AssertSyncReadEquals(kMsg2, kLen2); | |
| 307 } | |
| 308 | |
| 309 write_callback_.WaitForResult(); | |
| 310 } | |
| 311 | |
| 312 void SpdyProxyClientSocketTest::PopulateConnectRequestIR( | |
| 313 SpdyHeaderBlock* block) { | |
| 314 (*block)[spdy_util_.GetMethodKey()] = "CONNECT"; | |
| 315 (*block)[spdy_util_.GetPathKey()] = kOriginHostPort; | |
| 316 (*block)[spdy_util_.GetHostKey()] = kOriginHost; | |
| 317 (*block)["user-agent"] = kUserAgent; | |
| 318 spdy_util_.MaybeAddVersionHeader(block); | |
| 319 } | |
| 320 | |
| 321 void SpdyProxyClientSocketTest::PopulateConnectReplyIR(SpdyHeaderBlock* block, | |
| 322 const char* status) { | |
| 323 (*block)[spdy_util_.GetStatusKey()] = status; | |
| 324 spdy_util_.MaybeAddVersionHeader(block); | |
| 325 } | |
| 326 | |
| 327 // Constructs a standard SPDY SYN_STREAM frame for a CONNECT request. | |
| 328 SpdyFrame* | |
| 329 SpdyProxyClientSocketTest::ConstructConnectRequestFrame() { | |
| 330 SpdyHeaderBlock block; | |
| 331 PopulateConnectRequestIR(&block); | |
| 332 return spdy_util_.ConstructSpdySyn(kStreamId, block, LOWEST, false, false); | |
| 333 } | |
| 334 | |
| 335 // Constructs a SPDY SYN_STREAM frame for a CONNECT request which includes | |
| 336 // Proxy-Authorization headers. | |
| 337 SpdyFrame* SpdyProxyClientSocketTest::ConstructConnectAuthRequestFrame() { | |
| 338 SpdyHeaderBlock block; | |
| 339 PopulateConnectRequestIR(&block); | |
| 340 block["proxy-authorization"] = "Basic Zm9vOmJhcg=="; | |
| 341 return spdy_util_.ConstructSpdySyn(kStreamId, block, LOWEST, false, false); | |
| 342 } | |
| 343 | |
| 344 // Constructs a standard SPDY SYN_REPLY frame to match the SPDY CONNECT. | |
| 345 SpdyFrame* SpdyProxyClientSocketTest::ConstructConnectReplyFrame() { | |
| 346 SpdyHeaderBlock block; | |
| 347 PopulateConnectReplyIR(&block, "200"); | |
| 348 SpdySynReplyIR reply_ir(kStreamId); | |
| 349 return spdy_util_.ConstructSpdyReply(kStreamId, block); | |
| 350 } | |
| 351 | |
| 352 // Constructs a standard SPDY SYN_REPLY frame to match the SPDY CONNECT, | |
| 353 // including Proxy-Authenticate headers. | |
| 354 SpdyFrame* SpdyProxyClientSocketTest::ConstructConnectAuthReplyFrame() { | |
| 355 SpdyHeaderBlock block; | |
| 356 PopulateConnectReplyIR(&block, "407"); | |
| 357 block["proxy-authenticate"] = "Basic realm=\"MyRealm1\""; | |
| 358 return spdy_util_.ConstructSpdyReply(kStreamId, block); | |
| 359 } | |
| 360 | |
| 361 // Constructs a SPDY SYN_REPLY frame with an HTTP 302 redirect. | |
| 362 SpdyFrame* SpdyProxyClientSocketTest::ConstructConnectRedirectReplyFrame() { | |
| 363 SpdyHeaderBlock block; | |
| 364 PopulateConnectReplyIR(&block, "302"); | |
| 365 block["location"] = kRedirectUrl; | |
| 366 block["set-cookie"] = "foo=bar"; | |
| 367 return spdy_util_.ConstructSpdyReply(kStreamId, block); | |
| 368 } | |
| 369 | |
| 370 // Constructs a SPDY SYN_REPLY frame with an HTTP 500 error. | |
| 371 SpdyFrame* SpdyProxyClientSocketTest::ConstructConnectErrorReplyFrame() { | |
| 372 SpdyHeaderBlock block; | |
| 373 PopulateConnectReplyIR(&block, "500"); | |
| 374 return spdy_util_.ConstructSpdyReply(kStreamId, block); | |
| 375 } | |
| 376 | |
| 377 SpdyFrame* SpdyProxyClientSocketTest::ConstructBodyFrame( | |
| 378 const char* data, | |
| 379 int length) { | |
| 380 return framer_.CreateDataFrame(kStreamId, data, length, DATA_FLAG_NONE); | |
| 381 } | |
| 382 | |
| 383 // ----------- Connect | |
| 384 | |
| 385 TEST_P(SpdyProxyClientSocketTest, ConnectSendsCorrectRequest) { | |
| 386 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 387 MockWrite writes[] = { | |
| 388 CreateMockWrite(*conn, 0, SYNCHRONOUS), | |
| 389 }; | |
| 390 | |
| 391 scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame()); | |
| 392 MockRead reads[] = { | |
| 393 CreateMockRead(*resp, 1, ASYNC), | |
| 394 MockRead(ASYNC, 0, 2), // EOF | |
| 395 }; | |
| 396 | |
| 397 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 398 | |
| 399 ASSERT_FALSE(sock_->IsConnected()); | |
| 400 | |
| 401 AssertConnectSucceeds(); | |
| 402 | |
| 403 AssertConnectionEstablished(); | |
| 404 } | |
| 405 | |
| 406 TEST_P(SpdyProxyClientSocketTest, ConnectWithAuthRequested) { | |
| 407 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 408 MockWrite writes[] = { | |
| 409 CreateMockWrite(*conn, 0, SYNCHRONOUS), | |
| 410 }; | |
| 411 | |
| 412 scoped_ptr<SpdyFrame> resp(ConstructConnectAuthReplyFrame()); | |
| 413 MockRead reads[] = { | |
| 414 CreateMockRead(*resp, 1, ASYNC), | |
| 415 MockRead(ASYNC, 0, 2), // EOF | |
| 416 }; | |
| 417 | |
| 418 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 419 | |
| 420 AssertConnectFails(ERR_PROXY_AUTH_REQUESTED); | |
| 421 | |
| 422 const HttpResponseInfo* response = sock_->GetConnectResponseInfo(); | |
| 423 ASSERT_TRUE(response != NULL); | |
| 424 ASSERT_EQ(407, response->headers->response_code()); | |
| 425 } | |
| 426 | |
| 427 TEST_P(SpdyProxyClientSocketTest, ConnectWithAuthCredentials) { | |
| 428 scoped_ptr<SpdyFrame> conn(ConstructConnectAuthRequestFrame()); | |
| 429 MockWrite writes[] = { | |
| 430 CreateMockWrite(*conn, 0, SYNCHRONOUS), | |
| 431 }; | |
| 432 | |
| 433 scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame()); | |
| 434 MockRead reads[] = { | |
| 435 CreateMockRead(*resp, 1, ASYNC), | |
| 436 MockRead(ASYNC, 0, 2), // EOF | |
| 437 }; | |
| 438 | |
| 439 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 440 AddAuthToCache(); | |
| 441 | |
| 442 AssertConnectSucceeds(); | |
| 443 | |
| 444 AssertConnectionEstablished(); | |
| 445 } | |
| 446 | |
| 447 TEST_P(SpdyProxyClientSocketTest, ConnectRedirects) { | |
| 448 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 449 scoped_ptr<SpdyFrame> rst( | |
| 450 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL)); | |
| 451 MockWrite writes[] = { | |
| 452 CreateMockWrite(*conn, 0, SYNCHRONOUS), CreateMockWrite(*rst, 2), | |
| 453 }; | |
| 454 | |
| 455 scoped_ptr<SpdyFrame> resp(ConstructConnectRedirectReplyFrame()); | |
| 456 MockRead reads[] = { | |
| 457 CreateMockRead(*resp, 1, ASYNC), MockRead(ASYNC, 0, 3), // EOF | |
| 458 }; | |
| 459 | |
| 460 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 461 | |
| 462 AssertConnectFails(ERR_HTTPS_PROXY_TUNNEL_RESPONSE); | |
| 463 | |
| 464 const HttpResponseInfo* response = sock_->GetConnectResponseInfo(); | |
| 465 ASSERT_TRUE(response != NULL); | |
| 466 | |
| 467 const HttpResponseHeaders* headers = response->headers.get(); | |
| 468 ASSERT_EQ(302, headers->response_code()); | |
| 469 ASSERT_FALSE(headers->HasHeader("set-cookie")); | |
| 470 ASSERT_TRUE(headers->HasHeaderValue("content-length", "0")); | |
| 471 | |
| 472 std::string location; | |
| 473 ASSERT_TRUE(headers->IsRedirect(&location)); | |
| 474 ASSERT_EQ(location, kRedirectUrl); | |
| 475 | |
| 476 // Let the RST_STREAM write while |rst| is in-scope. | |
| 477 base::MessageLoop::current()->RunUntilIdle(); | |
| 478 } | |
| 479 | |
| 480 TEST_P(SpdyProxyClientSocketTest, ConnectFails) { | |
| 481 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 482 MockWrite writes[] = { | |
| 483 CreateMockWrite(*conn, 0, SYNCHRONOUS), | |
| 484 }; | |
| 485 | |
| 486 scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame()); | |
| 487 MockRead reads[] = { | |
| 488 MockRead(ASYNC, 0, 1), // EOF | |
| 489 }; | |
| 490 | |
| 491 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 492 | |
| 493 ASSERT_FALSE(sock_->IsConnected()); | |
| 494 | |
| 495 AssertConnectFails(ERR_CONNECTION_CLOSED); | |
| 496 | |
| 497 ASSERT_FALSE(sock_->IsConnected()); | |
| 498 } | |
| 499 | |
| 500 // ----------- WasEverUsed | |
| 501 | |
| 502 TEST_P(SpdyProxyClientSocketTest, WasEverUsedReturnsCorrectValues) { | |
| 503 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 504 scoped_ptr<SpdyFrame> rst( | |
| 505 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL)); | |
| 506 MockWrite writes[] = { | |
| 507 CreateMockWrite(*conn, 0, SYNCHRONOUS), CreateMockWrite(*rst, 2), | |
| 508 }; | |
| 509 | |
| 510 scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame()); | |
| 511 MockRead reads[] = { | |
| 512 CreateMockRead(*resp, 1, ASYNC), MockRead(ASYNC, 0, 3), // EOF | |
| 513 }; | |
| 514 | |
| 515 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 516 | |
| 517 EXPECT_FALSE(sock_->WasEverUsed()); | |
| 518 AssertConnectSucceeds(); | |
| 519 EXPECT_TRUE(sock_->WasEverUsed()); | |
| 520 sock_->Disconnect(); | |
| 521 EXPECT_TRUE(sock_->WasEverUsed()); | |
| 522 | |
| 523 // Let the RST_STREAM write while |rst| is in-scope. | |
| 524 base::MessageLoop::current()->RunUntilIdle(); | |
| 525 } | |
| 526 | |
| 527 // ----------- GetPeerAddress | |
| 528 | |
| 529 TEST_P(SpdyProxyClientSocketTest, GetPeerAddressReturnsCorrectValues) { | |
| 530 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 531 MockWrite writes[] = { | |
| 532 CreateMockWrite(*conn, 0, SYNCHRONOUS), | |
| 533 }; | |
| 534 | |
| 535 scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame()); | |
| 536 MockRead reads[] = { | |
| 537 CreateMockRead(*resp, 1, ASYNC), | |
| 538 MockRead(ASYNC, 0, 2), // EOF | |
| 539 }; | |
| 540 | |
| 541 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 542 | |
| 543 net::IPEndPoint addr; | |
| 544 EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED, sock_->GetPeerAddress(&addr)); | |
| 545 | |
| 546 AssertConnectSucceeds(); | |
| 547 EXPECT_TRUE(sock_->IsConnected()); | |
| 548 EXPECT_EQ(OK, sock_->GetPeerAddress(&addr)); | |
| 549 | |
| 550 Run(1); | |
| 551 | |
| 552 EXPECT_FALSE(sock_->IsConnected()); | |
| 553 EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED, sock_->GetPeerAddress(&addr)); | |
| 554 | |
| 555 sock_->Disconnect(); | |
| 556 | |
| 557 EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED, sock_->GetPeerAddress(&addr)); | |
| 558 } | |
| 559 | |
| 560 // ----------- Write | |
| 561 | |
| 562 TEST_P(SpdyProxyClientSocketTest, WriteSendsDataInDataFrame) { | |
| 563 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 564 scoped_ptr<SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1)); | |
| 565 scoped_ptr<SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2)); | |
| 566 MockWrite writes[] = { | |
| 567 CreateMockWrite(*conn, 0, SYNCHRONOUS), | |
| 568 CreateMockWrite(*msg1, 2, SYNCHRONOUS), | |
| 569 CreateMockWrite(*msg2, 3, SYNCHRONOUS), | |
| 570 }; | |
| 571 | |
| 572 scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame()); | |
| 573 MockRead reads[] = { | |
| 574 CreateMockRead(*resp, 1, ASYNC), | |
| 575 MockRead(ASYNC, 0, 4), // EOF | |
| 576 }; | |
| 577 | |
| 578 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 579 | |
| 580 AssertConnectSucceeds(); | |
| 581 | |
| 582 AssertAsyncWriteSucceeds(kMsg1, kLen1); | |
| 583 AssertAsyncWriteSucceeds(kMsg2, kLen2); | |
| 584 } | |
| 585 | |
| 586 TEST_P(SpdyProxyClientSocketTest, WriteSplitsLargeDataIntoMultipleFrames) { | |
| 587 std::string chunk_data(kMaxSpdyFrameChunkSize, 'x'); | |
| 588 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 589 scoped_ptr<SpdyFrame> chunk(ConstructBodyFrame(chunk_data.data(), | |
| 590 chunk_data.length())); | |
| 591 MockWrite writes[] = { | |
| 592 CreateMockWrite(*conn, 0, SYNCHRONOUS), | |
| 593 CreateMockWrite(*chunk, 2, SYNCHRONOUS), | |
| 594 CreateMockWrite(*chunk, 3, SYNCHRONOUS), | |
| 595 CreateMockWrite(*chunk, 4, SYNCHRONOUS) | |
| 596 }; | |
| 597 | |
| 598 scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame()); | |
| 599 MockRead reads[] = { | |
| 600 CreateMockRead(*resp, 1, ASYNC), | |
| 601 MockRead(ASYNC, 0, 5), // EOF | |
| 602 }; | |
| 603 | |
| 604 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 605 | |
| 606 AssertConnectSucceeds(); | |
| 607 | |
| 608 std::string big_data(kMaxSpdyFrameChunkSize * 3, 'x'); | |
| 609 scoped_refptr<IOBufferWithSize> buf(CreateBuffer(big_data.data(), | |
| 610 big_data.length())); | |
| 611 | |
| 612 EXPECT_EQ(ERR_IO_PENDING, | |
| 613 sock_->Write(buf.get(), buf->size(), write_callback_.callback())); | |
| 614 data_->RunFor(3); | |
| 615 | |
| 616 EXPECT_EQ(buf->size(), write_callback_.WaitForResult()); | |
| 617 } | |
| 618 | |
| 619 // ----------- Read | |
| 620 | |
| 621 TEST_P(SpdyProxyClientSocketTest, ReadReadsDataInDataFrame) { | |
| 622 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 623 MockWrite writes[] = { | |
| 624 CreateMockWrite(*conn, 0, SYNCHRONOUS), | |
| 625 }; | |
| 626 | |
| 627 scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame()); | |
| 628 scoped_ptr<SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1)); | |
| 629 MockRead reads[] = { | |
| 630 CreateMockRead(*resp, 1, ASYNC), | |
| 631 CreateMockRead(*msg1, 2, ASYNC), | |
| 632 MockRead(ASYNC, 0, 3), // EOF | |
| 633 }; | |
| 634 | |
| 635 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 636 | |
| 637 AssertConnectSucceeds(); | |
| 638 | |
| 639 Run(1); // SpdySession consumes the next read and sends it to | |
| 640 // sock_ to be buffered. | |
| 641 AssertSyncReadEquals(kMsg1, kLen1); | |
| 642 } | |
| 643 | |
| 644 TEST_P(SpdyProxyClientSocketTest, ReadDataFromBufferedFrames) { | |
| 645 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 646 MockWrite writes[] = { | |
| 647 CreateMockWrite(*conn, 0, SYNCHRONOUS), | |
| 648 }; | |
| 649 | |
| 650 scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame()); | |
| 651 scoped_ptr<SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1)); | |
| 652 scoped_ptr<SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2)); | |
| 653 MockRead reads[] = { | |
| 654 CreateMockRead(*resp, 1, ASYNC), | |
| 655 CreateMockRead(*msg1, 2, ASYNC), | |
| 656 CreateMockRead(*msg2, 3, ASYNC), | |
| 657 MockRead(ASYNC, 0, 4), // EOF | |
| 658 }; | |
| 659 | |
| 660 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 661 | |
| 662 AssertConnectSucceeds(); | |
| 663 | |
| 664 Run(1); // SpdySession consumes the next read and sends it to | |
| 665 // sock_ to be buffered. | |
| 666 AssertSyncReadEquals(kMsg1, kLen1); | |
| 667 Run(1); // SpdySession consumes the next read and sends it to | |
| 668 // sock_ to be buffered. | |
| 669 AssertSyncReadEquals(kMsg2, kLen2); | |
| 670 } | |
| 671 | |
| 672 TEST_P(SpdyProxyClientSocketTest, ReadDataMultipleBufferedFrames) { | |
| 673 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 674 MockWrite writes[] = { | |
| 675 CreateMockWrite(*conn, 0, SYNCHRONOUS), | |
| 676 }; | |
| 677 | |
| 678 scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame()); | |
| 679 scoped_ptr<SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1)); | |
| 680 scoped_ptr<SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2)); | |
| 681 MockRead reads[] = { | |
| 682 CreateMockRead(*resp, 1, ASYNC), | |
| 683 CreateMockRead(*msg1, 2, ASYNC), | |
| 684 CreateMockRead(*msg2, 3, ASYNC), | |
| 685 MockRead(ASYNC, 0, 4), // EOF | |
| 686 }; | |
| 687 | |
| 688 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 689 | |
| 690 AssertConnectSucceeds(); | |
| 691 | |
| 692 Run(2); // SpdySession consumes the next two reads and sends then to | |
| 693 // sock_ to be buffered. | |
| 694 AssertSyncReadEquals(kMsg1, kLen1); | |
| 695 AssertSyncReadEquals(kMsg2, kLen2); | |
| 696 } | |
| 697 | |
| 698 TEST_P(SpdyProxyClientSocketTest, | |
| 699 LargeReadWillMergeDataFromDifferentFrames) { | |
| 700 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 701 MockWrite writes[] = { | |
| 702 CreateMockWrite(*conn, 0, SYNCHRONOUS), | |
| 703 }; | |
| 704 | |
| 705 scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame()); | |
| 706 scoped_ptr<SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1)); | |
| 707 scoped_ptr<SpdyFrame> msg3(ConstructBodyFrame(kMsg3, kLen3)); | |
| 708 MockRead reads[] = { | |
| 709 CreateMockRead(*resp, 1, ASYNC), | |
| 710 CreateMockRead(*msg3, 2, ASYNC), | |
| 711 CreateMockRead(*msg3, 3, ASYNC), | |
| 712 MockRead(ASYNC, 0, 4), // EOF | |
| 713 }; | |
| 714 | |
| 715 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 716 | |
| 717 AssertConnectSucceeds(); | |
| 718 | |
| 719 Run(2); // SpdySession consumes the next two reads and sends then to | |
| 720 // sock_ to be buffered. | |
| 721 // The payload from two data frames, each with kMsg3 will be combined | |
| 722 // together into a single read(). | |
| 723 AssertSyncReadEquals(kMsg33, kLen33); | |
| 724 } | |
| 725 | |
| 726 TEST_P(SpdyProxyClientSocketTest, MultipleShortReadsThenMoreRead) { | |
| 727 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 728 MockWrite writes[] = { | |
| 729 CreateMockWrite(*conn, 0, SYNCHRONOUS), | |
| 730 }; | |
| 731 | |
| 732 scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame()); | |
| 733 scoped_ptr<SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1)); | |
| 734 scoped_ptr<SpdyFrame> msg3(ConstructBodyFrame(kMsg3, kLen3)); | |
| 735 scoped_ptr<SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2)); | |
| 736 MockRead reads[] = { | |
| 737 CreateMockRead(*resp, 1, ASYNC), | |
| 738 CreateMockRead(*msg1, 2, ASYNC), | |
| 739 CreateMockRead(*msg3, 3, ASYNC), | |
| 740 CreateMockRead(*msg3, 4, ASYNC), | |
| 741 CreateMockRead(*msg2, 5, ASYNC), | |
| 742 MockRead(ASYNC, 0, 6), // EOF | |
| 743 }; | |
| 744 | |
| 745 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 746 | |
| 747 AssertConnectSucceeds(); | |
| 748 | |
| 749 Run(4); // SpdySession consumes the next four reads and sends then to | |
| 750 // sock_ to be buffered. | |
| 751 AssertSyncReadEquals(kMsg1, kLen1); | |
| 752 // The payload from two data frames, each with kMsg3 will be combined | |
| 753 // together into a single read(). | |
| 754 AssertSyncReadEquals(kMsg33, kLen33); | |
| 755 AssertSyncReadEquals(kMsg2, kLen2); | |
| 756 } | |
| 757 | |
| 758 TEST_P(SpdyProxyClientSocketTest, ReadWillSplitDataFromLargeFrame) { | |
| 759 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 760 MockWrite writes[] = { | |
| 761 CreateMockWrite(*conn, 0, SYNCHRONOUS), | |
| 762 }; | |
| 763 | |
| 764 scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame()); | |
| 765 scoped_ptr<SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1)); | |
| 766 scoped_ptr<SpdyFrame> msg33(ConstructBodyFrame(kMsg33, kLen33)); | |
| 767 scoped_ptr<SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2)); | |
| 768 MockRead reads[] = { | |
| 769 CreateMockRead(*resp, 1, ASYNC), | |
| 770 CreateMockRead(*msg1, 2, ASYNC), | |
| 771 CreateMockRead(*msg33, 3, ASYNC), | |
| 772 MockRead(ASYNC, 0, 4), // EOF | |
| 773 }; | |
| 774 | |
| 775 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 776 | |
| 777 AssertConnectSucceeds(); | |
| 778 | |
| 779 Run(2); // SpdySession consumes the next two reads and sends then to | |
| 780 // sock_ to be buffered. | |
| 781 AssertSyncReadEquals(kMsg1, kLen1); | |
| 782 // The payload from the single large data frame will be read across | |
| 783 // two different reads. | |
| 784 AssertSyncReadEquals(kMsg3, kLen3); | |
| 785 AssertSyncReadEquals(kMsg3, kLen3); | |
| 786 } | |
| 787 | |
| 788 TEST_P(SpdyProxyClientSocketTest, MultipleReadsFromSameLargeFrame) { | |
| 789 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 790 MockWrite writes[] = { | |
| 791 CreateMockWrite(*conn, 0, SYNCHRONOUS), | |
| 792 }; | |
| 793 | |
| 794 scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame()); | |
| 795 scoped_ptr<SpdyFrame> msg333(ConstructBodyFrame(kMsg333, kLen333)); | |
| 796 MockRead reads[] = { | |
| 797 CreateMockRead(*resp, 1, ASYNC), | |
| 798 CreateMockRead(*msg333, 2, ASYNC), | |
| 799 MockRead(ASYNC, 0, 3), // EOF | |
| 800 }; | |
| 801 | |
| 802 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 803 | |
| 804 AssertConnectSucceeds(); | |
| 805 | |
| 806 Run(1); // SpdySession consumes the next read and sends it to | |
| 807 // sock_ to be buffered. | |
| 808 // The payload from the single large data frame will be read across | |
| 809 // two different reads. | |
| 810 AssertSyncReadEquals(kMsg33, kLen33); | |
| 811 | |
| 812 // Now attempt to do a read of more data than remains buffered | |
| 813 scoped_refptr<IOBuffer> buf(new IOBuffer(kLen33)); | |
| 814 ASSERT_EQ(kLen3, sock_->Read(buf.get(), kLen33, read_callback_.callback())); | |
| 815 ASSERT_EQ(std::string(kMsg3, kLen3), std::string(buf->data(), kLen3)); | |
| 816 ASSERT_TRUE(sock_->IsConnected()); | |
| 817 } | |
| 818 | |
| 819 TEST_P(SpdyProxyClientSocketTest, ReadAuthResponseBody) { | |
| 820 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 821 MockWrite writes[] = { | |
| 822 CreateMockWrite(*conn, 0, SYNCHRONOUS), | |
| 823 }; | |
| 824 | |
| 825 scoped_ptr<SpdyFrame> resp(ConstructConnectAuthReplyFrame()); | |
| 826 scoped_ptr<SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1)); | |
| 827 scoped_ptr<SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2)); | |
| 828 MockRead reads[] = { | |
| 829 CreateMockRead(*resp, 1, ASYNC), | |
| 830 CreateMockRead(*msg1, 2, ASYNC), | |
| 831 CreateMockRead(*msg2, 3, ASYNC), | |
| 832 MockRead(ASYNC, 0, 4), // EOF | |
| 833 }; | |
| 834 | |
| 835 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 836 | |
| 837 AssertConnectFails(ERR_PROXY_AUTH_REQUESTED); | |
| 838 | |
| 839 Run(2); // SpdySession consumes the next two reads and sends then to | |
| 840 // sock_ to be buffered. | |
| 841 AssertSyncReadEquals(kMsg1, kLen1); | |
| 842 AssertSyncReadEquals(kMsg2, kLen2); | |
| 843 } | |
| 844 | |
| 845 TEST_P(SpdyProxyClientSocketTest, ReadErrorResponseBody) { | |
| 846 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 847 MockWrite writes[] = { | |
| 848 CreateMockWrite(*conn, 0, SYNCHRONOUS), | |
| 849 }; | |
| 850 | |
| 851 scoped_ptr<SpdyFrame> resp(ConstructConnectErrorReplyFrame()); | |
| 852 scoped_ptr<SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1)); | |
| 853 scoped_ptr<SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2)); | |
| 854 MockRead reads[] = { | |
| 855 CreateMockRead(*resp, 1, ASYNC), | |
| 856 CreateMockRead(*msg1, 2, ASYNC), | |
| 857 CreateMockRead(*msg2, 3, ASYNC), | |
| 858 MockRead(ASYNC, 0, 4), // EOF | |
| 859 }; | |
| 860 | |
| 861 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 862 | |
| 863 AssertConnectFails(ERR_TUNNEL_CONNECTION_FAILED); | |
| 864 } | |
| 865 | |
| 866 // ----------- Reads and Writes | |
| 867 | |
| 868 TEST_P(SpdyProxyClientSocketTest, AsyncReadAroundWrite) { | |
| 869 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 870 scoped_ptr<SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2)); | |
| 871 MockWrite writes[] = { | |
| 872 CreateMockWrite(*conn, 0, SYNCHRONOUS), | |
| 873 CreateMockWrite(*msg2, 3, SYNCHRONOUS), | |
| 874 }; | |
| 875 | |
| 876 scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame()); | |
| 877 scoped_ptr<SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1)); | |
| 878 scoped_ptr<SpdyFrame> msg3(ConstructBodyFrame(kMsg3, kLen3)); | |
| 879 MockRead reads[] = { | |
| 880 CreateMockRead(*resp, 1, ASYNC), | |
| 881 CreateMockRead(*msg1, 2, ASYNC), // sync read | |
| 882 CreateMockRead(*msg3, 4, ASYNC), // async read | |
| 883 MockRead(ASYNC, 0, 5), // EOF | |
| 884 }; | |
| 885 | |
| 886 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 887 | |
| 888 AssertConnectSucceeds(); | |
| 889 | |
| 890 Run(1); | |
| 891 AssertSyncReadEquals(kMsg1, kLen1); | |
| 892 | |
| 893 AssertReadStarts(kMsg3, kLen3); | |
| 894 // Read should block until after the write succeeds | |
| 895 | |
| 896 AssertAsyncWriteSucceeds(kMsg2, kLen2); // Runs 1 step | |
| 897 | |
| 898 ASSERT_FALSE(read_callback_.have_result()); | |
| 899 Run(1); | |
| 900 // Now the read will return | |
| 901 AssertReadReturns(kMsg3, kLen3); | |
| 902 } | |
| 903 | |
| 904 TEST_P(SpdyProxyClientSocketTest, AsyncWriteAroundReads) { | |
| 905 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 906 scoped_ptr<SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2)); | |
| 907 MockWrite writes[] = { | |
| 908 CreateMockWrite(*conn, 0, SYNCHRONOUS), | |
| 909 CreateMockWrite(*msg2, 4, ASYNC), | |
| 910 }; | |
| 911 | |
| 912 scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame()); | |
| 913 scoped_ptr<SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1)); | |
| 914 scoped_ptr<SpdyFrame> msg3(ConstructBodyFrame(kMsg3, kLen3)); | |
| 915 MockRead reads[] = { | |
| 916 CreateMockRead(*resp, 1, ASYNC), | |
| 917 CreateMockRead(*msg1, 2, ASYNC), | |
| 918 CreateMockRead(*msg3, 3, ASYNC), | |
| 919 MockRead(ASYNC, 0, 5), // EOF | |
| 920 }; | |
| 921 | |
| 922 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 923 | |
| 924 AssertConnectSucceeds(); | |
| 925 | |
| 926 Run(1); | |
| 927 AssertSyncReadEquals(kMsg1, kLen1); | |
| 928 // Write should block until the read completes | |
| 929 AssertWriteReturns(kMsg2, kLen2, ERR_IO_PENDING); | |
| 930 | |
| 931 AssertAsyncReadEquals(kMsg3, kLen3); | |
| 932 | |
| 933 ASSERT_FALSE(write_callback_.have_result()); | |
| 934 | |
| 935 // Now the write will complete | |
| 936 Run(1); | |
| 937 AssertWriteLength(kLen2); | |
| 938 } | |
| 939 | |
| 940 // ----------- Reading/Writing on Closed socket | |
| 941 | |
| 942 // Reading from an already closed socket should return 0 | |
| 943 TEST_P(SpdyProxyClientSocketTest, ReadOnClosedSocketReturnsZero) { | |
| 944 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 945 MockWrite writes[] = { | |
| 946 CreateMockWrite(*conn, 0, SYNCHRONOUS), | |
| 947 }; | |
| 948 | |
| 949 scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame()); | |
| 950 MockRead reads[] = { | |
| 951 CreateMockRead(*resp, 1, ASYNC), | |
| 952 MockRead(ASYNC, 0, 2), // EOF | |
| 953 }; | |
| 954 | |
| 955 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 956 | |
| 957 AssertConnectSucceeds(); | |
| 958 | |
| 959 Run(1); | |
| 960 | |
| 961 ASSERT_FALSE(sock_->IsConnected()); | |
| 962 ASSERT_EQ(0, sock_->Read(NULL, 1, CompletionCallback())); | |
| 963 ASSERT_EQ(0, sock_->Read(NULL, 1, CompletionCallback())); | |
| 964 ASSERT_EQ(0, sock_->Read(NULL, 1, CompletionCallback())); | |
| 965 ASSERT_FALSE(sock_->IsConnectedAndIdle()); | |
| 966 } | |
| 967 | |
| 968 // Read pending when socket is closed should return 0 | |
| 969 TEST_P(SpdyProxyClientSocketTest, PendingReadOnCloseReturnsZero) { | |
| 970 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 971 MockWrite writes[] = { | |
| 972 CreateMockWrite(*conn, 0, SYNCHRONOUS), | |
| 973 }; | |
| 974 | |
| 975 scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame()); | |
| 976 MockRead reads[] = { | |
| 977 CreateMockRead(*resp, 1, ASYNC), | |
| 978 MockRead(ASYNC, 0, 2), // EOF | |
| 979 }; | |
| 980 | |
| 981 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 982 | |
| 983 AssertConnectSucceeds(); | |
| 984 | |
| 985 AssertReadStarts(kMsg1, kLen1); | |
| 986 | |
| 987 Run(1); | |
| 988 | |
| 989 ASSERT_EQ(0, read_callback_.WaitForResult()); | |
| 990 } | |
| 991 | |
| 992 // Reading from a disconnected socket is an error | |
| 993 TEST_P(SpdyProxyClientSocketTest, | |
| 994 ReadOnDisconnectSocketReturnsNotConnected) { | |
| 995 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 996 scoped_ptr<SpdyFrame> rst( | |
| 997 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL)); | |
| 998 MockWrite writes[] = { | |
| 999 CreateMockWrite(*conn, 0, SYNCHRONOUS), CreateMockWrite(*rst, 2), | |
| 1000 }; | |
| 1001 | |
| 1002 scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame()); | |
| 1003 MockRead reads[] = { | |
| 1004 CreateMockRead(*resp, 1, ASYNC), MockRead(ASYNC, 0, 3), // EOF | |
| 1005 }; | |
| 1006 | |
| 1007 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 1008 | |
| 1009 AssertConnectSucceeds(); | |
| 1010 | |
| 1011 sock_->Disconnect(); | |
| 1012 | |
| 1013 ASSERT_EQ(ERR_SOCKET_NOT_CONNECTED, | |
| 1014 sock_->Read(NULL, 1, CompletionCallback())); | |
| 1015 | |
| 1016 // Let the RST_STREAM write while |rst| is in-scope. | |
| 1017 base::MessageLoop::current()->RunUntilIdle(); | |
| 1018 } | |
| 1019 | |
| 1020 // Reading buffered data from an already closed socket should return | |
| 1021 // buffered data, then 0. | |
| 1022 TEST_P(SpdyProxyClientSocketTest, ReadOnClosedSocketReturnsBufferedData) { | |
| 1023 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 1024 MockWrite writes[] = { | |
| 1025 CreateMockWrite(*conn, 0, SYNCHRONOUS), | |
| 1026 }; | |
| 1027 | |
| 1028 scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame()); | |
| 1029 scoped_ptr<SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1)); | |
| 1030 MockRead reads[] = { | |
| 1031 CreateMockRead(*resp, 1, ASYNC), | |
| 1032 CreateMockRead(*msg1, 2, ASYNC), | |
| 1033 MockRead(ASYNC, 0, 3), // EOF | |
| 1034 }; | |
| 1035 | |
| 1036 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 1037 | |
| 1038 AssertConnectSucceeds(); | |
| 1039 | |
| 1040 Run(2); | |
| 1041 | |
| 1042 ASSERT_FALSE(sock_->IsConnected()); | |
| 1043 scoped_refptr<IOBuffer> buf(new IOBuffer(kLen1)); | |
| 1044 ASSERT_EQ(kLen1, sock_->Read(buf.get(), kLen1, CompletionCallback())); | |
| 1045 ASSERT_EQ(std::string(kMsg1, kLen1), std::string(buf->data(), kLen1)); | |
| 1046 | |
| 1047 ASSERT_EQ(0, sock_->Read(NULL, 1, CompletionCallback())); | |
| 1048 ASSERT_EQ(0, sock_->Read(NULL, 1, CompletionCallback())); | |
| 1049 sock_->Disconnect(); | |
| 1050 ASSERT_EQ(ERR_SOCKET_NOT_CONNECTED, | |
| 1051 sock_->Read(NULL, 1, CompletionCallback())); | |
| 1052 } | |
| 1053 | |
| 1054 // Calling Write() on a closed socket is an error | |
| 1055 TEST_P(SpdyProxyClientSocketTest, WriteOnClosedStream) { | |
| 1056 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 1057 MockWrite writes[] = { | |
| 1058 CreateMockWrite(*conn, 0, SYNCHRONOUS), | |
| 1059 }; | |
| 1060 | |
| 1061 scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame()); | |
| 1062 scoped_ptr<SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1)); | |
| 1063 MockRead reads[] = { | |
| 1064 CreateMockRead(*resp, 1, ASYNC), | |
| 1065 MockRead(ASYNC, 0, 2), // EOF | |
| 1066 }; | |
| 1067 | |
| 1068 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 1069 | |
| 1070 AssertConnectSucceeds(); | |
| 1071 | |
| 1072 Run(1); // Read EOF which will close the stream | |
| 1073 scoped_refptr<IOBufferWithSize> buf(CreateBuffer(kMsg1, kLen1)); | |
| 1074 EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED, | |
| 1075 sock_->Write(buf.get(), buf->size(), CompletionCallback())); | |
| 1076 } | |
| 1077 | |
| 1078 // Calling Write() on a disconnected socket is an error | |
| 1079 TEST_P(SpdyProxyClientSocketTest, WriteOnDisconnectedSocket) { | |
| 1080 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 1081 scoped_ptr<SpdyFrame> rst( | |
| 1082 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL)); | |
| 1083 MockWrite writes[] = { | |
| 1084 CreateMockWrite(*conn, 0, SYNCHRONOUS), CreateMockWrite(*rst, 2), | |
| 1085 }; | |
| 1086 | |
| 1087 scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame()); | |
| 1088 scoped_ptr<SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1)); | |
| 1089 MockRead reads[] = { | |
| 1090 CreateMockRead(*resp, 1, ASYNC), MockRead(ASYNC, 0, 3), // EOF | |
| 1091 }; | |
| 1092 | |
| 1093 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 1094 | |
| 1095 AssertConnectSucceeds(); | |
| 1096 | |
| 1097 sock_->Disconnect(); | |
| 1098 | |
| 1099 scoped_refptr<IOBufferWithSize> buf(CreateBuffer(kMsg1, kLen1)); | |
| 1100 EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED, | |
| 1101 sock_->Write(buf.get(), buf->size(), CompletionCallback())); | |
| 1102 | |
| 1103 // Let the RST_STREAM write while |rst| is in-scope. | |
| 1104 base::MessageLoop::current()->RunUntilIdle(); | |
| 1105 } | |
| 1106 | |
| 1107 // If the socket is closed with a pending Write(), the callback | |
| 1108 // should be called with ERR_CONNECTION_CLOSED. | |
| 1109 TEST_P(SpdyProxyClientSocketTest, WritePendingOnClose) { | |
| 1110 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 1111 MockWrite writes[] = { | |
| 1112 CreateMockWrite(*conn, 0, SYNCHRONOUS), | |
| 1113 MockWrite(ASYNC, ERR_ABORTED, 2), | |
| 1114 }; | |
| 1115 | |
| 1116 scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame()); | |
| 1117 MockRead reads[] = { | |
| 1118 CreateMockRead(*resp, 1, ASYNC), | |
| 1119 MockRead(ASYNC, 0, 3), // EOF | |
| 1120 }; | |
| 1121 | |
| 1122 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 1123 | |
| 1124 AssertConnectSucceeds(); | |
| 1125 | |
| 1126 EXPECT_TRUE(sock_->IsConnected()); | |
| 1127 | |
| 1128 scoped_refptr<IOBufferWithSize> buf(CreateBuffer(kMsg1, kLen1)); | |
| 1129 EXPECT_EQ(ERR_IO_PENDING, | |
| 1130 sock_->Write(buf.get(), buf->size(), write_callback_.callback())); | |
| 1131 | |
| 1132 CloseSpdySession(ERR_ABORTED, std::string()); | |
| 1133 | |
| 1134 EXPECT_EQ(ERR_CONNECTION_CLOSED, write_callback_.WaitForResult()); | |
| 1135 } | |
| 1136 | |
| 1137 // If the socket is Disconnected with a pending Write(), the callback | |
| 1138 // should not be called. | |
| 1139 TEST_P(SpdyProxyClientSocketTest, DisconnectWithWritePending) { | |
| 1140 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 1141 scoped_ptr<SpdyFrame> rst( | |
| 1142 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL)); | |
| 1143 MockWrite writes[] = { | |
| 1144 CreateMockWrite(*conn, 0, SYNCHRONOUS), CreateMockWrite(*rst, 2), | |
| 1145 MockWrite(SYNCHRONOUS, 0, 3), // EOF | |
| 1146 }; | |
| 1147 | |
| 1148 scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame()); | |
| 1149 MockRead reads[] = { | |
| 1150 CreateMockRead(*resp, 1, ASYNC), MockRead(ASYNC, 0, 4), // EOF | |
| 1151 }; | |
| 1152 | |
| 1153 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 1154 | |
| 1155 AssertConnectSucceeds(); | |
| 1156 | |
| 1157 EXPECT_TRUE(sock_->IsConnected()); | |
| 1158 | |
| 1159 scoped_refptr<IOBufferWithSize> buf(CreateBuffer(kMsg1, kLen1)); | |
| 1160 EXPECT_EQ(ERR_IO_PENDING, | |
| 1161 sock_->Write(buf.get(), buf->size(), write_callback_.callback())); | |
| 1162 | |
| 1163 sock_->Disconnect(); | |
| 1164 | |
| 1165 EXPECT_FALSE(sock_->IsConnected()); | |
| 1166 EXPECT_FALSE(write_callback_.have_result()); | |
| 1167 | |
| 1168 // Let the RST_STREAM write while |rst| is in-scope. | |
| 1169 base::MessageLoop::current()->RunUntilIdle(); | |
| 1170 } | |
| 1171 | |
| 1172 // If the socket is Disconnected with a pending Read(), the callback | |
| 1173 // should not be called. | |
| 1174 TEST_P(SpdyProxyClientSocketTest, DisconnectWithReadPending) { | |
| 1175 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 1176 scoped_ptr<SpdyFrame> rst( | |
| 1177 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL)); | |
| 1178 MockWrite writes[] = { | |
| 1179 CreateMockWrite(*conn, 0, SYNCHRONOUS), CreateMockWrite(*rst, 2), | |
| 1180 }; | |
| 1181 | |
| 1182 scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame()); | |
| 1183 MockRead reads[] = { | |
| 1184 CreateMockRead(*resp, 1, ASYNC), MockRead(ASYNC, 0, 3), // EOF | |
| 1185 }; | |
| 1186 | |
| 1187 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 1188 | |
| 1189 AssertConnectSucceeds(); | |
| 1190 | |
| 1191 EXPECT_TRUE(sock_->IsConnected()); | |
| 1192 | |
| 1193 scoped_refptr<IOBuffer> buf(new IOBuffer(kLen1)); | |
| 1194 ASSERT_EQ(ERR_IO_PENDING, | |
| 1195 sock_->Read(buf.get(), kLen1, read_callback_.callback())); | |
| 1196 | |
| 1197 sock_->Disconnect(); | |
| 1198 | |
| 1199 EXPECT_FALSE(sock_->IsConnected()); | |
| 1200 EXPECT_FALSE(read_callback_.have_result()); | |
| 1201 | |
| 1202 // Let the RST_STREAM write while |rst| is in-scope. | |
| 1203 base::MessageLoop::current()->RunUntilIdle(); | |
| 1204 } | |
| 1205 | |
| 1206 // If the socket is Reset when both a read and write are pending, | |
| 1207 // both should be called back. | |
| 1208 TEST_P(SpdyProxyClientSocketTest, RstWithReadAndWritePending) { | |
| 1209 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 1210 MockWrite writes[] = { | |
| 1211 CreateMockWrite(*conn, 0, SYNCHRONOUS), | |
| 1212 MockWrite(ASYNC, ERR_ABORTED, 3), | |
| 1213 }; | |
| 1214 | |
| 1215 scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame()); | |
| 1216 scoped_ptr<SpdyFrame> rst( | |
| 1217 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL)); | |
| 1218 MockRead reads[] = { | |
| 1219 CreateMockRead(*resp, 1, ASYNC), | |
| 1220 CreateMockRead(*rst, 2, ASYNC), | |
| 1221 MockRead(ASYNC, 0, 4) // EOF | |
| 1222 }; | |
| 1223 | |
| 1224 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 1225 | |
| 1226 AssertConnectSucceeds(); | |
| 1227 | |
| 1228 EXPECT_TRUE(sock_->IsConnected()); | |
| 1229 | |
| 1230 scoped_refptr<IOBuffer> read_buf(new IOBuffer(kLen1)); | |
| 1231 ASSERT_EQ(ERR_IO_PENDING, | |
| 1232 sock_->Read(read_buf.get(), kLen1, read_callback_.callback())); | |
| 1233 | |
| 1234 scoped_refptr<IOBufferWithSize> write_buf(CreateBuffer(kMsg1, kLen1)); | |
| 1235 EXPECT_EQ( | |
| 1236 ERR_IO_PENDING, | |
| 1237 sock_->Write( | |
| 1238 write_buf.get(), write_buf->size(), write_callback_.callback())); | |
| 1239 | |
| 1240 Run(2); | |
| 1241 | |
| 1242 EXPECT_TRUE(sock_.get()); | |
| 1243 EXPECT_TRUE(read_callback_.have_result()); | |
| 1244 EXPECT_TRUE(write_callback_.have_result()); | |
| 1245 | |
| 1246 // Let the RST_STREAM write while |rst| is in-scope. | |
| 1247 base::MessageLoop::current()->RunUntilIdle(); | |
| 1248 } | |
| 1249 | |
| 1250 // Makes sure the proxy client socket's source gets the expected NetLog events | |
| 1251 // and only the expected NetLog events (No SpdySession events). | |
| 1252 TEST_P(SpdyProxyClientSocketTest, NetLog) { | |
| 1253 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 1254 scoped_ptr<SpdyFrame> rst( | |
| 1255 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL)); | |
| 1256 MockWrite writes[] = { | |
| 1257 CreateMockWrite(*conn, 0, SYNCHRONOUS), CreateMockWrite(*rst, 3), | |
| 1258 }; | |
| 1259 | |
| 1260 scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame()); | |
| 1261 scoped_ptr<SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1)); | |
| 1262 MockRead reads[] = { | |
| 1263 CreateMockRead(*resp, 1, ASYNC), CreateMockRead(*msg1, 2, ASYNC), | |
| 1264 MockRead(ASYNC, 0, 4), // EOF | |
| 1265 }; | |
| 1266 | |
| 1267 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 1268 | |
| 1269 AssertConnectSucceeds(); | |
| 1270 | |
| 1271 Run(1); // SpdySession consumes the next read and sends it to | |
| 1272 // sock_ to be buffered. | |
| 1273 AssertSyncReadEquals(kMsg1, kLen1); | |
| 1274 | |
| 1275 NetLog::Source sock_source = sock_->NetLog().source(); | |
| 1276 sock_.reset(); | |
| 1277 | |
| 1278 CapturingNetLog::CapturedEntryList entry_list; | |
| 1279 net_log_.GetEntriesForSource(sock_source, &entry_list); | |
| 1280 | |
| 1281 ASSERT_EQ(entry_list.size(), 10u); | |
| 1282 EXPECT_TRUE(LogContainsBeginEvent(entry_list, 0, NetLog::TYPE_SOCKET_ALIVE)); | |
| 1283 EXPECT_TRUE(LogContainsEvent(entry_list, 1, | |
| 1284 NetLog::TYPE_SPDY_PROXY_CLIENT_SESSION, | |
| 1285 NetLog::PHASE_NONE)); | |
| 1286 EXPECT_TRUE(LogContainsBeginEvent(entry_list, 2, | |
| 1287 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST)); | |
| 1288 EXPECT_TRUE(LogContainsEvent(entry_list, 3, | |
| 1289 NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, | |
| 1290 NetLog::PHASE_NONE)); | |
| 1291 EXPECT_TRUE(LogContainsEndEvent(entry_list, 4, | |
| 1292 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST)); | |
| 1293 EXPECT_TRUE(LogContainsBeginEvent(entry_list, 5, | |
| 1294 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS)); | |
| 1295 EXPECT_TRUE(LogContainsEvent(entry_list, 6, | |
| 1296 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, | |
| 1297 NetLog::PHASE_NONE)); | |
| 1298 EXPECT_TRUE(LogContainsEndEvent(entry_list, 7, | |
| 1299 NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS)); | |
| 1300 EXPECT_TRUE(LogContainsEvent(entry_list, 8, | |
| 1301 NetLog::TYPE_SOCKET_BYTES_RECEIVED, | |
| 1302 NetLog::PHASE_NONE)); | |
| 1303 EXPECT_TRUE(LogContainsEndEvent(entry_list, 9, NetLog::TYPE_SOCKET_ALIVE)); | |
| 1304 | |
| 1305 // Let the RST_STREAM write while |rst| is in-scope. | |
| 1306 base::MessageLoop::current()->RunUntilIdle(); | |
| 1307 } | |
| 1308 | |
| 1309 // CompletionCallback that causes the SpdyProxyClientSocket to be | |
| 1310 // deleted when Run is invoked. | |
| 1311 class DeleteSockCallback : public TestCompletionCallbackBase { | |
| 1312 public: | |
| 1313 explicit DeleteSockCallback(scoped_ptr<SpdyProxyClientSocket>* sock) | |
| 1314 : sock_(sock), | |
| 1315 callback_(base::Bind(&DeleteSockCallback::OnComplete, | |
| 1316 base::Unretained(this))) { | |
| 1317 } | |
| 1318 | |
| 1319 ~DeleteSockCallback() override {} | |
| 1320 | |
| 1321 const CompletionCallback& callback() const { return callback_; } | |
| 1322 | |
| 1323 private: | |
| 1324 void OnComplete(int result) { | |
| 1325 sock_->reset(NULL); | |
| 1326 SetResult(result); | |
| 1327 } | |
| 1328 | |
| 1329 scoped_ptr<SpdyProxyClientSocket>* sock_; | |
| 1330 CompletionCallback callback_; | |
| 1331 | |
| 1332 DISALLOW_COPY_AND_ASSIGN(DeleteSockCallback); | |
| 1333 }; | |
| 1334 | |
| 1335 // If the socket is Reset when both a read and write are pending, and the | |
| 1336 // read callback causes the socket to be deleted, the write callback should | |
| 1337 // not be called. | |
| 1338 TEST_P(SpdyProxyClientSocketTest, RstWithReadAndWritePendingDelete) { | |
| 1339 scoped_ptr<SpdyFrame> conn(ConstructConnectRequestFrame()); | |
| 1340 MockWrite writes[] = { | |
| 1341 CreateMockWrite(*conn, 0, SYNCHRONOUS), | |
| 1342 MockWrite(ASYNC, ERR_ABORTED, 3), | |
| 1343 }; | |
| 1344 | |
| 1345 scoped_ptr<SpdyFrame> resp(ConstructConnectReplyFrame()); | |
| 1346 scoped_ptr<SpdyFrame> rst( | |
| 1347 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL)); | |
| 1348 MockRead reads[] = { | |
| 1349 CreateMockRead(*resp, 1, ASYNC), | |
| 1350 CreateMockRead(*rst, 2, ASYNC), | |
| 1351 MockRead(ASYNC, 0, 4), // EOF | |
| 1352 }; | |
| 1353 | |
| 1354 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 1355 | |
| 1356 AssertConnectSucceeds(); | |
| 1357 | |
| 1358 EXPECT_TRUE(sock_->IsConnected()); | |
| 1359 | |
| 1360 DeleteSockCallback read_callback(&sock_); | |
| 1361 | |
| 1362 scoped_refptr<IOBuffer> read_buf(new IOBuffer(kLen1)); | |
| 1363 ASSERT_EQ(ERR_IO_PENDING, | |
| 1364 sock_->Read(read_buf.get(), kLen1, read_callback.callback())); | |
| 1365 | |
| 1366 scoped_refptr<IOBufferWithSize> write_buf(CreateBuffer(kMsg1, kLen1)); | |
| 1367 EXPECT_EQ( | |
| 1368 ERR_IO_PENDING, | |
| 1369 sock_->Write( | |
| 1370 write_buf.get(), write_buf->size(), write_callback_.callback())); | |
| 1371 | |
| 1372 Run(1); | |
| 1373 | |
| 1374 EXPECT_FALSE(sock_.get()); | |
| 1375 EXPECT_TRUE(read_callback.have_result()); | |
| 1376 EXPECT_FALSE(write_callback_.have_result()); | |
| 1377 | |
| 1378 // Let the RST_STREAM write while |rst| is in-scope. | |
| 1379 base::MessageLoop::current()->RunUntilIdle(); | |
| 1380 } | |
| 1381 | |
| 1382 } // namespace net | |
| OLD | NEW |