Skip to content

Instantly share code, notes, and snippets.

@dotproto
Last active January 29, 2026 05:09
Show Gist options
  • Select an option

  • Save dotproto/df3a92c1e8075ccfddd824c152064658 to your computer and use it in GitHub Desktop.

Select an option

Save dotproto/df3a92c1e8075ccfddd824c152064658 to your computer and use it in GitHub Desktop.
Cross browser compatibility Info gathered while working on WebKit/WebKit#56662

Setup

  1. Copy the files in this gist into a temporary a local directory.
  2. CD into temporary directory and start a local HTTP server. I used npx http-server --proxy http://localhost:8080?, but anything should work
  3. In your borwser of choice, load the webext directory as a temporary extension.
    NOTE: You may need to grant additional host permissions after installation.
  4. If the extension didn't, open a new tab to http://localhost:8080
  5. Inspect the page, select the Network tab, and make the console visible.
  6. Reload the page.

When the page reloads, you should see a set of network requests that were blocked by the extension either in the Network tab directly or in the console.

Test results

Request Safari 26.2 Firefox 141 Chrome 144 c46127bd
fetch('/literal%7C') ✅ allowed ✅ allowed ✅ allowed ✅ allowed
fetch('/literal%7C+') ✅ allowed ✅ allowed ✅ allowed ✅ allowed
fetch('/literal%7C%2B') ✅ allowed ✅ allowed ✅ allowed ✅ allowed
fetch('/literal|') ✅ allowed ❌ blocked ✅ allowed ❌ blocked
fetch('/literal|+') ❌ blocked ❌ blocked ✅ allowed ❌ blocked
fetch('/literal|%2B') ✅ allowed ✅ allowed ✅ allowed ✅ allowed
fetch('/encoded%7C') ✅ allowed ❌ blocked ❌ blocked ❌ blocked
fetch('/encoded%7C+') ❌ blocked ❌ blocked ❌ blocked ❌ blocked
fetch('/encoded%7C%2B') ✅ allowed ✅ allowed ✅ allowed ✅ allowed
fetch('/encoded|') ✅ allowed ✅ allowed ❌ blocked ✅ allowed
fetch('/encoded|+') ✅ allowed ✅ allowed ❌ blocked ✅ allowed
fetch('/encoded|%2B') ✅ allowed ✅ allowed ✅ allowed ✅ allowed
globalThis.browser ??= globalThis.chrome;
browser.declarativeNetRequest.onRuleMatchedDebug.addListener(info => {
console.log("onRuleMatchedDebug", info);
});
browser.runtime.onInstalled.addListener(() => {
browser.tabs.query({ url: "http://localhost/*" }).then(tabs => {
if (tabs.length) {
browser.tabs.update(tabs[0].id, {active: true, url: tabs[0].url})
} else {
browser.tabs.create({ url: "http://localhost:8080/", active: true });
}
});
});
<script>
async function fetchSubResources()
{
try { await fetch('/literal%7C') } catch(e) { }
try { await fetch('/literal%7C+') } catch(e) { }
try { await fetch('/literal%7C%2B') } catch(e) { }
try { await fetch('/literal|') } catch(e) { }
try { await fetch('/literal|+') } catch(e) { }
try { await fetch('/literal|%2B') } catch(e) { }
try { await fetch('/encoded%7C') } catch(e) { }
try { await fetch('/encoded%7C+') } catch(e) { }
try { await fetch('/encoded%7C%2B') } catch(e) { }
try { await fetch('/encoded|') } catch(e) { }
try { await fetch('/encoded|+') } catch(e) { }
try { await fetch('/encoded|%2B') } catch(e) { }
}
fetchSubResources();
</script>
{
"name": "urlFilter test - 2026-01-27",
"version": "1.0",
"manifest_version": 3,
"description": "Test extension",
"permissions": [ "declarativeNetRequest", "declarativeNetRequestFeedback", "tabs" ],
"host_permissions": ["<all_urls>"],
"background": {
"scripts": [ "background.js" ],
"service_worker": "background.js",
"type": "module",
"persistent": false
},
"declarative_net_request": {
"rule_resources": [
{
"id": "urlFilterSpecialCharacterRules",
"enabled": true,
"path": "rules.json"
}
]
}
}
[
{ "id" : 1, "priority": 1, "action" : { "type" : "block" }, "condition" : { "urlFilter" : "/literal|^" } },
{ "id" : 2, "priority": 1, "action" : { "type" : "block" }, "condition" : { "urlFilter" : "/encoded%7C^" } }
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment