| Index: net/http/http_network_transaction_unittest.cc
|
| ===================================================================
|
| --- net/http/http_network_transaction_unittest.cc (revision 9963)
|
| +++ net/http/http_network_transaction_unittest.cc (working copy)
|
| @@ -711,6 +711,352 @@
|
| EXPECT_EQ(100, response->headers->GetContentLength());
|
| }
|
|
|
| +// Test the request-challenge-retry sequence for basic auth, over a keep-alive
|
| +// connection.
|
| +TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAlive) {
|
| + scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
|
| + scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
|
| + CreateSession(proxy_service.get()), &mock_socket_factory));
|
| +
|
| + net::HttpRequestInfo request;
|
| + request.method = "GET";
|
| + request.url = GURL("http://www.google.com/");
|
| + request.load_flags = 0;
|
| +
|
| + MockWrite data_writes1[] = {
|
| + MockWrite("GET / HTTP/1.1\r\n"
|
| + "Host: www.google.com\r\n"
|
| + "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("GET / HTTP/1.1\r\n"
|
| + "Host: www.google.com\r\n"
|
| + "Connection: keep-alive\r\n"
|
| + "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
|
| + };
|
| +
|
| + MockRead data_reads1[] = {
|
| + MockRead("HTTP/1.1 401 Unauthorized\r\n"),
|
| + MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
|
| + MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
|
| + MockRead("Content-Length: 14\r\n\r\n"),
|
| + MockRead("Unauthorized\r\n"),
|
| +
|
| + // Lastly, the server responds with the actual content.
|
| + MockRead("HTTP/1.1 200 OK\r\n"),
|
| + MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
|
| + MockRead("Content-Length: 100\r\n\r\n"),
|
| + MockRead(false, net::OK),
|
| + };
|
| +
|
| + MockSocket data1;
|
| + data1.reads = data_reads1;
|
| + data1.writes = data_writes1;
|
| + mock_sockets[0] = &data1;
|
| + mock_sockets[1] = NULL;
|
| +
|
| + TestCompletionCallback callback1;
|
| +
|
| + int rv = trans->Start(&request, &callback1);
|
| + EXPECT_EQ(net::ERR_IO_PENDING, rv);
|
| +
|
| + rv = callback1.WaitForResult();
|
| + EXPECT_EQ(net::OK, rv);
|
| +
|
| + const net::HttpResponseInfo* response = trans->GetResponseInfo();
|
| + EXPECT_FALSE(response == NULL);
|
| +
|
| + // The password prompt info should have been set in response->auth_challenge.
|
| + EXPECT_FALSE(response->auth_challenge.get() == NULL);
|
| +
|
| + // TODO(eroman): this should really include the effective port (80)
|
| + EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
|
| + EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
|
| + EXPECT_EQ(L"basic", response->auth_challenge->scheme);
|
| +
|
| + TestCompletionCallback callback2;
|
| +
|
| + rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
|
| + EXPECT_EQ(net::ERR_IO_PENDING, rv);
|
| +
|
| + rv = callback2.WaitForResult();
|
| + EXPECT_EQ(net::OK, rv);
|
| +
|
| + response = trans->GetResponseInfo();
|
| + EXPECT_FALSE(response == NULL);
|
| + EXPECT_TRUE(response->auth_challenge.get() == NULL);
|
| + EXPECT_EQ(100, response->headers->GetContentLength());
|
| +}
|
| +
|
| +// Test the request-challenge-retry sequence for basic auth, over a keep-alive
|
| +// connection and with no response body to drain.
|
| +TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveNoBody) {
|
| + scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
|
| + scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
|
| + CreateSession(proxy_service.get()), &mock_socket_factory));
|
| +
|
| + net::HttpRequestInfo request;
|
| + request.method = "GET";
|
| + request.url = GURL("http://www.google.com/");
|
| + request.load_flags = 0;
|
| +
|
| + MockWrite data_writes1[] = {
|
| + MockWrite("GET / HTTP/1.1\r\n"
|
| + "Host: www.google.com\r\n"
|
| + "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("GET / HTTP/1.1\r\n"
|
| + "Host: www.google.com\r\n"
|
| + "Connection: keep-alive\r\n"
|
| + "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
|
| + };
|
| +
|
| + // Respond with 5 kb of response body.
|
| + std::string large_body_string("Unauthorized");
|
| + large_body_string.append(5 * 1024, ' ');
|
| + large_body_string.append("\r\n");
|
| +
|
| + MockRead data_reads1[] = {
|
| + MockRead("HTTP/1.1 401 Unauthorized\r\n"),
|
| + MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
|
| + MockRead("Content-Length: 0\r\n\r\n"),
|
| +
|
| + // Lastly, the server responds with the actual content.
|
| + MockRead("HTTP/1.1 200 OK\r\n"),
|
| + MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
|
| + MockRead("Content-Length: 100\r\n\r\n"),
|
| + MockRead(false, net::OK),
|
| + };
|
| +
|
| + MockSocket data1;
|
| + data1.reads = data_reads1;
|
| + data1.writes = data_writes1;
|
| + mock_sockets[0] = &data1;
|
| + mock_sockets[1] = NULL;
|
| +
|
| + TestCompletionCallback callback1;
|
| +
|
| + int rv = trans->Start(&request, &callback1);
|
| + EXPECT_EQ(net::ERR_IO_PENDING, rv);
|
| +
|
| + rv = callback1.WaitForResult();
|
| + EXPECT_EQ(net::OK, rv);
|
| +
|
| + const net::HttpResponseInfo* response = trans->GetResponseInfo();
|
| + EXPECT_FALSE(response == NULL);
|
| +
|
| + // The password prompt info should have been set in response->auth_challenge.
|
| + EXPECT_FALSE(response->auth_challenge.get() == NULL);
|
| +
|
| + // TODO(eroman): this should really include the effective port (80)
|
| + EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
|
| + EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
|
| + EXPECT_EQ(L"basic", response->auth_challenge->scheme);
|
| +
|
| + TestCompletionCallback callback2;
|
| +
|
| + rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
|
| + EXPECT_EQ(net::ERR_IO_PENDING, rv);
|
| +
|
| + rv = callback2.WaitForResult();
|
| + EXPECT_EQ(net::OK, rv);
|
| +
|
| + response = trans->GetResponseInfo();
|
| + EXPECT_FALSE(response == NULL);
|
| + EXPECT_TRUE(response->auth_challenge.get() == NULL);
|
| + EXPECT_EQ(100, response->headers->GetContentLength());
|
| +}
|
| +
|
| +// Test the request-challenge-retry sequence for basic auth, over a keep-alive
|
| +// connection and with a large response body to drain.
|
| +TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveLargeBody) {
|
| + scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService());
|
| + scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
|
| + CreateSession(proxy_service.get()), &mock_socket_factory));
|
| +
|
| + net::HttpRequestInfo request;
|
| + request.method = "GET";
|
| + request.url = GURL("http://www.google.com/");
|
| + request.load_flags = 0;
|
| +
|
| + MockWrite data_writes1[] = {
|
| + MockWrite("GET / HTTP/1.1\r\n"
|
| + "Host: www.google.com\r\n"
|
| + "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("GET / HTTP/1.1\r\n"
|
| + "Host: www.google.com\r\n"
|
| + "Connection: keep-alive\r\n"
|
| + "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
|
| + };
|
| +
|
| + // Respond with 5 kb of response body.
|
| + std::string large_body_string("Unauthorized");
|
| + large_body_string.append(5 * 1024, ' ');
|
| + large_body_string.append("\r\n");
|
| +
|
| + MockRead data_reads1[] = {
|
| + MockRead("HTTP/1.1 401 Unauthorized\r\n"),
|
| + MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
|
| + MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
|
| + // 5134 = 12 + 5 * 1024 + 2
|
| + MockRead("Content-Length: 5134\r\n\r\n"),
|
| + MockRead(true, large_body_string.data(), large_body_string.size()),
|
| +
|
| + // Lastly, the server responds with the actual content.
|
| + MockRead("HTTP/1.1 200 OK\r\n"),
|
| + MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
|
| + MockRead("Content-Length: 100\r\n\r\n"),
|
| + MockRead(false, net::OK),
|
| + };
|
| +
|
| + MockSocket data1;
|
| + data1.reads = data_reads1;
|
| + data1.writes = data_writes1;
|
| + mock_sockets[0] = &data1;
|
| + mock_sockets[1] = NULL;
|
| +
|
| + TestCompletionCallback callback1;
|
| +
|
| + int rv = trans->Start(&request, &callback1);
|
| + EXPECT_EQ(net::ERR_IO_PENDING, rv);
|
| +
|
| + rv = callback1.WaitForResult();
|
| + EXPECT_EQ(net::OK, rv);
|
| +
|
| + const net::HttpResponseInfo* response = trans->GetResponseInfo();
|
| + EXPECT_FALSE(response == NULL);
|
| +
|
| + // The password prompt info should have been set in response->auth_challenge.
|
| + EXPECT_FALSE(response->auth_challenge.get() == NULL);
|
| +
|
| + // TODO(eroman): this should really include the effective port (80)
|
| + EXPECT_EQ(L"www.google.com", response->auth_challenge->host);
|
| + EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
|
| + EXPECT_EQ(L"basic", response->auth_challenge->scheme);
|
| +
|
| + TestCompletionCallback callback2;
|
| +
|
| + rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
|
| + EXPECT_EQ(net::ERR_IO_PENDING, rv);
|
| +
|
| + rv = callback2.WaitForResult();
|
| + EXPECT_EQ(net::OK, rv);
|
| +
|
| + response = trans->GetResponseInfo();
|
| + EXPECT_FALSE(response == NULL);
|
| + EXPECT_TRUE(response->auth_challenge.get() == NULL);
|
| + EXPECT_EQ(100, response->headers->GetContentLength());
|
| +}
|
| +
|
| +// Test the request-challenge-retry sequence for basic auth, over a keep-alive
|
| +// proxy connection, when setting up an SSL tunnel.
|
| +TEST_F(HttpNetworkTransactionTest, BasicAuthProxyKeepAlive) {
|
| + // Configure against proxy server "myproxy:70".
|
| + scoped_ptr<net::ProxyService> proxy_service(
|
| + CreateFixedProxyService("myproxy:70"));
|
| +
|
| + scoped_refptr<net::HttpNetworkSession> session(
|
| + CreateSession(proxy_service.get()));
|
| +
|
| + scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction(
|
| + session.get(), &mock_socket_factory));
|
| +
|
| + net::HttpRequestInfo request;
|
| + request.method = "GET";
|
| + request.url = GURL("https://www.google.com/");
|
| + request.load_flags = 0;
|
| +
|
| + // 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\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-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, net::ERR_UNEXPECTED), // Should not be reached.
|
| + };
|
| +
|
| + MockSocket data1;
|
| + data1.writes = data_writes1;
|
| + data1.reads = data_reads1;
|
| + mock_sockets[0] = &data1;
|
| + mock_sockets[1] = NULL;
|
| +
|
| + TestCompletionCallback callback1;
|
| +
|
| + int rv = trans->Start(&request, &callback1);
|
| + EXPECT_EQ(net::ERR_IO_PENDING, rv);
|
| +
|
| + rv = callback1.WaitForResult();
|
| + EXPECT_EQ(net::OK, rv);
|
| +
|
| + const net::HttpResponseInfo* response = trans->GetResponseInfo();
|
| + EXPECT_FALSE(response == NULL);
|
| +
|
| + EXPECT_TRUE(response->headers->IsKeepAlive());
|
| + EXPECT_EQ(407, response->headers->response_code());
|
| + EXPECT_EQ(10, response->headers->GetContentLength());
|
| + EXPECT_TRUE(net::HttpVersion(1, 1) == response->headers->GetHttpVersion());
|
| +
|
| + // The password prompt info should have been set in response->auth_challenge.
|
| + EXPECT_FALSE(response->auth_challenge.get() == NULL);
|
| +
|
| + // TODO(eroman): this should really include the effective port (80)
|
| + EXPECT_EQ(L"myproxy:70", response->auth_challenge->host);
|
| + EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
|
| + EXPECT_EQ(L"basic", response->auth_challenge->scheme);
|
| +
|
| + TestCompletionCallback callback2;
|
| +
|
| + // Wrong password (should be "bar").
|
| + rv = trans->RestartWithAuth(L"foo", L"baz", &callback2);
|
| + EXPECT_EQ(net::ERR_IO_PENDING, rv);
|
| +
|
| + rv = callback2.WaitForResult();
|
| + EXPECT_EQ(net::OK, rv);
|
| +
|
| + response = trans->GetResponseInfo();
|
| + EXPECT_FALSE(response == NULL);
|
| +
|
| + EXPECT_TRUE(response->headers->IsKeepAlive());
|
| + EXPECT_EQ(407, response->headers->response_code());
|
| + EXPECT_EQ(10, response->headers->GetContentLength());
|
| + EXPECT_TRUE(net::HttpVersion(1, 1) == response->headers->GetHttpVersion());
|
| +
|
| + // The password prompt info should have been set in response->auth_challenge.
|
| + EXPECT_FALSE(response->auth_challenge.get() == NULL);
|
| +
|
| + // TODO(eroman): this should really include the effective port (80)
|
| + EXPECT_EQ(L"myproxy:70", response->auth_challenge->host);
|
| + EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
|
| + EXPECT_EQ(L"basic", response->auth_challenge->scheme);
|
| +}
|
| +
|
| // Test the flow when both the proxy server AND origin server require
|
| // authentication. Again, this uses basic auth for both since that is
|
| // the simplest to mock.
|
|
|