diff options
-rw-r--r-- | net/http/http_cache_transaction.cc | 9 | ||||
-rw-r--r-- | net/http/http_cache_transaction.h | 2 | ||||
-rw-r--r-- | net/http/http_network_transaction.cc | 7 | ||||
-rw-r--r-- | net/http/http_network_transaction.h | 2 | ||||
-rw-r--r-- | net/http/http_network_transaction_spdy2_unittest.cc | 267 | ||||
-rw-r--r-- | net/http/http_network_transaction_spdy3_unittest.cc | 267 | ||||
-rw-r--r-- | net/http/http_transaction.h | 9 | ||||
-rw-r--r-- | net/http/http_transaction_unittest.cc | 5 | ||||
-rw-r--r-- | net/http/http_transaction_unittest.h | 4 | ||||
-rw-r--r-- | net/url_request/url_request.cc | 7 | ||||
-rw-r--r-- | net/url_request/url_request.h | 15 | ||||
-rw-r--r-- | net/url_request/url_request_http_job.cc | 8 | ||||
-rw-r--r-- | net/url_request/url_request_http_job.h | 2 | ||||
-rw-r--r-- | net/url_request/url_request_job.cc | 5 | ||||
-rw-r--r-- | net/url_request/url_request_job.h | 2 | ||||
-rw-r--r-- | net/url_request/url_request_test_util.cc | 13 | ||||
-rw-r--r-- | net/url_request/url_request_test_util.h | 8 | ||||
-rw-r--r-- | net/url_request/url_request_unittest.cc | 59 |
18 files changed, 680 insertions, 11 deletions
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc index 9559597..0e888a7 100644 --- a/net/http/http_cache_transaction.cc +++ b/net/http/http_cache_transaction.cc @@ -450,6 +450,15 @@ void HttpCache::Transaction::StopCaching() { } } +bool HttpCache::Transaction::GetFullRequestHeaders( + HttpRequestHeaders* headers) const { + if (network_trans_) + return network_trans_->GetFullRequestHeaders(headers); + + // TODO(ttuttle): Read headers from cache. + return false; +} + void HttpCache::Transaction::DoneReading() { if (cache_ && entry_) { DCHECK(reading_); diff --git a/net/http/http_cache_transaction.h b/net/http/http_cache_transaction.h index a5ddfcd..f0422bd 100644 --- a/net/http/http_cache_transaction.h +++ b/net/http/http_cache_transaction.h @@ -120,6 +120,8 @@ class HttpCache::Transaction : public HttpTransaction { int buf_len, const CompletionCallback& callback) OVERRIDE; virtual void StopCaching() OVERRIDE; + virtual bool GetFullRequestHeaders( + HttpRequestHeaders* headers) const OVERRIDE; virtual void DoneReading() OVERRIDE; virtual const HttpResponseInfo* GetResponseInfo() const OVERRIDE; virtual LoadState GetLoadState() const OVERRIDE; diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index b74b671..cdbd07c 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc @@ -355,6 +355,13 @@ int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len, return rv; } +bool HttpNetworkTransaction::GetFullRequestHeaders( + HttpRequestHeaders* headers) const { + // TODO(ttuttle): Make sure we've populated request_headers_. + *headers = request_headers_; + return true; +} + const HttpResponseInfo* HttpNetworkTransaction::GetResponseInfo() const { return ((headers_valid_ && response_.headers) || response_.ssl_info.cert || response_.cert_request_info) ? &response_ : NULL; diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h index a98778d..87209ea 100644 --- a/net/http/http_network_transaction.h +++ b/net/http/http_network_transaction.h @@ -57,6 +57,8 @@ class NET_EXPORT_PRIVATE HttpNetworkTransaction int buf_len, const CompletionCallback& callback) OVERRIDE; virtual void StopCaching() OVERRIDE {} + virtual bool GetFullRequestHeaders( + HttpRequestHeaders* headers) const OVERRIDE; virtual void DoneReading() OVERRIDE {} virtual const HttpResponseInfo* GetResponseInfo() const OVERRIDE; virtual LoadState GetLoadState() const OVERRIDE; diff --git a/net/http/http_network_transaction_spdy2_unittest.cc b/net/http/http_network_transaction_spdy2_unittest.cc index e302f0e..c3baebc 100644 --- a/net/http/http_network_transaction_spdy2_unittest.cc +++ b/net/http/http_network_transaction_spdy2_unittest.cc @@ -333,9 +333,18 @@ class HttpNetworkTransactionSpdy2Test : public PlatformTest { EXPECT_TRUE(entries[pos].GetStringValue("line", &line)); EXPECT_EQ("GET / HTTP/1.1\r\n", line); - std::string headers; - EXPECT_TRUE(GetHeaders(entries[pos].params.get(), &headers)); - EXPECT_EQ("['Host: www.google.com','Connection: keep-alive']", headers); + HttpRequestHeaders request_headers; + EXPECT_TRUE(trans->GetFullRequestHeaders(&request_headers)); + std::string value; + EXPECT_TRUE(request_headers.GetHeader("Host", &value)); + EXPECT_EQ("www.google.com", value); + EXPECT_TRUE(request_headers.GetHeader("Connection", &value)); + EXPECT_EQ("keep-alive", value); + + std::string response_headers; + EXPECT_TRUE(GetHeaders(entries[pos].params.get(), &response_headers)); + EXPECT_EQ("['Host: www.google.com','Connection: keep-alive']", + response_headers); return out; } @@ -11187,4 +11196,256 @@ TEST_F(HttpNetworkTransactionSpdy2Test, ErrorSocketNotConnected) { EXPECT_TRUE(trans2.GetResponseInfo()->was_fetched_via_spdy); } +TEST_F(HttpNetworkTransactionSpdy2Test, HttpSyncConnectError) { + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("http://www.google.com/"); + request.load_flags = 0; + + scoped_ptr<HttpTransaction> trans( + new HttpNetworkTransaction(DEFAULT_PRIORITY, + CreateSession(&session_deps_))); + + MockConnect mock_connect(SYNCHRONOUS, ERR_CONNECTION_REFUSED); + StaticSocketDataProvider data; + data.set_connect_data(mock_connect); + 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(ERR_CONNECTION_REFUSED, rv); + + EXPECT_EQ(NULL, trans->GetResponseInfo()); + + // We don't care whether this succeeds or fails, but it shouldn't crash. + HttpRequestHeaders request_headers; + trans->GetFullRequestHeaders(&request_headers); +} + +TEST_F(HttpNetworkTransactionSpdy2Test, HttpAsyncConnectError) { + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("http://www.google.com/"); + request.load_flags = 0; + + scoped_ptr<HttpTransaction> trans( + new HttpNetworkTransaction(DEFAULT_PRIORITY, + CreateSession(&session_deps_))); + + MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED); + StaticSocketDataProvider data; + data.set_connect_data(mock_connect); + 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(ERR_CONNECTION_REFUSED, rv); + + EXPECT_EQ(NULL, trans->GetResponseInfo()); + + // We don't care whether this succeeds or fails, but it shouldn't crash. + HttpRequestHeaders request_headers; + trans->GetFullRequestHeaders(&request_headers); +} + +TEST_F(HttpNetworkTransactionSpdy2Test, HttpSyncWriteError) { + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("http://www.google.com/"); + request.load_flags = 0; + + scoped_ptr<HttpTransaction> trans( + new HttpNetworkTransaction(DEFAULT_PRIORITY, + CreateSession(&session_deps_))); + + MockWrite data_writes[] = { + MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET), + }; + MockRead data_reads[] = { + MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. + }; + + 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(ERR_CONNECTION_RESET, rv); + + EXPECT_EQ(NULL, trans->GetResponseInfo()); + + HttpRequestHeaders request_headers; + EXPECT_TRUE(trans->GetFullRequestHeaders(&request_headers)); + EXPECT_TRUE(request_headers.HasHeader("Host")); +} + +TEST_F(HttpNetworkTransactionSpdy2Test, HttpAsyncWriteError) { + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("http://www.google.com/"); + request.load_flags = 0; + + scoped_ptr<HttpTransaction> trans( + new HttpNetworkTransaction(DEFAULT_PRIORITY, + CreateSession(&session_deps_))); + + MockWrite data_writes[] = { + MockWrite(ASYNC, ERR_CONNECTION_RESET), + }; + MockRead data_reads[] = { + MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. + }; + + 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(ERR_CONNECTION_RESET, rv); + + EXPECT_EQ(NULL, trans->GetResponseInfo()); + + HttpRequestHeaders request_headers; + EXPECT_TRUE(trans->GetFullRequestHeaders(&request_headers)); + EXPECT_TRUE(request_headers.HasHeader("Host")); +} + +TEST_F(HttpNetworkTransactionSpdy2Test, HttpSyncReadError) { + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("http://www.google.com/"); + request.load_flags = 0; + + scoped_ptr<HttpTransaction> trans( + new HttpNetworkTransaction(DEFAULT_PRIORITY, + CreateSession(&session_deps_))); + + MockWrite data_writes[] = { + MockWrite("GET / HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Connection: keep-alive\r\n\r\n"), + }; + MockRead data_reads[] = { + MockRead(SYNCHRONOUS, ERR_CONNECTION_RESET), + }; + + 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(ERR_CONNECTION_RESET, rv); + + EXPECT_EQ(NULL, trans->GetResponseInfo()); + + HttpRequestHeaders request_headers; + EXPECT_TRUE(trans->GetFullRequestHeaders(&request_headers)); + EXPECT_TRUE(request_headers.HasHeader("Host")); +} + +TEST_F(HttpNetworkTransactionSpdy2Test, HttpAsyncReadError) { + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("http://www.google.com/"); + request.load_flags = 0; + + scoped_ptr<HttpTransaction> trans( + new HttpNetworkTransaction(DEFAULT_PRIORITY, + CreateSession(&session_deps_))); + + MockWrite data_writes[] = { + 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, ERR_CONNECTION_RESET), + }; + + 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(ERR_CONNECTION_RESET, rv); + + EXPECT_EQ(NULL, trans->GetResponseInfo()); + + HttpRequestHeaders request_headers; + EXPECT_TRUE(trans->GetFullRequestHeaders(&request_headers)); + EXPECT_TRUE(request_headers.HasHeader("Host")); +} + +TEST_F(HttpNetworkTransactionSpdy2Test, + GetFullRequestHeadersIncludesExtraHeader) { + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("http://www.google.com/"); + request.load_flags = 0; + request.extra_headers.SetHeader("X-Foo", "bar"); + + scoped_ptr<HttpTransaction> trans( + new HttpNetworkTransaction(DEFAULT_PRIORITY, + CreateSession(&session_deps_))); + + MockWrite data_writes[] = { + MockWrite("GET / HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Connection: keep-alive\r\n" + "X-Foo: bar\r\n\r\n"), + }; + MockRead data_reads[] = { + MockRead("HTTP/1.1 200 OK\r\n" + "Content-Length: 5\r\n\r\n" + "hello"), + MockRead(ASYNC, ERR_UNEXPECTED), + }; + + 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); + + HttpRequestHeaders request_headers; + EXPECT_TRUE(trans->GetFullRequestHeaders(&request_headers)); + std::string foo; + EXPECT_TRUE(request_headers.GetHeader("X-Foo", &foo)); + EXPECT_EQ("bar", foo); +} + } // namespace net diff --git a/net/http/http_network_transaction_spdy3_unittest.cc b/net/http/http_network_transaction_spdy3_unittest.cc index 88e43eb..c406e0b 100644 --- a/net/http/http_network_transaction_spdy3_unittest.cc +++ b/net/http/http_network_transaction_spdy3_unittest.cc @@ -334,9 +334,18 @@ class HttpNetworkTransactionSpdy3Test : public PlatformTest { EXPECT_TRUE(entries[pos].GetStringValue("line", &line)); EXPECT_EQ("GET / HTTP/1.1\r\n", line); - std::string headers; - EXPECT_TRUE(GetHeaders(entries[pos].params.get(), &headers)); - EXPECT_EQ("['Host: www.google.com','Connection: keep-alive']", headers); + HttpRequestHeaders request_headers; + EXPECT_TRUE(trans->GetFullRequestHeaders(&request_headers)); + std::string value; + EXPECT_TRUE(request_headers.GetHeader("Host", &value)); + EXPECT_EQ("www.google.com", value); + EXPECT_TRUE(request_headers.GetHeader("Connection", &value)); + EXPECT_EQ("keep-alive", value); + + std::string response_headers; + EXPECT_TRUE(GetHeaders(entries[pos].params.get(), &response_headers)); + EXPECT_EQ("['Host: www.google.com','Connection: keep-alive']", + response_headers); return out; } @@ -11132,4 +11141,256 @@ TEST_F(HttpNetworkTransactionSpdy3Test, ErrorSocketNotConnected) { EXPECT_TRUE(trans2.GetResponseInfo()->was_fetched_via_spdy); } +TEST_F(HttpNetworkTransactionSpdy3Test, HttpSyncConnectError) { + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("http://www.google.com/"); + request.load_flags = 0; + + scoped_ptr<HttpTransaction> trans( + new HttpNetworkTransaction(DEFAULT_PRIORITY, + CreateSession(&session_deps_))); + + MockConnect mock_connect(SYNCHRONOUS, ERR_CONNECTION_REFUSED); + StaticSocketDataProvider data; + data.set_connect_data(mock_connect); + 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(ERR_CONNECTION_REFUSED, rv); + + EXPECT_EQ(NULL, trans->GetResponseInfo()); + + // We don't care whether this succeeds or fails, but it shouldn't crash. + HttpRequestHeaders request_headers; + trans->GetFullRequestHeaders(&request_headers); +} + +TEST_F(HttpNetworkTransactionSpdy3Test, HttpAsyncConnectError) { + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("http://www.google.com/"); + request.load_flags = 0; + + scoped_ptr<HttpTransaction> trans( + new HttpNetworkTransaction(DEFAULT_PRIORITY, + CreateSession(&session_deps_))); + + MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED); + StaticSocketDataProvider data; + data.set_connect_data(mock_connect); + 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(ERR_CONNECTION_REFUSED, rv); + + EXPECT_EQ(NULL, trans->GetResponseInfo()); + + // We don't care whether this succeeds or fails, but it shouldn't crash. + HttpRequestHeaders request_headers; + trans->GetFullRequestHeaders(&request_headers); +} + +TEST_F(HttpNetworkTransactionSpdy3Test, HttpSyncWriteError) { + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("http://www.google.com/"); + request.load_flags = 0; + + scoped_ptr<HttpTransaction> trans( + new HttpNetworkTransaction(DEFAULT_PRIORITY, + CreateSession(&session_deps_))); + + MockWrite data_writes[] = { + MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET), + }; + MockRead data_reads[] = { + MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. + }; + + 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(ERR_CONNECTION_RESET, rv); + + EXPECT_EQ(NULL, trans->GetResponseInfo()); + + HttpRequestHeaders request_headers; + EXPECT_TRUE(trans->GetFullRequestHeaders(&request_headers)); + EXPECT_TRUE(request_headers.HasHeader("Host")); +} + +TEST_F(HttpNetworkTransactionSpdy3Test, HttpAsyncWriteError) { + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("http://www.google.com/"); + request.load_flags = 0; + + scoped_ptr<HttpTransaction> trans( + new HttpNetworkTransaction(DEFAULT_PRIORITY, + CreateSession(&session_deps_))); + + MockWrite data_writes[] = { + MockWrite(ASYNC, ERR_CONNECTION_RESET), + }; + MockRead data_reads[] = { + MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. + }; + + 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(ERR_CONNECTION_RESET, rv); + + EXPECT_EQ(NULL, trans->GetResponseInfo()); + + HttpRequestHeaders request_headers; + EXPECT_TRUE(trans->GetFullRequestHeaders(&request_headers)); + EXPECT_TRUE(request_headers.HasHeader("Host")); +} + +TEST_F(HttpNetworkTransactionSpdy3Test, HttpSyncReadError) { + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("http://www.google.com/"); + request.load_flags = 0; + + scoped_ptr<HttpTransaction> trans( + new HttpNetworkTransaction(DEFAULT_PRIORITY, + CreateSession(&session_deps_))); + + MockWrite data_writes[] = { + MockWrite("GET / HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Connection: keep-alive\r\n\r\n"), + }; + MockRead data_reads[] = { + MockRead(SYNCHRONOUS, ERR_CONNECTION_RESET), + }; + + 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(ERR_CONNECTION_RESET, rv); + + EXPECT_EQ(NULL, trans->GetResponseInfo()); + + HttpRequestHeaders request_headers; + EXPECT_TRUE(trans->GetFullRequestHeaders(&request_headers)); + EXPECT_TRUE(request_headers.HasHeader("Host")); +} + +TEST_F(HttpNetworkTransactionSpdy3Test, HttpAsyncReadError) { + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("http://www.google.com/"); + request.load_flags = 0; + + scoped_ptr<HttpTransaction> trans( + new HttpNetworkTransaction(DEFAULT_PRIORITY, + CreateSession(&session_deps_))); + + MockWrite data_writes[] = { + 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, ERR_CONNECTION_RESET), + }; + + 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(ERR_CONNECTION_RESET, rv); + + EXPECT_EQ(NULL, trans->GetResponseInfo()); + + HttpRequestHeaders request_headers; + EXPECT_TRUE(trans->GetFullRequestHeaders(&request_headers)); + EXPECT_TRUE(request_headers.HasHeader("Host")); +} + +TEST_F(HttpNetworkTransactionSpdy3Test, + GetFullRequestHeadersIncludesExtraHeader) { + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("http://www.google.com/"); + request.load_flags = 0; + request.extra_headers.SetHeader("X-Foo", "bar"); + + scoped_ptr<HttpTransaction> trans( + new HttpNetworkTransaction(DEFAULT_PRIORITY, + CreateSession(&session_deps_))); + + MockWrite data_writes[] = { + MockWrite("GET / HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Connection: keep-alive\r\n" + "X-Foo: bar\r\n\r\n"), + }; + MockRead data_reads[] = { + MockRead("HTTP/1.1 200 OK\r\n" + "Content-Length: 5\r\n\r\n" + "hello"), + MockRead(ASYNC, ERR_UNEXPECTED), + }; + + 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); + + HttpRequestHeaders request_headers; + EXPECT_TRUE(trans->GetFullRequestHeaders(&request_headers)); + std::string foo; + EXPECT_TRUE(request_headers.GetHeader("X-Foo", &foo)); + EXPECT_EQ("bar", foo); +} + } // namespace net diff --git a/net/http/http_transaction.h b/net/http/http_transaction.h index c162b01..38d3bd7 100644 --- a/net/http/http_transaction.h +++ b/net/http/http_transaction.h @@ -15,6 +15,7 @@ namespace net { class AuthCredentials; class BoundNetLog; +class HttpRequestHeaders; struct HttpRequestInfo; class HttpResponseInfo; class IOBuffer; @@ -96,6 +97,14 @@ class NET_EXPORT_PRIVATE HttpTransaction { // Stops further caching of this request by the HTTP cache, if there is any. virtual void StopCaching() = 0; + // Gets the full request headers sent to the server. This is guaranteed to + // work only if Start returns success and the underlying transaction supports + // it. (Right now, this is only network transactions, not cache ones.) + // + // Returns true and overwrites headers if it can get the request headers; + // otherwise, returns false and does not modify headers. + virtual bool GetFullRequestHeaders(HttpRequestHeaders* headers) const = 0; + // Called to tell the transaction that we have successfully reached the end // of the stream. This is equivalent to performing an extra Read() at the end // that should return 0 bytes. This method should not be called if the diff --git a/net/http/http_transaction_unittest.cc b/net/http/http_transaction_unittest.cc index f84ddae..d91a0dd 100644 --- a/net/http/http_transaction_unittest.cc +++ b/net/http/http_transaction_unittest.cc @@ -320,6 +320,11 @@ int MockNetworkTransaction::Read(net::IOBuffer* buf, int buf_len, void MockNetworkTransaction::StopCaching() {} +bool MockNetworkTransaction::GetFullRequestHeaders( + net::HttpRequestHeaders* headers) const { + return false; +} + void MockNetworkTransaction::DoneReading() { if (transaction_factory_) transaction_factory_->TransactionDoneReading(); diff --git a/net/http/http_transaction_unittest.h b/net/http/http_transaction_unittest.h index 6e31097..bc8c45f 100644 --- a/net/http/http_transaction_unittest.h +++ b/net/http/http_transaction_unittest.h @@ -25,6 +25,7 @@ #include "net/http/http_response_info.h" namespace net { +class HttpRequestHeaders; class IOBuffer; } @@ -187,6 +188,9 @@ class MockNetworkTransaction virtual void StopCaching() OVERRIDE; + virtual bool GetFullRequestHeaders( + net::HttpRequestHeaders* headers) const OVERRIDE; + virtual void DoneReading() OVERRIDE; virtual const net::HttpResponseInfo* GetResponseInfo() const OVERRIDE; diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc index 0713062..fb20a15 100644 --- a/net/url_request/url_request.cc +++ b/net/url_request/url_request.cc @@ -376,6 +376,13 @@ void URLRequest::SetExtraRequestHeaders( // for request headers are implemented. } +bool URLRequest::GetFullRequestHeaders(HttpRequestHeaders* headers) const { + if (!job_) + return false; + + return job_->GetFullRequestHeaders(headers); +} + LoadStateWithParam URLRequest::GetLoadState() const { if (blocked_on_delegate_) { return LoadStateWithParam(LOAD_STATE_WAITING_FOR_DELEGATE, diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h index 111f8d3..1b461c1 100644 --- a/net/url_request/url_request.h +++ b/net/url_request/url_request.h @@ -421,6 +421,21 @@ class NET_EXPORT URLRequest : NON_EXPORTED_BASE(public base::NonThreadSafe), return extra_request_headers_; } + // Gets the full request headers sent to the server. + // + // Return true and overwrites headers if it can get the request headers; + // otherwise, returns false and does not modify headers. (Always returns + // false for request types that don't have headers, like file requests.) + // + // This is guaranteed to succeed if: + // + // 1. A redirect or auth callback is currently running. Once it ends, the + // headers may become unavailable as a new request with the new address + // or credentials is made. + // + // 2. The OnResponseStarted callback is currently running or has run. + bool GetFullRequestHeaders(HttpRequestHeaders* headers) const; + // Returns the current load state for the request. |param| is an optional // parameter describing details related to the load state. Not all load states // have a parameter. diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc index 71904a5..562beab 100644 --- a/net/url_request/url_request_http_job.cc +++ b/net/url_request/url_request_http_job.cc @@ -1249,6 +1249,14 @@ void URLRequestHttpJob::StopCaching() { transaction_->StopCaching(); } +bool URLRequestHttpJob::GetFullRequestHeaders( + HttpRequestHeaders* headers) const { + if (!transaction_) + return false; + + return transaction_->GetFullRequestHeaders(headers); +} + void URLRequestHttpJob::DoneReading() { if (transaction_.get()) transaction_->DoneReading(); diff --git a/net/url_request/url_request_http_job.h b/net/url_request/url_request_http_job.h index 73d216f..5589538 100644 --- a/net/url_request/url_request_http_job.h +++ b/net/url_request/url_request_http_job.h @@ -116,6 +116,8 @@ class NET_EXPORT_PRIVATE URLRequestHttpJob : public URLRequestJob { virtual bool ReadRawData(IOBuffer* buf, int buf_size, int* bytes_read) OVERRIDE; virtual void StopCaching() OVERRIDE; + virtual bool GetFullRequestHeaders( + HttpRequestHeaders* headers) const OVERRIDE; virtual void DoneReading() OVERRIDE; virtual HostPortPair GetSocketAddress() const OVERRIDE; virtual void NotifyURLRequestDestroyed() OVERRIDE; diff --git a/net/url_request/url_request_job.cc b/net/url_request/url_request_job.cc index edb1515..6a7a311 100644 --- a/net/url_request/url_request_job.cc +++ b/net/url_request/url_request_job.cc @@ -106,6 +106,11 @@ void URLRequestJob::StopCaching() { // Nothing to do here. } +bool URLRequestJob::GetFullRequestHeaders(HttpRequestHeaders* headers) const { + // Most job types don't send request headers. + return false; +} + LoadState URLRequestJob::GetLoadState() const { return LOAD_STATE_IDLE; } diff --git a/net/url_request/url_request_job.h b/net/url_request/url_request_job.h index a9cec85..58b8964 100644 --- a/net/url_request/url_request_job.h +++ b/net/url_request/url_request_job.h @@ -105,6 +105,8 @@ class NET_EXPORT URLRequestJob // URLRequest::StopCaching(). virtual void StopCaching(); + virtual bool GetFullRequestHeaders(HttpRequestHeaders* headers) const; + // Called to fetch the current load state for the job. virtual LoadState GetLoadState() const; diff --git a/net/url_request/url_request_test_util.cc b/net/url_request/url_request_test_util.cc index b1dab4b..b5cbe58 100644 --- a/net/url_request/url_request_test_util.cc +++ b/net/url_request/url_request_test_util.cc @@ -174,15 +174,25 @@ TestDelegate::TestDelegate() have_certificate_errors_(false), certificate_errors_are_fatal_(false), auth_required_(false), + have_full_request_headers_(false), buf_(new IOBuffer(kBufferSize)) { } TestDelegate::~TestDelegate() {} +void TestDelegate::ClearFullRequestHeaders() { + full_request_headers_.Clear(); + have_full_request_headers_ = false; +} + void TestDelegate::OnReceivedRedirect(URLRequest* request, const GURL& new_url, bool* defer_redirect) { EXPECT_TRUE(request->is_redirecting()); + + have_full_request_headers_ = + request->GetFullRequestHeaders(&full_request_headers_); + received_redirect_count_++; if (quit_on_redirect_) { *defer_redirect = true; @@ -221,6 +231,9 @@ void TestDelegate::OnResponseStarted(URLRequest* request) { DCHECK(!request->status().is_io_pending()); EXPECT_FALSE(request->is_redirecting()); + have_full_request_headers_ = + request->GetFullRequestHeaders(&full_request_headers_); + response_started_count_++; if (cancel_in_rs_) { request->Cancel(); diff --git a/net/url_request/url_request_test_util.h b/net/url_request/url_request_test_util.h index d0f06dc..a720f9b 100644 --- a/net/url_request/url_request_test_util.h +++ b/net/url_request/url_request_test_util.h @@ -32,6 +32,7 @@ #include "net/http/http_auth_handler_factory.h" #include "net/http/http_cache.h" #include "net/http/http_network_layer.h" +#include "net/http/http_request_headers.h" #include "net/proxy/proxy_service.h" #include "net/ssl/ssl_config_service_defaults.h" #include "net/url_request/url_request.h" @@ -149,6 +150,11 @@ class TestDelegate : public URLRequest::Delegate { return certificate_errors_are_fatal_; } bool auth_required_called() const { return auth_required_; } + bool have_full_request_headers() const { return have_full_request_headers_; } + const HttpRequestHeaders& full_request_headers() const { + return full_request_headers_; + } + void ClearFullRequestHeaders(); // URLRequest::Delegate: virtual void OnReceivedRedirect(URLRequest* request, const GURL& new_url, @@ -190,6 +196,8 @@ class TestDelegate : public URLRequest::Delegate { bool certificate_errors_are_fatal_; bool auth_required_; std::string data_received_; + bool have_full_request_headers_; + HttpRequestHeaders full_request_headers_; // our read buffer scoped_refptr<IOBuffer> buf_; diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index 8f7864f..0bed092 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc @@ -232,6 +232,17 @@ void CheckSSLInfo(const SSLInfo& ssl_info) { EXPECT_NE(0, cipher_suite); } +void CheckFullRequestHeaders(const HttpRequestHeaders& headers, + const GURL& host_url) { + std::string sent_value; + + EXPECT_TRUE(headers.GetHeader("Host", &sent_value)); + EXPECT_EQ(GetHostAndOptionalPort(host_url), sent_value); + + EXPECT_TRUE(headers.GetHeader("Connection", &sent_value)); + EXPECT_EQ("keep-alive", sent_value); +} + bool FingerprintsEqual(const HashValueVector& a, const HashValueVector& b) { size_t size = a.size(); @@ -597,6 +608,9 @@ TEST_F(URLRequestTest, AboutBlankTest) { EXPECT_EQ(d.bytes_received(), 0); EXPECT_EQ("", r.GetSocketAddress().host()); EXPECT_EQ(0, r.GetSocketAddress().port()); + + HttpRequestHeaders headers; + EXPECT_FALSE(r.GetFullRequestHeaders(&headers)); } } @@ -637,6 +651,9 @@ TEST_F(URLRequestTest, DataURLImageTest) { EXPECT_EQ(d.bytes_received(), 911); EXPECT_EQ("", r.GetSocketAddress().host()); EXPECT_EQ(0, r.GetSocketAddress().port()); + + HttpRequestHeaders headers; + EXPECT_FALSE(r.GetFullRequestHeaders(&headers)); } } @@ -663,6 +680,9 @@ TEST_F(URLRequestTest, FileTest) { EXPECT_EQ(d.bytes_received(), static_cast<int>(file_size)); EXPECT_EQ("", r.GetSocketAddress().host()); EXPECT_EQ(0, r.GetSocketAddress().port()); + + HttpRequestHeaders headers; + EXPECT_FALSE(r.GetFullRequestHeaders(&headers)); } } @@ -679,7 +699,7 @@ TEST_F(URLRequestTest, FileTestCancel) { EXPECT_TRUE(r.is_pending()); r.Cancel(); } - // Async cancelation should be safe even when URLRequest has been already + // Async cancellation should be safe even when URLRequest has been already // destroyed. MessageLoop::current()->RunUntilIdle(); } @@ -2797,6 +2817,13 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateOnAuthRequiredSyncNoAction) { GURL url(test_server_.GetURL("auth-basic")); URLRequest r(url, &d, &context); r.Start(); + + { + HttpRequestHeaders h; + EXPECT_TRUE(r.GetFullRequestHeaders(&h)); + EXPECT_FALSE(h.HasHeader("Authorization")); + } + MessageLoop::current()->Run(); EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status()); @@ -2810,7 +2837,8 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateOnAuthRequiredSyncNoAction) { } // Tests that the network delegate can synchronously complete OnAuthRequired -// by setting credentials. +// by setting credentials, and that GetFullRequestHeaders returns the proper +// headers (for the first or second request) when called at the proper times. TEST_F(URLRequestTestHTTP, NetworkDelegateOnAuthRequiredSyncSetAuth) { ASSERT_TRUE(test_server_.Start()); @@ -2839,6 +2867,12 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateOnAuthRequiredSyncSetAuth) { EXPECT_FALSE(d.auth_required_called()); EXPECT_EQ(1, network_delegate.created_requests()); EXPECT_EQ(0, network_delegate.destroyed_requests()); + + { + HttpRequestHeaders h; + EXPECT_TRUE(r.GetFullRequestHeaders(&h)); + EXPECT_TRUE(h.HasHeader("Authorization")); + } } EXPECT_EQ(1, network_delegate.destroyed_requests()); } @@ -3214,7 +3248,11 @@ TEST_F(URLRequestTestHTTP, GetTest) { TestDelegate d; { - URLRequest r(test_server_.GetURL(std::string()), &d, &default_context_); + GURL test_url(test_server_.GetURL(std::string())); + URLRequest r(test_url, &d, &default_context_); + + HttpRequestHeaders h; + EXPECT_FALSE(r.GetFullRequestHeaders(&h)); r.Start(); EXPECT_TRUE(r.is_pending()); @@ -3228,6 +3266,9 @@ TEST_F(URLRequestTestHTTP, GetTest) { r.GetSocketAddress().host()); EXPECT_EQ(test_server_.host_port_pair().port(), r.GetSocketAddress().port()); + + EXPECT_TRUE(d.have_full_request_headers()); + CheckFullRequestHeaders(d.full_request_headers(), test_url); } } @@ -3970,17 +4011,25 @@ TEST_F(URLRequestTestHTTP, DeferredRedirect) { TestDelegate d; { d.set_quit_on_redirect(true); - URLRequest req( - test_server_.GetURL("files/redirect-test.html"), &d, &default_context_); + GURL test_url(test_server_.GetURL("files/redirect-test.html")); + URLRequest req(test_url, &d, &default_context_); + + EXPECT_FALSE(d.have_full_request_headers()); + req.Start(); MessageLoop::current()->Run(); EXPECT_EQ(1, d.received_redirect_count()); + EXPECT_TRUE(d.have_full_request_headers()); + CheckFullRequestHeaders(d.full_request_headers(), test_url); + d.ClearFullRequestHeaders(); req.FollowDeferredRedirect(); MessageLoop::current()->Run(); EXPECT_EQ(1, d.response_started_count()); + EXPECT_TRUE(d.have_full_request_headers()); + CheckFullRequestHeaders(d.full_request_headers(), test_url); EXPECT_FALSE(d.received_data_before_response()); EXPECT_EQ(URLRequestStatus::SUCCESS, req.status().status()); |