diff options
Diffstat (limited to 'chromium/content/renderer/loader')
27 files changed, 683 insertions, 334 deletions
diff --git a/chromium/content/renderer/loader/child_url_loader_factory_bundle.cc b/chromium/content/renderer/loader/child_url_loader_factory_bundle.cc index feb92de61a6..32ddb9deabd 100644 --- a/chromium/content/renderer/loader/child_url_loader_factory_bundle.cc +++ b/chromium/content/renderer/loader/child_url_loader_factory_bundle.cc @@ -24,7 +24,13 @@ class URLLoaderRelay : public network::mojom::URLLoaderClient, client_sink_(std::move(client_sink)) {} // network::mojom::URLLoader implementation: - void FollowRedirect() override { loader_sink_->FollowRedirect(); } + void FollowRedirect(const base::Optional<net::HttpRequestHeaders>& + modified_request_headers) override { + DCHECK(!modified_request_headers.has_value()) + << "Redirect with modified headers was not supported yet. " + "crbug.com/845683"; + loader_sink_->FollowRedirect(base::nullopt); + } void ProceedWithResponse() override { loader_sink_->ProceedWithResponse(); } @@ -186,32 +192,12 @@ void ChildURLLoaderFactoryBundle::CreateLoaderAndStart( std::unique_ptr<network::SharedURLLoaderFactoryInfo> ChildURLLoaderFactoryBundle::Clone() { - InitDefaultBlobFactoryIfNecessary(); - InitDirectNetworkFactoryIfNecessary(); - - network::mojom::URLLoaderFactoryPtrInfo default_factory_info; - if (default_factory_) - default_factory_->Clone(mojo::MakeRequest(&default_factory_info)); - - std::map<std::string, network::mojom::URLLoaderFactoryPtrInfo> factories_info; - for (auto& factory : factories_) { - network::mojom::URLLoaderFactoryPtrInfo factory_info; - factory.second->Clone(mojo::MakeRequest(&factory_info)); - factories_info.emplace(factory.first, std::move(factory_info)); - } - - network::mojom::URLLoaderFactoryPtrInfo direct_network_factory_info; - if (direct_network_factory_) { - direct_network_factory_->Clone( - mojo::MakeRequest(&direct_network_factory_info)); - } - - // Currently there is no need to override subresources from workers, - // therefore |subresource_overrides| are not shared with the clones. + return CloneInternal(true /* include_default */); +} - return std::make_unique<ChildURLLoaderFactoryBundleInfo>( - std::move(default_factory_info), std::move(factories_info), - std::move(direct_network_factory_info)); +std::unique_ptr<network::SharedURLLoaderFactoryInfo> +ChildURLLoaderFactoryBundle::CloneWithoutDefaultFactory() { + return CloneInternal(false /* include_default */); } void ChildURLLoaderFactoryBundle::Update( @@ -260,6 +246,36 @@ void ChildURLLoaderFactoryBundle::InitDirectNetworkFactoryIfNecessary() { } } +std::unique_ptr<network::SharedURLLoaderFactoryInfo> +ChildURLLoaderFactoryBundle::CloneInternal(bool include_default) { + InitDefaultBlobFactoryIfNecessary(); + InitDirectNetworkFactoryIfNecessary(); + + network::mojom::URLLoaderFactoryPtrInfo default_factory_info; + if (include_default && default_factory_) + default_factory_->Clone(mojo::MakeRequest(&default_factory_info)); + + std::map<std::string, network::mojom::URLLoaderFactoryPtrInfo> factories_info; + for (auto& factory : factories_) { + network::mojom::URLLoaderFactoryPtrInfo factory_info; + factory.second->Clone(mojo::MakeRequest(&factory_info)); + factories_info.emplace(factory.first, std::move(factory_info)); + } + + network::mojom::URLLoaderFactoryPtrInfo direct_network_factory_info; + if (direct_network_factory_) { + direct_network_factory_->Clone( + mojo::MakeRequest(&direct_network_factory_info)); + } + + // Currently there is no need to override subresources from workers, + // therefore |subresource_overrides| are not shared with the clones. + + return std::make_unique<ChildURLLoaderFactoryBundleInfo>( + std::move(default_factory_info), std::move(factories_info), + std::move(direct_network_factory_info)); +} + std::unique_ptr<ChildURLLoaderFactoryBundleInfo> ChildURLLoaderFactoryBundle::PassInterface() { InitDefaultBlobFactoryIfNecessary(); diff --git a/chromium/content/renderer/loader/child_url_loader_factory_bundle.h b/chromium/content/renderer/loader/child_url_loader_factory_bundle.h index 922cca480bb..cb613cbc247 100644 --- a/chromium/content/renderer/loader/child_url_loader_factory_bundle.h +++ b/chromium/content/renderer/loader/child_url_loader_factory_bundle.h @@ -83,6 +83,11 @@ class CONTENT_EXPORT ChildURLLoaderFactoryBundle std::unique_ptr<network::SharedURLLoaderFactoryInfo> Clone() override; + // Returns an info that omits this bundle's default factory, if any. This is + // useful to make a clone that bypasses AppCache, for example. + std::unique_ptr<network::SharedURLLoaderFactoryInfo> + CloneWithoutDefaultFactory(); + std::unique_ptr<ChildURLLoaderFactoryBundleInfo> PassInterface(); void Update(std::unique_ptr<ChildURLLoaderFactoryBundleInfo> info, @@ -97,6 +102,8 @@ class CONTENT_EXPORT ChildURLLoaderFactoryBundle private: void InitDefaultBlobFactoryIfNecessary(); void InitDirectNetworkFactoryIfNecessary(); + std::unique_ptr<network::SharedURLLoaderFactoryInfo> CloneInternal( + bool include_default); PossiblyAssociatedFactoryGetterCallback direct_network_factory_getter_; PossiblyAssociatedURLLoaderFactoryPtr direct_network_factory_; diff --git a/chromium/content/renderer/loader/navigation_response_override_parameters.cc b/chromium/content/renderer/loader/navigation_response_override_parameters.cc new file mode 100644 index 00000000000..91be543f46c --- /dev/null +++ b/chromium/content/renderer/loader/navigation_response_override_parameters.cc @@ -0,0 +1,17 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/renderer/loader/navigation_response_override_parameters.h" + +#include "base/callback.h" + +namespace content { + +NavigationResponseOverrideParameters::NavigationResponseOverrideParameters() = + default; + +NavigationResponseOverrideParameters::~NavigationResponseOverrideParameters() = + default; + +} // namespace content diff --git a/chromium/content/renderer/loader/navigation_response_override_parameters.h b/chromium/content/renderer/loader/navigation_response_override_parameters.h new file mode 100644 index 00000000000..e9a9b7b1d22 --- /dev/null +++ b/chromium/content/renderer/loader/navigation_response_override_parameters.h @@ -0,0 +1,33 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_RENDERER_LOADER_NAVIGATION_RESPONSE_OVERRIDE_PARAMETERS_H_ +#define CONTENT_RENDERER_LOADER_NAVIGATION_RESPONSE_OVERRIDE_PARAMETERS_H_ + +#include <vector> + +#include "content/common/content_export.h" +#include "net/url_request/redirect_info.h" +#include "services/network/public/cpp/resource_response.h" +#include "services/network/public/mojom/url_loader.mojom.h" +#include "url/gurl.h" + +namespace content { + +// Used to override parameters of the navigation request. +struct CONTENT_EXPORT NavigationResponseOverrideParameters { + public: + NavigationResponseOverrideParameters(); + ~NavigationResponseOverrideParameters(); + + network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints; + network::ResourceResponseHead response; + std::vector<GURL> redirects; + std::vector<network::ResourceResponseHead> redirect_responses; + std::vector<net::RedirectInfo> redirect_infos; +}; + +} // namespace content + +#endif // CONTENT_RENDERER_LOADER_NAVIGATION_RESPONSE_OVERRIDE_PARAMETERS_H_ diff --git a/chromium/content/renderer/loader/request_extra_data.cc b/chromium/content/renderer/loader/request_extra_data.cc index 3b523978f38..de594517dd3 100644 --- a/chromium/content/renderer/loader/request_extra_data.cc +++ b/chromium/content/renderer/loader/request_extra_data.cc @@ -17,7 +17,6 @@ RequestExtraData::RequestExtraData() is_main_frame_(false), allow_download_(true), transition_type_(ui::PAGE_TRANSITION_LINK), - should_replace_current_entry_(false), service_worker_provider_id_(kInvalidServiceWorkerProviderId), originated_from_service_worker_(false), initiated_in_secure_context_(false), @@ -39,7 +38,6 @@ void RequestExtraData::CopyToResourceRequest( request->allow_download = allow_download_; request->transition_type = transition_type_; - request->should_replace_current_entry = should_replace_current_entry_; request->service_worker_provider_id = service_worker_provider_id_; request->originated_from_service_worker = originated_from_service_worker_; diff --git a/chromium/content/renderer/loader/request_extra_data.h b/chromium/content/renderer/loader/request_extra_data.h index 8d458507d5e..1c2f0bacdce 100644 --- a/chromium/content/renderer/loader/request_extra_data.h +++ b/chromium/content/renderer/loader/request_extra_data.h @@ -12,6 +12,7 @@ #include "content/common/content_export.h" #include "content/common/navigation_params.h" #include "content/public/common/url_loader_throttle.h" +#include "content/renderer/loader/navigation_response_override_parameters.h" #include "content/renderer/loader/web_url_loader_impl.h" #include "third_party/blink/public/mojom/page/page_visibility_state.mojom.h" #include "third_party/blink/public/platform/web_string.h" @@ -49,10 +50,6 @@ class CONTENT_EXPORT RequestExtraData : public blink::WebURLRequest::ExtraData { void set_transition_type(ui::PageTransition transition_type) { transition_type_ = transition_type; } - void set_should_replace_current_entry( - bool should_replace_current_entry) { - should_replace_current_entry_ = should_replace_current_entry; - } int service_worker_provider_id() const { return service_worker_provider_id_; } @@ -82,20 +79,20 @@ class CONTENT_EXPORT RequestExtraData : public blink::WebURLRequest::ExtraData { requested_with_ = requested_with; } - // PlzNavigate: |stream_override| is used to override certain parameters of - // navigation requests. - std::unique_ptr<StreamOverrideParameters> TakeStreamOverrideOwnership() { - return std::move(stream_override_); + // PlzNavigate: |navigation_response_override| is used to override certain + // parameters of navigation requests. + std::unique_ptr<NavigationResponseOverrideParameters> + TakeNavigationResponseOverrideOwnership() { + return std::move(navigation_response_override_); } - void set_stream_override( - std::unique_ptr<StreamOverrideParameters> stream_override) { - stream_override_ = std::move(stream_override); + void set_navigation_response_override( + std::unique_ptr<NavigationResponseOverrideParameters> response_override) { + navigation_response_override_ = std::move(response_override); } - // NavigationMojoResponse: |continue_navigation| is used to continue a - // navigation on the renderer process that has already been started on the - // browser process. + // |continue_navigation| is used to continue a navigation on the renderer + // process that has already been started on the browser process. base::OnceClosure TakeContinueNavigationFunctionOwnerShip() { return std::move(continue_navigation_function_); } @@ -163,14 +160,14 @@ class CONTENT_EXPORT RequestExtraData : public blink::WebURLRequest::ExtraData { bool is_main_frame_; bool allow_download_; ui::PageTransition transition_type_; - bool should_replace_current_entry_; int service_worker_provider_id_; bool originated_from_service_worker_; blink::WebString custom_user_agent_; blink::WebString requested_with_; - std::unique_ptr<StreamOverrideParameters> stream_override_; - // TODO(arthursonzogni): Once NavigationMojoResponse is launched, move most of - // the |stream_override_| content as parameters of this function. + std::unique_ptr<NavigationResponseOverrideParameters> + navigation_response_override_; + // TODO(arthursonzogni): Move most of the |navigation_response_override_| + // content as parameters of this function. base::OnceClosure continue_navigation_function_; bool initiated_in_secure_context_; bool is_for_no_state_prefetch_; diff --git a/chromium/content/renderer/loader/resource_dispatcher.cc b/chromium/content/renderer/loader/resource_dispatcher.cc index 8764f8e026f..f3f906a3c5a 100644 --- a/chromium/content/renderer/loader/resource_dispatcher.cc +++ b/chromium/content/renderer/loader/resource_dispatcher.cc @@ -14,7 +14,6 @@ #include "base/debug/alias.h" #include "base/debug/stack_trace.h" #include "base/files/file_path.h" -#include "base/message_loop/message_loop.h" #include "base/metrics/histogram_macros.h" #include "base/rand_util.h" #include "base/strings/string_util.h" @@ -24,6 +23,7 @@ #include "content/common/inter_process_time_ticks_converter.h" #include "content/common/navigation_params.h" #include "content/common/throttling_url_loader.h" +#include "content/public/common/browser_side_navigation_policy.h" #include "content/public/common/resource_load_info.mojom.h" #include "content/public/common/resource_type.h" #include "content/public/renderer/fixed_received_data.h" @@ -119,6 +119,20 @@ void NotifyResourceLoadComplete( std::move(resource_load_info)); } +// Returns true if the headers indicate that this resource should always be +// revalidated or not cached. +bool AlwaysAccessNetwork( + const scoped_refptr<net::HttpResponseHeaders>& headers) { + if (!headers) + return false; + + // RFC 2616, section 14.9. + return headers->HasHeaderValue("cache-control", "no-cache") || + headers->HasHeaderValue("cache-control", "no-store") || + headers->HasHeaderValue("pragma", "no-cache") || + headers->HasHeaderValue("vary", "*"); +} + int GetInitialRequestID() { // Starting with a random number speculatively avoids RDH_INVALID_REQUEST_ID // which are assumed to have been caused by restarting RequestID at 0 when @@ -172,13 +186,35 @@ void ResourceDispatcher::OnUploadProgress(int request_id, void ResourceDispatcher::OnReceivedResponse( int request_id, - const network::ResourceResponseHead& response_head) { + const network::ResourceResponseHead& initial_response_head) { TRACE_EVENT0("loader", "ResourceDispatcher::OnReceivedResponse"); PendingRequestInfo* request_info = GetPendingRequestInfo(request_id); if (!request_info) return; - request_info->response_start = base::TimeTicks::Now(); + request_info->local_response_start = base::TimeTicks::Now(); + request_info->remote_request_start = + initial_response_head.load_timing.request_start; + // Now that response_start has been set, we can properly set the TimeTicks in + // the ResourceResponseInfo. + network::ResourceResponseInfo renderer_response_info; + ToResourceResponseInfo(*request_info, initial_response_head, + &renderer_response_info); + request_info->load_timing_info = renderer_response_info.load_timing; + + network::ResourceResponseHead response_head; + std::unique_ptr<NavigationResponseOverrideParameters> response_override = + std::move(request_info->navigation_response_override); + if (response_override) { + CHECK(IsBrowserSideNavigationEnabled()); + response_head = response_override->response; + } else { + response_head = initial_response_head; + } + request_info->mime_type = response_head.mime_type; + request_info->network_accessed = response_head.network_accessed; + request_info->always_access_network = + AlwaysAccessNetwork(response_head.headers); if (delegate_) { std::unique_ptr<RequestPeer> new_peer = delegate_->OnReceivedResponse( std::move(request_info->peer), response_head.mime_type, @@ -186,14 +222,7 @@ void ResourceDispatcher::OnReceivedResponse( DCHECK(new_peer); request_info->peer = std::move(new_peer); } - - if (!response_head.socket_address.host().empty()) { - ignore_result(request_info->parsed_ip.AssignFromIPLiteral( - response_head.socket_address.host())); - } - - request_info->mime_type = response_head.mime_type; - request_info->network_accessed = response_head.network_accessed; + request_info->host_port_pair = renderer_response_info.socket_address; if (!IsResourceTypeFrame(request_info->resource_type)) { NotifySubresourceStarted(RenderThreadImpl::DeprecatedGetMainTaskRunner(), request_info->render_frame_id, @@ -201,8 +230,6 @@ void ResourceDispatcher::OnReceivedResponse( response_head.cert_status); } - network::ResourceResponseInfo renderer_response_info; - ToResourceResponseInfo(*request_info, response_head, &renderer_response_info); request_info->peer->OnReceivedResponse(renderer_response_info); } @@ -248,7 +275,8 @@ void ResourceDispatcher::OnReceivedRedirect( PendingRequestInfo* request_info = GetPendingRequestInfo(request_id); if (!request_info) return; - request_info->response_start = base::TimeTicks::Now(); + request_info->local_response_start = base::TimeTicks::Now(); + request_info->remote_request_start = response_head.load_timing.request_start; network::ResourceResponseInfo renderer_response_info; ToResourceResponseInfo(*request_info, response_head, &renderer_response_info); @@ -264,9 +292,19 @@ void ResourceDispatcher::OnReceivedRedirect( request_info->response_method = redirect_info.new_method; request_info->response_referrer = GURL(redirect_info.new_referrer); request_info->has_pending_redirect = true; - if (!request_info->is_deferred) { + mojom::RedirectInfoPtr net_redirect_info = mojom::RedirectInfo::New(); + net_redirect_info->url = redirect_info.new_url; + net_redirect_info->network_info = mojom::CommonNetworkInfo::New(); + net_redirect_info->network_info->network_accessed = + response_head.network_accessed; + net_redirect_info->network_info->always_access_network = + AlwaysAccessNetwork(response_head.headers); + net_redirect_info->network_info->ip_port_pair = + response_head.socket_address; + request_info->redirect_info_chain.push_back(std::move(net_redirect_info)); + + if (!request_info->is_deferred) FollowPendingRedirect(request_info); - } } else { Cancel(request_id, std::move(task_runner)); } @@ -274,8 +312,11 @@ void ResourceDispatcher::OnReceivedRedirect( void ResourceDispatcher::FollowPendingRedirect( PendingRequestInfo* request_info) { - if (request_info->has_pending_redirect) { + if (request_info->has_pending_redirect && + request_info->should_follow_redirect) { request_info->has_pending_redirect = false; + // net::URLRequest clears its request_start on redirect, so should we. + request_info->local_request_start = base::TimeTicks::Now(); request_info->url_loader->FollowRedirect(); } } @@ -288,7 +329,6 @@ void ResourceDispatcher::OnRequestComplete( PendingRequestInfo* request_info = GetPendingRequestInfo(request_id); if (!request_info) return; - request_info->completion_time = base::TimeTicks::Now(); request_info->buffer.reset(); request_info->buffer_size = 0; @@ -299,13 +339,21 @@ void ResourceDispatcher::OnRequestComplete( resource_load_info->method = request_info->response_method; resource_load_info->resource_type = request_info->resource_type; resource_load_info->request_id = request_id; - if (request_info->parsed_ip.IsValid()) - resource_load_info->ip = request_info->parsed_ip; resource_load_info->mime_type = request_info->mime_type; - resource_load_info->network_accessed = request_info->network_accessed; + resource_load_info->network_info = mojom::CommonNetworkInfo::New(); + resource_load_info->network_info->network_accessed = + request_info->network_accessed; + resource_load_info->network_info->always_access_network = + request_info->always_access_network; + resource_load_info->network_info->ip_port_pair = request_info->host_port_pair; + resource_load_info->load_timing_info = request_info->load_timing_info; resource_load_info->was_cached = status.exists_in_cache; resource_load_info->net_error = status.error_code; - resource_load_info->request_start = request_info->request_start; + resource_load_info->redirect_info_chain = + std::move(request_info->redirect_info_chain); + resource_load_info->total_received_bytes = status.encoded_data_length; + resource_load_info->raw_body_bytes = status.encoded_body_length; + NotifyResourceLoadComplete(RenderThreadImpl::DeprecatedGetMainTaskRunner(), request_info->render_frame_id, std::move(resource_load_info)); @@ -320,15 +368,34 @@ void ResourceDispatcher::OnRequestComplete( request_info->peer = std::move(new_peer); } + network::URLLoaderCompletionStatus renderer_status(status); + if (status.completion_time.is_null()) { + // No completion timestamp is provided, leave it as is. + } else if (request_info->remote_request_start.is_null() || + request_info->load_timing_info.request_start.is_null()) { + // We cannot convert the remote time to a local time, let's use the current + // timestamp. This happens when + // - We get an error before OnReceivedRedirect or OnReceivedResponse is + // called, or + // - Somehow such a timestamp was missing in the LoadTimingInfo. + renderer_status.completion_time = base::TimeTicks::Now(); + } else { + // We have already converted the request start timestamp, let's use that + // conversion information. + // Note: We cannot create a InterProcessTimeTicksConverter with + // (local_request_start, now, remote_request_start, remote_completion_time) + // as that may result in inconsistent timestamps. + renderer_status.completion_time = + std::min(status.completion_time - request_info->remote_request_start + + request_info->load_timing_info.request_start, + base::TimeTicks::Now()); + } // The request ID will be removed from our pending list in the destructor. // Normally, dispatching this message causes the reference-counted request to // die immediately. // TODO(kinuko): Revisit here. This probably needs to call request_info->peer // but the past attempt to change it seems to have caused crashes. // (crbug.com/547047) - network::URLLoaderCompletionStatus renderer_status(status); - renderer_status.completion_time = - ToRendererCompletionTime(*request_info, status.completion_time); peer->OnCompletedRequest(renderer_status); } @@ -427,7 +494,9 @@ ResourceDispatcher::PendingRequestInfo::PendingRequestInfo( const GURL& request_url, const std::string& method, const GURL& referrer, - bool download_to_file) + bool download_to_file, + std::unique_ptr<NavigationResponseOverrideParameters> + navigation_response_override_params) : peer(std::move(peer)), resource_type(resource_type), render_frame_id(render_frame_id), @@ -436,7 +505,10 @@ ResourceDispatcher::PendingRequestInfo::PendingRequestInfo( response_method(method), response_referrer(referrer), download_to_file(download_to_file), - request_start(base::TimeTicks::Now()) {} + local_request_start(base::TimeTicks::Now()), + buffer_size(0), + navigation_response_override( + std::move(navigation_response_override_params)) {} ResourceDispatcher::PendingRequestInfo::~PendingRequestInfo() { } @@ -449,12 +521,13 @@ void ResourceDispatcher::StartSync( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, std::vector<std::unique_ptr<URLLoaderThrottle>> throttles, double timeout, - blink::mojom::BlobRegistryPtrInfo download_to_blob_registry) { + blink::mojom::BlobRegistryPtrInfo download_to_blob_registry, + std::unique_ptr<RequestPeer> peer) { CheckSchemeForReferrerPolicy(*request); std::unique_ptr<network::SharedURLLoaderFactoryInfo> factory_info = url_loader_factory->Clone(); - base::WaitableEvent completed_event( + base::WaitableEvent redirect_or_response_event( base::WaitableEvent::ResetPolicy::MANUAL, base::WaitableEvent::InitialState::NOT_SIGNALED); @@ -474,10 +547,32 @@ void ResourceDispatcher::StartSync( std::move(request), routing_id, task_runner, traffic_annotation, std::move(factory_info), std::move(throttles), base::Unretained(response), - base::Unretained(&completed_event), + base::Unretained(&redirect_or_response_event), base::Unretained(terminate_sync_load_event_), timeout, std::move(download_to_blob_registry))); - completed_event.Wait(); + + // redirect_or_response_event will signal when each redirect completes, and + // when the final response is complete. + redirect_or_response_event.Wait(); + + while (response->context_for_redirect) { + DCHECK(response->redirect_info); + bool follow_redirect = + peer->OnReceivedRedirect(*response->redirect_info, response->info); + redirect_or_response_event.Reset(); + if (follow_redirect) { + task_runner->PostTask( + FROM_HERE, + base::BindOnce(&SyncLoadContext::FollowRedirect, + base::Unretained(response->context_for_redirect))); + } else { + task_runner->PostTask( + FROM_HERE, + base::BindOnce(&SyncLoadContext::CancelRedirect, + base::Unretained(response->context_for_redirect))); + } + redirect_or_response_event.Wait(); + } } int ResourceDispatcher::StartAsync( @@ -490,27 +585,32 @@ int ResourceDispatcher::StartAsync( std::unique_ptr<RequestPeer> peer, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, std::vector<std::unique_ptr<URLLoaderThrottle>> throttles, - network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints, + std::unique_ptr<NavigationResponseOverrideParameters> + response_override_params, base::OnceClosure* continue_navigation_function) { CheckSchemeForReferrerPolicy(*request); + bool override_url_loader = + !!response_override_params && + !!response_override_params->url_loader_client_endpoints; + // Compute a unique request_id for this renderer process. int request_id = MakeRequestID(); pending_requests_[request_id] = std::make_unique<PendingRequestInfo>( std::move(peer), static_cast<ResourceType>(request->resource_type), request->render_frame_id, request->url, request->method, - request->referrer, request->download_to_file); + request->referrer, request->download_to_file, + std::move(response_override_params)); - if (url_loader_client_endpoints) { + if (override_url_loader) { pending_requests_[request_id]->url_loader_client = std::make_unique<URLLoaderClientImpl>(request_id, this, loading_task_runner); DCHECK(continue_navigation_function); - *continue_navigation_function = base::BindOnce( - &ResourceDispatcher::ContinueForNavigation, weak_factory_.GetWeakPtr(), - request_id, std::move(url_loader_client_endpoints)); - + *continue_navigation_function = + base::BindOnce(&ResourceDispatcher::ContinueForNavigation, + weak_factory_.GetWeakPtr(), request_id); return request_id; } @@ -550,16 +650,16 @@ void ResourceDispatcher::ToResourceResponseInfo( network::ResourceResponseInfo* renderer_info) const { *renderer_info = browser_info; if (base::TimeTicks::IsConsistentAcrossProcesses() || - request_info.request_start.is_null() || - request_info.response_start.is_null() || + request_info.local_request_start.is_null() || + request_info.local_response_start.is_null() || browser_info.request_start.is_null() || browser_info.response_start.is_null() || browser_info.load_timing.request_start.is_null()) { return; } InterProcessTimeTicksConverter converter( - LocalTimeTicks::FromTimeTicks(request_info.request_start), - LocalTimeTicks::FromTimeTicks(request_info.response_start), + LocalTimeTicks::FromTimeTicks(request_info.local_request_start), + LocalTimeTicks::FromTimeTicks(request_info.local_response_start), RemoteTimeTicks::FromTimeTicks(browser_info.request_start), RemoteTimeTicks::FromTimeTicks(browser_info.response_start)); @@ -582,46 +682,42 @@ void ResourceDispatcher::ToResourceResponseInfo( RemoteToLocalTimeTicks(converter, &renderer_info->service_worker_ready_time); } -base::TimeTicks ResourceDispatcher::ToRendererCompletionTime( - const PendingRequestInfo& request_info, - const base::TimeTicks& browser_completion_time) const { - if (request_info.completion_time.is_null()) { - return browser_completion_time; - } - - // TODO(simonjam): The optimal lower bound should be the most recent value of - // TimeTicks::Now() returned to WebKit. Is it worth trying to cache that? - // Until then, |response_start| is used as it is the most recent value - // returned for this request. - int64_t result = std::max(browser_completion_time.ToInternalValue(), - request_info.response_start.ToInternalValue()); - result = std::min(result, request_info.completion_time.ToInternalValue()); - return base::TimeTicks::FromInternalValue(result); -} - -void ResourceDispatcher::ContinueForNavigation( - int request_id, - network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints) { - DCHECK(url_loader_client_endpoints); +void ResourceDispatcher::ContinueForNavigation(int request_id) { PendingRequestInfo* request_info = GetPendingRequestInfo(request_id); if (!request_info) return; + std::unique_ptr<NavigationResponseOverrideParameters> response_override = + std::move(request_info->navigation_response_override); + DCHECK(response_override); + + // Mark the request so we do not attempt to follow the redirects, they already + // happened. + request_info->should_follow_redirect = false; + URLLoaderClientImpl* client_ptr = request_info->url_loader_client.get(); + // PlzNavigate: during navigations, the ResourceResponse has already been + // received on the browser side, and has been passed down to the renderer. + // Replay the redirects that happened during navigation. + DCHECK_EQ(response_override->redirect_responses.size(), + response_override->redirect_infos.size()); + for (size_t i = 0; i < response_override->redirect_responses.size(); ++i) { + client_ptr->OnReceiveRedirect(response_override->redirect_infos[i], + response_override->redirect_responses[i]); + // The request might have been cancelled while processing the redirect. + if (!GetPendingRequestInfo(request_id)) + return; + } - // Short circuiting call to OnReceivedResponse to immediately start - // the request. ResourceResponseHead can be empty here because we - // pull the StreamOverride's one in - // WebURLLoaderImpl::Context::OnReceivedResponse. - client_ptr->OnReceiveResponse(network::ResourceResponseHead(), + client_ptr->OnReceiveResponse(response_override->response, network::mojom::DownloadedTempFilePtr()); - // TODO(clamy): Move the replaying of redirects from WebURLLoaderImpl here. // Abort if the request is cancelled. if (!GetPendingRequestInfo(request_id)) return; - client_ptr->Bind(std::move(url_loader_client_endpoints)); + DCHECK(response_override->url_loader_client_endpoints); + client_ptr->Bind(std::move(response_override->url_loader_client_endpoints)); } } // namespace content diff --git a/chromium/content/renderer/loader/resource_dispatcher.h b/chromium/content/renderer/loader/resource_dispatcher.h index af1364a8799..609aaef3f2a 100644 --- a/chromium/content/renderer/loader/resource_dispatcher.h +++ b/chromium/content/renderer/loader/resource_dispatcher.h @@ -12,6 +12,7 @@ #include <map> #include <memory> #include <string> +#include <vector> #include "base/containers/circular_deque.h" #include "base/containers/hash_tables.h" @@ -22,9 +23,11 @@ #include "base/single_thread_task_runner.h" #include "base/time/time.h" #include "content/common/content_export.h" +#include "content/public/common/resource_load_info.mojom.h" #include "content/public/common/resource_type.h" #include "content/public/common/url_loader_throttle.h" #include "mojo/public/cpp/system/data_pipe.h" +#include "net/base/host_port_pair.h" #include "net/base/request_priority.h" #include "net/traffic_annotation/network_traffic_annotation.h" #include "services/network/public/cpp/shared_url_loader_factory.h" @@ -52,6 +55,7 @@ class URLLoaderFactory; } namespace content { +struct NavigationResponseOverrideParameters; class RequestPeer; class ResourceDispatcherDelegate; struct SyncLoadResponse; @@ -96,7 +100,8 @@ class CONTENT_EXPORT ResourceDispatcher { scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, std::vector<std::unique_ptr<URLLoaderThrottle>> throttles, double timeout, - blink::mojom::BlobRegistryPtrInfo download_to_blob_registry); + blink::mojom::BlobRegistryPtrInfo download_to_blob_registry, + std::unique_ptr<RequestPeer> peer); // Call this method to initiate the request. If this method succeeds, then // the peer's methods will be called asynchronously to report various events. @@ -122,7 +127,8 @@ class CONTENT_EXPORT ResourceDispatcher { std::unique_ptr<RequestPeer> peer, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, std::vector<std::unique_ptr<URLLoaderThrottle>> throttles, - network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints, + std::unique_ptr<NavigationResponseOverrideParameters> + response_override_params, base::OnceClosure* continue_navigation_function); network::mojom::DownloadedTempFilePtr TakeDownloadedTempFile(int request_id); @@ -179,7 +185,9 @@ class CONTENT_EXPORT ResourceDispatcher { const GURL& request_url, const std::string& method, const GURL& referrer, - bool download_to_file); + bool download_to_file, + std::unique_ptr<NavigationResponseOverrideParameters> + response_override_params); ~PendingRequestInfo(); @@ -196,14 +204,21 @@ class CONTENT_EXPORT ResourceDispatcher { GURL response_referrer; bool download_to_file; bool has_pending_redirect = false; - base::TimeTicks request_start; - base::TimeTicks response_start; - base::TimeTicks completion_time; + base::TimeTicks local_request_start; + base::TimeTicks local_response_start; + base::TimeTicks remote_request_start; + net::LoadTimingInfo load_timing_info; linked_ptr<base::SharedMemory> buffer; int buffer_size; - net::IPAddress parsed_ip; + net::HostPortPair host_port_pair; bool network_accessed = false; std::string mime_type; + std::unique_ptr<NavigationResponseOverrideParameters> + navigation_response_override; + bool should_follow_redirect = true; + bool always_access_network = false; + + std::vector<content::mojom::RedirectInfoPtr> redirect_info_chain; // For mojo loading. std::unique_ptr<ThrottlingURLLoader> url_loader; @@ -239,13 +254,7 @@ class CONTENT_EXPORT ResourceDispatcher { const network::ResourceResponseHead& browser_info, network::ResourceResponseInfo* renderer_info) const; - base::TimeTicks ToRendererCompletionTime( - const PendingRequestInfo& request_info, - const base::TimeTicks& browser_completion_time) const; - - void ContinueForNavigation( - int request_id, - network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints); + void ContinueForNavigation(int request_id); // All pending requests issued to the host PendingRequestMap pending_requests_; diff --git a/chromium/content/renderer/loader/resource_dispatcher_unittest.cc b/chromium/content/renderer/loader/resource_dispatcher_unittest.cc index 32b18cfc520..9d89c8b0198 100644 --- a/chromium/content/renderer/loader/resource_dispatcher_unittest.cc +++ b/chromium/content/renderer/loader/resource_dispatcher_unittest.cc @@ -21,10 +21,10 @@ #include "base/test/scoped_feature_list.h" #include "content/common/appcache_interfaces.h" #include "content/public/common/content_features.h" -#include "content/public/common/weak_wrapper_shared_url_loader_factory.h" #include "content/public/renderer/fixed_received_data.h" #include "content/public/renderer/request_peer.h" #include "content/public/renderer/resource_dispatcher_delegate.h" +#include "content/renderer/loader/navigation_response_override_parameters.h" #include "content/renderer/loader/request_extra_data.h" #include "content/renderer/loader/test_request_peer.h" #include "net/base/net_errors.h" @@ -34,6 +34,7 @@ #include "services/network/public/cpp/resource_request.h" #include "services/network/public/cpp/resource_response.h" #include "services/network/public/cpp/url_loader_completion_status.h" +#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" #include "services/network/public/mojom/request_context_frame_type.mojom.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h" @@ -117,9 +118,9 @@ class ResourceDispatcherTest : public testing::Test, std::move(request), 0, blink::scheduler::GetSingleThreadTaskRunnerForTesting(), TRAFFIC_ANNOTATION_FOR_TESTS, false, false, std::move(peer), - base::MakeRefCounted<WeakWrapperSharedURLLoaderFactory>(this), + base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(this), std::vector<std::unique_ptr<URLLoaderThrottle>>(), - network::mojom::URLLoaderClientEndpointsPtr(), + nullptr /* navigation_response_override_params */, nullptr /* continue_navigation_function */); peer_context->request_id = request_id; return request_id; @@ -377,4 +378,85 @@ TEST_F(TimeConversionTest, NotInitialized) { response_info().load_timing.connect_timing.dns_start); } +class CompletionTimeConversionTest : public ResourceDispatcherTest { + public: + void PerformTest(base::TimeTicks remote_request_start, + base::TimeTicks completion_time, + base::TimeDelta delay) { + std::unique_ptr<network::ResourceRequest> request(CreateResourceRequest()); + StartAsync(std::move(request), nullptr, &peer_context_); + + ASSERT_EQ(1u, loader_and_clients_.size()); + auto client = std::move(loader_and_clients_[0].second); + network::ResourceResponseHead response_head; + response_head.request_start = remote_request_start; + response_head.load_timing.request_start = remote_request_start; + response_head.load_timing.receive_headers_end = remote_request_start; + // We need to put somthing non-null time, otherwise no values will be + // copied. + response_head.load_timing.request_start_time = + base::Time() + base::TimeDelta::FromSeconds(99); + client->OnReceiveResponse(response_head, {}); + + network::URLLoaderCompletionStatus status; + status.completion_time = completion_time; + + client->OnComplete(status); + + const base::TimeTicks until = base::TimeTicks::Now() + delay; + while (base::TimeTicks::Now() < until) + base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1)); + base::RunLoop().RunUntilIdle(); + loader_and_clients_.clear(); + } + + base::TimeTicks request_start() const { + EXPECT_TRUE(peer_context_.received_response); + return peer_context_.last_load_timing.request_start; + } + base::TimeTicks completion_time() const { + EXPECT_TRUE(peer_context_.complete); + return peer_context_.completion_status.completion_time; + } + + private: + TestRequestPeer::Context peer_context_; +}; + +TEST_F(CompletionTimeConversionTest, NullCompletionTimestamp) { + const auto remote_request_start = + base::TimeTicks() + base::TimeDelta::FromMilliseconds(4); + + PerformTest(remote_request_start, base::TimeTicks(), base::TimeDelta()); + + EXPECT_EQ(base::TimeTicks(), completion_time()); +} + +TEST_F(CompletionTimeConversionTest, RemoteRequestStartIsUnavailable) { + base::TimeTicks begin = base::TimeTicks::Now(); + + const auto remote_completion_time = + base::TimeTicks() + base::TimeDelta::FromMilliseconds(8); + + PerformTest(base::TimeTicks(), remote_completion_time, base::TimeDelta()); + + base::TimeTicks end = base::TimeTicks::Now(); + EXPECT_LE(begin, completion_time()); + EXPECT_LE(completion_time(), end); +} + +TEST_F(CompletionTimeConversionTest, Convert) { + const auto remote_request_start = + base::TimeTicks() + base::TimeDelta::FromMilliseconds(4); + + const auto remote_completion_time = + remote_request_start + base::TimeDelta::FromMilliseconds(3); + + PerformTest(remote_request_start, remote_completion_time, + base::TimeDelta::FromMilliseconds(15)); + + EXPECT_EQ(completion_time(), + request_start() + base::TimeDelta::FromMilliseconds(3)); +} + } // namespace content diff --git a/chromium/content/renderer/loader/shared_memory_data_consumer_handle.cc b/chromium/content/renderer/loader/shared_memory_data_consumer_handle.cc index 2551ead92fa..f302985c610 100644 --- a/chromium/content/renderer/loader/shared_memory_data_consumer_handle.cc +++ b/chromium/content/renderer/loader/shared_memory_data_consumer_handle.cc @@ -11,7 +11,6 @@ #include "base/containers/circular_deque.h" #include "base/macros.h" #include "base/memory/ptr_util.h" -#include "base/message_loop/message_loop.h" #include "base/single_thread_task_runner.h" #include "base/synchronization/lock.h" #include "base/threading/thread_task_runner_handle.h" diff --git a/chromium/content/renderer/loader/sync_load_context.cc b/chromium/content/renderer/loader/sync_load_context.cc index fc94a225897..17da79d30b5 100644 --- a/chromium/content/renderer/loader/sync_load_context.cc +++ b/chromium/content/renderer/loader/sync_load_context.cc @@ -9,6 +9,7 @@ #include "base/logging.h" #include "base/synchronization/waitable_event.h" #include "content/public/common/url_loader_throttle.h" +#include "content/renderer/loader/navigation_response_override_parameters.h" #include "content/renderer/loader/sync_load_response.h" #include "net/url_request/redirect_info.h" #include "services/network/public/cpp/resource_request.h" @@ -16,6 +17,59 @@ namespace content { +// An inner helper class to manage the SyncLoadContext's events and timeouts, +// so that we can stop or resumse all of them at once. +class SyncLoadContext::SignalHelper final { + public: + SignalHelper(SyncLoadContext* context, + base::WaitableEvent* redirect_or_response_event, + base::WaitableEvent* abort_event, + double timeout) + : context_(context), + redirect_or_response_event_(redirect_or_response_event), + abort_event_(abort_event) { + Start(base::TimeDelta::FromSecondsD(timeout)); + } + + void SignalRedirectOrResponseComplete() { + abort_watcher_.StopWatching(); + timeout_timer_.AbandonAndStop(); + redirect_or_response_event_->Signal(); + } + + bool RestartAfterRedirect() { + if (abort_event_ && abort_event_->IsSignaled()) + return false; + base::TimeDelta timeout_remainder = + timeout_timer_.desired_run_time() - base::TimeTicks::Now(); + if (timeout_remainder <= base::TimeDelta()) + return false; + Start(timeout_remainder); + return true; + } + + private: + void Start(const base::TimeDelta& timeout) { + DCHECK(!redirect_or_response_event_->IsSignaled()); + if (abort_event_) { + abort_watcher_.StartWatching( + abort_event_, + base::BindOnce(&SyncLoadContext::OnAbort, base::Unretained(context_)), + context_->task_runner_); + } + if (timeout > base::TimeDelta()) { + timeout_timer_.Start(FROM_HERE, timeout, context_, + &SyncLoadContext::OnTimeout); + } + } + + SyncLoadContext* context_; + base::WaitableEvent* redirect_or_response_event_; + base::WaitableEvent* abort_event_; + base::WaitableEventWatcher abort_watcher_; + base::OneShotTimer timeout_timer_; +}; + // static void SyncLoadContext::StartAsyncWithWaitableEvent( std::unique_ptr<network::ResourceRequest> request, @@ -26,21 +80,21 @@ void SyncLoadContext::StartAsyncWithWaitableEvent( url_loader_factory_info, std::vector<std::unique_ptr<URLLoaderThrottle>> throttles, SyncLoadResponse* response, - base::WaitableEvent* completed_event, + base::WaitableEvent* redirect_or_response_event, base::WaitableEvent* abort_event, double timeout, blink::mojom::BlobRegistryPtrInfo download_to_blob_registry) { bool download_to_blob = download_to_blob_registry.is_valid(); auto* context = new SyncLoadContext( request.get(), std::move(url_loader_factory_info), response, - completed_event, abort_event, timeout, + redirect_or_response_event, abort_event, timeout, std::move(download_to_blob_registry), loading_task_runner); context->request_id_ = context->resource_dispatcher_->StartAsync( std::move(request), routing_id, std::move(loading_task_runner), traffic_annotation, true /* is_sync */, download_to_blob /* pass_response_pipe_to_peer */, base::WrapUnique(context), context->url_loader_factory_, - std::move(throttles), network::mojom::URLLoaderClientEndpointsPtr(), + std::move(throttles), nullptr /* navigation_response_override_params */, nullptr /* continue_for_navigation */); } @@ -48,27 +102,21 @@ SyncLoadContext::SyncLoadContext( network::ResourceRequest* request, std::unique_ptr<network::SharedURLLoaderFactoryInfo> url_loader_factory, SyncLoadResponse* response, - base::WaitableEvent* completed_event, + base::WaitableEvent* redirect_or_response_event, base::WaitableEvent* abort_event, double timeout, blink::mojom::BlobRegistryPtrInfo download_to_blob_registry, scoped_refptr<base::SingleThreadTaskRunner> task_runner) : response_(response), - completed_event_(completed_event), download_to_blob_registry_(std::move(download_to_blob_registry)), - task_runner_(std::move(task_runner)) { + task_runner_(std::move(task_runner)), + signals_(std::make_unique<SignalHelper>(this, + redirect_or_response_event, + abort_event, + timeout)), + fetch_request_mode_(request->fetch_request_mode) { url_loader_factory_ = network::SharedURLLoaderFactory::Create(std::move(url_loader_factory)); - if (abort_event) { - abort_watcher_.StartWatching( - abort_event, - base::BindOnce(&SyncLoadContext::OnAbort, base::Unretained(this)), - task_runner_); - } - if (timeout) { - timeout_timer_.Start(FROM_HERE, base::TimeDelta::FromSecondsD(timeout), - this, &SyncLoadContext::OnTimeout); - } // Constructs a new ResourceDispatcher specifically for this request. resource_dispatcher_ = std::make_unique<ResourceDispatcher>(); @@ -86,7 +134,13 @@ bool SyncLoadContext::OnReceivedRedirect( const net::RedirectInfo& redirect_info, const network::ResourceResponseInfo& info) { DCHECK(!Completed()); - if (redirect_info.new_url.GetOrigin() != response_->url.GetOrigin()) { + // Synchronous loads in blink aren't associated with a ResourceClient, and + // CORS checks are performed by ResourceClient subclasses, so there's + // currently no way to perform CORS checks for redirects. + // Err on the side of extreme caution and block any cross origin redirect + // that might have CORS implications. + if (fetch_request_mode_ != network::mojom::FetchRequestMode::kNoCORS && + redirect_info.new_url.GetOrigin() != response_->url.GetOrigin()) { LOG(ERROR) << "Cross origin redirect denied"; response_->error_code = net::ERR_ABORTED; @@ -98,9 +152,33 @@ bool SyncLoadContext::OnReceivedRedirect( } response_->url = redirect_info.new_url; + response_->info = info; + response_->redirect_info = redirect_info; + response_->context_for_redirect = this; + resource_dispatcher_->SetDefersLoading(request_id_, true); + signals_->SignalRedirectOrResponseComplete(); return true; } +void SyncLoadContext::FollowRedirect() { + if (!signals_->RestartAfterRedirect()) { + CancelRedirect(); + return; + } + + response_->redirect_info = net::RedirectInfo(); + response_->context_for_redirect = nullptr; + + resource_dispatcher_->SetDefersLoading(request_id_, false); +} + +void SyncLoadContext::CancelRedirect() { + response_->redirect_info = net::RedirectInfo(); + response_->context_for_redirect = nullptr; + response_->error_code = net::ERR_ABORTED; + CompleteRequest(true); +} + void SyncLoadContext::OnReceivedResponse( const network::ResourceResponseInfo& info) { DCHECK(!Completed()); @@ -181,12 +259,8 @@ void SyncLoadContext::OnTimeout() { } void SyncLoadContext::CompleteRequest(bool remove_pending_request) { - abort_watcher_.StopWatching(); - timeout_timer_.AbandonAndStop(); - - completed_event_->Signal(); - - completed_event_ = nullptr; + signals_->SignalRedirectOrResponseComplete(); + signals_ = nullptr; response_ = nullptr; if (remove_pending_request) { @@ -196,7 +270,7 @@ void SyncLoadContext::CompleteRequest(bool remove_pending_request) { } bool SyncLoadContext::Completed() const { - DCHECK_EQ(!completed_event_, !response_); + DCHECK_EQ(!signals_, !response_); return !response_; } diff --git a/chromium/content/renderer/loader/sync_load_context.h b/chromium/content/renderer/loader/sync_load_context.h index b0b474405a3..23a7e7e8094 100644 --- a/chromium/content/renderer/loader/sync_load_context.h +++ b/chromium/content/renderer/loader/sync_load_context.h @@ -7,6 +7,7 @@ #include "base/macros.h" #include "base/optional.h" +#include "base/single_thread_task_runner.h" #include "base/synchronization/waitable_event_watcher.h" #include "base/timer/timer.h" #include "content/public/renderer/request_peer.h" @@ -54,6 +55,9 @@ class SyncLoadContext : public RequestPeer { ~SyncLoadContext() override; + void FollowRedirect(); + void CancelRedirect(); + private: SyncLoadContext( network::ResourceRequest* request, @@ -90,10 +94,6 @@ class SyncLoadContext : public RequestPeer { // Set to null after CompleteRequest() is called. SyncLoadResponse* response_; - // This event is signaled when the request is complete. - // Set to null after CompleteRequest() is called. - base::WaitableEvent* completed_event_; - // State necessary to run a request on an independent thread. scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; std::unique_ptr<ResourceDispatcher> resource_dispatcher_; @@ -110,8 +110,10 @@ class SyncLoadContext : public RequestPeer { base::Optional<int64_t> downloaded_file_length_; - base::WaitableEventWatcher abort_watcher_; - base::OneShotTimer timeout_timer_; + class SignalHelper; + std::unique_ptr<SignalHelper> signals_; + + const network::mojom::FetchRequestMode fetch_request_mode_; DISALLOW_COPY_AND_ASSIGN(SyncLoadContext); }; diff --git a/chromium/content/renderer/loader/sync_load_response.h b/chromium/content/renderer/loader/sync_load_response.h index bd46a9b14a9..ea252ca5f31 100644 --- a/chromium/content/renderer/loader/sync_load_response.h +++ b/chromium/content/renderer/loader/sync_load_response.h @@ -17,6 +17,8 @@ namespace content { +class SyncLoadContext; + // See the SyncLoad method. (The name of this struct is not // suffixed with "Info" because it also contains the response data.) struct CONTENT_EXPORT SyncLoadResponse { @@ -26,6 +28,9 @@ struct CONTENT_EXPORT SyncLoadResponse { SyncLoadResponse& operator=(SyncLoadResponse&& other); + base::Optional<net::RedirectInfo> redirect_info; + SyncLoadContext* context_for_redirect = nullptr; + network::ResourceResponseInfo info; // The response error code. diff --git a/chromium/content/renderer/loader/test_request_peer.cc b/chromium/content/renderer/loader/test_request_peer.cc index 42b46e16e41..1d92c02c630 100644 --- a/chromium/content/renderer/loader/test_request_peer.cc +++ b/chromium/content/renderer/loader/test_request_peer.cc @@ -27,6 +27,7 @@ bool TestRequestPeer::OnReceivedRedirect( EXPECT_FALSE(context_->cancelled); EXPECT_FALSE(context_->complete); ++context_->seen_redirects; + context_->last_load_timing = info.load_timing; if (context_->defer_on_redirect) dispatcher_->SetDefersLoading(context_->request_id, true); return context_->follow_redirects; @@ -38,6 +39,7 @@ void TestRequestPeer::OnReceivedResponse( EXPECT_FALSE(context_->received_response); EXPECT_FALSE(context_->complete); context_->received_response = true; + context_->last_load_timing = info.load_timing; if (context_->cancel_on_receive_response) { dispatcher_->Cancel( context_->request_id, @@ -101,6 +103,7 @@ void TestRequestPeer::OnCompletedRequest( EXPECT_TRUE(context_->received_response); EXPECT_FALSE(context_->complete); context_->complete = true; + context_->completion_status = status; } TestRequestPeer::Context::Context() = default; diff --git a/chromium/content/renderer/loader/test_request_peer.h b/chromium/content/renderer/loader/test_request_peer.h index 06e3a24e7c0..3c40627b410 100644 --- a/chromium/content/renderer/loader/test_request_peer.h +++ b/chromium/content/renderer/loader/test_request_peer.h @@ -11,6 +11,8 @@ #include <vector> #include "base/time/time.h" #include "content/public/renderer/request_peer.h" +#include "net/base/load_timing_info.h" +#include "services/network/public/cpp/url_loader_completion_status.h" namespace net { struct RedirectInfo; @@ -77,6 +79,9 @@ class TestRequestPeer : public RequestPeer { bool complete = false; bool cancelled = false; int request_id = -1; + + net::LoadTimingInfo last_load_timing; + network::URLLoaderCompletionStatus completion_status; }; private: diff --git a/chromium/content/renderer/loader/tracked_child_url_loader_factory_bundle.h b/chromium/content/renderer/loader/tracked_child_url_loader_factory_bundle.h index aaa4289f50c..d76f70f6355 100644 --- a/chromium/content/renderer/loader/tracked_child_url_loader_factory_bundle.h +++ b/chromium/content/renderer/loader/tracked_child_url_loader_factory_bundle.h @@ -5,6 +5,7 @@ #ifndef CONTENT_RENDERER_LOADER_TRACKED_CHILD_URL_LOADER_FACTORY_BUNDLE_H_ #define CONTENT_RENDERER_LOADER_TRACKED_CHILD_URL_LOADER_FACTORY_BUNDLE_H_ +#include "base/sequenced_task_runner.h" #include "content/common/content_export.h" #include "content/renderer/loader/child_url_loader_factory_bundle.h" diff --git a/chromium/content/renderer/loader/url_loader_client_impl.h b/chromium/content/renderer/loader/url_loader_client_impl.h index 96712b00667..66c1a455214 100644 --- a/chromium/content/renderer/loader/url_loader_client_impl.h +++ b/chromium/content/renderer/loader/url_loader_client_impl.h @@ -60,10 +60,9 @@ class CONTENT_EXPORT URLLoaderClientImpl final // Binds this instance to the given URLLoaderClient endpoints so that it can // start getting the mojo calls from the given loader. This is used only for - // the main resource loading when NavigationMojoResponse and/or NetworkService - // is enabled. Otherwise (in regular subresource loading cases) |this| is not - // bound to a client request, but used via ThrottlingURLLoader to get client - // upcalls from the loader. + // the main resource loading. Otherwise (in regular subresource loading cases) + // |this| is not bound to a client request, but used via ThrottlingURLLoader + // to get client upcalls from the loader. void Bind( network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints); @@ -112,7 +111,6 @@ class CONTENT_EXPORT URLLoaderClientImpl final ResourceDispatcher* const resource_dispatcher_; scoped_refptr<base::SingleThreadTaskRunner> task_runner_; - // Used in NavigationMojoResponse and NetworkService. network::mojom::URLLoaderPtr url_loader_; mojo::Binding<network::mojom::URLLoaderClient> url_loader_client_binding_; diff --git a/chromium/content/renderer/loader/url_loader_client_impl_unittest.cc b/chromium/content/renderer/loader/url_loader_client_impl_unittest.cc index 9c00707535e..4278bd904a9 100644 --- a/chromium/content/renderer/loader/url_loader_client_impl_unittest.cc +++ b/chromium/content/renderer/loader/url_loader_client_impl_unittest.cc @@ -7,13 +7,14 @@ #include <vector> #include "base/message_loop/message_loop.h" #include "base/run_loop.h" -#include "content/public/common/weak_wrapper_shared_url_loader_factory.h" +#include "content/renderer/loader/navigation_response_override_parameters.h" #include "content/renderer/loader/resource_dispatcher.h" #include "content/renderer/loader/test_request_peer.h" #include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/interface_ptr.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "net/url_request/redirect_info.h" +#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" #include "services/network/public/mojom/url_loader_factory.mojom.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h" @@ -30,9 +31,9 @@ class URLLoaderClientImplTest : public ::testing::Test, TRAFFIC_ANNOTATION_FOR_TESTS, false, false, std::make_unique<TestRequestPeer>(dispatcher_.get(), &request_peer_context_), - base::MakeRefCounted<WeakWrapperSharedURLLoaderFactory>(this), + base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(this), std::vector<std::unique_ptr<URLLoaderThrottle>>(), - network::mojom::URLLoaderClientEndpointsPtr(), + nullptr /* navigation_response_override_params */, nullptr /* continue_navigation_function */); request_peer_context_.request_id = request_id_; @@ -62,7 +63,7 @@ class URLLoaderClientImplTest : public ::testing::Test, static MojoCreateDataPipeOptions DataPipeOptions() { MojoCreateDataPipeOptions options; options.struct_size = sizeof(MojoCreateDataPipeOptions); - options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE; + options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE; options.element_num_bytes = 1; options.capacity_num_bytes = 4096; return options; diff --git a/chromium/content/renderer/loader/url_response_body_consumer_unittest.cc b/chromium/content/renderer/loader/url_response_body_consumer_unittest.cc index 49cb00b247c..3038533caa2 100644 --- a/chromium/content/renderer/loader/url_response_body_consumer_unittest.cc +++ b/chromium/content/renderer/loader/url_response_body_consumer_unittest.cc @@ -10,14 +10,15 @@ #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" -#include "content/public/common/weak_wrapper_shared_url_loader_factory.h" #include "content/public/renderer/request_peer.h" +#include "content/renderer/loader/navigation_response_override_parameters.h" #include "content/renderer/loader/request_extra_data.h" #include "content/renderer/loader/resource_dispatcher.h" #include "net/base/request_priority.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "services/network/public/cpp/resource_request.h" #include "services/network/public/cpp/url_loader_completion_status.h" +#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" #include "services/network/public/mojom/request_context_frame_type.mojom.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h" @@ -143,7 +144,7 @@ class URLResponseBodyConsumerTest : public ::testing::Test { MojoCreateDataPipeOptions CreateDataPipeOptions() { MojoCreateDataPipeOptions options; options.struct_size = sizeof(MojoCreateDataPipeOptions); - options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE; + options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE; options.element_num_bytes = 1; options.capacity_num_bytes = 1024; return options; @@ -158,9 +159,10 @@ class URLResponseBodyConsumerTest : public ::testing::Test { TRAFFIC_ANNOTATION_FOR_TESTS, false, false /* pass_response_pipe_to_peer */, std::make_unique<TestRequestPeer>(context, message_loop_.task_runner()), - base::MakeRefCounted<WeakWrapperSharedURLLoaderFactory>(&factory_), + base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( + &factory_), std::vector<std::unique_ptr<URLLoaderThrottle>>(), - network::mojom::URLLoaderClientEndpointsPtr(), + nullptr /* navigation_response_override_params */, nullptr /* continue_navigation_function */); } diff --git a/chromium/content/renderer/loader/web_data_consumer_handle_impl.cc b/chromium/content/renderer/loader/web_data_consumer_handle_impl.cc index b97d43b62cc..c05041f207c 100644 --- a/chromium/content/renderer/loader/web_data_consumer_handle_impl.cc +++ b/chromium/content/renderer/loader/web_data_consumer_handle_impl.cc @@ -81,7 +81,7 @@ Result WebDataConsumerHandleImpl::ReaderImpl::Read(void* data, context_->handle()->ReadData(data, &size_to_pass, flags_to_pass); if (rv == MOJO_RESULT_OK) *read_size = size_to_pass; - if (rv == MOJO_RESULT_OK || rv == MOJO_RESULT_SHOULD_WAIT) + if (rv == MOJO_RESULT_SHOULD_WAIT) handle_watcher_.ArmOrNotify(); return HandleReadResult(rv); @@ -104,13 +104,13 @@ Result WebDataConsumerHandleImpl::ReaderImpl::BeginRead(const void** buffer, context_->handle()->BeginReadData(buffer, &size_to_pass, flags_to_pass); if (rv == MOJO_RESULT_OK) *available = size_to_pass; + if (rv == MOJO_RESULT_SHOULD_WAIT) + handle_watcher_.ArmOrNotify(); return HandleReadResult(rv); } Result WebDataConsumerHandleImpl::ReaderImpl::EndRead(size_t read_size) { MojoResult rv = context_->handle()->EndReadData(read_size); - if (rv == MOJO_RESULT_OK) - handle_watcher_.ArmOrNotify(); return rv == MOJO_RESULT_OK ? kOk : kUnexpectedError; } diff --git a/chromium/content/renderer/loader/web_data_consumer_handle_impl.h b/chromium/content/renderer/loader/web_data_consumer_handle_impl.h index 83427b1149e..f79cb797b8e 100644 --- a/chromium/content/renderer/loader/web_data_consumer_handle_impl.h +++ b/chromium/content/renderer/loader/web_data_consumer_handle_impl.h @@ -9,6 +9,7 @@ #include <memory> +#include "base/single_thread_task_runner.h" #include "content/common/content_export.h" #include "mojo/public/cpp/system/data_pipe.h" #include "mojo/public/cpp/system/simple_watcher.h" diff --git a/chromium/content/renderer/loader/web_data_consumer_handle_impl_unittest.cc b/chromium/content/renderer/loader/web_data_consumer_handle_impl_unittest.cc index b01e4800a3d..8e4f0a216a5 100644 --- a/chromium/content/renderer/loader/web_data_consumer_handle_impl_unittest.cc +++ b/chromium/content/renderer/loader/web_data_consumer_handle_impl_unittest.cc @@ -196,7 +196,7 @@ class WebDataConsumerHandleImplTest : public ::testing::Test { void SetUp() override { MojoCreateDataPipeOptions options; options.struct_size = sizeof(MojoCreateDataPipeOptions); - options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE; + options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE; options.element_num_bytes = 1; options.capacity_num_bytes = kDataPipeCapacity; @@ -326,7 +326,7 @@ class CountDidGetReadableClient : public blink::WebDataConsumerHandle::Client { TEST_F(WebDataConsumerHandleImplTest, DidGetReadable) { static constexpr size_t kBlockSize = kDataPipeCapacity / 3; - static constexpr size_t kTotalSize = kBlockSize * 3; + static constexpr size_t kTotalSize = kBlockSize * 2; std::unique_ptr<CountDidGetReadableClient> client = std::make_unique<CountDidGetReadableClient>(); @@ -337,7 +337,7 @@ TEST_F(WebDataConsumerHandleImplTest, DidGetReadable) { base::RunLoop().RunUntilIdle(); EXPECT_EQ(0, client->num_did_get_readable_called()); - // Push three blocks. + // Push two blocks. { std::string expected; int index = 0; @@ -365,10 +365,10 @@ TEST_F(WebDataConsumerHandleImplTest, DidGetReadable) { EXPECT_EQ(sizeof(buffer), size); } base::RunLoop().RunUntilIdle(); - // |client| is notified the pipe is still ready. - EXPECT_EQ(2, client->num_did_get_readable_called()); + // |client| is NOT notified since the data is still available. + EXPECT_EQ(1, client->num_did_get_readable_called()); - // Read one more block. + // Read the other block. { const void* buffer = nullptr; size_t size = sizeof(buffer); @@ -378,28 +378,38 @@ TEST_F(WebDataConsumerHandleImplTest, DidGetReadable) { EXPECT_TRUE(buffer); EXPECT_EQ(kTotalSize - kBlockSize, size); base::RunLoop().RunUntilIdle(); - // |client| is NOT notified until EndRead is called. - EXPECT_EQ(2, client->num_did_get_readable_called()); rv = reader->EndRead(kBlockSize); EXPECT_EQ(Result::kOk, rv); } base::RunLoop().RunUntilIdle(); - // |client| is notified the pipe is still ready. - EXPECT_EQ(3, client->num_did_get_readable_called()); + // |client| is NOT notified the pipe is still waiting for more data. + EXPECT_EQ(1, client->num_did_get_readable_called()); - // Read the final block. + // Read one more. { char buffer[kBlockSize]; size_t size = 0; Result rv = reader->Read(&buffer, sizeof(buffer), WebDataConsumerHandle::kFlagNone, &size); - EXPECT_EQ(Result::kOk, rv); - EXPECT_EQ(sizeof(buffer), size); + EXPECT_EQ(Result::kShouldWait, rv); + } + base::RunLoop().RunUntilIdle(); + // |client| is NOT notified because the pipe is still waiting for more data. + EXPECT_EQ(1, client->num_did_get_readable_called()); + + // Push one more block. + { + std::string expected(kBlockSize, 'x'); + uint32_t size = expected.size(); + MojoResult rv = + producer_->WriteData(expected.data(), &size, MOJO_WRITE_DATA_FLAG_NONE); + EXPECT_EQ(MOJO_RESULT_OK, rv); + EXPECT_EQ(expected.size(), size); } base::RunLoop().RunUntilIdle(); - // |client| is NOT notified because the pipe doesn't have any data. - EXPECT_EQ(3, client->num_did_get_readable_called()); + // |client| is notified the pipe gets ready. + EXPECT_EQ(2, client->num_did_get_readable_called()); } } // namespace diff --git a/chromium/content/renderer/loader/web_url_loader_impl.cc b/chromium/content/renderer/loader/web_url_loader_impl.cc index 0c2ed0fbdce..c1ece37554f 100644 --- a/chromium/content/renderer/loader/web_url_loader_impl.cc +++ b/chromium/content/renderer/loader/web_url_loader_impl.cc @@ -142,32 +142,21 @@ void PopulateURLLoadTiming(const net::LoadTimingInfo& load_timing, WebURLLoadTiming* url_timing) { DCHECK(!load_timing.request_start.is_null()); - const TimeTicks kNullTicks; url_timing->Initialize(); - url_timing->SetRequestTime( - (load_timing.request_start - kNullTicks).InSecondsF()); - url_timing->SetProxyStart( - (load_timing.proxy_resolve_start - kNullTicks).InSecondsF()); - url_timing->SetProxyEnd( - (load_timing.proxy_resolve_end - kNullTicks).InSecondsF()); - url_timing->SetDNSStart( - (load_timing.connect_timing.dns_start - kNullTicks).InSecondsF()); - url_timing->SetDNSEnd( - (load_timing.connect_timing.dns_end - kNullTicks).InSecondsF()); - url_timing->SetConnectStart( - (load_timing.connect_timing.connect_start - kNullTicks).InSecondsF()); - url_timing->SetConnectEnd( - (load_timing.connect_timing.connect_end - kNullTicks).InSecondsF()); - url_timing->SetSSLStart( - (load_timing.connect_timing.ssl_start - kNullTicks).InSecondsF()); - url_timing->SetSSLEnd( - (load_timing.connect_timing.ssl_end - kNullTicks).InSecondsF()); - url_timing->SetSendStart((load_timing.send_start - kNullTicks).InSecondsF()); - url_timing->SetSendEnd((load_timing.send_end - kNullTicks).InSecondsF()); - url_timing->SetReceiveHeadersEnd( - (load_timing.receive_headers_end - kNullTicks).InSecondsF()); - url_timing->SetPushStart((load_timing.push_start - kNullTicks).InSecondsF()); - url_timing->SetPushEnd((load_timing.push_end - kNullTicks).InSecondsF()); + url_timing->SetRequestTime(load_timing.request_start); + url_timing->SetProxyStart(load_timing.proxy_resolve_start); + url_timing->SetProxyEnd(load_timing.proxy_resolve_end); + url_timing->SetDNSStart(load_timing.connect_timing.dns_start); + url_timing->SetDNSEnd(load_timing.connect_timing.dns_end); + url_timing->SetConnectStart(load_timing.connect_timing.connect_start); + url_timing->SetConnectEnd(load_timing.connect_timing.connect_end); + url_timing->SetSSLStart(load_timing.connect_timing.ssl_start); + url_timing->SetSSLEnd(load_timing.connect_timing.ssl_end); + url_timing->SetSendStart(load_timing.send_start); + url_timing->SetSendEnd(load_timing.send_end); + url_timing->SetReceiveHeadersEnd(load_timing.receive_headers_end); + url_timing->SetPushStart(load_timing.push_start); + url_timing->SetPushEnd(load_timing.push_end); } net::RequestPriority ConvertWebKitPriorityToNetPriority( @@ -363,12 +352,6 @@ void SetSecurityStyleAndDetails(const GURL& url, } // namespace -StreamOverrideParameters::StreamOverrideParameters() {} -StreamOverrideParameters::~StreamOverrideParameters() { - if (on_delete) - std::move(on_delete).Run(stream_url); -} - WebURLLoaderFactoryImpl::WebURLLoaderFactoryImpl( base::WeakPtr<ResourceDispatcher> resource_dispatcher, scoped_refptr<network::SharedURLLoaderFactory> loader_factory) @@ -469,7 +452,6 @@ class WebURLLoaderImpl::Context : public base::RefCounted<Context> { ResourceDispatcher* resource_dispatcher_; scoped_refptr<base::SingleThreadTaskRunner> task_runner_; std::unique_ptr<FtpDirectoryListingResponseDelegate> ftp_listing_delegate_; - std::unique_ptr<StreamOverrideParameters> stream_override_; std::unique_ptr<SharedMemoryDataConsumerHandle::Writer> body_stream_writer_; std::unique_ptr<KeepAliveHandleWithChildProcessReference> keep_alive_handle_; enum DeferState {NOT_DEFERRING, SHOULD_DEFER, DEFERRED_DATA}; @@ -630,10 +612,11 @@ void WebURLLoaderImpl::Context::Start(const WebURLRequest& request, return; } + std::unique_ptr<NavigationResponseOverrideParameters> response_override; if (request.GetExtraData()) { RequestExtraData* extra_data = static_cast<RequestExtraData*>(request.GetExtraData()); - stream_override_ = extra_data->TakeStreamOverrideOwnership(); + response_override = extra_data->TakeNavigationResponseOverrideOwnership(); } @@ -641,7 +624,7 @@ void WebURLLoaderImpl::Context::Start(const WebURLRequest& request, // the WebURLLoader are the ones created by CommitNavigation. Several browser // tests load HTML directly through a data url which will be handled by the // block above. - DCHECK(!IsBrowserSideNavigationEnabled() || stream_override_ || + DCHECK(response_override || request.GetFrameType() == network::mojom::RequestContextFrameType::kNone); @@ -686,6 +669,11 @@ void WebURLLoaderImpl::Context::Start(const WebURLRequest& request, network::kDefaultAcceptHeader); } + if (resource_request->resource_type == RESOURCE_TYPE_PREFETCH || + resource_request->resource_type == RESOURCE_TYPE_FAVICON) { + resource_request->do_not_prompt_for_login = true; + } + resource_request->load_flags = GetLoadFlagsForWebURLRequest(request); // |plugin_child_id| only needs to be non-zero if the request originates @@ -725,22 +713,13 @@ void WebURLLoaderImpl::Context::Start(const WebURLRequest& request, resource_request->previews_state = static_cast<int>(request.GetPreviewsState()); - // PlzNavigate: The network request has already been made by the browser. - // The renderer should request a stream which contains the body of the - // response. If the Network Service or NavigationMojoResponse is enabled, the - // URLLoaderClientEndpoints is used instead to get the body. - network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints; - if (stream_override_) { - CHECK(IsBrowserSideNavigationEnabled()); + // The network request has already been made by the browser. The renderer + // should bind the URLLoaderClientEndpoints stored in |response_override| to + // an implementation of a URLLoaderClient to get the response body. + if (response_override) { DCHECK(!sync_load_response); DCHECK_NE(network::mojom::RequestContextFrameType::kNone, request.GetFrameType()); - if (stream_override_->url_loader_client_endpoints) { - url_loader_client_endpoints = - std::move(stream_override_->url_loader_client_endpoints); - } else { - resource_request->resource_body_stream_url = stream_override_->stream_url; - } } RequestExtraData empty_extra_data; @@ -751,6 +730,16 @@ void WebURLLoaderImpl::Context::Start(const WebURLRequest& request, extra_data = &empty_extra_data; extra_data->CopyToResourceRequest(resource_request.get()); + std::unique_ptr<RequestPeer> peer; + if (extra_data->download_to_network_cache_only()) { + peer = std::make_unique<SinkPeer>(this); + } else { + const bool discard_body = + (resource_request->resource_type == RESOURCE_TYPE_PREFETCH); + peer = + std::make_unique<WebURLLoaderImpl::RequestPeerImpl>(this, discard_body); + } + if (sync_load_response) { DCHECK(defers_loading_ == NOT_DEFERRING); @@ -763,20 +752,11 @@ void WebURLLoaderImpl::Context::Start(const WebURLRequest& request, std::move(resource_request), request.RequestorID(), GetTrafficAnnotationTag(request), sync_load_response, url_loader_factory_, extra_data->TakeURLLoaderThrottles(), - request.TimeoutInterval(), std::move(download_to_blob_registry)); + request.TimeoutInterval(), std::move(download_to_blob_registry), + std::move(peer)); return; } - std::unique_ptr<RequestPeer> peer; - if (extra_data->download_to_network_cache_only()) { - peer = std::make_unique<SinkPeer>(this); - } else { - const bool discard_body = - (resource_request->resource_type == RESOURCE_TYPE_PREFETCH); - peer = - std::make_unique<WebURLLoaderImpl::RequestPeerImpl>(this, discard_body); - } - TRACE_EVENT_WITH_FLOW0("loading", "WebURLLoaderImpl::Context::Start", this, TRACE_EVENT_FLAG_FLOW_OUT); base::OnceClosure continue_navigation_function; @@ -784,8 +764,8 @@ void WebURLLoaderImpl::Context::Start(const WebURLRequest& request, std::move(resource_request), request.RequestorID(), task_runner_, GetTrafficAnnotationTag(request), false /* is_sync */, request.PassResponsePipeToClient(), std::move(peer), url_loader_factory_, - extra_data->TakeURLLoaderThrottles(), - std::move(url_loader_client_endpoints), &continue_navigation_function); + extra_data->TakeURLLoaderThrottles(), std::move(response_override), + &continue_navigation_function); extra_data->set_continue_navigation_function( std::move(continue_navigation_function)); @@ -823,7 +803,7 @@ bool WebURLLoaderImpl::Context::OnReceivedRedirect( } void WebURLLoaderImpl::Context::OnReceivedResponse( - const network::ResourceResponseInfo& initial_info) { + const network::ResourceResponseInfo& info) { if (!client_) return; @@ -831,25 +811,6 @@ void WebURLLoaderImpl::Context::OnReceivedResponse( "loading", "WebURLLoaderImpl::Context::OnReceivedResponse", this, TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); - network::ResourceResponseInfo info = initial_info; - - // PlzNavigate: during navigations, the ResourceResponse has already been - // received on the browser side, and has been passed down to the renderer. - if (stream_override_) { - CHECK(IsBrowserSideNavigationEnabled()); - info = stream_override_->response; - - // Replay the redirects that happened during navigation. - DCHECK_EQ(stream_override_->redirect_responses.size(), - stream_override_->redirect_infos.size()); - for (size_t i = 0; i < stream_override_->redirect_responses.size(); ++i) { - bool result = OnReceivedRedirect(stream_override_->redirect_infos[i], - stream_override_->redirect_responses[i]); - if (!result) - return; - } - } - WebURLResponse response; PopulateURLResponse(url_, info, &response, report_raw_headers_); @@ -1001,10 +962,9 @@ void WebURLLoaderImpl::Context::OnCompletedRequest( WebURLError::IsWebSecurityViolation::kFalse, url_), total_transfer_size, encoded_body_size, status.decoded_body_length); } else { - client_->DidFinishLoading( - (status.completion_time - TimeTicks()).InSecondsF(), - total_transfer_size, encoded_body_size, status.decoded_body_length, - status.blocked_cross_site_document); + client_->DidFinishLoading(status.completion_time, total_transfer_size, + encoded_body_size, status.decoded_body_length, + status.blocked_cross_site_document); } } } @@ -1266,11 +1226,8 @@ void WebURLLoaderImpl::PopulateURLResponse( if (!info.load_timing.receive_headers_end.is_null()) { WebURLLoadTiming timing; PopulateURLLoadTiming(info.load_timing, &timing); - const TimeTicks kNullTicks; - timing.SetWorkerStart( - (info.service_worker_start_time - kNullTicks).InSecondsF()); - timing.SetWorkerReady( - (info.service_worker_ready_time - kNullTicks).InSecondsF()); + timing.SetWorkerStart(info.service_worker_start_time); + timing.SetWorkerReady(info.service_worker_ready_time); response->SetLoadTiming(timing); } @@ -1334,6 +1291,7 @@ void WebURLLoaderImpl::PopulateURLResponse( void WebURLLoaderImpl::LoadSynchronously( const WebURLRequest& request, + WebURLLoaderClient* client, WebURLResponse& response, base::Optional<WebURLError>& error, WebData& data, @@ -1343,6 +1301,9 @@ void WebURLLoaderImpl::LoadSynchronously( blink::WebBlobInfo& downloaded_blob) { TRACE_EVENT0("loading", "WebURLLoaderImpl::loadSynchronously"); SyncLoadResponse sync_load_response; + + DCHECK(!context_->client()); + context_->set_client(client); context_->Start(request, &sync_load_response); const GURL& final_url = sync_load_response.url; diff --git a/chromium/content/renderer/loader/web_url_loader_impl.h b/chromium/content/renderer/loader/web_url_loader_impl.h index 147130d926e..ced62e5a71b 100644 --- a/chromium/content/renderer/loader/web_url_loader_impl.h +++ b/chromium/content/renderer/loader/web_url_loader_impl.h @@ -5,22 +5,15 @@ #ifndef CONTENT_RENDERER_LOADER_WEB_URL_LOADER_IMPL_H_ #define CONTENT_RENDERER_LOADER_WEB_URL_LOADER_IMPL_H_ -#include <vector> - -#include "base/callback_forward.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "content/common/content_export.h" #include "content/common/frame.mojom.h" #include "mojo/public/cpp/system/data_pipe.h" -#include "net/url_request/redirect_info.h" -#include "services/network/public/cpp/resource_response.h" #include "services/network/public/cpp/shared_url_loader_factory.h" -#include "services/network/public/mojom/url_loader.mojom.h" #include "services/network/public/mojom/url_loader_factory.mojom.h" #include "third_party/blink/public/platform/web_url_loader.h" #include "third_party/blink/public/platform/web_url_loader_factory.h" -#include "url/gurl.h" namespace base { class SingleThreadTaskRunner; @@ -34,24 +27,6 @@ namespace content { class ResourceDispatcher; -// PlzNavigate: Used to override parameters of the navigation request. -struct CONTENT_EXPORT StreamOverrideParameters { - public: - StreamOverrideParameters(); - ~StreamOverrideParameters(); - - GURL stream_url; - network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints; - network::ResourceResponseHead response; - std::vector<GURL> redirects; - std::vector<network::ResourceResponseInfo> redirect_responses; - std::vector<net::RedirectInfo> redirect_infos; - - // Called when this struct is deleted. Used to notify the browser that it can - // release its associated StreamHandle. - base::OnceCallback<void(const GURL&)> on_delete; -}; - // Default implementation of WebURLLoaderFactory. class CONTENT_EXPORT WebURLLoaderFactoryImpl : public blink::WebURLLoaderFactory { @@ -95,6 +70,7 @@ class CONTENT_EXPORT WebURLLoaderImpl : public blink::WebURLLoader { bool report_security_info); // WebURLLoader methods: void LoadSynchronously(const blink::WebURLRequest& request, + blink::WebURLLoaderClient* client, blink::WebURLResponse& response, base::Optional<blink::WebURLError>& error, blink::WebData& data, diff --git a/chromium/content/renderer/loader/web_url_loader_impl_unittest.cc b/chromium/content/renderer/loader/web_url_loader_impl_unittest.cc index a573dee34d4..e3fd5112703 100644 --- a/chromium/content/renderer/loader/web_url_loader_impl_unittest.cc +++ b/chromium/content/renderer/loader/web_url_loader_impl_unittest.cc @@ -19,9 +19,9 @@ #include "base/time/default_tick_clock.h" #include "base/time/time.h" #include "content/public/common/content_switches.h" -#include "content/public/common/weak_wrapper_shared_url_loader_factory.h" #include "content/public/renderer/fixed_received_data.h" #include "content/public/renderer/request_peer.h" +#include "content/renderer/loader/navigation_response_override_parameters.h" #include "content/renderer/loader/request_extra_data.h" #include "content/renderer/loader/resource_dispatcher.h" #include "content/renderer/loader/sync_load_response.h" @@ -35,6 +35,7 @@ #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "net/url_request/redirect_info.h" #include "services/network/public/cpp/resource_response_info.h" +#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" #include "services/network/public/mojom/request_context_frame_type.mojom.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h" @@ -77,7 +78,8 @@ class TestResourceDispatcher : public ResourceDispatcher { scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, std::vector<std::unique_ptr<URLLoaderThrottle>> throttles, double timeout, - blink::mojom::BlobRegistryPtrInfo download_to_blob_registry) override { + blink::mojom::BlobRegistryPtrInfo download_to_blob_registry, + std::unique_ptr<RequestPeer> peer) override { *response = std::move(sync_load_response_); } @@ -91,14 +93,16 @@ class TestResourceDispatcher : public ResourceDispatcher { std::unique_ptr<RequestPeer> peer, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, std::vector<std::unique_ptr<URLLoaderThrottle>> throttles, - network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints, + std::unique_ptr<NavigationResponseOverrideParameters> + navigation_response_override_params, base::OnceClosure* continue_navigation_function) override { EXPECT_FALSE(peer_); if (sync_load_response_.info.encoded_body_length != -1) EXPECT_TRUE(is_sync); peer_ = std::move(peer); url_ = request->url; - stream_url_ = request->resource_body_stream_url; + navigation_response_override_params_ = + std::move(navigation_response_override_params); return 1; } @@ -125,6 +129,11 @@ class TestResourceDispatcher : public ResourceDispatcher { sync_load_response_ = std::move(sync_load_response); } + std::unique_ptr<NavigationResponseOverrideParameters> + TakeNavigationResponseOverrideParams() { + return std::move(navigation_response_override_params_); + } + private: std::unique_ptr<RequestPeer> peer_; bool canceled_; @@ -132,6 +141,8 @@ class TestResourceDispatcher : public ResourceDispatcher { GURL url_; GURL stream_url_; SyncLoadResponse sync_load_response_; + std::unique_ptr<NavigationResponseOverrideParameters> + navigation_response_override_params_; DISALLOW_COPY_AND_ASSIGN(TestResourceDispatcher); }; @@ -165,7 +176,7 @@ class TestWebURLLoaderClient : public blink::WebURLLoaderClient { : loader_(new WebURLLoaderImpl( dispatcher, blink::scheduler::GetSingleThreadTaskRunnerForTesting(), - base::MakeRefCounted<WeakWrapperSharedURLLoaderFactory>( + base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( &fake_url_loader_factory_))), delete_on_receive_redirect_(false), delete_on_receive_response_(false), @@ -230,7 +241,7 @@ class TestWebURLLoaderClient : public blink::WebURLLoaderClient { loader_.reset(); } - void DidFinishLoading(double finishTime, + void DidFinishLoading(base::TimeTicks finishTime, int64_t totalEncodedDataLength, int64_t totalEncodedBodyLength, int64_t totalDecodedBodyLength, @@ -622,33 +633,32 @@ TEST_F(WebURLLoaderImplTest, FtpDeleteOnFail) { DoFailRequest(); } -// PlzNavigate: checks that the stream override parameters provided on +// Checks that the navigation response override parameters provided on // navigation commit are properly applied. TEST_F(WebURLLoaderImplTest, BrowserSideNavigationCommit) { // Initialize the request and the stream override. const GURL kNavigationURL = GURL(kTestURL); - const GURL kStreamURL = GURL("http://bar"); const std::string kMimeType = "text/html"; blink::WebURLRequest request(kNavigationURL); request.SetFrameType(network::mojom::RequestContextFrameType::kTopLevel); request.SetRequestContext(blink::WebURLRequest::kRequestContextFrame); - std::unique_ptr<StreamOverrideParameters> stream_override( - new StreamOverrideParameters()); - stream_override->stream_url = kStreamURL; - stream_override->response.mime_type = kMimeType; + std::unique_ptr<NavigationResponseOverrideParameters> response_override( + new NavigationResponseOverrideParameters()); + response_override->response.mime_type = kMimeType; auto extra_data = std::make_unique<RequestExtraData>(); - extra_data->set_stream_override(std::move(stream_override)); + extra_data->set_navigation_response_override(std::move(response_override)); request.SetExtraData(std::move(extra_data)); client()->loader()->LoadAsynchronously(request, client()); - // The stream url should have been added to the ResourceRequest. ASSERT_TRUE(peer()); EXPECT_EQ(kNavigationURL, dispatcher()->url()); - EXPECT_EQ(kStreamURL, dispatcher()->stream_url()); - EXPECT_FALSE(client()->did_receive_response()); - peer()->OnReceivedResponse(network::ResourceResponseInfo()); + + response_override = dispatcher()->TakeNavigationResponseOverrideParams(); + ASSERT_TRUE(response_override); + peer()->OnReceivedResponse(response_override->response); + EXPECT_TRUE(client()->did_receive_response()); // The response info should have been overriden. @@ -789,8 +799,8 @@ TEST_F(WebURLLoaderImplTest, SyncLengths) { base::Optional<int64_t> downloaded_file_length; blink::WebBlobInfo downloaded_blob; client()->loader()->LoadSynchronously( - request, response, error, data, encoded_data_length, encoded_body_length, - downloaded_file_length, downloaded_blob); + request, nullptr, response, error, data, encoded_data_length, + encoded_body_length, downloaded_file_length, downloaded_blob); EXPECT_EQ(kEncodedBodyLength, encoded_body_length); EXPECT_EQ(kEncodedDataLength, encoded_data_length); diff --git a/chromium/content/renderer/loader/web_url_request_util.cc b/chromium/content/renderer/loader/web_url_request_util.cc index 13ff3603eba..9dacb1aad64 100644 --- a/chromium/content/renderer/loader/web_url_request_util.cc +++ b/chromium/content/renderer/loader/web_url_request_util.cc @@ -24,8 +24,9 @@ #include "services/network/public/mojom/request_context_frame_type.mojom.h" #include "services/service_manager/public/cpp/connector.h" #include "services/service_manager/public/cpp/interface_provider.h" -#include "third_party/blink/public/mojom/blob/blob.mojom.h" +#include "third_party/blink/public/mojom/blob/blob_registry.mojom.h" #include "third_party/blink/public/platform/file_path_conversion.h" +#include "third_party/blink/public/platform/interface_provider.h" #include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-shared.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/platform/web_data.h" @@ -296,10 +297,17 @@ int GetLoadFlagsForWebURLRequest(const WebURLRequest& request) { WebHTTPBody GetWebHTTPBodyForRequestBody( const network::ResourceRequestBody& input) { + return GetWebHTTPBodyForRequestBodyWithBlobPtrs(input, {}); +} + +WebHTTPBody GetWebHTTPBodyForRequestBodyWithBlobPtrs( + const network::ResourceRequestBody& input, + std::vector<blink::mojom::BlobPtrInfo> blob_ptrs) { WebHTTPBody http_body; http_body.Initialize(); http_body.SetIdentifier(input.identifier()); http_body.SetContainsPasswordData(input.contains_sensitive_info()); + auto blob_ptr_iter = blob_ptrs.begin(); for (auto& element : *input.elements()) { switch (element.type()) { case network::DataElement::TYPE_BYTES: @@ -314,12 +322,16 @@ WebHTTPBody GetWebHTTPBodyForRequestBody( element.expected_modification_time().ToDoubleT()); break; case network::DataElement::TYPE_BLOB: - http_body.AppendBlob(WebString::FromASCII(element.blob_uuid())); + if (blob_ptrs.empty()) { + http_body.AppendBlob(WebString::FromASCII(element.blob_uuid())); + } else { + DCHECK(blob_ptr_iter != blob_ptrs.end()); + blink::mojom::BlobPtrInfo& blob = *blob_ptr_iter++; + http_body.AppendBlob(WebString::FromASCII(element.blob_uuid()), + element.length(), blob.PassHandle()); + } break; case network::DataElement::TYPE_DATA_PIPE: { - // Append the cloned data pipe to the |http_body|. This might not be - // needed for all callsites today but it respects the constness of - // |input|, as opposed to moving the data pipe out of |input|. http_body.AppendDataPipe( element.CloneDataPipeGetter().PassInterface().PassHandle()); break; @@ -334,6 +346,25 @@ WebHTTPBody GetWebHTTPBodyForRequestBody( return http_body; } +std::vector<blink::mojom::BlobPtrInfo> GetBlobPtrsForRequestBody( + const network::ResourceRequestBody& input) { + std::vector<blink::mojom::BlobPtrInfo> blob_ptrs; + blink::mojom::BlobRegistryPtr blob_registry; + for (auto& element : *input.elements()) { + if (element.type() == network::DataElement::TYPE_BLOB) { + blink::mojom::BlobPtrInfo blob_ptr; + if (!blob_registry) { + blink::Platform::Current()->GetInterfaceProvider()->GetInterface( + mojo::MakeRequest(&blob_registry)); + } + blob_registry->GetBlobFromUUID(mojo::MakeRequest(&blob_ptr), + element.blob_uuid()); + blob_ptrs.push_back(std::move(blob_ptr)); + } + } + return blob_ptrs; +} + scoped_refptr<network::ResourceRequestBody> GetRequestBodyForWebURLRequest( const WebURLRequest& request) { scoped_refptr<network::ResourceRequestBody> request_body; @@ -390,7 +421,8 @@ scoped_refptr<network::ResourceRequestBody> GetRequestBodyForWebHTTPBody( request_body->AppendDataPipe(std::move(data_pipe_getter_ptr)); } else { - request_body->AppendBlob(element.blob_uuid.Utf8()); + request_body->AppendBlob(element.blob_uuid.Utf8(), + element.blob_length); } break; } diff --git a/chromium/content/renderer/loader/web_url_request_util.h b/chromium/content/renderer/loader/web_url_request_util.h index dd42dcb240e..bc85bb64d15 100644 --- a/chromium/content/renderer/loader/web_url_request_util.h +++ b/chromium/content/renderer/loader/web_url_request_util.h @@ -13,6 +13,7 @@ #include "net/http/http_request_headers.h" #include "services/network/public/cpp/resource_request_body.h" #include "services/network/public/mojom/request_context_frame_type.mojom.h" +#include "third_party/blink/public/mojom/blob/blob_registry.mojom.h" #include "third_party/blink/public/platform/web_mixed_content_context_type.h" #include "third_party/blink/public/platform/web_url_request.h" @@ -40,6 +41,19 @@ int GetLoadFlagsForWebURLRequest(const blink::WebURLRequest& request); blink::WebHTTPBody GetWebHTTPBodyForRequestBody( const network::ResourceRequestBody& input); +// Takes a ResourceRequestBody with additional |blob_ptrs| which corresponds to +// each Blob entries, and converts into WebHTTPBody. +// TODO(kinuko): Remove this once Network Service is shipped. +blink::WebHTTPBody GetWebHTTPBodyForRequestBodyWithBlobPtrs( + const network::ResourceRequestBody& input, + std::vector<blink::mojom::BlobPtrInfo> blob_ptrs); + +// Takes a ResourceRequestBody and gets blob pointers for Blob entries. +// Used only in non-NetworkService cases but with S13nServiceWorker. +// TODO(kinuko): Remove this once Network Service is shipped. +std::vector<blink::mojom::BlobPtrInfo> GetBlobPtrsForRequestBody( + const network::ResourceRequestBody& input); + // Takes a WebHTTPBody and converts into a ResourceRequestBody. scoped_refptr<network::ResourceRequestBody> GetRequestBodyForWebHTTPBody( const blink::WebHTTPBody& httpBody); |