Use the chrome.experimental.webRequest module to intercept, block,
or modify requests in-flight. This module is still very much experimental. For
information on how to use experimental APIs, see the
chrome.experimental.* APIs page.
You must declare the "experimental" permission in the extension manifest to use the webRequest settings API. For example:
{
"name": "My extension",
...
"permissions": [
"experimental"
],
...
}
The webRequest API defines the following events:
onBeforeRequest (optionally synchronous)onBeforeSendHeaders (optionally synchronous)onBeforeSendHeaders event is passed to all subscribers, so
different subscribers may attempt to modify the request, see section conflict resolution for details how this is
handled. This event can still be used to cancel the request.onSendHeadersonResponseStartedonBeforeRedirectonCompletedonErrorOccurredonComplete or onErrorOccurred is fired as the final
event.
The life-cycle of successful requests can be illustrated as follows:
| v onBeforeRequest -------------------------------- | ^ | | [data and file URLs] | | | [redirection | | ------- | from extension] | v | | | onBeforeSendHeaders | | | | ^ | | | v | [auth] | | | onSendHeaders | | | | | | | | | v | | | | onBeforeRedirect <-- | | | v | onResponseStarted <----------------------------- | v onCompleted [auth] = In case of an basic/digest authentication request from server, we send another HTTP request with the respective headers.Note that this diagram does not capture a bug that will be fixed soon: If extensions redirect a URL request via the webRequest API, this redirection does not trigger
onBeforeRedirect. Instead the request is cancelled
and a new request is started at onBeforeRedirect. See http://crbug.com/79520.
(*) Note that the webRequest API presents an abstraction of the network stack to the extension. Internally, one URL request can be split into several HTTP requests (for example to fetch individual byte ranges from a large file) or can be handled by the network stack without communicating with the network. For this reason, the API does not provide the final HTTP headers that are sent to the network. For example all headers that are related to caching are invisible to the extension.
This is a list of headers that are currently not provided to the onBeforeSendHeaders signal. The list is not guaranteed to be complete nor stable:
The signals of the webRequest API follow certain concepts and patterns that shall be described in the following.
Each request is identified by a request ID. This ID is unique within a browser session and the context of an extension. It remains constant during the the life-cycle of a request and can be used to match signals for the same request.
For each signal XXX of the webRequest API, the API provides a function
chrome.experimental.webRequest.XXX.addListener() with the following
signature.
var callback = function(details) {...};
var opt_filter = {...};
var opt_extraInfoSpec = [...];
chrome.experimental.webRequest.XXX.addListener(
callback, opt_filter, opt_extraInfoSpec);
Each addListener() call takes a mandatory callback function as
the first parameter. This callback function is passed a dictionary containing
information about the current URL request. The information in this dictionary
depends on the specific event type as well as the content of
opt_extraInfoSpec.
If the optional opt_extraInfoSpec array contains the string
'blocking' (only allowed for specific signals), the callback
function is handled synchronously. That means that the request is blocked until
the callback function returns. In this case, the callback can return a BlockingResponse that determines the further
life-cycle of the request. Depending on the context, this response allows
cancelling or redirecting a request (onBeforeRequest), or cancelling or modifying
headers (onBeforeSendHeaders).
Depending on the specific signal, opt_extraInfoSpec may contain
further strings that indicate that specific information shall be passed to the
extension. This is used to provide detailed information on requests data only if
explicitly requested.
The optional RequestFilter
opt_filter allows to limit the requests for which events are
triggered in various dimensions:
*://www.google.com/foo*bar.main_frame (a document that is loaded for
a top-level frame), sub_frame (a document that is loaded for an
embedded frame), image (an image on a web site) and others. See
RequestFilter.In the current implementation of the webRequest API, a request is considered as canceled if at least one extension instructs to cancel the request. If an extension cancels a request, all extensions are notified by an onErrorOccurred event. Only one extension is allowed to redirect a request or modify a header at a time. If more than one extension attempts to modify the request, the most recently installed extension wins while all others are ignored. An extension is currently not notified, if its instruction to modify or redirect has been ignored.
It's important to note that some technical oddities in the OS's handling
of distinct Chrome processes can cause the clock to be skewed between the
browser itself and extension processes. That means that WebRequest's events'
timeStamp property is only guaranteed to be internally
consistent. Comparing one event to another event will give you the correct
offset between them, but comparing them to the current time inside the
extension (via (new Date()).getTime(), for instance) might give
unexpected results.
The following example illustrates how to block all requests to
www.evil.com:
chrome.experimental.webRequest.onBeforeRequest.addListener(
function(details) {
return {cancel: details.url.indexOf("://www.evil.com/") != -1};
},
{},
["blocking"]);
The following example achives the same goal in a more efficient way because
requests that are not targeted to www.evil.com do not need to be
passed to the extension:
chrome.experimental.webRequest.onBeforeRequest.addListener(
function(details) { return {cancel: true}; },
{"*://www.evil.com/*"},
["blocking"]);
The following example illustrates how the User-Agent header can be deleted from all requests:
chrome.experimental.webRequest.onBeforeSendHeaders.addListener(
function(details) {
delete details.requestHeaders['User-Agent'];
return {requestHeaders: details.requestHeaders};
},
{},
["blocking"]);
For efficiency reason, the webRequest API does not pass the URL of the frame that issued a request to each request. If this information is required, for example to distinguish between first and third party requests, this example shows how to track the URLs of frames.
// dictionary "windowId" -> "tabId"-"frameId" -> "frameUrl"
var frameUrl = {};
function recordFrameUrl(windowId, tabId, frameId, frameUrl) {
if (!frameUrl[windowId]) {
frameUrl[windowId] = {};
}
frameUrl[windowId][tabId + "-" + frameId] = frameUrl;
}
function getFrameUrl(windowId, tabId, frameId, frameUrl) {
return (frameUrl[windowId] || {})[tabId + "-" + frameId];
}
chrome.experimental.webRequest.onBeforeRequest.addListener(
function(d) {
if (d.type == 'main_frame' || d.type == 'sub_frame') {
recordFrameUrl(d.windowId, d.tabId, d.frameId, d.frameUrl);
}
var frameUrl = getFrameUrl(d.windowId, d.tabId, d.frameId);
// Use the frameUrl e.g. to selectively cancel requests.
// Attention: The frameUrl can be undefined in some cases. Requests may not
// originate from a frame (e.g. requests from extensions or shared workers).
});
chrome.windows.onRemoved.addListener(
function(windowId) {delete frameUrl[windowId];}
);