diff options
-rw-r--r-- | net/http/http_network_transaction_unittest.cc | 319 | ||||
-rw-r--r-- | net/http/http_proxy_client_socket.cc | 1 | ||||
-rw-r--r-- | net/http/http_stream_parser.cc | 4 | ||||
-rw-r--r-- | net/socket/socket_test_util.cc | 4 | ||||
-rw-r--r-- | net/socket/socket_test_util.h | 1 | ||||
-rw-r--r-- | net/socket/socks5_client_socket.cc | 1 | ||||
-rw-r--r-- | net/socket/socks_client_socket.cc | 1 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_pool.cc | 1 |
8 files changed, 326 insertions, 6 deletions
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc index fbff846..56b73c5 100644 --- a/net/http/http_network_transaction_unittest.cc +++ b/net/http/http_network_transaction_unittest.cc @@ -2494,6 +2494,160 @@ TEST_F(HttpNetworkTransactionTest, RecycleSocket) { EXPECT_EQ(1, session->tcp_socket_pool()->IdleSocketCount()); } +// Make sure that we recycle a SSL socket after reading all of the response +// body. +TEST_F(HttpNetworkTransactionTest, RecycleSSLSocket) { + SessionDependencies session_deps; + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("https://www.google.com/"); + request.load_flags = 0; + + MockWrite data_writes[] = { + MockWrite("GET / HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Connection: keep-alive\r\n\r\n"), + }; + + MockRead data_reads[] = { + MockRead("HTTP/1.1 200 OK\r\n"), + MockRead("Content-Length: 11\r\n\r\n"), + MockRead("hello world"), + MockRead(false, OK), + }; + + SSLSocketDataProvider ssl(true, OK); + session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); + + StaticSocketDataProvider data(data_reads, arraysize(data_reads), + data_writes, arraysize(data_writes)); + session_deps.socket_factory.AddSocketDataProvider(&data); + + TestCompletionCallback callback; + + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); + scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); + + int rv = trans->Start(&request, &callback, BoundNetLog()); + + EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_EQ(OK, callback.WaitForResult()); + + const HttpResponseInfo* response = trans->GetResponseInfo(); + ASSERT_TRUE(response != NULL); + ASSERT_TRUE(response->headers != NULL); + EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); + + EXPECT_EQ(0, session->tcp_socket_pool()->IdleSocketCount()); + + std::string response_data; + rv = ReadTransaction(trans.get(), &response_data); + EXPECT_EQ(OK, rv); + EXPECT_EQ("hello world", response_data); + + // Empty the current queue. This is necessary because idle sockets are + // added to the connection pool asynchronously with a PostTask. + MessageLoop::current()->RunAllPending(); + + // We now check to make sure the socket was added back to the pool. + EXPECT_EQ(1, session->ssl_socket_pool()->IdleSocketCount()); +} + +// Grab a SSL socket, use it, and put it back into the pool. Then, reuse it +// from the pool and make sure that we recover okay. +TEST_F(HttpNetworkTransactionTest, RecycleDeadSSLSocket) { + SessionDependencies session_deps; + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("https://www.google.com/"); + request.load_flags = 0; + + MockWrite data_writes[] = { + MockWrite("GET / HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Connection: keep-alive\r\n\r\n"), + MockWrite("GET / HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Connection: keep-alive\r\n\r\n"), + }; + + MockRead data_reads[] = { + MockRead("HTTP/1.1 200 OK\r\n"), + MockRead("Content-Length: 11\r\n\r\n"), + MockRead(false, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), + MockRead("hello world"), + MockRead(true, 0, 0) // EOF + }; + + SSLSocketDataProvider ssl(true, OK); + SSLSocketDataProvider ssl2(true, OK); + session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); + session_deps.socket_factory.AddSSLSocketDataProvider(&ssl2); + + StaticSocketDataProvider data(data_reads, arraysize(data_reads), + data_writes, arraysize(data_writes)); + StaticSocketDataProvider data2(data_reads, arraysize(data_reads), + data_writes, arraysize(data_writes)); + session_deps.socket_factory.AddSocketDataProvider(&data); + session_deps.socket_factory.AddSocketDataProvider(&data2); + + TestCompletionCallback callback; + + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); + scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); + + int rv = trans->Start(&request, &callback, BoundNetLog()); + + EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_EQ(OK, callback.WaitForResult()); + + const HttpResponseInfo* response = trans->GetResponseInfo(); + ASSERT_TRUE(response != NULL); + ASSERT_TRUE(response->headers != NULL); + EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); + + EXPECT_EQ(0, session->tcp_socket_pool()->IdleSocketCount()); + + std::string response_data; + rv = ReadTransaction(trans.get(), &response_data); + EXPECT_EQ(OK, rv); + EXPECT_EQ("hello world", response_data); + + // Empty the current queue. This is necessary because idle sockets are + // added to the connection pool asynchronously with a PostTask. + MessageLoop::current()->RunAllPending(); + + // We now check to make sure the socket was added back to the pool. + EXPECT_EQ(1, session->ssl_socket_pool()->IdleSocketCount()); + + // Now start the second transaction, which should reuse the previous socket. + + trans.reset(new HttpNetworkTransaction(session)); + + rv = trans->Start(&request, &callback, BoundNetLog()); + + EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_EQ(OK, callback.WaitForResult()); + + response = trans->GetResponseInfo(); + ASSERT_TRUE(response != NULL); + ASSERT_TRUE(response->headers != NULL); + EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); + + EXPECT_EQ(0, session->tcp_socket_pool()->IdleSocketCount()); + + rv = ReadTransaction(trans.get(), &response_data); + EXPECT_EQ(OK, rv); + EXPECT_EQ("hello world", response_data); + + // Empty the current queue. This is necessary because idle sockets are + // added to the connection pool asynchronously with a PostTask. + MessageLoop::current()->RunAllPending(); + + // We now check to make sure the socket was added back to the pool. + EXPECT_EQ(1, session->ssl_socket_pool()->IdleSocketCount()); +} + // Make sure that we recycle a socket after a zero-length response. // http://crbug.com/9880 TEST_F(HttpNetworkTransactionTest, RecycleSocketAfterZeroContentLength) { @@ -6595,4 +6749,169 @@ TEST_F(HttpNetworkTransactionTest, SimpleCancel) { MessageLoop::current()->RunAllPending(); } +// Test a basic GET request through a proxy. +TEST_F(HttpNetworkTransactionTest, ProxyGet) { + SessionDependencies session_deps(CreateFixedProxyService("myproxy:70")); + CapturingBoundNetLog log(CapturingNetLog::kUnbounded); + session_deps.net_log = log.bound().net_log(); + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); + + scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); + + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("http://www.google.com/"); + + MockWrite data_writes1[] = { + MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Proxy-Connection: keep-alive\r\n\r\n"), + }; + + MockRead data_reads1[] = { + MockRead("HTTP/1.1 200 OK\r\n"), + MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), + MockRead("Content-Length: 100\r\n\r\n"), + MockRead(false, OK), + }; + + StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), + data_writes1, arraysize(data_writes1)); + session_deps.socket_factory.AddSocketDataProvider(&data1); + + TestCompletionCallback callback1; + + int rv = trans->Start(&request, &callback1, log.bound()); + EXPECT_EQ(ERR_IO_PENDING, rv); + + rv = callback1.WaitForResult(); + EXPECT_EQ(OK, rv); + + const HttpResponseInfo* response = trans->GetResponseInfo(); + ASSERT_FALSE(response == NULL); + + EXPECT_TRUE(response->headers->IsKeepAlive()); + EXPECT_EQ(200, response->headers->response_code()); + EXPECT_EQ(100, response->headers->GetContentLength()); + EXPECT_TRUE(response->was_fetched_via_proxy); + EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); +} + +// Test a basic HTTPS GET request through a proxy. +TEST_F(HttpNetworkTransactionTest, ProxyTunnelGet) { + SessionDependencies session_deps(CreateFixedProxyService("myproxy:70")); + CapturingBoundNetLog log(CapturingNetLog::kUnbounded); + session_deps.net_log = log.bound().net_log(); + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); + + scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); + + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("https://www.google.com/"); + + // Since we have proxy, should try to establish tunnel. + MockWrite data_writes1[] = { + MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Proxy-Connection: keep-alive\r\n\r\n"), + + MockWrite("GET / HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Connection: keep-alive\r\n\r\n"), + }; + + MockRead data_reads1[] = { + MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), + + MockRead("HTTP/1.1 200 OK\r\n"), + MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), + MockRead("Content-Length: 100\r\n\r\n"), + MockRead(false, OK), + }; + + StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), + data_writes1, arraysize(data_writes1)); + session_deps.socket_factory.AddSocketDataProvider(&data1); + SSLSocketDataProvider ssl(true, OK); + session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); + + TestCompletionCallback callback1; + + int rv = trans->Start(&request, &callback1, log.bound()); + EXPECT_EQ(ERR_IO_PENDING, rv); + + rv = callback1.WaitForResult(); + EXPECT_EQ(OK, rv); + size_t pos = ExpectLogContainsSomewhere( + log.entries(), 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, + NetLog::PHASE_NONE); + ExpectLogContainsSomewhere( + log.entries(), pos, + NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, + NetLog::PHASE_NONE); + + const HttpResponseInfo* response = trans->GetResponseInfo(); + ASSERT_FALSE(response == NULL); + + EXPECT_TRUE(response->headers->IsKeepAlive()); + EXPECT_EQ(200, response->headers->response_code()); + EXPECT_EQ(100, response->headers->GetContentLength()); + EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); + EXPECT_TRUE(response->was_fetched_via_proxy); +} + +// Test a basic HTTPS GET request through a proxy, but the server hangs up +// while establishing the tunnel. +TEST_F(HttpNetworkTransactionTest, ProxyTunnelGetHangup) { + SessionDependencies session_deps(CreateFixedProxyService("myproxy:70")); + CapturingBoundNetLog log(CapturingNetLog::kUnbounded); + session_deps.net_log = log.bound().net_log(); + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); + + scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); + + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("https://www.google.com/"); + + // Since we have proxy, should try to establish tunnel. + MockWrite data_writes1[] = { + MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Proxy-Connection: keep-alive\r\n\r\n"), + + MockWrite("GET / HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Connection: keep-alive\r\n\r\n"), + }; + + MockRead data_reads1[] = { + MockRead(false, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), + MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), + MockRead(true, 0, 0), // EOF + }; + + StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), + data_writes1, arraysize(data_writes1)); + session_deps.socket_factory.AddSocketDataProvider(&data1); + SSLSocketDataProvider ssl(true, OK); + session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); + + TestCompletionCallback callback1; + + int rv = trans->Start(&request, &callback1, log.bound()); + EXPECT_EQ(ERR_IO_PENDING, rv); + + rv = callback1.WaitForResult(); + EXPECT_EQ(ERR_EMPTY_RESPONSE, rv); + size_t pos = ExpectLogContainsSomewhere( + log.entries(), 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, + NetLog::PHASE_NONE); + ExpectLogContainsSomewhere( + log.entries(), pos, + NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, + NetLog::PHASE_NONE); +} + } // namespace net diff --git a/net/http/http_proxy_client_socket.cc b/net/http/http_proxy_client_socket.cc index 78d470b..76882fa 100644 --- a/net/http/http_proxy_client_socket.cc +++ b/net/http/http_proxy_client_socket.cc @@ -81,7 +81,6 @@ HttpProxyClientSocket::~HttpProxyClientSocket() { int HttpProxyClientSocket::Connect(CompletionCallback* callback) { DCHECK(transport_.get()); DCHECK(transport_->socket()); - DCHECK(transport_->socket()->IsConnected()); DCHECK(!user_callback_); if (!tunnel_) diff --git a/net/http/http_stream_parser.cc b/net/http/http_stream_parser.cc index 5fbcb5b..b114519 100644 --- a/net/http/http_stream_parser.cc +++ b/net/http/http_stream_parser.cc @@ -579,7 +579,8 @@ void HttpStreamParser::SetConnectionReused() { void HttpStreamParser::GetSSLInfo(SSLInfo* ssl_info) { if (request_->url.SchemeIs("https")) { - CHECK(connection_->socket()->IsConnected()); + if (!connection_->socket() || !connection_->socket()->IsConnected()) + return; SSLClientSocket* ssl_socket = static_cast<SSLClientSocket*>(connection_->socket()); ssl_socket->GetSSLInfo(ssl_info); @@ -591,7 +592,6 @@ void HttpStreamParser::GetSSLCertRequestInfo( if (request_->url.SchemeIs("https")) { if (!connection_->socket() || !connection_->socket()->IsConnected()) return; - CHECK(connection_->socket()->IsConnected()); SSLClientSocket* ssl_socket = static_cast<SSLClientSocket*>(connection_->socket()); ssl_socket->GetSSLCertRequestInfo(cert_request_info); diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc index 069c293..5ffd1d4 100644 --- a/net/socket/socket_test_util.cc +++ b/net/socket/socket_test_util.cc @@ -493,6 +493,10 @@ void MockSSLClientSocket::Disconnect() { transport_->socket()->Disconnect(); } +bool MockSSLClientSocket::IsConnected() const { + return transport_->socket()->IsConnected(); +} + int MockSSLClientSocket::Read(net::IOBuffer* buf, int buf_len, net::CompletionCallback* callback) { return transport_->socket()->Read(buf, buf_len, callback); diff --git a/net/socket/socket_test_util.h b/net/socket/socket_test_util.h index ad30353..533a18d 100644 --- a/net/socket/socket_test_util.h +++ b/net/socket/socket_test_util.h @@ -636,6 +636,7 @@ class MockSSLClientSocket : public MockClientSocket { // ClientSocket methods: virtual int Connect(net::CompletionCallback* callback); virtual void Disconnect(); + virtual bool IsConnected() const; // Socket methods: virtual int Read(net::IOBuffer* buf, int buf_len, diff --git a/net/socket/socks5_client_socket.cc b/net/socket/socks5_client_socket.cc index 997fb25..9c9ecbe 100644 --- a/net/socket/socks5_client_socket.cc +++ b/net/socket/socks5_client_socket.cc @@ -67,7 +67,6 @@ SOCKS5ClientSocket::~SOCKS5ClientSocket() { int SOCKS5ClientSocket::Connect(CompletionCallback* callback) { DCHECK(transport_.get()); DCHECK(transport_->socket()); - DCHECK(transport_->socket()->IsConnected()); DCHECK_EQ(STATE_NONE, next_state_); DCHECK(!user_callback_); diff --git a/net/socket/socks_client_socket.cc b/net/socket/socks_client_socket.cc index 32c4e3b..2000754 100644 --- a/net/socket/socks_client_socket.cc +++ b/net/socket/socks_client_socket.cc @@ -102,7 +102,6 @@ SOCKSClientSocket::~SOCKSClientSocket() { int SOCKSClientSocket::Connect(CompletionCallback* callback) { DCHECK(transport_.get()); DCHECK(transport_->socket()); - DCHECK(transport_->socket()->IsConnected()); DCHECK_EQ(STATE_NONE, next_state_); DCHECK(!user_callback_); diff --git a/net/socket/ssl_client_socket_pool.cc b/net/socket/ssl_client_socket_pool.cc index 059354e..541792f 100644 --- a/net/socket/ssl_client_socket_pool.cc +++ b/net/socket/ssl_client_socket_pool.cc @@ -240,7 +240,6 @@ int SSLConnectJob::DoTunnelConnectComplete(int result) { if (result < 0) return result; - DCHECK(tunnel_socket->IsConnected()); next_state_ = STATE_SSL_CONNECT; return result; } |