blob: 2f6bdf38568b08e8d051c632692b45dc8892f1f4 [file] [log] [blame]
// Copyright 2017 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_BROWSER_LOADER_NAVIGATION_URL_LOADER_IMPL_H_
#define CONTENT_BROWSER_LOADER_NAVIGATION_URL_LOADER_IMPL_H_
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "content/browser/loader/navigation_url_loader.h"
#include "content/browser/loader/single_request_url_loader_factory.h"
#include "content/browser/navigation_subresource_loader_params.h"
#include "content/common/navigation_params.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/global_request_id.h"
#include "content/public/browser/ssl_status.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "net/url_request/url_request.h"
#include "services/network/public/mojom/url_loader.mojom.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/blink/public/common/loader/previews_state.h"
#include "third_party/blink/public/common/navigation/navigation_policy.h"
namespace net {
struct RedirectInfo;
}
namespace content {
class BrowserContext;
class NavigationEarlyHintsManager;
class NavigationLoaderInterceptor;
class PrefetchedSignedExchangeCache;
class SignedExchangePrefetchMetricRecorder;
class SignedExchangeRequestHandler;
class StoragePartition;
class StoragePartitionImpl;
struct WebPluginInfo;
class CONTENT_EXPORT NavigationURLLoaderImpl
: public NavigationURLLoader,
public network::mojom::URLLoaderClient {
public:
// The caller is responsible for ensuring that |delegate| outlives the loader.
// Note |initial_interceptors| is there for test purposes only.
NavigationURLLoaderImpl(
BrowserContext* browser_context,
StoragePartition* storage_partition,
std::unique_ptr<NavigationRequestInfo> request_info,
std::unique_ptr<NavigationUIData> navigation_ui_data,
ServiceWorkerMainResourceHandle* service_worker_handle,
AppCacheNavigationHandle* appcache_handle,
scoped_refptr<PrefetchedSignedExchangeCache>
prefetched_signed_exchange_cache,
NavigationURLLoaderDelegate* delegate,
mojo::PendingRemote<network::mojom::CookieAccessObserver> cookie_observer,
mojo::PendingRemote<network::mojom::URLLoaderNetworkServiceObserver>
url_loader_network_observer,
mojo::PendingRemote<network::mojom::DevToolsObserver> devtools_observer,
std::vector<std::unique_ptr<NavigationLoaderInterceptor>>
initial_interceptors);
~NavigationURLLoaderImpl() override;
// TODO(kinuko): Make most of these methods private.
// TODO(kinuko): Some method parameters can probably be just kept as
// member variables rather than being passed around.
// Starts the loader by finalizing loader factories initialization and
// calling Restart().
// This is called only once (while Restart can be called multiple times).
// Sets |started_| true.
void Start(
scoped_refptr<network::SharedURLLoaderFactory> network_loader_factory,
AppCacheNavigationHandle* appcache_handle,
scoped_refptr<PrefetchedSignedExchangeCache>
prefetched_signed_exchange_cache,
scoped_refptr<SignedExchangePrefetchMetricRecorder>
signed_exchange_prefetch_metric_recorder,
mojo::PendingRemote<network::mojom::URLLoaderFactory> factory_for_webui,
std::string accept_langs,
bool needs_loader_factory_interceptor);
void CreateInterceptors(AppCacheNavigationHandle* appcache_handle,
scoped_refptr<PrefetchedSignedExchangeCache>
prefetched_signed_exchange_cache,
scoped_refptr<SignedExchangePrefetchMetricRecorder>
signed_exchange_prefetch_metric_recorder,
const std::string& accept_langs);
// This could be called multiple times to follow a chain of redirects.
void Restart();
// |interceptor| is non-null if this is called by one of the interceptors
// (via a LoaderCallback).
// |single_request_handler| is the RequestHandler given by the
// |interceptor|, non-null if the interceptor wants to handle the request.
void MaybeStartLoader(
NavigationLoaderInterceptor* interceptor,
scoped_refptr<network::SharedURLLoaderFactory> single_request_factory);
// This is the |fallback_callback| passed to
// NavigationLoaderInterceptor::MaybeCreateLoader. It allows an interceptor
// to initially elect to handle a request, and later decide to fallback to
// the default behavior. This is needed for service worker network fallback
// and signed exchange (SXG) fallback redirect.
void FallbackToNonInterceptedRequest(bool reset_subresource_loader_params);
scoped_refptr<network::SharedURLLoaderFactory>
PrepareForNonInterceptedRequest(uint32_t* out_options);
// TODO(kinuko): Merge this back to FollowRedirect().
void FollowRedirectInternal(
const std::vector<std::string>& removed_headers,
const net::HttpRequestHeaders& modified_headers,
const net::HttpRequestHeaders& modified_cors_exempt_headers,
blink::PreviewsState new_previews_state,
base::Time ui_post_time);
// network::mojom::URLLoaderClient implementation:
void OnReceiveEarlyHints(network::mojom::EarlyHintsPtr early_hints) override;
void OnReceiveResponse(network::mojom::URLResponseHeadPtr head) override;
void OnStartLoadingResponseBody(
mojo::ScopedDataPipeConsumerHandle response_body) override;
void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
network::mojom::URLResponseHeadPtr head) override;
void OnUploadProgress(int64_t current_position,
int64_t total_size,
OnUploadProgressCallback callback) override;
void OnReceiveCachedMetadata(mojo_base::BigBuffer data) override;
void OnTransferSizeUpdated(int32_t transfer_size_diff) override {}
void OnComplete(const network::URLLoaderCompletionStatus& status) override;
#if BUILDFLAG(ENABLE_PLUGINS)
void CheckPluginAndContinueOnReceiveResponse(
network::mojom::URLResponseHeadPtr head,
network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
bool is_download_if_not_handled_by_plugin,
const std::vector<WebPluginInfo>& plugins);
#endif
void CallOnReceivedResponse(
network::mojom::URLResponseHeadPtr head,
network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
bool is_download);
bool MaybeCreateLoaderForResponse(
network::mojom::URLResponseHeadPtr* response);
std::vector<std::unique_ptr<blink::URLLoaderThrottle>>
CreateURLLoaderThrottles();
std::unique_ptr<SignedExchangeRequestHandler>
CreateSignedExchangeRequestHandler(
const NavigationRequestInfo& request_info,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
scoped_refptr<SignedExchangePrefetchMetricRecorder>
signed_exchange_prefetch_metric_recorder,
std::string accept_langs);
void ParseHeaders(const GURL& url,
network::mojom::URLResponseHead* head,
base::OnceClosure continuation);
// NavigationURLLoader implementation:
void FollowRedirect(
const std::vector<std::string>& removed_headers,
const net::HttpRequestHeaders& modified_headers,
const net::HttpRequestHeaders& modified_cors_exempt_headers,
blink::PreviewsState new_previews_state) override;
void NotifyResponseStarted(
network::mojom::URLResponseHeadPtr response_head,
network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
mojo::ScopedDataPipeConsumerHandle response_body,
const GlobalRequestID& global_request_id,
bool is_download);
void NotifyRequestRedirected(net::RedirectInfo redirect_info,
network::mojom::URLResponseHeadPtr response);
void NotifyRequestFailed(const network::URLLoaderCompletionStatus& status);
// Intercepts loading of frame requests when network service is enabled and
// either a network::mojom::TrustedURLLoaderHeaderClient is being used or
// for schemes not handled by network service (e.g. files). This must be
// called on the UI thread or before threads start.
using URLLoaderFactoryInterceptor = base::RepeatingCallback<void(
mojo::PendingReceiver<network::mojom::URLLoaderFactory>* receiver)>;
static void SetURLLoaderFactoryInterceptorForTesting(
const URLLoaderFactoryInterceptor& interceptor);
// Creates a URLLoaderFactory for a navigation. The factory uses
// |header_client|. This should have the same settings as the factory from
// the URLLoaderFactoryGetter. Called on the UI thread.
static void CreateURLLoaderFactoryWithHeaderClient(
mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>
header_client,
mojo::PendingReceiver<network::mojom::URLLoaderFactory> factory_receiver,
StoragePartitionImpl* partition);
private:
void BindNonNetworkURLLoaderFactoryReceiver(
const GURL& url,
mojo::PendingReceiver<network::mojom::URLLoaderFactory> factory_receiver);
void BindAndInterceptNonNetworkURLLoaderFactoryReceiver(
const GURL& url,
mojo::PendingReceiver<network::mojom::URLLoaderFactory> factory_receiver);
NavigationURLLoaderDelegate* delegate_;
BrowserContext* browser_context_;
StoragePartitionImpl* storage_partition_;
ServiceWorkerMainResourceHandle* service_worker_handle_;
std::unique_ptr<network::ResourceRequest> resource_request_;
std::unique_ptr<NavigationRequestInfo> request_info_;
// Current URL that is being navigated, updated after redirection.
GURL url_;
// Redirect URL chain.
std::vector<GURL> url_chain_;
const int frame_tree_node_id_;
const GlobalRequestID global_request_id_;
net::RedirectInfo redirect_info_;
int redirect_limit_ = net::URLRequest::kMaxRedirects;
base::RepeatingCallback<WebContents*()> web_contents_getter_;
std::unique_ptr<NavigationUIData> navigation_ui_data_;
scoped_refptr<network::SharedURLLoaderFactory> network_loader_factory_;
std::unique_ptr<blink::ThrottlingURLLoader> url_loader_;
// Caches the modified request headers provided by clients during redirect,
// will be consumed by next |url_loader_->FollowRedirect()|.
std::vector<std::string> url_loader_removed_headers_;
net::HttpRequestHeaders url_loader_modified_headers_;
net::HttpRequestHeaders url_loader_modified_cors_exempt_headers_;
// Currently used by the AppCache loader to pass its factory to the
// renderer which enables it to handle subresources.
absl::optional<SubresourceLoaderParams> subresource_loader_params_;
std::vector<std::unique_ptr<NavigationLoaderInterceptor>> interceptors_;
size_t interceptor_index_ = 0;
// Set to true if the default URLLoader (network service) was used for the
// current navigation.
bool default_loader_used_ = false;
// URLLoaderClient receiver for loaders created for responses received from
// the network loader.
mojo::Receiver<network::mojom::URLLoaderClient> response_loader_receiver_{
this};
// URLLoader instance for response loaders, i.e loaders created for handling
// responses received from the network URLLoader.
mojo::PendingRemote<network::mojom::URLLoader> response_url_loader_;
// Set to true if we receive a valid response from a URLLoader, i.e.
// URLLoaderClient::OnStartLoadingResponseBody() is called.
bool received_response_ = false;
// When URLLoaderClient::OnReceiveResponse() is called. For UMA.
base::TimeTicks on_receive_response_time_;
bool started_ = false;
// The completion status if it has been received. This is needed to handle
// the case that the response is intercepted by download, and OnComplete()
// is already called while we are transferring the |url_loader_| and
// response body to download code.
absl::optional<network::URLLoaderCompletionStatus> status_;
// Before creating this URLLoaderRequestController on UI thread, the
// embedder may have elected to proxy the URLLoaderFactory receiver, in
// which case these fields will contain input (remote) and output (receiver)
// endpoints for the proxy. If this controller is handling a receiver for
// which proxying is supported, receivers will be plumbed through these
// endpoints.
//
// Note that these are only used for receivers that go to the Network
// Service.
mojo::PendingReceiver<network::mojom::URLLoaderFactory>
proxied_factory_receiver_;
mojo::PendingRemote<network::mojom::URLLoaderFactory> proxied_factory_remote_;
// The schemes that this loader can use. For anything else we'll try
// external protocol handlers.
std::set<std::string> known_schemes_;
// True when a proxy will handle the redirect checks, or when an interceptor
// intentionally returned unsafe redirect response
// (eg: NavigationLoaderInterceptor for loading a local Web Bundle file).
bool bypass_redirect_checks_ = false;
network::mojom::URLResponseHeadPtr head_;
mojo::ScopedDataPipeConsumerHandle response_body_;
blink::NavigationDownloadPolicy download_policy_;
// Factories to handle navigation requests for non-network resources.
ContentBrowserClient::NonNetworkURLLoaderFactoryMap
non_network_url_loader_factories_;
// Lazily initialized and used in the case of non-network resource
// navigations. Keyed by URL scheme.
// (These are cloned by entries populated in
// non_network_url_loader_factories_ and are ready to use, i.e. preparation
// calls like WillCreateURLLoaderFactory are already called)
std::map<std::string, mojo::Remote<network::mojom::URLLoaderFactory>>
non_network_url_loader_factory_remotes_;
// Counts the time overhead of all the hops from the IO to the UI threads.
base::TimeDelta io_to_ui_time_;
std::unique_ptr<NavigationEarlyHintsManager> early_hints_manager_;
base::WeakPtrFactory<NavigationURLLoaderImpl> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(NavigationURLLoaderImpl);
};
} // namespace content
#endif // CONTENT_BROWSER_LOADER_NAVIGATION_URL_LOADER_IMPL_H_