OverviewThis document describes the following API:
Use casesAn API of detailed Web progress notifications can be used to log traffic data, measure browser performance, etc. Please note that this requirement has been listed in the API Wish List (the Network item).
Could this API be part of the web platform?To the best of my knowledge, it could not.
Do you expect this API to be fairly stable?I think the API will be fairly stable, since the way how HTTP works, as well as how the browser handles Web page navigations, is mature and stable. However, as described in the Open questions section, there may be some improvements in the future.
What UI does this API expose?The API doesn’t expose any UI.
How could this API be abused?There may be privacy issues since extensions can collect detailed information about network traffic via this API.
How would you implement your desired features if this API didn't exist?Without this API,
Draft API specManifestIn order to use chrome.webRequest or chrome.webNavigation, the "web_progress" permission has to be declared in the permissions section of the extension manifest.
{ "name": "My extension", ... "permissions": [ "web_progress", "http://www.google.com/" ], ... } // This isn’t allowed since it requests extra information for any URL. chrome.webRequest.onBeforeRequest.addListener( function(object details) { ... }, null, ["requestHeaders"]); // This is allowed. chrome.webRequest.onBeforeRequest.addListener( function(object details) { ... }, {urls: ["http://www.google.com/foo*bar"]},
["requestHeaders"]); // This is allowed too, since it doesn’t request any extra information. chrome.webRequest.onBeforeRequest.addListener( function(object details) { ... }, {urls: ["http://www.youtube.com/*"]}); chrome.webRequest.onBeforeRequest.addListener( function(object details) { ... }, RequestFilter filter, array of string extraInfoSpec); Fires when a request is about to occur. This is sent before any TCP connection is made. Parameters
details (object)
The ID of the request. Request IDs are unique within a browser session. As a result, they could be used to relate different events of the same request.
filter (optional RequestFilter)
extraInfoSpec (optional array of string)
chrome.webRequest.onBeforeSendHeaders.addListener( function(object details) { ... }, RequestFilter filter, array of string extraInfoSpec); Fires when an HTTP request is about to occur. This may occur after a TCP connection is made to the server, but before any HTTP data is sent. The HTTP request headers are available at this point. Parameters details (object)
The ID of the request. Request IDs are unique within a browser session. As a result, they could be used to relate different events of the same request.
filter (optional RequestFilter)
extraInfoSpec (optional array of string)
onSendHeaderschrome.webRequest.onSendHeaders.addListener( function(object details) { ... }, RequestFilter filter, array of string extraInfoSpec); Fires just before the headers are sent to the server (after all users of the webrequest api had a chance to modify the request in onBeforeSendHeaders). Parameters
details (object)
filter (optional RequestFilter)
extraInfoSpec (optional array of string)
onResponseStartedchrome.webRequest.onResponseStarted.addListener( function(object details) { ... }, RequestFilter filter, array of string extraInfoSpec); Fires when the first byte of the response body is received. For HTTP requests, this means that the status line and response headers are available. Parameters
details (object)
filter (optional RequestFilter)
extraInfoSpec (optional array of string)
onBeforeRedirectchrome.webRequest.onBeforeRedirect.addListener( function(object details) { ... }, RequestFilter filter, array of string extraInfoSpec); Fires when a server initiated redirect is about to occur. Parameters
details (object)
filter (optional RequestFilter)
extraInfoSpec (optional array of string)
onCompletedchrome.webRequest.onCompleted.addListener( function(object details) { ... }, RequestFilter filter, array of string extraInfoSpec); Fires when a request is completed. Parameters
details (object)
filter (optional RequestFilter)
extraInfoSpec (optional array of string)
onErrorOccurredchrome.webRequest.onErrorOccurred.addListener( function(object details) { ... }, RequestFilter filter); Fires when an error occurs. Parameters
details (object)
filter (optional RequestFilter)
Event orderFor any successful request, events are fired in the following order:
onBeforeRequest -> onBeforeSendHeaders[1] -> onSendHeaders -> (onBeforeRedirect -> onBeforeRequest -> onBeforeSendHeaders[1] -> onSendHeaders ->)* -> onResponseStarted -> onCompleted[1] Note: onBeforeSendHeaders is only fired for HTTP requests. It will not be fired for e.g. file:/// URLs. The part enclosed in parentheses indicates that there may be zero or more server initiated redirects.
Any error that occurs during the process results in an onErrorOccurred event. For a specific request, there is no further events fired after onErrorOccurred.
chrome.webNavigationEventsonBeforeNavigatechrome.webNavigation.onBeforeNavigate.addListener(function(object details) { ... }); Fires when a navigation is about to occur. Parameters
details (object)
onCommittedchrome.webNavigation.onCommitted.addListener(function(object details) { ... }); Fires when a navigation is committed. The document (and the resources it refers to, such as images and subframes) might still be downloading, but at least part of the document has been received from the server and the browser has decided to switch to the new document. Parameters
details (object)
onDOMContentLoadedchrome.webNavigation.onDOMContentLoaded.addListener(function(object details) { ... }); Fires when the page’s DOM is fully constructed, but the referenced resources may not finish loading. Parameters
details (object)
onCompletedchrome.webNavigation.onCompleted.addListener(function(object details) { ... }); Fires when a document, including the resources it refers to, is completely loaded and initialized. Parameters
details (object)
onErrorOccurredchrome.webNavigation.onErrorOccurred.addListener(function(object details) { ... }); Fires when an error occurs. Parameters
details (object)
onBeforeRetargetchrome.webNavigation.onBeforeRetarget.addListener(function(object details) { ... }); Fires when a new window, or a new tab in an existing window, is about to be created to host a navigation. Parameters
details (object)
Event orderFor a navigation that is successfully completed, events are fired in the following order:
onBeforeNavigate -> onCommitted -> onDOMContentLoaded -> onCompleted Any error that occurs during the process results in an onErrorOccurred event. For a specific navigation, there is no further events fired after onErrorOccurred. Note that it is possible that a new navigation occurs in the same frame before the former navigation completes. As a result, even if a navigation proceeds successfully, the event sequence doesn’t necessarily end with an onCompleted.
If a navigating frame contains subframes, its onCommitted is fired before any of its children’s onBeforeNavigate; while its onCompleted is fired after any of its children’s onCompleted.
TypesRequest typesHow the requested resource will be used.
Transition qualifier valuesAny transition type can be augmented by qualifiers, which further define the navigation.
RequestFilter(object)
Open questionsAccessing request and response bodies from extensions?We could support extensions to specify "requestBody" element in the extraInfoSpec array of chrome.webRequest.onBeforeRequest (or onRequestSent), so that an extra property, requestBody, will be added to the details object passed into the event handler. Similarly, we could support extensions to ask for responseBody, too.
Both requestBody and responseBody are EntityBody objects.
EntityBodyMethodsreadBytes(integer length, boolean wait, function callback) Parameters
length (integer)
wait (boolean)
callback (function)
Callback function
It should specify a function that looks like this:
function (integer actualLength, string base64EncodedData) actualLength (integer)
base64EncodedData (string)
Some issues need to be considered:
As a result, the browser has to properly manage the lifetime of request bodies and response bodies. One possible approach is to keep track of references to each EntityBody object (either requestBody or responseBody). An entity body maybe be accessed by several EntityBody objects, which are passed to different extensions. If all these EntityBody objects are no longer referenced, the browser knows that the entity body is no long needed by any extension, and it is safe to remove it.
// entityBody is an EntityBody object, which deals with bytes. var textEntityBody = new TextEntityBody(entityBody, ‘UTF-8’); // textEntityBody calls entityBody.readBytes() and converts the result to text. textEntityBody.readText(10, true, function (text, reachEnd) { // Handle text directly. });
Synchronous (blocking) notifications?The API proposed above is supposed to be asynchronous (non-blocking) notifications. This is consistent with other chrome.* APIs. More importantly, notification publishers / consumers live in different processes. If we block the publisher side for sending each notifications, it may hurt browser performance.
However, in some cases we would like to affect the control flow in event handlers. (Please note that this has been listed as a requirement on the API Wish List, the Navigation Interception item.)
Consider the following use case: in the callback function of chrome.webRequest.onBeforeRequest we may want to cancel the request or modify the request headers. If the notification is asynchronous, the browser fires the notification and immediately makes the request. There is no way for extensions to make a change.
One possible solution is to design some functions like "installSyncOnXyzHandler" that installs a short snippet of JavaScript to run synchronously within the browser process for the notifications that may need synchronous responses. However, this may not fit with the overall Chrome architecture where we want to avoid running javascript in the browser process; and the JavaScript snippet in the browser process might need to communicate back to the extension for some of its decisions as well.
Another feasible solution is to add support for browser to wait for a response from an extension. Take chrome.webRequest.onBeforeRequest as an example, we could reform it the extraInfoSpec parameter to accept an optional string "blocking". If present, then the browser needs to be blocked and wait for a response from the callback function. If blocking is present, the callback function could optionally return an object to cancel or modify the request:
result (optional object)
redirectUrl (optional string) The biggest concern is the impact on browser performance. We have to measure the performance impact very carefully if we really want to make the move.
References |
For Developers > Design Documents > Extensions > Proposed & Proposing New Changes > API Proposals (New APIs Start Here) >