Skip to content

Commit 1d852ea

Browse files
committed
AG-50239 Fix 'prevent-fetch' — do not use 'modifyResponse' on redirected requests. #545
Squashed commit of the following: commit e0ac5b3 Author: Adam Wróblewski <adam@adguard.com> Date: Fri Feb 27 11:37:41 2026 +0100 Add newline commit 7602669 Author: Adam Wróblewski <adam@adguard.com> Date: Fri Feb 27 11:30:31 2026 +0100 Add extension scheme check and related tests to prevent-fetch scriptlet
1 parent cdf6ab9 commit 1d852ea

3 files changed

Lines changed: 51 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@ The format is based on [Keep a Changelog], and this project adheres to [Semantic
2121

2222
### Fixed
2323

24+
- `prevent-fetch` — do not use `modifyResponse` on redirected requests [#545].
2425
- issue with assigning `window` to property which was not set in
2526
`abort-on-property-read`, `abort-on-property-write`, `abort-on-stack-trace`,
2627
`abort-current-inline-script`, `debug-on-property-write`, `debug-on-property-read`,
2728
`debug-current-inline-script` and `log-on-stack-trace` scriptlets [#513].
2829

2930
[Unreleased]: https://github.com/AdguardTeam/Scriptlets/compare/v2.2.16...HEAD
3031
[#513]: https://github.com/AdguardTeam/Scriptlets/issues/513
32+
[#545]: https://github.com/AdguardTeam/Scriptlets/issues/545
3133

3234
## [v2.2.16] - 2026-02-19
3335

src/scriptlets/prevent-fetch.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,22 @@ export function preventFetch(source, propsToMatch, responseBody = 'emptyObj', re
168168
return;
169169
}
170170

171+
const EXTENSION_SCHEMES = [
172+
'chrome-extension:',
173+
'moz-extension:',
174+
'ms-browser-extension:',
175+
'safari-web-extension:',
176+
];
177+
178+
/**
179+
* Check whether a URL uses a known browser extension scheme.
180+
* https://github.com/AdguardTeam/Scriptlets/issues/545
181+
*
182+
* @param {string} url - URL string to check.
183+
* @returns {boolean} `true` if the URL starts with a known extension scheme.
184+
*/
185+
const isExtensionScheme = (url) => EXTENSION_SCHEMES.some((scheme) => url.startsWith(scheme));
186+
171187
/**
172188
* Get the response type based on the given request object.
173189
*
@@ -210,7 +226,7 @@ export function preventFetch(source, propsToMatch, responseBody = 'emptyObj', re
210226
// In the case of apps, the blocked request has status 500
211227
// and no error is thrown, so it's necessary to check response.ok
212228
// https://github.com/AdguardTeam/Scriptlets/issues/334
213-
if (!origResponse.ok) {
229+
if (!origResponse.ok || isExtensionScheme(origResponse.url)) {
214230
return noopPromiseResolve(strResponseBody, fetchData.url, finalResponseType);
215231
}
216232
return modifyResponse(

tests/scriptlets/prevent-fetch.test.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,4 +551,36 @@ if (!isSupported) {
551551
assert.strictEqual(window.hit, 'FIRED', 'hit function fired');
552552
done();
553553
});
554+
555+
test('extension-redirected response should preserve content-length and original URL', async (assert) => {
556+
const REQUESTED_URL = `${FETCH_OBJECTS_PATH}/pagead/js/adsbygoogle.js`;
557+
const EXTENSION_URL = 'chrome-extension://foo/pagead/js/adsbygoogle.js';
558+
const RESPONSE_BODY = 'Response body test';
559+
560+
// Mock native fetch to simulate browser extension redirect
561+
window.fetch = () => {
562+
const resp = new Response(RESPONSE_BODY, {
563+
status: 200,
564+
statusText: 'OK',
565+
headers: {
566+
// Extension response is missing Content-Length header
567+
},
568+
});
569+
// Simulate extension-provided URL
570+
Object.defineProperty(resp, 'url', { value: EXTENSION_URL });
571+
return Promise.resolve(resp);
572+
};
573+
574+
runScriptlet(name, ['adsbygoogle']);
575+
const done = assert.async();
576+
577+
const response = await fetch(REQUESTED_URL);
578+
579+
const contentLengthHeader = response.headers.get('Content-Length');
580+
581+
assert.ok(contentLengthHeader !== null, 'Content-Length header is present');
582+
assert.strictEqual(response.url, REQUESTED_URL, 'Response URL is the original requested URL');
583+
assert.strictEqual(window.hit, 'FIRED', 'hit function fired');
584+
done();
585+
});
554586
}

0 commit comments

Comments
 (0)