diff --git a/browser_patches/firefox/BUILD_NUMBER b/browser_patches/firefox/BUILD_NUMBER index b96bfec6c7..628625b6bd 100644 --- a/browser_patches/firefox/BUILD_NUMBER +++ b/browser_patches/firefox/BUILD_NUMBER @@ -1 +1 @@ -1053 +1054 diff --git a/browser_patches/firefox/patches/bootstrap.diff b/browser_patches/firefox/patches/bootstrap.diff index 86fb93b6ce..b5ede48a20 100644 --- a/browser_patches/firefox/patches/bootstrap.diff +++ b/browser_patches/firefox/patches/bootstrap.diff @@ -1067,10 +1067,10 @@ index 0000000000000000000000000000000000000000..862c680198bbb503a5f04c19bdb8fdf2 + diff --git a/juggler/NetworkObserver.js b/juggler/NetworkObserver.js new file mode 100644 -index 0000000000000000000000000000000000000000..347a2b24dc4c933c6a643469967346a6014000f9 +index 0000000000000000000000000000000000000000..11483d18af264d9398961e08d2021d5d5f0c1463 --- /dev/null +++ b/juggler/NetworkObserver.js -@@ -0,0 +1,726 @@ +@@ -0,0 +1,773 @@ +"use strict"; + +const {EventEmitter} = ChromeUtils.import('resource://gre/modules/EventEmitter.jsm'); @@ -1125,6 +1125,9 @@ index 0000000000000000000000000000000000000000..347a2b24dc4c933c6a643469967346a6 + this._redirectMap = new Map(); // oldId => newId + this._resumedRequestIdToHeaders = new Map(); // requestId => { headers } + this._postResumeChannelIdToRequestId = new Map(); // post-resume channel id => pre-resume request id ++ this._pendingAuthentication = new Set(); // pre-auth id ++ this._postAuthChannelIdToRequestId = new Map(); // pre-auth id => post-auth id ++ this._bodyListeners = new Map(); // channel id => ResponseBodyListener. + + this._channelSink = { + QueryInterface: ChromeUtils.generateQI([Ci.nsIChannelEventSink]), @@ -1206,9 +1209,18 @@ index 0000000000000000000000000000000000000000..347a2b24dc4c933c6a643469967346a6 + this._takeInterceptor(browser, requestId)._abort(errorCode); + } + ++ _requestAuthenticated(httpChannel) { ++ this._pendingAuthentication.add(httpChannel.channelId + ''); ++ } ++ ++ _requestIdBeforeAuthentication(httpChannel) { ++ const id = httpChannel.channelId + ''; ++ return this._postAuthChannelIdToRequestId.has(id) ? id : undefined; ++ } ++ + _requestId(httpChannel) { + const id = httpChannel.channelId + ''; -+ return this._postResumeChannelIdToRequestId.get(id) || id; ++ return this._postResumeChannelIdToRequestId.get(id) || this._postAuthChannelIdToRequestId.get(id) || id; + } + + _onRedirect(oldChannel, newChannel, flags) { @@ -1260,6 +1272,8 @@ index 0000000000000000000000000000000000000000..347a2b24dc4c933c6a643469967346a6 + return; + if (this._isResumedChannel(httpChannel)) + return; ++ if (this._requestIdBeforeAuthentication(httpChannel)) ++ return; + this._sendOnRequestFinished(httpChannel); + } + @@ -1294,6 +1308,16 @@ index 0000000000000000000000000000000000000000..347a2b24dc4c933c6a643469967346a6 + new ResponseBodyListener(this, browser, httpChannel); + return; + } ++ // Convert pending auth bit into auth mapping. ++ const channelId = httpChannel.channelId + ''; ++ if (this._pendingAuthentication.has(channelId)) { ++ this._postAuthChannelIdToRequestId.set(channelId, channelId + '-auth'); ++ this._redirectMap.set(channelId + '-auth', channelId); ++ this._pendingAuthentication.delete(channelId); ++ const bodyListener = this._bodyListeners.get(channelId); ++ if (bodyListener) ++ bodyListener.dispose(); ++ } + const browserContext = TargetRegistry.instance().browserContextForBrowser(browser); + if (browserContext) + this._appendExtraHTTPHeaders(httpChannel, browserContext.options.extraHTTPHeaders); @@ -1402,7 +1426,7 @@ index 0000000000000000000000000000000000000000..347a2b24dc4c933c6a643469967346a6 + postData: readRequestPostData(httpChannel), + headers: requestHeaders(httpChannel), + method: httpChannel.requestMethod, -+ navigationId: httpChannel.isMainDocumentChannel ? this._requestId(httpChannel) : undefined, ++ navigationId: httpChannel.isMainDocumentChannel ? this._requestIdBeforeAuthentication(httpChannel) || this._requestId(httpChannel) : undefined, + cause: causeTypeToString(causeType), + }); + } @@ -1411,7 +1435,7 @@ index 0000000000000000000000000000000000000000..347a2b24dc4c933c6a643469967346a6 + this.emit('requestfinished', httpChannel, { + requestId: this._requestId(httpChannel), + }); -+ this._postResumeChannelIdToRequestId.delete(httpChannel.channelId + ''); ++ this._cleanupChannelState(httpChannel); + } + + _sendOnRequestFailed(httpChannel, error) { @@ -1419,7 +1443,13 @@ index 0000000000000000000000000000000000000000..347a2b24dc4c933c6a643469967346a6 + requestId: this._requestId(httpChannel), + errorCode: helper.getNetworkErrorStatusText(error), + }); -+ this._postResumeChannelIdToRequestId.delete(httpChannel.channelId + ''); ++ this._cleanupChannelState(httpChannel); ++ } ++ ++ _cleanupChannelState(httpChannel) { ++ const id = httpChannel.channelId + ''; ++ this._postResumeChannelIdToRequestId.delete(id); ++ this._postAuthChannelIdToRequestId.delete(id); + } + + _onResponse(fromCache, httpChannel, topic) { @@ -1622,9 +1652,16 @@ index 0000000000000000000000000000000000000000..347a2b24dc4c933c6a643469967346a6 + this.QueryInterface = ChromeUtils.generateQI([Ci.nsIStreamListener]); + httpChannel.QueryInterface(Ci.nsITraceableChannel); + this.originalListener = httpChannel.setNewListener(this); ++ this._disposed = false; ++ this._networkObserver._bodyListeners.set(this._httpChannel.channelId + '', this); + } + + onDataAvailable(aRequest, aInputStream, aOffset, aCount) { ++ if (this._disposed) { ++ this.originalListener.onDataAvailable(aRequest, aInputStream, aOffset, aCount); ++ return; ++ } ++ + const iStream = new BinaryInputStream(aInputStream); + const sStream = new StorageStream(8192, aCount, null); + const oStream = new BinaryOutputStream(sStream.getOutputStream(0)); @@ -1643,9 +1680,18 @@ index 0000000000000000000000000000000000000000..347a2b24dc4c933c6a643469967346a6 + + onStopRequest(aRequest, aStatusCode) { + this.originalListener.onStopRequest(aRequest, aStatusCode); ++ if (this._disposed) ++ return; ++ + const body = this._chunks.join(''); + delete this._chunks; + this._networkObserver._onResponseFinished(this._browser, this._httpChannel, body); ++ this.dispose(); ++ } ++ ++ dispose() { ++ this._disposed = true; ++ this._networkObserver._bodyListeners.delete(this._httpChannel.channelId + ''); + } +} + @@ -1728,6 +1774,7 @@ index 0000000000000000000000000000000000000000..347a2b24dc4c933c6a643469967346a6 + return false; + authInfo.username = credentials.username; + authInfo.password = credentials.password; ++ this._networkObserver._requestAuthenticated(this._httpChannel); + return true; + } +