Index: net/http/http_network_transaction_unittest.cc |
=================================================================== |
--- net/http/http_network_transaction_unittest.cc (revision 29289) |
+++ net/http/http_network_transaction_unittest.cc (working copy) |
@@ -12,8 +12,10 @@ |
#include "net/base/test_completion_callback.h" |
#include "net/base/upload_data.h" |
#include "net/http/http_auth_handler_ntlm.h" |
+#include "net/http/http_basic_stream.h" |
#include "net/http/http_network_session.h" |
#include "net/http/http_network_transaction.h" |
+#include "net/http/http_stream.h" |
#include "net/http/http_transaction_unittest.h" |
#include "net/proxy/proxy_config_service_fixed.h" |
#include "net/socket/client_socket_factory.h" |
@@ -320,6 +322,24 @@ |
EXPECT_EQ("", out.response_data); |
} |
+// A simple request using chunked encoding with some extra data after. |
+// (Like might be seen in a pipelined response.) |
+TEST_F(HttpNetworkTransactionTest, ChunkedEncoding) { |
+ MockRead data_reads[] = { |
+ MockRead("HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"), |
+ MockRead("5\r\nHello\r\n"), |
+ MockRead("1\r\n"), |
+ MockRead(" \r\n"), |
+ MockRead("5\r\nworld\r\n"), |
+ MockRead("0\r\n\r\nHTTP/1.1 200 OK\r\n"), |
+ MockRead(false, OK), |
+ }; |
+ SimpleGetHelperResult out = SimpleGetHelper(data_reads); |
+ EXPECT_EQ(OK, out.rv); |
+ EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); |
+ EXPECT_EQ("Hello world", out.response_data); |
+} |
+ |
// Do a request using the HEAD method. Verify that we don't try to read the |
// message body (since HEAD has none). |
TEST_F(HttpNetworkTransactionTest, Head) { |
@@ -471,7 +491,7 @@ |
// This test is almost the same as Ignores100 above, but the response contains |
// a 102 instead of a 100. Also, instead of HTTP/1.0 the response is |
-// HTTP/1.1. |
+// HTTP/1.1 and the two status headers are read in one read. |
TEST_F(HttpNetworkTransactionTest, Ignores1xx) { |
SessionDependencies session_deps; |
scoped_ptr<HttpTransaction> trans( |
@@ -483,8 +503,8 @@ |
request.load_flags = 0; |
MockRead data_reads[] = { |
- MockRead("HTTP/1.1 102 Unspecified status code\r\n\r\n"), |
- MockRead("HTTP/1.1 200 OK\r\n\r\n"), |
+ MockRead("HTTP/1.1 102 Unspecified status code\r\n\r\n" |
+ "HTTP/1.1 200 OK\r\n\r\n"), |
MockRead("hello world"), |
MockRead(false, OK), |
}; |
@@ -2678,53 +2698,40 @@ |
new HttpNetworkTransaction(CreateSession(&session_deps))); |
// Setup some state (which we expect ResetStateForRestart() will clear). |
- trans->header_buf_->Realloc(10); |
- trans->header_buf_capacity_ = 10; |
- trans->header_buf_len_ = 3; |
- trans->header_buf_body_offset_ = 11; |
- trans->header_buf_http_offset_ = 0; |
- trans->response_body_length_ = 100; |
- trans->response_body_read_ = 1; |
trans->read_buf_ = new IOBuffer(15); |
trans->read_buf_len_ = 15; |
- trans->request_headers_->headers_ = "Authorization: NTLM"; |
- trans->request_headers_bytes_sent_ = 3; |
+ trans->request_headers_ = "Authorization: NTLM"; |
// Setup state in response_ |
- trans->response_.auth_challenge = new AuthChallengeInfo(); |
- trans->response_.ssl_info.cert_status = -15; |
- trans->response_.response_time = base::Time::Now(); |
- trans->response_.was_cached = true; // (Wouldn't ever actually be true...) |
+ trans->http_stream_.reset(new HttpBasicStream(NULL)); |
+ HttpResponseInfo* response = trans->http_stream_->GetResponseInfo(); |
+ response->auth_challenge = new AuthChallengeInfo(); |
+ response->ssl_info.cert_status = -15; |
+ response->response_time = base::Time::Now(); |
+ response->was_cached = true; // (Wouldn't ever actually be true...) |
{ // Setup state for response_.vary_data |
HttpRequestInfo request; |
std::string temp("HTTP/1.1 200 OK\nVary: foo, bar\n\n"); |
std::replace(temp.begin(), temp.end(), '\n', '\0'); |
- scoped_refptr<HttpResponseHeaders> response = new HttpResponseHeaders(temp); |
+ scoped_refptr<HttpResponseHeaders> headers = new HttpResponseHeaders(temp); |
request.extra_headers = "Foo: 1\nbar: 23"; |
- EXPECT_TRUE(trans->response_.vary_data.Init(request, *response)); |
+ EXPECT_TRUE(response->vary_data.Init(request, *headers)); |
} |
// Cause the above state to be reset. |
trans->ResetStateForRestart(); |
// Verify that the state that needed to be reset, has been reset. |
- EXPECT_TRUE(trans->header_buf_->headers() == NULL); |
- EXPECT_EQ(0, trans->header_buf_capacity_); |
- EXPECT_EQ(0, trans->header_buf_len_); |
- EXPECT_EQ(-1, trans->header_buf_body_offset_); |
- EXPECT_EQ(-1, trans->header_buf_http_offset_); |
- EXPECT_EQ(-1, trans->response_body_length_); |
- EXPECT_EQ(0, trans->response_body_read_); |
+ response = trans->http_stream_->GetResponseInfo(); |
EXPECT_TRUE(trans->read_buf_.get() == NULL); |
EXPECT_EQ(0, trans->read_buf_len_); |
- EXPECT_EQ("", trans->request_headers_->headers_); |
- EXPECT_EQ(0U, trans->request_headers_bytes_sent_); |
- EXPECT_TRUE(trans->response_.auth_challenge.get() == NULL); |
- EXPECT_TRUE(trans->response_.headers.get() == NULL); |
- EXPECT_EQ(false, trans->response_.was_cached); |
- EXPECT_EQ(0, trans->response_.ssl_info.cert_status); |
- EXPECT_FALSE(trans->response_.vary_data.is_valid()); |
+ EXPECT_EQ(0U, trans->request_headers_.size()); |
+ EXPECT_TRUE(response->auth_challenge.get() == NULL); |
+ EXPECT_TRUE(response->headers.get() == NULL); |
+ EXPECT_EQ(false, response->was_cached); |
+ EXPECT_EQ(0, response->ssl_info.cert_status); |
+ EXPECT_FALSE(response->vary_data.is_valid()); |
} |
// Test HTTPS connections to a site with a bad certificate |
@@ -3595,4 +3602,189 @@ |
EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv); |
} |
+// Make sure we can handle an error when writing the request. |
+TEST_F(HttpNetworkTransactionTest, RequestWriteError) { |
+ SessionDependencies session_deps; |
+ scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps); |
+ |
+ HttpRequestInfo request; |
+ request.method = "GET"; |
+ request.url = GURL("http://www.foo.com/"); |
+ request.load_flags = 0; |
+ |
+ MockWrite write_failure[] = { |
+ MockWrite(true, ERR_CONNECTION_RESET), |
+ }; |
+ StaticMockSocket data(NULL, write_failure); |
+ session_deps.socket_factory.AddMockSocket(&data); |
+ |
+ TestCompletionCallback callback; |
+ |
+ scoped_ptr<HttpTransaction> trans( |
+ new HttpNetworkTransaction(CreateSession(&session_deps))); |
+ |
+ int rv = trans->Start(&request, &callback, NULL); |
+ EXPECT_EQ(ERR_IO_PENDING, rv); |
+ |
+ rv = callback.WaitForResult(); |
+ EXPECT_EQ(ERR_CONNECTION_RESET, rv); |
+} |
+ |
+// Check that a connection closed after the start of the headers finishes ok. |
+TEST_F(HttpNetworkTransactionTest, ConnectionClosedAfterStartOfHeaders) { |
+ SessionDependencies session_deps; |
+ scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps); |
+ |
+ HttpRequestInfo request; |
+ request.method = "GET"; |
+ request.url = GURL("http://www.foo.com/"); |
+ request.load_flags = 0; |
+ |
+ MockRead data_reads[] = { |
+ MockRead("HTTP/1."), |
+ MockRead(false, OK), |
+ }; |
+ |
+ StaticMockSocket data(data_reads, NULL); |
+ session_deps.socket_factory.AddMockSocket(&data); |
+ |
+ TestCompletionCallback callback; |
+ |
+ scoped_ptr<HttpTransaction> trans( |
+ new HttpNetworkTransaction(CreateSession(&session_deps))); |
+ |
+ int rv = trans->Start(&request, &callback, NULL); |
+ EXPECT_EQ(ERR_IO_PENDING, rv); |
+ |
+ rv = callback.WaitForResult(); |
+ EXPECT_EQ(OK, rv); |
+ |
+ const HttpResponseInfo* response = trans->GetResponseInfo(); |
+ EXPECT_TRUE(response != NULL); |
+ |
+ EXPECT_TRUE(response->headers != NULL); |
+ EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine()); |
+ |
+ std::string response_data; |
+ rv = ReadTransaction(trans.get(), &response_data); |
+ EXPECT_EQ(OK, rv); |
+ EXPECT_EQ("", response_data); |
+} |
+ |
+// Make sure that a dropped connection while draining the body for auth |
+// restart does the right thing. |
+TEST_F(HttpNetworkTransactionTest, DrainResetOK) { |
+ SessionDependencies session_deps; |
+ scoped_ptr<HttpTransaction> trans( |
+ new HttpNetworkTransaction(CreateSession(&session_deps))); |
+ |
+ 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"), |
+ }; |
+ |
+ 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("Unauth"), |
+ MockRead(true, ERR_CONNECTION_RESET), |
+ }; |
+ |
+ StaticMockSocket data1(data_reads1, data_writes1); |
+ session_deps.socket_factory.AddMockSocket(&data1); |
+ |
+ // After calling trans->RestartWithAuth(), this is the request we should |
+ // be issuing -- the final header line contains the credentials. |
+ MockWrite data_writes2[] = { |
+ 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"), |
+ }; |
+ |
+ // Lastly, the server responds with the actual content. |
+ MockRead data_reads2[] = { |
+ MockRead("HTTP/1.1 200 OK\r\n"), |
+ MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), |
+ MockRead("Content-Length: 100\r\n\r\n"), |
+ MockRead(false, OK), |
+ }; |
+ |
+ StaticMockSocket data2(data_reads2, data_writes2); |
+ session_deps.socket_factory.AddMockSocket(&data2); |
+ |
+ TestCompletionCallback callback1; |
+ |
+ int rv = trans->Start(&request, &callback1, NULL); |
+ EXPECT_EQ(ERR_IO_PENDING, rv); |
+ |
+ rv = callback1.WaitForResult(); |
+ EXPECT_EQ(OK, rv); |
+ |
+ const 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); |
+ |
+ EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port); |
+ 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(ERR_IO_PENDING, rv); |
+ |
+ rv = callback2.WaitForResult(); |
+ EXPECT_EQ(OK, rv); |
+ |
+ response = trans->GetResponseInfo(); |
+ EXPECT_FALSE(response == NULL); |
+ EXPECT_TRUE(response->auth_challenge.get() == NULL); |
+ EXPECT_EQ(100, response->headers->GetContentLength()); |
+} |
+ |
+// Test HTTPS connections going through a proxy that sends extra data. |
+TEST_F(HttpNetworkTransactionTest, HTTPSViaProxyWithExtraData) { |
+ SessionDependencies session_deps(CreateFixedProxyService("myproxy:70")); |
+ |
+ HttpRequestInfo request; |
+ request.method = "GET"; |
+ request.url = GURL("https://www.google.com/"); |
+ request.load_flags = 0; |
+ |
+ MockRead proxy_reads[] = { |
+ MockRead("HTTP/1.0 200 Connected\r\n\r\nExtra data"), |
+ MockRead(false, OK) |
+ }; |
+ |
+ StaticMockSocket data(proxy_reads, NULL); |
+ MockSSLSocket ssl(true, OK); |
+ |
+ session_deps.socket_factory.AddMockSocket(&data); |
+ session_deps.socket_factory.AddMockSSLSocket(&ssl); |
+ |
+ TestCompletionCallback callback; |
+ |
+ session_deps.socket_factory.ResetNextMockIndexes(); |
+ |
+ scoped_ptr<HttpTransaction> trans( |
+ new HttpNetworkTransaction(CreateSession(&session_deps))); |
+ |
+ int rv = trans->Start(&request, &callback, NULL); |
+ EXPECT_EQ(ERR_IO_PENDING, rv); |
+ |
+ rv = callback.WaitForResult(); |
+ EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv); |
+} |
+ |
} // namespace net |