Skip to content

Commit c86ed52

Browse files
committed
Add regex extraction transformation step to urlskip= option
Related feedback: uBlockOrigin/uBlock-issues#3206 (comment) The first capture group of the regex will be used as the result of the transformation. Example: ||podtrac.com/pts/redirect.mp3/$urlskip=/podtrac\.com\/pts\/redirect\.mp3\/(.*?\.mp3\b)/ +https If the regex is invalid, or if it fails to extract a first capture group, no redirection will occur.
1 parent 913f20f commit c86ed52

File tree

1 file changed

+76
-25
lines changed

1 file changed

+76
-25
lines changed

src/js/static-net-filtering.js

Lines changed: 76 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5356,12 +5356,10 @@ StaticNetFilteringEngine.prototype.transformRequest = function(fctxt, out = [])
53565356
out.push(directive);
53575357
continue;
53585358
}
5359-
const { refs } = directive;
5360-
if ( refs instanceof Object === false ) { continue; }
5361-
if ( refs.$cache === null ) {
5362-
refs.$cache = sfp.parseReplaceValue(refs.value);
5359+
if ( directive.cache === null ) {
5360+
directive.cache = sfp.parseReplaceValue(directive.value);
53635361
}
5364-
const cache = refs.$cache;
5362+
const cache = directive.cache;
53655363
if ( cache === undefined ) { continue; }
53665364
const before = `${redirectURL.pathname}${redirectURL.search}${redirectURL.hash}`;
53675365
if ( cache.re.test(before) !== true ) { continue; }
@@ -5382,7 +5380,49 @@ StaticNetFilteringEngine.prototype.transformRequest = function(fctxt, out = [])
53825380
return out;
53835381
};
53845382

5385-
/******************************************************************************/
5383+
/**
5384+
* @trustedOption urlkip
5385+
*
5386+
* @description
5387+
* Extract a URL from another URL according to one or more transformation steps,
5388+
* thereby skipping over intermediate network request(s) to remote servers.
5389+
* Requires a trusted source.
5390+
*
5391+
* @param steps
5392+
* A serie of space-separated directives representing the transformation steps
5393+
* to perform to extract the final URL to which a network request should be
5394+
* redirected.
5395+
*
5396+
* Supported directives:
5397+
*
5398+
* `?name`: extract the value of parameter `name` as the current string.
5399+
*
5400+
* `&i`: extract the name of the parameter at position `i` as the current
5401+
* string. The position is 1-based.
5402+
*
5403+
* `/.../`: extract the first capture group of a regex as the current string.
5404+
*
5405+
* `+https`: prepend the current string with `https://`.
5406+
*
5407+
* `-base64`: decode the current string as a base64-encoded string.
5408+
*
5409+
* At any given step, the currently extracted string may not necessarily be
5410+
* a valid URL, and more transformation steps may be needed to obtain a valid
5411+
* URL once all the steps are applied.
5412+
*
5413+
* An unsupported step or a failed step will abort the transformation and no
5414+
* redirection will be performed.
5415+
*
5416+
* The final step is expected to yield a valid URL. If the result is not a
5417+
* valid URL, no redirection will be performed.
5418+
*
5419+
* @example
5420+
* ||example.com/path/to/tracker$urlskip=?url
5421+
* ||example.com/path/to/tracker$urlskip=?url ?to
5422+
* ||pixiv.net/jump.php?$urlskip=&1
5423+
* ||podtrac.com/pts/redirect.mp3/$urlskip=/podtrac\.com\/pts\/redirect\.mp3\/(.*?\.mp3\b)/ +https
5424+
*
5425+
* */
53865426

53875427
StaticNetFilteringEngine.prototype.urlSkip = function(fctxt, out = []) {
53885428
if ( fctxt.redirectURL !== undefined ) { return; }
@@ -5396,7 +5436,7 @@ StaticNetFilteringEngine.prototype.urlSkip = function(fctxt, out = []) {
53965436
const urlin = fctxt.url;
53975437
const value = directive.value;
53985438
const steps = value.includes(' ') && value.split(/ +/) || [ value ];
5399-
const urlout = urlSkip(urlin, steps);
5439+
const urlout = urlSkip(directive, urlin, steps);
54005440
if ( urlout === undefined ) { continue; }
54015441
if ( urlout === urlin ) { continue; }
54025442
fctxt.redirectURL = urlout;
@@ -5407,41 +5447,52 @@ StaticNetFilteringEngine.prototype.urlSkip = function(fctxt, out = []) {
54075447
return out;
54085448
};
54095449

5410-
function urlSkip(urlin, steps) {
5450+
function urlSkip(directive, urlin, steps) {
54115451
try {
5412-
let urlout;
5452+
let urlout = urlin;
54135453
for ( const step of steps ) {
5454+
const urlin = urlout;
54145455
const c0 = step.charCodeAt(0);
5415-
// Extract from URL parameter
5416-
if ( c0 === 0x3F ) { /* ? */
5417-
urlout = (new URL(urlin)).searchParams.get(step.slice(1));
5418-
if ( urlout === null ) { return; }
5419-
if ( urlout.includes(' ') ) {
5420-
urlout = urlout.replace(/ /g, '%20');
5421-
}
5422-
urlin = urlout;
5423-
continue;
5424-
}
54255456
// Extract from URL parameter name at position i
5426-
if ( c0 === 0x26 ) { /* & */
5457+
if ( c0 === 0x26 ) { // &
54275458
const i = (parseInt(step.slice(1)) || 0) - 1;
54285459
if ( i < 0 ) { return; }
54295460
const url = new URL(urlin);
54305461
if ( i >= url.searchParams.size ) { return; }
54315462
const params = Array.from(url.searchParams.keys());
5432-
urlin = urlout = decodeURIComponent(params[i]);
5463+
urlout = decodeURIComponent(params[i]);
54335464
continue;
54345465
}
54355466
// Enforce https
5436-
if ( step === '+https' ) {
5467+
if ( c0 === 0x2B && step === '+https' ) {
54375468
const s = urlin.replace(/^https?:\/\//, '');
54385469
if ( /^[\w-]:\/\//.test(s) ) { return; }
5439-
urlin = urlout = `https://${s}`;
5470+
urlout = `https://${s}`;
54405471
continue;
54415472
}
54425473
// Decode base64
5443-
if ( step === '-base64' ) {
5444-
urlin = urlout = self.atob(urlin);
5474+
if ( c0 === 0x2D && step === '-base64' ) {
5475+
urlout = self.atob(urlin);
5476+
continue;
5477+
}
5478+
// Regex extraction from first capture group
5479+
if ( c0 === 0x2F ) { // /
5480+
if ( directive.cache === null ) {
5481+
directive.cache = new RegExp(step.slice(1, -1));
5482+
}
5483+
const match = directive.cache.exec(urlin);
5484+
if ( match === null ) { return; }
5485+
if ( match.length <= 1 ) { return; }
5486+
urlout = match[1];
5487+
continue;
5488+
}
5489+
// Extract from URL parameter
5490+
if ( c0 === 0x3F ) { // ?
5491+
urlout = (new URL(urlin)).searchParams.get(step.slice(1));
5492+
if ( urlout === null ) { return; }
5493+
if ( urlout.includes(' ') ) {
5494+
urlout = urlout.replace(/ /g, '%20');
5495+
}
54455496
continue;
54465497
}
54475498
// Unknown directive

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy