@@ -1291,8 +1291,8 @@ function jsonPruneFetchResponse(
1291
1291
rawNeedlePaths ,
1292
1292
{ matchAll : true } ,
1293
1293
extraArgs
1294
- ) ;
1295
- if ( typeof objAfter !== 'object' ) { return responseBefore ; }
1294
+ ) ;
1295
+ if ( typeof objAfter !== 'object' ) { return responseBefore ; }
1296
1296
const responseAfter = Response . json ( objAfter , {
1297
1297
status : responseBefore . status ,
1298
1298
statusText : responseBefore . statusText ,
@@ -1321,6 +1321,113 @@ function jsonPruneFetchResponse(
1321
1321
1322
1322
/******************************************************************************/
1323
1323
1324
+ builtinScriptlets . push ( {
1325
+ name : 'json-prune-xhr-response.js' ,
1326
+ fn : jsonPruneXhrResponse ,
1327
+ dependencies : [
1328
+ 'match-object-properties.fn' ,
1329
+ 'object-prune.fn' ,
1330
+ 'parse-properties-to-match.fn' ,
1331
+ 'safe-self.fn' ,
1332
+ 'should-log.fn' ,
1333
+ ] ,
1334
+ } ) ;
1335
+ function jsonPruneXhrResponse (
1336
+ rawPrunePaths = '' ,
1337
+ rawNeedlePaths = ''
1338
+ ) {
1339
+ const safe = safeSelf ( ) ;
1340
+ const xhrInstances = new WeakMap ( ) ;
1341
+ const extraArgs = safe . getExtraArgs ( Array . from ( arguments ) , 2 ) ;
1342
+ const logLevel = shouldLog ( { log : rawPrunePaths === '' || extraArgs . log , } ) ;
1343
+ const log = logLevel ? ( ( ...args ) => { safe . uboLog ( ...args ) ; } ) : ( ( ) => { } ) ;
1344
+ const propNeedles = parsePropertiesToMatch ( extraArgs . propsToMatch , 'url' ) ;
1345
+ self . XMLHttpRequest = class extends self . XMLHttpRequest {
1346
+ open ( method , url , ...args ) {
1347
+ const outerXhr = this ;
1348
+ const xhrDetails = { method, url, args : [ ...args ] } ;
1349
+ let outcome = 'match' ;
1350
+ if ( propNeedles . size !== 0 ) {
1351
+ if ( matchObjectProperties ( propNeedles , { method, url } ) === false ) {
1352
+ outcome = 'nomatch' ;
1353
+ }
1354
+ }
1355
+ if ( outcome === logLevel || outcome === 'all' ) {
1356
+ log ( `xhr.open(${ method } , ${ url } , ${ args . join ( ', ' ) } )` ) ;
1357
+ }
1358
+ if ( outcome === 'match' ) {
1359
+ xhrInstances . set ( outerXhr , xhrDetails ) ;
1360
+ }
1361
+ return super . open ( method , url , ...args ) ;
1362
+ }
1363
+ send ( ...args ) {
1364
+ const outerXhr = this ;
1365
+ const xhrDetails = xhrInstances . get ( outerXhr ) ;
1366
+ if ( xhrDetails === undefined ) {
1367
+ return super . send ( ...args ) ;
1368
+ }
1369
+ switch ( outerXhr . responseType ) {
1370
+ case '' :
1371
+ case 'json' :
1372
+ case 'text' :
1373
+ break ;
1374
+ default :
1375
+ return super . send ( ...args ) ;
1376
+ }
1377
+ const innerXhr = new safe . XMLHttpRequest ( ) ;
1378
+ innerXhr . open ( xhrDetails . method , xhrDetails . url , ...xhrDetails . args ) ;
1379
+ innerXhr . responseType = outerXhr . responseType ;
1380
+ innerXhr . onloadend = function ( ) {
1381
+ let objBefore ;
1382
+ switch ( outerXhr . responseType ) {
1383
+ case '' :
1384
+ case 'text' :
1385
+ try {
1386
+ objBefore = safe . jsonParse ( innerXhr . responseText ) ;
1387
+ } catch ( ex ) {
1388
+ }
1389
+ break ;
1390
+ case 'json' :
1391
+ objBefore = innerXhr . response ;
1392
+ break ;
1393
+ default :
1394
+ break ;
1395
+ }
1396
+ let objAfter ;
1397
+ if ( typeof objBefore === 'object' ) {
1398
+ objAfter = objectPrune (
1399
+ objBefore ,
1400
+ rawPrunePaths ,
1401
+ rawNeedlePaths ,
1402
+ { matchAll : true } ,
1403
+ extraArgs
1404
+ ) ;
1405
+ }
1406
+ let response = objAfter || objBefore ;
1407
+ let responseText = '' ;
1408
+ if ( typeof response === 'object' && outerXhr . responseType !== 'json' ) {
1409
+ response = responseText = safe . jsonStringify ( response ) ;
1410
+ }
1411
+ Object . defineProperties ( outerXhr , {
1412
+ readyState : { value : 4 } ,
1413
+ response : { value : response } ,
1414
+ responseText : { value : responseText } ,
1415
+ responseXML : { value : null } ,
1416
+ responseURL : { value : innerXhr . url } ,
1417
+ status : { value : innerXhr . status } ,
1418
+ statusText : { value : innerXhr . statusText } ,
1419
+ } ) ;
1420
+ outerXhr . dispatchEvent ( new Event ( 'readystatechange' ) ) ;
1421
+ outerXhr . dispatchEvent ( new Event ( 'load' ) ) ;
1422
+ outerXhr . dispatchEvent ( new Event ( 'loadend' ) ) ;
1423
+ } ;
1424
+ innerXhr . send ( ...args ) ;
1425
+ }
1426
+ } ;
1427
+ }
1428
+
1429
+ /******************************************************************************/
1430
+
1324
1431
// There is still code out there which uses `eval` in lieu of `JSON.parse`.
1325
1432
1326
1433
builtinScriptlets . push ( {
@@ -3622,3 +3729,102 @@ function trustedReplaceFetchResponse(
3622
3729
}
3623
3730
3624
3731
/******************************************************************************/
3732
+
3733
+ builtinScriptlets . push ( {
3734
+ name : 'trusted-replace-xhr-response.js' ,
3735
+ fn : trustedReplaceXhrResponse ,
3736
+ dependencies : [
3737
+ 'match-object-properties.fn' ,
3738
+ 'parse-properties-to-match.fn' ,
3739
+ 'safe-self.fn' ,
3740
+ 'should-log.fn' ,
3741
+ ] ,
3742
+ } ) ;
3743
+ function trustedReplaceXhrResponse (
3744
+ pattern = '' ,
3745
+ replacement = '' ,
3746
+ propsToMatch = ''
3747
+ ) {
3748
+ const safe = safeSelf ( ) ;
3749
+ const xhrInstances = new WeakMap ( ) ;
3750
+ const extraArgs = safe . getExtraArgs ( Array . from ( arguments ) , 3 ) ;
3751
+ const logLevel = shouldLog ( {
3752
+ log : pattern === '' && 'all' || extraArgs . log ,
3753
+ } ) ;
3754
+ const log = logLevel ? ( ( ...args ) => { safe . uboLog ( ...args ) ; } ) : ( ( ) => { } ) ;
3755
+ if ( pattern === '*' ) { pattern = '.*' ; }
3756
+ const rePattern = safe . patternToRegex ( pattern ) ;
3757
+ const propNeedles = parsePropertiesToMatch ( propsToMatch , 'url' ) ;
3758
+ self . XMLHttpRequest = class extends self . XMLHttpRequest {
3759
+ open ( method , url , ...args ) {
3760
+ const outerXhr = this ;
3761
+ const xhrDetails = { method, url, args : [ ...args ] } ;
3762
+ let outcome = 'match' ;
3763
+ if ( propNeedles . size !== 0 ) {
3764
+ if ( matchObjectProperties ( propNeedles , { method, url } ) === false ) {
3765
+ outcome = 'nomatch' ;
3766
+ }
3767
+ }
3768
+ if ( outcome === logLevel || outcome === 'all' ) {
3769
+ log ( `xhr.open(${ method } , ${ url } , ${ args . join ( ', ' ) } )` ) ;
3770
+ }
3771
+ if ( outcome === 'match' ) {
3772
+ xhrInstances . set ( outerXhr , xhrDetails ) ;
3773
+ }
3774
+ return super . open ( method , url , ...args ) ;
3775
+ }
3776
+ send ( ...args ) {
3777
+ const outerXhr = this ;
3778
+ const xhrDetails = xhrInstances . get ( outerXhr ) ;
3779
+ if ( xhrDetails === undefined ) {
3780
+ return super . send ( ...args ) ;
3781
+ }
3782
+ switch ( outerXhr . responseType ) {
3783
+ case '' :
3784
+ case 'json' :
3785
+ case 'text' :
3786
+ break ;
3787
+ default :
3788
+ return super . send ( ...args ) ;
3789
+ }
3790
+ const innerXhr = new safe . XMLHttpRequest ( ) ;
3791
+ innerXhr . open ( xhrDetails . method , xhrDetails . url , ...xhrDetails . args ) ;
3792
+ innerXhr . responseType = outerXhr . responseType ;
3793
+ innerXhr . onloadend = function ( ) {
3794
+ const textBefore = innerXhr . responseText ;
3795
+ const textAfter = textBefore . replace ( rePattern , replacement ) ;
3796
+ const outcome = textAfter !== textBefore ? 'match' : 'nomatch' ;
3797
+ if ( outcome === logLevel || logLevel === 'all' ) {
3798
+ log (
3799
+ `trusted-replace-xhr-response (${ outcome } )` ,
3800
+ `\n\tpattern: ${ pattern } ` ,
3801
+ `\n\treplacement: ${ replacement } ` ,
3802
+ ) ;
3803
+ }
3804
+ let response = innerXhr . responseText ;
3805
+ if ( outerXhr . responseType === 'json' ) {
3806
+ try {
3807
+ response = safe . jsonParse ( innerXhr . responseText ) ;
3808
+ } catch ( ex ) {
3809
+ response = innerXhr . response ;
3810
+ }
3811
+ }
3812
+ Object . defineProperties ( outerXhr , {
3813
+ readyState : { value : 4 } ,
3814
+ response : { value : response } ,
3815
+ responseText : { value : textAfter } ,
3816
+ responseXML : { value : null } ,
3817
+ responseURL : { value : innerXhr . url } ,
3818
+ status : { value : innerXhr . status } ,
3819
+ statusText : { value : innerXhr . statusText } ,
3820
+ } ) ;
3821
+ outerXhr . dispatchEvent ( new Event ( 'readystatechange' ) ) ;
3822
+ outerXhr . dispatchEvent ( new Event ( 'load' ) ) ;
3823
+ outerXhr . dispatchEvent ( new Event ( 'loadend' ) ) ;
3824
+ } ;
3825
+ innerXhr . send ( ...args ) ;
3826
+ }
3827
+ } ;
3828
+ }
3829
+
3830
+ /******************************************************************************/
0 commit comments