// Copyright (c) 2019 The Chromium Embedded Framework Authors. Portions // Copyright (c) 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 CEF_LIBCEF_BROWSER_NET_SERVICE_PROXY_URL_LOADER_FACTORY_H_ #define CEF_LIBCEF_BROWSER_NET_SERVICE_PROXY_URL_LOADER_FACTORY_H_ #include "libcef/browser/net_service/stream_reader_url_loader.h" #include "base/callback.h" #include "base/containers/unique_ptr_adapters.h" #include "base/hash/hash.h" #include "base/macros.h" #include "base/strings/string_piece.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/web_contents.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/receiver_set.h" #include "services/network/public/mojom/network_context.mojom.h" #include "services/network/public/mojom/url_loader_factory.mojom.h" #include "third_party/abseil-cpp/absl/types/optional.h" namespace content { class ResourceContext; } namespace net_service { class InterceptedRequest; class ResourceContextData; // Implement this interface to to evaluate requests. All methods are called on // the IO thread, and all callbacks must be executed on the IO thread. class InterceptedRequestHandler { public: InterceptedRequestHandler(); virtual ~InterceptedRequestHandler(); // Optionally modify |request| and execute |callback| to continue the request. // Set |intercept_request| to false if the request will not be intercepted. // Set |intercept_only| to true if the loader should not proceed unless the // request is intercepted. Keep a reference to |cancel_callback| and execute // at any time to cancel the request. using OnBeforeRequestResultCallback = base::OnceCallback; using CancelRequestCallback = base::OnceCallback; virtual void OnBeforeRequest(int32_t request_id, network::ResourceRequest* request, bool request_was_redirected, OnBeforeRequestResultCallback callback, CancelRequestCallback cancel_callback); // Optionally modify |request| and execute |callback| after determining if the // request hould be intercepted. using ShouldInterceptRequestResultCallback = base::OnceCallback)>; virtual void ShouldInterceptRequest( int32_t request_id, network::ResourceRequest* request, ShouldInterceptRequestResultCallback callback); // Called to evaluate and optionally modify request headers. |request| is the // current request information. |redirect_url| will be non-empty if this // method is called in response to a redirect. The |modified_headers| and // |removed_headers| may be modified. If non-empty the |modified_headers| // values will be merged first, and then any |removed_headers| values will be // removed. This comparison is case sensitive. virtual void ProcessRequestHeaders( int32_t request_id, const network::ResourceRequest& request, const GURL& redirect_url, net::HttpRequestHeaders* modified_headers, std::vector* removed_headers) {} // Called to evaluate and optionally modify response headers. |request| is the // current request information. |redirect_url| will be non-empty if this // method is called in response to a redirect. Even though |head| is const the // |head.headers| value is non-const and any changes will be passed to the // client. virtual void ProcessResponseHeaders(int32_t request_id, const network::ResourceRequest& request, const GURL& redirect_url, net::HttpResponseHeaders* headers) {} enum class ResponseMode { // Continue the request. CONTINUE, // Restart the request. RESTART, // Cancel the request. CANCEL }; // Called on response. |request| is the current request information. // |redirect_info| will be non-empty for redirect responses. // Optionally modify |request| and execute the callback as appropriate. using OnRequestResponseResultCallback = base::OnceCallback /* override_headers */, const GURL& /* redirect_url */)>; virtual void OnRequestResponse( int32_t request_id, network::ResourceRequest* request, net::HttpResponseHeaders* headers, absl::optional redirect_info, OnRequestResponseResultCallback callback); // Called to optionally filter the response body. virtual mojo::ScopedDataPipeConsumerHandle OnFilterResponseBody( int32_t request_id, const network::ResourceRequest& request, mojo::ScopedDataPipeConsumerHandle body); // Called on completion notification from the loader (successful or not). virtual void OnRequestComplete( int32_t request_id, const network::ResourceRequest& request, const network::URLLoaderCompletionStatus& status) {} // Called on error. virtual void OnRequestError(int32_t request_id, const network::ResourceRequest& request, int error_code, bool safebrowsing_hit) {} private: DISALLOW_COPY_AND_ASSIGN(InterceptedRequestHandler); }; // URL Loader Factory that supports request/response interception, processing // and callback invocation. // Based on android_webview/browser/network_service/ // aw_proxying_url_loader_factory.cc class ProxyURLLoaderFactory : public network::mojom::URLLoaderFactory, public network::mojom::TrustedURLLoaderHeaderClient { public: ~ProxyURLLoaderFactory() override; // Create a proxy object on the UI thread. static void CreateProxy( content::BrowserContext* browser_context, mojo::PendingReceiver* factory_receiver, mojo::PendingRemote* header_client, std::unique_ptr request_handler); // Create a proxy object on the IO thread. static void CreateProxy( content::WebContents::Getter web_contents_getter, mojo::PendingReceiver loader_request, std::unique_ptr request_handler); // mojom::URLLoaderFactory methods: void CreateLoaderAndStart( mojo::PendingReceiver receiver, int32_t request_id, uint32_t options, const network::ResourceRequest& request, mojo::PendingRemote client, const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) override; void Clone( mojo::PendingReceiver factory) override; // network::mojom::TrustedURLLoaderHeaderClient: void OnLoaderCreated( int32_t request_id, mojo::PendingReceiver receiver) override; void OnLoaderForCorsPreflightCreated( const network::ResourceRequest& request, mojo::PendingReceiver receiver) override; private: friend class InterceptedRequest; friend class ResourceContextData; ProxyURLLoaderFactory( mojo::PendingReceiver factory_receiver, network::mojom::URLLoaderFactoryPtrInfo target_factory_info, mojo::PendingReceiver header_client_receiver, std::unique_ptr request_handler); static void CreateOnIOThread( mojo::PendingReceiver factory_receiver, network::mojom::URLLoaderFactoryPtrInfo target_factory_info, mojo::PendingReceiver header_client_receiver, content::ResourceContext* resource_context, std::unique_ptr request_handler); using DisconnectCallback = base::OnceCallback; void SetDisconnectCallback(DisconnectCallback on_disconnect); void OnTargetFactoryError(); void OnProxyBindingError(); void RemoveRequest(InterceptedRequest* request); void MaybeDestroySelf(); mojo::ReceiverSet proxy_receivers_; mojo::Remote target_factory_; mojo::Receiver url_loader_header_client_receiver_{this}; std::unique_ptr request_handler_; bool destroyed_ = false; DisconnectCallback on_disconnect_; // Map of request ID to request object. std::map> requests_; base::WeakPtrFactory weak_factory_; DISALLOW_COPY_AND_ASSIGN(ProxyURLLoaderFactory); }; } // namespace net_service #endif // CEF_LIBCEF_BROWSER_NET_SERVICE_PROXY_URL_LOADER_FACTORY_H_