From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Tue, 17 Aug 2021 22:42:42 -0700 Subject: feat: expose raw response headers from URLLoader With https://chromium-review.googlesource.com/c/chromium/src/+/2856099 unfiltered response headers are only available via trusted channel through //services/network/public/mojom/devtools_observer.mojom. https://github.com/electron/electron/pull/30503/commits/28f4da1582d046e96cb58f3cbb590503e89dfd0d was an attempt to use this interface but given the original response is signalled on a different interface via URLLoaderClient::OnReceiveResponse it is harder to sync these data from two different channels for a synchronous event emitted on the SimpleURLLoaderWrapper::OnResponseStarted. This patch does the minimal approach to add back the raw response headers, moving forward we should find a way in upstream to provide access to these headers for loader clients created on the browser process. diff --git a/services/network/public/cpp/resource_request.cc b/services/network/public/cpp/resource_request.cc index 4dd6f8a62e42c9442ba439240f45fffb43b4871e..6e6affff213b92e40aec0c0a1a4e6bba5a83421e 100644 --- a/services/network/public/cpp/resource_request.cc +++ b/services/network/public/cpp/resource_request.cc @@ -151,6 +151,7 @@ ResourceRequest::TrustedParams& ResourceRequest::TrustedParams::operator=( disable_secure_dns = other.disable_secure_dns; has_user_activation = other.has_user_activation; allow_cookies_from_browser = other.allow_cookies_from_browser; + report_raw_headers = other.report_raw_headers; cookie_observer = Clone(&const_cast&>( other.cookie_observer)); @@ -177,6 +178,7 @@ bool ResourceRequest::TrustedParams::EqualsForTesting( const TrustedParams& other) const { return isolation_info.IsEqualForTesting(other.isolation_info) && disable_secure_dns == other.disable_secure_dns && + report_raw_headers == other.report_raw_headers && has_user_activation == other.has_user_activation && allow_cookies_from_browser == other.allow_cookies_from_browser && client_security_state == other.client_security_state; diff --git a/services/network/public/cpp/resource_request.h b/services/network/public/cpp/resource_request.h index 461aa40ed0bfc35c59dbd002ed4c4ab3bc65b031..3f5a872b473f27e1af3e1861bbec6be6790cf526 100644 --- a/services/network/public/cpp/resource_request.h +++ b/services/network/public/cpp/resource_request.h @@ -70,6 +70,7 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ResourceRequest { bool disable_secure_dns = false; bool has_user_activation = false; bool allow_cookies_from_browser = false; + bool report_raw_headers = false; mojo::PendingRemote cookie_observer; mojo::PendingRemote trust_token_observer; mojo::PendingRemote diff --git a/services/network/public/cpp/url_request_mojom_traits.cc b/services/network/public/cpp/url_request_mojom_traits.cc index e08518981fd1bac068327eb122b96b52fbfe23c6..c6770e680e180a29bb1155267dbc56a0f5d3e125 100644 --- a/services/network/public/cpp/url_request_mojom_traits.cc +++ b/services/network/public/cpp/url_request_mojom_traits.cc @@ -93,6 +93,7 @@ bool StructTraitsdisable_secure_dns = data.disable_secure_dns(); out->has_user_activation = data.has_user_activation(); out->allow_cookies_from_browser = data.allow_cookies_from_browser(); + out->report_raw_headers = data.report_raw_headers(); out->cookie_observer = data.TakeCookieObserver< mojo::PendingRemote>(); out->trust_token_observer = data.TakeTrustTokenObserver< diff --git a/services/network/public/cpp/url_request_mojom_traits.h b/services/network/public/cpp/url_request_mojom_traits.h index c5f22e5010de7e359c92810b4eb229d5f37da415..eb6e9d643075689b93bee4828ee066bdec48be63 100644 --- a/services/network/public/cpp/url_request_mojom_traits.h +++ b/services/network/public/cpp/url_request_mojom_traits.h @@ -73,6 +73,10 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) const network::ResourceRequest::TrustedParams& trusted_params) { return trusted_params.allow_cookies_from_browser; } + static bool report_raw_headers( + const network::ResourceRequest::TrustedParams& trusted_params) { + return trusted_params.report_raw_headers; + } static mojo::PendingRemote cookie_observer( const network::ResourceRequest::TrustedParams& trusted_params) { diff --git a/services/network/public/mojom/url_request.mojom b/services/network/public/mojom/url_request.mojom index 627a3df2debbc2a66be14556641f29232820ccf7..2a6a6e23244d9e1bc1b1f63279766e61f3962180 100644 --- a/services/network/public/mojom/url_request.mojom +++ b/services/network/public/mojom/url_request.mojom @@ -74,6 +74,9 @@ struct TrustedUrlRequestParams { // FollowRedirect(). bool allow_cookies_from_browser; + // [Electron] Whether to provide unfiltered response headers. + bool report_raw_headers; + // Observer which should be notified when this URLRequest reads or writes // a cookie. If this is set to non-null, the observer passed to // URLLoaderFactory will be ignored. diff --git a/services/network/public/mojom/url_response_head.mojom b/services/network/public/mojom/url_response_head.mojom index 5803d57c1c85f219a1ee4675d1fc4bb0c5ee81d0..880d360cfd58f368eafbabd8c3abdb361dcfbc6f 100644 --- a/services/network/public/mojom/url_response_head.mojom +++ b/services/network/public/mojom/url_response_head.mojom @@ -12,6 +12,7 @@ import "services/network/public/mojom/encoded_body_length.mojom"; import "services/network/public/mojom/attribution.mojom"; import "services/network/public/mojom/fetch_api.mojom"; import "services/network/public/mojom/ip_address_space.mojom"; +import "services/network/public/mojom/http_raw_headers.mojom"; import "services/network/public/mojom/ip_endpoint.mojom"; import "services/network/public/mojom/load_timing_info.mojom"; import "services/network/public/mojom/network_param.mojom"; @@ -42,6 +43,9 @@ struct URLResponseHead { // The response headers or NULL if the URL type does not support headers. HttpResponseHeaders headers; + // Actual response headers, as obtained from the network stack. + array raw_response_headers; + // The mime type of the response. This may be a derived value. string mime_type; diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc index 89027aee8f1e704eb8a032bd3f1ad28369898575..0909f6e2a1fe6244ea590fd0f8261e2ecb064522 100644 --- a/services/network/url_loader.cc +++ b/services/network/url_loader.cc @@ -673,6 +673,7 @@ URLLoader::URLLoader( has_user_activation_ = request.trusted_params->has_user_activation; allow_cookies_from_browser_ = request.trusted_params->allow_cookies_from_browser; + report_raw_headers_ = request.trusted_params->report_raw_headers; } // Store any cookies passed from the browser process to later attach them to @@ -711,7 +712,7 @@ URLLoader::URLLoader( &URLLoader::IsSharedDictionaryReadAllowed, base::Unretained(this))); } - if (devtools_request_id()) { + if (devtools_request_id() || report_raw_headers_) { url_request_->SetResponseHeadersCallback(base::BindRepeating( &URLLoader::SetRawResponseHeaders, base::Unretained(this))); } @@ -1646,6 +1647,19 @@ void URLLoader::OnResponseStarted(net::URLRequest* url_request, int net_error) { } response_ = BuildResponseHead(); + if (raw_response_headers_ && report_raw_headers_) { + std::vector header_array; + size_t iterator = 0; + std::string name, value; + while (raw_response_headers_->EnumerateHeaderLines(&iterator, &name, &value)) { + network::mojom::HttpRawHeaderPairPtr pair = + network::mojom::HttpRawHeaderPair::New(); + pair->key = name; + pair->value = value; + header_array.push_back(std::move(pair)); + } + response_->raw_response_headers = std::move(header_array); + } DispatchOnRawResponse(); // Parse and remove the Trust Tokens response headers, if any are expected, diff --git a/services/network/url_loader.h b/services/network/url_loader.h index 97e1f35642fa5b2f8589220f3fbcaa3385c3726b..756b824df48bc361e3a9243c6a5ae1b9a1c03ef4 100644 --- a/services/network/url_loader.h +++ b/services/network/url_loader.h @@ -648,6 +648,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) URLLoader std::unique_ptr resource_scheduler_request_handle_; + // Whether client requested raw headers. + bool report_raw_headers_ = false; bool enable_reporting_raw_headers_ = false; bool seen_raw_request_headers_ = false; scoped_refptr raw_response_headers_;