blob: 04c47a54ff59f22e89ca344ff78b4e7b55b94204 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef EXTENSIONS_BROWSER_API_WEB_REQUEST_WEB_REQUEST_API_H_
#define EXTENSIONS_BROWSER_API_WEB_REQUEST_WEB_REQUEST_API_H_
#include <stdint.h>
#include <list>
#include <map>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "base/containers/unique_ptr_adapters.h"
#include "base/feature_list.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/no_destructor.h"
#include "base/strings/string_util.h"
#include "base/time/time.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/global_request_id.h"
#include "extensions/browser/api/declarative/rules_registry.h"
#include "extensions/browser/api/declarative_webrequest/request_stage.h"
#include "extensions/browser/api/web_request/web_request_api_helpers.h"
#include "extensions/browser/api/web_request/web_request_permissions.h"
#include "extensions/browser/browser_context_keyed_api_factory.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_api_frame_id_map.h"
#include "extensions/browser/extension_function.h"
#include "extensions/browser/extension_registry_observer.h"
#include "extensions/common/url_pattern_set.h"
#include "ipc/ipc_sender.h"
#include "net/base/auth.h"
#include "net/base/completion_once_callback.h"
#include "net/http/http_request_headers.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
#include "services/network/public/mojom/websocket.mojom.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
class ExtensionWebRequestTimeTracker;
class GURL;
namespace base {
class DictionaryValue;
} // namespace base
namespace content {
class BrowserContext;
class RenderFrameHost;
} // namespace content
namespace net {
class AuthChallengeInfo;
class AuthCredentials;
class HttpRequestHeaders;
class HttpResponseHeaders;
class SiteForCookies;
} // namespace net
namespace extensions {
enum class WebRequestResourceType : uint8_t;
class WebRequestEventDetails;
struct WebRequestInfo;
class WebRequestRulesRegistry;
// Support class for the WebRequest API. Lives on the UI thread. Most of the
// work is done by ExtensionWebRequestEventRouter below. This class observes
// extensions::EventRouter to deal with event listeners. There is one instance
// per BrowserContext which is shared with incognito.
class WebRequestAPI : public BrowserContextKeyedAPI,
public EventRouter::Observer,
public ExtensionRegistryObserver {
public:
// A callback used to asynchronously respond to an intercepted authentication
// request. If |should_cancel| is true the request will be cancelled.
// Otherwise any supplied |credentials| will be used. If no credentials are
// supplied, default browser behavior will follow (e.g. UI prompt for login).
using AuthRequestCallback = base::OnceCallback<void(
const absl::optional<net::AuthCredentials>& credentials,
bool should_cancel)>;
// An interface which is held by ProxySet defined below.
class Proxy {
public:
virtual ~Proxy() {}
// Asks the Proxy to handle an auth request on behalf of one of its known
// in-progress network requests. If the request will *not* be handled by
// the proxy, |callback| should be invoked with |absl::nullopt|.
virtual void HandleAuthRequest(
const net::AuthChallengeInfo& auth_info,
scoped_refptr<net::HttpResponseHeaders> response_headers,
int32_t request_id,
AuthRequestCallback callback);
};
// A ProxySet is a set of proxies used by WebRequestAPI: It holds Proxy
// instances, and removes all proxies when it is destroyed.
class ProxySet {
public:
ProxySet();
ProxySet(const ProxySet&) = delete;
ProxySet& operator=(const ProxySet&) = delete;
~ProxySet();
// Add a Proxy.
void AddProxy(std::unique_ptr<Proxy> proxy);
// Remove a Proxy. The removed proxy is deleted upon this call.
void RemoveProxy(Proxy* proxy);
// Associates |proxy| with |id|. |proxy| must already be registered within
// this ProxySet.
//
// Each Proxy may be responsible for multiple requests, but any given
// request identified by |id| must be associated with only a single proxy.
void AssociateProxyWithRequestId(Proxy* proxy,
const content::GlobalRequestID& id);
// Disassociates |proxy| with |id|. |proxy| must already be registered
// within this ProxySet.
void DisassociateProxyWithRequestId(Proxy* proxy,
const content::GlobalRequestID& id);
Proxy* GetProxyFromRequestId(const content::GlobalRequestID& id);
void MaybeProxyAuthRequest(
const net::AuthChallengeInfo& auth_info,
scoped_refptr<net::HttpResponseHeaders> response_headers,
const content::GlobalRequestID& request_id,
AuthRequestCallback callback);
private:
// Although these members are initialized on the UI thread, we expect at
// least one memory barrier before actually calling Generate in the IO
// thread, so we don't protect them with a lock.
std::set<std::unique_ptr<Proxy>, base::UniquePtrComparator> proxies_;
// Bi-directional mapping between request ID and Proxy for faster lookup.
std::map<content::GlobalRequestID, Proxy*> request_id_to_proxy_map_;
std::map<Proxy*, std::set<content::GlobalRequestID>>
proxy_to_request_id_map_;
};
class RequestIDGenerator {
public:
RequestIDGenerator();
RequestIDGenerator(const RequestIDGenerator&) = delete;
RequestIDGenerator& operator=(const RequestIDGenerator&) = delete;
~RequestIDGenerator();
// Generates a WebRequest ID. If the same (routing_id,
// network_service_request_id) pair is passed to this as was previously
// passed to SaveID(), the |request_id| passed to SaveID() will be returned.
int64_t Generate(int32_t routing_id, int32_t network_service_request_id);
// This saves a WebRequest ID mapped to the (routing_id,
// network_service_request_id) pair. Clients must call Generate() with the
// same ID pair to retrieve the |request_id|, or else there may be a memory
// leak.
void SaveID(int32_t routing_id,
int32_t network_service_request_id,
uint64_t request_id);
private:
int64_t id_ = 0;
std::map<std::pair<int32_t, int32_t>, uint64_t> saved_id_map_;
};
explicit WebRequestAPI(content::BrowserContext* context);
WebRequestAPI(const WebRequestAPI&) = delete;
WebRequestAPI& operator=(const WebRequestAPI&) = delete;
~WebRequestAPI() override;
// BrowserContextKeyedAPI support:
static BrowserContextKeyedAPIFactory<WebRequestAPI>* GetFactoryInstance();
void Shutdown() override;
// EventRouter::Observer overrides:
void OnListenerRemoved(const EventListenerInfo& details) override;
// If any WebRequest event listeners are currently active for this
// BrowserContext, |*factory_request| is swapped out for a new request which
// proxies through an internal URLLoaderFactory. This supports lifetime
// observation and control on behalf of the WebRequest API.
// |frame| and |render_process_id| are the frame and render process id in
// which the URLLoaderFactory will be used. |frame| can be nullptr for
// factories proxied for service worker.
//
// Returns |true| if the URLLoaderFactory will be proxied; |false| otherwise.
bool MaybeProxyURLLoaderFactory(
content::BrowserContext* browser_context,
content::RenderFrameHost* frame,
int render_process_id,
content::ContentBrowserClient::URLLoaderFactoryType type,
absl::optional<int64_t> navigation_id,
ukm::SourceIdObj ukm_source_id,
mojo::PendingReceiver<network::mojom::URLLoaderFactory>* factory_receiver,
mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>*
header_client,
const url::Origin& request_initiator = url::Origin());
// Any request which requires authentication to complete will be bounced
// through this method.
//
// If this returns |true|, |callback| will eventually be invoked on the UI
// thread.
bool MaybeProxyAuthRequest(
content::BrowserContext* browser_context,
const net::AuthChallengeInfo& auth_info,
scoped_refptr<net::HttpResponseHeaders> response_headers,
const content::GlobalRequestID& request_id,
bool is_main_frame,
AuthRequestCallback callback);
// Starts proxying the connection with |factory|. This function can be called
// only when MayHaveProxies() returns true.
void ProxyWebSocket(
content::RenderFrameHost* frame,
content::ContentBrowserClient::WebSocketFactory factory,
const GURL& url,
const net::SiteForCookies& site_for_cookies,
const absl::optional<std::string>& user_agent,
mojo::PendingRemote<network::mojom::WebSocketHandshakeClient>
handshake_client);
// Starts proxying WebTransport handshake.
void ProxyWebTransport(
content::RenderProcessHost& render_process_host,
int frame_routing_id,
const GURL& url,
const url::Origin& initiator_origin,
mojo::PendingRemote<network::mojom::WebTransportHandshakeClient>
handshake_client,
content::ContentBrowserClient::WillCreateWebTransportCallback callback);
void ForceProxyForTesting();
// Indicates whether or not the WebRequestAPI may have one or more proxies
// installed to support the API.
bool MayHaveProxies() const;
bool HasExtraHeadersListenerForTesting();
private:
friend class BrowserContextKeyedAPIFactory<WebRequestAPI>;
// BrowserContextKeyedAPI support:
static const char* service_name() { return "WebRequestAPI"; }
static const bool kServiceRedirectedInIncognito = true;
static const bool kServiceIsNULLWhileTesting = true;
// Checks if |MayHaveProxies()| has changed from false to true, and resets
// URLLoaderFactories if so.
void UpdateMayHaveProxies();
// ExtensionRegistryObserver implementation.
void OnExtensionLoaded(content::BrowserContext* browser_context,
const Extension* extension) override;
void OnExtensionUnloaded(content::BrowserContext* browser_context,
const Extension* extension,
UnloadedExtensionReason reason) override;
// A count of active extensions for this BrowserContext that use web request
// permissions.
int web_request_extension_count_ = 0;
const raw_ptr<content::BrowserContext> browser_context_;
RequestIDGenerator request_id_generator_;
std::unique_ptr<ProxySet> proxies_;
// Stores the last result of |MayHaveProxies()|, so it can be used in
// |UpdateMayHaveProxies()|.
bool may_have_proxies_;
};
// This class observes network events and routes them to the appropriate
// extensions listening to those events. All methods must be called on the IO
// thread unless otherwise specified.
class ExtensionWebRequestEventRouter {
public:
struct BlockedRequest;
// The events denoting the lifecycle of a given network request.
enum EventTypes {
kInvalidEvent = 0,
kOnBeforeRequest = 1 << 0,
kOnBeforeSendHeaders = 1 << 1,
kOnSendHeaders = 1 << 2,
kOnHeadersReceived = 1 << 3,
kOnBeforeRedirect = 1 << 4,
kOnAuthRequired = 1 << 5,
kOnResponseStarted = 1 << 6,
kOnErrorOccurred = 1 << 7,
kOnCompleted = 1 << 8,
};
// Internal representation of the webRequest.RequestFilter type, used to
// filter what network events an extension cares about.
struct RequestFilter {
RequestFilter();
~RequestFilter();
RequestFilter(const RequestFilter&) = delete;
RequestFilter& operator=(const RequestFilter&) = delete;
RequestFilter(RequestFilter&& other);
RequestFilter& operator=(RequestFilter&& other);
// Returns false if there was an error initializing. If it is a user error,
// an error message is provided, otherwise the error is internal (and
// unexpected).
bool InitFromValue(const base::DictionaryValue& value, std::string* error);
extensions::URLPatternSet urls;
std::vector<WebRequestResourceType> types;
int tab_id;
int window_id;
};
// Contains an extension's response to a blocking event.
struct EventResponse {
EventResponse(const std::string& extension_id,
const base::Time& extension_install_time);
EventResponse(const EventResponse&) = delete;
EventResponse& operator=(const EventResponse&) = delete;
~EventResponse();
// ID of the extension that sent this response.
std::string extension_id;
// The time that the extension was installed. Used for deciding order of
// precedence in case multiple extensions respond with conflicting
// decisions.
base::Time extension_install_time;
// Response values. These are mutually exclusive.
bool cancel;
GURL new_url;
std::unique_ptr<net::HttpRequestHeaders> request_headers;
std::unique_ptr<extension_web_request_api_helpers::ResponseHeaders>
response_headers;
absl::optional<net::AuthCredentials> auth_credentials;
};
// AuthRequiredResponse indicates how an OnAuthRequired call is handled.
enum class AuthRequiredResponse {
// No credenitals were provided.
AUTH_REQUIRED_RESPONSE_NO_ACTION,
// AuthCredentials is filled in with a username and password, which should
// be used in a response to the provided auth challenge.
AUTH_REQUIRED_RESPONSE_SET_AUTH,
// The request should be canceled.
AUTH_REQUIRED_RESPONSE_CANCEL_AUTH,
// The action will be decided asynchronously. |callback| will be invoked
// when the decision is made, and one of the other AuthRequiredResponse
// values will be passed in with the same semantics as described above.
AUTH_REQUIRED_RESPONSE_IO_PENDING,
};
using AuthCallback = base::OnceCallback<void(AuthRequiredResponse)>;
static ExtensionWebRequestEventRouter* GetInstance();
// Registers a rule registry. Pass null for |rules_registry| to unregister
// the rule registry for |browser_context|.
void RegisterRulesRegistry(
content::BrowserContext* browser_context,
int rules_registry_id,
scoped_refptr<extensions::WebRequestRulesRegistry> rules_registry);
// Dispatches the OnBeforeRequest event to any extensions whose filters match
// the given request. Returns net::ERR_IO_PENDING if an extension is
// intercepting the request and OK if the request should proceed normally.
// net::ERR_BLOCKED_BY_CLIENT is returned if the request should be blocked. In
// this case, |should_collapse_initiator| might be set to true indicating
// whether the DOM element which initiated the request should be blocked.
int OnBeforeRequest(content::BrowserContext* browser_context,
WebRequestInfo* request,
net::CompletionOnceCallback callback,
GURL* new_url,
bool* should_collapse_initiator);
using BeforeSendHeadersCallback =
base::OnceCallback<void(const std::set<std::string>& removed_headers,
const std::set<std::string>& set_headers,
int error_code)>;
// Dispatches the onBeforeSendHeaders event. This is fired for HTTP(s)
// requests only, and allows modification of the outgoing request headers.
// Returns net::ERR_IO_PENDING if an extension is intercepting the request, OK
// otherwise.
int OnBeforeSendHeaders(content::BrowserContext* browser_context,
const WebRequestInfo* request,
BeforeSendHeadersCallback callback,
net::HttpRequestHeaders* headers);
// Dispatches the onSendHeaders event. This is fired for HTTP(s) requests
// only.
void OnSendHeaders(content::BrowserContext* browser_context,
const WebRequestInfo* request,
const net::HttpRequestHeaders& headers);
// Dispatches the onHeadersReceived event. This is fired for HTTP(s)
// requests only, and allows modification of incoming response headers.
// Returns net::ERR_IO_PENDING if an extension is intercepting the request,
// OK otherwise. |original_response_headers| is reference counted. |callback|
// |override_response_headers| and |preserve_fragment_on_redirect_url| are not
// owned but are guaranteed to be valid until |callback| is called or
// OnRequestWillBeDestroyed is called (whatever comes first).
// Do not modify |original_response_headers| directly but write new ones
// into |override_response_headers|.
int OnHeadersReceived(
content::BrowserContext* browser_context,
const WebRequestInfo* request,
net::CompletionOnceCallback callback,
const net::HttpResponseHeaders* original_response_headers,
scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
GURL* preserve_fragment_on_redirect_url);
// Dispatches the OnAuthRequired event to any extensions whose filters match
// the given request. If the listener is not registered as "blocking", then
// AUTH_REQUIRED_RESPONSE_NO_ACTION is returned. Otherwise,
// AUTH_REQUIRED_RESPONSE_IO_PENDING is returned and |callback| will be
// invoked later.
AuthRequiredResponse OnAuthRequired(content::BrowserContext* browser_context,
const WebRequestInfo* request,
const net::AuthChallengeInfo& auth_info,
AuthCallback callback,
net::AuthCredentials* credentials);
// Dispatches the onBeforeRedirect event. This is fired for HTTP(s) requests
// only.
void OnBeforeRedirect(content::BrowserContext* browser_context,
const WebRequestInfo* request,
const GURL& new_location);
// Dispatches the onResponseStarted event indicating that the first bytes of
// the response have arrived.
void OnResponseStarted(content::BrowserContext* browser_context,
const WebRequestInfo* request,
int net_error);
// Dispatches the onComplete event.
void OnCompleted(content::BrowserContext* browser_context,
const WebRequestInfo* request,
int net_error);
// Dispatches an onErrorOccurred event.
void OnErrorOccurred(content::BrowserContext* browser_context,
const WebRequestInfo* request,
bool started,
int net_error);
// Notificaties when |request| is no longer being processed, regardless of
// whether it has gone to completion or merely been cancelled. This is
// guaranteed to be called eventually for any request observed by this object,
// and |*request| will be immintently destroyed after this returns.
void OnRequestWillBeDestroyed(content::BrowserContext* browser_context,
const WebRequestInfo* request);
// Called when an event listener handles a blocking event and responds.
void OnEventHandled(content::BrowserContext* browser_context,
const std::string& extension_id,
const std::string& event_name,
const std::string& sub_event_name,
uint64_t request_id,
int render_process_id,
int web_view_instance_id,
int worker_thread_id,
int64_t service_worker_version_id,
EventResponse* response);
// Adds a listener to the given event. |event_name| specifies the event being
// listened to. |sub_event_name| is an internal event uniquely generated in
// the extension process to correspond to the given filter and
// extra_info_spec. It returns true on success, false on failure.
bool AddEventListener(content::BrowserContext* browser_context,
const std::string& extension_id,
const std::string& extension_name,
events::HistogramValue histogram_value,
const std::string& event_name,
const std::string& sub_event_name,
RequestFilter filter,
int extra_info_spec,
int render_process_id,
int web_view_instance_id,
int worker_thread_id,
int64_t service_worker_version_id);
// Removes the listeners for a given <webview>.
void RemoveWebViewEventListeners(content::BrowserContext* browser_context,
int render_process_id,
int web_view_instance_id);
// Called when an incognito browser_context is created or destroyed.
void OnOTRBrowserContextCreated(
content::BrowserContext* original_browser_context,
content::BrowserContext* otr_browser_context);
void OnOTRBrowserContextDestroyed(
content::BrowserContext* original_browser_context,
content::BrowserContext* otr_browser_context);
// Registers a |callback| that is executed when the next page load happens.
// The callback is then deleted.
void AddCallbackForPageLoad(base::OnceClosure callback);
// Whether there is a listener matching the request that has
// ExtraInfoSpec::EXTRA_HEADERS set.
bool HasExtraHeadersListenerForRequest(
content::BrowserContext* browser_context,
const WebRequestInfo* request);
// Whether there are any listeners for this context that have
// ExtraInfoSpec::EXTRA_HEADERS set.
bool HasAnyExtraHeadersListener(content::BrowserContext* browser_context);
void IncrementExtraHeadersListenerCount(
content::BrowserContext* browser_context);
void DecrementExtraHeadersListenerCount(
content::BrowserContext* browser_context);
// Called when a BrowserContext is being destroyed.
void OnBrowserContextShutdown(content::BrowserContext* browser_context);
// Get the number of listeners - for testing only.
size_t GetListenerCountForTesting(content::BrowserContext* browser_context,
const std::string& event_name);
size_t GetInactiveListenerCountForTesting(
content::BrowserContext* browser_context,
const std::string& event_name);
private:
friend class WebRequestAPI;
friend class base::NoDestructor<ExtensionWebRequestEventRouter>;
FRIEND_TEST_ALL_PREFIXES(ExtensionWebRequestTest, AddAndRemoveListeners);
FRIEND_TEST_ALL_PREFIXES(ExtensionWebRequestTest, BrowserContextShutdown);
struct EventListener {
struct ID {
ID(content::BrowserContext* browser_context,
const std::string& extension_id,
const std::string& sub_event_name,
int render_process_id,
int web_view_instance_id,
int worker_thread_id,
int64_t service_worker_version_id);
ID(const ID& source);
bool operator==(const ID& that) const;
raw_ptr<content::BrowserContext> browser_context;
std::string extension_id;
std::string sub_event_name;
// In the case of a webview, this is the process ID of the embedder.
int render_process_id;
int web_view_instance_id;
// The worker_thread_id and service_worker_version_id members are only
// meaningful for event listeners for ServiceWorker events. Otherwise,
// they are initialized to sentinel values.
int worker_thread_id;
int64_t service_worker_version_id;
};
EventListener(ID id);
EventListener(const EventListener&) = delete;
EventListener& operator=(const EventListener&) = delete;
~EventListener();
ID id;
std::string extension_name;
events::HistogramValue histogram_value = events::UNKNOWN;
RequestFilter filter;
int extra_info_spec = 0;
std::unordered_set<uint64_t> blocked_requests;
};
using RawListeners = std::vector<EventListener*>;
using ListenerIDs = std::vector<EventListener::ID>;
using Listeners = std::vector<std::unique_ptr<EventListener>>;
using ListenerMap = std::map<std::string, Listeners>;
// A collection of data associated with a given BrowserContext.
struct BrowserContextData {
BrowserContextData();
BrowserContextData(BrowserContextData&&);
~BrowserContextData();
// The listeners that are currently active (i.e., have a corresponding
// render process).
ListenerMap active_listeners;
// Listeners that are associated with currently-inactive lazy contexts.
// These can still match events, but don't have an active renderer process.
ListenerMap inactive_listeners;
// The number of listeners that request extra headers be included with their
// events. Modified through `IncrementExtraHeadersListenerCount()` and
// `DecrementExtraHeadersListenerCount()`.
int extra_headers_count = 0;
// The corresponding incognito or on-the-record context for this
// BrowserContext. That is, if this context is incognito, `cross_context`
// will point to the original context; if this context is the original,
// `cross_context` will point to the incognito context (if any).
content::BrowserContext* cross_context = nullptr;
};
using DataMap = std::map<content::BrowserContext*, BrowserContextData>;
using BlockedRequestMap = std::map<uint64_t, BlockedRequest>;
// Map of request_id -> bit vector of EventTypes already signaled
using SignaledRequestMap = std::map<uint64_t, int>;
using CallbacksForPageLoad = std::list<base::OnceClosure>;
// The type of listener removal.
enum class ListenerUpdateType {
// The listener was fully removed by the extension and the registration
// should be removed here.
kRemove,
// This is for a lazy listener where the "active" listener's process is shut
// down, but the listener should still be registered (and will be stored in
// `BrowserContextData::inactive_listeners`).
kDeactivate,
};
ExtensionWebRequestEventRouter();
ExtensionWebRequestEventRouter(const ExtensionWebRequestEventRouter&) =
delete;
ExtensionWebRequestEventRouter& operator=(
const ExtensionWebRequestEventRouter&) = delete;
// This instance is leaked.
~ExtensionWebRequestEventRouter() = delete;
// Returns the EventListener with the given |id|, or nullptr. Must be called
// from the IO thread.
EventListener* FindEventListener(const EventListener::ID& id);
// Returns the EventListener with the given |id| from |listeners|.
EventListener* FindEventListenerInContainer(const EventListener::ID& id,
Listeners& listeners);
// Updates the active listener registration indicated by the given criteria.
// `update_type` indicates whether the listener is fully removed or if it's
// a lazy listener that had its context shut down.
void UpdateActiveListener(ListenerUpdateType update_type,
content::BrowserContext* browser_context,
const ExtensionId& extension_id,
const std::string& sub_event_name,
int worker_thread_id,
int64_t service_worker_version_id);
// Removes a lazy listener registration. This affects both the provided
// `original_context` and any incognito context associated with it.
void RemoveLazyListener(content::BrowserContext* original_context,
const ExtensionId& extension_id,
const std::string& sub_event_name);
// Removes the listener from `listeners` that matches the given criteria.
// Optional criteria are ignored if not provided. Removes the matching
// listener, if any. Expects a maximum of one listener to match.
static std::unique_ptr<EventListener> RemoveMatchingListener(
Listeners& listeners,
const ExtensionId& extension_id,
const std::string& sub_event_name,
absl::optional<int> worker_thread_id,
absl::optional<int64_t> service_worker_version_id,
content::BrowserContext* browser_context);
// Cleans up for a listener being removed, unblocking any requests and
// updating counts as appropriate.
void CleanUpForListener(const EventListener& listener,
ListenerUpdateType removal_type);
// Ensures that future callbacks for |request| are ignored so that it can be
// destroyed safely.
void ClearPendingCallbacks(const WebRequestInfo& request);
bool DispatchEvent(content::BrowserContext* browser_context,
const WebRequestInfo* request,
const RawListeners& listener_ids,
std::unique_ptr<WebRequestEventDetails> event_details);
void DispatchEventToListeners(
content::BrowserContext* browser_context,
std::unique_ptr<ListenerIDs> listener_ids,
std::unique_ptr<WebRequestEventDetails> event_details);
// Returns a list of event listeners that care about the given event, based
// on their filter parameters. |extra_info_spec| will contain the combined
// set of extra_info_spec flags that every matching listener asked for.
RawListeners GetMatchingListeners(content::BrowserContext* browser_context,
const std::string& event_name,
const WebRequestInfo* request,
int* extra_info_spec);
// Returns true if the given `listener` matches the `request`.
// This needs to be a class method because `EventListener` is a private
// struct.
static bool ListenerMatchesRequest(const EventListener& listener,
const WebRequestInfo& request,
content::BrowserContext& browser_context,
bool is_request_from_extension,
bool crosses_incognito);
// Adds all listeners that match `request` from `listeners` into
// `listeners_out` and populates `extra_info_spec_out` with the set of all
// options on the matches listeners.
static void GetMatchingListenersForRequest(
const Listeners& listeners,
const WebRequestInfo& request,
content::BrowserContext& browser_context,
bool is_request_from_extension,
bool crosses_incognito,
RawListeners* listeners_out,
int* extra_info_spec_out);
// Decrements the count of event handlers blocking the given request. When the
// count reaches 0, we stop blocking the request and proceed it using the
// method requested by the extension with the highest precedence. Precedence
// is decided by extension install time. If |response| is non-NULL, this
// method assumes ownership.
void DecrementBlockCount(content::BrowserContext* browser_context,
const std::string& extension_id,
const std::string& event_name,
uint64_t request_id,
EventResponse* response,
int extra_info_spec);
// Processes the generated deltas from blocked_requests_ on the specified
// request. If |call_callback| is true, the callback registered in
// |blocked_requests_| is called.
// The function returns the error code for the network request. This is
// mostly relevant in case the caller passes |call_callback| = false
// and wants to return the correct network error code themself.
int ExecuteDeltas(content::BrowserContext* browser_context,
const WebRequestInfo* request,
bool call_callback);
// Evaluates the rules of the declarative webrequest API and stores
// modifications to the request that result from WebRequestActions as
// deltas in |blocked_requests_|. |filtered_response_headers| should only be
// set for the OnHeadersReceived stage and NULL otherwise. Returns whether any
// deltas were generated.
bool ProcessDeclarativeRules(
content::BrowserContext* browser_context,
const std::string& event_name,
const WebRequestInfo* request,
extensions::RequestStage request_stage,
const net::HttpResponseHeaders* filtered_response_headers);
// If the BlockedRequest contains messages_to_extension entries in the event
// deltas, we send them to subscribers of
// chrome.declarativeWebRequest.onMessage.
void SendMessages(content::BrowserContext* browser_context,
const BlockedRequest& blocked_request);
// Called when the RulesRegistry is ready to unblock a request that was
// waiting for said event.
void OnRulesRegistryReady(content::BrowserContext* browser_context,
const std::string& event_name,
uint64_t request_id,
extensions::RequestStage request_stage);
// Sets the flag that |event_type| has been signaled for |request_id|.
// Returns the value of the flag before setting it.
bool GetAndSetSignaled(uint64_t request_id, EventTypes event_type);
// Clears the flag that |event_type| has been signaled for |request_id|.
void ClearSignaled(uint64_t request_id, EventTypes event_type);
// Returns whether |request| represents a top level window navigation.
bool IsPageLoad(const WebRequestInfo& request) const;
// Called on a page load to process all registered callbacks.
void NotifyPageLoad();
// Returns the matching cross browser_context (the regular browser_context if
// |browser_context| is OTR and vice versa).
content::BrowserContext* GetCrossBrowserContext(
content::BrowserContext* browser_context) const;
// Returns true if |request| was already signaled to some event handlers.
bool WasSignaled(const WebRequestInfo& request) const;
// Helper for |HasAnyExtraHeadersListener()|.
bool HasAnyExtraHeadersListenerImpl(content::BrowserContext* browser_context);
// A map of data associated with given BrowserContexts.
DataMap data_;
// A map of network requests that are waiting for at least one event handler
// to respond.
BlockedRequestMap blocked_requests_;
// A map of request ids to a bitvector indicating which events have been
// signaled and should not be sent again.
SignaledRequestMap signaled_requests_;
// Keeps track of time spent waiting on extensions using the blocking
// webRequest API.
std::unique_ptr<ExtensionWebRequestTimeTracker> request_time_tracker_;
CallbacksForPageLoad callbacks_for_page_load_;
typedef std::pair<content::BrowserContext*, int> RulesRegistryKey;
// Maps each browser_context (and OTRBrowserContext) and a webview key to its
// respective rules registry.
std::map<RulesRegistryKey,
scoped_refptr<extensions::WebRequestRulesRegistry> > rules_registries_;
};
class WebRequestInternalFunction : public ExtensionFunction {
public:
WebRequestInternalFunction() {}
protected:
~WebRequestInternalFunction() override {}
const std::string& extension_id_safe() const {
return extension() ? extension_id() : base::EmptyString();
}
};
class WebRequestInternalAddEventListenerFunction
: public WebRequestInternalFunction {
public:
DECLARE_EXTENSION_FUNCTION("webRequestInternal.addEventListener",
WEBREQUESTINTERNAL_ADDEVENTLISTENER)
protected:
~WebRequestInternalAddEventListenerFunction() override {}
// ExtensionFunction:
ResponseAction Run() override;
};
class WebRequestInternalEventHandledFunction
: public WebRequestInternalFunction {
public:
DECLARE_EXTENSION_FUNCTION("webRequestInternal.eventHandled",
WEBREQUESTINTERNAL_EVENTHANDLED)
protected:
~WebRequestInternalEventHandledFunction() override {}
private:
// Unblocks the network request. Use this function when handling incorrect
// requests from the extension that cannot be detected by the schema
// validator.
void OnError(
const std::string& event_name,
const std::string& sub_event_name,
uint64_t request_id,
int render_process_id,
int web_view_instance_id,
std::unique_ptr<ExtensionWebRequestEventRouter::EventResponse> response);
// ExtensionFunction:
ResponseAction Run() override;
};
class WebRequestHandlerBehaviorChangedFunction
: public WebRequestInternalFunction {
public:
DECLARE_EXTENSION_FUNCTION("webRequest.handlerBehaviorChanged",
WEBREQUEST_HANDLERBEHAVIORCHANGED)
protected:
~WebRequestHandlerBehaviorChangedFunction() override {}
// ExtensionFunction:
void GetQuotaLimitHeuristics(
extensions::QuotaLimitHeuristics* heuristics) const override;
// Handle quota exceeded gracefully: Only warn the user but still execute the
// function.
void OnQuotaExceeded(std::string error) override;
ResponseAction Run() override;
};
} // namespace extensions
#endif // EXTENSIONS_BROWSER_API_WEB_REQUEST_WEB_REQUEST_API_H_