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