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 |