commit a344785815b4cb21716c54a4449d5cfd4c94a06f
parent 8f2a3fac38ddb47db9216164a710c092b278720d
Author: Valentin Gosu <valentin.gosu@gmail.com>
Date: Wed, 7 Jan 2026 09:26:06 +0000
Bug 1992512 - nsHTTPCompressConv::OnDataFinished should not QI listener off-main-thread r=necko-reviewers,kershaw
Since nsHTTPCompressConv::CheckListenerChain will return NS_OK in the
content process, that means OnDataFinished might be called even if
not all the listeners in the listener chain support being called
off-main-thread. This is the case for a JS implemented listener.
It is important to not QI a JS implemented listener off main thread.
Since the listener wouldn't benefit from OnDataFinished since it's
limited to the main thread, that means we can avoid calling it
entirely.
Differential Revision: https://phabricator.services.mozilla.com/D274324
Diffstat:
1 file changed, 25 insertions(+), 19 deletions(-)
diff --git a/netwerk/streamconv/converters/nsHTTPCompressConv.cpp b/netwerk/streamconv/converters/nsHTTPCompressConv.cpp
@@ -1099,43 +1099,49 @@ uint32_t nsHTTPCompressConv::check_header(nsIInputStream* iStr,
NS_IMETHODIMP
nsHTTPCompressConv::CheckListenerChain() {
- if (XRE_IsContentProcess() &&
- StaticPrefs::network_decompression_off_mainthread2()) {
- // handle decompression OMT always. If the chain needs to be MT,
- // we'll determine that in OnStartRequest and dispatch to MT
- return NS_OK;
- }
+ MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIThreadRetargetableStreamListener> listener;
{
MutexAutoLock lock(mMutex);
listener = do_QueryInterface(mListener);
}
- if (!listener) {
- return NS_ERROR_NO_INTERFACE;
+
+ nsresult rv = NS_ERROR_NO_INTERFACE;
+ if (listener) {
+ rv = listener->CheckListenerChain();
+ }
+
+ // handle decompression OMT always. If the chain needs to be MT,
+ // we'll determine that in OnStartRequest and dispatch to MT
+ bool alwaysOMT = XRE_IsContentProcess() &&
+ StaticPrefs::network_decompression_off_mainthread2();
+
+ if (NS_FAILED(rv) && alwaysOMT) {
+ mDispatchToMainThread = true;
+ return NS_OK;
}
- return listener->CheckListenerChain();
+ return rv;
}
NS_IMETHODIMP
nsHTTPCompressConv::OnDataFinished(nsresult aStatus) {
- nsCOMPtr<nsIThreadRetargetableStreamListener> listener;
+ if (mDispatchToMainThread && !NS_IsMainThread()) {
+ // If this is called off main thread, but the listener can only
+ // handle calls on the main thread, then just return.
+ // Also important - never QI the listener off main thread
+ // if mDispatchToMainThread is true, because the listener
+ // might be JS implemented and won't support that.
+ return NS_OK;
+ }
+ nsCOMPtr<nsIThreadRetargetableStreamListener> listener;
{
MutexAutoLock lock(mMutex);
listener = do_QueryInterface(mListener);
}
if (listener) {
- if (mDispatchToMainThread && !NS_IsMainThread()) {
- nsCOMPtr<nsIRunnable> handler = NS_NewRunnableFunction(
- "dispatch", [listener{std::move(listener)}, aStatus]() {
- (void)listener->OnDataFinished(aStatus);
- });
-
- return NS_DispatchToMainThread(handler);
- }
-
return listener->OnDataFinished(aStatus);
}