| OLD | NEW |
| (Empty) |
| 1 <div id="pageData-name" class="pageData">WebRequest API</div> | |
| 2 | |
| 3 <!-- BEGIN AUTHORED CONTENT --> | |
| 4 <p id="classSummary"> | |
| 5 Use the <code>chrome.experimental.webRequest</code> module to intercept, block, | |
| 6 or modify requests in-flight. This module is still experimental. For | |
| 7 information on how to use experimental APIs, see the | |
| 8 <a href="experimental.html">chrome.experimental.* APIs</a> page. | |
| 9 </p> | |
| 10 | |
| 11 <h2 id="manifest">Manifest</h2> | |
| 12 <p>You must declare the "experimental" permission in the <a | |
| 13 href="manifest.html">extension manifest</a> to use the webRequest settings | |
| 14 API, along with <a href="manifest.html#permissions">host permissions</a> | |
| 15 for any hosts whose network requests you want to access. | |
| 16 For example:</p> | |
| 17 <pre>{ | |
| 18 "name": "My extension", | |
| 19 ... | |
| 20 <b>"permissions": [ | |
| 21 "experimental", | |
| 22 "*://*.google.com" | |
| 23 ]</b>, | |
| 24 ... | |
| 25 }</pre> | |
| 26 | |
| 27 <h2 id="life_cycle">Life-cycle of requests</h2> | |
| 28 | |
| 29 <p> | |
| 30 The webRequest API defines the following events: | |
| 31 <dl> | |
| 32 <dt><code>onBeforeRequest (optionally synchronous)</code></dt> | |
| 33 <dd>Fires when a request is about to occur. This is sent before any TCP | |
| 34 connection is made and can be used to cancel or redirect requests.</dd> | |
| 35 <dt><code>onBeforeSendHeaders (optionally synchronous)</code></dt> | |
| 36 <dd>Fires when a request is about to occur and the initial headers are | |
| 37 prepared. The event is intended to allow extensions to add, modify and delete | |
| 38 request headers <a href="#life_cycle_footnote">(*)</a>. The | |
| 39 <code>onBeforeSendHeaders</code> event is passed to all subscribers, so | |
| 40 different subscribers may attempt to modify the request, see section <a | |
| 41 href="#conflict_resolution">conflict resolution</a> for details how this is | |
| 42 handled. This event can still be used to cancel the request.</dd> | |
| 43 <dt><code>onSendHeaders</code></dt> | |
| 44 <dd>Fires after all extensions had a chance of modifying the request headers | |
| 45 and presents the final <a href="#life_cycle_footnote">(*)</a> version. The | |
| 46 event is triggered, before the headers are sent to the network. This event is | |
| 47 informational and handled asynchronously. It does not allow to modify or | |
| 48 cancel the request.</dd> | |
| 49 <dt><code>onHeadersReceived (optionally synchronous)</code></dt> | |
| 50 <dd>Fires each time when a HTTP(S) response header has been received. Due | |
| 51 to redirects and authentication requests this can happen multiple times per | |
| 52 request. This event is intended to allow extensions to add, modify and delete | |
| 53 response headers, like incoming Set-Cookie headers for example.</dd> | |
| 54 <dt><code>onAuthRequired (optionally synchronous)</code></dt> | |
| 55 <dd>Fires when a request requires authentication of the user. This signal can | |
| 56 be handled synchronously to provide authentication credentials. Note that | |
| 57 extensions may provide invalid credentials. Take care not to enter an infinite | |
| 58 loop by repeatedly providing invalid credentials.</dd> | |
| 59 <dt><code>onBeforeRedirect</code></dt> | |
| 60 <dd>Fires before a redirect is about to be executed. A redirection can be | |
| 61 triggered by a HTTP response code or by an extension. This event is | |
| 62 informational and handled asynchronously. It does not allow you to modify or | |
| 63 cancel the request. </dd> | |
| 64 <dt><code>onResponseStarted</code></dt> | |
| 65 <dd>Fires when the first byte of the response body is received. For HTTP | |
| 66 requests, this means that the status line and response headers are | |
| 67 available. This event is informational and handled asynchronously. It does not | |
| 68 allow to modify or cancel the request.</dd> | |
| 69 <dt><code>onCompleted</code></dt> | |
| 70 <dd>Fires when a request has been processed successfully.</dd> | |
| 71 <dt><code>onErrorOccurred</code></dt> | |
| 72 <dd>Fires when a request could not be processed successfully.</dd> | |
| 73 </dl> | |
| 74 The webRequest API gurantees that for each request either | |
| 75 <code>onComplete</code> or <code>onErrorOccurred</code> is fired as the final | |
| 76 event. | |
| 77 </p> | |
| 78 | |
| 79 <p> | |
| 80 The life-cycle of successful requests can be illustrated as follows: | |
| 81 <pre> | |
| 82 | | |
| 83 v | |
| 84 onBeforeRequest -------------------------------- | |
| 85 | ^ | | [data and file URLs] | |
| 86 | | | [redirection | | |
| 87 | ---------- | from extension] | | |
| 88 v | | | | |
| 89 onBeforeSendHeaders | | | | |
| 90 | ^ | | | | |
| 91 v | | | | | |
| 92 onSendHeaders | | | | | |
| 93 | | | | | | |
| 94 v | | | | | |
| 95 onHeadersReceived | | | | | |
| 96 | | | | | | | | |
| 97 | | v | | | | | |
| 98 | | onAuthRequired / | | | |
| 99 | v / | | | |
| 100 | onBeforeRedirect <---- | | |
| 101 v | | |
| 102 onResponseStarted <----------------------------- | |
| 103 | | |
| 104 v | |
| 105 onCompleted | |
| 106 </pre> | |
| 107 <em>Note that this diagram does not capture a bug that will be fixed soon: If | |
| 108 extensions redirect a URL request via the webRequest API, this redirection does | |
| 109 not trigger <code>onBeforeRedirect</code>. Instead the request is cancelled | |
| 110 and a new request is started at <code>onBeforeRedirect</code>. See <a | |
| 111 href="http://crbug.com/79520">http://crbug.com/79520</a>.</em> | |
| 112 </p> | |
| 113 | |
| 114 <p id="life_cycle_footnote">(*) Note that the webRequest API presents an | |
| 115 abstraction of the network stack to the extension. Internally, one URL request | |
| 116 can be split into several HTTP requests (for example to fetch individual byte | |
| 117 ranges from a large file) or can be handled by the network stack without | |
| 118 communicating with the network. For this reason, the API does not provide the | |
| 119 final HTTP headers that are sent to the network. For example all headers that | |
| 120 are related to caching are invisible to the extension.</p> | |
| 121 | |
| 122 <p>This is a list of headers that are currently not provided to the | |
| 123 onBeforeSendHeaders signal. The list is not guaranteed to be complete nor | |
| 124 stable: | |
| 125 <ul> | |
| 126 <li>Authorization</li> | |
| 127 <li>Cache-Control</li> | |
| 128 <li>Connection</li> | |
| 129 <li>Content-Length</li> | |
| 130 <li>Host</li> | |
| 131 <li>If-Modified-Since</li> | |
| 132 <li>If-None-Match</li> | |
| 133 <li>If-Range</li> | |
| 134 <li>Partial-Data</li> | |
| 135 <li>Pragma</li> | |
| 136 <li>Proxy-Authorization</li> | |
| 137 <li>Proxy-Connection</li> | |
| 138 <li>Transfer-Encoding</li> | |
| 139 </ul> | |
| 140 </p> | |
| 141 | |
| 142 <h2 id="concepts">Concepts of the webRequest API</h2> | |
| 143 | |
| 144 <p>The signals of the webRequest API follow certain concepts and patterns that | |
| 145 shall be described in the following.</p> | |
| 146 | |
| 147 <h3 id="Request IDs">Request IDs</h3> | |
| 148 | |
| 149 <p>Each request is identified by a request ID. This ID is unique within a | |
| 150 browser session and the context of an extension. It remains constant during the | |
| 151 the life-cycle of a request and can be used to match signals for the same | |
| 152 request. Note that several HTTP requests are mapped to one webRequest in case of | |
| 153 HTTP redirection or HTTP authentication.</p> | |
| 154 | |
| 155 <h3 id="subscription">Subscription</h3> | |
| 156 | |
| 157 <p>For each signal XXX of the webRequest API, the API provides a function | |
| 158 <code>chrome.experimental.webRequest.XXX.addListener()</code> with the following | |
| 159 signature.</p> | |
| 160 | |
| 161 <pre> | |
| 162 var callback = function(details) {...}; | |
| 163 var opt_filter = {...}; | |
| 164 var opt_extraInfoSpec = [...]; | |
| 165 | |
| 166 chrome.experimental.webRequest.XXX.addListener( | |
| 167 callback, opt_filter, opt_extraInfoSpec); | |
| 168 </pre> | |
| 169 | |
| 170 <p>Each <code>addListener()</code> call takes a mandatory callback function as | |
| 171 the first parameter. This callback function is passed a dictionary containing | |
| 172 information about the current URL request. The information in this dictionary | |
| 173 depends on the specific event type as well as the content of | |
| 174 <code>opt_extraInfoSpec</code>.</p> | |
| 175 | |
| 176 <p>If the optional <code>opt_extraInfoSpec</code> array contains the string | |
| 177 <code>'blocking'</code> (only allowed for specific signals), the callback | |
| 178 function is handled synchronously. That means that the request is blocked until | |
| 179 the callback function returns. In this case, the callback can return a <a | |
| 180 href="#type-BlockingResponse">BlockingResponse</a> that determines the further | |
| 181 life-cycle of the request. Depending on the context, this response allows | |
| 182 cancelling or redirecting a request (onBeforeRequest), cancelling or | |
| 183 modifying headers (onBeforeSendHeaders, onHeadersReceived), or providing | |
| 184 authentication credentials (onAuthRequired).</p> | |
| 185 | |
| 186 <p>Depending on the specific signal, <code>opt_extraInfoSpec</code> may contain | |
| 187 further strings that indicate that specific information shall be passed to the | |
| 188 extension. This is used to provide detailed information on requests data only if | |
| 189 explicitly requested.</p> | |
| 190 | |
| 191 <p>The optional <a href="#type-RequestFilter">RequestFilter</a> | |
| 192 <code>opt_filter</code> allows to limit the requests for which events are | |
| 193 triggered in various dimensions: | |
| 194 <dl> | |
| 195 <dt>URLs</dt> | |
| 196 <dd>URL patterns like <code>*://www.google.com/foo*bar</code>.</dd> | |
| 197 <dt>Types</dt> | |
| 198 <dd>Request types like <code>main_frame</code> (a document that is loaded for | |
| 199 a top-level frame), <code>sub_frame</code> (a document that is loaded for an | |
| 200 embedded frame), <code>image</code> (an image on a web site) and others. See | |
| 201 <a href="#type-RequestFilter">RequestFilter</a>.</dd> | |
| 202 <dt>Tab IDs</dt> | |
| 203 <dd>The ID that identifies a specific tab in a window.</dd> | |
| 204 <dt>Window IDs</dt> | |
| 205 <dd>The ID that identifies a specific window.</dd> | |
| 206 </p> | |
| 207 | |
| 208 <h2 id="conflict_resolution">Conflict resolution</h2> | |
| 209 | |
| 210 <p>In the current implementation of the webRequest API, a request is considered | |
| 211 as canceled if at least one extension instructs to cancel the request. If | |
| 212 an extension cancels a request, all extensions are notified by an | |
| 213 onErrorOccurred event. Only one extension is allowed to redirect a request or | |
| 214 modify a header at a time. If more than one extension attempts to modify the | |
| 215 request, the most recently installed extension wins while all others are | |
| 216 ignored. An extension is currently not notified, if its instruction to modify or | |
| 217 redirect has been ignored.</p> | |
| 218 | |
| 219 <h2>A note about caching</h2> | |
| 220 <p> | |
| 221 Chrome employs two caches, an on-disk cache and a very fast in-memory cache. | |
| 222 The life-time of an in-memory cache is attached to the life-time of a render | |
| 223 process which roughly corresponds to a tab. Requests that are answered from the | |
| 224 in-memory cache are invisible to the webRequest API. If a request handler | |
| 225 changes its behavior (for example the behavior according to which requests are | |
| 226 blocked), a simple page refresh might not respect this changed behavior. | |
| 227 <code>chrome.experimental.webRequest.handlerBehaviorChanged()</code> needs to be | |
| 228 called to flush the in-memory cache. This is a very expensive operation and | |
| 229 should not be done often. | |
| 230 </p> | |
| 231 | |
| 232 <h2>A note about timestamps</h2> | |
| 233 <p> | |
| 234 It's important to note that some technical oddities in the OS's handling | |
| 235 of distinct Chrome processes can cause the clock to be skewed between the | |
| 236 browser itself and extension processes. That means that WebRequest's events' | |
| 237 <code>timeStamp</code> property is only guaranteed to be <i>internally</i> | |
| 238 consistent. Comparing one event to another event will give you the correct | |
| 239 offset between them, but comparing them to the current time inside the | |
| 240 extension (via <code>(new Date()).getTime()</code>, for instance) might give | |
| 241 unexpected results. | |
| 242 </p> | |
| 243 | |
| 244 <h2 id="examples">Examples</h2> | |
| 245 | |
| 246 <p>The following example illustrates how to block all requests to | |
| 247 <code>www.evil.com</code>:</p> | |
| 248 <pre> | |
| 249 chrome.experimental.webRequest.onBeforeRequest.addListener( | |
| 250 function(details) { | |
| 251 return {cancel: details.url.indexOf("://www.evil.com/") != -1}; | |
| 252 }, | |
| 253 {}, | |
| 254 ["blocking"]); | |
| 255 </pre> | |
| 256 | |
| 257 <p>The following example achives the same goal in a more efficient way because | |
| 258 requests that are not targeted to <code>www.evil.com</code> do not need to be | |
| 259 passed to the extension:</p> | |
| 260 <pre> | |
| 261 chrome.experimental.webRequest.onBeforeRequest.addListener( | |
| 262 function(details) { return {cancel: true}; }, | |
| 263 {urls: ["*://www.evil.com/*"]}, | |
| 264 ["blocking"]); | |
| 265 </pre> | |
| 266 | |
| 267 <p>The following example illustrates how the User-Agent header can be deleted | |
| 268 from all requests:</p> | |
| 269 <pre> | |
| 270 chrome.experimental.webRequest.onBeforeSendHeaders.addListener( | |
| 271 function(details) { | |
| 272 delete details.requestHeaders['User-Agent']; | |
| 273 return {requestHeaders: details.requestHeaders}; | |
| 274 }, | |
| 275 {}, | |
| 276 ["blocking"]); | |
| 277 </pre> | |
| 278 | |
| 279 <!-- | |
| 280 TODO(mkwst): update this section. We do not pass windowIds any more. | |
| 281 http://crbug.com/98937 | |
| 282 | |
| 283 <h3 id="tracking_frames">Tracking frames</h3> | |
| 284 <p>For efficiency reason, the webRequest API does not pass the URL of the frame | |
| 285 that issued a request to each request. If this information is required, for | |
| 286 example to distinguish between first and third party requests, this example | |
| 287 shows how to track the URLs of frames.</p> | |
| 288 <pre> | |
| 289 // dictionary "windowId" -> "tabId"-"frameId" -> "frameUrl" | |
| 290 var frameUrl = {}; | |
| 291 | |
| 292 function recordFrameUrl(windowId, tabId, frameId, frameUrl) { | |
| 293 if (!frameUrl[windowId]) { | |
| 294 frameUrl[windowId] = {}; | |
| 295 } | |
| 296 frameUrl[windowId][tabId + "-" + frameId] = frameUrl; | |
| 297 } | |
| 298 | |
| 299 function getFrameUrl(windowId, tabId, frameId, frameUrl) { | |
| 300 return (frameUrl[windowId] || {})[tabId + "-" + frameId]; | |
| 301 } | |
| 302 | |
| 303 chrome.experimental.webRequest.onBeforeRequest.addListener( | |
| 304 function(d) { | |
| 305 if (d.type == 'main_frame' || d.type == 'sub_frame') { | |
| 306 recordFrameUrl(d.windowId, d.tabId, d.frameId, d.frameUrl); | |
| 307 } | |
| 308 var frameUrl = getFrameUrl(d.windowId, d.tabId, d.frameId); | |
| 309 // Use the frameUrl e.g. to selectively cancel requests. | |
| 310 // Attention: The frameUrl can be undefined in some cases. Requests may not | |
| 311 // originate from a frame (e.g. requests from extensions or shared workers). | |
| 312 }); | |
| 313 | |
| 314 chrome.windows.onRemoved.addListener( | |
| 315 function(windowId) {delete frameUrl[windowId];} | |
| 316 ); | |
| 317 </pre> | |
| 318 --> | |
| 319 <!-- END AUTHORED CONTENT --> | |
| OLD | NEW |