Bug 1396395 - Part 1, resume input pump after callback finished. r?dragana
OnStartRequest callback chain is interrupted by add-on during the "http-on-modify-request" observer event.
Therefore, nsInputStreamPump think OnStartRequest is finished. After resuming http channel, nsHttpChannel
asynchronously continue the OnStartRequest procedure and synchronously resume the nsInputStreamPump. Before
nsDocumentOpenInfo invoke the next OnStartRequest on the listener chain, sync XHR in web content is executed
on the call stack. This will spin main thread event queue and will eventually callback OnDataAvailable/OnStopRequest
on the same call stack.
nsHttpChannel should not resume the nsInputStreamPump before |mCallOnResume| is complete, to ensure that
no input stream event can interrupt the resumed call stack before it finished.
MozReview-Commit-ID: 6Q9EtMhcff9
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -9030,19 +9030,42 @@ nsHttpChannel::ResumeInternal()
LOG(("nsHttpChannel::ResumeInternal [this=%p]\n", this));
if (--mSuspendCount == 0) {
mSuspendTotalTime += (TimeStamp::NowLoRes() - mSuspendTimestamp).
ToMilliseconds();
if (mCallOnResume) {
- nsresult rv = AsyncCall(mCallOnResume);
+ // Resume the interrupted procedure first, then resume
+ // the pump to continue process the input stream.
+ RefPtr<nsRunnableMethod<nsHttpChannel>> callOnResume=
+ NewRunnableMethod("CallOnResume", this, mCallOnResume);
+ // Should not resume pump that created after resumption.
+ RefPtr<nsInputStreamPump> transactionPump = mTransactionPump;
+ RefPtr<nsInputStreamPump> cachePump = mCachePump;
+
+ nsresult rv =
+ NS_DispatchToCurrentThread(NS_NewRunnableFunction(
+ "nsHttpChannel::CallOnResume",
+ [callOnResume, transactionPump, cachePump]() {
+ callOnResume->Run();
+
+ if (transactionPump) {
+ transactionPump->Resume();
+ }
+
+ if (cachePump) {
+ cachePump->Resume();
+ }
+ })
+ );
mCallOnResume = nullptr;
NS_ENSURE_SUCCESS(rv, rv);
+ return rv;
}
}
nsresult rvTransaction = NS_OK;
if (mTransactionPump) {
rvTransaction = mTransactionPump->Resume();
}