summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/http/http_cache_transaction.cc9
-rw-r--r--net/http/http_cache_transaction.h2
-rw-r--r--net/http/http_network_transaction.cc7
-rw-r--r--net/http/http_network_transaction.h2
-rw-r--r--net/http/http_network_transaction_spdy2_unittest.cc267
-rw-r--r--net/http/http_network_transaction_spdy3_unittest.cc267
-rw-r--r--net/http/http_transaction.h9
-rw-r--r--net/http/http_transaction_unittest.cc5
-rw-r--r--net/http/http_transaction_unittest.h4
-rw-r--r--net/url_request/url_request.cc7
-rw-r--r--net/url_request/url_request.h15
-rw-r--r--net/url_request/url_request_http_job.cc8
-rw-r--r--net/url_request/url_request_http_job.h2
-rw-r--r--net/url_request/url_request_job.cc5
-rw-r--r--net/url_request/url_request_job.h2
-rw-r--r--net/url_request/url_request_test_util.cc13
-rw-r--r--net/url_request/url_request_test_util.h8
-rw-r--r--net/url_request/url_request_unittest.cc59
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());