summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authormmenke@chromium.org <mmenke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-24 05:28:20 +0000
committermmenke@chromium.org <mmenke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-24 05:28:20 +0000
commit029c83b673fd8dbe900e9b06c92c79e0dcf329d1 (patch)
treeb98ba82c877aa17a35cddbeb3b15e965e6e1e26b /net
parent44703cc73a24cc39b3e5e832f447d8261701fa4c (diff)
downloadchromium_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.h22
-rw-r--r--net/http/http_network_transaction.cc3
-rw-r--r--net/http/http_network_transaction_spdy2_unittest.cc483
-rw-r--r--net/http/http_network_transaction_spdy3_unittest.cc483
-rw-r--r--net/proxy/proxy_info.cc4
-rw-r--r--net/proxy/proxy_info.h14
-rw-r--r--net/proxy/proxy_service.cc14
-rw-r--r--net/proxy/proxy_service_unittest.cc75
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