Get raw response headers using URLRequest::SetResponseHeadersCallback()
DevTools used to get actual response headers with NetLogObserver. Once we
removed NetLogObserver, we started using URLRequest::response_headers().
However, it returns the original cached headers in case of revalidation
requests, which is not what DevTools expect.
This adds SetResponseHeadersCallback() similar to SetRequestHeadersCallback()
to resolve the issue.
Bug: 758090, 721408
Change-Id: I8d8a7a757601fe282a82b8a092148726cdab85e2
Reviewed-on: https://chromium-review.googlesource.com/631119
Reviewed-by: Matt Menke <mmenke@chromium.org>
Reviewed-by: Dmitry Gozman <dgozman@chromium.org>
Commit-Queue: Andrey Kosyakov <caseq@chromium.org>
Cr-Commit-Position: refs/heads/master@{#498894}diff --git a/chrome/browser/devtools/devtools_network_transaction.cc b/chrome/browser/devtools/devtools_network_transaction.cc
index 7c16ef3a..6508896 100644
--- a/chrome/browser/devtools/devtools_network_transaction.cc
+++ b/chrome/browser/devtools/devtools_network_transaction.cc
@@ -290,6 +290,11 @@
network_transaction_->SetRequestHeadersCallback(std::move(callback));
}
+void DevToolsNetworkTransaction::SetResponseHeadersCallback(
+ net::ResponseHeadersCallback callback) {
+ network_transaction_->SetResponseHeadersCallback(std::move(callback));
+}
+
void DevToolsNetworkTransaction::SetBeforeHeadersSentCallback(
const BeforeHeadersSentCallback& callback) {
network_transaction_->SetBeforeHeadersSentCallback(callback);
diff --git a/chrome/browser/devtools/devtools_network_transaction.h b/chrome/browser/devtools/devtools_network_transaction.h
index 7805290..f52ca9f 100644
--- a/chrome/browser/devtools/devtools_network_transaction.h
+++ b/chrome/browser/devtools/devtools_network_transaction.h
@@ -89,6 +89,8 @@
void SetBeforeHeadersSentCallback(
const BeforeHeadersSentCallback& callback) override;
void SetRequestHeadersCallback(net::RequestHeadersCallback callback) override;
+ void SetResponseHeadersCallback(
+ net::ResponseHeadersCallback callback) override;
int ResumeNetworkStart() override;
void GetConnectionAttempts(net::ConnectionAttempts* out) const override;
diff --git a/chrome/browser/devtools/devtools_sanity_browsertest.cc b/chrome/browser/devtools/devtools_sanity_browsertest.cc
index faf2c46..95c216e 100644
--- a/chrome/browser/devtools/devtools_sanity_browsertest.cc
+++ b/chrome/browser/devtools/devtools_sanity_browsertest.cc
@@ -84,6 +84,7 @@
#include "net/test/spawned_test_server/spawned_test_server.h"
#include "net/test/url_request/url_request_mock_http_job.h"
#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_filter.h"
#include "net/url_request/url_request_http_job.h"
#include "third_party/WebKit/public/platform/WebInputEvent.h"
@@ -2116,3 +2117,40 @@
DevToolsWindowTesting::CloseDevToolsWindowSync(window);
content::WebUIControllerFactory::UnregisterFactoryForTesting(&test_factory);
}
+
+void AddHSTSHost(scoped_refptr<net::URLRequestContextGetter> context,
+ std::string host) {
+ net::TransportSecurityState* transport_security_state =
+ context->GetURLRequestContext()->transport_security_state();
+ base::Time expiry = base::Time::Now() + base::TimeDelta::FromDays(1000);
+ bool include_subdomains = false;
+ transport_security_state->AddHSTS(host, expiry, include_subdomains);
+}
+
+IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestRawHeadersWithRedirectAndHSTS) {
+ net::EmbeddedTestServer https_test_server(
+ net::EmbeddedTestServer::TYPE_HTTPS);
+ https_test_server.SetSSLConfig(
+ net::EmbeddedTestServer::CERT_COMMON_NAME_IS_DOMAIN);
+ https_test_server.ServeFilesFromSourceDirectory("chrome/test/data");
+ ASSERT_TRUE(https_test_server.Start());
+ GURL https_url = https_test_server.GetURL("localhost", "/devtools/image.png");
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(
+ AddHSTSHost,
+ base::RetainedRef(browser()->profile()->GetRequestContext()),
+ https_url.host()));
+ ASSERT_TRUE(embedded_test_server()->Start());
+
+ OpenDevToolsWindow(std::string(), false);
+ GURL::Replacements replace_scheme;
+ replace_scheme.SetSchemeStr("http");
+ GURL http_url = https_url.ReplaceComponents(replace_scheme);
+ GURL redirect_url =
+ embedded_test_server()->GetURL("/server-redirect?" + http_url.spec());
+
+ DispatchOnTestSuite(window_, "testRawHeadersWithHSTS",
+ redirect_url.spec().c_str());
+ CloseDevToolsWindow();
+}
diff --git a/content/browser/loader/resource_loader.cc b/content/browser/loader/resource_loader.cc
index ac97abf..a7acc5b2 100644
--- a/content/browser/loader/resource_loader.cc
+++ b/content/browser/loader/resource_loader.cc
@@ -52,7 +52,8 @@
ResourceRequestInfoImpl* info,
net::URLRequest* request,
ResourceResponse* response,
- const net::HttpRawRequestHeaders& raw_request_headers) {
+ const net::HttpRawRequestHeaders& raw_request_headers,
+ const net::HttpResponseHeaders* raw_response_headers) {
response->head.request_time = request->request_time();
response->head.response_time = request->response_time();
response->head.headers = request->response_headers();
@@ -72,7 +73,7 @@
response->head.previews_state = request_info->GetPreviewsState();
if (info->ShouldReportRawHeaders()) {
response->head.devtools_info =
- BuildDevToolsInfo(*request, raw_request_headers);
+ BuildDevToolsInfo(*request, raw_request_headers, raw_response_headers);
}
response->head.effective_connection_type =
@@ -342,7 +343,10 @@
scoped_refptr<ResourceResponse> response = new ResourceResponse();
PopulateResourceResponse(info, request_.get(), response.get(),
- raw_request_headers_);
+ raw_request_headers_, raw_response_headers_.get());
+ raw_request_headers_ = net::HttpRawRequestHeaders();
+ raw_response_headers_ = nullptr;
+
delegate_->DidReceiveRedirect(this, redirect_info.new_url, response.get());
// Can't used ScopedDeferral here, because on sync completion, need to set
@@ -573,6 +577,8 @@
request_->SetRequestHeadersCallback(
base::Bind(&net::HttpRawRequestHeaders::Assign,
base::Unretained(&raw_request_headers_)));
+ request_->SetResponseHeadersCallback(base::Bind(
+ &ResourceLoader::SetRawResponseHeaders, base::Unretained(this)));
}
request_->Start();
@@ -640,7 +646,9 @@
ResourceRequestInfoImpl* info = GetRequestInfo();
scoped_refptr<ResourceResponse> response = new ResourceResponse();
PopulateResourceResponse(info, request_.get(), response.get(),
- raw_request_headers_);
+ raw_request_headers_, raw_response_headers_.get());
+ raw_request_headers_ = net::HttpRawRequestHeaders();
+ raw_response_headers_ = nullptr;
delegate_->DidReceiveResponse(this, response.get());
@@ -821,4 +829,9 @@
}
}
+void ResourceLoader::SetRawResponseHeaders(
+ scoped_refptr<const net::HttpResponseHeaders> headers) {
+ raw_response_headers_ = headers;
+}
+
} // namespace content
diff --git a/content/browser/loader/resource_loader.h b/content/browser/loader/resource_loader.h
index 924c368..259d498 100644
--- a/content/browser/loader/resource_loader.h
+++ b/content/browser/loader/resource_loader.h
@@ -22,6 +22,7 @@
#include "url/gurl.h"
namespace net {
+class HttpResponseHeaders;
class X509Certificate;
}
@@ -114,6 +115,8 @@
void ResponseCompleted();
void CallDidFinishLoading();
void RecordHistograms();
+ void SetRawResponseHeaders(
+ scoped_refptr<const net::HttpResponseHeaders> headers);
bool is_deferred() const { return deferred_stage_ != DEFERRED_NONE; }
@@ -180,6 +183,7 @@
int read_buffer_size_;
net::HttpRawRequestHeaders raw_request_headers_;
+ scoped_refptr<const net::HttpResponseHeaders> raw_response_headers_;
base::ThreadChecker thread_checker_;
diff --git a/content/common/loader_util.cc b/content/common/loader_util.cc
index 27170c67..0886c2b 100644
--- a/content/common/loader_util.cc
+++ b/content/common/loader_util.cc
@@ -41,7 +41,8 @@
scoped_refptr<ResourceDevToolsInfo> BuildDevToolsInfo(
const net::URLRequest& request,
- const net::HttpRawRequestHeaders& raw_request_headers) {
+ const net::HttpRawRequestHeaders& raw_request_headers,
+ const net::HttpResponseHeaders* raw_response_headers) {
scoped_refptr<ResourceDevToolsInfo> info = new ResourceDevToolsInfo();
const net::HttpResponseInfo& response_info = request.response_info();
@@ -65,21 +66,22 @@
info->request_headers_text = std::move(text);
}
- const net::HttpResponseHeaders* response_headers = request.response_headers();
- if (response_headers) {
- info->http_status_code = response_headers->response_code();
- info->http_status_text = response_headers->GetStatusText();
+ if (!raw_response_headers)
+ raw_response_headers = request.response_headers();
+ if (raw_response_headers) {
+ info->http_status_code = raw_response_headers->response_code();
+ info->http_status_text = raw_response_headers->GetStatusText();
std::string name;
std::string value;
for (size_t it = 0;
- response_headers->EnumerateHeaderLines(&it, &name, &value);) {
+ raw_response_headers->EnumerateHeaderLines(&it, &name, &value);) {
info->response_headers.push_back(std::make_pair(name, value));
}
if (report_headers_text) {
info->response_headers_text =
net::HttpUtil::ConvertHeadersBackToHTTPResponse(
- response_headers->raw_headers());
+ raw_response_headers->raw_headers());
}
}
return info;
diff --git a/content/common/loader_util.h b/content/common/loader_util.h
index 99e74664..8f232c3 100644
--- a/content/common/loader_util.h
+++ b/content/common/loader_util.h
@@ -9,6 +9,7 @@
namespace net {
class HttpRawRequestHeaders;
+class HttpResponseHeaders;
class URLRequest;
}
@@ -27,7 +28,8 @@
// Fill ResourceDevToolsInfo based on raw headers.
scoped_refptr<ResourceDevToolsInfo> BuildDevToolsInfo(
const net::URLRequest& request,
- const net::HttpRawRequestHeaders& raw_request_headers);
+ const net::HttpRawRequestHeaders& raw_request_headers,
+ const net::HttpResponseHeaders* raw_response_headers);
} // namespace content
diff --git a/content/network/url_loader_impl.cc b/content/network/url_loader_impl.cc
index 61254bb..40e38e56 100644
--- a/content/network/url_loader_impl.cc
+++ b/content/network/url_loader_impl.cc
@@ -211,6 +211,8 @@
url_request_->SetRequestHeadersCallback(
base::Bind(&net::HttpRawRequestHeaders::Assign,
base::Unretained(&raw_request_headers_)));
+ url_request_->SetResponseHeadersCallback(base::Bind(
+ &URLLoaderImpl::SetRawResponseHeaders, base::Unretained(this)));
}
url_request_->Start();
}
@@ -253,8 +255,10 @@
scoped_refptr<ResourceResponse> response = new ResourceResponse();
PopulateResourceResponse(url_request_.get(), response.get());
if (report_raw_headers_) {
- response->head.devtools_info =
- BuildDevToolsInfo(*url_request_, raw_request_headers_);
+ response->head.devtools_info = BuildDevToolsInfo(
+ *url_request_, raw_request_headers_, raw_response_headers_.get());
+ raw_request_headers_ = net::HttpRawRequestHeaders();
+ raw_response_headers_ = nullptr;
}
url_loader_client_->OnReceiveRedirect(redirect_info, response->head);
}
@@ -272,8 +276,10 @@
response_ = new ResourceResponse();
PopulateResourceResponse(url_request_.get(), response_.get());
if (report_raw_headers_) {
- response_->head.devtools_info =
- BuildDevToolsInfo(*url_request_, raw_request_headers_);
+ response_->head.devtools_info = BuildDevToolsInfo(
+ *url_request_, raw_request_headers_, raw_response_headers_.get());
+ raw_request_headers_ = net::HttpRawRequestHeaders();
+ raw_response_headers_ = nullptr;
}
mojo::DataPipe data_pipe(kDefaultAllocationSize);
@@ -481,4 +487,9 @@
total_written_bytes_ += pending_write_buffer_offset_;
}
+void URLLoaderImpl::SetRawResponseHeaders(
+ scoped_refptr<const net::HttpResponseHeaders> headers) {
+ raw_response_headers_ = headers;
+}
+
} // namespace content
diff --git a/content/network/url_loader_impl.h b/content/network/url_loader_impl.h
index c9f6677..c4e0bc5 100644
--- a/content/network/url_loader_impl.h
+++ b/content/network/url_loader_impl.h
@@ -19,6 +19,10 @@
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/url_request/url_request.h"
+namespace net {
+class HttpResponseHeaders;
+}
+
namespace network {
class NetToMojoPendingBuffer;
}
@@ -67,6 +71,7 @@
void DeleteIfNeeded();
void SendResponseToClient();
void CompletePendingWrite();
+ void SetRawResponseHeaders(scoped_refptr<const net::HttpResponseHeaders>);
NetworkContext* context_;
int32_t options_;
@@ -90,6 +95,7 @@
bool report_raw_headers_;
net::HttpRawRequestHeaders raw_request_headers_;
+ scoped_refptr<const net::HttpResponseHeaders> raw_response_headers_;
base::WeakPtrFactory<URLLoaderImpl> weak_ptr_factory_;
diff --git a/net/http/failing_http_transaction_factory.cc b/net/http/failing_http_transaction_factory.cc
index 18c757fd..d6202bf 100644
--- a/net/http/failing_http_transaction_factory.cc
+++ b/net/http/failing_http_transaction_factory.cc
@@ -71,6 +71,7 @@
int ResumeNetworkStart() override;
void GetConnectionAttempts(ConnectionAttempts* out) const override;
void SetRequestHeadersCallback(RequestHeadersCallback) override {}
+ void SetResponseHeadersCallback(ResponseHeadersCallback) override {}
private:
Error error_;
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc
index 1439c700..8912d2e 100644
--- a/net/http/http_cache_transaction.cc
+++ b/net/http/http_cache_transaction.cc
@@ -555,6 +555,12 @@
request_headers_callback_ = std::move(callback);
}
+void HttpCache::Transaction::SetResponseHeadersCallback(
+ ResponseHeadersCallback callback) {
+ DCHECK(!network_trans_);
+ response_headers_callback_ = std::move(callback);
+}
+
int HttpCache::Transaction::ResumeNetworkStart() {
if (network_trans_)
return network_trans_->ResumeNetworkStart();
@@ -1501,6 +1507,7 @@
network_trans_->SetBeforeNetworkStartCallback(before_network_start_callback_);
network_trans_->SetBeforeHeadersSentCallback(before_headers_sent_callback_);
network_trans_->SetRequestHeadersCallback(request_headers_callback_);
+ network_trans_->SetResponseHeadersCallback(response_headers_callback_);
// Old load timing information, if any, is now obsolete.
old_network_trans_load_timing_.reset();
diff --git a/net/http/http_cache_transaction.h b/net/http/http_cache_transaction.h
index 6357334..8c709a754 100644
--- a/net/http/http_cache_transaction.h
+++ b/net/http/http_cache_transaction.h
@@ -169,7 +169,8 @@
const BeforeNetworkStartCallback& callback) override;
void SetBeforeHeadersSentCallback(
const BeforeHeadersSentCallback& callback) override;
- void SetRequestHeadersCallback(RequestHeadersCallback) override;
+ void SetRequestHeadersCallback(RequestHeadersCallback callback) override;
+ void SetResponseHeadersCallback(ResponseHeadersCallback callback) override;
int ResumeNetworkStart() override;
void GetConnectionAttempts(ConnectionAttempts* out) const override;
@@ -569,6 +570,7 @@
BeforeNetworkStartCallback before_network_start_callback_;
BeforeHeadersSentCallback before_headers_sent_callback_;
RequestHeadersCallback request_headers_callback_;
+ ResponseHeadersCallback response_headers_callback_;
// True if the Transaction is currently processing the DoLoop.
bool in_do_loop_;
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index 4f0deafa4d..2290f32 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -457,6 +457,12 @@
request_headers_callback_ = std::move(callback);
}
+void HttpNetworkTransaction::SetResponseHeadersCallback(
+ ResponseHeadersCallback callback) {
+ DCHECK(!stream_);
+ response_headers_callback_ = std::move(callback);
+}
+
int HttpNetworkTransaction::ResumeNetworkStart() {
DCHECK_EQ(next_state_, STATE_CREATE_STREAM);
return DoLoop(OK);
@@ -1280,6 +1286,8 @@
net_log_.AddEvent(
NetLogEventType::HTTP_TRANSACTION_READ_RESPONSE_HEADERS,
base::Bind(&HttpResponseHeaders::NetLogCallback, response_.headers));
+ if (response_headers_callback_)
+ response_headers_callback_.Run(response_.headers);
if (response_.headers->GetHttpVersion() < HttpVersion(1, 0)) {
// HTTP/0.9 doesn't support the PUT method, so lack of response headers
diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h
index 735e3d2..866b5a2 100644
--- a/net/http/http_network_transaction.h
+++ b/net/http/http_network_transaction.h
@@ -90,7 +90,8 @@
const BeforeNetworkStartCallback& callback) override;
void SetBeforeHeadersSentCallback(
const BeforeHeadersSentCallback& callback) override;
- void SetRequestHeadersCallback(RequestHeadersCallback) override;
+ void SetRequestHeadersCallback(RequestHeadersCallback callback) override;
+ void SetResponseHeadersCallback(ResponseHeadersCallback callback) override;
int ResumeNetworkStart() override;
@@ -398,6 +399,7 @@
BeforeNetworkStartCallback before_network_start_callback_;
BeforeHeadersSentCallback before_headers_sent_callback_;
RequestHeadersCallback request_headers_callback_;
+ ResponseHeadersCallback response_headers_callback_;
ConnectionAttempts connection_attempts_;
IPEndPoint remote_endpoint_;
diff --git a/net/http/http_response_headers.h b/net/http/http_response_headers.h
index ea27a47..839dd75d8 100644
--- a/net/http/http_response_headers.h
+++ b/net/http/http_response_headers.h
@@ -390,6 +390,9 @@
DISALLOW_COPY_AND_ASSIGN(HttpResponseHeaders);
};
+using ResponseHeadersCallback =
+ base::Callback<void(scoped_refptr<const HttpResponseHeaders>)>;
+
} // namespace net
#endif // NET_HTTP_HTTP_RESPONSE_HEADERS_H_
diff --git a/net/http/http_transaction.h b/net/http/http_transaction.h
index 28fe77e..a921206 100644
--- a/net/http/http_transaction.h
+++ b/net/http/http_transaction.h
@@ -14,6 +14,7 @@
#include "net/base/request_priority.h"
#include "net/base/upload_progress.h"
#include "net/http/http_raw_request_headers.h"
+#include "net/http/http_response_headers.h"
#include "net/socket/connection_attempts.h"
#include "net/websockets/websocket_handshake_stream_base.h"
@@ -193,7 +194,8 @@
virtual void SetBeforeHeadersSentCallback(
const BeforeHeadersSentCallback& callback) = 0;
- virtual void SetRequestHeadersCallback(RequestHeadersCallback) = 0;
+ virtual void SetRequestHeadersCallback(RequestHeadersCallback callback) = 0;
+ virtual void SetResponseHeadersCallback(ResponseHeadersCallback callback) = 0;
// Resumes the transaction after being deferred.
virtual int ResumeNetworkStart() = 0;
diff --git a/net/http/http_transaction_test_util.h b/net/http/http_transaction_test_util.h
index 419719a..bc834575 100644
--- a/net/http/http_transaction_test_util.h
+++ b/net/http/http_transaction_test_util.h
@@ -238,6 +238,7 @@
const BeforeHeadersSentCallback& callback) override;
void SetRequestHeadersCallback(RequestHeadersCallback callback) override {}
+ void SetResponseHeadersCallback(ResponseHeadersCallback) override {}
int ResumeNetworkStart() override;
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc
index 5ccc821..a66d192b 100644
--- a/net/url_request/url_request.cc
+++ b/net/url_request/url_request.cc
@@ -28,7 +28,6 @@
#include "net/base/network_change_notifier.h"
#include "net/base/network_delegate.h"
#include "net/base/upload_data_stream.h"
-#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
#include "net/log/net_log.h"
#include "net/log/net_log_event_type.h"
@@ -646,6 +645,7 @@
job_->SetExtraRequestHeaders(extra_request_headers_);
job_->SetPriority(priority_);
job_->SetRequestHeadersCallback(request_headers_callback_);
+ job_->SetResponseHeadersCallback(response_headers_callback_);
if (upload_data_stream_.get())
job_->SetUpload(upload_data_stream_.get());
@@ -1220,6 +1220,12 @@
request_headers_callback_ = std::move(callback);
}
+void URLRequest::SetResponseHeadersCallback(ResponseHeadersCallback callback) {
+ DCHECK(!job_.get());
+ DCHECK(response_headers_callback_.is_null());
+ response_headers_callback_ = std::move(callback);
+}
+
void URLRequest::set_status(URLRequestStatus status) {
DCHECK(status_.is_io_pending() || status_.is_success() ||
(!status.is_success() && !status.is_io_pending()));
diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h
index 603c4bd..ae6bba1 100644
--- a/net/url_request/url_request.h
+++ b/net/url_request/url_request.h
@@ -31,6 +31,7 @@
#include "net/cookies/canonical_cookie.h"
#include "net/http/http_raw_request_headers.h"
#include "net/http/http_request_headers.h"
+#include "net/http/http_response_headers.h"
#include "net/http/http_response_info.h"
#include "net/log/net_log_with_source.h"
#include "net/proxy/proxy_server.h"
@@ -673,6 +674,13 @@
// before the request is started.
void SetRequestHeadersCallback(RequestHeadersCallback callback);
+ // Sets a callback that will be invoked each time the response is received
+ // from the remote party with the actual response headers recieved. Note this
+ // is different from response_headers() getter in that in case of revalidation
+ // request, the latter will return cached headers, while the callback will be
+ // called with a response from the server.
+ void SetResponseHeadersCallback(ResponseHeadersCallback callback);
+
protected:
// Allow the URLRequestJob class to control the is_pending() flag.
void set_is_pending(bool value) { is_pending_ = value; }
@@ -877,8 +885,9 @@
const NetworkTrafficAnnotationTag traffic_annotation_;
- // See SetRequestHeadersCallback() above for details.
+ // See Set{Request|Response}HeadersCallback() above for details.
RequestHeadersCallback request_headers_callback_;
+ ResponseHeadersCallback response_headers_callback_;
THREAD_CHECKER(thread_checker_);
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index 7a61c851..6b115afc 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -576,6 +576,7 @@
base::Bind(&URLRequestHttpJob::NotifyBeforeSendHeadersCallback,
base::Unretained(this)));
transaction_->SetRequestHeadersCallback(request_headers_callback_);
+ transaction_->SetResponseHeadersCallback(response_headers_callback_);
if (!throttling_entry_.get() ||
!throttling_entry_->ShouldRejectRequest(*request_)) {
@@ -1558,6 +1559,13 @@
request_headers_callback_ = std::move(callback);
}
+void URLRequestHttpJob::SetResponseHeadersCallback(
+ ResponseHeadersCallback callback) {
+ DCHECK(!transaction_);
+ DCHECK(!response_headers_callback_);
+ response_headers_callback_ = std::move(callback);
+}
+
void URLRequestHttpJob::RecordPerfHistograms(CompletionCause reason) {
if (start_time_.is_null())
return;
diff --git a/net/url_request/url_request_http_job.h b/net/url_request/url_request_http_job.h
index 989c5c8f..55101ce 100644
--- a/net/url_request/url_request_http_job.h
+++ b/net/url_request/url_request_http_job.h
@@ -50,6 +50,7 @@
// access it.
void RecordPacketStats(SdchPolicyDelegate::StatisticSelector statistic) const;
void SetRequestHeadersCallback(RequestHeadersCallback callback) override;
+ void SetResponseHeadersCallback(ResponseHeadersCallback callback) override;
protected:
URLRequestHttpJob(URLRequest* request,
@@ -271,6 +272,7 @@
int64_t total_sent_bytes_from_previous_transactions_;
RequestHeadersCallback request_headers_callback_;
+ ResponseHeadersCallback response_headers_callback_;
base::WeakPtrFactory<URLRequestHttpJob> weak_factory_;
diff --git a/net/url_request/url_request_job.cc b/net/url_request/url_request_job.cc
index d7feb59..9112c44 100644
--- a/net/url_request/url_request_job.cc
+++ b/net/url_request/url_request_job.cc
@@ -27,7 +27,6 @@
#include "net/base/load_states.h"
#include "net/base/net_errors.h"
#include "net/base/network_delegate.h"
-#include "net/http/http_response_headers.h"
#include "net/log/net_log.h"
#include "net/log/net_log_capture_mode.h"
#include "net/log/net_log_event_type.h"
@@ -382,10 +381,6 @@
out->clear();
}
-void URLRequestJob::SetRequestHeadersCallback(RequestHeadersCallback callback) {
- request_headers_callback_ = std::move(callback);
-}
-
// static
GURL URLRequestJob::ComputeReferrerForPolicy(URLRequest::ReferrerPolicy policy,
const GURL& original_referrer,
diff --git a/net/url_request/url_request_job.h b/net/url_request/url_request_job.h
index a844f74..aaed867 100644
--- a/net/url_request/url_request_job.h
+++ b/net/url_request/url_request_job.h
@@ -22,6 +22,7 @@
#include "net/cookies/canonical_cookie.h"
#include "net/filter/source_stream.h"
#include "net/http/http_raw_request_headers.h"
+#include "net/http/http_response_headers.h"
#include "net/socket/connection_attempts.h"
#include "net/url_request/redirect_info.h"
#include "net/url_request/url_request.h"
@@ -234,7 +235,11 @@
// be actually sent and will receive actual request headers that are about
// to hit the wire, including SPDY/QUIC internal headers and any additional
// request headers set via BeforeSendHeaders hooks.
- virtual void SetRequestHeadersCallback(RequestHeadersCallback callback);
+ virtual void SetRequestHeadersCallback(RequestHeadersCallback callback) {}
+
+ // Sets a callback that will be invoked each time the response is received
+ // from the remote party with the actual response headers recieved.
+ virtual void SetResponseHeadersCallback(ResponseHeadersCallback callback) {}
// Given |policy|, |referrer|, and |destination|, returns the
// referrer URL mandated by |request|'s referrer policy.
@@ -450,9 +455,6 @@
// completed.
CompletionCallback read_raw_callback_;
- // See SetRequestHeadersCallback() above for details.
- RequestHeadersCallback request_headers_callback_;
-
base::WeakPtrFactory<URLRequestJob> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(URLRequestJob);
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 0794a3a..937bae4 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -11716,7 +11716,7 @@
EXPECT_EQ(0, d.received_redirect_count());
}
-TEST_F(URLRequestTestHTTP, RequestHeadersCallback) {
+TEST_F(URLRequestTestHTTP, HeadersCallbacks) {
ASSERT_TRUE(http_test_server()->Start());
TestURLRequestContext context;
GURL url(http_test_server()->GetURL("/cachetime"));
@@ -11725,44 +11725,54 @@
extra_headers.SetHeader("X-Foo", "bar");
{
- HttpRawRequestHeaders raw_headers;
+ HttpRawRequestHeaders raw_req_headers;
+ scoped_refptr<const HttpResponseHeaders> raw_resp_headers;
+
std::unique_ptr<URLRequest> r(context.CreateRequest(
url, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS));
r->SetExtraRequestHeaders(extra_headers);
- r->SetRequestHeadersCallback(base::Bind(&HttpRawRequestHeaders::Assign,
- base::Unretained(&raw_headers)));
+ r->SetRequestHeadersCallback(base::Bind(
+ &HttpRawRequestHeaders::Assign, base::Unretained(&raw_req_headers)));
+ r->SetResponseHeadersCallback(base::Bind(
+ [](scoped_refptr<const HttpResponseHeaders>* left,
+ scoped_refptr<const HttpResponseHeaders> right) { *left = right; },
+ base::Unretained(&raw_resp_headers)));
r->Start();
while (!delegate.response_started_count())
base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(raw_headers.headers().empty());
+ EXPECT_FALSE(raw_req_headers.headers().empty());
std::string value;
- EXPECT_TRUE(raw_headers.FindHeaderForTest("X-Foo", &value));
+ EXPECT_TRUE(raw_req_headers.FindHeaderForTest("X-Foo", &value));
EXPECT_EQ("bar", value);
- EXPECT_TRUE(raw_headers.FindHeaderForTest("Accept-Encoding", &value));
+ EXPECT_TRUE(raw_req_headers.FindHeaderForTest("Accept-Encoding", &value));
EXPECT_EQ("gzip, deflate", value);
- EXPECT_TRUE(raw_headers.FindHeaderForTest("Connection", &value));
- EXPECT_TRUE(raw_headers.FindHeaderForTest("Host", &value));
- EXPECT_EQ("GET /cachetime HTTP/1.1\r\n", raw_headers.request_line());
+ EXPECT_TRUE(raw_req_headers.FindHeaderForTest("Connection", &value));
+ EXPECT_TRUE(raw_req_headers.FindHeaderForTest("Host", &value));
+ EXPECT_EQ("GET /cachetime HTTP/1.1\r\n", raw_req_headers.request_line());
+ EXPECT_EQ(raw_resp_headers.get(), r->response_headers());
}
{
- HttpRawRequestHeaders raw_headers;
std::unique_ptr<URLRequest> r(context.CreateRequest(
url, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS));
r->SetExtraRequestHeaders(extra_headers);
- r->SetRequestHeadersCallback(base::Bind([](net::HttpRawRequestHeaders) {
+ r->SetRequestHeadersCallback(base::Bind([](HttpRawRequestHeaders) {
FAIL() << "Callback should not be called unless request is sent";
}));
+ r->SetResponseHeadersCallback(
+ base::Bind([](scoped_refptr<const HttpResponseHeaders>) {
+ FAIL() << "Callback should not be called unless request is sent";
+ }));
r->Start();
base::RunLoop().Run();
EXPECT_TRUE(r->was_cached());
- EXPECT_TRUE(raw_headers.headers().empty());
- EXPECT_TRUE(raw_headers.request_line().empty());
}
}
-TEST_F(URLRequestTestHTTP, RequestHeadersCallbackWithRedirect) {
+TEST_F(URLRequestTestHTTP, HeadersCallbacksWithRedirect) {
ASSERT_TRUE(http_test_server()->Start());
- HttpRawRequestHeaders raw_headers;
+ HttpRawRequestHeaders raw_req_headers;
+ scoped_refptr<const HttpResponseHeaders> raw_resp_headers;
+
TestURLRequestContext context;
TestDelegate delegate;
HttpRequestHeaders extra_headers;
@@ -11773,30 +11783,41 @@
url, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS));
r->SetExtraRequestHeaders(extra_headers);
r->SetRequestHeadersCallback(base::Bind(&HttpRawRequestHeaders::Assign,
- base::Unretained(&raw_headers)));
+ base::Unretained(&raw_req_headers)));
+ r->SetResponseHeadersCallback(base::Bind(
+ [](scoped_refptr<const HttpResponseHeaders>* left,
+ scoped_refptr<const HttpResponseHeaders> right) { *left = right; },
+ base::Unretained(&raw_resp_headers)));
r->Start();
base::RunLoop().Run();
ASSERT_EQ(1, delegate.received_redirect_count());
std::string value;
- EXPECT_TRUE(raw_headers.FindHeaderForTest("X-Foo", &value));
+ EXPECT_TRUE(raw_req_headers.FindHeaderForTest("X-Foo", &value));
EXPECT_EQ("bar", value);
- EXPECT_TRUE(raw_headers.FindHeaderForTest("Accept-Encoding", &value));
+ EXPECT_TRUE(raw_req_headers.FindHeaderForTest("Accept-Encoding", &value));
EXPECT_EQ("gzip, deflate", value);
EXPECT_EQ(1, delegate.received_redirect_count());
- EXPECT_EQ("GET /redirect-test.html HTTP/1.1\r\n", raw_headers.request_line());
+ EXPECT_EQ("GET /redirect-test.html HTTP/1.1\r\n",
+ raw_req_headers.request_line());
+ EXPECT_TRUE(raw_resp_headers->HasHeader("Location"));
+ EXPECT_EQ(302, raw_resp_headers->response_code());
+ EXPECT_EQ("Redirect", raw_resp_headers->GetStatusText());
- raw_headers = HttpRawRequestHeaders();
+ raw_req_headers = HttpRawRequestHeaders();
+ raw_resp_headers = nullptr;
r->FollowDeferredRedirect();
base::RunLoop().Run();
- EXPECT_TRUE(raw_headers.FindHeaderForTest("X-Foo", &value));
+ EXPECT_TRUE(raw_req_headers.FindHeaderForTest("X-Foo", &value));
EXPECT_EQ("bar", value);
- EXPECT_TRUE(raw_headers.FindHeaderForTest("Accept-Encoding", &value));
+ EXPECT_TRUE(raw_req_headers.FindHeaderForTest("Accept-Encoding", &value));
EXPECT_EQ("gzip, deflate", value);
- EXPECT_EQ("GET /with-headers.html HTTP/1.1\r\n", raw_headers.request_line());
+ EXPECT_EQ("GET /with-headers.html HTTP/1.1\r\n",
+ raw_req_headers.request_line());
+ EXPECT_EQ(r->response_headers(), raw_resp_headers.get());
}
-TEST_F(URLRequestTest, RequestHeadersCallbackConnectFailed) {
+TEST_F(URLRequestTest, HeadersCallbacksConnectFailed) {
TestDelegate request_delegate;
std::unique_ptr<URLRequest> r(default_context_.CreateRequest(
@@ -11805,12 +11826,16 @@
r->SetRequestHeadersCallback(base::Bind([](net::HttpRawRequestHeaders) {
FAIL() << "Callback should not be called unless request is sent";
}));
+ r->SetResponseHeadersCallback(
+ base::Bind([](scoped_refptr<const net::HttpResponseHeaders>) {
+ FAIL() << "Callback should not be called unless request is sent";
+ }));
r->Start();
base::RunLoop().Run();
EXPECT_FALSE(r->is_pending());
}
-TEST_F(URLRequestTestHTTP, RequestHeadersCallbackAuthRetry) {
+TEST_F(URLRequestTestHTTP, HeadersCallbacksAuthRetry) {
ASSERT_TRUE(http_test_server()->Start());
GURL url(http_test_server()->GetURL("/auth-basic"));
@@ -11821,38 +11846,75 @@
HttpRequestHeaders extra_headers;
extra_headers.SetHeader("X-Foo", "bar");
- using HeadersVector = std::vector<std::unique_ptr<HttpRawRequestHeaders>>;
- HeadersVector raw_headers;
+ using ReqHeadersVector = std::vector<std::unique_ptr<HttpRawRequestHeaders>>;
+ ReqHeadersVector raw_req_headers;
+ using RespHeadersVector =
+ std::vector<scoped_refptr<const HttpResponseHeaders>>;
+ RespHeadersVector raw_resp_headers;
+
+ auto req_headers_callback = base::Bind(
+ [](ReqHeadersVector* vec, HttpRawRequestHeaders headers) {
+ vec->emplace_back(new HttpRawRequestHeaders(std::move(headers)));
+ },
+ &raw_req_headers);
+ auto resp_headers_callback = base::Bind(
+ [](RespHeadersVector* vec,
+ scoped_refptr<const HttpResponseHeaders> headers) {
+ vec->push_back(headers);
+ },
+ &raw_resp_headers);
std::unique_ptr<URLRequest> r(context.CreateRequest(
url, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS));
r->SetExtraRequestHeaders(extra_headers);
- r->SetRequestHeadersCallback(base::Bind(
- [](HeadersVector* vec, HttpRawRequestHeaders headers) {
- vec->emplace_back(new HttpRawRequestHeaders(std::move(headers)));
- },
- &raw_headers));
+ r->SetRequestHeadersCallback(req_headers_callback);
+ r->SetResponseHeadersCallback(resp_headers_callback);
r->Start();
base::RunLoop().Run();
EXPECT_FALSE(r->is_pending());
- ASSERT_GE(raw_headers.size(), 2u);
+ ASSERT_EQ(raw_req_headers.size(), 2u);
+ ASSERT_EQ(raw_resp_headers.size(), 2u);
std::string value;
- EXPECT_FALSE(raw_headers[0]->FindHeaderForTest("Authorization", &value));
- EXPECT_TRUE(raw_headers[0]->FindHeaderForTest("X-Foo", &value));
+ EXPECT_FALSE(raw_req_headers[0]->FindHeaderForTest("Authorization", &value));
+ EXPECT_TRUE(raw_req_headers[0]->FindHeaderForTest("X-Foo", &value));
EXPECT_EQ("bar", value);
- EXPECT_TRUE(raw_headers[1]->FindHeaderForTest("Authorization", &value));
- EXPECT_TRUE(raw_headers[1]->FindHeaderForTest("X-Foo", &value));
+ EXPECT_TRUE(raw_req_headers[1]->FindHeaderForTest("Authorization", &value));
+ EXPECT_TRUE(raw_req_headers[1]->FindHeaderForTest("X-Foo", &value));
EXPECT_EQ("bar", value);
+ EXPECT_EQ(raw_resp_headers[1], r->response_headers());
+ EXPECT_NE(raw_resp_headers[0], raw_resp_headers[1]);
+ EXPECT_EQ(401, raw_resp_headers[0]->response_code());
+ EXPECT_EQ("Unauthorized", raw_resp_headers[0]->GetStatusText());
+
+ std::unique_ptr<URLRequest> r2(context.CreateRequest(
+ url, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS));
+ r2->SetExtraRequestHeaders(extra_headers);
+ r2->SetRequestHeadersCallback(req_headers_callback);
+ r2->SetResponseHeadersCallback(resp_headers_callback);
+ r2->SetLoadFlags(LOAD_VALIDATE_CACHE);
+ r2->Start();
+ base::RunLoop().Run();
+ EXPECT_FALSE(r2->is_pending());
+ ASSERT_EQ(raw_req_headers.size(), 3u);
+ ASSERT_EQ(raw_resp_headers.size(), 3u);
+ EXPECT_TRUE(raw_req_headers[2]->FindHeaderForTest("If-None-Match", &value));
+ EXPECT_NE(raw_resp_headers[2].get(), r2->response_headers());
+ EXPECT_EQ(304, raw_resp_headers[2]->response_code());
+ EXPECT_EQ("Not Modified", raw_resp_headers[2]->GetStatusText());
}
-TEST_F(URLRequestTest, RequestHeadersCallbackNonHTTP) {
+TEST_F(URLRequestTest, HeadersCallbacksNonHTTP) {
GURL data_url("data:text/html,<html><body>Hello!</body></html>");
TestDelegate d;
std::unique_ptr<URLRequest> r(default_context_.CreateRequest(
data_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS));
r->SetRequestHeadersCallback(base::Bind([](net::HttpRawRequestHeaders) {
- FAIL() << "Callback should not be called unless request is sent";
+ FAIL() << "Callback should not be called for non-HTTP schemes";
}));
+ r->SetResponseHeadersCallback(
+ base::Bind([](scoped_refptr<const net::HttpResponseHeaders>) {
+ FAIL() << "Callback should not be called for non-HTTP schemes";
+ }));
r->Start();
base::RunLoop().Run();
EXPECT_FALSE(r->is_pending());
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/network/raw-response-headers-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/network/raw-response-headers-expected.txt
new file mode 100644
index 0000000..fb71abb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/network/raw-response-headers-expected.txt
@@ -0,0 +1,5 @@
+Tests that raw response headers are correctly reported in case of revalidation.
+Response status: 304 Not Modified
+Response headers text present: true
+Content-Length present: false
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/network/raw-response-headers.js b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/network/raw-response-headers.js
new file mode 100644
index 0000000..03aa16e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/network/raw-response-headers.js
@@ -0,0 +1,16 @@
+(async function(testRunner) {
+ var {page, session, dp} = await testRunner.startURL(
+ '../resources/test-page.html',
+ `Tests that raw response headers are correctly reported in case of revalidation.`);
+
+ dp.Network.enable();
+ session.protocol.Page.reload();
+ const response = (await dp.Network.onceResponseReceived()).params.response;
+
+ const haveContentLength = Object.keys(response.headers).indexOf('Content-Length') >= 0;
+ testRunner.log(`Response status: ${response.status} ${response.statusText}`);
+ testRunner.log(`Response headers text present: ${!!response.headersText.length}`);
+ testRunner.log(`Content-Length present: ${haveContentLength}`);
+
+ testRunner.completeTest();
+})
\ No newline at end of file
diff --git a/third_party/WebKit/Source/devtools/front_end/Tests.js b/third_party/WebKit/Source/devtools/front_end/Tests.js
index 7d2ee70f..deeccf62 100644
--- a/third_party/WebKit/Source/devtools/front_end/Tests.js
+++ b/third_party/WebKit/Source/devtools/front_end/Tests.js
@@ -930,6 +930,50 @@
}
};
+ TestSuite.prototype.testRawHeadersWithHSTS = function(url) {
+ var test = this;
+ test.takeControl();
+ SDK.targetManager.addModelListener(
+ SDK.NetworkManager, SDK.NetworkManager.Events.ResponseReceived, onResponseReceived);
+
+ this.evaluateInConsole_(`
+ var img = document.createElement('img');
+ img.src = "${url}";
+ document.body.appendChild(img);
+ `, () => {});
+
+ var count = 0;
+ function onResponseReceived(event) {
+ var networkRequest = event.data;
+ if (!networkRequest.url().startsWith('http'))
+ return;
+ switch (++count) {
+ case 1: // Original redirect
+ test.assertEquals(301, networkRequest.statusCode);
+ test.assertEquals('Moved Permanently', networkRequest.statusText);
+ test.assertTrue(url.endsWith(networkRequest.responseHeaderValue('Location')));
+ break;
+
+ case 2: // HSTS internal redirect
+ test.assertTrue(networkRequest.url().startsWith('http://'));
+ test.assertEquals(undefined, networkRequest.requestHeadersText());
+ test.assertEquals(307, networkRequest.statusCode);
+ test.assertEquals('Internal Redirect', networkRequest.statusText);
+ test.assertEquals('HSTS', networkRequest.responseHeaderValue('Non-Authoritative-Reason'));
+ test.assertTrue(networkRequest.responseHeaderValue('Location').startsWith('https://'));
+ break;
+
+ case 3: // Final response
+ test.assertTrue(networkRequest.url().startsWith('https://'));
+ test.assertTrue(networkRequest.requestHeaderValue('Referer').startsWith('http://127.0.0.1'));
+ test.assertEquals(200, networkRequest.statusCode);
+ test.assertEquals('OK', networkRequest.statusText);
+ test.assertEquals('132', networkRequest.responseHeaderValue('Content-Length'));
+ test.releaseControl();
+ }
+ }
+ };
+
TestSuite.prototype.waitForTestResultsInConsole = function() {
var messages = ConsoleModel.consoleModel.messages();
for (var i = 0; i < messages.length; ++i) {