Index: chrome/test/data/extensions/api_test/webrequest/events/test.html |
diff --git a/chrome/test/data/extensions/api_test/webrequest/events/test.html b/chrome/test/data/extensions/api_test/webrequest/events/test.html |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c692844cfc4da5f29471d50229878f33c0a3ace0 |
--- /dev/null |
+++ b/chrome/test/data/extensions/api_test/webrequest/events/test.html |
@@ -0,0 +1,928 @@ |
+<script> |
+var getURL = chrome.extension.getURL; |
+var deepEq = chrome.test.checkDeepEq; |
+var expectedEventData; |
+var capturedEventData; |
+var expectedEventOrder; |
+var tabId; |
+var eventsCaptured; |
+ |
+// PORT will be changed to the port of the test server. |
+var URL_HTTP_SIMPLE_LOAD = |
+ 'http://www.a.com:PORT/files/extensions/api_test/webrequest/events/simpleLoad/a.html'; |
+var URL_HTTP_SIMPLE_LOAD_REDIRECT = |
+ 'http://www.a.com:PORT/server-redirect?'+URL_HTTP_SIMPLE_LOAD; |
+var URL_ECHO_USER_AGENT = |
+ 'http://www.a.com:PORT/echoheader?User-Agent'; |
+var URL_AUTH_REQUIRED = |
+ 'http://www.a.com:PORT/auth-basic'; |
+var URL_HTTP_XHR = |
+ 'http://www.a.com:PORT/files/extensions/api_test/webrequest/events/xhr/a.html'; |
+var URL_HTTP_XHR_DATA = |
+ 'http://www.a.com:PORT/files/extensions/api_test/webrequest/events/xhr/data.json'; |
+ |
+function runTests(tests) { |
+ chrome.tabs.getSelected(null, function(tab) { |
+ tabId = tab.id; |
+ chrome.test.getConfig(function(config) { |
+ var fixPort = function(url) { |
+ return url.replace(/PORT/g, config.testServer.port); |
+ }; |
+ URL_HTTP_SIMPLE_LOAD = fixPort(URL_HTTP_SIMPLE_LOAD); |
+ URL_HTTP_SIMPLE_LOAD_REDIRECT = fixPort(URL_HTTP_SIMPLE_LOAD_REDIRECT); |
+ URL_ECHO_USER_AGENT = fixPort(URL_ECHO_USER_AGENT); |
+ URL_AUTH_REQUIRED = fixPort(URL_AUTH_REQUIRED); |
+ URL_HTTP_XHR = fixPort(URL_HTTP_XHR); |
+ URL_HTTP_XHR_DATA = fixPort(URL_HTTP_XHR_DATA); |
+ |
+ chrome.test.runTests(tests); |
+ }); |
+ }); |
+} |
+ |
+// Helper to advance to the next test only when the tab has finished loading. |
+// This is because tabs.update can sometimes fail if the tab is in the middle |
+// of a navigation (from the previous test), resulting in flakiness. |
+function navigateAndWait(url, callback) { |
+ var done = chrome.test.listenForever(chrome.tabs.onUpdated, |
+ function (_, info, tab) { |
+ if (tab.id == tabId && info.status == "complete") { |
+ if (callback) callback(); |
+ done(); |
+ } |
+ }); |
+ chrome.tabs.update(tabId, {url: url}); |
+} |
+ |
+// data: array of extected events, each one is a dictionary: |
+// { label: "<unique identifier>", |
+// event: "<webrequest event type>", |
+// details: { <expected details of the webrequest event> }, |
+// retval: { <dictionary that the event handler shall return> } (optional) |
+// } |
+// order: an array of sequences, e.g. [ ["a", "b", "c"], ["d", "e"] ] means that |
+// event with label "a" needs to occur before event with label "b". The |
+// relative order of "a" and "d" does not matter. |
+// filter: filter dictionary passed on to the event subscription of the |
+// webRequest API. |
+// extraInfoSpec: the union of all desired extraInfoSpecs for the events. |
+function expect(data, order, filter, extraInfoSpec) { |
+ expectedEventData = data; |
+ capturedEventData = []; |
+ expectedEventOrder = order; |
+ eventsCaptured = chrome.test.callbackAdded(); |
+ tabAndFrameUrls = {}; // Maps "{tabId}-{frameId}" to the URL of the frame. |
+ removeListeners(); |
+ initListeners(filter || {}, extraInfoSpec || []); |
+} |
+ |
+function checkExpectations() { |
+ if (capturedEventData.length < expectedEventData.length) { |
+ return; |
+ } |
+ if (capturedEventData.length > expectedEventData.length) { |
+ chrome.test.fail("Recorded too many events. " + |
+ JSON.stringify(capturedEventData)); |
+ return; |
+ } |
+ // We have ensured that capturedEventData contains exactly the same elements |
+ // as expectedEventData. Now we need to verify the ordering. |
+ // Step 1: build positions such that |
+ // positions[<event-label>]=<position of this event in capturedEventData> |
+ var curPos = 0; |
+ var positions = {} |
+ capturedEventData.forEach(function (event) { |
+ chrome.test.assertTrue(event.hasOwnProperty("label")); |
+ positions[event.label] = curPos; |
+ curPos++; |
+ }); |
+ // Step 2: check that elements arrived in correct order |
+ expectedEventOrder.forEach(function (order) { |
+ var previousLabel = undefined; |
+ order.forEach(function(label) { |
+ if (previousLabel === undefined) { |
+ previousLabel = label; |
+ return; |
+ } |
+ chrome.test.assertTrue(positions[previousLabel] < positions[label], |
+ "Event " + previousLabel + " is supposed to arrive before " + |
+ label + "."); |
+ previousLabel = label; |
+ }); |
+ }); |
+ |
+ eventsCaptured(); |
+} |
+ |
+// Simple check to see that we have a User-Agent header, and that it contains |
+// an expected value. This is a basic check that the request headers are valid. |
+function checkUserAgent(headers) { |
+ for (var i in headers) { |
+ if (headers[i].name.toLowerCase() == "user-agent") |
+ return headers[i].value.toLowerCase().indexOf("chrome") != -1; |
+ } |
+ return false; |
+} |
+ |
+function captureEvent(name, details) { |
+ // Ignore system-level requests like safebrowsing updates and favicon fetches |
+ // since they are unpredictable. |
+ if (details.tabId == -1 || details.type == "other" || |
+ details.url.match(/\/favicon.ico$/) || |
+ details.url.match(/https:\/\/dl.google.com/)) |
+ return; |
+ |
+ // Pull the extra per-event options out of the expected data. These let |
+ // us specify special return values per event. |
+ var currentIndex = capturedEventData.length; |
+ var extraOptions; |
+ if (expectedEventData.length > currentIndex) { |
+ retval = expectedEventData[currentIndex].retval; |
+ } |
+ |
+ // Check that the frameId can be used to reliably determine the URL of the |
+ // frame that caused requests. |
+ if (name == "onBeforeRequest") { |
+ chrome.test.assertTrue('frameId' in details && |
+ typeof details.frameId === 'number'); |
+ chrome.test.assertTrue('tabId' in details && |
+ typeof details.tabId === 'number'); |
+ var key = details.tabId + "-" + details.frameId; |
+ if (details.type == "main_frame" || details.type == "sub_frame") { |
+ tabAndFrameUrls[key] = details.url; |
+ } |
+ details.frameUrl = tabAndFrameUrls[key] || "unknown frame URL"; |
+ } |
+ delete details.frameId; |
+ |
+ delete details.requestId; |
+ delete details.timeStamp; |
+ if (details.requestHeaders) { |
+ details.requestHeadersValid = checkUserAgent(details.requestHeaders); |
+ delete details.requestHeaders; |
+ } |
+ if (details.responseHeaders) { |
+ details.responseHeadersExist = true; |
+ delete details.responseHeaders; |
+ } |
+ |
+ // find |details| in expectedEventData |
+ var found = false; |
+ var label = undefined; |
+ expectedEventData.forEach(function (exp) { |
+ if (deepEq(exp.event, name) && deepEq(exp.details, details)) { |
+ if (found) { |
+ chrome.test.fail("Received event twice '" + name + "':" + |
+ JSON.stringify(details)); |
+ } else { |
+ found = true; |
+ label = exp.label; |
+ } |
+ } |
+ }); |
+ if (!found) { |
+ chrome.test.fail("Received unexpected event '" + name + "':" + |
+ JSON.stringify(details)); |
+ } |
+ |
+ capturedEventData.push({label: label, event: name, details: details}); |
+ checkExpectations(); |
+ return retval; |
+} |
+ |
+// Simple array intersection. We use this to filter extraInfoSpec so |
+// that only the allowed specs are sent to each listener. |
+function intersect(array1, array2) { |
+ return array1.filter(function(x) { return array2.indexOf(x) != -1; }); |
+} |
+ |
+function initListeners(filter, extraInfoSpec) { |
+ chrome.experimental.webRequest.onBeforeRequest.addListener( |
+ function(details) { |
+ return captureEvent("onBeforeRequest", details); |
+ }, filter, intersect(extraInfoSpec, ["blocking"])); |
+ chrome.experimental.webRequest.onBeforeSendHeaders.addListener( |
+ function(details) { |
+ return captureEvent("onBeforeSendHeaders", details); |
+ }, filter, intersect(extraInfoSpec, ["blocking", "requestHeaders"])); |
+ chrome.experimental.webRequest.onSendHeaders.addListener( |
+ function(details) { |
+ return captureEvent("onSendHeaders", details); |
+ }, filter, intersect(extraInfoSpec, ["requestHeaders"])); |
+ chrome.experimental.webRequest.onAuthRequired.addListener( |
+ function(details) { |
+ return captureEvent("onAuthRequired", details); |
+ }, filter, intersect(extraInfoSpec, ["responseHeaders", "statusLine"])); |
+ chrome.experimental.webRequest.onResponseStarted.addListener( |
+ function(details) { |
+ return captureEvent("onResponseStarted", details); |
+ }, filter, intersect(extraInfoSpec, ["responseHeaders", "statusLine"])); |
+ chrome.experimental.webRequest.onBeforeRedirect.addListener( |
+ function(details) { |
+ return captureEvent("onBeforeRedirect", details); |
+ }, filter, intersect(extraInfoSpec, ["responseHeaders", "statusLine"])); |
+ chrome.experimental.webRequest.onCompleted.addListener( |
+ function(details) { |
+ return captureEvent("onCompleted", details); |
+ }, filter, intersect(extraInfoSpec, ["responseHeaders", "statusLine"])); |
+ chrome.experimental.webRequest.onErrorOccurred.addListener( |
+ function(details) { |
+ return captureEvent("onErrorOccurred", details); |
+ }, filter); |
+} |
+ |
+function removeListeners() { |
+ function helper(event) { |
+ // Note: We're poking at the internal event data, but it's easier than |
+ // the alternative. If this starts failing, we just need to update this |
+ // helper. |
+ for (var cb in event.callbackMap_) { |
+ event.removeListener(cb); |
+ } |
+ chrome.test.assertFalse(event.hasListeners()); |
+ } |
+ helper(chrome.experimental.webRequest.onBeforeRequest); |
+ helper(chrome.experimental.webRequest.onBeforeSendHeaders); |
+ helper(chrome.experimental.webRequest.onAuthRequired); |
+ helper(chrome.experimental.webRequest.onSendHeaders); |
+ helper(chrome.experimental.webRequest.onResponseStarted); |
+ helper(chrome.experimental.webRequest.onBeforeRedirect); |
+ helper(chrome.experimental.webRequest.onCompleted); |
+ helper(chrome.experimental.webRequest.onErrorOccurred); |
+} |
+ |
+runTests([ |
+ // Navigates to a blank page. |
+ function simpleLoad() { |
+ expect( |
+ [ // events |
+ { label: "a-onBeforeRequest", |
+ event: "onBeforeRequest", |
+ details: { |
+ method: "GET", |
+ tabId: tabId, |
+ type: "main_frame", |
+ url: getURL("simpleLoad/a.html"), |
+ frameUrl: getURL("simpleLoad/a.html") |
+ } |
+ }, |
+ { label: "a-onResponseStarted", |
+ event: "onResponseStarted", |
+ details: { |
+ url: getURL("simpleLoad/a.html"), |
+ statusCode: 200, |
+ fromCache: false |
+ // Request to chrome-extension:// url has no IP. |
+ } |
+ }, |
+ { label: "a-onCompleted", |
+ event: "onCompleted", |
+ details: { |
+ url: getURL("simpleLoad/a.html"), |
+ statusCode: 200, |
+ fromCache: false |
+ // Request to chrome-extension:// url has no IP. |
+ } |
+ }, |
+ ], |
+ [ // event order |
+ ["a-onBeforeRequest", "a-onResponseStarted", "a-onCompleted"] ]); |
+ navigateAndWait(getURL("simpleLoad/a.html")); |
+ }, |
+ |
+ // Navigates to a blank page via HTTP. Only HTTP requests get the |
+ // onBeforeSendHeaders event. |
+ function simpleLoadHttp() { |
+ expect( |
+ [ // events |
+ { label: "onBeforeRequest-1", |
+ event: "onBeforeRequest", |
+ details: { |
+ method: "GET", |
+ tabId: tabId, |
+ type: "main_frame", |
+ url: URL_HTTP_SIMPLE_LOAD_REDIRECT, |
+ frameUrl: URL_HTTP_SIMPLE_LOAD_REDIRECT |
+ } |
+ }, |
+ { label: "onBeforeSendHeaders-1", |
+ event: "onBeforeSendHeaders", |
+ details: { |
+ url: URL_HTTP_SIMPLE_LOAD_REDIRECT, |
+ requestHeadersValid: true |
+ } |
+ }, |
+ { label: "onSendHeaders-1", |
+ event: "onSendHeaders", |
+ details: { |
+ url: URL_HTTP_SIMPLE_LOAD_REDIRECT, |
+ requestHeadersValid: true |
+ } |
+ }, |
+ { label: "onBeforeRedirect", |
+ event: "onBeforeRedirect", |
+ details: { |
+ url: URL_HTTP_SIMPLE_LOAD_REDIRECT, |
+ redirectUrl: URL_HTTP_SIMPLE_LOAD, |
+ statusCode: 301, |
+ responseHeadersExist: true, |
+ ip: "127.0.0.1", |
+ fromCache: false, |
+ statusLine: "HTTP/1.0 301 Moved Permanently" |
+ } |
+ }, |
+ { label: "onBeforeRequest-2", |
+ event: "onBeforeRequest", |
+ details: { |
+ method: "GET", |
+ tabId: tabId, |
+ type: "main_frame", |
+ url: URL_HTTP_SIMPLE_LOAD, |
+ frameUrl: URL_HTTP_SIMPLE_LOAD |
+ } |
+ }, |
+ { label: "onBeforeSendHeaders-2", |
+ event: "onBeforeSendHeaders", |
+ details: { |
+ url: URL_HTTP_SIMPLE_LOAD, |
+ requestHeadersValid: true |
+ } |
+ }, |
+ { label: "onSendHeaders-2", |
+ event: "onSendHeaders", |
+ details: { |
+ url: URL_HTTP_SIMPLE_LOAD, |
+ requestHeadersValid: true |
+ } |
+ }, |
+ { label: "onResponseStarted", |
+ event: "onResponseStarted", |
+ details: { |
+ url: URL_HTTP_SIMPLE_LOAD, |
+ statusCode: 200, |
+ responseHeadersExist: true, |
+ ip: "127.0.0.1", |
+ fromCache: false, |
+ statusLine: "HTTP/1.0 200 OK", |
+ } |
+ }, |
+ { label: "onCompleted", |
+ event: "onCompleted", |
+ details: { |
+ url: URL_HTTP_SIMPLE_LOAD, |
+ statusCode: 200, |
+ ip: "127.0.0.1", |
+ fromCache: false, |
+ responseHeadersExist: true, |
+ statusLine: "HTTP/1.0 200 OK" |
+ } |
+ } |
+ ], |
+ [ // event order |
+ ["onBeforeRequest-1", "onBeforeSendHeaders-1", "onSendHeaders-1", |
+ "onBeforeRedirect", |
+ "onBeforeRequest-2", "onBeforeSendHeaders-2", "onSendHeaders-2", |
+ "onResponseStarted", "onCompleted"] ], |
+ {}, // filter |
+ ["requestHeaders", "responseHeaders", "statusLine"]); |
+ navigateAndWait(URL_HTTP_SIMPLE_LOAD_REDIRECT); |
+ }, |
+ |
+ // Navigates to a page to generates an XHR. |
+ function xhrLoad() { |
+ expect( |
+ [ // events |
+ { label: "onBeforeRequest-1", |
+ event: "onBeforeRequest", |
+ details: { |
+ method: "GET", |
+ tabId: tabId, |
+ type: "main_frame", |
+ url: URL_HTTP_XHR, |
+ frameUrl: URL_HTTP_XHR |
+ } |
+ }, |
+ { label: "onBeforeSendHeaders-1", |
+ event: "onBeforeSendHeaders", |
+ details: { |
+ url: URL_HTTP_XHR, |
+ } |
+ }, |
+ { label: "onSendHeaders-1", |
+ event: "onSendHeaders", |
+ details: { |
+ url: URL_HTTP_XHR, |
+ } |
+ }, |
+ { label: "onResponseStarted-1", |
+ event: "onResponseStarted", |
+ details: { |
+ url: URL_HTTP_XHR, |
+ statusCode: 200, |
+ ip: "127.0.0.1", |
+ fromCache: false, |
+ } |
+ }, |
+ { label: "onCompleted-1", |
+ event: "onCompleted", |
+ details: { |
+ url: URL_HTTP_XHR, |
+ statusCode: 200, |
+ ip: "127.0.0.1", |
+ fromCache: false, |
+ } |
+ }, |
+ { label: "onBeforeRequest-2", |
+ event: "onBeforeRequest", |
+ details: { |
+ method: "GET", |
+ tabId: tabId, |
+ type: "xmlhttprequest", |
+ url: URL_HTTP_XHR_DATA, |
+ frameUrl: URL_HTTP_XHR |
+ } |
+ }, |
+ { label: "onBeforeSendHeaders-2", |
+ event: "onBeforeSendHeaders", |
+ details: { |
+ url: URL_HTTP_XHR_DATA, |
+ } |
+ }, |
+ { label: "onSendHeaders-2", |
+ event: "onSendHeaders", |
+ details: { |
+ url: URL_HTTP_XHR_DATA, |
+ } |
+ }, |
+ { label: "onResponseStarted-2", |
+ event: "onResponseStarted", |
+ details: { |
+ url: URL_HTTP_XHR_DATA, |
+ statusCode: 200, |
+ ip: "127.0.0.1", |
+ fromCache: false, |
+ } |
+ }, |
+ { label: "onCompleted-2", |
+ event: "onCompleted", |
+ details: { |
+ url: URL_HTTP_XHR_DATA, |
+ statusCode: 200, |
+ ip: "127.0.0.1", |
+ fromCache: false, |
+ } |
+ } |
+ ], |
+ [ // event order |
+ ["onBeforeRequest-1", "onBeforeSendHeaders-1", "onSendHeaders-1", |
+ "onResponseStarted-1", "onCompleted-1", |
+ "onBeforeRequest-2", "onBeforeSendHeaders-2", "onSendHeaders-2", |
+ "onResponseStarted-2", "onCompleted-2"] ], |
+ {}, []); |
+ navigateAndWait(URL_HTTP_XHR); |
+ }, |
+ |
+ // Navigates to a page with subresources. |
+ // TODO(mpcomplete): add multiple subresources; requires support for |
+ // recognizing partial ordering. |
+ function complexLoad() { |
+ expect( |
+ [ // events |
+ { label: "a.html-onBeforeRequest", |
+ event: "onBeforeRequest", |
+ details: { |
+ method: "GET", |
+ tabId: tabId, |
+ type: "main_frame", |
+ url: getURL("complexLoad/a.html"), |
+ frameUrl: getURL("complexLoad/a.html") |
+ } |
+ }, |
+ { label: "b.html-onBeforeRequest", |
+ event: "onBeforeRequest", |
+ details: { |
+ method: "GET", |
+ tabId: tabId, |
+ type: "sub_frame", |
+ url: getURL("complexLoad/b.html"), |
+ frameUrl: getURL("complexLoad/b.html") |
+ } |
+ }, |
+ { label: "b.jpg-onBeforeRequest", |
+ event: "onBeforeRequest", |
+ details: { |
+ method: "GET", |
+ tabId: tabId, |
+ type: "image", |
+ url: getURL("complexLoad/b.jpg"), |
+ frameUrl: getURL("complexLoad/b.html") |
+ } |
+ }, |
+ { label: "a.html-onResponseStarted", |
+ event: "onResponseStarted", |
+ details: { |
+ url: getURL("complexLoad/a.html"), |
+ fromCache: false, |
+ statusCode: 200 |
+ // Request to chrome-extension:// url has no IP. |
+ } |
+ }, |
+ { label: "b.html-onResponseStarted", |
+ event: "onResponseStarted", |
+ details: { |
+ url: getURL("complexLoad/b.html"), |
+ fromCache: false, |
+ statusCode: 200 |
+ // Request to chrome-extension:// url has no IP. |
+ } |
+ }, |
+ { label: "b.jpg-onResponseStarted", |
+ event: "onResponseStarted", |
+ details: { |
+ url: getURL("complexLoad/b.jpg"), |
+ fromCache: false, |
+ statusCode: 200 |
+ // Request to chrome-extension:// url has no IP. |
+ } |
+ }, |
+ { label: "a.html-onCompleted", |
+ event: "onCompleted", |
+ details: { |
+ url: getURL("complexLoad/a.html"), |
+ fromCache: false, |
+ statusCode: 200 |
+ // Request to chrome-extension:// url has no IP. |
+ } |
+ }, |
+ { label: "b.html-onCompleted", |
+ event: "onCompleted", |
+ details: { |
+ url: getURL("complexLoad/b.html"), |
+ fromCache: false, |
+ statusCode: 200 |
+ // Request to chrome-extension:// url has no IP. |
+ } |
+ }, |
+ { label: "b.jpg-onCompleted", |
+ event: "onCompleted", |
+ details: { |
+ url: getURL("complexLoad/b.jpg"), |
+ fromCache: false, |
+ statusCode: 200 |
+ // Request to chrome-extension:// url has no IP. |
+ } |
+ }, |
+ ], |
+ [ // event order |
+ ["a.html-onBeforeRequest", "a.html-onResponseStarted", |
+ "b.html-onBeforeRequest", "b.html-onResponseStarted", |
+ "b.jpg-onBeforeRequest", "b.jpg-onResponseStarted" ], |
+ ["a.html-onResponseStarted", "a.html-onCompleted"], |
+ ["b.html-onResponseStarted", "b.html-onCompleted"], |
+ ["b.jpg-onResponseStarted", "b.jpg-onCompleted"] ] |
+ ); |
+ navigateAndWait(getURL("complexLoad/a.html")); |
+ }, |
+ |
+ // Navigates to a page with subresources, with a blocking handler that |
+ // cancels the page request. The page will not load, and we should not |
+ // see the subresources. |
+ function complexLoadCancelled() { |
+ expect( |
+ [ // events |
+ { label: "onBeforeRequest", |
+ event: "onBeforeRequest", |
+ details: { |
+ method: "GET", |
+ tabId: tabId, |
+ type: "main_frame", |
+ url: getURL("complexLoad/a.html"), |
+ frameUrl: getURL("complexLoad/a.html") |
+ }, |
+ retval: {cancel: true} |
+ }, |
+ // Cancelling is considered an error. |
+ { label: "onErrorOccurred", |
+ event: "onErrorOccurred", |
+ details: { |
+ url: getURL("complexLoad/a.html"), |
+ fromCache: false, |
+ error: "net::ERR_EMPTY_RESPONSE" |
+ // Request to chrome-extension:// url has no IP. |
+ } |
+ }, |
+ ], |
+ [ // event order |
+ ["onBeforeRequest"] |
+ ], |
+ {}, // filter |
+ ["blocking"]); |
+ navigateAndWait(getURL("complexLoad/a.html")); |
+ }, |
+ |
+ // Navigates to a page with a blocking handler that redirects to a different |
+ // page. |
+ // TODO(mpcomplete): We should see an onBeforeRedirect as well, but our |
+ // process switching logic cancels the original redirect request and |
+ // starts a new one instead. See http://crbug.com/79520. |
+ function complexLoadRedirected() { |
+ expect( |
+ [ // events |
+ { label: "onBeforeRequest-1", |
+ event: "onBeforeRequest", |
+ details: { |
+ method: "GET", |
+ tabId: tabId, |
+ type: "main_frame", |
+ url: getURL("complexLoad/a.html"), |
+ frameUrl: getURL("complexLoad/a.html") |
+ }, |
+ retval: {redirectUrl: getURL("simpleLoad/a.html")} |
+ }, |
+ { label: "onErrorOccurred-1", |
+ event: "onErrorOccurred", |
+ details: { |
+ url: getURL("complexLoad/a.html"), |
+ fromCache: false, |
+ error: "net::ERR_ABORTED" |
+ // Request to chrome-extension:// url has no IP. |
+ } |
+ }, |
+ { label: "onBeforeRequest-2", |
+ event: "onBeforeRequest", |
+ details: { |
+ method: "GET", |
+ tabId: tabId, |
+ type: "main_frame", |
+ url: getURL("simpleLoad/a.html"), |
+ frameUrl: getURL("simpleLoad/a.html"), |
+ }, |
+ }, |
+ { label: "onResponseStarted", |
+ event: "onResponseStarted", |
+ details: { |
+ url: getURL("simpleLoad/a.html"), |
+ fromCache: false, |
+ statusCode: 200 |
+ // Request to chrome-extension:// url has no IP. |
+ } |
+ }, |
+ { label: "onCompleted", |
+ event: "onCompleted", |
+ details: { |
+ url: getURL("simpleLoad/a.html"), |
+ fromCache: false, |
+ statusCode: 200 |
+ // Request to chrome-extension:// url has no IP. |
+ } |
+ }, |
+ ], |
+ [ // event order |
+ ["onBeforeRequest-1", "onErrorOccurred-1", "onBeforeRequest-2", |
+ "onResponseStarted", "onCompleted"], |
+ ], |
+ {}, // filter |
+ ["blocking"]); |
+ navigateAndWait(getURL("complexLoad/a.html")); |
+ }, |
+ |
+ // Loads several resources, but should only see the complexLoad main_frame |
+ // and image due to the filter. |
+ function complexLoadFiltered() { |
+ expect( |
+ [ // events |
+ { label: "a-onBeforeRequest", |
+ event: "onBeforeRequest", |
+ details: { |
+ method: "GET", |
+ tabId: tabId, |
+ type: "main_frame", |
+ url: getURL("complexLoad/a.html"), |
+ frameUrl: getURL("complexLoad/a.html") |
+ } |
+ }, |
+ { label: "b-onBeforeRequest", |
+ event: "onBeforeRequest", |
+ details: { |
+ method: "GET", |
+ tabId: tabId, |
+ type: "image", |
+ url: getURL("complexLoad/b.jpg"), |
+ // As we do not listed to sub-frames we do not know the frameUrl. |
+ frameUrl: "unknown frame URL" |
+ } |
+ }, |
+ { label: "a-onResponseStarted", |
+ event: "onResponseStarted", |
+ details: { |
+ url: getURL("complexLoad/a.html"), |
+ fromCache: false, |
+ statusCode: 200 |
+ // Request to chrome-extension:// url has no IP. |
+ } |
+ }, |
+ { label: "b-onResponseStarted", |
+ event: "onResponseStarted", |
+ details: { |
+ url: getURL("complexLoad/b.jpg"), |
+ fromCache: false, |
+ statusCode: 200 |
+ // Request to chrome-extension:// url has no IP. |
+ } |
+ }, |
+ { label: "a-onCompleted", |
+ event: "onCompleted", |
+ details: { |
+ url: getURL("complexLoad/a.html"), |
+ fromCache: false, |
+ statusCode: 200 |
+ // Request to chrome-extension:// url has no IP. |
+ } |
+ }, |
+ { label: "b-onCompleted", |
+ event: "onCompleted", |
+ details: { |
+ url: getURL("complexLoad/b.jpg"), |
+ fromCache: false, |
+ statusCode: 200 |
+ // Request to chrome-extension:// url has no IP. |
+ } |
+ }, |
+ ], |
+ [ // event order |
+ ["a-onBeforeRequest", "a-onResponseStarted", |
+ "b-onBeforeRequest", "b-onResponseStarted"], |
+ ["a-onResponseStarted", "a-onCompleted"], |
+ ["b-onResponseStarted", "b-onCompleted"] ], |
+ { // filters |
+ urls: [getURL("complexLoad/*")], |
+ types: ["main_frame", "image"], |
+ tabId: tabId |
+ }); |
+ chrome.tabs.create({ url: getURL("simpleLoad/a.html") }, |
+ function(newTab) { |
+ chrome.tabs.remove(newTab.id); |
+ navigateAndWait(getURL("complexLoad/a.html")); |
+ }); |
+ }, |
+ |
+ // Navigates to a non-existing page. |
+ function nonExistingLoad() { |
+ expect( |
+ [ // events |
+ { label: "onBeforeRequest", |
+ event: "onBeforeRequest", |
+ details: { |
+ method: "GET", |
+ tabId: tabId, |
+ type: "main_frame", |
+ url: getURL("does_not_exist.html"), |
+ frameUrl: getURL("does_not_exist.html") |
+ } |
+ }, |
+ { label: "onErrorOccurred", |
+ event: "onErrorOccurred", |
+ details: { |
+ url: getURL("does_not_exist.html"), |
+ fromCache: false, |
+ error: "net::ERR_FILE_NOT_FOUND", |
+ // Request to chrome-extension:// url has no IP. |
+ } |
+ }, |
+ ], |
+ [ // event order |
+ ["onBeforeRequest", "onErrorOccurred"] ]); |
+ navigateAndWait(getURL("does_not_exist.html")); |
+ }, |
+ |
+ // Loads a testserver page that echoes the User-Agent header that was |
+ // sent to fetch it. We modify the outgoing User-Agent in |
+ // onBeforeSendHeaders, so we should see that modified version. |
+ function modifyRequestHeaders() { |
+ expect( |
+ [ // events |
+ { label: "onBeforeRequest", |
+ event: "onBeforeRequest", |
+ details: { |
+ method: "GET", |
+ tabId: tabId, |
+ type: "main_frame", |
+ url: URL_ECHO_USER_AGENT, |
+ frameUrl: URL_ECHO_USER_AGENT |
+ } |
+ }, |
+ { label: "onBeforeSendHeaders", |
+ event: "onBeforeSendHeaders", |
+ details: { |
+ url: URL_ECHO_USER_AGENT, |
+ // Note: no requestHeaders because we don't ask for them. |
+ }, |
+ retval: {requestHeaders: [{name: "User-Agent", value: "FoobarUA"}]} |
+ }, |
+ { label: "onSendHeaders", |
+ event: "onSendHeaders", |
+ details: { |
+ url: URL_ECHO_USER_AGENT |
+ } |
+ }, |
+ { label: "onResponseStarted", |
+ event: "onResponseStarted", |
+ details: { |
+ url: URL_ECHO_USER_AGENT, |
+ fromCache: false, |
+ statusCode: 200, |
+ ip: "127.0.0.1" |
+ } |
+ }, |
+ { label: "onCompleted", |
+ event: "onCompleted", |
+ details: { |
+ url: URL_ECHO_USER_AGENT, |
+ fromCache: false, |
+ statusCode: 200, |
+ ip: "127.0.0.1" |
+ } |
+ }, |
+ ], |
+ [ // event order |
+ ["onBeforeRequest", "onBeforeSendHeaders", "onSendHeaders", |
+ "onResponseStarted", "onCompleted"] |
+ ], |
+ {}, ["blocking"]); |
+ // Check the page content for our modified User-Agent string. |
+ navigateAndWait(URL_ECHO_USER_AGENT, function() { |
+ chrome.test.listenOnce(chrome.extension.onRequest, function(request) { |
+ chrome.test.assertTrue(request.pass, "Request header was not set."); |
+ }); |
+ chrome.tabs.executeScript(tabId, |
+ { |
+ code: "chrome.extension.sendRequest(" + |
+ "{pass: document.body.innerText.indexOf('FoobarUA') >= 0});" |
+ }); |
+ }); |
+ }, |
+ |
+ // Loads a testserver page that requires authentication. |
+ function authRequired() { |
+ expect( |
+ [ // events |
+ { label: "onBeforeRequest", |
+ event: "onBeforeRequest", |
+ details: { |
+ method: "GET", |
+ tabId: tabId, |
+ type: "main_frame", |
+ url: URL_AUTH_REQUIRED, |
+ frameUrl: URL_AUTH_REQUIRED |
+ } |
+ }, |
+ { label: "onBeforeSendHeaders", |
+ event: "onBeforeSendHeaders", |
+ details: { |
+ url: URL_AUTH_REQUIRED, |
+ // Note: no requestHeaders because we don't ask for them. |
+ }, |
+ }, |
+ { label: "onSendHeaders", |
+ event: "onSendHeaders", |
+ details: { |
+ url: URL_AUTH_REQUIRED, |
+ } |
+ }, |
+ { label: "onAuthRequired", |
+ event: "onAuthRequired", |
+ details: { |
+ url: URL_AUTH_REQUIRED, |
+ isProxy: false, |
+ scheme: "basic", |
+ realm: "testrealm", |
+ } |
+ }, |
+ { label: "onResponseStarted", |
+ event: "onResponseStarted", |
+ details: { |
+ url: URL_AUTH_REQUIRED, |
+ fromCache: false, |
+ statusCode: 401, |
+ ip: "127.0.0.1" |
+ } |
+ }, |
+ { label: "onCompleted", |
+ event: "onCompleted", |
+ details: { |
+ url: URL_AUTH_REQUIRED, |
+ fromCache: false, |
+ statusCode: 401, |
+ ip: "127.0.0.1" |
+ } |
+ }, |
+ ], |
+ [ // event order |
+ ["onBeforeRequest", "onBeforeSendHeaders", "onSendHeaders", |
+ "onAuthRequired", "onResponseStarted", "onCompleted"] |
+ ], |
+ {}, []); |
+ navigateAndWait(URL_AUTH_REQUIRED); |
+ }, |
+]); |
+</script> |