-
Notifications
You must be signed in to change notification settings - Fork 107
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: $removeparam
#4528
base: master
Are you sure you want to change the base?
feat: $removeparam
#4528
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: we're going to apply filters one by one |
Leaving a note: regexp wrapping: |
test: add `isRemoveParam` and `isRedirectable` chore: reject on `removeparam` negation test: parsing removeparam test: removeparam test: removeparam
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this support exceptions like $removeparam=igshid,domain=instagram.com|threads.net
?
* s1) global removal + exception => global removal wins ``` @@||example.com$removeparam=utm ||example.com$removeparam ``` result.filter=global removal result.exception=(none) * s2) removal + global exception => exception wins ``` ||example.com$removeparam=utm @@||example.com$removeparam ``` result.filter=removal result.exception=global exception * s3) removal + exception => exception wins ``` ||example.com$removeparam=utm @@||example.com$removeparam=utm ``` result.filter=removal result.exception=exception --- 0. global exception 1. global removal 2. exception 3. removal
We don't know what operations will be done in the meantime but we know that all operations are safe at the end.
@@ -1151,6 +1162,8 @@ export default class NetworkFilter implements IFilter { | |||
} | |||
} | |||
|
|||
mask >>>= 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@chrmod @remusao Should we move this operator to constructor or another place? We need to make sure that the mask
to be uint32 before it get serialized for safety. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unsigned_right_shift_assignment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@seia-soto can this be removed now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lets move out the bit operations safety out of this PR. Besides, it looks good imo.
Waiting for #4634 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The AdGuard documentation mentions:
Please note that such rules are only applied to GET, HEAD, OPTIONS, and sometimes POST requests.
Where do we intend to perform those checks?
if (filter.isRemoveParam()) { | ||
redirects.push(filter); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we store removeparam as redirect rules? Aren't they of different nature?
for (const filter of redirectableFilters) { | ||
if (filter.isRemoveParam()) { | ||
if (filter.isException()) { | ||
removeparamExceptionFilters.set(filter.removeparam!, filter); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it might be possible to inform the type checker from isRemoveParam
that filter.removeparam
is not undefined/null.
if (filter.isException()) { | ||
removeparamExceptionFilters.set(filter.removeparam!, filter); | ||
} else { | ||
removeparamFilters.set(filter.removeparam!, filter); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it safe to use removeparam
as a key in a Set? What about other possible constraints like 1p/3p, or request type such as script/xhr/etc.
// * If redirect=none is found, then cancel all redirects. | ||
// * Else if redirect-rule is found, only redirect if request would be blocked. | ||
// * Else if redirect is found, redirect. | ||
if (result.filter === undefined && redirectFilters.length !== 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the rational behind giving priority to removeparam over redirects? Wouldn't it make sense to do it the other way around? A redirect rule is a block rule + a redirect rule (as per uBO semantics). Hence if a request is blocked it should have priority over keeping the request and remove some of the parameters.
@@ -888,6 +889,16 @@ export default class NetworkFilter implements IFilter { | |||
mask = setBit(mask, NETWORK_FILTER_MASK.isReplace); | |||
optionValue = value; | |||
|
|||
break; | |||
case 'removeparam': | |||
// TODO: Support regex |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about ~
negation supported by AdGuard? I see it might be handled below but maybe worth documenting the limitation (and having a unit test for each)
} | ||
|
||
if (redirectUrl.searchParams.has(key)) { | ||
result.filter = filter; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That seems invalid in case there is more than one removeparam
filter applying to the URL. I also think that in terms of semantics, the result.filter
means a blocking filter, but removeparam filters aren't blocking requests. Maybe would it make more sense to add an additional key on result
with a list of removeparams (or if we want to generalize, a list of URL/request modifiers)
for (let i = 0; i < params.length; i++) { | ||
const { redirect } = engine.match(request); | ||
expect(redirect).not.to.be.undefined; | ||
request = urlToDocumentRequest(redirect!.dataUrl); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is surprising to me that we need to call the .match(...)
multiple times to remove all params. Shouldn't a single call to .match(...)
remove all matching params in a single pass?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We didn't know how to return the filters matched since the return type allows only one filter to be returned. That means not the all of filters matched will be sent to the return value of match
unless we change the shape.
result.redirect = { | ||
body: '', | ||
contentType: 'text/plain', | ||
dataUrl: redirectUrl!.toString(), | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems a bit counter-intuitive to me to reuse the dataUrl in order to express the removeparam result. Why not return a list of URL modifiers to be interpreted by the client code and adapted based on available capability of the platform? (iOS, Manifest v2, Manifest v3, might not have the best way to modify request parameters) Ideally the adblocker library should not need to think about these considerations and return a more "abstract" kind of response.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add more tests for corner cases? For example: if we have a global $removeparam
and also @@||example.org$removeparam=utm
, do we remove all parameters or skip utm
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add a test case to cover the regexp removeparam case (as being unsupported for now)
This adds experimental
$removeparam
support for adblocker: https://github.com/gorhill/ublock/wiki/static-filter-syntax#removeparamThe suggested matching process changed by this PR is illustrated as follows:
The removeparam filter priorities are as the followings, and also described in the exception test as a code:
Details
result.filter=global removal
result.exception=(none)
result.filter=removal
result.exception=global exception
result.filter=removal
result.exception=exception
TODO