Fix potential exceptions in new response body filtering code

Related feedback:
https://github.com/uBlockOrigin/uBlock-issues/discussions/2929

Related commit:
7c3e060c01
This commit is contained in:
Raymond Hill 2023-11-04 09:43:38 -04:00
parent 4774a39b17
commit 4de6bd6f07
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
2 changed files with 50 additions and 39 deletions

View File

@ -37,30 +37,30 @@ import {
// values -- the assumption being that integer operations are faster than // values -- the assumption being that integer operations are faster than
// string operations. // string operations.
const NO_TYPE = 0; export const NO_TYPE = 0;
const BEACON = 1 << 0; export const BEACON = 1 << 0;
const CSP_REPORT = 1 << 1; export const CSP_REPORT = 1 << 1;
const FONT = 1 << 2; export const FONT = 1 << 2;
const IMAGE = 1 << 4; export const IMAGE = 1 << 4;
const IMAGESET = 1 << 4; export const IMAGESET = 1 << 4;
const MAIN_FRAME = 1 << 5; export const MAIN_FRAME = 1 << 5;
const MEDIA = 1 << 6; export const MEDIA = 1 << 6;
const OBJECT = 1 << 7; export const OBJECT = 1 << 7;
const OBJECT_SUBREQUEST = 1 << 7; export const OBJECT_SUBREQUEST = 1 << 7;
const PING = 1 << 8; export const PING = 1 << 8;
const SCRIPT = 1 << 9; export const SCRIPT = 1 << 9;
const STYLESHEET = 1 << 10; export const STYLESHEET = 1 << 10;
const SUB_FRAME = 1 << 11; export const SUB_FRAME = 1 << 11;
const WEBSOCKET = 1 << 12; export const WEBSOCKET = 1 << 12;
const XMLHTTPREQUEST = 1 << 13; export const XMLHTTPREQUEST = 1 << 13;
const INLINE_FONT = 1 << 14; export const INLINE_FONT = 1 << 14;
const INLINE_SCRIPT = 1 << 15; export const INLINE_SCRIPT = 1 << 15;
const OTHER = 1 << 16; export const OTHER = 1 << 16;
const FRAME_ANY = MAIN_FRAME | SUB_FRAME; export const FRAME_ANY = MAIN_FRAME | SUB_FRAME;
const FONT_ANY = FONT | INLINE_FONT; export const FONT_ANY = FONT | INLINE_FONT;
const INLINE_ANY = INLINE_FONT | INLINE_SCRIPT; export const INLINE_ANY = INLINE_FONT | INLINE_SCRIPT;
const PING_ANY = BEACON | CSP_REPORT | PING; export const PING_ANY = BEACON | CSP_REPORT | PING;
const SCRIPT_ANY = SCRIPT | INLINE_SCRIPT; export const SCRIPT_ANY = SCRIPT | INLINE_SCRIPT;
const typeStrToIntMap = { const typeStrToIntMap = {
'no_type': NO_TYPE, 'no_type': NO_TYPE,
@ -84,15 +84,15 @@ const typeStrToIntMap = {
'other': OTHER, 'other': OTHER,
}; };
const METHOD_NONE = 0; export const METHOD_NONE = 0;
const METHOD_CONNECT = 1 << 1; export const METHOD_CONNECT = 1 << 1;
const METHOD_DELETE = 1 << 2; export const METHOD_DELETE = 1 << 2;
const METHOD_GET = 1 << 3; export const METHOD_GET = 1 << 3;
const METHOD_HEAD = 1 << 4; export const METHOD_HEAD = 1 << 4;
const METHOD_OPTIONS = 1 << 5; export const METHOD_OPTIONS = 1 << 5;
const METHOD_PATCH = 1 << 6; export const METHOD_PATCH = 1 << 6;
const METHOD_POST = 1 << 7; export const METHOD_POST = 1 << 7;
const METHOD_PUT = 1 << 8; export const METHOD_PUT = 1 << 8;
const methodStrToBitMap = { const methodStrToBitMap = {
'': METHOD_NONE, '': METHOD_NONE,
@ -128,7 +128,7 @@ const methodBitToStrMap = new Map([
/******************************************************************************/ /******************************************************************************/
const FilteringContext = class { export const FilteringContext = class {
constructor(other) { constructor(other) {
if ( other instanceof FilteringContext ) { if ( other instanceof FilteringContext ) {
return this.fromFilteringContext(other); 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; FilteringContext.prototype.METHOD_PUT = FilteringContext.METHOD_PUT = METHOD_PUT;
/******************************************************************************/ /******************************************************************************/
export { FilteringContext };

View File

@ -33,6 +33,7 @@ import staticNetFilteringEngine from './static-net-filtering.js';
import textEncode from './text-encode.js'; import textEncode from './text-encode.js';
import µb from './background.js'; import µb from './background.js';
import * as sfp from './static-filtering-parser.js'; import * as sfp from './static-filtering-parser.js';
import * as fc from './filtering-context.js';
import { import {
sessionFirewall, sessionFirewall,
@ -699,6 +700,8 @@ const bodyFilterer = (( ) => {
'application/xml', 'application/xml',
'application/xhtml+xml', 'application/xhtml+xml',
]); ]);
const NOT_TEXT_TYPES = fc.FONT | fc.IMAGE | fc.MEDIA | fc.WEBSOCKET;
let textDecoder, textEncoder; let textDecoder, textEncoder;
const mimeFromContentType = contentType => { const mimeFromContentType = contentType => {
@ -878,6 +881,14 @@ const bodyFilterer = (( ) => {
static canFilter(fctxt, details) { static canFilter(fctxt, details) {
if ( µb.canFilterResponseData !== true ) { return; } 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 // https://github.com/gorhill/uBlock/issues/3478
const statusCode = details.statusCode || 0; const statusCode = details.statusCode || 0;
if ( statusCode !== 0 && (statusCode < 200 || statusCode >= 300) ) { if ( statusCode !== 0 && (statusCode < 200 || statusCode >= 300) ) {
@ -890,12 +901,14 @@ const bodyFilterer = (( ) => {
// https://bugzilla.mozilla.org/show_bug.cgi?id=1426789 // https://bugzilla.mozilla.org/show_bug.cgi?id=1426789
const headers = details.responseHeaders; const headers = details.responseHeaders;
const disposition = headerValueFromName('content-disposition', headers); const disposition = headerValueFromName('content-disposition', headers);
if ( disposition !== '' && disposition.startsWith('inline') === false ) { if ( disposition !== '' ) {
return; if ( disposition.startsWith('inline') === false ) {
return;
}
} }
const contentType = headerValueFromName('content-type', headers); const contentType = headerValueFromName('content-type', headers);
let mime, charset; let mime = 'text/plain', charset;
if ( contentType !== '' ) { if ( contentType !== '' ) {
mime = mimeFromContentType(contentType); mime = mimeFromContentType(contentType);
if ( mime === undefined ) { return; } if ( mime === undefined ) { return; }