Chromium Code Reviews| Index: net/http/http_network_transaction_unittest.cc |
| =================================================================== |
| --- net/http/http_network_transaction_unittest.cc (revision 117986) |
| +++ net/http/http_network_transaction_unittest.cc (working copy) |
| @@ -421,6 +421,16 @@ |
| return true; |
| } |
| +bool CheckNTLMProxyAuth(const AuthChallengeInfo* auth_challenge) { |
| + if (!auth_challenge) |
| + return false; |
| + EXPECT_TRUE(auth_challenge->is_proxy); |
| + EXPECT_EQ("proxy:70", auth_challenge->challenger.ToString()); |
| + EXPECT_EQ(std::string(), auth_challenge->realm); |
| + EXPECT_EQ("ntlm", auth_challenge->scheme); |
| + return true; |
| +} |
| + |
| TEST_F(HttpNetworkTransactionTest, Basic) { |
| SessionDependencies session_deps; |
| scoped_ptr<HttpTransaction> trans( |
| @@ -1718,6 +1728,9 @@ |
| "Host: www.google.com\r\n" |
| "Proxy-Connection: keep-alive\r\n\r\n"), |
| + }; |
| + |
| + MockWrite data_writes2[] = { |
| // After calling trans->RestartWithAuth(), this is the request we should |
| // be issuing -- the final header line contains the credentials. |
| MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" |
| @@ -1737,7 +1750,9 @@ |
| MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), |
| MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), |
| MockRead("Proxy-Connection: close\r\n\r\n"), |
| + }; |
| + MockRead data_reads2[] = { |
| MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), |
| MockRead("HTTP/1.1 200 OK\r\n"), |
| @@ -1748,7 +1763,10 @@ |
| StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), |
| data_writes1, arraysize(data_writes1)); |
| + StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), |
| + data_writes2, arraysize(data_writes2)); |
| session_deps.socket_factory.AddSocketDataProvider(&data1); |
| + session_deps.socket_factory.AddSocketDataProvider(&data2); |
| SSLSocketDataProvider ssl(true, OK); |
| session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); |
| @@ -1963,6 +1981,372 @@ |
| session->CloseAllConnections(); |
| } |
| +// Test the request-challenge-retry sequence for basic auth, over a connection |
| +// that requires a restart when setting up an SSL tunnel. |
| +TEST_F(HttpNetworkTransactionTest, BasicAuthHttpsProxyNoKeepAlive) { |
| + HttpRequestInfo request; |
| + request.method = "GET"; |
| + request.url = GURL("https://www.google.com/"); |
| + // when the no authentication data flag is set. |
| + request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; |
| + |
| + // Configure against https proxy server "myproxy:70". |
| + SessionDependencies session_deps( |
| + ProxyService::CreateFixed("https://myproxy:70")); |
| + CapturingBoundNetLog log(CapturingNetLog::kUnbounded); |
| + 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 data_writes2[] = { |
| + // After calling trans->RestartWithAuth(), this is the request we should |
| + // be issuing -- the final header line contains the credentials. |
| + MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" |
| + "Host: www.google.com\r\n" |
| + "Proxy-Connection: keep-alive\r\n" |
| + "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), |
| + |
| + MockWrite("GET / 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[] = { |
| + // No credentials. |
| + MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), |
| + MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), |
| + MockRead("Proxy-Connection: close\r\n\r\n"), |
| + }; |
| + |
| + MockRead data_reads2[] = { |
| + MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), |
| + |
| + MockRead("HTTP/1.1 200 OK\r\n"), |
| + MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), |
| + MockRead("Content-Length: 5\r\n\r\n"), |
| + MockRead(false, "hello"), |
| + }; |
| + |
| + StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), |
| + data_writes1, arraysize(data_writes1)); |
| + StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), |
| + data_writes2, arraysize(data_writes2)); |
| + session_deps.socket_factory.AddSocketDataProvider(&data1); |
| + session_deps.socket_factory.AddSocketDataProvider(&data2); |
| + SSLSocketDataProvider proxy(true, OK); |
| + session_deps.socket_factory.AddSSLSocketDataProvider(&proxy); |
| + SSLSocketDataProvider proxy2(true, OK); |
| + session_deps.socket_factory.AddSSLSocketDataProvider(&proxy2); |
| + SSLSocketDataProvider server(true, OK); |
| + session_deps.socket_factory.AddSSLSocketDataProvider(&server); |
| + |
| + TestCompletionCallback callback1; |
| + |
| + scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); |
| + |
| + int rv = trans->Start(&request, callback1.callback(), log.bound()); |
| + EXPECT_EQ(ERR_IO_PENDING, rv); |
| + |
| + rv = callback1.WaitForResult(); |
| + EXPECT_EQ(OK, rv); |
| + net::CapturingNetLog::EntryList entries; |
| + log.GetEntries(&entries); |
| + size_t pos = ExpectLogContainsSomewhere( |
| + entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, |
| + NetLog::PHASE_NONE); |
| + ExpectLogContainsSomewhere( |
| + entries, pos, |
| + NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, |
| + NetLog::PHASE_NONE); |
| + |
| + const HttpResponseInfo* response = trans->GetResponseInfo(); |
| + ASSERT_TRUE(response != NULL); |
| + ASSERT_FALSE(response->headers == NULL); |
| + EXPECT_EQ(407, response->headers->response_code()); |
| + EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); |
| + EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); |
| + |
| + TestCompletionCallback callback2; |
| + |
| + rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBar), |
| + callback2.callback()); |
| + EXPECT_EQ(ERR_IO_PENDING, rv); |
| + |
| + rv = callback2.WaitForResult(); |
| + EXPECT_EQ(OK, rv); |
| + |
| + response = trans->GetResponseInfo(); |
| + ASSERT_TRUE(response != NULL); |
| + |
| + EXPECT_TRUE(response->headers->IsKeepAlive()); |
| + EXPECT_EQ(200, response->headers->response_code()); |
| + EXPECT_EQ(5, response->headers->GetContentLength()); |
| + EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); |
| + |
| + // The password prompt info should not be set. |
| + EXPECT_TRUE(response->auth_challenge.get() == NULL); |
| + |
| + trans.reset(); |
| + session->CloseAllConnections(); |
| +} |
| + |
| +// Test the request-challenge-retry sequence for basic auth, over a keep-alive |
| +// proxy connection, when setting up an SSL tunnel. |
| +TEST_F(HttpNetworkTransactionTest, BasicAuthHttpsProxyKeepAlive) { |
| + HttpRequestInfo request; |
| + request.method = "GET"; |
| + request.url = GURL("https://www.google.com/"); |
| + // Ensure that proxy authentication is attempted even |
| + // when the no authentication data flag is set. |
| + request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; |
| + |
| + // Configure against https proxy server "myproxy:70". |
| + SessionDependencies session_deps( |
| + ProxyService::CreateFixed("https://myproxy:70")); |
| + CapturingBoundNetLog log(CapturingNetLog::kUnbounded); |
| + session_deps.net_log = log.bound().net_log(); |
| + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); |
| + |
| + scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); |
| + |
| + // 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"), |
| + |
| + // After calling trans->RestartWithAuth(), this is the request we should |
| + // be issuing -- the final header line contains the credentials. |
| + MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" |
| + "Host: www.google.com\r\n" |
| + "Proxy-Connection: keep-alive\r\n" |
| + "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"), |
| + }; |
| + |
| + // The proxy responds to the connect with a 407, using a persistent |
| + // connection. |
| + MockRead data_reads1[] = { |
| + // No credentials. |
| + MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), |
| + MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), |
| + MockRead("Content-Length: 10\r\n\r\n"), |
| + MockRead("0123456789"), |
| + |
| + // Wrong credentials (wrong password). |
| + MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), |
| + MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), |
| + MockRead("Content-Length: 10\r\n\r\n"), |
| + // No response body because the test stops reading here. |
| + MockRead(false, ERR_UNEXPECTED), // Should not be reached. |
| + }; |
| + |
| + StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), |
| + data_writes1, arraysize(data_writes1)); |
| + session_deps.socket_factory.AddSocketDataProvider(&data1); |
| + SSLSocketDataProvider ssl(true, OK); |
| + session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); |
| + |
| + TestCompletionCallback callback1; |
| + |
| + int rv = trans->Start(&request, callback1.callback(), log.bound()); |
| + EXPECT_EQ(ERR_IO_PENDING, rv); |
| + |
| + rv = callback1.WaitForResult(); |
| + EXPECT_EQ(OK, rv); |
| + net::CapturingNetLog::EntryList entries; |
| + log.GetEntries(&entries); |
| + size_t pos = ExpectLogContainsSomewhere( |
| + entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, |
| + NetLog::PHASE_NONE); |
| + ExpectLogContainsSomewhere( |
| + entries, pos, |
| + NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, |
| + NetLog::PHASE_NONE); |
| + |
| + const HttpResponseInfo* response = trans->GetResponseInfo(); |
| + ASSERT_TRUE(response != NULL); |
| + ASSERT_FALSE(response->headers == NULL); |
| + EXPECT_TRUE(response->headers->IsKeepAlive()); |
| + EXPECT_EQ(407, response->headers->response_code()); |
| + EXPECT_EQ(10, response->headers->GetContentLength()); |
| + EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); |
| + EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); |
| + |
| + TestCompletionCallback callback2; |
| + |
| + // Wrong password (should be "bar"). |
| + rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBaz), |
| + callback2.callback()); |
| + EXPECT_EQ(ERR_IO_PENDING, rv); |
| + |
| + rv = callback2.WaitForResult(); |
| + EXPECT_EQ(OK, rv); |
| + |
| + response = trans->GetResponseInfo(); |
| + ASSERT_TRUE(response != NULL); |
| + ASSERT_FALSE(response->headers == NULL); |
| + EXPECT_TRUE(response->headers->IsKeepAlive()); |
| + EXPECT_EQ(407, response->headers->response_code()); |
| + EXPECT_EQ(10, response->headers->GetContentLength()); |
| + EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); |
| + EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); |
| + |
| + // Flush the idle socket before the NetLog and HttpNetworkTransaction go |
| + // out of scope. |
| + session->CloseAllConnections(); |
| +} |
| + |
| +// Test the request-challenge-retry sequence for basic auth, through |
| +// a SPDY proxy over a single SPDY session. |
| +TEST_F(HttpNetworkTransactionTest, BasicAuthSpdyProxy) { |
| + HttpRequestInfo request; |
| + request.method = "GET"; |
| + request.url = GURL("https://www.google.com/"); |
| + // when the no authentication data flag is set. |
| + request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; |
| + |
| + // Configure against https proxy server "myproxy:70". |
| + SessionDependencies session_deps( |
| + ProxyService::CreateFixed("https://myproxy:70")); |
| + CapturingBoundNetLog log(CapturingNetLog::kUnbounded); |
| + session_deps.net_log = log.bound().net_log(); |
| + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); |
| + |
| + // Since we have proxy, should try to establish tunnel. |
| + scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyConnect(NULL, 0, 1)); |
| + scoped_ptr<spdy::SpdyFrame> rst(ConstructSpdyRstStream(1, spdy::CANCEL)); |
| + |
| + // After calling trans->RestartWithAuth(), this is the request we should |
| + // be issuing -- the final header line contains the credentials. |
| + const char* const kAuthCredentials[] = { |
| + "proxy-authorization", "Basic Zm9vOmJhcg==", |
| + }; |
| + scoped_ptr<spdy::SpdyFrame> connect2( |
| + ConstructSpdyConnect(kAuthCredentials, arraysize(kAuthCredentials)/2, 3)); |
| + // fetch https://www.google.com/ via HTTP |
| + const char get[] = "GET / HTTP/1.1\r\n" |
| + "Host: www.google.com\r\n" |
| + "Connection: keep-alive\r\n\r\n"; |
| + scoped_ptr<spdy::SpdyFrame> wrapped_get( |
| + ConstructSpdyBodyFrame(3, get, strlen(get), false)); |
| + |
| + MockWrite spdy_writes[] = { |
| + CreateMockWrite(*req, 0, true), |
| + CreateMockWrite(*rst, 2, true), |
| + CreateMockWrite(*connect2, 3), |
| + CreateMockWrite(*wrapped_get, 5) |
| + }; |
| + |
| + // The proxy responds to the connect with a 407, using a persistent |
| + // connection. |
| + const char* const kAuthChallenge[] = { |
| + "status", "407 Proxy Authentication Required", |
| + "version", "HTTP/1.1", |
| + "proxy-authenticate", "Basic realm=\"MyRealm1\"", |
| + }; |
| + |
| + scoped_ptr<spdy::SpdyFrame> conn_auth_resp( |
| + ConstructSpdyControlFrame(NULL, |
| + 0, |
| + false, |
| + 1, |
| + LOWEST, |
| + spdy::SYN_REPLY, |
| + spdy::CONTROL_FLAG_NONE, |
| + kAuthChallenge, |
| + arraysize(kAuthChallenge))); |
| + |
| + scoped_ptr<spdy::SpdyFrame> conn_resp(ConstructSpdyGetSynReply(NULL, 0, 3)); |
| + const char resp[] = "HTTP/1.1 200 OK\r\n" |
| + "Content-Length: 5\r\n\r\n"; |
| + |
| + scoped_ptr<spdy::SpdyFrame> wrapped_get_resp( |
| + ConstructSpdyBodyFrame(3, resp, strlen(resp), false)); |
| + scoped_ptr<spdy::SpdyFrame> wrapped_body( |
| + ConstructSpdyBodyFrame(3, "hello", 5, false)); |
| + MockRead spdy_reads[] = { |
| + CreateMockRead(*conn_auth_resp, 1, true), |
| + CreateMockRead(*conn_resp, 4, true), |
| + CreateMockRead(*wrapped_get_resp, 5, true), |
| + CreateMockRead(*wrapped_body, 6, true), |
| + MockRead(false, ERR_IO_PENDING), |
| + }; |
| + |
| + scoped_refptr<OrderedSocketData> spdy_data( |
| + new OrderedSocketData( |
| + spdy_reads, arraysize(spdy_reads), |
| + spdy_writes, arraysize(spdy_writes))); |
| + session_deps.socket_factory.AddSocketDataProvider(spdy_data); |
| + // Negotiate SPDY to the proxy |
| + SSLSocketDataProvider proxy(true, OK); |
| + proxy.next_proto_status = SSLClientSocket::kNextProtoNegotiated; |
| + proxy.next_proto = "spdy/2"; |
| + proxy.was_npn_negotiated = true; |
| + session_deps.socket_factory.AddSSLSocketDataProvider(&proxy); |
| + // Vanilla SSL to the server |
| + SSLSocketDataProvider server(true, OK); |
| + session_deps.socket_factory.AddSSLSocketDataProvider(&server); |
| + |
| + TestCompletionCallback callback1; |
| + |
| + scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); |
| + |
| + int rv = trans->Start(&request, callback1.callback(), log.bound()); |
| + EXPECT_EQ(ERR_IO_PENDING, rv); |
| + |
| + rv = callback1.WaitForResult(); |
| + EXPECT_EQ(OK, rv); |
| + net::CapturingNetLog::EntryList entries; |
| + log.GetEntries(&entries); |
| + size_t pos = ExpectLogContainsSomewhere( |
| + entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, |
| + NetLog::PHASE_NONE); |
| + ExpectLogContainsSomewhere( |
| + entries, pos, |
| + NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, |
| + NetLog::PHASE_NONE); |
| + |
| + const HttpResponseInfo* response = trans->GetResponseInfo(); |
| + ASSERT_TRUE(response != NULL); |
| + ASSERT_FALSE(response->headers == NULL); |
| + EXPECT_EQ(407, response->headers->response_code()); |
| + EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); |
| + EXPECT_TRUE(response->auth_challenge.get() != NULL); |
| + EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); |
| + |
| + TestCompletionCallback callback2; |
| + |
| + rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBar), |
| + callback2.callback()); |
| + EXPECT_EQ(ERR_IO_PENDING, rv); |
| + |
| + rv = callback2.WaitForResult(); |
| + EXPECT_EQ(OK, rv); |
| + |
| + response = trans->GetResponseInfo(); |
| + ASSERT_TRUE(response != NULL); |
| + |
| + EXPECT_TRUE(response->headers->IsKeepAlive()); |
| + EXPECT_EQ(200, response->headers->response_code()); |
| + EXPECT_EQ(5, response->headers->GetContentLength()); |
| + EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); |
| + |
| + // The password prompt info should not be set. |
| + EXPECT_TRUE(response->auth_challenge.get() == NULL); |
| + |
| + trans.reset(); |
| + session->CloseAllConnections(); |
| +} |
| + |
| + |
| // Test when a server (non-proxy) returns a 407 (proxy-authenticate). |
| // The request should fail with ERR_UNEXPECTED_PROXY_AUTH. |
| TEST_F(HttpNetworkTransactionTest, UnexpectedProxyAuth) { |
| @@ -3065,6 +3449,152 @@ |
| EXPECT_EQ(13, response->headers->GetContentLength()); |
| } |
| + |
| +// Enter the correct password and authenticate successfully. |
| +TEST_F(HttpNetworkTransactionTest, NTLMAuthFull) { |
|
cbentzel
2012/01/20 02:09:46
Should the name/description of this test include a
Ryan Hamilton
2012/01/20 04:20:04
Done.
|
| + HttpRequestInfo request; |
| + request.method = "GET"; |
| + request.url = GURL("https://www.google.com/"); |
| + request.load_flags = 0; |
| + |
| + HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockGenerateRandom1, |
| + MockGetHostName); |
| + SessionDependencies session_deps(ProxyService::CreateFixed( |
| + "https://proxy:70")); |
| + |
| + 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"), |
| + }; |
| + |
| + MockRead data_reads1[] = { |
| + MockRead("HTTP/1.1 407 Access Denied\r\n"), |
| + // Negotiate and NTLM are often requested together. However, we only want |
| + // to test NTLM. Since Negotiate is preferred over NTLM, we have to skip |
| + // the header that requests Negotiate for this test. |
| + MockRead("Proxy-Authenticate: NTLM\r\n"), |
| + MockRead("Connection: close\r\n"), |
| + MockRead("Content-Length: 42\r\n"), |
| + MockRead("Content-Type: text/html\r\n\r\n"), |
| + // Missing content -- won't matter, as connection will be reset. |
| + MockRead(false, ERR_UNEXPECTED), |
| + }; |
| + |
| + MockWrite data_writes2[] = { |
| + // After restarting with a null identity, this is the |
| + // request we should be issuing -- the final header line contains a Type |
| + // 1 message. |
| + MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" |
| + "Host: www.google.com\r\n" |
| + "Proxy-Connection: keep-alive\r\n" |
| + "Proxy-Authorization: NTLM " |
| + "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"), |
| + |
| + // After calling trans->RestartWithAuth(), we should send a Type 3 message |
| + // (the credentials for the origin server). The second request continues |
| + // on the same connection. |
| + MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" |
| + "Host: www.google.com\r\n" |
| + "Proxy-Connection: keep-alive\r\n" |
| + "Proxy-Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA" |
| + "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA" |
| + "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwBVKW" |
| + "Yma5xzVAAAAAAAAAAAAAAAAAAAAACH+gWcm+YsP9Tqb9zCR3WAeZZX" |
| + "ahlhx5I=\r\n\r\n"), |
| + |
| + MockWrite("GET / HTTP/1.1\r\n" |
| + "Host: www.google.com\r\n" |
| + "Connection: keep-alive\r\n\r\n"), |
| + }; |
| + |
| + MockRead data_reads2[] = { |
| + // The origin server responds with a Type 2 message. |
| + MockRead("HTTP/1.1 407 Access Denied\r\n"), |
| + MockRead("Proxy-Authenticate: NTLM " |
| + "TlRMTVNTUAACAAAADAAMADgAAAAFgokCjGpMpPGlYKkAAAAAAAAAALo" |
| + "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE" |
| + "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA" |
| + "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy" |
| + "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB" |
| + "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw" |
| + "BtAAAAAAA=\r\n"), |
| + MockRead("Content-Length: 42\r\n"), |
| + MockRead("Content-Type: text/html\r\n\r\n"), |
| + MockRead("You are not authorized to view this page\r\n"), |
| + |
| + // Connect succeeds |
| + MockRead("HTTP/1.0 200 Connected\r\n\r\n"), |
| + |
| + // Lastly we get the desired content. |
| + MockRead("HTTP/1.1 200 OK\r\n"), |
| + MockRead("Content-Type: text/html; charset=utf-8\r\n"), |
| + MockRead("Content-Length: 13\r\n\r\n"), |
| + MockRead("Please Login\r\n"), |
| + MockRead(false, OK), |
| + }; |
| + |
| + StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), |
| + data_writes1, arraysize(data_writes1)); |
| + StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), |
| + data_writes2, arraysize(data_writes2)); |
| + SSLSocketDataProvider ssl(true, OK); |
| + SSLSocketDataProvider ssl2(true, OK); |
| + SSLSocketDataProvider ssl3(true, OK); |
| + SSLSocketDataProvider ssl_server(true, OK); |
| + session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); |
| + session_deps.socket_factory.AddSSLSocketDataProvider(&ssl2); |
| + session_deps.socket_factory.AddSSLSocketDataProvider(&ssl3); |
| + session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_server); |
| + session_deps.socket_factory.AddSocketDataProvider(&data1); |
| + session_deps.socket_factory.AddSocketDataProvider(&data2); |
| + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); |
| + |
| + TestCompletionCallback callback1; |
| + |
| + scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); |
| + |
| + int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); |
| + EXPECT_EQ(ERR_IO_PENDING, rv); |
| + |
| + rv = callback1.WaitForResult(); |
| + EXPECT_EQ(OK, rv); |
| + |
| + EXPECT_FALSE(trans->IsReadyToRestartForAuth()); |
| + |
| + const HttpResponseInfo* response = trans->GetResponseInfo(); |
| + ASSERT_FALSE(response == NULL); |
| + EXPECT_TRUE(CheckNTLMProxyAuth(response->auth_challenge.get())); |
| + |
| + TestCompletionCallback callback2; |
| + |
| + rv = trans->RestartWithAuth(AuthCredentials(kTestingNTLM, kTestingNTLM), |
| + callback2.callback()); |
| + EXPECT_EQ(ERR_IO_PENDING, rv); |
| + |
| + rv = callback2.WaitForResult(); |
| + EXPECT_EQ(OK, rv); |
| + |
| + EXPECT_TRUE(trans->IsReadyToRestartForAuth()); |
| + |
| + response = trans->GetResponseInfo(); |
| + ASSERT_TRUE(response != NULL); |
| + EXPECT_TRUE(response->auth_challenge.get() == NULL); |
| + |
| + TestCompletionCallback callback3; |
| + |
| + rv = trans->RestartWithAuth(AuthCredentials(), callback3.callback()); |
| + EXPECT_EQ(ERR_IO_PENDING, rv); |
| + |
| + rv = callback3.WaitForResult(); |
| + EXPECT_EQ(OK, rv); |
| + |
| + response = trans->GetResponseInfo(); |
| + ASSERT_TRUE(response != NULL); |
| + EXPECT_TRUE(response->auth_challenge.get() == NULL); |
| + EXPECT_EQ(13, response->headers->GetContentLength()); |
| +} |
| + |
| // Enter a wrong password, and then the correct one. |
| TEST_F(HttpNetworkTransactionTest, NTLMAuth2) { |
| HttpRequestInfo request; |
| @@ -7398,7 +7928,7 @@ |
| // - HTTP or HTTPS backend (to include proxy tunneling). |
| // - Non-authenticating and authenticating backend. |
| // |
| -// In all, there are 44 reasonable permuations (for example, if there are |
| +// In all, there are 44 reasonable permutations (for example, if there are |
| // problems generating an auth token for an authenticating proxy, we don't |
| // need to test all permutations of the backend server). |
| // |
| @@ -8256,11 +8786,6 @@ |
| // After the failure, a tunnel is established to www.google.com using |
| // Proxy-Authorization headers. There is then a SPDY request round. |
| // |
| - // NOTE: Despite the "Proxy-Connection: Close", these are done on the |
| - // same MockTCPClientSocket since the underlying HttpNetworkClientSocket |
| - // does a Disconnect and Connect on the same socket, rather than trying |
| - // to obtain a new one. |
| - // |
| // NOTE: Originally, the proxy response to the second CONNECT request |
| // simply returned another 407 so the unit test could skip the SSL connection |
| // establishment and SPDY framing issues. Alas, the |
| @@ -8277,7 +8802,17 @@ |
| "Host: www.google.com\r\n" |
| "Proxy-Connection: keep-alive\r\n" |
| "\r\n"), |
| + }; |
| + MockWrite data_writes_3[] = { |
| + // Non-alternate protocol job that will run in parallel |
| + MockWrite("GET https://www.google.com/ HTTP/1.1\r\n" |
| + "Host: www.google.com\r\n" |
| + "Proxy-Connection: keep-alive\r\n" |
| + "\r\n"), |
| + }; |
| + |
| + MockWrite data_writes_4[] = { |
| // Second connection attempt with Proxy-Authorization. |
| MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" |
| "Host: www.google.com\r\n" |
| @@ -8291,6 +8826,7 @@ |
| const char kRejectConnectResponse[] = ("HTTP/1.1 407 Unauthorized\r\n" |
| "Proxy-Authenticate: Mock\r\n" |
| "Proxy-Connection: close\r\n" |
| + "Content-Length: 0\r\n" |
| "\r\n"); |
| const char kAcceptConnectResponse[] = "HTTP/1.1 200 Connected\r\n\r\n"; |
| MockRead data_reads_2[] = { |
| @@ -8298,19 +8834,35 @@ |
| MockRead(false, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ, 1), |
| MockRead(true, kRejectConnectResponse, |
| arraysize(kRejectConnectResponse) - 1, 1), |
| + }; |
| + // Hang forever so we can ensure the alt job wins |
| + MockRead data_reads_3[] = { |
| + MockRead(false, ERR_IO_PENDING), |
| + }; |
| + |
| + MockRead data_reads_4[] = { |
| // Second connection attempt passes |
| MockRead(true, kAcceptConnectResponse, |
| - arraysize(kAcceptConnectResponse) -1, 4), |
| + arraysize(kAcceptConnectResponse) -1, 1), |
| // SPDY response |
| - CreateMockRead(*resp.get(), 6), |
| - CreateMockRead(*data.get(), 6), |
| - MockRead(true, 0, 0, 6), |
| + CreateMockRead(*resp.get(), 3), |
| + CreateMockRead(*data.get(), 3), |
| + MockRead(true, 0, 0, 4), |
| }; |
| scoped_refptr<OrderedSocketData> data_2( |
| new OrderedSocketData(data_reads_2, arraysize(data_reads_2), |
| data_writes_2, arraysize(data_writes_2))); |
| + scoped_refptr<OrderedSocketData> data_3( |
| + new OrderedSocketData(data_reads_3, arraysize(data_reads_3), |
| + data_writes_3, arraysize(data_writes_3))); |
| + // Hang forever so we can ensure the alt job wins |
| + MockConnect conn_3(false, ERR_IO_PENDING); |
| + data_3->set_connect_data(conn_3); |
| + scoped_refptr<OrderedSocketData> data_4( |
| + new OrderedSocketData(data_reads_4, arraysize(data_reads_4), |
| + data_writes_4, arraysize(data_writes_4))); |
| SSLSocketDataProvider ssl(true, OK); |
| ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated; |
| @@ -8326,7 +8878,10 @@ |
| session_deps.socket_factory.AddSocketDataProvider(&data_1); |
| session_deps.socket_factory.AddSocketDataProvider(data_2.get()); |
| + session_deps.socket_factory.AddSocketDataProvider(data_3.get()); |
| + session_deps.socket_factory.AddSocketDataProvider(data_4.get()); |
| session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); |
| + session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); |
| session_deps.socket_factory.AddSocketDataProvider( |
| &hanging_non_alternate_protocol_socket); |
| scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); |