| // Copyright (c) 2012 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. |
| |
| // See http://dev.chromium.org/developers/design-documents/multi-process-resource-loading |
| |
| #ifndef CONTENT_RENDERER_LOADER_RESOURCE_DISPATCHER_H_ |
| #define CONTENT_RENDERER_LOADER_RESOURCE_DISPATCHER_H_ |
| |
| #include <stdint.h> |
| |
| #include <map> |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| #include "base/containers/circular_deque.h" |
| #include "base/containers/hash_tables.h" |
| #include "base/macros.h" |
| #include "base/memory/linked_ptr.h" |
| #include "base/memory/shared_memory.h" |
| #include "base/memory/weak_ptr.h" |
| #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/net_errors.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" |
| #include "services/network/public/mojom/url_loader.mojom.h" |
| #include "third_party/blink/public/mojom/blob/blob_registry.mojom.h" |
| #include "third_party/blink/public/platform/web_url_request.h" |
| #include "url/gurl.h" |
| |
| namespace base { |
| class WaitableEvent; |
| } |
| |
| namespace net { |
| struct RedirectInfo; |
| } |
| |
| namespace network { |
| struct ResourceResponseInfo; |
| struct ResourceRequest; |
| struct ResourceResponseHead; |
| struct URLLoaderCompletionStatus; |
| namespace mojom { |
| class URLLoaderFactory; |
| } |
| } |
| |
| namespace content { |
| struct NavigationResponseOverrideParameters; |
| class RequestPeer; |
| class ResourceDispatcherDelegate; |
| struct SyncLoadResponse; |
| class ThrottlingURLLoader; |
| class URLLoaderClientImpl; |
| |
| // This class serves as a communication interface to the ResourceDispatcherHost |
| // in the browser process. It can be used from any child process. |
| // Virtual methods are for tests. |
| class CONTENT_EXPORT ResourceDispatcher { |
| public: |
| // Generates ids for requests initiated by child processes unique to the |
| // particular process, counted up from 0 (browser initiated requests count |
| // down from -2). |
| // |
| // Public to be used by URLLoaderFactory and/or URLLoader implementations with |
| // the need to perform additional requests besides the main request, e.g., |
| // CORS preflight requests. |
| static int MakeRequestID(); |
| |
| ResourceDispatcher(); |
| virtual ~ResourceDispatcher(); |
| |
| // Call this method to load the resource synchronously (i.e., in one shot). |
| // This is an alternative to the StartAsync method. Be warned that this method |
| // will block the calling thread until the resource is fully downloaded or an |
| // error occurs. It could block the calling thread for a long time, so only |
| // use this if you really need it! There is also no way for the caller to |
| // interrupt this method. Errors are reported via the status field of the |
| // response parameter. |
| // |
| // |routing_id| is used to associated the bridge with a frame's network |
| // context. |
| // |timeout| is used to abort the sync request on timeouts. TimeDelta::Max() |
| // is interpreted as no-timeout. |
| // If |download_to_blob_registry| is not null, it is used to redirect the |
| // download to a blob, using StartAsync's |pass_response_pipe_to_peer| flag. |
| virtual void StartSync( |
| std::unique_ptr<network::ResourceRequest> request, |
| int routing_id, |
| const net::NetworkTrafficAnnotationTag& traffic_annotation, |
| SyncLoadResponse* response, |
| scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, |
| std::vector<std::unique_ptr<URLLoaderThrottle>> throttles, |
| base::TimeDelta timeout, |
| 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. |
| // Returns the request id. |url_loader_factory| must be non-null. |
| // |
| // |routing_id| is used to associated the bridge with a frame's network |
| // context. |
| // |
| // If |pass_response_pipe_to_peer| is true, the raw datapipe containing the |
| // response body is passed on to |peer| without any extra processing. If it |
| // is set to false instead OnReceivedData is called on the |peer| whenever a |
| // chunk of data is available. |
| // |
| // You need to pass a non-null |loading_task_runner| to specify task queue to |
| // execute loading tasks on. |
| virtual int StartAsync( |
| std::unique_ptr<network::ResourceRequest> request, |
| int routing_id, |
| scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner, |
| const net::NetworkTrafficAnnotationTag& traffic_annotation, |
| bool is_sync, |
| bool pass_response_pipe_to_peer, |
| std::unique_ptr<RequestPeer> peer, |
| scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, |
| std::vector<std::unique_ptr<URLLoaderThrottle>> throttles, |
| std::unique_ptr<NavigationResponseOverrideParameters> |
| response_override_params, |
| base::OnceClosure* continue_navigation_function); |
| |
| // Removes a request from the |pending_requests_| list, returning true if the |
| // request was found and removed. |
| bool RemovePendingRequest( |
| int request_id, |
| scoped_refptr<base::SingleThreadTaskRunner> task_runner); |
| |
| // Cancels a request in the |pending_requests_| list. The request will be |
| // removed from the dispatcher as well. |
| virtual void Cancel(int request_id, |
| scoped_refptr<base::SingleThreadTaskRunner> task_runner); |
| |
| // Toggles the is_deferred attribute for the specified request. |
| virtual void SetDefersLoading(int request_id, bool value); |
| |
| // Indicates the priority of the specified request changed. |
| void DidChangePriority(int request_id, |
| net::RequestPriority new_priority, |
| int intra_priority_value); |
| |
| // This does not take ownership of the delegate. It is expected that the |
| // delegate have a longer lifetime than the ResourceDispatcher. |
| void set_delegate(ResourceDispatcherDelegate* delegate) { |
| delegate_ = delegate; |
| } |
| |
| base::WeakPtr<ResourceDispatcher> GetWeakPtr() { |
| return weak_factory_.GetWeakPtr(); |
| } |
| |
| void OnTransferSizeUpdated(int request_id, int32_t transfer_size_diff); |
| |
| // This is used only when |this| is created for a worker thread. |
| // Sets |terminate_sync_load_event_| which will be signaled from the main |
| // thread when the worker thread is being terminated so that the sync requests |
| // requested on the worker thread can be aborted. |
| void set_terminate_sync_load_event( |
| base::WaitableEvent* terminate_sync_load_event) { |
| terminate_sync_load_event_ = terminate_sync_load_event; |
| } |
| |
| private: |
| friend class URLLoaderClientImpl; |
| friend class URLResponseBodyConsumer; |
| friend class ResourceDispatcherTest; |
| |
| struct PendingRequestInfo { |
| PendingRequestInfo(std::unique_ptr<RequestPeer> peer, |
| ResourceType resource_type, |
| int render_frame_id, |
| const GURL& request_url, |
| const std::string& method, |
| const GURL& referrer, |
| std::unique_ptr<NavigationResponseOverrideParameters> |
| response_override_params); |
| |
| ~PendingRequestInfo(); |
| |
| std::unique_ptr<RequestPeer> peer; |
| ResourceType resource_type; |
| int render_frame_id; |
| bool is_deferred = false; |
| // Original requested url. |
| GURL url; |
| // The url, method and referrer of the latest response even in case of |
| // redirection. |
| GURL response_url; |
| std::string response_method; |
| GURL response_referrer; |
| bool has_pending_redirect = false; |
| 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::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; |
| // Network error code the request completed with, or net::ERR_IO_PENDING if |
| // it's not completed. Used both to distinguish completion from |
| // cancellation, and to log histograms. |
| int net_error = net::ERR_IO_PENDING; |
| |
| std::vector<content::mojom::RedirectInfoPtr> redirect_info_chain; |
| |
| // For mojo loading. |
| std::unique_ptr<ThrottlingURLLoader> url_loader; |
| std::unique_ptr<URLLoaderClientImpl> url_loader_client; |
| }; |
| using PendingRequestMap = std::map<int, std::unique_ptr<PendingRequestInfo>>; |
| |
| // Helper to lookup the info based on the request_id. |
| // May return NULL if the request as been canceled from the client side. |
| PendingRequestInfo* GetPendingRequestInfo(int request_id); |
| |
| // Follows redirect, if any, for the given request. |
| void FollowPendingRedirect(PendingRequestInfo* request_info); |
| |
| // Message response handlers, called by the message handler for this process. |
| void OnUploadProgress(int request_id, int64_t position, int64_t size); |
| void OnReceivedResponse(int request_id, const network::ResourceResponseHead&); |
| void OnReceivedCachedMetadata(int request_id, |
| const std::vector<uint8_t>& data); |
| void OnReceivedRedirect( |
| int request_id, |
| const net::RedirectInfo& redirect_info, |
| const network::ResourceResponseHead& response_head, |
| scoped_refptr<base::SingleThreadTaskRunner> task_runner); |
| void OnStartLoadingResponseBody(int request_id, |
| mojo::ScopedDataPipeConsumerHandle body); |
| void OnRequestComplete(int request_id, |
| const network::URLLoaderCompletionStatus& status); |
| |
| void ToResourceResponseInfo( |
| const PendingRequestInfo& request_info, |
| const network::ResourceResponseHead& browser_info, |
| network::ResourceResponseInfo* renderer_info) const; |
| |
| void ContinueForNavigation(int request_id); |
| |
| // All pending requests issued to the host |
| PendingRequestMap pending_requests_; |
| |
| ResourceDispatcherDelegate* delegate_; |
| |
| base::WaitableEvent* terminate_sync_load_event_ = nullptr; |
| |
| base::WeakPtrFactory<ResourceDispatcher> weak_factory_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ResourceDispatcher); |
| }; |
| |
| } // namespace content |
| |
| #endif // CONTENT_RENDERER_LOADER_RESOURCE_DISPATCHER_H_ |