From 98d32c5d670737fa624c8b0184ebc2e6506734f5 Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Thu, 7 May 2020 11:04:58 -0700 Subject: [PATCH] browser(firefox): do not fail when decoding large responses (#2130) String.fromCharCode cannot be used to convert very large arrays to strings. Use chunking in this case. --- browser_patches/firefox/BUILD_NUMBER | 2 +- .../firefox/patches/bootstrap.diff | 47 +++++++++++++++++-- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/browser_patches/firefox/BUILD_NUMBER b/browser_patches/firefox/BUILD_NUMBER index 336df56907..97938e6e8d 100644 --- a/browser_patches/firefox/BUILD_NUMBER +++ b/browser_patches/firefox/BUILD_NUMBER @@ -1 +1 @@ -1090 +1091 diff --git a/browser_patches/firefox/patches/bootstrap.diff b/browser_patches/firefox/patches/bootstrap.diff index 2d23a66ed5..d394d36ee3 100644 --- a/browser_patches/firefox/patches/bootstrap.diff +++ b/browser_patches/firefox/patches/bootstrap.diff @@ -1400,17 +1400,16 @@ index 0000000000000000000000000000000000000000..2b1fe7fa712ae210af3ebbccda084041 + diff --git a/juggler/NetworkObserver.js b/juggler/NetworkObserver.js new file mode 100644 -index 0000000000000000000000000000000000000000..1a55b5498c18d2403eab21fe9149242f286157d4 +index 0000000000000000000000000000000000000000..4ed81876c3e176cf07fdeab4ca3fc83874f865a3 --- /dev/null +++ b/juggler/NetworkObserver.js -@@ -0,0 +1,794 @@ +@@ -0,0 +1,833 @@ +"use strict"; + +const {EventEmitter} = ChromeUtils.import('resource://gre/modules/EventEmitter.jsm'); +const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); +const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); +const {NetUtil} = ChromeUtils.import('resource://gre/modules/NetUtil.jsm'); -+const {CommonUtils} = ChromeUtils.import("resource://services-common/utils.js"); + + +const Cc = Components.classes; @@ -1978,7 +1977,7 @@ index 0000000000000000000000000000000000000000..1a55b5498c18d2403eab21fe9149242f + let result = response.body; + if (response.encodings && response.encodings.length) { + for (const encoding of response.encodings) -+ result = CommonUtils.convertString(result, encoding, 'uncompressed'); ++ result = convertString(result, encoding, 'uncompressed'); + } + return {base64body: btoa(result)}; + } @@ -2171,6 +2170,46 @@ index 0000000000000000000000000000000000000000..1a55b5498c18d2403eab21fe9149242f + } +} + ++function convertString(s, source, dest) { ++ const is = Cc["@mozilla.org/io/string-input-stream;1"].createInstance( ++ Ci.nsIStringInputStream ++ ); ++ is.setData(s, s.length); ++ const listener = Cc["@mozilla.org/network/stream-loader;1"].createInstance( ++ Ci.nsIStreamLoader ++ ); ++ let result = []; ++ listener.init({ ++ onStreamComplete: function onStreamComplete( ++ loader, ++ context, ++ status, ++ length, ++ data ++ ) { ++ const array = Array.from(data); ++ const kChunk = 100000; ++ for (let i = 0; i < length; i += kChunk) { ++ const len = Math.min(kChunk, length - i); ++ const chunk = String.fromCharCode.apply(this, array.slice(i, i + len)); ++ result.push(chunk); ++ } ++ }, ++ }); ++ const converter = Cc["@mozilla.org/streamConverters;1"].getService( ++ Ci.nsIStreamConverterService ++ ).asyncConvertData( ++ source, ++ dest, ++ listener, ++ null ++ ); ++ converter.onStartRequest(null, null); ++ converter.onDataAvailable(null, is, 0, s.length); ++ converter.onStopRequest(null, null, null); ++ return result.join(''); ++} ++ +const errorMap = { + 'aborted': Cr.NS_ERROR_ABORT, + 'accessdenied': Cr.NS_ERROR_PORT_ACCESS_NOT_ALLOWED,