diff options
Diffstat (limited to 'chromium/content/browser/frame_host/navigation_request.cc')
-rw-r--r-- | chromium/content/browser/frame_host/navigation_request.cc | 163 |
1 files changed, 98 insertions, 65 deletions
diff --git a/chromium/content/browser/frame_host/navigation_request.cc b/chromium/content/browser/frame_host/navigation_request.cc index 701167c2055..3687817b179 100644 --- a/chromium/content/browser/frame_host/navigation_request.cc +++ b/chromium/content/browser/frame_host/navigation_request.cc @@ -10,6 +10,7 @@ #include "base/optional.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" +#include "base/task/post_task.h" #include "build/build_config.h" #include "content/browser/appcache/appcache_navigation_handle.h" #include "content/browser/appcache/chrome_appcache_service.h" @@ -28,6 +29,7 @@ #include "content/browser/frame_host/render_frame_host_impl.h" #include "content/browser/loader/navigation_url_loader.h" #include "content/browser/renderer_host/render_process_host_impl.h" +#include "content/browser/renderer_host/render_view_host_delegate.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" #include "content/browser/service_worker/service_worker_navigation_handle.h" @@ -35,6 +37,7 @@ #include "content/common/appcache_interfaces.h" #include "content/common/content_constants_internal.h" #include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/global_request_id.h" @@ -52,7 +55,6 @@ #include "content/public/common/content_switches.h" #include "content/public/common/origin_util.h" #include "content/public/common/renderer_preferences.h" -#include "content/public/common/request_context_type.h" #include "content/public/common/url_constants.h" #include "content/public/common/url_utils.h" #include "content/public/common/web_preferences.h" @@ -67,6 +69,8 @@ #include "services/network/public/cpp/resource_response.h" #include "services/network/public/cpp/url_loader_completion_status.h" #include "third_party/blink/public/common/frame/sandbox_flags.h" +#include "third_party/blink/public/common/service_worker/service_worker_utils.h" +#include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom.h" #include "third_party/blink/public/platform/resource_request_blocked_reason.h" #include "third_party/blink/public/platform/web_mixed_content_context_type.h" #include "url/url_constants.h" @@ -287,9 +291,11 @@ std::unique_ptr<NavigationRequest> NavigationRequest::CreateBrowserInitiated( bool is_same_document_history_load, bool is_history_navigation_in_new_child, const scoped_refptr<network::ResourceRequestBody>& post_body, - const base::TimeTicks& navigation_start, + base::TimeTicks navigation_start, NavigationControllerImpl* controller, - std::unique_ptr<NavigationUIData> navigation_ui_data) { + std::unique_ptr<NavigationUIData> navigation_ui_data, + base::TimeTicks input_start, + WasActivatedOption was_activated) { // A form submission happens either because the navigation is a // renderer-initiated form submission that took the OpenURL path or a // back/forward/reload navigation the does a form resubmission. @@ -322,7 +328,7 @@ std::unique_ptr<NavigationRequest> NavigationRequest::CreateBrowserInitiated( CommonNavigationParams common_params = entry.ConstructCommonNavigationParams( frame_entry, request_body, dest_url, dest_referrer, navigation_type, - previews_state, navigation_start); + previews_state, navigation_start, input_start); RequestNavigationParams request_params = entry.ConstructRequestNavigationParams( @@ -334,19 +340,21 @@ std::unique_ptr<NavigationRequest> NavigationRequest::CreateBrowserInitiated( controller->GetLastCommittedEntryIndex(), controller->GetEntryCount()); request_params.post_content_type = post_content_type; + request_params.was_activated = was_activated; std::unique_ptr<NavigationRequest> navigation_request(new NavigationRequest( frame_tree_node, common_params, mojom::BeginNavigationParams::New( entry.extra_headers(), net::LOAD_NORMAL, - false /* skip_service_worker */, REQUEST_CONTEXT_TYPE_LOCATION, + false /* skip_service_worker */, + blink::mojom::RequestContextType::LOCATION, blink::WebMixedContentContextType::kBlockable, is_form_submission, GURL() /* searchable_form_url */, std::string() /* searchable_form_encoding */, initiator, GURL() /* client_side_redirect_url */, base::nullopt /* devtools_initiator_info */), request_params, browser_initiated, false /* from_begin_navigation */, - &frame_entry, &entry, std::move(navigation_ui_data), nullptr)); + &frame_entry, &entry, std::move(navigation_ui_data), nullptr, nullptr)); navigation_request->blob_url_loader_factory_ = frame_entry.blob_url_loader_factory(); return navigation_request; @@ -362,7 +370,8 @@ std::unique_ptr<NavigationRequest> NavigationRequest::CreateRendererInitiated( int current_history_list_length, bool override_user_agent, scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory, - mojom::NavigationClientAssociatedPtrInfo navigation_client) { + mojom::NavigationClientAssociatedPtrInfo navigation_client, + blink::mojom::NavigationInitiatorPtr navigation_initiator) { // Only normal navigations to a different document or reloads are expected. // - Renderer-initiated fragment-navigations never take place in the browser, // even with PlzNavigate. @@ -397,7 +406,7 @@ std::unique_ptr<NavigationRequest> NavigationRequest::CreateRendererInitiated( true, // from_begin_navigation nullptr, entry, nullptr, // navigation_ui_data - std::move(navigation_client))); + std::move(navigation_client), std::move(navigation_initiator))); navigation_request->blob_url_loader_factory_ = std::move(blob_url_loader_factory); return navigation_request; @@ -413,7 +422,8 @@ NavigationRequest::NavigationRequest( const FrameNavigationEntry* frame_entry, const NavigationEntryImpl* entry, std::unique_ptr<NavigationUIData> navigation_ui_data, - mojom::NavigationClientAssociatedPtrInfo navigation_client) + mojom::NavigationClientAssociatedPtrInfo navigation_client, + blink::mojom::NavigationInitiatorPtr navigation_initiator) : frame_tree_node_(frame_tree_node), common_params_(common_params), begin_params_(std::move(begin_params)), @@ -534,7 +544,9 @@ NavigationRequest::NavigationRequest( begin_params_->headers = headers.ToString(); initiator_csp_context_.reset(new InitiatorCSPContext( - common_params_.initiator_csp, common_params_.initiator_self_source)); + common_params_.initiator_csp_info.initiator_csp, + common_params_.initiator_csp_info.initiator_self_source, + std::move(navigation_initiator))); } NavigationRequest::~NavigationRequest() { @@ -592,8 +604,8 @@ void NavigationRequest::BeginNavigation() { // otherwise block. Similarly, the NavigationHandle is created afterwards, so // that it gets the request URL after potentially being modified by CSP. net::Error net_error = CheckContentSecurityPolicy( - false /* is redirect */, false /* url_upgraded_after_redirect */, - false /* is_response_check */); + false /* has_followed redirect */, + false /* url_upgraded_after_redirect */, false /* is_response_check */); if (net_error != net::OK) { // Create a navigation handle so that the correct error code can be set on // it by OnRequestFailedInternal(). @@ -686,7 +698,7 @@ void NavigationRequest::CreateNavigationHandle() { common_params_.navigation_type), common_params_.navigation_start, nav_entry_id_, common_params_.started_from_context_menu, - common_params_.should_check_main_world_csp, + common_params_.initiator_csp_info.should_check_main_world_csp, begin_params_->is_form_submission, std::move(navigation_ui_data_), common_params_.method, std::move(headers), common_params_.post_data, Referrer::SanitizeForRequest(common_params_.url, @@ -852,9 +864,10 @@ void NavigationRequest::OnRequestRedirected( // Check Content Security Policy before the NavigationThrottles run. This // gives CSP a chance to modify requests that NavigationThrottles would // otherwise block. - net::Error net_error = CheckContentSecurityPolicy( - true /* is redirect */, redirect_info.insecure_scheme_was_upgraded, - false /* is_response_check */); + net::Error net_error = + CheckContentSecurityPolicy(true /* has_followed_redirect */, + redirect_info.insecure_scheme_was_upgraded, + false /* is_response_check */); if (net_error != net::OK) { OnRequestFailedInternal( network::URLLoaderCompletionStatus(net_error), false /*skip_throttles*/, @@ -958,6 +971,16 @@ void NavigationRequest::OnResponseStarted( ? navigation_handle_->appcache_handle()->appcache_host_id() : kAppCacheNoHostId; + // Update fetch start timing. While NavigationRequest updates fetch start + // timing for redirects, it's not aware of service worker interception so + // fetch start timing could happen earlier than worker start timing. Use + // worker ready time if it is greater than the current value to make sure + // fetch start timing always comes after worker start timing (if a service + // worker intercepted the navigation). + request_params_.navigation_timing.fetch_start = + std::max(request_params_.navigation_timing.fetch_start, + response->head.service_worker_ready_time); + // A navigation is user activated if it contains a user gesture or the frame // received a gesture and the navigation is renderer initiated. If the // navigation is browser initiated, it has to come from the context menu. @@ -965,7 +988,7 @@ void NavigationRequest::OnResponseStarted( // `ShouldPropagateUserActivation` requirements (same eTLD+1). // There are two different checks: // 1. if the `frame_tree_node_` has an origin and is following the rules above - // with the target URL, it is used and the bit is set iif the navigation is + // with the target URL, it is used and the bit is set if the navigation is // renderer initiated and the `frame_tree_node_` had a gesture. This should // apply to same page navigations and is preferred over using the referrer // as it can be changed. @@ -975,23 +998,28 @@ void NavigationRequest::OnResponseStarted( // context menu. This should apply to pages that open in a new tab and we // have to follow the referrer. It means that the activation might not be // transmitted if it should have. - request_params_.was_activated = false; - if (navigation_handle_->IsRendererInitiated() && - frame_tree_node_->has_received_user_gesture() && - ShouldPropagateUserActivation( - frame_tree_node_->current_origin(), - url::Origin::Create(navigation_handle_->GetURL()))) { - request_params_.was_activated = true; - // TODO(805871): the next check is relying on - // navigation_handle_->GetReferrer() but should ideally use a more reliable - // source for the originating URL when the navigation is renderer initiated. - } else if (((navigation_handle_->HasUserGesture() && - navigation_handle_->IsRendererInitiated()) || - navigation_handle_->WasStartedFromContextMenu()) && - ShouldPropagateUserActivation( - url::Origin::Create(navigation_handle_->GetReferrer().url), - url::Origin::Create(navigation_handle_->GetURL()))) { - request_params_.was_activated = true; + if (request_params_.was_activated == WasActivatedOption::kUnknown) { + request_params_.was_activated = WasActivatedOption::kNo; + + if (navigation_handle_->IsRendererInitiated() && + (frame_tree_node_->has_received_user_gesture() || + frame_tree_node_->has_received_user_gesture_before_nav()) && + ShouldPropagateUserActivation( + frame_tree_node_->current_origin(), + url::Origin::Create(navigation_handle_->GetURL()))) { + request_params_.was_activated = WasActivatedOption::kYes; + // TODO(805871): the next check is relying on + // navigation_handle_->GetReferrer() but should ideally use a more + // reliable source for the originating URL when the navigation is renderer + // initiated. + } else if (((navigation_handle_->HasUserGesture() && + navigation_handle_->IsRendererInitiated()) || + navigation_handle_->WasStartedFromContextMenu()) && + ShouldPropagateUserActivation( + url::Origin::Create(navigation_handle_->GetReferrer().url), + url::Origin::Create(navigation_handle_->GetURL()))) { + request_params_.was_activated = WasActivatedOption::kYes; + } } // Update the previews state of the request. @@ -1088,7 +1116,7 @@ void NavigationRequest::OnResponseStarted( // redirect or not in order to perform its checks. This is the reason // why we need to check the CSP both on request and response. net::Error net_error = CheckContentSecurityPolicy( - navigation_handle_->WasServerRedirect(), + navigation_handle_->WasServerRedirect() /* has_followed_redirect */, false /* url_upgraded_after_redirect */, true /* is_response_check */); if (net_error != net::OK) { OnRequestFailedInternal(network::URLLoaderCompletionStatus(net_error), @@ -1106,7 +1134,7 @@ void NavigationRequest::OnResponseStarted( render_frame_host, response->head.headers.get(), response->head.connection_info, response->head.socket_address, ssl_info_, request_id, common_params_.should_replace_current_entry, is_download, - is_stream, + is_stream, response->head.is_signed_exchange_inner_response, base::Bind(&NavigationRequest::OnWillProcessResponseChecksComplete, base::Unretained(this))); } @@ -1226,12 +1254,6 @@ bool NavigationRequest::ShouldKeepErrorPageInCurrentProcess(int net_error) { } void NavigationRequest::OnRequestStarted(base::TimeTicks timestamp) { - if (frame_tree_node_->IsMainFrame()) { - TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP0( - "navigation", "Navigation timeToNetworkStack", navigation_handle_.get(), - timestamp); - } - frame_tree_node_->navigator()->LogResourceRequestTime(timestamp, common_params_.url); } @@ -1266,8 +1288,8 @@ void NavigationRequest::OnStartChecksComplete( // is no onbeforeunload handler or if a NavigationThrottle cancelled it, // then this could cause reentrancy into NavigationController. So use a // PostTask to avoid that. - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::UI}, base::BindOnce( &NavigationRequest::OnRequestFailedInternal, weak_factory_.GetWeakPtr(), @@ -1343,7 +1365,7 @@ void NavigationRequest::OnStartChecksComplete( : frame_tree_node_->frame_tree()->root()->current_url(); // Walk the ancestor chain to determine whether all frames are same-site. If - // not, the |site_for_cookies| is set to an opaque URL. + // not, the |site_for_cookies| is set to an empty URL. // // TODO(mkwst): This is incorrect. It ought to use the definition from // 'Document::SiteForCookies()' in Blink, which special-cases extension @@ -1363,7 +1385,7 @@ void NavigationRequest::OnStartChecksComplete( (ancestors_are_same_site || !base_url.is_empty()) ? (frame_tree_node_->IsMainFrame() ? common_params_.url : top_document_url) - : GURL("data:,"); + : GURL::EmptyGURL(); bool parent_is_main_frame = !frame_tree_node_->parent() ? false : frame_tree_node_->parent()->IsMainFrame(); @@ -1493,10 +1515,20 @@ void NavigationRequest::OnWillProcessResponseChecksComplete( // If the NavigationThrottles allowed the navigation to continue, have the // processing of the response resume in the network stack. if (result.action() == NavigationThrottle::PROCEED) { - // If this is a download, intercept the navigation response and pass it to - // DownloadManager, and cancel the navigation. - if (is_download_ && - base::FeatureList::IsEnabled(network::features::kNetworkService)) { + // NetworkService doesn't use ResourceDispatcherHost. + bool served_via_resource_dispatcher_host = + !base::FeatureList::IsEnabled(network::features::kNetworkService); + // When S13nServiceWorker is on, it doesn't use ResourceDispatcherHost when + // a service worker serves the response. + served_via_resource_dispatcher_host = + served_via_resource_dispatcher_host && + !(blink::ServiceWorkerUtils::IsServicificationEnabled() && + response_->head.was_fetched_via_service_worker); + + // NetworkService or S13nServiceWorker: If this is a download, intercept the + // navigation response and pass it to DownloadManager, and cancel the + // navigation. + if (is_download_ && !served_via_resource_dispatcher_host) { // TODO(arthursonzogni): Pass the real ResourceRequest. For the moment // only these 4 parameters will be used, but it may evolve quickly. auto resource_request = std::make_unique<network::ResourceRequest>(); @@ -1669,7 +1701,7 @@ void NavigationRequest::CommitNavigation() { bool NavigationRequest::IsAllowedByCSPDirective( CSPContext* context, CSPDirective::Name directive, - bool is_redirect, + bool has_followed_redirect, bool url_upgraded_after_redirect, bool is_response_check, CSPContext::CheckCSPDisposition disposition) { @@ -1686,25 +1718,26 @@ bool NavigationRequest::IsAllowedByCSPDirective( url = common_params_.url; } return context->IsAllowedByCsp( - directive, url, is_redirect, is_response_check, + directive, url, has_followed_redirect, is_response_check, common_params_.source_location.value_or(SourceLocation()), disposition, begin_params_->is_form_submission); } net::Error NavigationRequest::CheckCSPDirectives( RenderFrameHostImpl* parent, - bool is_redirect, + bool has_followed_redirect, bool url_upgraded_after_redirect, bool is_response_check, CSPContext::CheckCSPDisposition disposition) { bool navigate_to_allowed = IsAllowedByCSPDirective( - initiator_csp_context_.get(), CSPDirective::NavigateTo, is_redirect, - url_upgraded_after_redirect, is_response_check, disposition); + initiator_csp_context_.get(), CSPDirective::NavigateTo, + has_followed_redirect, url_upgraded_after_redirect, is_response_check, + disposition); bool frame_src_allowed = true; if (parent) { frame_src_allowed = IsAllowedByCSPDirective( - parent, CSPDirective::FrameSrc, is_redirect, + parent, CSPDirective::FrameSrc, has_followed_redirect, url_upgraded_after_redirect, is_response_check, disposition); } @@ -1724,13 +1757,13 @@ net::Error NavigationRequest::CheckCSPDirectives( } net::Error NavigationRequest::CheckContentSecurityPolicy( - bool is_redirect, + bool has_followed_redirect, bool url_upgraded_after_redirect, bool is_response_check) { if (common_params_.url.SchemeIs(url::kAboutScheme)) return net::OK; - if (common_params_.should_check_main_world_csp == + if (common_params_.initiator_csp_info.should_check_main_world_csp == CSPDisposition::DO_NOT_CHECK) { return net::OK; } @@ -1756,13 +1789,13 @@ net::Error NavigationRequest::CheckContentSecurityPolicy( // This sequence of events allows site owners to learn about (via step 1) any // requests that are upgraded in step 2. - net::Error report_only_csp_status = - CheckCSPDirectives(parent, is_redirect, url_upgraded_after_redirect, - is_response_check, CSPContext::CHECK_REPORT_ONLY_CSP); + net::Error report_only_csp_status = CheckCSPDirectives( + parent, has_followed_redirect, url_upgraded_after_redirect, + is_response_check, CSPContext::CHECK_REPORT_ONLY_CSP); // upgrade-insecure-requests is handled in the network code for redirects, // only do the upgrade here if this is not a redirect. - if (!is_redirect && !frame_tree_node()->IsMainFrame()) { + if (!has_followed_redirect && !frame_tree_node()->IsMainFrame()) { if (parent && parent->ShouldModifyRequestUrlForCsp(true /* is subresource */)) { upgrade_if_insecure_ = true; @@ -1771,9 +1804,9 @@ net::Error NavigationRequest::CheckContentSecurityPolicy( } } - net::Error enforced_csp_status = - CheckCSPDirectives(parent, is_redirect, url_upgraded_after_redirect, - is_response_check, CSPContext::CHECK_ENFORCED_CSP); + net::Error enforced_csp_status = CheckCSPDirectives( + parent, has_followed_redirect, url_upgraded_after_redirect, + is_response_check, CSPContext::CHECK_ENFORCED_CSP); if (enforced_csp_status != net::OK) return enforced_csp_status; return report_only_csp_status; |