Add option to filter by HTTP method in static network filters

Related issue:
- https://github.com/uBlockOrigin/uBlock-issues/issues/2117

Option: `method=`
Value: a list of `|`-separated lowercased method names. Negated
method names are allowed. These are valid methods:

- connect
- delete
- get
- head
- options
- patch
- post
- put

As per DNR's own documentation:
- https://developer.chrome.com/docs/extensions/reference/declarativeNetRequest/#type-RequestMethod

The logger shows the method used for every network request. It's
possible to filter the logger output for most-common methods: `get`,
`head`, `post`.
This commit is contained in:
Raymond Hill 2022-12-18 15:36:59 -05:00
parent e5a9b066ec
commit b6981877ba
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
8 changed files with 305 additions and 89 deletions

View File

@ -5,6 +5,7 @@
"esversion": 8, "esversion": 8,
"globals": { "globals": {
"chrome": false, // global variable in Chromium, Chrome, Opera "chrome": false, // global variable in Chromium, Chrome, Opera
"globalThis": false,
"self": false, "self": false,
"vAPI": false, "vAPI": false,
"URLSearchParams": false, "URLSearchParams": false,

View File

@ -176,8 +176,8 @@ const µBlock = { // jshint ignore:line
// Read-only // Read-only
systemSettings: { systemSettings: {
compiledMagic: 50, // Increase when compiled format changes compiledMagic: 51, // Increase when compiled format changes
selfieMagic: 50, // Increase when selfie format changes selfieMagic: 51, // Increase when selfie format changes
}, },
// https://github.com/uBlockOrigin/uBlock-issues/issues/759#issuecomment-546654501 // https://github.com/uBlockOrigin/uBlock-issues/issues/759#issuecomment-546654501
@ -285,6 +285,7 @@ const µBlock = { // jshint ignore:line
this.fromTabId(tabId); // Must be called AFTER tab context management this.fromTabId(tabId); // Must be called AFTER tab context management
this.realm = ''; this.realm = '';
this.id = details.requestId; this.id = details.requestId;
this.setMethod(details.method);
this.setURL(details.url); this.setURL(details.url);
this.aliasURL = details.aliasURL || undefined; this.aliasURL = details.aliasURL || undefined;
if ( this.itype !== this.SUB_FRAME ) { if ( this.itype !== this.SUB_FRAME ) {
@ -337,24 +338,31 @@ const µBlock = { // jshint ignore:line
} }
toLogger() { toLogger() {
this.tstamp = Date.now(); const details = {
if ( this.domain === undefined ) { id: this.id,
void this.getDomain(); tstamp: Date.now(),
} realm: this.realm,
if ( this.docDomain === undefined ) { method: this.getMethodName(),
void this.getDocDomain(); type: this.stype,
} tabId: this.tabId,
if ( this.tabDomain === undefined ) { tabDomain: this.getTabDomain(),
void this.getTabDomain(); tabHostname: this.getTabHostname(),
} docDomain: this.getDocDomain(),
const filters = this.filter; docHostname: this.getDocHostname(),
domain: this.getDomain(),
hostname: this.getHostname(),
url: this.url,
aliasURL: this.aliasURL,
filter: undefined,
};
// Many filters may have been applied to the current context // Many filters may have been applied to the current context
if ( Array.isArray(filters) === false ) { if ( Array.isArray(this.filter) === false ) {
return logger.writeOne(this); details.filter = this.filter;
return logger.writeOne(details);
} }
for ( const filter of filters ) { for ( const filter of this.filter ) {
this.filter = filter; details.filter = filter;
logger.writeOne(this); logger.writeOne(details);
} }
} }
}; };

View File

@ -84,6 +84,48 @@ const typeStrToIntMap = {
'other': OTHER, 'other': OTHER,
}; };
const METHOD_NONE = 0;
const METHOD_CONNECT = 1 << 1;
const METHOD_DELETE = 1 << 2;
const METHOD_GET = 1 << 3;
const METHOD_HEAD = 1 << 4;
const METHOD_OPTIONS = 1 << 5;
const METHOD_PATCH = 1 << 6;
const METHOD_POST = 1 << 7;
const METHOD_PUT = 1 << 8;
const methodStrToBitMap = {
'': METHOD_NONE,
'connect': METHOD_CONNECT,
'delete': METHOD_DELETE,
'get': METHOD_GET,
'head': METHOD_HEAD,
'options': METHOD_OPTIONS,
'patch': METHOD_PATCH,
'post': METHOD_POST,
'put': METHOD_PUT,
'CONNECT': METHOD_CONNECT,
'DELETE': METHOD_DELETE,
'GET': METHOD_GET,
'HEAD': METHOD_HEAD,
'OPTIONS': METHOD_OPTIONS,
'PATCH': METHOD_PATCH,
'POST': METHOD_POST,
'PUT': METHOD_PUT,
};
const methodBitToStrMap = new Map([
[ METHOD_NONE, '' ],
[ METHOD_CONNECT, 'connect' ],
[ METHOD_DELETE, 'delete' ],
[ METHOD_GET, 'get' ],
[ METHOD_HEAD, 'head' ],
[ METHOD_OPTIONS, 'options' ],
[ METHOD_PATCH, 'patch' ],
[ METHOD_POST, 'post' ],
[ METHOD_PUT, 'put' ],
]);
/******************************************************************************/ /******************************************************************************/
const FilteringContext = class { const FilteringContext = class {
@ -94,7 +136,8 @@ const FilteringContext = class {
this.tstamp = 0; this.tstamp = 0;
this.realm = ''; this.realm = '';
this.id = undefined; this.id = undefined;
this.itype = 0; this.method = 0;
this.itype = NO_TYPE;
this.stype = undefined; this.stype = undefined;
this.url = undefined; this.url = undefined;
this.aliasURL = undefined; this.aliasURL = undefined;
@ -133,6 +176,7 @@ const FilteringContext = class {
fromFilteringContext(other) { fromFilteringContext(other) {
this.realm = other.realm; this.realm = other.realm;
this.type = other.type; this.type = other.type;
this.method = other.method;
this.url = other.url; this.url = other.url;
this.hostname = other.hostname; this.hostname = other.hostname;
this.domain = other.domain; this.domain = other.domain;
@ -358,6 +402,23 @@ const FilteringContext = class {
} }
return this; return this;
} }
setMethod(a) {
this.method = methodStrToBitMap[a] || 0;
return this;
}
getMethodName() {
return FilteringContext.getMethodName(this.method);
}
static getMethod(a) {
return methodStrToBitMap[a] || 0;
}
static getMethodName(a) {
return methodBitToStrMap.get(a) || '';
}
}; };
/******************************************************************************/ /******************************************************************************/
@ -386,6 +447,16 @@ FilteringContext.prototype.INLINE_ANY = FilteringContext.INLINE_ANY = INLINE_ANY
FilteringContext.prototype.PING_ANY = FilteringContext.PING_ANY = PING_ANY; FilteringContext.prototype.PING_ANY = FilteringContext.PING_ANY = PING_ANY;
FilteringContext.prototype.SCRIPT_ANY = FilteringContext.SCRIPT_ANY = SCRIPT_ANY; FilteringContext.prototype.SCRIPT_ANY = FilteringContext.SCRIPT_ANY = SCRIPT_ANY;
FilteringContext.prototype.METHOD_NONE = FilteringContext.METHOD_NONE = METHOD_NONE;
FilteringContext.prototype.METHOD_CONNECT = FilteringContext.METHOD_CONNECT = METHOD_CONNECT;
FilteringContext.prototype.METHOD_DELETE = FilteringContext.METHOD_DELETE = METHOD_DELETE;
FilteringContext.prototype.METHOD_GET = FilteringContext.METHOD_GET = METHOD_GET;
FilteringContext.prototype.METHOD_HEAD = FilteringContext.METHOD_HEAD = METHOD_HEAD;
FilteringContext.prototype.METHOD_OPTIONS = FilteringContext.METHOD_OPTIONS = METHOD_OPTIONS;
FilteringContext.prototype.METHOD_PATCH = FilteringContext.METHOD_PATCH = METHOD_PATCH;
FilteringContext.prototype.METHOD_POST = FilteringContext.METHOD_POST = METHOD_POST;
FilteringContext.prototype.METHOD_PUT = FilteringContext.METHOD_PUT = METHOD_PUT;
/******************************************************************************/ /******************************************************************************/
export { FilteringContext }; export { FilteringContext };

View File

@ -36,6 +36,16 @@ const logDate = new Date();
const logDateTimezoneOffset = logDate.getTimezoneOffset() * 60000; const logDateTimezoneOffset = logDate.getTimezoneOffset() * 60000;
const loggerEntries = []; const loggerEntries = [];
const COLUMN_TIMESTAMP = 0;
const COLUMN_FILTER = 1;
const COLUMN_MESSAGE = 1;
const COLUMN_RESULT = 2;
const COLUMN_INITIATOR = 3;
const COLUMN_PARTYNESS = 4;
const COLUMN_METHOD = 5;
const COLUMN_TYPE = 6;
const COLUMN_URL = 7;
let filteredLoggerEntries = []; let filteredLoggerEntries = [];
let filteredLoggerEntryVoidedCount = 0; let filteredLoggerEntryVoidedCount = 0;
@ -211,7 +221,6 @@ const LogEntry = function(details) {
this[prop] = details[prop]; this[prop] = details[prop];
} }
} }
this.type = details.stype || details.type;
if ( details.aliasURL !== undefined ) { if ( details.aliasURL !== undefined ) {
this.aliased = true; this.aliased = true;
} }
@ -233,6 +242,7 @@ LogEntry.prototype = {
domain: '', domain: '',
filter: undefined, filter: undefined,
id: '', id: '',
method: '',
realm: '', realm: '',
tabDomain: '', tabDomain: '',
tabHostname: '', tabHostname: '',
@ -413,17 +423,20 @@ const parseLogEntry = function(details) {
textContent.push(''); textContent.push('');
} }
// Cell 5 // Cell 5: method
textContent.push(entry.method || '');
// Cell 6
textContent.push( textContent.push(
normalizeToStr(prettyRequestTypes[entry.type] || entry.type) normalizeToStr(prettyRequestTypes[entry.type] || entry.type)
); );
// Cell 6 // Cell 7
textContent.push(normalizeToStr(details.url)); textContent.push(normalizeToStr(details.url));
// Hidden cells -- useful for row-filtering purpose // Hidden cells -- useful for row-filtering purpose
// Cell 7 // Cell 8
if ( entry.aliased ) { if ( entry.aliased ) {
textContent.push(`aliasURL=${details.aliasURL}`); textContent.push(`aliasURL=${details.aliasURL}`);
} }
@ -534,49 +547,56 @@ const viewPort = (( ) => {
: 0; : 0;
}); });
const reservedWidth = const reservedWidth =
cellWidths[0] + cellWidths[2] + cellWidths[4] + cellWidths[5]; cellWidths[COLUMN_TIMESTAMP] +
cellWidths[6] = 0.5; cellWidths[COLUMN_RESULT] +
if ( cellWidths[1] === 0 && cellWidths[3] === 0 ) { cellWidths[COLUMN_PARTYNESS] +
cellWidths[6] = 1; cellWidths[COLUMN_METHOD] +
} else if ( cellWidths[1] === 0 ) { cellWidths[COLUMN_TYPE];
cellWidths[3] = 0.35; cellWidths[COLUMN_URL] = 0.5;
cellWidths[6] = 0.65; if ( cellWidths[COLUMN_FILTER] === 0 && cellWidths[COLUMN_INITIATOR] === 0 ) {
} else if ( cellWidths[3] === 0 ) { cellWidths[COLUMN_URL] = 1;
cellWidths[1] = 0.35; } else if ( cellWidths[COLUMN_FILTER] === 0 ) {
cellWidths[6] = 0.65; cellWidths[COLUMN_INITIATOR] = 0.35;
cellWidths[COLUMN_URL] = 0.65;
} else if ( cellWidths[COLUMN_INITIATOR] === 0 ) {
cellWidths[COLUMN_FILTER] = 0.35;
cellWidths[COLUMN_URL] = 0.65;
} else { } else {
cellWidths[1] = 0.25; cellWidths[COLUMN_FILTER] = 0.25;
cellWidths[3] = 0.25; cellWidths[COLUMN_INITIATOR] = 0.25;
cellWidths[6] = 0.5; cellWidths[COLUMN_URL] = 0.5;
} }
const style = qs$('#vwRendererRuntimeStyles'); const style = qs$('#vwRendererRuntimeStyles');
const cssRules = [ const cssRules = [
'#vwContent .logEntry {', '#vwContent .logEntry {',
` height: ${newLineHeight}px;`, ` height: ${newLineHeight}px;`,
'}', '}',
'#vwContent .logEntry > div > span:nth-of-type(1) {', `#vwContent .logEntry > div > span:nth-of-type(${COLUMN_TIMESTAMP+1}) {`,
` width: ${cellWidths[0]}px;`, ` width: ${cellWidths[COLUMN_TIMESTAMP]}px;`,
'}', '}',
'#vwContent .logEntry > div > span:nth-of-type(2) {', `#vwContent .logEntry > div > span:nth-of-type(${COLUMN_FILTER+1}) {`,
` width: calc(calc(100% - ${reservedWidth}px) * ${cellWidths[1]});`, ` width: calc(calc(100% - ${reservedWidth}px) * ${cellWidths[COLUMN_FILTER]});`,
'}', '}',
'#vwContent .logEntry > div.messageRealm > span:nth-of-type(2) {', `#vwContent .logEntry > div.messageRealm > span:nth-of-type(${COLUMN_MESSAGE+1}) {`,
` width: calc(100% - ${cellWidths[0]}px);`, ` width: calc(100% - ${cellWidths[COLUMN_MESSAGE]}px);`,
'}', '}',
'#vwContent .logEntry > div > span:nth-of-type(3) {', `#vwContent .logEntry > div > span:nth-of-type(${COLUMN_RESULT+1}) {`,
` width: ${cellWidths[2]}px;`, ` width: ${cellWidths[COLUMN_RESULT]}px;`,
'}', '}',
'#vwContent .logEntry > div > span:nth-of-type(4) {', `#vwContent .logEntry > div > span:nth-of-type(${COLUMN_INITIATOR+1}) {`,
` width: calc(calc(100% - ${reservedWidth}px) * ${cellWidths[3]});`, ` width: calc(calc(100% - ${reservedWidth}px) * ${cellWidths[COLUMN_INITIATOR]});`,
'}', '}',
'#vwContent .logEntry > div > span:nth-of-type(5) {', `#vwContent .logEntry > div > span:nth-of-type(${COLUMN_PARTYNESS+1}) {`,
` width: ${cellWidths[4]}px;`, ` width: ${cellWidths[COLUMN_PARTYNESS]}px;`,
'}', '}',
'#vwContent .logEntry > div > span:nth-of-type(6) {', `#vwContent .logEntry > div > span:nth-of-type(${COLUMN_METHOD+1}) {`,
` width: ${cellWidths[5]}px;`, ` width: ${cellWidths[COLUMN_METHOD]}px;`,
'}', '}',
'#vwContent .logEntry > div > span:nth-of-type(7) {', `#vwContent .logEntry > div > span:nth-of-type(${COLUMN_TYPE+1}) {`,
` width: calc(calc(100% - ${reservedWidth}px) * ${cellWidths[6]});`, ` width: ${cellWidths[COLUMN_TYPE]}px;`,
'}',
`#vwContent .logEntry > div > span:nth-of-type(${COLUMN_URL+1}) {`,
` width: calc(calc(100% - ${reservedWidth}px) * ${cellWidths[COLUMN_URL]});`,
'}', '}',
'', '',
]; ];
@ -651,8 +671,8 @@ const viewPort = (( ) => {
} }
// Timestamp // Timestamp
span = div.children[0]; span = div.children[COLUMN_TIMESTAMP];
span.textContent = cells[0]; span.textContent = cells[COLUMN_TIMESTAMP];
// Tab id // Tab id
if ( details.tabId !== undefined ) { if ( details.tabId !== undefined ) {
@ -666,8 +686,8 @@ const viewPort = (( ) => {
if ( details.type !== undefined ) { if ( details.type !== undefined ) {
dom.attr(div, 'data-type', details.type); dom.attr(div, 'data-type', details.type);
} }
span = div.children[1]; span = div.children[COLUMN_MESSAGE];
span.textContent = cells[1]; span.textContent = cells[COLUMN_MESSAGE];
return div; return div;
} }
@ -692,23 +712,23 @@ const viewPort = (( ) => {
dom.attr(div, 'data-modifier', ''); dom.attr(div, 'data-modifier', '');
} }
} }
span = div.children[1]; span = div.children[COLUMN_FILTER];
if ( renderFilterToSpan(span, cells[1]) === false ) { if ( renderFilterToSpan(span, cells[COLUMN_FILTER]) === false ) {
span.textContent = cells[1]; span.textContent = cells[COLUMN_FILTER];
} }
// Event // Event
if ( cells[2] === '--' ) { if ( cells[COLUMN_RESULT] === '--' ) {
dom.attr(div, 'data-status', '1'); dom.attr(div, 'data-status', '1');
} else if ( cells[2] === '++' ) { } else if ( cells[COLUMN_RESULT] === '++' ) {
dom.attr(div, 'data-status', '2'); dom.attr(div, 'data-status', '2');
} else if ( cells[2] === '**' ) { } else if ( cells[COLUMN_RESULT] === '**' ) {
dom.attr(div, 'data-status', '3'); dom.attr(div, 'data-status', '3');
} else if ( cells[2] === '<<' ) { } else if ( cells[COLUMN_RESULT] === '<<' ) {
divcl.add('redirect'); divcl.add('redirect');
} }
span = div.children[2]; span = div.children[COLUMN_RESULT];
span.textContent = cells[2]; span.textContent = cells[COLUMN_RESULT];
// Origins // Origins
if ( details.tabHostname ) { if ( details.tabHostname ) {
@ -717,12 +737,12 @@ const viewPort = (( ) => {
if ( details.docHostname ) { if ( details.docHostname ) {
dom.attr(div, 'data-dochn', details.docHostname); dom.attr(div, 'data-dochn', details.docHostname);
} }
span = div.children[3]; span = div.children[COLUMN_INITIATOR];
span.textContent = cells[3]; span.textContent = cells[COLUMN_INITIATOR];
// Partyness // Partyness
if ( if (
cells[4] !== '' && cells[COLUMN_PARTYNESS] !== '' &&
details.realm === 'network' && details.realm === 'network' &&
details.domain !== undefined details.domain !== undefined
) { ) {
@ -733,12 +753,16 @@ const viewPort = (( ) => {
text += ` \u21d2 ${details.domain}`; text += ` \u21d2 ${details.domain}`;
dom.attr(div, 'data-parties', text); dom.attr(div, 'data-parties', text);
} }
span = div.children[4]; span = div.children[COLUMN_PARTYNESS];
span.textContent = cells[4]; span.textContent = cells[COLUMN_PARTYNESS];
// Method
span = div.children[COLUMN_METHOD];
span.textContent = cells[COLUMN_METHOD];
// Type // Type
span = div.children[5]; span = div.children[COLUMN_TYPE];
span.textContent = cells[5]; span.textContent = cells[COLUMN_TYPE];
// URL // URL
let re; let re;
@ -747,7 +771,7 @@ const viewPort = (( ) => {
} else if ( filteringType === 'dynamicUrl' ) { } else if ( filteringType === 'dynamicUrl' ) {
re = regexFromURLFilteringResult(filter.rule.join(' ')); re = regexFromURLFilteringResult(filter.rule.join(' '));
} }
nodeFromURL(div.children[6], cells[6], re); nodeFromURL(div.children[COLUMN_URL], cells[COLUMN_URL], re);
// Alias URL (CNAME, etc.) // Alias URL (CNAME, etc.)
if ( cells.length > 7 ) { if ( cells.length > 7 ) {
@ -1468,7 +1492,7 @@ const reloadTab = function(ev) {
}; };
const filterFromTargetRow = function() { const filterFromTargetRow = function() {
return dom.text(targetRow.children[1]); return dom.text(targetRow.children[COLUMN_FILTER]);
}; };
const aliasURLFromID = function(id) { const aliasURLFromID = function(id) {
@ -1476,13 +1500,13 @@ const reloadTab = function(ev) {
for ( const entry of loggerEntries ) { for ( const entry of loggerEntries ) {
if ( entry.id !== id || entry.aliased ) { continue; } if ( entry.id !== id || entry.aliased ) { continue; }
const fields = entry.textContent.split('\t'); const fields = entry.textContent.split('\t');
return fields[6] || ''; return fields[COLUMN_URL] || '';
} }
return ''; return '';
}; };
const toSummaryPaneFilterNode = async function(receiver, filter) { const toSummaryPaneFilterNode = async function(receiver, filter) {
receiver.children[1].textContent = filter; receiver.children[COLUMN_FILTER].textContent = filter;
if ( dom.cl.has(targetRow, 'canLookup') === false ) { return; } if ( dom.cl.has(targetRow, 'canLookup') === false ) { return; }
const isException = reIsExceptionFilter.test(filter); const isException = reIsExceptionFilter.test(filter);
let isExcepted = false; let isExcepted = false;
@ -1498,7 +1522,7 @@ const reloadTab = function(ev) {
}; };
const fillSummaryPaneFilterList = async function(rows) { const fillSummaryPaneFilterList = async function(rows) {
const rawFilter = targetRow.children[1].textContent; const rawFilter = targetRow.children[COLUMN_FILTER].textContent;
const nodeFromFilter = function(filter, lists) { const nodeFromFilter = function(filter, lists) {
const fragment = document.createDocumentFragment(); const fragment = document.createDocumentFragment();
@ -1561,7 +1585,7 @@ const reloadTab = function(ev) {
} else if ( dom.cl.has(targetRow, 'extendedRealm') ) { } else if ( dom.cl.has(targetRow, 'extendedRealm') ) {
const response = await messaging.send('loggerUI', { const response = await messaging.send('loggerUI', {
what: 'listsFromCosmeticFilter', what: 'listsFromCosmeticFilter',
url: targetRow.children[6].textContent, url: targetRow.children[COLUMN_URL].textContent,
rawFilter: rawFilter, rawFilter: rawFilter,
}); });
handleResponse(response); handleResponse(response);
@ -1619,19 +1643,19 @@ const reloadTab = function(ev) {
// Partyness // Partyness
text = dom.attr(tr, 'data-parties') || ''; text = dom.attr(tr, 'data-parties') || '';
if ( text !== '' ) { if ( text !== '' ) {
rows[5].children[1].textContent = `(${trch[4].textContent})\u2002${text}`; rows[5].children[1].textContent = `(${trch[COLUMN_PARTYNESS].textContent})\u2002${text}`;
} else { } else {
rows[5].style.display = 'none'; rows[5].style.display = 'none';
} }
// Type // Type
text = trch[5].textContent; text = trch[COLUMN_TYPE].textContent;
if ( text !== '' ) { if ( text !== '' ) {
rows[6].children[1].textContent = text; rows[6].children[1].textContent = text;
} else { } else {
rows[6].style.display = 'none'; rows[6].style.display = 'none';
} }
// URL // URL
const canonicalURL = trch[6].textContent; const canonicalURL = trch[COLUMN_URL].textContent;
if ( canonicalURL !== '' ) { if ( canonicalURL !== '' ) {
const attr = dom.attr(tr, 'data-status') || ''; const attr = dom.attr(tr, 'data-status') || '';
if ( attr !== '' ) { if ( attr !== '' ) {
@ -1640,7 +1664,7 @@ const reloadTab = function(ev) {
dom.attr(rows[7], 'data-modifier', ''); dom.attr(rows[7], 'data-modifier', '');
} }
} }
rows[7].children[1].appendChild(dom.clone(trch[6])); rows[7].children[1].appendChild(dom.clone(trch[COLUMN_URL]));
} else { } else {
rows[7].style.display = 'none'; rows[7].style.display = 'none';
} }
@ -1846,8 +1870,8 @@ const reloadTab = function(ev) {
if ( targetRow === null ) { return; } if ( targetRow === null ) { return; }
ev.stopPropagation(); ev.stopPropagation();
targetTabId = tabIdFromAttribute(targetRow); targetTabId = tabIdFromAttribute(targetRow);
targetType = targetRow.children[5].textContent.trim() || ''; targetType = targetRow.children[COLUMN_TYPE].textContent.trim() || '';
targetURLs = createTargetURLs(targetRow.children[6].textContent); targetURLs = createTargetURLs(targetRow.children[COLUMN_URL].textContent);
targetPageHostname = dom.attr(targetRow, 'data-tabhn') || ''; targetPageHostname = dom.attr(targetRow, 'data-tabhn') || '';
targetFrameHostname = dom.attr(targetRow, 'data-dochn') || ''; targetFrameHostname = dom.attr(targetRow, 'data-dochn') || '';
@ -2640,7 +2664,7 @@ const loggerSettings = (( ) => {
maxEntryCount: 2000, // per-tab maxEntryCount: 2000, // per-tab
maxLoadCount: 20, // per-tab maxLoadCount: 20, // per-tab
}, },
columns: [ true, true, true, true, true, true, true, true ], columns: [ true, true, true, true, true, true, true, true, true ],
linesPerEntry: 4, linesPerEntry: 4,
}; };

View File

@ -511,7 +511,7 @@ browser.runtime.onUpdateAvailable.addListener(details => {
if ( selfieIsValid ) { if ( selfieIsValid ) {
µb.supportStats.allReadyAfter += ' (selfie)'; µb.supportStats.allReadyAfter += ' (selfie)';
} }
ubolog(`All ready ${µb.supportStats.allReadyAfter} ms after launch`); ubolog(`All ready ${µb.supportStats.allReadyAfter} after launch`);
// <<<<< end of private scope // <<<<< end of private scope
})(); })();

View File

@ -2377,7 +2377,8 @@ const OPTTokenShide = 37;
const OPTTokenXhr = 38; const OPTTokenXhr = 38;
const OPTTokenWebrtc = 39; const OPTTokenWebrtc = 39;
const OPTTokenWebsocket = 40; const OPTTokenWebsocket = 40;
const OPTTokenCount = 41; const OPTTokenMethod = 41;
const OPTTokenCount = 42;
//const OPTPerOptionMask = 0x0000ff00; //const OPTPerOptionMask = 0x0000ff00;
const OPTCanNegate = 1 << 8; const OPTCanNegate = 1 << 8;
@ -2481,6 +2482,7 @@ Parser.prototype.OPTTokenFrame = OPTTokenFrame;
Parser.prototype.OPTTokenXhr = OPTTokenXhr; Parser.prototype.OPTTokenXhr = OPTTokenXhr;
Parser.prototype.OPTTokenWebrtc = OPTTokenWebrtc; Parser.prototype.OPTTokenWebrtc = OPTTokenWebrtc;
Parser.prototype.OPTTokenWebsocket = OPTTokenWebsocket; Parser.prototype.OPTTokenWebsocket = OPTTokenWebsocket;
Parser.prototype.OPTTokenMethod = OPTTokenMethod;
Parser.prototype.OPTCanNegate = OPTCanNegate; Parser.prototype.OPTCanNegate = OPTCanNegate;
Parser.prototype.OPTBlockOnly = OPTBlockOnly; Parser.prototype.OPTBlockOnly = OPTBlockOnly;
@ -2527,6 +2529,7 @@ const netOptionTokenDescriptors = new Map([
[ 'inline-script', OPTTokenInlineScript | OPTNonNetworkType | OPTCanNegate | OPTNonCspableType | OPTNonRedirectableType ], [ 'inline-script', OPTTokenInlineScript | OPTNonNetworkType | OPTCanNegate | OPTNonCspableType | OPTNonRedirectableType ],
[ 'match-case', OPTTokenMatchCase ], [ 'match-case', OPTTokenMatchCase ],
[ 'media', OPTTokenMedia | OPTCanNegate | OPTNetworkType | OPTModifiableType | OPTRedirectableType | OPTNonCspableType ], [ 'media', OPTTokenMedia | OPTCanNegate | OPTNetworkType | OPTModifiableType | OPTRedirectableType | OPTNonCspableType ],
[ 'method', OPTTokenMethod | OPTNetworkType | OPTMustAssign ],
[ 'mp4', OPTTokenMp4 | OPTNetworkType | OPTBlockOnly | OPTModifierType ], [ 'mp4', OPTTokenMp4 | OPTNetworkType | OPTBlockOnly | OPTModifierType ],
[ '_', OPTTokenNoop ], [ '_', OPTTokenNoop ],
[ 'object', OPTTokenObject | OPTCanNegate | OPTNetworkType | OPTModifiableType | OPTRedirectableType | OPTNonCspableType ], [ 'object', OPTTokenObject | OPTCanNegate | OPTNetworkType | OPTModifiableType | OPTRedirectableType | OPTNonCspableType ],
@ -2586,6 +2589,7 @@ Parser.netOptionTokenIds = new Map([
[ 'inline-script', OPTTokenInlineScript ], [ 'inline-script', OPTTokenInlineScript ],
[ 'match-case', OPTTokenMatchCase ], [ 'match-case', OPTTokenMatchCase ],
[ 'media', OPTTokenMedia ], [ 'media', OPTTokenMedia ],
[ 'method', OPTTokenMethod ],
[ 'mp4', OPTTokenMp4 ], [ 'mp4', OPTTokenMp4 ],
[ '_', OPTTokenNoop ], [ '_', OPTTokenNoop ],
[ 'object', OPTTokenObject ], [ 'object', OPTTokenObject ],
@ -2635,6 +2639,7 @@ Parser.netOptionTokenNames = new Map([
[ OPTTokenInlineScript, 'inline-script' ], [ OPTTokenInlineScript, 'inline-script' ],
[ OPTTokenMatchCase, 'match-case' ], [ OPTTokenMatchCase, 'match-case' ],
[ OPTTokenMedia, 'media' ], [ OPTTokenMedia, 'media' ],
[ OPTTokenMethod, 'method' ],
[ OPTTokenMp4, 'mp4' ], [ OPTTokenMp4, 'mp4' ],
[ OPTTokenNoop, '_' ], [ OPTTokenNoop, '_' ],
[ OPTTokenObject, 'object' ], [ OPTTokenObject, 'object' ],

View File

@ -199,6 +199,7 @@ const INVALID_TOKEN_HASH = 0xFFFFFFFF;
// See the following as short-lived registers, used during evaluation. They are // See the following as short-lived registers, used during evaluation. They are
// valid until the next evaluation. // valid until the next evaluation.
let $requestMethodBit = 0;
let $requestTypeValue = 0; let $requestTypeValue = 0;
let $requestURL = ''; let $requestURL = '';
let $requestURLRaw = ''; let $requestURLRaw = '';
@ -1265,6 +1266,82 @@ registerFilterClass(FilterRegex);
/******************************************************************************/ /******************************************************************************/
const FilterMethod = class {
static match(idata) {
if ( $requestMethodBit === 0 ) { return false; }
const methodBits = filterData[idata+1];
const notMethodBits = filterData[idata+2];
return (methodBits !== 0 && ($requestMethodBit & methodBits) !== 0) ||
(notMethodBits !== 0 && ($requestMethodBit & notMethodBits) === 0);
}
static compile(details) {
return [ FilterMethod.fid, details.methodBits, details.notMethodBits ];
}
static fromCompiled(args) {
const idata = filterDataAllocLen(3);
filterData[idata+0] = args[0]; // fid
filterData[idata+1] = args[1]; // methodBits
filterData[idata+2] = args[2]; // notMethodBits
return idata;
}
static dnrFromCompiled(args, rule) {
rule.condition = rule.condition || {};
const rc = rule.condition;
let methodBits = args[1];
let notMethodBits = args[2];
if ( methodBits !== 0 && rc.requestMethods === undefined ) {
rc.requestMethods = [];
}
if ( notMethodBits !== 0 && rc.excludedRequestMethods === undefined ) {
rc.excludedRequestMethods = [];
}
for ( let i = 1; methodBits !== 0 || notMethodBits !== 0; i++ ) {
const bit = 1 << i;
const methodName = FilteringContext.getMethodName(bit);
if ( (methodBits & bit) !== 0 ) {
methodBits &= ~bit;
rc.requestMethods.push(methodName);
} else if ( (notMethodBits & bit) !== 0 ) {
notMethodBits &= ~bit;
rc.excludedRequestMethods.push(methodName);
}
}
}
static keyFromArgs(args) {
return `${args[1]} ${args[2]}`;
}
static logData(idata, details) {
const methods = [];
let methodBits = filterData[idata+1];
let notMethodBits = filterData[idata+2];
for ( let i = 0; methodBits !== 0 || notMethodBits !== 0; i++ ) {
const bit = 1 << i;
const methodName = FilteringContext.getMethodName(bit);
if ( (methodBits & bit) !== 0 ) {
methodBits &= ~bit;
methods.push(methodName);
} else if ( (notMethodBits & bit) !== 0 ) {
notMethodBits &= ~bit;
methods.push(`~${methodName}`);
}
}
details.options.push(`method=${methods.join('|')}`);
}
static dumpInfo(idata) {
return `0b${filterData[idata+1].toString(2)} 0b${filterData[idata+2].toString(2)}`;
}
};
registerFilterClass(FilterMethod);
/******************************************************************************/
// stylesheet: 1 => bit 0 // stylesheet: 1 => bit 0
// image: 2 => bit 1 // image: 2 => bit 1
// object: 3 => bit 2 // object: 3 => bit 2
@ -3025,6 +3102,8 @@ class FilterCompiler {
this.tokenBeg = 0; this.tokenBeg = 0;
this.typeBits = 0; this.typeBits = 0;
this.notTypeBits = 0; this.notTypeBits = 0;
this.methodBits = 0;
this.notMethodBits = 0;
this.wildcardPos = -1; this.wildcardPos = -1;
this.caretPos = -1; this.caretPos = -1;
return this; return this;
@ -3055,6 +3134,21 @@ class FilterCompiler {
} }
} }
processMethodOption(value) {
for ( const method of value.split('|') ) {
if ( method.charCodeAt(0) === 0x7E /* '~' */ ) {
const bit = FilteringContext.getMethod(method.slice(1)) || 0;
if ( bit === 0 ) { continue; }
this.notMethodBits |= bit;
} else {
const bit = FilteringContext.getMethod(method) || 0;
if ( bit === 0 ) { continue; }
this.methodBits |= bit;
}
}
this.methodBits &= ~this.notMethodBits;
}
// https://github.com/chrisaljoudi/uBlock/issues/589 // https://github.com/chrisaljoudi/uBlock/issues/589
// Be ready to handle multiple negated types // Be ready to handle multiple negated types
@ -3225,6 +3319,9 @@ class FilterCompiler {
} }
this.optionUnitBits |= this.REDIRECT_BIT; this.optionUnitBits |= this.REDIRECT_BIT;
break; break;
case parser.OPTTokenMethod:
this.processMethodOption(val);
break;
case parser.OPTTokenInvalid: case parser.OPTTokenInvalid:
return false; return false;
default: default:
@ -3573,6 +3670,11 @@ class FilterCompiler {
units.push(FilterAnchorRight.compile()); units.push(FilterAnchorRight.compile());
} }
// Method(s)
if ( this.methodBits !== 0 || this.notMethodBits !== 0 ) {
units.push(FilterMethod.compile(this));
}
// Not types // Not types
if ( this.notTypeBits !== 0 ) { if ( this.notTypeBits !== 0 ) {
units.push(FilterNotType.compile(this)); units.push(FilterNotType.compile(this));
@ -4566,6 +4668,7 @@ FilterContainer.prototype.matchAndFetchModifiers = function(
$docHostname = fctxt.getDocHostname(); $docHostname = fctxt.getDocHostname();
$docDomain = fctxt.getDocDomain(); $docDomain = fctxt.getDocDomain();
$requestHostname = fctxt.getHostname(); $requestHostname = fctxt.getHostname();
$requestMethodBit = fctxt.method || 0;
$requestTypeValue = (typeBits & TypeBitsMask) >>> TypeBitsOffset; $requestTypeValue = (typeBits & TypeBitsMask) >>> TypeBitsOffset;
const partyBits = fctxt.is3rdPartyToDoc() ? ThirdParty : FirstParty; const partyBits = fctxt.is3rdPartyToDoc() ? ThirdParty : FirstParty;
@ -4866,6 +4969,7 @@ FilterContainer.prototype.matchRequestReverse = function(type, url) {
// Prime tokenizer: we get a normalized URL in return. // Prime tokenizer: we get a normalized URL in return.
$requestURL = urlTokenizer.setURL(url); $requestURL = urlTokenizer.setURL(url);
$requestURLRaw = url; $requestURLRaw = url;
$requestMethodBit = 0;
$requestTypeValue = (typeBits & TypeBitsMask) >>> TypeBitsOffset; $requestTypeValue = (typeBits & TypeBitsMask) >>> TypeBitsOffset;
$isBlockImportant = false; $isBlockImportant = false;
this.$filterUnit = 0; this.$filterUnit = 0;
@ -4933,6 +5037,7 @@ FilterContainer.prototype.matchRequest = function(fctxt, modifiers = 0) {
$docHostname = fctxt.getDocHostname(); $docHostname = fctxt.getDocHostname();
$docDomain = fctxt.getDocDomain(); $docDomain = fctxt.getDocDomain();
$requestHostname = fctxt.getHostname(); $requestHostname = fctxt.getHostname();
$requestMethodBit = fctxt.method || 0;
$requestTypeValue = (typeBits & TypeBitsMask) >>> TypeBitsOffset; $requestTypeValue = (typeBits & TypeBitsMask) >>> TypeBitsOffset;
$isBlockImportant = false; $isBlockImportant = false;
@ -4967,6 +5072,7 @@ FilterContainer.prototype.matchHeaders = function(fctxt, headers) {
$docHostname = fctxt.getDocHostname(); $docHostname = fctxt.getDocHostname();
$docDomain = fctxt.getDocDomain(); $docDomain = fctxt.getDocDomain();
$requestHostname = fctxt.getHostname(); $requestHostname = fctxt.getHostname();
$requestMethodBit = fctxt.method || 0;
$requestTypeValue = (typeBits & TypeBitsMask) >>> TypeBitsOffset; $requestTypeValue = (typeBits & TypeBitsMask) >>> TypeBitsOffset;
$httpHeaders.init(headers); $httpHeaders.init(headers);

View File

@ -66,6 +66,7 @@
</span> </span>
</div> </div>
<div><span data-filtex="!" data-i18n="loggerRowFiltererBuiltinNot"></span><span data-filtex="\t(?:0,)?1\t" data-i18n="loggerRowFiltererBuiltin1p"></span><span data-filtex="\t(?:3(?:,\d)?|0,3)\t" data-i18n="loggerRowFiltererBuiltin3p"></span></div> <div><span data-filtex="!" data-i18n="loggerRowFiltererBuiltinNot"></span><span data-filtex="\t(?:0,)?1\t" data-i18n="loggerRowFiltererBuiltin1p"></span><span data-filtex="\t(?:3(?:,\d)?|0,3)\t" data-i18n="loggerRowFiltererBuiltin3p"></span></div>
<div><span data-filtex="!" data-i18n="loggerRowFiltererBuiltinNot"></span><span data-filtex="\tget\t">get</span><span data-filtex="\thead\t">head</span><span data-filtex="\tpost\t">post</span></div>
<div id="filterExprCnameOf" style="display:none"><span data-filtex="!" data-i18n="loggerRowFiltererBuiltinNot"></span><span data-filtex="\taliasURL=.">CNAME</span></div> <div id="filterExprCnameOf" style="display:none"><span data-filtex="!" data-i18n="loggerRowFiltererBuiltinNot"></span><span data-filtex="\taliasURL=.">CNAME</span></div>
</div> </div>
</span> </span>
@ -85,7 +86,7 @@
</div> </div>
</div> </div>
<div id="vwLineSizer"> <div id="vwLineSizer">
<div class="logEntry oneLine"><div><span>00:00:00</span><span>&nbsp;</span><span>**</span><span>&nbsp;</span><span>3,3</span><span>inline-script</span><span>&nbsp;</span></div></div> <div class="logEntry oneLine"><div><span>00:00:00</span><span>&nbsp;</span><span>**</span><span>&nbsp;</span><span>3,3</span><span>options</span><span>inline-script</span><span>&nbsp;</span></div></div>
</div> </div>
</div> </div>
</div> </div>
@ -101,7 +102,7 @@
</div> </div>
<div id="templates" style="display: none;"> <div id="templates" style="display: none;">
<div id="logEntryTemplate"><div><span></span>&#8203;<span></span>&#8203;<span></span>&#8203;<span></span>&#8203;<span></span>&#8203;<span></span>&#8203;<span></span></div></div> <div id="logEntryTemplate"><div><span></span>&#8203;<span></span>&#8203;<span></span>&#8203;<span></span>&#8203;<span></span>&#8203;<span></span>&#8203;<span></span>&#8203;<span></span></div></div>
<div id="netFilteringDialog" data-pane="details"> <div id="netFilteringDialog" data-pane="details">
<div class="hide preview"><span>click to preview</span></div> <div class="hide preview"><span>click to preview</span></div>