From 4de6bd6f07efc6b06faa38ef7483f5faf379549a Mon Sep 17 00:00:00 2001 From: Raymond Hill Date: Sat, 4 Nov 2023 09:43:38 -0400 Subject: [PATCH] Fix potential exceptions in new response body filtering code Related feedback: https://github.com/uBlockOrigin/uBlock-issues/discussions/2929 Related commit: https://github.com/gorhill/uBlock/commit/7c3e060c017a7e832314ef67c624ebbb20e52473 --- src/js/filtering-context.js | 70 ++++++++++++++++++------------------- src/js/traffic.js | 19 ++++++++-- 2 files changed, 50 insertions(+), 39 deletions(-) diff --git a/src/js/filtering-context.js b/src/js/filtering-context.js index 3d67f996d..6085a59b5 100644 --- a/src/js/filtering-context.js +++ b/src/js/filtering-context.js @@ -37,30 +37,30 @@ import { // values -- the assumption being that integer operations are faster than // string operations. -const NO_TYPE = 0; -const BEACON = 1 << 0; -const CSP_REPORT = 1 << 1; -const FONT = 1 << 2; -const IMAGE = 1 << 4; -const IMAGESET = 1 << 4; -const MAIN_FRAME = 1 << 5; -const MEDIA = 1 << 6; -const OBJECT = 1 << 7; -const OBJECT_SUBREQUEST = 1 << 7; -const PING = 1 << 8; -const SCRIPT = 1 << 9; -const STYLESHEET = 1 << 10; -const SUB_FRAME = 1 << 11; -const WEBSOCKET = 1 << 12; -const XMLHTTPREQUEST = 1 << 13; -const INLINE_FONT = 1 << 14; -const INLINE_SCRIPT = 1 << 15; -const OTHER = 1 << 16; -const FRAME_ANY = MAIN_FRAME | SUB_FRAME; -const FONT_ANY = FONT | INLINE_FONT; -const INLINE_ANY = INLINE_FONT | INLINE_SCRIPT; -const PING_ANY = BEACON | CSP_REPORT | PING; -const SCRIPT_ANY = SCRIPT | INLINE_SCRIPT; +export const NO_TYPE = 0; +export const BEACON = 1 << 0; +export const CSP_REPORT = 1 << 1; +export const FONT = 1 << 2; +export const IMAGE = 1 << 4; +export const IMAGESET = 1 << 4; +export const MAIN_FRAME = 1 << 5; +export const MEDIA = 1 << 6; +export const OBJECT = 1 << 7; +export const OBJECT_SUBREQUEST = 1 << 7; +export const PING = 1 << 8; +export const SCRIPT = 1 << 9; +export const STYLESHEET = 1 << 10; +export const SUB_FRAME = 1 << 11; +export const WEBSOCKET = 1 << 12; +export const XMLHTTPREQUEST = 1 << 13; +export const INLINE_FONT = 1 << 14; +export const INLINE_SCRIPT = 1 << 15; +export const OTHER = 1 << 16; +export const FRAME_ANY = MAIN_FRAME | SUB_FRAME; +export const FONT_ANY = FONT | INLINE_FONT; +export const INLINE_ANY = INLINE_FONT | INLINE_SCRIPT; +export const PING_ANY = BEACON | CSP_REPORT | PING; +export const SCRIPT_ANY = SCRIPT | INLINE_SCRIPT; const typeStrToIntMap = { 'no_type': NO_TYPE, @@ -84,15 +84,15 @@ const typeStrToIntMap = { '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; +export const METHOD_NONE = 0; +export const METHOD_CONNECT = 1 << 1; +export const METHOD_DELETE = 1 << 2; +export const METHOD_GET = 1 << 3; +export const METHOD_HEAD = 1 << 4; +export const METHOD_OPTIONS = 1 << 5; +export const METHOD_PATCH = 1 << 6; +export const METHOD_POST = 1 << 7; +export const METHOD_PUT = 1 << 8; const methodStrToBitMap = { '': METHOD_NONE, @@ -128,7 +128,7 @@ const methodBitToStrMap = new Map([ /******************************************************************************/ -const FilteringContext = class { +export const FilteringContext = class { constructor(other) { if ( other instanceof FilteringContext ) { return this.fromFilteringContext(other); @@ -459,5 +459,3 @@ FilteringContext.prototype.METHOD_POST = FilteringContext.METHOD_POST = METHOD_P FilteringContext.prototype.METHOD_PUT = FilteringContext.METHOD_PUT = METHOD_PUT; /******************************************************************************/ - -export { FilteringContext }; diff --git a/src/js/traffic.js b/src/js/traffic.js index d98b44355..969be8785 100644 --- a/src/js/traffic.js +++ b/src/js/traffic.js @@ -33,6 +33,7 @@ import staticNetFilteringEngine from './static-net-filtering.js'; import textEncode from './text-encode.js'; import µb from './background.js'; import * as sfp from './static-filtering-parser.js'; +import * as fc from './filtering-context.js'; import { sessionFirewall, @@ -699,6 +700,8 @@ const bodyFilterer = (( ) => { 'application/xml', 'application/xhtml+xml', ]); + const NOT_TEXT_TYPES = fc.FONT | fc.IMAGE | fc.MEDIA | fc.WEBSOCKET; + let textDecoder, textEncoder; const mimeFromContentType = contentType => { @@ -878,6 +881,14 @@ const bodyFilterer = (( ) => { static canFilter(fctxt, details) { if ( µb.canFilterResponseData !== true ) { return; } + if ( (fctxt.itype & NOT_TEXT_TYPES) !== 0 ) { return; } + + if ( fctxt.method !== fc.METHOD_GET ) { + if ( fctxt.method !== fc.METHOD_POST ) { + return; + } + } + // https://github.com/gorhill/uBlock/issues/3478 const statusCode = details.statusCode || 0; if ( statusCode !== 0 && (statusCode < 200 || statusCode >= 300) ) { @@ -890,12 +901,14 @@ const bodyFilterer = (( ) => { // https://bugzilla.mozilla.org/show_bug.cgi?id=1426789 const headers = details.responseHeaders; const disposition = headerValueFromName('content-disposition', headers); - if ( disposition !== '' && disposition.startsWith('inline') === false ) { - return; + if ( disposition !== '' ) { + if ( disposition.startsWith('inline') === false ) { + return; + } } const contentType = headerValueFromName('content-type', headers); - let mime, charset; + let mime = 'text/plain', charset; if ( contentType !== '' ) { mime = mimeFromContentType(contentType); if ( mime === undefined ) { return; }