/******************************************************************************* uBlock Origin - a browser extension to block requests. Copyright (C) 2019-present Raymond Hill This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see {http://www.gnu.org/licenses/}. Home: https://github.com/gorhill/uBlock The scriptlets below are meant to be injected only into a web page context. */ /* jshint esversion:11 */ 'use strict'; /******************************************************************************/ /// name no-xhr-if /******************************************************************************/ // Important! // Isolate from global scope (function uBOL_noXhrIf() { /******************************************************************************/ // $rulesetId$ const argsList = self.$argsList$; const hostnamesMap = new Map(self.$hostnamesMap$); /******************************************************************************/ const scriptlet = ( conditions = '' ) => { const xhrInstances = new WeakMap(); const needles = []; for ( const condition of conditions.split(/\s+/) ) { if ( condition === '' ) { continue; } const pos = condition.indexOf(':'); let key, value; if ( pos !== -1 ) { key = condition.slice(0, pos); value = condition.slice(pos + 1); } else { key = 'url'; value = condition; } if ( value === '' ) { value = '^'; } else if ( value.startsWith('/') && value.endsWith('/') ) { value = value.slice(1, -1); } else { value = value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } needles.push({ key, re: new RegExp(value) }); } self.XMLHttpRequest = class extends self.XMLHttpRequest { open(...args) { const argNames = [ 'method', 'url' ]; const haystack = new Map(); for ( let i = 0; i < args.length && i < argNames.length; i++ ) { haystack.set(argNames[i], args[i]); } if ( haystack.size !== 0 ) { let matches = true; for ( const { key, re } of needles ) { matches = re.test(haystack.get(key) || ''); if ( matches === false ) { break; } } if ( matches ) { xhrInstances.set(this, haystack); } } return super.open(...args); } send(...args) { const haystack = xhrInstances.get(this); if ( haystack === undefined ) { return super.send(...args); } Object.defineProperties(this, { readyState: { value: 4, writable: false }, response: { value: '', writable: false }, responseText: { value: '', writable: false }, responseURL: { value: haystack.get('url'), writable: false }, responseXML: { value: '', writable: false }, status: { value: 200, writable: false }, statusText: { value: 'OK', writable: false }, }); this.dispatchEvent(new Event('readystatechange')); this.dispatchEvent(new Event('load')); this.dispatchEvent(new Event('loadend')); } }; }; /******************************************************************************/ let hn; try { hn = document.location.hostname; } catch(ex) { } while ( hn ) { if ( hostnamesMap.has(hn) ) { let argsIndices = hostnamesMap.get(hn); if ( typeof argsIndices === 'number' ) { argsIndices = [ argsIndices ]; } for ( const argsIndex of argsIndices ) { const details = argsList[argsIndex]; if ( details.n && details.n.includes(hn) ) { continue; } try { scriptlet(...details.a); } catch(ex) {} } } if ( hn === '*' ) { break; } const pos = hn.indexOf('.'); if ( pos !== -1 ) { hn = hn.slice(pos + 1); } else { hn = '*'; } } argsList.length = 0; hostnamesMap.clear(); /******************************************************************************/ })(); /******************************************************************************/