Skip to content

Commit 13612d1

Browse files
committed
Improve scriptlets proxying fetch
Related issue: uBlockOrigin/uBlock-issues#3892
1 parent d2b680f commit 13612d1

File tree

6 files changed

+60
-84
lines changed

6 files changed

+60
-84
lines changed

src/js/resources/json-edit.js

Lines changed: 10 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
*/
2222

2323
import {
24+
collateFetchArgumentsFn,
2425
matchObjectPropertiesFn,
2526
parsePropertiesToMatchFn,
2627
} from './utils.js';
@@ -569,18 +570,8 @@ function jsonEditFetchResponseFn(trusted, jsonq = '') {
569570
const args = context.callArgs;
570571
const fetchPromise = context.reflect();
571572
if ( propNeedles.size !== 0 ) {
572-
const objs = [ args[0] instanceof Object ? args[0] : { url: args[0] } ];
573-
if ( objs[0] instanceof Request ) {
574-
try {
575-
objs[0] = safe.Request_clone.call(objs[0]);
576-
} catch(ex) {
577-
safe.uboErr(logPrefix, 'Error:', ex);
578-
}
579-
}
580-
if ( args[1] instanceof Object ) {
581-
objs.push(args[1]);
582-
}
583-
const matched = matchObjectPropertiesFn(propNeedles, ...objs);
573+
const props = collateFetchArgumentsFn(...args);
574+
const matched = matchObjectPropertiesFn(propNeedles, props);
584575
if ( matched === undefined ) { return fetchPromise; }
585576
if ( safe.logLevel > 1 ) {
586577
safe.uboLog(logPrefix, `Matched "propsToMatch":\n\t${matched.join('\n\t')}`);
@@ -618,6 +609,7 @@ function jsonEditFetchResponseFn(trusted, jsonq = '') {
618609
registerScriptlet(jsonEditFetchResponseFn, {
619610
name: 'json-edit-fetch-response.fn',
620611
dependencies: [
612+
collateFetchArgumentsFn,
621613
JSONPath,
622614
matchObjectPropertiesFn,
623615
parsePropertiesToMatchFn,
@@ -716,17 +708,8 @@ function jsonEditFetchRequestFn(trusted, jsonq = '') {
716708
return context.reflect();
717709
}
718710
if ( propNeedles.size !== 0 ) {
719-
const objs = [
720-
resource instanceof Object ? resource : { url: `${resource}` }
721-
];
722-
if ( objs[0] instanceof Request ) {
723-
try {
724-
objs[0] = safe.Request_clone.call(objs[0]);
725-
} catch(ex) {
726-
safe.uboErr(logPrefix, 'Error:', ex);
727-
}
728-
}
729-
const matched = matchObjectPropertiesFn(propNeedles, ...objs);
711+
const props = collateFetchArgumentsFn(resource, options);
712+
const matched = matchObjectPropertiesFn(propNeedles, props);
730713
if ( matched === undefined ) { return context.reflect(); }
731714
if ( safe.logLevel > 1 ) {
732715
safe.uboLog(logPrefix, `Matched "propsToMatch":\n\t${matched.join('\n\t')}`);
@@ -745,6 +728,7 @@ function jsonEditFetchRequestFn(trusted, jsonq = '') {
745728
registerScriptlet(jsonEditFetchRequestFn, {
746729
name: 'json-edit-fetch-request.fn',
747730
dependencies: [
731+
collateFetchArgumentsFn,
748732
JSONPath,
749733
matchObjectPropertiesFn,
750734
parsePropertiesToMatchFn,
@@ -986,18 +970,8 @@ function jsonlEditFetchResponseFn(trusted, jsonq = '') {
986970
const args = context.callArgs;
987971
const fetchPromise = context.reflect();
988972
if ( propNeedles.size !== 0 ) {
989-
const objs = [ args[0] instanceof Object ? args[0] : { url: args[0] } ];
990-
if ( objs[0] instanceof Request ) {
991-
try {
992-
objs[0] = safe.Request_clone.call(objs[0]);
993-
} catch(ex) {
994-
safe.uboErr(logPrefix, 'Error:', ex);
995-
}
996-
}
997-
if ( args[1] instanceof Object ) {
998-
objs.push(args[1]);
999-
}
1000-
const matched = matchObjectPropertiesFn(propNeedles, ...objs);
973+
const props = collateFetchArgumentsFn(...args);
974+
const matched = matchObjectPropertiesFn(propNeedles, props);
1001975
if ( matched === undefined ) { return fetchPromise; }
1002976
if ( safe.logLevel > 1 ) {
1003977
safe.uboLog(logPrefix, `Matched "propsToMatch":\n\t${matched.join('\n\t')}`);
@@ -1039,6 +1013,7 @@ function jsonlEditFetchResponseFn(trusted, jsonq = '') {
10391013
registerScriptlet(jsonlEditFetchResponseFn, {
10401014
name: 'jsonl-edit-fetch-response.fn',
10411015
dependencies: [
1016+
collateFetchArgumentsFn,
10421017
JSONPath,
10431018
jsonlEditFn,
10441019
matchObjectPropertiesFn,

src/js/resources/json-prune.js

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
*/
2222

2323
import {
24+
collateFetchArgumentsFn,
2425
matchObjectPropertiesFn,
2526
parsePropertiesToMatchFn,
2627
} from './utils.js';
@@ -86,18 +87,8 @@ function jsonPruneFetchResponse(
8687
const applyHandler = function(target, thisArg, args) {
8788
const fetchPromise = Reflect.apply(target, thisArg, args);
8889
if ( propNeedles.size !== 0 ) {
89-
const objs = [ args[0] instanceof Object ? args[0] : { url: args[0] } ];
90-
if ( objs[0] instanceof Request ) {
91-
try {
92-
objs[0] = safe.Request_clone.call(objs[0]);
93-
} catch(ex) {
94-
safe.uboErr(logPrefix, 'Error:', ex);
95-
}
96-
}
97-
if ( args[1] instanceof Object ) {
98-
objs.push(args[1]);
99-
}
100-
const matched = matchObjectPropertiesFn(propNeedles, ...objs);
90+
const props = collateFetchArgumentsFn(...args);
91+
const matched = matchObjectPropertiesFn(propNeedles, props);
10192
if ( matched === undefined ) { return fetchPromise; }
10293
if ( safe.logLevel > 1 ) {
10394
safe.uboLog(logPrefix, `Matched "propsToMatch":\n\t${matched.join('\n\t')}`);
@@ -148,6 +139,7 @@ function jsonPruneFetchResponse(
148139
registerScriptlet(jsonPruneFetchResponse, {
149140
name: 'json-prune-fetch-response.js',
150141
dependencies: [
142+
collateFetchArgumentsFn,
151143
matchObjectPropertiesFn,
152144
objectPruneFn,
153145
parsePropertiesToMatchFn,

src/js/resources/prevent-fetch.js

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
*/
2222

2323
import {
24+
collateFetchArgumentsFn,
2425
generateContentFn,
2526
matchObjectPropertiesFn,
2627
parsePropertiesToMatchFn,
@@ -75,32 +76,9 @@ function preventFetchFn(
7576
responseProps.type = { value: responseType };
7677
}
7778
}
78-
const fetchProps = (src, out) => {
79-
if ( typeof src !== 'object' || src === null ) { return; }
80-
const props = [
81-
'body', 'cache', 'credentials', 'duplex', 'headers',
82-
'integrity', 'keepalive', 'method', 'mode', 'priority',
83-
'redirect', 'referrer', 'referrerPolicy', 'signal',
84-
];
85-
for ( const prop of props ) {
86-
if ( src[prop] === undefined ) { continue; }
87-
out[prop] = src[prop];
88-
}
89-
};
90-
const fetchDetails = args => {
91-
const out = {};
92-
if ( args[0] instanceof self.Request ) {
93-
out.url = `${args[0].url}`;
94-
fetchProps(args[0], out);
95-
} else {
96-
out.url = `${args[0]}`;
97-
}
98-
fetchProps(args[1], out);
99-
return out;
100-
};
10179
proxyApplyFn('fetch', function fetch(context) {
10280
const { callArgs } = context;
103-
const details = fetchDetails(callArgs);
81+
const details = collateFetchArgumentsFn(...callArgs);
10482
if ( safe.logLevel > 1 || propsToMatch === '' && responseBody === '' ) {
10583
const out = Array.from(Object.entries(details)).map(a => `${a[0]}:${a[1]}`);
10684
safe.uboLog(logPrefix, `Called: ${out.join('\n')}`);
@@ -136,6 +114,7 @@ function preventFetchFn(
136114
registerScriptlet(preventFetchFn, {
137115
name: 'prevent-fetch.fn',
138116
dependencies: [
117+
collateFetchArgumentsFn,
139118
generateContentFn,
140119
matchObjectPropertiesFn,
141120
parsePropertiesToMatchFn,

src/js/resources/safe-self.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export function safeSelf() {
4747
'Object_fromEntries': Object.fromEntries.bind(Object),
4848
'Object_getOwnPropertyDescriptor': Object.getOwnPropertyDescriptor.bind(Object),
4949
'Object_hasOwn': Object.hasOwn.bind(Object),
50+
'Object_toString': Object.prototype.toString,
5051
'RegExp': self.RegExp,
5152
'RegExp_test': self.RegExp.prototype.test,
5253
'RegExp_exec': self.RegExp.prototype.exec,

src/js/resources/scriptlets.js

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import './replace-argument.js';
3535
import './spoof-css.js';
3636

3737
import {
38+
collateFetchArgumentsFn,
3839
generateContentFn,
3940
getExceptionTokenFn,
4041
getRandomTokenFn,
@@ -314,6 +315,7 @@ builtinScriptlets.push({
314315
name: 'replace-fetch-response.fn',
315316
fn: replaceFetchResponseFn,
316317
dependencies: [
318+
'collate-fetch-arguments.fn',
317319
'match-object-properties.fn',
318320
'parse-properties-to-match.fn',
319321
'safe-self.fn',
@@ -338,19 +340,8 @@ function replaceFetchResponseFn(
338340
const fetchPromise = Reflect.apply(target, thisArg, args);
339341
if ( pattern === '' ) { return fetchPromise; }
340342
if ( propNeedles.size !== 0 ) {
341-
const objs = [ args[0] instanceof Object ? args[0] : { url: args[0] } ];
342-
if ( objs[0] instanceof Request ) {
343-
try {
344-
objs[0] = safe.Request_clone.call(objs[0]);
345-
}
346-
catch(ex) {
347-
safe.uboErr(logPrefix, ex);
348-
}
349-
}
350-
if ( args[1] instanceof Object ) {
351-
objs.push(args[1]);
352-
}
353-
const matched = matchObjectPropertiesFn(propNeedles, ...objs);
343+
const props = collateFetchArgumentsFn(...args);
344+
const matched = matchObjectPropertiesFn(propNeedles, props);
354345
if ( matched === undefined ) { return fetchPromise; }
355346
if ( safe.logLevel > 1 ) {
356347
safe.uboLog(logPrefix, `Matched "propsToMatch":\n\t${matched.join('\n\t')}`);

src/js/resources/utils.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,44 @@ registerScriptlet(getExceptionTokenFn, {
6262

6363
/******************************************************************************/
6464

65+
export function collateFetchArgumentsFn(resource, options) {
66+
const safe = safeSelf();
67+
const props = [
68+
'body', 'cache', 'credentials', 'duplex', 'headers',
69+
'integrity', 'keepalive', 'method', 'mode', 'priority',
70+
'redirect', 'referrer', 'referrerPolicy', 'signal',
71+
];
72+
const out = {};
73+
if ( collateFetchArgumentsFn.collateKnownProps === undefined ) {
74+
collateFetchArgumentsFn.collateKnownProps = (src, out) => {
75+
for ( const prop of props ) {
76+
if ( src[prop] === undefined ) { continue; }
77+
out[prop] = src[prop];
78+
}
79+
};
80+
}
81+
if (
82+
typeof resource !== 'object' ||
83+
safe.Object_toString.call(resource) !== '[object Request]'
84+
) {
85+
out.url = `${resource}`;
86+
} else {
87+
collateFetchArgumentsFn.collateKnownProps(resource, out);
88+
}
89+
if ( typeof options === 'object' && options !== null ) {
90+
collateFetchArgumentsFn.collateKnownProps(options, out);
91+
}
92+
return out;
93+
}
94+
registerScriptlet(collateFetchArgumentsFn, {
95+
name: 'collate-fetch-arguments.fn',
96+
dependencies: [
97+
safeSelf,
98+
],
99+
});
100+
101+
/******************************************************************************/
102+
65103
export function parsePropertiesToMatchFn(propsToMatch, implicit = '') {
66104
const safe = safeSelf();
67105
const needles = new Map();

0 commit comments

Comments
 (0)