diff options
author | ttuttle@chromium.org <ttuttle@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-10 21:08:50 +0000 |
---|---|---|
committer | ttuttle@chromium.org <ttuttle@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-10 21:08:50 +0000 |
commit | 396361315d2d4170c89bb9adb398807d220ace3e (patch) | |
tree | 8feefea7d93acad79b8a9a810dfdad5173bb7ee4 | |
parent | e8f3f9981fe331526bc5db64cda1e4fce73d35f3 (diff) | |
download | chromium_src-396361315d2d4170c89bb9adb398807d220ace3e.zip chromium_src-396361315d2d4170c89bb9adb398807d220ace3e.tar.gz chromium_src-396361315d2d4170c89bb9adb398807d220ace3e.tar.bz2 |
Add GetFullRequestHeaders, from URLRequestJob to HttpNetworkTransaction.
Dev Tools displays the raw request and response headers. Right now, it gets
them by snarfing them out of the NetLog, which is bad, as the NetLog is for
huamn consumption only. I'm trying to refactor the DevToolsNetLogObserver
away; providing an alternate, supported path to get the request headers is the
first step.
BUG=196304
TEST=added to URLRequest, HttpTransaction, and HttpNetworkTransaction unittests
Review URL: https://chromiumcodereview.appspot.com/12621011
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@199535 0039d316-1c4b-4281-b951-d872f2087c98
-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()); |