diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /toolkit/components/extensions/test/xpcshell/test_ext_webRequest_suspend.js | |
parent | Initial commit. (diff) | |
download | thunderbird-upstream.tar.xz thunderbird-upstream.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/extensions/test/xpcshell/test_ext_webRequest_suspend.js')
-rw-r--r-- | toolkit/components/extensions/test/xpcshell/test_ext_webRequest_suspend.js | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_webRequest_suspend.js b/toolkit/components/extensions/test/xpcshell/test_ext_webRequest_suspend.js new file mode 100644 index 0000000000..f8116aced0 --- /dev/null +++ b/toolkit/components/extensions/test/xpcshell/test_ext_webRequest_suspend.js @@ -0,0 +1,289 @@ +"use strict"; + +const HOSTS = new Set(["example.com"]); + +const server = createHttpServer({ hosts: HOSTS }); + +const BASE_URL = "http://example.com"; +const FETCH_ORIGIN = "http://example.com/dummy"; + +server.registerPathHandler("/return_headers.sjs", (request, response) => { + response.setHeader("Content-Type", "text/plain", false); + + let headers = {}; + for (let { data: header } of request.headers) { + headers[header.toLowerCase()] = request.getHeader(header); + } + + response.write(JSON.stringify(headers)); +}); + +server.registerPathHandler("/dummy", (request, response) => { + response.setStatusLine(request.httpVersion, 200, "OK"); + response.write("ok"); +}); + +add_task(async function test_suspend() { + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + permissions: ["webRequest", "webRequestBlocking", `${BASE_URL}/`], + }, + + background() { + browser.webRequest.onBeforeSendHeaders.addListener( + details => { + // Make sure that returning undefined or a promise that resolves to + // undefined does not break later handlers. + }, + { urls: ["<all_urls>"] }, + ["blocking", "requestHeaders"] + ); + + browser.webRequest.onBeforeSendHeaders.addListener( + details => { + return Promise.resolve(); + }, + { urls: ["<all_urls>"] }, + ["blocking", "requestHeaders"] + ); + + browser.webRequest.onBeforeSendHeaders.addListener( + details => { + let requestHeaders = details.requestHeaders.concat({ + name: "Foo", + value: "Bar", + }); + + return new Promise(resolve => { + // eslint-disable-next-line mozilla/no-arbitrary-setTimeout + setTimeout(resolve, 500); + }).then(() => { + return { requestHeaders }; + }); + }, + { urls: ["<all_urls>"] }, + ["blocking", "requestHeaders"] + ); + }, + }); + + await extension.startup(); + + let headers = JSON.parse( + await ExtensionTestUtils.fetch( + FETCH_ORIGIN, + `${BASE_URL}/return_headers.sjs` + ) + ); + + equal( + headers.foo, + "Bar", + "Request header was correctly set on suspended request" + ); + + await extension.unload(); +}); + +// Test that requests that were canceled while suspended for a blocking +// listener are correctly resumed. +add_task(async function test_error_resume() { + let observer = channel => { + if ( + channel instanceof Ci.nsIHttpChannel && + channel.URI.spec === "http://example.com/dummy" + ) { + Services.obs.removeObserver(observer, "http-on-before-connect"); + + // Wait until the next tick to make sure this runs after WebRequest observers. + Promise.resolve().then(() => { + channel.cancel(Cr.NS_BINDING_ABORTED); + }); + } + }; + + Services.obs.addObserver(observer, "http-on-before-connect"); + + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + permissions: ["webRequest", "webRequestBlocking", `${BASE_URL}/`], + }, + + background() { + browser.webRequest.onBeforeSendHeaders.addListener( + details => { + browser.test.log(`onBeforeSendHeaders({url: ${details.url}})`); + + if (details.url === "http://example.com/dummy") { + browser.test.sendMessage("got-before-send-headers"); + } + }, + { urls: ["<all_urls>"] }, + ["blocking"] + ); + + browser.webRequest.onErrorOccurred.addListener( + details => { + browser.test.log(`onErrorOccurred({url: ${details.url}})`); + + if (details.url === "http://example.com/dummy") { + browser.test.sendMessage("got-error-occurred"); + } + }, + { urls: ["<all_urls>"] } + ); + }, + }); + + await extension.startup(); + + try { + await ExtensionTestUtils.fetch(FETCH_ORIGIN, `${BASE_URL}/dummy`); + ok(false, "Fetch should have failed."); + } catch (e) { + ok(true, "Got expected error."); + } + + await extension.awaitMessage("got-before-send-headers"); + await extension.awaitMessage("got-error-occurred"); + + // Wait for the next tick so the onErrorRecurred response can be + // processed before shutting down the extension. + await new Promise(resolve => executeSoon(resolve)); + + await extension.unload(); +}); + +// Test that response header modifications take effect before onStartRequest fires. +add_task(async function test_set_responseHeaders() { + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + permissions: ["webRequest", "webRequestBlocking", "http://example.com/"], + }, + + background() { + browser.webRequest.onHeadersReceived.addListener( + details => { + browser.test.log(`onHeadersReceived({url: ${details.url}})`); + + details.responseHeaders.push({ name: "foo", value: "bar" }); + + return { responseHeaders: details.responseHeaders }; + }, + { urls: ["http://example.com/?modify_headers"] }, + ["blocking", "responseHeaders"] + ); + }, + }); + + await extension.startup(); + + await new Promise(resolve => setTimeout(resolve, 0)); + + let resolveHeaderPromise; + let headerPromise = new Promise(resolve => { + resolveHeaderPromise = resolve; + }); + { + let ssm = Services.scriptSecurityManager; + + let channel = NetUtil.newChannel({ + uri: "http://example.com/?modify_headers", + loadingPrincipal: + ssm.createContentPrincipalFromOrigin("http://example.com"), + contentPolicyType: Ci.nsIContentPolicy.TYPE_XMLHTTPREQUEST, + securityFlags: Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL, + }); + + channel.asyncOpen({ + QueryInterface: ChromeUtils.generateQI(["nsIStreamListener"]), + + onStartRequest(request) { + request.QueryInterface(Ci.nsIHttpChannel); + + try { + resolveHeaderPromise(request.getResponseHeader("foo")); + } catch (e) { + resolveHeaderPromise(null); + } + request.cancel(Cr.NS_BINDING_ABORTED); + }, + + onStopRequest() {}, + + onDataAvailable() { + throw new Components.Exception("", Cr.NS_ERROR_FAILURE); + }, + }); + } + + let headerValue = await headerPromise; + equal(headerValue, "bar", "Expected Foo header value"); + + await extension.unload(); +}); + +// Test that exceptions raised from a blocking webRequest listener that returns +// a promise are logged as expected. +add_task(async function test_logged_error_on_promise_result() { + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + permissions: ["webRequest", "webRequestBlocking", `${BASE_URL}/`], + }, + + background() { + async function onBeforeRequest() { + throw new Error("Expected webRequest exception from a promise result"); + } + + let exceptionRaised = false; + + browser.webRequest.onBeforeRequest.addListener( + () => { + if (exceptionRaised) { + return; + } + + // We only need to raise the exception once. + exceptionRaised = true; + return onBeforeRequest(); + }, + { + urls: ["http://example.com/*"], + types: ["main_frame"], + }, + ["blocking"] + ); + + browser.webRequest.onBeforeRequest.addListener( + () => { + browser.test.sendMessage("web-request-event-received"); + }, + { + urls: ["http://example.com/*"], + types: ["main_frame"], + }, + ["blocking"] + ); + }, + }); + + let { messages } = await promiseConsoleOutput(async () => { + await extension.startup(); + + let contentPage = await ExtensionTestUtils.loadContentPage( + `${BASE_URL}/dummy` + ); + await extension.awaitMessage("web-request-event-received"); + await contentPage.close(); + }); + + ok( + messages.some(msg => + /Expected webRequest exception from a promise result/.test(msg.message) + ), + "Got expected console message" + ); + + await extension.unload(); +}); |