diff --git a/src/js/hntrie.js b/src/js/hntrie.js index 607d8ef8a..fce9fe853 100644 --- a/src/js/hntrie.js +++ b/src/js/hntrie.js @@ -372,11 +372,13 @@ HNTrieContainer.prototype = { }, unserialize: function(selfie, decoder) { + this.needle = ''; const shouldDecode = typeof selfie === 'string'; let byteLength = shouldDecode ? decoder.decodeSize(selfie) : selfie.length << 2; byteLength = byteLength + HNTRIE_PAGE_SIZE-1 & ~(HNTRIE_PAGE_SIZE-1); + if ( byteLength === 0 ) { return; } if ( this.wasmMemory !== null ) { const pageCountBefore = this.buf.length >>> 16; const pageCountAfter = byteLength >>> 16; @@ -394,7 +396,6 @@ HNTrieContainer.prototype = { } else { this.buf32.set(selfie); } - this.needle = ''; }, //-------------------------------------------------------------------------- diff --git a/src/js/storage.js b/src/js/storage.js index a536f90eb..049db27a8 100644 --- a/src/js/storage.js +++ b/src/js/storage.js @@ -935,17 +935,17 @@ // https://github.com/AdguardTeam/AdguardBrowserExtension/issues/917 µBlock.processDirectives = function(content) { - var reIf = /^!#(if|endif)\b([^\n]*)/gm, - parts = [], - beg = 0, depth = 0, discard = false; + const reIf = /^!#(if|endif)\b([^\n]*)/gm; + const parts = []; + let beg = 0, depth = 0, discard = false; while ( beg < content.length ) { - var match = reIf.exec(content); + const match = reIf.exec(content); if ( match === null ) { break; } if ( match[1] === 'if' ) { - var expr = match[2].trim(); - var target = expr.startsWith('!'); + let expr = match[2].trim(); + const target = expr.startsWith('!'); if ( target ) { expr = expr.slice(1); } - var token = this.processDirectives.tokens.get(expr); + const token = this.processDirectives.tokens.get(expr); if ( depth === 0 && discard === false && @@ -1034,8 +1034,11 @@ 'compiled/' + this.pslAssetKey ).then(details => publicSuffixList.fromSelfie(details.content, µBlock.base128) - ).then(valid => { - if ( valid === true ) { return; } + ).catch(reason => { + console.info(reason); + return false; + }).then(success => { + if ( success ) { return; } return this.assets.get(this.pslAssetKey, details => { if ( details.content !== '' ) { this.compilePublicSuffixList(details.content); diff --git a/src/js/utils.js b/src/js/utils.js index f2d7fd0b4..88e51e361 100644 --- a/src/js/utils.js +++ b/src/js/utils.js @@ -505,9 +505,22 @@ // Could expand the LZ4 codec API to be able to return UTF8-safe string // representation of a compressed buffer, and thus the code below could be // moved LZ4 codec-side. +// https://github.com/uBlockOrigin/uBlock-issues/issues/461 +// Provide a fallback encoding for Chromium 59 and less by issuing a plain +// JSON string. The fallback can be removed once min supported version is +// above 59. µBlock.base128 = { encode: function(arrbuf, arrlen) { + if ( + vAPI.webextFlavor.soup.has('chromium') && + vAPI.webextFlavor.major < 60 + ) { + return this.encodeJSON(arrbuf); + } + return this.encodeBase128(arrbuf, arrlen); + }, + encodeBase128: function(arrbuf, arrlen) { const inbuf = new Uint8Array(arrbuf, 0, arrlen); const inputLength = arrlen; let _7cnt = Math.floor(inputLength / 7); @@ -556,6 +569,9 @@ const textDecoder = new TextDecoder(); return textDecoder.decode(outbuf); }, + encodeJSON: function(arrbuf) { + return JSON.stringify(Array.from(new Uint32Array(arrbuf))); + }, // TODO: // Surprisingly, there does not seem to be any performance gain when // first converting the input string into a Uint8Array through @@ -568,6 +584,22 @@ // const inbuf = textEncoder.encode(instr); // const inputLength = inbuf.byteLength; decode: function(instr, arrbuf) { + if ( instr.length === 0 ) { return; } + if ( instr.charCodeAt(0) === 0x5B /* '[' */ ) { + const outbuf = this.decodeJSON(instr, arrbuf); + if ( outbuf !== undefined ) { + return outbuf; + } + } + if ( + vAPI.webextFlavor.soup.has('chromium') && + vAPI.webextFlavor.major < 60 + ) { + throw new Error('Unexpected µBlock.base128 encoding'); + } + return this.decodeBase128(instr, arrbuf); + }, + decodeBase128: function(instr, arrbuf) { const inputLength = instr.length; let _8cnt = inputLength >>> 3; let outputLength = _8cnt * 7; @@ -599,7 +631,37 @@ } return outbuf; }, + decodeJSON: function(instr, arrbuf) { + let buf; + try { + buf = JSON.parse(instr); + } catch (ex) { + } + if ( Array.isArray(buf) === false ) { return; } + const outbuf = arrbuf instanceof ArrayBuffer === false + ? new Uint32Array(buf.length << 2) + : new Uint32Array(arrbuf); + outbuf.set(buf); + return new Uint8Array(outbuf.buffer); + }, decodeSize: function(instr) { + if ( instr.length === 0 ) { return 0; } + if ( instr.charCodeAt(0) === 0x5B /* '[' */ ) { + let buf; + try { + buf = JSON.parse(instr); + } catch (ex) { + } + if ( Array.isArray(buf) ) { + return buf.length << 2; + } + } + if ( + vAPI.webextFlavor.soup.has('chromium') && + vAPI.webextFlavor.major < 60 + ) { + throw new Error('Unexpected µBlock.base128 encoding'); + } const size = (instr.length >>> 3) * 7; const rem = instr.length & 7; return rem === 0 ? size : size + rem - 1; diff --git a/src/lib/publicsuffixlist/publicsuffixlist.js b/src/lib/publicsuffixlist/publicsuffixlist.js index aa1ae1655..0a01278e0 100644 --- a/src/lib/publicsuffixlist/publicsuffixlist.js +++ b/src/lib/publicsuffixlist/publicsuffixlist.js @@ -500,6 +500,7 @@ const fromSelfie = function(selfie, decoder) { } const bufferStr = selfie.slice(pos + 1); byteLength = decoder.decodeSize(bufferStr); + if ( byteLength === 0 ) { return false; } allocateBuffers(byteLength); decoder.decode(bufferStr, pslBuffer8.buffer); } else if (