diff options
author | mmenke@chromium.org <mmenke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-24 05:28:20 +0000 |
---|---|---|
committer | mmenke@chromium.org <mmenke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-24 05:28:20 +0000 |
commit | 029c83b673fd8dbe900e9b06c92c79e0dcf329d1 (patch) | |
tree | b98ba82c877aa17a35cddbeb3b15e965e6e1e26b /net | |
parent | 44703cc73a24cc39b3e5e832f447d8261701fa4c (diff) | |
download | chromium_src-029c83b673fd8dbe900e9b06c92c79e0dcf329d1.zip chromium_src-029c83b673fd8dbe900e9b06c92c79e0dcf329d1.tar.gz chromium_src-029c83b673fd8dbe900e9b06c92c79e0dcf329d1.tar.bz2 |
LoadTiming in net part 4.
Add proxy resolution timing support.
Also document a few weird behaviors.
R=eroman@chromium.org
BUG=77446
Review URL: https://codereview.chromium.org/12047032
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@178524 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/base/load_timing_info.h | 22 | ||||
-rw-r--r-- | net/http/http_network_transaction.cc | 3 | ||||
-rw-r--r-- | net/http/http_network_transaction_spdy2_unittest.cc | 483 | ||||
-rw-r--r-- | net/http/http_network_transaction_spdy3_unittest.cc | 483 | ||||
-rw-r--r-- | net/proxy/proxy_info.cc | 4 | ||||
-rw-r--r-- | net/proxy/proxy_info.h | 14 | ||||
-rw-r--r-- | net/proxy/proxy_service.cc | 14 | ||||
-rw-r--r-- | net/proxy/proxy_service_unittest.cc | 75 |
8 files changed, 1027 insertions, 71 deletions
diff --git a/net/base/load_timing_info.h b/net/base/load_timing_info.h index 446b1e9..3e876bd 100644 --- a/net/base/load_timing_info.h +++ b/net/base/load_timing_info.h @@ -14,6 +14,9 @@ namespace net { // All events that do not apply to a request have null times. For non-HTTP // requests, all times other than the request_start times are null. // +// Requests with connection errors generally only have request start times as +// well, since they never received an established socket. +// // The general order for events is: // request_start // proxy_start @@ -33,6 +36,14 @@ namespace net { // by the connection attempt itself. Since the connection attempt may be // started before a URLRequest, the starred times may occur before, during, or // after the request_start and proxy events. +// +// DNS and SSL times are both times for the host, not the proxy, so DNS times +// when using proxies are null, and only requests to HTTPS hosts (Not proxies) +// have SSL times. One exception to this is when a proxy server itself returns +// a redirect response. In this case, the connect times treat the proxy as the +// host. The send and receive times will all be null, however. +// See HttpNetworkTransaction::OnHttpsProxyTunnelResponse. +// TODO(mmenke): Is this worth fixing? struct NET_EXPORT LoadTimingInfo { // Contains the LoadTimingInfo events related to establishing a connection. // These are all set by ConnectJobs. @@ -76,11 +87,20 @@ struct NET_EXPORT LoadTimingInfo { // True if the socket was reused. When true, DNS, connect, and SSL times // will all be null. When false, those times may be null, too, for non-HTTP // requests, or when they don't apply to a request. + // + // For requests that are sent again after an AUTH challenge, this will be true + // if the original socket is reused, and false if a new socket is used. + // Responding to a proxy AUTH challenge is never considered to be reusing a + // socket, since a connection to the host wasn't established when the + // challenge was received. bool socket_reused; // Unique socket ID, can be used to identify requests served by the same // socket. - // TODO(mmenke): Do something reasonable for SPDY proxies. + // TODO(mmenke): Do something reasonable for SPDY proxies. Currently, SPDY + // sessions (And HTTPS requests?) over SPDY proxies use the ID + // of the SPDY proxy's session. HTTP requests, however, use + // the ID of the SPDY proxy's socket. uint32 socket_log_id; // Start time as a base::Time, so times can be coverted into actual times. diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index caa8f11..7c9c930 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc @@ -487,6 +487,9 @@ bool HttpNetworkTransaction::GetLoadTimingInfo( if (!stream_ || !stream_->GetLoadTimingInfo(load_timing_info)) return false; + load_timing_info->proxy_resolve_start = + proxy_info_.proxy_resolve_start_time(); + load_timing_info->proxy_resolve_end = proxy_info_.proxy_resolve_end_time(); load_timing_info->send_start = send_start_time_; load_timing_info->send_end = send_end_time_; load_timing_info->receive_headers_end = receive_headers_end_; diff --git a/net/http/http_network_transaction_spdy2_unittest.cc b/net/http/http_network_transaction_spdy2_unittest.cc index 2ea9bf7..dd0683b 100644 --- a/net/http/http_network_transaction_spdy2_unittest.cc +++ b/net/http/http_network_transaction_spdy2_unittest.cc @@ -133,42 +133,93 @@ bool GetHeaders(DictionaryValue* params, std::string* headers) { return true; } -// |connect_time_flags| is ignored if expect_reused is true. -void TestLoadTiming(const net::LoadTimingInfo& load_timing_info, - bool expect_reused, int connect_timing_flags) { - EXPECT_EQ(expect_reused, load_timing_info.socket_reused); +// Tests LoadTimingInfo in the case a socket is reused and no PAC script is +// used. +void TestLoadTimingReused(const net::LoadTimingInfo& load_timing_info) { + EXPECT_TRUE(load_timing_info.socket_reused); EXPECT_NE(net::NetLog::Source::kInvalidId, load_timing_info.socket_log_id); - if (expect_reused) { - net::ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing); - EXPECT_FALSE(load_timing_info.send_start.is_null()); - } else { - net::ExpectConnectTimingHasTimes(load_timing_info.connect_timing, - connect_timing_flags); - EXPECT_LE(load_timing_info.connect_timing.connect_end, - load_timing_info.send_start); - } + EXPECT_TRUE(load_timing_info.proxy_resolve_start.is_null()); + EXPECT_TRUE(load_timing_info.proxy_resolve_end.is_null()); + + net::ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing); + EXPECT_FALSE(load_timing_info.send_start.is_null()); EXPECT_LE(load_timing_info.send_start, load_timing_info.send_end); EXPECT_LE(load_timing_info.send_end, load_timing_info.receive_headers_end); - // Not set by these tests. + // Set by URLRequest, at a higher level. + EXPECT_TRUE(load_timing_info.request_start_time.is_null()); + EXPECT_TRUE(load_timing_info.request_start.is_null()); +} + +// Tests LoadTimingInfo in the case a new socket is used and no PAC script is +// used. +void TestLoadTimingNotReused(const net::LoadTimingInfo& load_timing_info, + int connect_timing_flags) { + EXPECT_FALSE(load_timing_info.socket_reused); + EXPECT_NE(net::NetLog::Source::kInvalidId, load_timing_info.socket_log_id); + EXPECT_TRUE(load_timing_info.proxy_resolve_start.is_null()); EXPECT_TRUE(load_timing_info.proxy_resolve_end.is_null()); + net::ExpectConnectTimingHasTimes(load_timing_info.connect_timing, + connect_timing_flags); + EXPECT_LE(load_timing_info.connect_timing.connect_end, + load_timing_info.send_start); + + EXPECT_LE(load_timing_info.send_start, load_timing_info.send_end); + EXPECT_LE(load_timing_info.send_end, load_timing_info.receive_headers_end); + // Set by URLRequest, at a higher level. EXPECT_TRUE(load_timing_info.request_start_time.is_null()); EXPECT_TRUE(load_timing_info.request_start.is_null()); } -void TestLoadTimingReused(const net::LoadTimingInfo& load_timing_info) { - TestLoadTiming(load_timing_info, true, - net::CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY); +// Tests LoadTimingInfo in the case a socket is reused and a PAC script is +// used. +void TestLoadTimingReusedWithPac(const net::LoadTimingInfo& load_timing_info) { + EXPECT_TRUE(load_timing_info.socket_reused); + EXPECT_NE(net::NetLog::Source::kInvalidId, load_timing_info.socket_log_id); + + net::ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing); + + EXPECT_FALSE(load_timing_info.proxy_resolve_start.is_null()); + EXPECT_LE(load_timing_info.proxy_resolve_start, + load_timing_info.proxy_resolve_end); + EXPECT_LE(load_timing_info.proxy_resolve_end, + load_timing_info.send_start); + EXPECT_LE(load_timing_info.send_start, load_timing_info.send_end); + EXPECT_LE(load_timing_info.send_end, load_timing_info.receive_headers_end); + + // Set by URLRequest, at a higher level. + EXPECT_TRUE(load_timing_info.request_start_time.is_null()); + EXPECT_TRUE(load_timing_info.request_start.is_null()); } -void TestLoadTimingNotReused(const net::LoadTimingInfo& load_timing_info, - int connect_timing_flags) { - TestLoadTiming(load_timing_info, false, connect_timing_flags); +// Tests LoadTimingInfo in the case a new socket is used and a PAC script is +// used. +void TestLoadTimingNotReusedWithPac(const net::LoadTimingInfo& load_timing_info, + int connect_timing_flags) { + EXPECT_FALSE(load_timing_info.socket_reused); + EXPECT_NE(net::NetLog::Source::kInvalidId, load_timing_info.socket_log_id); + + EXPECT_FALSE(load_timing_info.proxy_resolve_start.is_null()); + EXPECT_LE(load_timing_info.proxy_resolve_start, + load_timing_info.proxy_resolve_end); + EXPECT_LE(load_timing_info.proxy_resolve_end, + load_timing_info.connect_timing.connect_start); + net::ExpectConnectTimingHasTimes(load_timing_info.connect_timing, + connect_timing_flags); + EXPECT_LE(load_timing_info.connect_timing.connect_end, + load_timing_info.send_start); + + EXPECT_LE(load_timing_info.send_start, load_timing_info.send_end); + EXPECT_LE(load_timing_info.send_end, load_timing_info.receive_headers_end); + + // Set by URLRequest, at a higher level. + EXPECT_TRUE(load_timing_info.request_start_time.is_null()); + EXPECT_TRUE(load_timing_info.request_start.is_null()); } } // namespace @@ -1884,7 +1935,8 @@ TEST_F(HttpNetworkTransactionSpdy2Test, BasicAuthProxyNoKeepAlive) { request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; // Configure against proxy server "myproxy:70". - SpdySessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); + SpdySessionDependencies session_deps( + ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")); CapturingBoundNetLog log; session_deps.net_log = log.bound().net_log(); scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); @@ -1955,6 +2007,11 @@ TEST_F(HttpNetworkTransactionSpdy2Test, BasicAuthProxyNoKeepAlive) { EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); + LoadTimingInfo load_timing_info; + // CONNECT requests and responses are handled at the connect job level, so + // the transaction does not yet have a connection. + EXPECT_FALSE(trans->GetLoadTimingInfo(&load_timing_info)); + TestCompletionCallback callback2; rv = trans->RestartWithAuth( @@ -1975,6 +2032,10 @@ TEST_F(HttpNetworkTransactionSpdy2Test, BasicAuthProxyNoKeepAlive) { // The password prompt info should not be set. EXPECT_TRUE(response->auth_challenge.get() == NULL); + EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); + TestLoadTimingNotReusedWithPac(load_timing_info, + CONNECT_TIMING_HAS_SSL_TIMES); + trans.reset(); session->CloseAllConnections(); } @@ -2244,6 +2305,199 @@ TEST_F(HttpNetworkTransactionSpdy2Test, NetLog::PHASE_NONE); } +// Test the load timing for HTTPS requests with an HTTP proxy. +TEST_F(HttpNetworkTransactionSpdy2Test, HttpProxyLoadTimingNoPacTwoRequests) { + HttpRequestInfo request1; + request1.method = "GET"; + request1.url = GURL("https://www.google.com/1"); + + HttpRequestInfo request2; + request2.method = "GET"; + request2.url = GURL("https://www.google.com/2"); + + // Configure against proxy server "myproxy:70". + SpdySessionDependencies session_deps( + ProxyService::CreateFixed("PROXY myproxy:70")); + CapturingBoundNetLog log; + session_deps.net_log = log.bound().net_log(); + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); + + // 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 /1 HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Connection: keep-alive\r\n\r\n"), + + MockWrite("GET /2 HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Connection: keep-alive\r\n\r\n"), + }; + + // The proxy responds to the connect with a 407, using a persistent + // connection. + MockRead data_reads1[] = { + MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), + + MockRead("HTTP/1.1 200 OK\r\n"), + MockRead("Content-Length: 1\r\n\r\n"), + MockRead(SYNCHRONOUS, "1"), + + MockRead("HTTP/1.1 200 OK\r\n"), + MockRead("Content-Length: 2\r\n\r\n"), + MockRead(SYNCHRONOUS, "22"), + }; + + StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), + data_writes1, arraysize(data_writes1)); + session_deps.socket_factory->AddSocketDataProvider(&data1); + SSLSocketDataProvider ssl(ASYNC, OK); + session_deps.socket_factory->AddSSLSocketDataProvider(&ssl); + + TestCompletionCallback callback1; + scoped_ptr<HttpTransaction> trans1(new HttpNetworkTransaction(session)); + + int rv = trans1->Start(&request1, callback1.callback(), log.bound()); + EXPECT_EQ(ERR_IO_PENDING, rv); + + rv = callback1.WaitForResult(); + EXPECT_EQ(OK, rv); + + const HttpResponseInfo* response1 = trans1->GetResponseInfo(); + ASSERT_TRUE(response1 != NULL); + ASSERT_TRUE(response1->headers != NULL); + EXPECT_EQ(1, response1->headers->GetContentLength()); + + LoadTimingInfo load_timing_info1; + EXPECT_TRUE(trans1->GetLoadTimingInfo(&load_timing_info1)); + TestLoadTimingNotReused(load_timing_info1, CONNECT_TIMING_HAS_SSL_TIMES); + + trans1.reset(); + + TestCompletionCallback callback2; + scoped_ptr<HttpTransaction> trans2(new HttpNetworkTransaction(session)); + + rv = trans2->Start(&request2, callback2.callback(), log.bound()); + EXPECT_EQ(ERR_IO_PENDING, rv); + + rv = callback2.WaitForResult(); + EXPECT_EQ(OK, rv); + + const HttpResponseInfo* response2 = trans2->GetResponseInfo(); + ASSERT_TRUE(response2 != NULL); + ASSERT_TRUE(response2->headers != NULL); + EXPECT_EQ(2, response2->headers->GetContentLength()); + + LoadTimingInfo load_timing_info2; + EXPECT_TRUE(trans2->GetLoadTimingInfo(&load_timing_info2)); + TestLoadTimingReused(load_timing_info2); + + EXPECT_EQ(load_timing_info1.socket_log_id, load_timing_info2.socket_log_id); + + trans2.reset(); + session->CloseAllConnections(); +} + +// Test the load timing for HTTPS requests with an HTTP proxy and a PAC script. +TEST_F(HttpNetworkTransactionSpdy2Test, HttpProxyLoadTimingWithPacTwoRequests) { + HttpRequestInfo request1; + request1.method = "GET"; + request1.url = GURL("https://www.google.com/1"); + + HttpRequestInfo request2; + request2.method = "GET"; + request2.url = GURL("https://www.google.com/2"); + + // Configure against proxy server "myproxy:70". + SpdySessionDependencies session_deps( + ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")); + CapturingBoundNetLog log; + session_deps.net_log = log.bound().net_log(); + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); + + // 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 /1 HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Connection: keep-alive\r\n\r\n"), + + MockWrite("GET /2 HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Connection: keep-alive\r\n\r\n"), + }; + + // The proxy responds to the connect with a 407, using a persistent + // connection. + MockRead data_reads1[] = { + MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), + + MockRead("HTTP/1.1 200 OK\r\n"), + MockRead("Content-Length: 1\r\n\r\n"), + MockRead(SYNCHRONOUS, "1"), + + MockRead("HTTP/1.1 200 OK\r\n"), + MockRead("Content-Length: 2\r\n\r\n"), + MockRead(SYNCHRONOUS, "22"), + }; + + StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), + data_writes1, arraysize(data_writes1)); + session_deps.socket_factory->AddSocketDataProvider(&data1); + SSLSocketDataProvider ssl(ASYNC, OK); + session_deps.socket_factory->AddSSLSocketDataProvider(&ssl); + + TestCompletionCallback callback1; + scoped_ptr<HttpTransaction> trans1(new HttpNetworkTransaction(session)); + + int rv = trans1->Start(&request1, callback1.callback(), log.bound()); + EXPECT_EQ(ERR_IO_PENDING, rv); + + rv = callback1.WaitForResult(); + EXPECT_EQ(OK, rv); + + const HttpResponseInfo* response1 = trans1->GetResponseInfo(); + ASSERT_TRUE(response1 != NULL); + ASSERT_TRUE(response1->headers != NULL); + EXPECT_EQ(1, response1->headers->GetContentLength()); + + LoadTimingInfo load_timing_info1; + EXPECT_TRUE(trans1->GetLoadTimingInfo(&load_timing_info1)); + TestLoadTimingNotReusedWithPac(load_timing_info1, + CONNECT_TIMING_HAS_SSL_TIMES); + + trans1.reset(); + + TestCompletionCallback callback2; + scoped_ptr<HttpTransaction> trans2(new HttpNetworkTransaction(session)); + + rv = trans2->Start(&request2, callback2.callback(), log.bound()); + EXPECT_EQ(ERR_IO_PENDING, rv); + + rv = callback2.WaitForResult(); + EXPECT_EQ(OK, rv); + + const HttpResponseInfo* response2 = trans2->GetResponseInfo(); + ASSERT_TRUE(response2 != NULL); + ASSERT_TRUE(response2->headers != NULL); + EXPECT_EQ(2, response2->headers->GetContentLength()); + + LoadTimingInfo load_timing_info2; + EXPECT_TRUE(trans2->GetLoadTimingInfo(&load_timing_info2)); + TestLoadTimingReusedWithPac(load_timing_info2); + + EXPECT_EQ(load_timing_info1.socket_log_id, load_timing_info2.socket_log_id); + + trans2.reset(); + session->CloseAllConnections(); +} + // Test a simple get through an HTTPS Proxy. TEST_F(HttpNetworkTransactionSpdy2Test, HttpsProxyGet) { HttpRequestInfo request; @@ -4791,8 +5045,10 @@ TEST_F(HttpNetworkTransactionSpdy2Test, HTTPSBadCertificateViaProxy) { // Test HTTPS connections to a site, going through an HTTPS proxy TEST_F(HttpNetworkTransactionSpdy2Test, HTTPSViaHttpsProxy) { - SpdySessionDependencies session_deps(ProxyService::CreateFixed( - "https://proxy:70")); + SpdySessionDependencies session_deps( + ProxyService::CreateFixedFromPacResult("HTTPS proxy:70")); + CapturingNetLog net_log; + session_deps.net_log = &net_log; HttpRequestInfo request; request.method = "GET"; @@ -4843,12 +5099,19 @@ TEST_F(HttpNetworkTransactionSpdy2Test, HTTPSViaHttpsProxy) { EXPECT_EQ(200, response->headers->response_code()); EXPECT_EQ(100, response->headers->GetContentLength()); EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); + + LoadTimingInfo load_timing_info; + EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); + TestLoadTimingNotReusedWithPac(load_timing_info, + CONNECT_TIMING_HAS_SSL_TIMES); } // Test an HTTPS Proxy's ability to redirect a CONNECT request TEST_F(HttpNetworkTransactionSpdy2Test, RedirectOfHttpsConnectViaHttpsProxy) { SpdySessionDependencies session_deps( - ProxyService::CreateFixed("https://proxy:70")); + ProxyService::CreateFixedFromPacResult("HTTPS proxy:70")); + CapturingNetLog net_log; + session_deps.net_log = &net_log; HttpRequestInfo request; request.method = "GET"; @@ -4893,6 +5156,29 @@ TEST_F(HttpNetworkTransactionSpdy2Test, RedirectOfHttpsConnectViaHttpsProxy) { std::string url; EXPECT_TRUE(response->headers->IsRedirect(&url)); EXPECT_EQ("http://login.example.com/", url); + + // In the case of redirects from proxies, HttpNetworkTransaction returns + // timing for the proxy connection instead of the connection to the host, + // and no send / receive times. + // See HttpNetworkTransaction::OnHttpsProxyTunnelResponse. + LoadTimingInfo load_timing_info; + EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); + + EXPECT_FALSE(load_timing_info.socket_reused); + EXPECT_NE(net::NetLog::Source::kInvalidId, load_timing_info.socket_log_id); + + EXPECT_FALSE(load_timing_info.proxy_resolve_start.is_null()); + EXPECT_LE(load_timing_info.proxy_resolve_start, + load_timing_info.proxy_resolve_end); + EXPECT_LE(load_timing_info.proxy_resolve_end, + load_timing_info.connect_timing.connect_start); + ExpectConnectTimingHasTimes( + load_timing_info.connect_timing, + CONNECT_TIMING_HAS_DNS_TIMES | CONNECT_TIMING_HAS_SSL_TIMES); + + EXPECT_TRUE(load_timing_info.send_start.is_null()); + EXPECT_TRUE(load_timing_info.send_end.is_null()); + EXPECT_TRUE(load_timing_info.receive_headers_end.is_null()); } // Test an HTTPS (SPDY) Proxy's ability to redirect a CONNECT request @@ -5066,7 +5352,7 @@ TEST_F(HttpNetworkTransactionSpdy2Test, BasicAuthSpdyProxy) { // Configure against https proxy server "myproxy:70". SpdySessionDependencies session_deps( - ProxyService::CreateFixed("https://myproxy:70")); + ProxyService::CreateFixedFromPacResult("HTTPS myproxy:70")); CapturingBoundNetLog log; session_deps.net_log = log.bound().net_log(); scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); @@ -5190,6 +5476,11 @@ TEST_F(HttpNetworkTransactionSpdy2Test, BasicAuthSpdyProxy) { // The password prompt info should not be set. EXPECT_TRUE(response->auth_challenge.get() == NULL); + LoadTimingInfo load_timing_info; + EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); + TestLoadTimingNotReusedWithPac(load_timing_info, + CONNECT_TIMING_HAS_SSL_TIMES); + trans.reset(); session->CloseAllConnections(); } @@ -5213,7 +5504,7 @@ TEST_F(HttpNetworkTransactionSpdy2Test, CrossOriginProxyPush) { // Configure against https proxy server "myproxy:70". SpdySessionDependencies session_deps( - ProxyService::CreateFixed("https://myproxy:70")); + ProxyService::CreateFixedFromPacResult("HTTPS myproxy:70")); CapturingBoundNetLog log; session_deps.net_log = log.bound().net_log(); @@ -5288,6 +5579,11 @@ TEST_F(HttpNetworkTransactionSpdy2Test, CrossOriginProxyPush) { EXPECT_EQ(OK, rv); EXPECT_EQ("hello!", response_data); + LoadTimingInfo load_timing_info; + EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); + TestLoadTimingNotReusedWithPac(load_timing_info, + CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY); + // Verify the pushed stream. EXPECT_TRUE(push_response->headers != NULL); EXPECT_EQ(200, push_response->headers->response_code()); @@ -5296,6 +5592,14 @@ TEST_F(HttpNetworkTransactionSpdy2Test, CrossOriginProxyPush) { EXPECT_EQ(OK, rv); EXPECT_EQ("pushed", response_data); + LoadTimingInfo push_load_timing_info; + EXPECT_TRUE(push_trans->GetLoadTimingInfo(&push_load_timing_info)); + TestLoadTimingReusedWithPac(push_load_timing_info); + // The transactions should share a socket ID, despite being for different + // origins. + EXPECT_EQ(load_timing_info.socket_log_id, + push_load_timing_info.socket_log_id); + trans.reset(); push_trans.reset(); session->CloseAllConnections(); @@ -5858,7 +6162,9 @@ TEST_F(HttpNetworkTransactionSpdy2Test, SOCKS4_HTTP_GET) { request.load_flags = 0; SpdySessionDependencies session_deps( - ProxyService::CreateFixed("socks4://myproxy:1080")); + ProxyService::CreateFixedFromPacResult("SOCKS myproxy:1080")); + CapturingNetLog net_log; + session_deps.net_log = &net_log; scoped_ptr<HttpTransaction> trans( new HttpNetworkTransaction(CreateSession(&session_deps))); @@ -5896,6 +6202,11 @@ TEST_F(HttpNetworkTransactionSpdy2Test, SOCKS4_HTTP_GET) { const HttpResponseInfo* response = trans->GetResponseInfo(); ASSERT_TRUE(response != NULL); + LoadTimingInfo load_timing_info; + EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); + TestLoadTimingNotReusedWithPac(load_timing_info, + CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY); + std::string response_text; rv = ReadTransaction(trans.get(), &response_text); EXPECT_EQ(OK, rv); @@ -5909,7 +6220,9 @@ TEST_F(HttpNetworkTransactionSpdy2Test, SOCKS4_SSL_GET) { request.load_flags = 0; SpdySessionDependencies session_deps( - ProxyService::CreateFixed("socks4://myproxy:1080")); + ProxyService::CreateFixedFromPacResult("SOCKS myproxy:1080")); + CapturingNetLog net_log; + session_deps.net_log = &net_log; scoped_ptr<HttpTransaction> trans( new HttpNetworkTransaction(CreateSession(&session_deps))); @@ -5949,9 +6262,72 @@ TEST_F(HttpNetworkTransactionSpdy2Test, SOCKS4_SSL_GET) { rv = callback.WaitForResult(); EXPECT_EQ(OK, rv); + LoadTimingInfo load_timing_info; + EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); + TestLoadTimingNotReusedWithPac(load_timing_info, + CONNECT_TIMING_HAS_SSL_TIMES); + + const HttpResponseInfo* response = trans->GetResponseInfo(); + ASSERT_TRUE(response != NULL); + + std::string response_text; + rv = ReadTransaction(trans.get(), &response_text); + EXPECT_EQ(OK, rv); + EXPECT_EQ("Payload", response_text); +} + +TEST_F(HttpNetworkTransactionSpdy2Test, SOCKS4_HTTP_GET_no_PAC) { + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("http://www.google.com/"); + request.load_flags = 0; + + SpdySessionDependencies session_deps( + ProxyService::CreateFixed("socks4://myproxy:1080")); + CapturingNetLog net_log; + session_deps.net_log = &net_log; + + scoped_ptr<HttpTransaction> trans( + new HttpNetworkTransaction(CreateSession(&session_deps))); + + char write_buffer[] = { 0x04, 0x01, 0x00, 0x50, 127, 0, 0, 1, 0 }; + char read_buffer[] = { 0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0 }; + + MockWrite data_writes[] = { + MockWrite(ASYNC, write_buffer, arraysize(write_buffer)), + MockWrite("GET / HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Connection: keep-alive\r\n\r\n") + }; + + MockRead data_reads[] = { + MockRead(ASYNC, read_buffer, arraysize(read_buffer)), + MockRead("HTTP/1.0 200 OK\r\n"), + MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"), + MockRead("Payload"), + MockRead(SYNCHRONOUS, OK) + }; + + StaticSocketDataProvider data(data_reads, arraysize(data_reads), + data_writes, arraysize(data_writes)); + session_deps.socket_factory->AddSocketDataProvider(&data); + + TestCompletionCallback callback; + + int rv = trans->Start(&request, callback.callback(), BoundNetLog()); + EXPECT_EQ(ERR_IO_PENDING, rv); + + rv = callback.WaitForResult(); + EXPECT_EQ(OK, rv); + const HttpResponseInfo* response = trans->GetResponseInfo(); ASSERT_TRUE(response != NULL); + LoadTimingInfo load_timing_info; + EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); + TestLoadTimingNotReused(load_timing_info, + CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY); + std::string response_text; rv = ReadTransaction(trans.get(), &response_text); EXPECT_EQ(OK, rv); @@ -5965,7 +6341,9 @@ TEST_F(HttpNetworkTransactionSpdy2Test, SOCKS5_HTTP_GET) { request.load_flags = 0; SpdySessionDependencies session_deps( - ProxyService::CreateFixed("socks5://myproxy:1080")); + ProxyService::CreateFixedFromPacResult("SOCKS5 myproxy:1080")); + CapturingNetLog net_log; + session_deps.net_log = &net_log; scoped_ptr<HttpTransaction> trans( new HttpNetworkTransaction(CreateSession(&session_deps))); @@ -6017,6 +6395,11 @@ TEST_F(HttpNetworkTransactionSpdy2Test, SOCKS5_HTTP_GET) { const HttpResponseInfo* response = trans->GetResponseInfo(); ASSERT_TRUE(response != NULL); + LoadTimingInfo load_timing_info; + EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); + TestLoadTimingNotReusedWithPac(load_timing_info, + CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY); + std::string response_text; rv = ReadTransaction(trans.get(), &response_text); EXPECT_EQ(OK, rv); @@ -6030,7 +6413,9 @@ TEST_F(HttpNetworkTransactionSpdy2Test, SOCKS5_SSL_GET) { request.load_flags = 0; SpdySessionDependencies session_deps( - ProxyService::CreateFixed("socks5://myproxy:1080")); + ProxyService::CreateFixedFromPacResult("SOCKS5 myproxy:1080")); + CapturingNetLog net_log; + session_deps.net_log = &net_log; scoped_ptr<HttpTransaction> trans( new HttpNetworkTransaction(CreateSession(&session_deps))); @@ -6087,6 +6472,11 @@ TEST_F(HttpNetworkTransactionSpdy2Test, SOCKS5_SSL_GET) { const HttpResponseInfo* response = trans->GetResponseInfo(); ASSERT_TRUE(response != NULL); + LoadTimingInfo load_timing_info; + EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); + TestLoadTimingNotReusedWithPac(load_timing_info, + CONNECT_TIMING_HAS_SSL_TIMES); + std::string response_text; rv = ReadTransaction(trans.get(), &response_text); EXPECT_EQ(OK, rv); @@ -7731,6 +8121,8 @@ TEST_F(HttpNetworkTransactionSpdy2Test, SpdySessionDependencies session_deps(new ProxyService( new ProxyConfigServiceFixed(proxy_config), capturing_proxy_resolver, NULL)); + CapturingNetLog net_log; + session_deps.net_log = &net_log; HttpRequestInfo request; request.method = "GET"; @@ -7826,6 +8218,11 @@ TEST_F(HttpNetworkTransactionSpdy2Test, EXPECT_EQ("https://www.google.com/", capturing_proxy_resolver->resolved()[1].spec()); + LoadTimingInfo load_timing_info; + EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); + TestLoadTimingNotReusedWithPac(load_timing_info, + CONNECT_TIMING_HAS_SSL_TIMES); + HttpStreamFactory::SetNextProtos(std::vector<std::string>()); HttpStreamFactory::set_use_alternate_protocols(false); } @@ -8772,7 +9169,10 @@ TEST_F(HttpNetworkTransactionSpdy2Test, SpdyAlternateProtocolThroughProxy) { MakeNextProtos( "http/1.1", "http1.1", "spdy/2", "spdy", NULL)); - SpdySessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); + SpdySessionDependencies session_deps( + ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")); + CapturingNetLog net_log; + session_deps.net_log = &net_log; HttpAuthHandlerMock::Factory* auth_factory = new HttpAuthHandlerMock::Factory(); HttpAuthHandlerMock* auth_handler = new HttpAuthHandlerMock(); @@ -8910,6 +9310,11 @@ TEST_F(HttpNetworkTransactionSpdy2Test, SpdyAlternateProtocolThroughProxy) { EXPECT_EQ("https", request_url.scheme()); EXPECT_EQ("www.google.com", request_url.host()); + LoadTimingInfo load_timing_info; + EXPECT_TRUE(trans_2->GetLoadTimingInfo(&load_timing_info)); + TestLoadTimingNotReusedWithPac(load_timing_info, + CONNECT_TIMING_HAS_SSL_TIMES); + HttpStreamFactory::SetNextProtos(std::vector<std::string>()); HttpStreamFactory::set_use_alternate_protocols(false); } @@ -8955,7 +9360,8 @@ TEST_F(HttpNetworkTransactionSpdy2Test, SimpleCancel) { // Test a basic GET request through a proxy. TEST_F(HttpNetworkTransactionSpdy2Test, ProxyGet) { - SpdySessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); + SpdySessionDependencies session_deps( + ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")); CapturingBoundNetLog log; session_deps.net_log = log.bound().net_log(); scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); @@ -8999,11 +9405,17 @@ TEST_F(HttpNetworkTransactionSpdy2Test, ProxyGet) { EXPECT_EQ(100, response->headers->GetContentLength()); EXPECT_TRUE(response->was_fetched_via_proxy); EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); + + LoadTimingInfo load_timing_info; + EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); + TestLoadTimingNotReusedWithPac(load_timing_info, + CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY); } // Test a basic HTTPS GET request through a proxy. TEST_F(HttpNetworkTransactionSpdy2Test, ProxyTunnelGet) { - SpdySessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); + SpdySessionDependencies session_deps( + ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")); CapturingBoundNetLog log; session_deps.net_log = log.bound().net_log(); scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); @@ -9065,6 +9477,11 @@ TEST_F(HttpNetworkTransactionSpdy2Test, ProxyTunnelGet) { EXPECT_EQ(100, response->headers->GetContentLength()); EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); EXPECT_TRUE(response->was_fetched_via_proxy); + + LoadTimingInfo load_timing_info; + EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); + TestLoadTimingNotReusedWithPac(load_timing_info, + CONNECT_TIMING_HAS_SSL_TIMES); } // Test a basic HTTPS GET request through a proxy, but the server hangs up diff --git a/net/http/http_network_transaction_spdy3_unittest.cc b/net/http/http_network_transaction_spdy3_unittest.cc index f2ee049..03a2c8e 100644 --- a/net/http/http_network_transaction_spdy3_unittest.cc +++ b/net/http/http_network_transaction_spdy3_unittest.cc @@ -143,42 +143,93 @@ bool GetHeaders(DictionaryValue* params, std::string* headers) { return true; } -// |connect_time_flags| is ignored if expect_reused is true. -void TestLoadTiming(const net::LoadTimingInfo& load_timing_info, - bool expect_reused, int connect_timing_flags) { - EXPECT_EQ(expect_reused, load_timing_info.socket_reused); +// Tests LoadTimingInfo in the case a socket is reused and no PAC script is +// used. +void TestLoadTimingReused(const net::LoadTimingInfo& load_timing_info) { + EXPECT_TRUE(load_timing_info.socket_reused); EXPECT_NE(net::NetLog::Source::kInvalidId, load_timing_info.socket_log_id); - if (expect_reused) { - net::ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing); - EXPECT_FALSE(load_timing_info.send_start.is_null()); - } else { - net::ExpectConnectTimingHasTimes(load_timing_info.connect_timing, - connect_timing_flags); - EXPECT_LE(load_timing_info.connect_timing.connect_end, - load_timing_info.send_start); - } + EXPECT_TRUE(load_timing_info.proxy_resolve_start.is_null()); + EXPECT_TRUE(load_timing_info.proxy_resolve_end.is_null()); + + net::ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing); + EXPECT_FALSE(load_timing_info.send_start.is_null()); EXPECT_LE(load_timing_info.send_start, load_timing_info.send_end); EXPECT_LE(load_timing_info.send_end, load_timing_info.receive_headers_end); - // Not set by these tests. + // Set by URLRequest, at a higher level. + EXPECT_TRUE(load_timing_info.request_start_time.is_null()); + EXPECT_TRUE(load_timing_info.request_start.is_null()); +} + +// Tests LoadTimingInfo in the case a new socket is used and no PAC script is +// used. +void TestLoadTimingNotReused(const net::LoadTimingInfo& load_timing_info, + int connect_timing_flags) { + EXPECT_FALSE(load_timing_info.socket_reused); + EXPECT_NE(net::NetLog::Source::kInvalidId, load_timing_info.socket_log_id); + EXPECT_TRUE(load_timing_info.proxy_resolve_start.is_null()); EXPECT_TRUE(load_timing_info.proxy_resolve_end.is_null()); + net::ExpectConnectTimingHasTimes(load_timing_info.connect_timing, + connect_timing_flags); + EXPECT_LE(load_timing_info.connect_timing.connect_end, + load_timing_info.send_start); + + EXPECT_LE(load_timing_info.send_start, load_timing_info.send_end); + EXPECT_LE(load_timing_info.send_end, load_timing_info.receive_headers_end); + // Set by URLRequest, at a higher level. EXPECT_TRUE(load_timing_info.request_start_time.is_null()); EXPECT_TRUE(load_timing_info.request_start.is_null()); } -void TestLoadTimingReused(const net::LoadTimingInfo& load_timing_info) { - TestLoadTiming(load_timing_info, true, - net::CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY); +// Tests LoadTimingInfo in the case a socket is reused and a PAC script is +// used. +void TestLoadTimingReusedWithPac(const net::LoadTimingInfo& load_timing_info) { + EXPECT_TRUE(load_timing_info.socket_reused); + EXPECT_NE(net::NetLog::Source::kInvalidId, load_timing_info.socket_log_id); + + net::ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing); + + EXPECT_FALSE(load_timing_info.proxy_resolve_start.is_null()); + EXPECT_LE(load_timing_info.proxy_resolve_start, + load_timing_info.proxy_resolve_end); + EXPECT_LE(load_timing_info.proxy_resolve_end, + load_timing_info.send_start); + EXPECT_LE(load_timing_info.send_start, load_timing_info.send_end); + EXPECT_LE(load_timing_info.send_end, load_timing_info.receive_headers_end); + + // Set by URLRequest, at a higher level. + EXPECT_TRUE(load_timing_info.request_start_time.is_null()); + EXPECT_TRUE(load_timing_info.request_start.is_null()); } -void TestLoadTimingNotReused(const net::LoadTimingInfo& load_timing_info, - int connect_timing_flags) { - TestLoadTiming(load_timing_info, false, connect_timing_flags); +// Tests LoadTimingInfo in the case a new socket is used and a PAC script is +// used. +void TestLoadTimingNotReusedWithPac(const net::LoadTimingInfo& load_timing_info, + int connect_timing_flags) { + EXPECT_FALSE(load_timing_info.socket_reused); + EXPECT_NE(net::NetLog::Source::kInvalidId, load_timing_info.socket_log_id); + + EXPECT_FALSE(load_timing_info.proxy_resolve_start.is_null()); + EXPECT_LE(load_timing_info.proxy_resolve_start, + load_timing_info.proxy_resolve_end); + EXPECT_LE(load_timing_info.proxy_resolve_end, + load_timing_info.connect_timing.connect_start); + net::ExpectConnectTimingHasTimes(load_timing_info.connect_timing, + connect_timing_flags); + EXPECT_LE(load_timing_info.connect_timing.connect_end, + load_timing_info.send_start); + + EXPECT_LE(load_timing_info.send_start, load_timing_info.send_end); + EXPECT_LE(load_timing_info.send_end, load_timing_info.receive_headers_end); + + // Set by URLRequest, at a higher level. + EXPECT_TRUE(load_timing_info.request_start_time.is_null()); + EXPECT_TRUE(load_timing_info.request_start.is_null()); } } // namespace @@ -1884,7 +1935,8 @@ TEST_F(HttpNetworkTransactionSpdy3Test, BasicAuthProxyNoKeepAlive) { request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; // Configure against proxy server "myproxy:70". - SpdySessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); + SpdySessionDependencies session_deps( + ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")); CapturingBoundNetLog log; session_deps.net_log = log.bound().net_log(); scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); @@ -1955,6 +2007,11 @@ TEST_F(HttpNetworkTransactionSpdy3Test, BasicAuthProxyNoKeepAlive) { EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); + LoadTimingInfo load_timing_info; + // CONNECT requests and responses are handled at the connect job level, so + // the transaction does not yet have a connection. + EXPECT_FALSE(trans->GetLoadTimingInfo(&load_timing_info)); + TestCompletionCallback callback2; rv = trans->RestartWithAuth( @@ -1975,6 +2032,10 @@ TEST_F(HttpNetworkTransactionSpdy3Test, BasicAuthProxyNoKeepAlive) { // The password prompt info should not be set. EXPECT_TRUE(response->auth_challenge.get() == NULL); + EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); + TestLoadTimingNotReusedWithPac(load_timing_info, + CONNECT_TIMING_HAS_SSL_TIMES); + trans.reset(); session->CloseAllConnections(); } @@ -2244,6 +2305,199 @@ TEST_F(HttpNetworkTransactionSpdy3Test, NetLog::PHASE_NONE); } +// Test the load timing for HTTPS requests with an HTTP proxy. +TEST_F(HttpNetworkTransactionSpdy3Test, HttpProxyLoadTimingNoPacTwoRequests) { + HttpRequestInfo request1; + request1.method = "GET"; + request1.url = GURL("https://www.google.com/1"); + + HttpRequestInfo request2; + request2.method = "GET"; + request2.url = GURL("https://www.google.com/2"); + + // Configure against proxy server "myproxy:70". + SpdySessionDependencies session_deps( + ProxyService::CreateFixed("PROXY myproxy:70")); + CapturingBoundNetLog log; + session_deps.net_log = log.bound().net_log(); + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); + + // 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 /1 HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Connection: keep-alive\r\n\r\n"), + + MockWrite("GET /2 HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Connection: keep-alive\r\n\r\n"), + }; + + // The proxy responds to the connect with a 407, using a persistent + // connection. + MockRead data_reads1[] = { + MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), + + MockRead("HTTP/1.1 200 OK\r\n"), + MockRead("Content-Length: 1\r\n\r\n"), + MockRead(SYNCHRONOUS, "1"), + + MockRead("HTTP/1.1 200 OK\r\n"), + MockRead("Content-Length: 2\r\n\r\n"), + MockRead(SYNCHRONOUS, "22"), + }; + + StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), + data_writes1, arraysize(data_writes1)); + session_deps.socket_factory->AddSocketDataProvider(&data1); + SSLSocketDataProvider ssl(ASYNC, OK); + session_deps.socket_factory->AddSSLSocketDataProvider(&ssl); + + TestCompletionCallback callback1; + scoped_ptr<HttpTransaction> trans1(new HttpNetworkTransaction(session)); + + int rv = trans1->Start(&request1, callback1.callback(), log.bound()); + EXPECT_EQ(ERR_IO_PENDING, rv); + + rv = callback1.WaitForResult(); + EXPECT_EQ(OK, rv); + + const HttpResponseInfo* response1 = trans1->GetResponseInfo(); + ASSERT_TRUE(response1 != NULL); + ASSERT_TRUE(response1->headers != NULL); + EXPECT_EQ(1, response1->headers->GetContentLength()); + + LoadTimingInfo load_timing_info1; + EXPECT_TRUE(trans1->GetLoadTimingInfo(&load_timing_info1)); + TestLoadTimingNotReused(load_timing_info1, CONNECT_TIMING_HAS_SSL_TIMES); + + trans1.reset(); + + TestCompletionCallback callback2; + scoped_ptr<HttpTransaction> trans2(new HttpNetworkTransaction(session)); + + rv = trans2->Start(&request2, callback2.callback(), log.bound()); + EXPECT_EQ(ERR_IO_PENDING, rv); + + rv = callback2.WaitForResult(); + EXPECT_EQ(OK, rv); + + const HttpResponseInfo* response2 = trans2->GetResponseInfo(); + ASSERT_TRUE(response2 != NULL); + ASSERT_TRUE(response2->headers != NULL); + EXPECT_EQ(2, response2->headers->GetContentLength()); + + LoadTimingInfo load_timing_info2; + EXPECT_TRUE(trans2->GetLoadTimingInfo(&load_timing_info2)); + TestLoadTimingReused(load_timing_info2); + + EXPECT_EQ(load_timing_info1.socket_log_id, load_timing_info2.socket_log_id); + + trans2.reset(); + session->CloseAllConnections(); +} + +// Test the load timing for HTTPS requests with an HTTP proxy and a PAC script. +TEST_F(HttpNetworkTransactionSpdy3Test, HttpProxyLoadTimingWithPacTwoRequests) { + HttpRequestInfo request1; + request1.method = "GET"; + request1.url = GURL("https://www.google.com/1"); + + HttpRequestInfo request2; + request2.method = "GET"; + request2.url = GURL("https://www.google.com/2"); + + // Configure against proxy server "myproxy:70". + SpdySessionDependencies session_deps( + ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")); + CapturingBoundNetLog log; + session_deps.net_log = log.bound().net_log(); + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); + + // 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 /1 HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Connection: keep-alive\r\n\r\n"), + + MockWrite("GET /2 HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Connection: keep-alive\r\n\r\n"), + }; + + // The proxy responds to the connect with a 407, using a persistent + // connection. + MockRead data_reads1[] = { + MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), + + MockRead("HTTP/1.1 200 OK\r\n"), + MockRead("Content-Length: 1\r\n\r\n"), + MockRead(SYNCHRONOUS, "1"), + + MockRead("HTTP/1.1 200 OK\r\n"), + MockRead("Content-Length: 2\r\n\r\n"), + MockRead(SYNCHRONOUS, "22"), + }; + + StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), + data_writes1, arraysize(data_writes1)); + session_deps.socket_factory->AddSocketDataProvider(&data1); + SSLSocketDataProvider ssl(ASYNC, OK); + session_deps.socket_factory->AddSSLSocketDataProvider(&ssl); + + TestCompletionCallback callback1; + scoped_ptr<HttpTransaction> trans1(new HttpNetworkTransaction(session)); + + int rv = trans1->Start(&request1, callback1.callback(), log.bound()); + EXPECT_EQ(ERR_IO_PENDING, rv); + + rv = callback1.WaitForResult(); + EXPECT_EQ(OK, rv); + + const HttpResponseInfo* response1 = trans1->GetResponseInfo(); + ASSERT_TRUE(response1 != NULL); + ASSERT_TRUE(response1->headers != NULL); + EXPECT_EQ(1, response1->headers->GetContentLength()); + + LoadTimingInfo load_timing_info1; + EXPECT_TRUE(trans1->GetLoadTimingInfo(&load_timing_info1)); + TestLoadTimingNotReusedWithPac(load_timing_info1, + CONNECT_TIMING_HAS_SSL_TIMES); + + trans1.reset(); + + TestCompletionCallback callback2; + scoped_ptr<HttpTransaction> trans2(new HttpNetworkTransaction(session)); + + rv = trans2->Start(&request2, callback2.callback(), log.bound()); + EXPECT_EQ(ERR_IO_PENDING, rv); + + rv = callback2.WaitForResult(); + EXPECT_EQ(OK, rv); + + const HttpResponseInfo* response2 = trans2->GetResponseInfo(); + ASSERT_TRUE(response2 != NULL); + ASSERT_TRUE(response2->headers != NULL); + EXPECT_EQ(2, response2->headers->GetContentLength()); + + LoadTimingInfo load_timing_info2; + EXPECT_TRUE(trans2->GetLoadTimingInfo(&load_timing_info2)); + TestLoadTimingReusedWithPac(load_timing_info2); + + EXPECT_EQ(load_timing_info1.socket_log_id, load_timing_info2.socket_log_id); + + trans2.reset(); + session->CloseAllConnections(); +} + // Test a simple get through an HTTPS Proxy. TEST_F(HttpNetworkTransactionSpdy3Test, HttpsProxyGet) { HttpRequestInfo request; @@ -4791,8 +5045,10 @@ TEST_F(HttpNetworkTransactionSpdy3Test, HTTPSBadCertificateViaProxy) { // Test HTTPS connections to a site, going through an HTTPS proxy TEST_F(HttpNetworkTransactionSpdy3Test, HTTPSViaHttpsProxy) { - SpdySessionDependencies session_deps(ProxyService::CreateFixed( - "https://proxy:70")); + SpdySessionDependencies session_deps( + ProxyService::CreateFixedFromPacResult("HTTPS proxy:70")); + CapturingNetLog net_log; + session_deps.net_log = &net_log; HttpRequestInfo request; request.method = "GET"; @@ -4843,12 +5099,19 @@ TEST_F(HttpNetworkTransactionSpdy3Test, HTTPSViaHttpsProxy) { EXPECT_EQ(200, response->headers->response_code()); EXPECT_EQ(100, response->headers->GetContentLength()); EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); + + LoadTimingInfo load_timing_info; + EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); + TestLoadTimingNotReusedWithPac(load_timing_info, + CONNECT_TIMING_HAS_SSL_TIMES); } // Test an HTTPS Proxy's ability to redirect a CONNECT request TEST_F(HttpNetworkTransactionSpdy3Test, RedirectOfHttpsConnectViaHttpsProxy) { SpdySessionDependencies session_deps( - ProxyService::CreateFixed("https://proxy:70")); + ProxyService::CreateFixedFromPacResult("HTTPS proxy:70")); + CapturingNetLog net_log; + session_deps.net_log = &net_log; HttpRequestInfo request; request.method = "GET"; @@ -4893,6 +5156,29 @@ TEST_F(HttpNetworkTransactionSpdy3Test, RedirectOfHttpsConnectViaHttpsProxy) { std::string url; EXPECT_TRUE(response->headers->IsRedirect(&url)); EXPECT_EQ("http://login.example.com/", url); + + // In the case of redirects from proxies, HttpNetworkTransaction returns + // timing for the proxy connection instead of the connection to the host, + // and no send / receive times. + // See HttpNetworkTransaction::OnHttpsProxyTunnelResponse. + LoadTimingInfo load_timing_info; + EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); + + EXPECT_FALSE(load_timing_info.socket_reused); + EXPECT_NE(net::NetLog::Source::kInvalidId, load_timing_info.socket_log_id); + + EXPECT_FALSE(load_timing_info.proxy_resolve_start.is_null()); + EXPECT_LE(load_timing_info.proxy_resolve_start, + load_timing_info.proxy_resolve_end); + EXPECT_LE(load_timing_info.proxy_resolve_end, + load_timing_info.connect_timing.connect_start); + ExpectConnectTimingHasTimes( + load_timing_info.connect_timing, + CONNECT_TIMING_HAS_DNS_TIMES | CONNECT_TIMING_HAS_SSL_TIMES); + + EXPECT_TRUE(load_timing_info.send_start.is_null()); + EXPECT_TRUE(load_timing_info.send_end.is_null()); + EXPECT_TRUE(load_timing_info.receive_headers_end.is_null()); } // Test an HTTPS (SPDY) Proxy's ability to redirect a CONNECT request @@ -5066,7 +5352,7 @@ TEST_F(HttpNetworkTransactionSpdy3Test, BasicAuthSpdyProxy) { // Configure against https proxy server "myproxy:70". SpdySessionDependencies session_deps( - ProxyService::CreateFixed("https://myproxy:70")); + ProxyService::CreateFixedFromPacResult("HTTPS myproxy:70")); CapturingBoundNetLog log; session_deps.net_log = log.bound().net_log(); scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); @@ -5190,6 +5476,11 @@ TEST_F(HttpNetworkTransactionSpdy3Test, BasicAuthSpdyProxy) { // The password prompt info should not be set. EXPECT_TRUE(response->auth_challenge.get() == NULL); + LoadTimingInfo load_timing_info; + EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); + TestLoadTimingNotReusedWithPac(load_timing_info, + CONNECT_TIMING_HAS_SSL_TIMES); + trans.reset(); session->CloseAllConnections(); } @@ -5213,7 +5504,7 @@ TEST_F(HttpNetworkTransactionSpdy3Test, CrossOriginProxyPush) { // Configure against https proxy server "myproxy:70". SpdySessionDependencies session_deps( - ProxyService::CreateFixed("https://myproxy:70")); + ProxyService::CreateFixedFromPacResult("HTTPS myproxy:70")); CapturingBoundNetLog log; session_deps.net_log = log.bound().net_log(); @@ -5288,6 +5579,11 @@ TEST_F(HttpNetworkTransactionSpdy3Test, CrossOriginProxyPush) { EXPECT_EQ(OK, rv); EXPECT_EQ("hello!", response_data); + LoadTimingInfo load_timing_info; + EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); + TestLoadTimingNotReusedWithPac(load_timing_info, + CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY); + // Verify the pushed stream. EXPECT_TRUE(push_response->headers != NULL); EXPECT_EQ(200, push_response->headers->response_code()); @@ -5296,6 +5592,14 @@ TEST_F(HttpNetworkTransactionSpdy3Test, CrossOriginProxyPush) { EXPECT_EQ(OK, rv); EXPECT_EQ("pushed", response_data); + LoadTimingInfo push_load_timing_info; + EXPECT_TRUE(push_trans->GetLoadTimingInfo(&push_load_timing_info)); + TestLoadTimingReusedWithPac(push_load_timing_info); + // The transactions should share a socket ID, despite being for different + // origins. + EXPECT_EQ(load_timing_info.socket_log_id, + push_load_timing_info.socket_log_id); + trans.reset(); push_trans.reset(); session->CloseAllConnections(); @@ -5858,7 +6162,9 @@ TEST_F(HttpNetworkTransactionSpdy3Test, SOCKS4_HTTP_GET) { request.load_flags = 0; SpdySessionDependencies session_deps( - ProxyService::CreateFixed("socks4://myproxy:1080")); + ProxyService::CreateFixedFromPacResult("SOCKS myproxy:1080")); + CapturingNetLog net_log; + session_deps.net_log = &net_log; scoped_ptr<HttpTransaction> trans( new HttpNetworkTransaction(CreateSession(&session_deps))); @@ -5896,6 +6202,11 @@ TEST_F(HttpNetworkTransactionSpdy3Test, SOCKS4_HTTP_GET) { const HttpResponseInfo* response = trans->GetResponseInfo(); ASSERT_TRUE(response != NULL); + LoadTimingInfo load_timing_info; + EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); + TestLoadTimingNotReusedWithPac(load_timing_info, + CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY); + std::string response_text; rv = ReadTransaction(trans.get(), &response_text); EXPECT_EQ(OK, rv); @@ -5909,7 +6220,9 @@ TEST_F(HttpNetworkTransactionSpdy3Test, SOCKS4_SSL_GET) { request.load_flags = 0; SpdySessionDependencies session_deps( - ProxyService::CreateFixed("socks4://myproxy:1080")); + ProxyService::CreateFixedFromPacResult("SOCKS myproxy:1080")); + CapturingNetLog net_log; + session_deps.net_log = &net_log; scoped_ptr<HttpTransaction> trans( new HttpNetworkTransaction(CreateSession(&session_deps))); @@ -5949,9 +6262,72 @@ TEST_F(HttpNetworkTransactionSpdy3Test, SOCKS4_SSL_GET) { rv = callback.WaitForResult(); EXPECT_EQ(OK, rv); + LoadTimingInfo load_timing_info; + EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); + TestLoadTimingNotReusedWithPac(load_timing_info, + CONNECT_TIMING_HAS_SSL_TIMES); + + const HttpResponseInfo* response = trans->GetResponseInfo(); + ASSERT_TRUE(response != NULL); + + std::string response_text; + rv = ReadTransaction(trans.get(), &response_text); + EXPECT_EQ(OK, rv); + EXPECT_EQ("Payload", response_text); +} + +TEST_F(HttpNetworkTransactionSpdy3Test, SOCKS4_HTTP_GET_no_PAC) { + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("http://www.google.com/"); + request.load_flags = 0; + + SpdySessionDependencies session_deps( + ProxyService::CreateFixed("socks4://myproxy:1080")); + CapturingNetLog net_log; + session_deps.net_log = &net_log; + + scoped_ptr<HttpTransaction> trans( + new HttpNetworkTransaction(CreateSession(&session_deps))); + + char write_buffer[] = { 0x04, 0x01, 0x00, 0x50, 127, 0, 0, 1, 0 }; + char read_buffer[] = { 0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0 }; + + MockWrite data_writes[] = { + MockWrite(ASYNC, write_buffer, arraysize(write_buffer)), + MockWrite("GET / HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Connection: keep-alive\r\n\r\n") + }; + + MockRead data_reads[] = { + MockRead(ASYNC, read_buffer, arraysize(read_buffer)), + MockRead("HTTP/1.0 200 OK\r\n"), + MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"), + MockRead("Payload"), + MockRead(SYNCHRONOUS, OK) + }; + + StaticSocketDataProvider data(data_reads, arraysize(data_reads), + data_writes, arraysize(data_writes)); + session_deps.socket_factory->AddSocketDataProvider(&data); + + TestCompletionCallback callback; + + int rv = trans->Start(&request, callback.callback(), BoundNetLog()); + EXPECT_EQ(ERR_IO_PENDING, rv); + + rv = callback.WaitForResult(); + EXPECT_EQ(OK, rv); + const HttpResponseInfo* response = trans->GetResponseInfo(); ASSERT_TRUE(response != NULL); + LoadTimingInfo load_timing_info; + EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); + TestLoadTimingNotReused(load_timing_info, + CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY); + std::string response_text; rv = ReadTransaction(trans.get(), &response_text); EXPECT_EQ(OK, rv); @@ -5965,7 +6341,9 @@ TEST_F(HttpNetworkTransactionSpdy3Test, SOCKS5_HTTP_GET) { request.load_flags = 0; SpdySessionDependencies session_deps( - ProxyService::CreateFixed("socks5://myproxy:1080")); + ProxyService::CreateFixedFromPacResult("SOCKS5 myproxy:1080")); + CapturingNetLog net_log; + session_deps.net_log = &net_log; scoped_ptr<HttpTransaction> trans( new HttpNetworkTransaction(CreateSession(&session_deps))); @@ -6017,6 +6395,11 @@ TEST_F(HttpNetworkTransactionSpdy3Test, SOCKS5_HTTP_GET) { const HttpResponseInfo* response = trans->GetResponseInfo(); ASSERT_TRUE(response != NULL); + LoadTimingInfo load_timing_info; + EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); + TestLoadTimingNotReusedWithPac(load_timing_info, + CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY); + std::string response_text; rv = ReadTransaction(trans.get(), &response_text); EXPECT_EQ(OK, rv); @@ -6030,7 +6413,9 @@ TEST_F(HttpNetworkTransactionSpdy3Test, SOCKS5_SSL_GET) { request.load_flags = 0; SpdySessionDependencies session_deps( - ProxyService::CreateFixed("socks5://myproxy:1080")); + ProxyService::CreateFixedFromPacResult("SOCKS5 myproxy:1080")); + CapturingNetLog net_log; + session_deps.net_log = &net_log; scoped_ptr<HttpTransaction> trans( new HttpNetworkTransaction(CreateSession(&session_deps))); @@ -6087,6 +6472,11 @@ TEST_F(HttpNetworkTransactionSpdy3Test, SOCKS5_SSL_GET) { const HttpResponseInfo* response = trans->GetResponseInfo(); ASSERT_TRUE(response != NULL); + LoadTimingInfo load_timing_info; + EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); + TestLoadTimingNotReusedWithPac(load_timing_info, + CONNECT_TIMING_HAS_SSL_TIMES); + std::string response_text; rv = ReadTransaction(trans.get(), &response_text); EXPECT_EQ(OK, rv); @@ -7730,6 +8120,8 @@ TEST_F(HttpNetworkTransactionSpdy3Test, SpdySessionDependencies session_deps(new ProxyService( new ProxyConfigServiceFixed(proxy_config), capturing_proxy_resolver, NULL)); + CapturingNetLog net_log; + session_deps.net_log = &net_log; HttpRequestInfo request; request.method = "GET"; @@ -7825,6 +8217,11 @@ TEST_F(HttpNetworkTransactionSpdy3Test, EXPECT_EQ("https://www.google.com/", capturing_proxy_resolver->resolved()[1].spec()); + LoadTimingInfo load_timing_info; + EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); + TestLoadTimingNotReusedWithPac(load_timing_info, + CONNECT_TIMING_HAS_SSL_TIMES); + HttpStreamFactory::SetNextProtos(std::vector<std::string>()); HttpStreamFactory::set_use_alternate_protocols(false); } @@ -8771,7 +9168,10 @@ TEST_F(HttpNetworkTransactionSpdy3Test, SpdyAlternateProtocolThroughProxy) { MakeNextProtos( "http/1.1", "http1.1", "spdy/2", "spdy/3", "spdy", NULL)); - SpdySessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); + SpdySessionDependencies session_deps( + ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")); + CapturingNetLog net_log; + session_deps.net_log = &net_log; HttpAuthHandlerMock::Factory* auth_factory = new HttpAuthHandlerMock::Factory(); HttpAuthHandlerMock* auth_handler = new HttpAuthHandlerMock(); @@ -8909,6 +9309,11 @@ TEST_F(HttpNetworkTransactionSpdy3Test, SpdyAlternateProtocolThroughProxy) { EXPECT_EQ("https", request_url.scheme()); EXPECT_EQ("www.google.com", request_url.host()); + LoadTimingInfo load_timing_info; + EXPECT_TRUE(trans_2->GetLoadTimingInfo(&load_timing_info)); + TestLoadTimingNotReusedWithPac(load_timing_info, + CONNECT_TIMING_HAS_SSL_TIMES); + HttpStreamFactory::SetNextProtos(std::vector<std::string>()); HttpStreamFactory::set_use_alternate_protocols(false); } @@ -8954,7 +9359,8 @@ TEST_F(HttpNetworkTransactionSpdy3Test, SimpleCancel) { // Test a basic GET request through a proxy. TEST_F(HttpNetworkTransactionSpdy3Test, ProxyGet) { - SpdySessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); + SpdySessionDependencies session_deps( + ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")); CapturingBoundNetLog log; session_deps.net_log = log.bound().net_log(); scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); @@ -8998,11 +9404,17 @@ TEST_F(HttpNetworkTransactionSpdy3Test, ProxyGet) { EXPECT_EQ(100, response->headers->GetContentLength()); EXPECT_TRUE(response->was_fetched_via_proxy); EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); + + LoadTimingInfo load_timing_info; + EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); + TestLoadTimingNotReusedWithPac(load_timing_info, + CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY); } // Test a basic HTTPS GET request through a proxy. TEST_F(HttpNetworkTransactionSpdy3Test, ProxyTunnelGet) { - SpdySessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); + SpdySessionDependencies session_deps( + ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")); CapturingBoundNetLog log; session_deps.net_log = log.bound().net_log(); scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); @@ -9064,6 +9476,11 @@ TEST_F(HttpNetworkTransactionSpdy3Test, ProxyTunnelGet) { EXPECT_EQ(100, response->headers->GetContentLength()); EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); EXPECT_TRUE(response->was_fetched_via_proxy); + + LoadTimingInfo load_timing_info; + EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); + TestLoadTimingNotReusedWithPac(load_timing_info, + CONNECT_TIMING_HAS_SSL_TIMES); } // Test a basic HTTPS GET request through a proxy, but the server hangs up diff --git a/net/proxy/proxy_info.cc b/net/proxy/proxy_info.cc index 26018cf..dd68820 100644 --- a/net/proxy/proxy_info.cc +++ b/net/proxy/proxy_info.cc @@ -19,6 +19,8 @@ ProxyInfo::~ProxyInfo() { } void ProxyInfo::Use(const ProxyInfo& other) { + proxy_resolve_start_time_ = other.proxy_resolve_start_time_; + proxy_resolve_end_time_ = other.proxy_resolve_end_time_; proxy_list_ = other.proxy_list_; proxy_retry_info_ = other.proxy_retry_info_; config_id_ = other.config_id_; @@ -65,6 +67,8 @@ void ProxyInfo::RemoveProxiesWithoutScheme(int scheme_bit_field) { } void ProxyInfo::Reset() { + proxy_resolve_start_time_ = base::TimeTicks(); + proxy_resolve_end_time_ = base::TimeTicks(); proxy_list_.Clear(); proxy_retry_info_.clear(); config_id_ = ProxyConfig::kInvalidConfigID; diff --git a/net/proxy/proxy_info.h b/net/proxy/proxy_info.h index d0fa523..cea21e2 100644 --- a/net/proxy/proxy_info.h +++ b/net/proxy/proxy_info.h @@ -7,6 +7,7 @@ #include <string> +#include "base/time.h" #include "net/base/net_export.h" #include "net/base/net_log.h" #include "net/proxy/proxy_config.h" @@ -119,6 +120,14 @@ class NET_EXPORT ProxyInfo { ProxyConfig::ID config_id() const { return config_id_; } + base::TimeTicks proxy_resolve_start_time() const { + return proxy_resolve_start_time_; + } + + base::TimeTicks proxy_resolve_end_time() const { + return proxy_resolve_end_time_; + } + private: friend class ProxyService; @@ -147,6 +156,11 @@ class NET_EXPORT ProxyInfo { // Whether we used a PAC script for resolving the proxy. bool did_use_pac_script_; + + // How long it took to resolve the proxy. Times are both null if proxy was + // determined synchronously without running a PAC. + base::TimeTicks proxy_resolve_start_time_; + base::TimeTicks proxy_resolve_end_time_; }; } // namespace net diff --git a/net/proxy/proxy_service.cc b/net/proxy/proxy_service.cc index 17e46ed..55088f3 100644 --- a/net/proxy/proxy_service.cc +++ b/net/proxy/proxy_service.cc @@ -724,10 +724,10 @@ class ProxyService::PacRequest : public base::RefCounted<ProxyService::PacRequest> { public: PacRequest(ProxyService* service, - const GURL& url, - ProxyInfo* results, - const net::CompletionCallback& user_callback, - const BoundNetLog& net_log) + const GURL& url, + ProxyInfo* results, + const net::CompletionCallback& user_callback, + const BoundNetLog& net_log) : service_(service), user_callback_(user_callback), results_(results), @@ -748,6 +748,7 @@ class ProxyService::PacRequest config_id_ = service_->config_.id(); config_source_ = service_->config_.source(); + proxy_resolve_start_time_ = TimeTicks::Now(); return resolver()->GetProxyForURL( url_, results_, @@ -808,6 +809,8 @@ class ProxyService::PacRequest results_->config_id_ = config_id_; results_->config_source_ = config_source_; results_->did_use_pac_script_ = true; + results_->proxy_resolve_start_time_ = proxy_resolve_start_time_; + results_->proxy_resolve_end_time_ = TimeTicks::Now(); // Reset the state associated with in-progress-resolve. resolve_job_ = NULL; @@ -856,6 +859,9 @@ class ProxyService::PacRequest ProxyConfig::ID config_id_; // The config id when the resolve was started. ProxyConfigSource config_source_; // The source of proxy settings. BoundNetLog net_log_; + // Time when the PAC is started. Cached here since resetting ProxyInfo also + // clears the proxy times. + TimeTicks proxy_resolve_start_time_; }; // ProxyService --------------------------------------------------------------- diff --git a/net/proxy/proxy_service_unittest.cc b/net/proxy/proxy_service_unittest.cc index 341550e..c5a8d12 100644 --- a/net/proxy/proxy_service_unittest.cc +++ b/net/proxy/proxy_service_unittest.cc @@ -169,6 +169,8 @@ TEST_F(ProxyServiceTest, Direct) { EXPECT_TRUE(resolver->pending_requests().empty()); EXPECT_TRUE(info.is_direct()); + EXPECT_TRUE(info.proxy_resolve_start_time().is_null()); + EXPECT_TRUE(info.proxy_resolve_end_time().is_null()); // Check the NetLog was filled correctly. CapturingNetLog::CapturedEntryList entries; @@ -218,6 +220,10 @@ TEST_F(ProxyServiceTest, PAC) { EXPECT_EQ("foopy:80", info.proxy_server().ToURI()); EXPECT_TRUE(info.did_use_pac_script()); + EXPECT_FALSE(info.proxy_resolve_start_time().is_null()); + EXPECT_FALSE(info.proxy_resolve_end_time().is_null()); + EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time()); + // Check the NetLog was filled correctly. CapturingNetLog::CapturedEntryList entries; log.GetEntries(&entries); @@ -295,6 +301,10 @@ TEST_F(ProxyServiceTest, PAC_FailoverWithoutDirect) { EXPECT_EQ("foopy:8080", info.proxy_server().ToURI()); EXPECT_TRUE(info.did_use_pac_script()); + EXPECT_FALSE(info.proxy_resolve_start_time().is_null()); + EXPECT_FALSE(info.proxy_resolve_end_time().is_null()); + EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time()); + // Now, imagine that connecting to foopy:8080 fails: there is nothing // left to fallback to, since our proxy list was NOT terminated by // DIRECT. @@ -340,6 +350,10 @@ TEST_F(ProxyServiceTest, PAC_RuntimeError) { EXPECT_TRUE(info.is_direct()); EXPECT_TRUE(info.did_use_pac_script()); EXPECT_EQ(1, info.config_id()); + + EXPECT_FALSE(info.proxy_resolve_start_time().is_null()); + EXPECT_FALSE(info.proxy_resolve_end_time().is_null()); + EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time()); } // The proxy list could potentially contain the DIRECT fallback choice @@ -448,6 +462,10 @@ TEST_F(ProxyServiceTest, PAC_ConfigSourcePropagates) { EXPECT_EQ(OK, callback.WaitForResult()); EXPECT_EQ(PROXY_CONFIG_SOURCE_TEST, info.config_source()); EXPECT_TRUE(info.did_use_pac_script()); + + EXPECT_FALSE(info.proxy_resolve_start_time().is_null()); + EXPECT_FALSE(info.proxy_resolve_end_time().is_null()); + EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time()); } TEST_F(ProxyServiceTest, ProxyResolverFails) { @@ -485,6 +503,11 @@ TEST_F(ProxyServiceTest, ProxyResolverFails) { EXPECT_EQ(OK, callback1.WaitForResult()); EXPECT_TRUE(info.is_direct()); + // Failed PAC executions still have proxy resolution times. + EXPECT_FALSE(info.proxy_resolve_start_time().is_null()); + EXPECT_FALSE(info.proxy_resolve_end_time().is_null()); + EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time()); + // The second resolve request will try to run through the proxy resolver, // regardless of whether the first request failed in it. TestCompletionCallback callback2; @@ -692,12 +715,22 @@ TEST_F(ProxyServiceTest, ProxyFallback) { EXPECT_FALSE(info.is_direct()); EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI()); + EXPECT_FALSE(info.proxy_resolve_start_time().is_null()); + EXPECT_FALSE(info.proxy_resolve_end_time().is_null()); + EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time()); + base::TimeTicks proxy_resolve_start_time = info.proxy_resolve_start_time(); + base::TimeTicks proxy_resolve_end_time = info.proxy_resolve_end_time(); + // Fake an error on the proxy. TestCompletionCallback callback2; rv = service.ReconsiderProxyAfterError(url, &info, callback2.callback(), NULL, BoundNetLog()); EXPECT_EQ(OK, rv); + // Proxy times should not have been modified by fallback. + EXPECT_EQ(proxy_resolve_start_time, info.proxy_resolve_start_time()); + EXPECT_EQ(proxy_resolve_end_time, info.proxy_resolve_end_time()); + // The second proxy should be specified. EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI()); // Report back that the second proxy worked. This will globally mark the @@ -722,6 +755,14 @@ TEST_F(ProxyServiceTest, ProxyFallback) { EXPECT_FALSE(info.is_direct()); EXPECT_EQ("foopy3:7070", info.proxy_server().ToURI()); + // Proxy times should have been updated, so get them again. + EXPECT_LE(proxy_resolve_end_time, info.proxy_resolve_start_time()); + EXPECT_FALSE(info.proxy_resolve_start_time().is_null()); + EXPECT_FALSE(info.proxy_resolve_end_time().is_null()); + EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time()); + proxy_resolve_start_time = info.proxy_resolve_start_time(); + proxy_resolve_end_time = info.proxy_resolve_end_time(); + // We fake another error. It should now try the third one. TestCompletionCallback callback4; rv = service.ReconsiderProxyAfterError(url, &info, callback4.callback(), NULL, @@ -747,6 +788,10 @@ TEST_F(ProxyServiceTest, ProxyFallback) { EXPECT_FALSE(info.is_direct()); EXPECT_TRUE(info.is_empty()); + // Proxy times should not have been modified by fallback. + EXPECT_EQ(proxy_resolve_start_time, info.proxy_resolve_start_time()); + EXPECT_EQ(proxy_resolve_end_time, info.proxy_resolve_end_time()); + // Look up proxies again TestCompletionCallback callback7; rv = service.ResolveProxy(url, &info, callback7.callback(), NULL, @@ -767,6 +812,9 @@ TEST_F(ProxyServiceTest, ProxyFallback) { EXPECT_FALSE(info.is_direct()); EXPECT_EQ("foopy3:7070", info.proxy_server().ToURI()); + EXPECT_LE(proxy_resolve_end_time, info.proxy_resolve_start_time()); + EXPECT_FALSE(info.proxy_resolve_start_time().is_null()); + EXPECT_FALSE(info.proxy_resolve_end_time().is_null()); // TODO(nsylvain): Test that the proxy can be retried after the delay. } @@ -824,6 +872,10 @@ TEST_F(ProxyServiceTest, ProxyFallbackToDirect) { // Finally, we get back DIRECT. EXPECT_TRUE(info.is_direct()); + EXPECT_FALSE(info.proxy_resolve_start_time().is_null()); + EXPECT_FALSE(info.proxy_resolve_end_time().is_null()); + EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time()); + // Now we tell the proxy service that even DIRECT failed. TestCompletionCallback callback4; rv = service.ReconsiderProxyAfterError(url, &info, callback4.callback(), NULL, @@ -924,6 +976,10 @@ TEST_F(ProxyServiceTest, ProxyFallback_NewSettings) { EXPECT_EQ(OK, callback4.WaitForResult()); EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI()); + + EXPECT_FALSE(info.proxy_resolve_start_time().is_null()); + EXPECT_FALSE(info.proxy_resolve_end_time().is_null()); + EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time()); } TEST_F(ProxyServiceTest, ProxyFallback_BadConfig) { @@ -1010,6 +1066,10 @@ TEST_F(ProxyServiceTest, ProxyFallback_BadConfig) { EXPECT_EQ(OK, callback4.WaitForResult()); EXPECT_FALSE(info3.is_direct()); EXPECT_EQ("foopy1:8080", info3.proxy_server().ToURI()); + + EXPECT_FALSE(info.proxy_resolve_start_time().is_null()); + EXPECT_FALSE(info.proxy_resolve_end_time().is_null()); + EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time()); } TEST_F(ProxyServiceTest, ProxyFallback_BadConfigMandatory) { @@ -1442,12 +1502,21 @@ TEST_F(ProxyServiceTest, InitialPACScriptDownload) { // Complete and verify that requests ran as expected. EXPECT_EQ(OK, callback1.WaitForResult()); EXPECT_EQ("request1:80", info1.proxy_server().ToURI()); + EXPECT_FALSE(info1.proxy_resolve_start_time().is_null()); + EXPECT_FALSE(info1.proxy_resolve_end_time().is_null()); + EXPECT_LE(info1.proxy_resolve_start_time(), info1.proxy_resolve_end_time()); EXPECT_EQ(OK, callback2.WaitForResult()); EXPECT_EQ("request2:80", info2.proxy_server().ToURI()); + EXPECT_FALSE(info2.proxy_resolve_start_time().is_null()); + EXPECT_FALSE(info2.proxy_resolve_end_time().is_null()); + EXPECT_LE(info2.proxy_resolve_start_time(), info2.proxy_resolve_end_time()); EXPECT_EQ(OK, callback3.WaitForResult()); EXPECT_EQ("request3:80", info3.proxy_server().ToURI()); + EXPECT_FALSE(info3.proxy_resolve_start_time().is_null()); + EXPECT_FALSE(info3.proxy_resolve_end_time().is_null()); + EXPECT_LE(info3.proxy_resolve_start_time(), info3.proxy_resolve_end_time()); } // Test changing the ProxyScriptFetcher while PAC download is in progress. @@ -1664,9 +1733,15 @@ TEST_F(ProxyServiceTest, FallbackFromAutodetectToCustomPac) { // Verify that requests ran as expected. EXPECT_EQ(OK, callback1.WaitForResult()); EXPECT_EQ("request1:80", info1.proxy_server().ToURI()); + EXPECT_FALSE(info1.proxy_resolve_start_time().is_null()); + EXPECT_FALSE(info1.proxy_resolve_end_time().is_null()); + EXPECT_LE(info1.proxy_resolve_start_time(), info1.proxy_resolve_end_time()); EXPECT_EQ(OK, callback2.WaitForResult()); EXPECT_EQ("request2:80", info2.proxy_server().ToURI()); + EXPECT_FALSE(info2.proxy_resolve_start_time().is_null()); + EXPECT_FALSE(info2.proxy_resolve_end_time().is_null()); + EXPECT_LE(info2.proxy_resolve_start_time(), info2.proxy_resolve_end_time()); } // This is the same test as FallbackFromAutodetectToCustomPac, except |