1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=8 et tw=80 : */
3 
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 
8 // HttpLog.h should generally be included first
9 #include "HttpLog.h"
10 
11 #include "nsHttp.h"
12 #include "nsICacheEntry.h"
13 #include "mozilla/BasePrincipal.h"
14 #include "mozilla/PerfStats.h"
15 #include "mozilla/Unused.h"
16 #include "mozilla/dom/ContentChild.h"
17 #include "mozilla/dom/DocGroup.h"
18 #include "mozilla/dom/ServiceWorkerUtils.h"
19 #include "mozilla/dom/BrowserChild.h"
20 #include "mozilla/extensions/StreamFilterParent.h"
21 #include "mozilla/ipc/FileDescriptorSetChild.h"
22 #include "mozilla/ipc/IPCStreamUtils.h"
23 #include "mozilla/net/NeckoChild.h"
24 #include "mozilla/net/HttpChannelChild.h"
25 #include "mozilla/net/UrlClassifierCommon.h"
26 #include "mozilla/net/UrlClassifierFeatureFactory.h"
27 
28 #include "AltDataOutputStreamChild.h"
29 #include "CookieServiceChild.h"
30 #include "HttpBackgroundChannelChild.h"
31 #include "nsCOMPtr.h"
32 #include "nsContentPolicyUtils.h"
33 #include "nsDOMNavigationTiming.h"
34 #include "nsGlobalWindow.h"
35 #include "nsStringStream.h"
36 #include "nsHttpChannel.h"
37 #include "nsHttpHandler.h"
38 #include "nsNetUtil.h"
39 #include "nsSerializationHelper.h"
40 #include "mozilla/Attributes.h"
41 #include "mozilla/dom/PerformanceStorage.h"
42 #include "mozilla/ipc/InputStreamUtils.h"
43 #include "mozilla/ipc/URIUtils.h"
44 #include "mozilla/ipc/BackgroundUtils.h"
45 #include "mozilla/net/DNS.h"
46 #include "mozilla/net/SocketProcessBridgeChild.h"
47 #include "mozilla/ScopeExit.h"
48 #include "mozilla/StaticPrefs_network.h"
49 #include "mozilla/StoragePrincipalHelper.h"
50 #include "SerializedLoadContext.h"
51 #include "nsInputStreamPump.h"
52 #include "InterceptedChannel.h"
53 #include "nsContentSecurityManager.h"
54 #include "nsICompressConvStats.h"
55 #include "nsIDeprecationWarner.h"
56 #include "mozilla/dom/Document.h"
57 #include "nsIScriptError.h"
58 #include "nsISerialEventTarget.h"
59 #include "nsRedirectHistoryEntry.h"
60 #include "nsSocketTransportService2.h"
61 #include "nsStreamUtils.h"
62 #include "nsThreadUtils.h"
63 #include "nsCORSListenerProxy.h"
64 #include "ClassifierDummyChannel.h"
65 #include "nsIOService.h"
66 
67 #include <functional>
68 
69 using namespace mozilla::dom;
70 using namespace mozilla::ipc;
71 
72 namespace mozilla {
73 namespace net {
74 
75 //-----------------------------------------------------------------------------
76 // HttpChannelChild
77 //-----------------------------------------------------------------------------
78 
HttpChannelChild()79 HttpChannelChild::HttpChannelChild()
80     : HttpAsyncAborter<HttpChannelChild>(this),
81       NeckoTargetHolder(nullptr),
82       mCacheEntryAvailable(false),
83       mAltDataCacheEntryAvailable(false),
84       mSendResumeAt(false),
85       mKeptAlive(false),
86       mIPCActorDeleted(false),
87       mSuspendSent(false),
88       mIsLastPartOfMultiPart(false),
89       mSuspendForWaitCompleteRedirectSetup(false),
90       mRecvOnStartRequestSentCalled(false),
91       mSuspendedByWaitingForPermissionCookie(false) {
92   LOG(("Creating HttpChannelChild @%p\n", this));
93 
94   mChannelCreationTime = PR_Now();
95   mChannelCreationTimestamp = TimeStamp::Now();
96   mLastStatusReported =
97       mChannelCreationTimestamp;  // in case we enable the profiler after Init()
98   mAsyncOpenTime = TimeStamp::Now();
99   mEventQ = new ChannelEventQueue(static_cast<nsIHttpChannel*>(this));
100 
101   // Ensure that the cookie service is initialized before the first
102   // IPC HTTP channel is created.
103   // We require that the parent cookie service actor exists while
104   // processing HTTP responses.
105   RefPtr<CookieServiceChild> cookieService = CookieServiceChild::GetSingleton();
106 }
107 
~HttpChannelChild()108 HttpChannelChild::~HttpChannelChild() {
109   LOG(("Destroying HttpChannelChild @%p\n", this));
110 
111 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
112   if (mDoDiagnosticAssertWhenOnStopNotCalledOnDestroy && mAsyncOpenSucceeded &&
113       !mSuccesfullyRedirected && !LoadOnStopRequestCalled()) {
114     bool emptyBgChildQueue, nullBgChild;
115     {
116       MutexAutoLock lock(mBgChildMutex);
117       nullBgChild = !mBgChild;
118       emptyBgChildQueue = !nullBgChild && mBgChild->IsQueueEmpty();
119     }
120 
121     uint32_t flags =
122         (mRedirectChannelChild ? 1 << 0 : 0) |
123         (mEventQ->IsEmpty() ? 1 << 1 : 0) | (nullBgChild ? 1 << 2 : 0) |
124         (emptyBgChildQueue ? 1 << 3 : 0) |
125         (LoadOnStartRequestCalled() ? 1 << 4 : 0) |
126         (mBackgroundChildQueueFinalState == BCKCHILD_EMPTY ? 1 << 5 : 0) |
127         (mBackgroundChildQueueFinalState == BCKCHILD_NON_EMPTY ? 1 << 6 : 0) |
128         (mRemoteChannelExistedAtCancel ? 1 << 7 : 0) |
129         (mEverHadBgChildAtAsyncOpen ? 1 << 8 : 0) |
130         (mEverHadBgChildAtConnectParent ? 1 << 9 : 0) |
131         (mCreateBackgroundChannelFailed ? 1 << 10 : 0) |
132         (mBgInitFailCallbackTriggered ? 1 << 11 : 0) |
133         (mCanSendAtCancel ? 1 << 12 : 0) | (!!mSuspendCount ? 1 << 13 : 0) |
134         (!!mCallOnResume ? 1 << 14 : 0);
135     MOZ_CRASH_UNSAFE_PRINTF(
136         "~HttpChannelChild, LoadOnStopRequestCalled()=false, mStatus=0x%08x, "
137         "mActorDestroyReason=%d, 20200717 flags=%u",
138         static_cast<uint32_t>(nsresult(mStatus)),
139         static_cast<int32_t>(mActorDestroyReason ? *mActorDestroyReason : -1),
140         flags);
141   }
142 #endif
143 
144   mEventQ->NotifyReleasingOwner();
145 
146   ReleaseMainThreadOnlyReferences();
147 }
148 
ReleaseMainThreadOnlyReferences()149 void HttpChannelChild::ReleaseMainThreadOnlyReferences() {
150   if (NS_IsMainThread()) {
151     // Already on main thread, let dtor to
152     // take care of releasing references
153     return;
154   }
155 
156   NS_ReleaseOnMainThread("HttpChannelChild::mRedirectChannelChild",
157                          mRedirectChannelChild.forget());
158 }
159 //-----------------------------------------------------------------------------
160 // HttpChannelChild::nsISupports
161 //-----------------------------------------------------------------------------
162 
163 NS_IMPL_ADDREF(HttpChannelChild)
164 
NS_IMETHODIMP_(MozExternalRefCountType)165 NS_IMETHODIMP_(MozExternalRefCountType) HttpChannelChild::Release() {
166   if (!NS_IsMainThread()) {
167     nsrefcnt count = mRefCnt;
168     nsresult rv = NS_DispatchToMainThread(NewNonOwningRunnableMethod(
169         "HttpChannelChild::Release", this, &HttpChannelChild::Release));
170 
171     // Continue Release procedure if failed to dispatch to main thread.
172     if (!NS_WARN_IF(NS_FAILED(rv))) {
173       return count - 1;
174     }
175   }
176 
177   nsrefcnt count = --mRefCnt;
178   MOZ_ASSERT(int32_t(count) >= 0, "dup release");
179 
180   // Normally we Send_delete in OnStopRequest, but when we need to retain the
181   // remote channel for security info IPDL itself holds 1 reference, so we
182   // Send_delete when refCnt==1.  But if !CanSend(), then there's nobody to send
183   // to, so we fall through.
184   if (mKeptAlive && count == 1 && CanSend()) {
185     NS_LOG_RELEASE(this, 1, "HttpChannelChild");
186     mKeptAlive = false;
187     // We send a message to the parent, which calls SendDelete, and then the
188     // child calling Send__delete__() to finally drop the refcount to 0.
189     TrySendDeletingChannel();
190     return 1;
191   }
192 
193   if (count == 0) {
194     mRefCnt = 1; /* stabilize */
195 
196     // We don't have a listener when AsyncOpen has failed or when this channel
197     // has been sucessfully redirected.
198     if (MOZ_LIKELY(LoadOnStartRequestCalled() && LoadOnStopRequestCalled()) ||
199         !mListener) {
200       NS_LOG_RELEASE(this, 0, "HttpChannelChild");
201       delete this;
202       return 0;
203     }
204 
205     // This makes sure we fulfill the stream listener contract all the time.
206     if (NS_SUCCEEDED(mStatus)) {
207       mStatus = NS_ERROR_ABORT;
208     }
209 
210     // Turn the stabilization refcount into a regular strong reference.
211 
212     // 1) We tell refcount logging about the "stabilization" AddRef, which
213     // will become the reference for |channel|. We do this first so that we
214     // don't tell refcount logging that the refcount has dropped to zero, which
215     // it will interpret as destroying the object.
216     NS_LOG_ADDREF(this, 2, "HttpChannelChild", sizeof(*this));
217 
218     // 2) We tell refcount logging about the original call to Release().
219     NS_LOG_RELEASE(this, 1, "HttpChannelChild");
220 
221     // 3) Finally, we turn the reference into a regular smart pointer.
222     RefPtr<HttpChannelChild> channel = dont_AddRef(this);
223 
224     // This runnable will create a strong reference to |this|.
225     NS_DispatchToMainThread(
226         NewRunnableMethod("~HttpChannelChild>DoNotifyListener", channel,
227                           &HttpChannelChild::DoNotifyListener));
228 
229     // If NS_DispatchToMainThread failed then we're going to leak the runnable,
230     // and thus the channel, so there's no need to do anything else.
231 
232     // We should have already done any special handling for the refcount = 1
233     // case when the refcount first went from 2 to 1. We don't want it to happen
234     // when |channel| is destroyed.
235     MOZ_ASSERT(!mKeptAlive || !CanSend());
236 
237     // XXX If std::move(channel) is allowed, then we don't have to have extra
238     // checks for the refcount going from 2 to 1. See bug 1680217.
239 
240     // This will release the stabilization refcount, which is necessary to avoid
241     // a leak.
242     channel = nullptr;
243 
244     return mRefCnt;
245   }
246 
247   NS_LOG_RELEASE(this, count, "HttpChannelChild");
248   return count;
249 }
250 
251 NS_INTERFACE_MAP_BEGIN(HttpChannelChild)
NS_INTERFACE_MAP_ENTRY(nsIRequest)252   NS_INTERFACE_MAP_ENTRY(nsIRequest)
253   NS_INTERFACE_MAP_ENTRY(nsIChannel)
254   NS_INTERFACE_MAP_ENTRY(nsIHttpChannel)
255   NS_INTERFACE_MAP_ENTRY(nsIHttpChannelInternal)
256   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsICacheInfoChannel,
257                                      !mMultiPartID.isSome())
258   NS_INTERFACE_MAP_ENTRY(nsIResumableChannel)
259   NS_INTERFACE_MAP_ENTRY(nsISupportsPriority)
260   NS_INTERFACE_MAP_ENTRY(nsIClassOfService)
261   NS_INTERFACE_MAP_ENTRY(nsIProxiedChannel)
262   NS_INTERFACE_MAP_ENTRY(nsITraceableChannel)
263   NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectCallback)
264   NS_INTERFACE_MAP_ENTRY(nsIChildChannel)
265   NS_INTERFACE_MAP_ENTRY(nsIHttpChannelChild)
266   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIMultiPartChannel, mMultiPartID.isSome())
267   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIThreadRetargetableRequest,
268                                      !mMultiPartID.isSome())
269   NS_INTERFACE_MAP_ENTRY_CONCRETE(HttpChannelChild)
270 NS_INTERFACE_MAP_END_INHERITING(HttpBaseChannel)
271 
272 //-----------------------------------------------------------------------------
273 // HttpChannelChild::PHttpChannelChild
274 //-----------------------------------------------------------------------------
275 
276 void HttpChannelChild::OnBackgroundChildReady(
277     HttpBackgroundChannelChild* aBgChild) {
278   LOG(("HttpChannelChild::OnBackgroundChildReady [this=%p, bgChild=%p]\n", this,
279        aBgChild));
280   MOZ_ASSERT(OnSocketThread());
281 
282   {
283     MutexAutoLock lock(mBgChildMutex);
284 
285     // mBgChild might be removed or replaced while the original background
286     // channel is inited on STS thread.
287     if (mBgChild != aBgChild) {
288       return;
289     }
290 
291     MOZ_ASSERT(mBgInitFailCallback);
292     mBgInitFailCallback = nullptr;
293   }
294 }
295 
OnBackgroundChildDestroyed(HttpBackgroundChannelChild * aBgChild)296 void HttpChannelChild::OnBackgroundChildDestroyed(
297     HttpBackgroundChannelChild* aBgChild) {
298   LOG(("HttpChannelChild::OnBackgroundChildDestroyed [this=%p]\n", this));
299   // This function might be called during shutdown phase, so OnSocketThread()
300   // might return false even on STS thread. Use IsOnCurrentThreadInfallible()
301   // to get correct information.
302   MOZ_ASSERT(gSocketTransportService);
303   MOZ_ASSERT(gSocketTransportService->IsOnCurrentThreadInfallible());
304 
305   nsCOMPtr<nsIRunnable> callback;
306   {
307     MutexAutoLock lock(mBgChildMutex);
308 
309     // mBgChild might be removed or replaced while the original background
310     // channel is destroyed on STS thread.
311     if (aBgChild != mBgChild) {
312       return;
313     }
314 
315     mBgChild = nullptr;
316     callback = std::move(mBgInitFailCallback);
317   }
318 
319   if (callback) {
320 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
321     mBgInitFailCallbackTriggered = true;
322 #endif
323     nsCOMPtr<nsISerialEventTarget> neckoTarget = GetNeckoTarget();
324     neckoTarget->Dispatch(callback, NS_DISPATCH_NORMAL);
325   }
326 }
327 
RecvOnStartRequestSent()328 mozilla::ipc::IPCResult HttpChannelChild::RecvOnStartRequestSent() {
329   LOG(("HttpChannelChild::RecvOnStartRequestSent [this=%p]\n", this));
330   MOZ_ASSERT(NS_IsMainThread());
331   MOZ_ASSERT(!mRecvOnStartRequestSentCalled);
332 
333   mRecvOnStartRequestSentCalled = true;
334 
335   if (mSuspendedByWaitingForPermissionCookie) {
336     mSuspendedByWaitingForPermissionCookie = false;
337     mEventQ->Resume();
338   }
339   return IPC_OK();
340 }
341 
ProcessOnStartRequest(const nsHttpResponseHead & aResponseHead,const bool & aUseResponseHead,const nsHttpHeaderArray & aRequestHeaders,const HttpChannelOnStartRequestArgs & aArgs)342 void HttpChannelChild::ProcessOnStartRequest(
343     const nsHttpResponseHead& aResponseHead, const bool& aUseResponseHead,
344     const nsHttpHeaderArray& aRequestHeaders,
345     const HttpChannelOnStartRequestArgs& aArgs) {
346   LOG(("HttpChannelChild::ProcessOnStartRequest [this=%p]\n", this));
347   MOZ_ASSERT(OnSocketThread());
348 
349 #ifdef NIGHTLY_BUILD
350   TimeStamp start = TimeStamp::Now();
351 #endif
352 
353   mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
354       this, [self = UnsafePtr<HttpChannelChild>(this), aResponseHead,
355 #ifdef NIGHTLY_BUILD
356              aUseResponseHead, aRequestHeaders, aArgs, start]() {
357         if (self->mLoadFlags & nsIRequest::LOAD_RECORD_START_REQUEST_DELAY) {
358           TimeDuration delay = TimeStamp::Now() - start;
359           Telemetry::Accumulate(
360               Telemetry::HTTP_PRELOAD_IMAGE_STARTREQUEST_DELAY,
361               static_cast<uint32_t>(delay.ToMilliseconds()));
362         }
363 #else
364              aUseResponseHead, aRequestHeaders, aArgs]() {
365 #endif
366 
367         self->OnStartRequest(aResponseHead, aUseResponseHead, aRequestHeaders,
368                              aArgs);
369       }));
370 }
371 
372 static void ResourceTimingStructArgsToTimingsStruct(
373     const ResourceTimingStructArgs& aArgs, TimingStruct& aTimings) {
374   aTimings.domainLookupStart = aArgs.domainLookupStart();
375   aTimings.domainLookupEnd = aArgs.domainLookupEnd();
376   aTimings.connectStart = aArgs.connectStart();
377   aTimings.tcpConnectEnd = aArgs.tcpConnectEnd();
378   aTimings.secureConnectionStart = aArgs.secureConnectionStart();
379   aTimings.connectEnd = aArgs.connectEnd();
380   aTimings.requestStart = aArgs.requestStart();
381   aTimings.responseStart = aArgs.responseStart();
382   aTimings.responseEnd = aArgs.responseEnd();
383 }
384 
385 void HttpChannelChild::OnStartRequest(
386     const nsHttpResponseHead& aResponseHead, const bool& aUseResponseHead,
387     const nsHttpHeaderArray& aRequestHeaders,
388     const HttpChannelOnStartRequestArgs& aArgs) {
389   LOG(("HttpChannelChild::OnStartRequest [this=%p]\n", this));
390 
391   // If this channel was aborted by ActorDestroy, then there may be other
392   // OnStartRequest/OnStopRequest/OnDataAvailable IPC messages that need to
393   // be handled. In that case we just ignore them to avoid calling the listener
394   // twice.
395   if (LoadOnStartRequestCalled() && mIPCActorDeleted) {
396     return;
397   }
398 
399   // Copy arguments only. It's possible to handle other IPC between
400   // OnStartRequest and DoOnStartRequest.
401   mComputedCrossOriginOpenerPolicy = aArgs.openerPolicy();
402 
403   if (!mCanceled && NS_SUCCEEDED(mStatus)) {
404     mStatus = aArgs.channelStatus();
405   }
406 
407   // Cookies headers should not be visible to the child process
408   MOZ_ASSERT(!aRequestHeaders.HasHeader(nsHttp::Cookie));
409   MOZ_ASSERT(!nsHttpResponseHead(aResponseHead).HasHeader(nsHttp::Set_Cookie));
410 
411   if (aUseResponseHead && !mCanceled) {
412     mResponseHead = MakeUnique<nsHttpResponseHead>(aResponseHead);
413   }
414 
415   if (!aArgs.securityInfoSerialization().IsEmpty()) {
416     [[maybe_unused]] nsresult rv = NS_DeserializeObject(
417         aArgs.securityInfoSerialization(), getter_AddRefs(mSecurityInfo));
418     MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
419                           "Deserializing security info should not fail");
420   }
421 
422   ipc::MergeParentLoadInfoForwarder(aArgs.loadInfoForwarder(), mLoadInfo);
423 
424   mIsFromCache = aArgs.isFromCache();
425   mIsRacing = aArgs.isRacing();
426   mCacheEntryAvailable = aArgs.cacheEntryAvailable();
427   mCacheEntryId = aArgs.cacheEntryId();
428   mCacheFetchCount = aArgs.cacheFetchCount();
429   mCacheExpirationTime = aArgs.cacheExpirationTime();
430   mSelfAddr = aArgs.selfAddr();
431   mPeerAddr = aArgs.peerAddr();
432 
433   mRedirectCount = aArgs.redirectCount();
434   mAvailableCachedAltDataType = aArgs.altDataType();
435   StoreDeliveringAltData(aArgs.deliveringAltData());
436   mAltDataLength = aArgs.altDataLength();
437   StoreResolvedByTRR(aArgs.isResolvedByTRR());
438 
439   SetApplyConversion(aArgs.applyConversion());
440 
441   StoreAfterOnStartRequestBegun(true);
442   StoreHasHTTPSRR(aArgs.hasHTTPSRR());
443 
444   AutoEventEnqueuer ensureSerialDispatch(mEventQ);
445 
446   mCacheKey = aArgs.cacheKey();
447 
448   // replace our request headers with what actually got sent in the parent
449   mRequestHead.SetHeaders(aRequestHeaders);
450 
451   // Note: this is where we would notify "http-on-examine-response" observers.
452   // We have deliberately disabled this for child processes (see bug 806753)
453   //
454   // gHttpHandler->OnExamineResponse(this);
455 
456   ResourceTimingStructArgsToTimingsStruct(aArgs.timing(), mTransactionTimings);
457 
458   StoreAllRedirectsSameOrigin(aArgs.allRedirectsSameOrigin());
459 
460   mMultiPartID = aArgs.multiPartID();
461   mIsLastPartOfMultiPart = aArgs.isLastPartOfMultiPart();
462 
463   if (aArgs.overrideReferrerInfo()) {
464     // The arguments passed to SetReferrerInfoInternal here should mirror the
465     // arguments passed in
466     // nsHttpChannel::ReEvaluateReferrerAfterTrackingStatusIsKnown(), except for
467     // aRespectBeforeConnect which we pass false here since we're intentionally
468     // overriding the referrer after BeginConnect().
469     Unused << SetReferrerInfoInternal(aArgs.overrideReferrerInfo(), false, true,
470                                       false);
471   }
472 
473   if (!aArgs.cookie().IsEmpty()) {
474     SetCookie(aArgs.cookie());
475   }
476 
477   if (aArgs.shouldWaitForOnStartRequestSent() &&
478       !mRecvOnStartRequestSentCalled) {
479     LOG(("  > pending DoOnStartRequest until RecvOnStartRequestSent\n"));
480     MOZ_ASSERT(NS_IsMainThread());
481 
482     mEventQ->Suspend();
483     mSuspendedByWaitingForPermissionCookie = true;
484     mEventQ->PrependEvent(MakeUnique<NeckoTargetChannelFunctionEvent>(
485         this, [self = UnsafePtr<HttpChannelChild>(this)]() {
486           self->DoOnStartRequest(self, nullptr);
487         }));
488     return;
489   }
490 
491   // Remember whether HTTP3 is supported
492   if (mResponseHead) {
493     mSupportsHTTP3 =
494         nsHttpHandler::IsHttp3SupportedByServer(mResponseHead.get());
495   }
496 
497   DoOnStartRequest(this, nullptr);
498 }
499 
500 void HttpChannelChild::ProcessOnAfterLastPart(const nsresult& aStatus) {
501   LOG(("HttpChannelChild::ProcessOnAfterLastPart [this=%p]\n", this));
502   MOZ_ASSERT(OnSocketThread());
503   mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
504       this, [self = UnsafePtr<HttpChannelChild>(this), aStatus]() {
505         self->OnAfterLastPart(aStatus);
506       }));
507 }
508 
509 void HttpChannelChild::OnAfterLastPart(const nsresult& aStatus) {
510   if (LoadOnStopRequestCalled()) {
511     return;
512   }
513   StoreOnStopRequestCalled(true);
514 
515   // notify "http-on-stop-connect" observers
516   gHttpHandler->OnStopRequest(this);
517 
518   ReleaseListeners();
519 
520   // If a preferred alt-data type was set, the parent would hold a reference to
521   // the cache entry in case the child calls openAlternativeOutputStream().
522   // (see nsHttpChannel::OnStopRequest)
523   if (!mPreferredCachedAltDataTypes.IsEmpty()) {
524     mAltDataCacheEntryAvailable = mCacheEntryAvailable;
525   }
526   mCacheEntryAvailable = false;
527 
528   if (mLoadGroup) mLoadGroup->RemoveRequest(this, nullptr, mStatus);
529   CleanupBackgroundChannel();
530 
531   if (mLoadFlags & LOAD_DOCUMENT_URI) {
532     // Keep IPDL channel open, but only for updating security info.
533     // If IPDL is already closed, then do nothing.
534     if (CanSend()) {
535       mKeptAlive = true;
536       SendDocumentChannelCleanup(true);
537     }
538   } else {
539     // The parent process will respond by sending a DeleteSelf message and
540     // making sure not to send any more messages after that.
541     TrySendDeletingChannel();
542   }
543 }
544 
545 void HttpChannelChild::DoOnStartRequest(nsIRequest* aRequest,
546                                         nsISupports* aContext) {
547   nsresult rv;
548 
549   LOG(("HttpChannelChild::DoOnStartRequest [this=%p]\n", this));
550 
551   // We handle all the listener chaining before OnStartRequest at this moment.
552   // Prevent additional listeners being added to the chain after the request
553   // as started.
554   StoreTracingEnabled(false);
555 
556   // mListener could be null if the redirect setup is not completed.
557   MOZ_ASSERT(mListener || LoadOnStartRequestCalled());
558   if (!mListener) {
559     Cancel(NS_ERROR_FAILURE);
560     return;
561   }
562 
563   if (mListener) {
564     nsCOMPtr<nsIStreamListener> listener(mListener);
565     StoreOnStartRequestCalled(true);
566     rv = listener->OnStartRequest(aRequest);
567   } else {
568     rv = NS_ERROR_UNEXPECTED;
569   }
570   StoreOnStartRequestCalled(true);
571 
572   if (NS_FAILED(rv)) {
573     Cancel(rv);
574     return;
575   }
576 
577   nsCOMPtr<nsIStreamListener> listener;
578   rv = DoApplyContentConversions(mListener, getter_AddRefs(listener), nullptr);
579   if (NS_FAILED(rv)) {
580     Cancel(rv);
581   } else if (listener) {
582     mListener = listener;
583     mCompressListener = listener;
584   }
585 }
586 
587 void HttpChannelChild::ProcessOnTransportAndData(
588     const nsresult& aChannelStatus, const nsresult& aTransportStatus,
589     const uint64_t& aOffset, const uint32_t& aCount, const nsCString& aData) {
590   LOG(("HttpChannelChild::ProcessOnTransportAndData [this=%p]\n", this));
591   MOZ_ASSERT(OnSocketThread());
592   mEventQ->RunOrEnqueue(new ChannelFunctionEvent(
593       [self = UnsafePtr<HttpChannelChild>(this)]() {
594         return self->GetODATarget();
595       },
596       [self = UnsafePtr<HttpChannelChild>(this), aChannelStatus,
597        aTransportStatus, aOffset, aCount, aData]() {
598         self->OnTransportAndData(aChannelStatus, aTransportStatus, aOffset,
599                                  aCount, aData);
600       }));
601 }
602 
603 void HttpChannelChild::OnTransportAndData(const nsresult& aChannelStatus,
604                                           const nsresult& aTransportStatus,
605                                           const uint64_t& aOffset,
606                                           const uint32_t& aCount,
607                                           const nsCString& aData) {
608   LOG(("HttpChannelChild::OnTransportAndData [this=%p]\n", this));
609 
610   if (!mCanceled && NS_SUCCEEDED(mStatus)) {
611     mStatus = aChannelStatus;
612   }
613 
614   if (mCanceled || NS_FAILED(mStatus)) {
615     return;
616   }
617 
618   // Hold queue lock throughout all three calls, else we might process a later
619   // necko msg in between them.
620   AutoEventEnqueuer ensureSerialDispatch(mEventQ);
621 
622   int64_t progressMax;
623   if (NS_FAILED(GetContentLength(&progressMax))) {
624     progressMax = -1;
625   }
626 
627   const int64_t progress = aOffset + aCount;
628 
629   // OnTransportAndData will be run on retargeted thread if applicable, however
630   // OnStatus/OnProgress event can only be fired on main thread. We need to
631   // dispatch the status/progress event handling back to main thread with the
632   // appropriate event target for networking.
633   if (NS_IsMainThread()) {
634     DoOnStatus(this, aTransportStatus);
635     DoOnProgress(this, progress, progressMax);
636   } else {
637     RefPtr<HttpChannelChild> self = this;
638     nsCOMPtr<nsISerialEventTarget> neckoTarget = GetNeckoTarget();
639     MOZ_ASSERT(neckoTarget);
640 
641     DebugOnly<nsresult> rv = neckoTarget->Dispatch(
642         NS_NewRunnableFunction(
643             "net::HttpChannelChild::OnTransportAndData",
644             [self, aTransportStatus, progress, progressMax]() {
645               self->DoOnStatus(self, aTransportStatus);
646               self->DoOnProgress(self, progress, progressMax);
647             }),
648         NS_DISPATCH_NORMAL);
649     MOZ_ASSERT(NS_SUCCEEDED(rv));
650   }
651 
652   // OnDataAvailable
653   //
654   // NOTE: the OnDataAvailable contract requires the client to read all the data
655   // in the inputstream.  This code relies on that ('data' will go away after
656   // this function).  Apparently the previous, non-e10s behavior was to actually
657   // support only reading part of the data, allowing later calls to read the
658   // rest.
659   nsCOMPtr<nsIInputStream> stringStream;
660   nsresult rv =
661       NS_NewByteInputStream(getter_AddRefs(stringStream),
662                             Span(aData).To(aCount), NS_ASSIGNMENT_DEPEND);
663   if (NS_FAILED(rv)) {
664     Cancel(rv);
665     return;
666   }
667 
668   DoOnDataAvailable(this, nullptr, stringStream, aOffset, aCount);
669   stringStream->Close();
670 
671   // TODO: Bug 1523916 backpressure needs to take into account if the data is
672   // coming from the main process or from the socket process via PBackground.
673   if (NeedToReportBytesRead()) {
674     mUnreportBytesRead += aCount;
675     if (mUnreportBytesRead >= gHttpHandler->SendWindowSize() >> 2) {
676       if (NS_IsMainThread()) {
677         Unused << SendBytesRead(mUnreportBytesRead);
678       } else {
679         // PHttpChannel connects to the main thread
680         RefPtr<HttpChannelChild> self = this;
681         int32_t bytesRead = mUnreportBytesRead;
682         nsCOMPtr<nsISerialEventTarget> neckoTarget = GetNeckoTarget();
683         MOZ_ASSERT(neckoTarget);
684 
685         DebugOnly<nsresult> rv = neckoTarget->Dispatch(
686             NS_NewRunnableFunction("net::HttpChannelChild::SendBytesRead",
687                                    [self, bytesRead]() {
688                                      Unused << self->SendBytesRead(bytesRead);
689                                    }),
690             NS_DISPATCH_NORMAL);
691         MOZ_ASSERT(NS_SUCCEEDED(rv));
692       }
693       mUnreportBytesRead = 0;
694     }
695   }
696 }
697 
698 bool HttpChannelChild::NeedToReportBytesRead() {
699   if (mCacheNeedToReportBytesReadInitialized) {
700     return mNeedToReportBytesRead;
701   }
702 
703   // Might notify parent for partial cache, and the IPC message is ignored by
704   // parent.
705   int64_t contentLength = -1;
706   if (gHttpHandler->SendWindowSize() == 0 || mIsFromCache ||
707       NS_FAILED(GetContentLength(&contentLength)) ||
708       contentLength < gHttpHandler->SendWindowSize()) {
709     mNeedToReportBytesRead = false;
710   }
711 
712   mCacheNeedToReportBytesReadInitialized = true;
713   return mNeedToReportBytesRead;
714 }
715 
716 void HttpChannelChild::DoOnStatus(nsIRequest* aRequest, nsresult status) {
717   LOG(("HttpChannelChild::DoOnStatus [this=%p]\n", this));
718   MOZ_ASSERT(NS_IsMainThread());
719 
720   if (mCanceled) return;
721 
722   // cache the progress sink so we don't have to query for it each time.
723   if (!mProgressSink) GetCallback(mProgressSink);
724 
725   // block status/progress after Cancel or OnStopRequest has been called,
726   // or if channel has LOAD_BACKGROUND set.
727   if (mProgressSink && NS_SUCCEEDED(mStatus) && LoadIsPending() &&
728       !(mLoadFlags & LOAD_BACKGROUND)) {
729     nsAutoCString host;
730     mURI->GetHost(host);
731     mProgressSink->OnStatus(aRequest, status,
732                             NS_ConvertUTF8toUTF16(host).get());
733   }
734 }
735 
736 void HttpChannelChild::DoOnProgress(nsIRequest* aRequest, int64_t progress,
737                                     int64_t progressMax) {
738   LOG(("HttpChannelChild::DoOnProgress [this=%p]\n", this));
739   MOZ_ASSERT(NS_IsMainThread());
740 
741   if (mCanceled) return;
742 
743   // cache the progress sink so we don't have to query for it each time.
744   if (!mProgressSink) GetCallback(mProgressSink);
745 
746   // block status/progress after Cancel or OnStopRequest has been called,
747   // or if channel has LOAD_BACKGROUND set.
748   if (mProgressSink && NS_SUCCEEDED(mStatus) && LoadIsPending()) {
749     // OnProgress
750     //
751     if (progress > 0) {
752       mProgressSink->OnProgress(aRequest, progress, progressMax);
753     }
754   }
755 }
756 
757 void HttpChannelChild::DoOnDataAvailable(nsIRequest* aRequest,
758                                          nsISupports* aContext,
759                                          nsIInputStream* aStream,
760                                          uint64_t aOffset, uint32_t aCount) {
761   AUTO_PROFILER_LABEL("HttpChannelChild::DoOnDataAvailable", NETWORK);
762   LOG(("HttpChannelChild::DoOnDataAvailable [this=%p]\n", this));
763   if (mCanceled) return;
764 
765   if (mListener) {
766     nsCOMPtr<nsIStreamListener> listener(mListener);
767     nsresult rv = listener->OnDataAvailable(aRequest, aStream, aOffset, aCount);
768     if (NS_FAILED(rv)) {
769       CancelOnMainThread(rv);
770     }
771   }
772 }
773 
774 void HttpChannelChild::ProcessOnStopRequest(
775     const nsresult& aChannelStatus, const ResourceTimingStructArgs& aTiming,
776     const nsHttpHeaderArray& aResponseTrailers,
777     nsTArray<ConsoleReportCollected>&& aConsoleReports,
778     bool aFromSocketProcess) {
779   LOG(
780       ("HttpChannelChild::ProcessOnStopRequest [this=%p, "
781        "aFromSocketProcess=%d]\n",
782        this, aFromSocketProcess));
783   MOZ_ASSERT(OnSocketThread());
784 
785   mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
786       this, [self = UnsafePtr<HttpChannelChild>(this), aChannelStatus, aTiming,
787              aResponseTrailers,
788              consoleReports = CopyableTArray{aConsoleReports.Clone()},
789              aFromSocketProcess]() mutable {
790         self->OnStopRequest(aChannelStatus, aTiming, aResponseTrailers);
791         if (!aFromSocketProcess) {
792           self->DoOnConsoleReport(std::move(consoleReports));
793           self->ContinueOnStopRequest();
794         }
795       }));
796 }
797 
798 void HttpChannelChild::ProcessOnConsoleReport(
799     nsTArray<ConsoleReportCollected>&& aConsoleReports) {
800   LOG(("HttpChannelChild::ProcessOnConsoleReport [this=%p]\n", this));
801   MOZ_ASSERT(OnSocketThread());
802 
803   mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
804       this,
805       [self = UnsafePtr<HttpChannelChild>(this),
806        consoleReports = CopyableTArray{aConsoleReports.Clone()}]() mutable {
807         self->DoOnConsoleReport(std::move(consoleReports));
808         self->ContinueOnStopRequest();
809       }));
810 }
811 
812 void HttpChannelChild::DoOnConsoleReport(
813     nsTArray<ConsoleReportCollected>&& aConsoleReports) {
814   if (aConsoleReports.IsEmpty()) {
815     return;
816   }
817 
818   for (ConsoleReportCollected& report : aConsoleReports) {
819     if (report.propertiesFile() <
820         nsContentUtils::PropertiesFile::PropertiesFile_COUNT) {
821       AddConsoleReport(report.errorFlags(), report.category(),
822                        nsContentUtils::PropertiesFile(report.propertiesFile()),
823                        report.sourceFileURI(), report.lineNumber(),
824                        report.columnNumber(), report.messageName(),
825                        report.stringParams());
826     }
827   }
828   MaybeFlushConsoleReports();
829 }
830 
831 void HttpChannelChild::OnStopRequest(
832     const nsresult& aChannelStatus, const ResourceTimingStructArgs& aTiming,
833     const nsHttpHeaderArray& aResponseTrailers) {
834   LOG(("HttpChannelChild::OnStopRequest [this=%p status=%" PRIx32 "]\n", this,
835        static_cast<uint32_t>(aChannelStatus)));
836   MOZ_ASSERT(NS_IsMainThread());
837 
838   // If this channel was aborted by ActorDestroy, then there may be other
839   // OnStartRequest/OnStopRequest/OnDataAvailable IPC messages that need to
840   // be handled. In that case we just ignore them to avoid calling the listener
841   // twice.
842   if (LoadOnStopRequestCalled() && mIPCActorDeleted) {
843     return;
844   }
845 
846   nsCOMPtr<nsICompressConvStats> conv = do_QueryInterface(mCompressListener);
847   if (conv) {
848     conv->GetDecodedDataLength(&mDecodedBodySize);
849   }
850 
851   ResourceTimingStructArgsToTimingsStruct(aTiming, mTransactionTimings);
852 
853   // Do not overwrite or adjust the original mAsyncOpenTime by timing.fetchStart
854   // We must use the original child process time in order to account for child
855   // side work and IPC transit overhead.
856   // XXX: This depends on TimeStamp being equivalent across processes.
857   // This is true for modern hardware but for older platforms it is not always
858   // true.
859 
860   mRedirectStartTimeStamp = aTiming.redirectStart();
861   mRedirectEndTimeStamp = aTiming.redirectEnd();
862   mTransferSize = aTiming.transferSize();
863   mEncodedBodySize = aTiming.encodedBodySize();
864   mProtocolVersion = aTiming.protocolVersion();
865 
866   mCacheReadStart = aTiming.cacheReadStart();
867   mCacheReadEnd = aTiming.cacheReadEnd();
868 
869 #ifdef MOZ_GECKO_PROFILER
870   if (profiler_can_accept_markers()) {
871     nsAutoCString requestMethod;
872     GetRequestMethod(requestMethod);
873     nsAutoCString contentType;
874     if (mResponseHead) {
875       mResponseHead->ContentType(contentType);
876     }
877     int32_t priority = PRIORITY_NORMAL;
878     GetPriority(&priority);
879     profiler_add_network_marker(
880         mURI, requestMethod, priority, mChannelId, NetworkLoadType::LOAD_STOP,
881         mLastStatusReported, TimeStamp::Now(), mTransferSize, kCacheUnknown,
882         mLoadInfo->GetInnerWindowID(), &mTransactionTimings, std::move(mSource),
883         Some(nsDependentCString(contentType.get())));
884   }
885 #endif
886 
887   TimeDuration channelCompletionDuration = TimeStamp::Now() - mAsyncOpenTime;
888   if (mIsFromCache) {
889     PerfStats::RecordMeasurement(PerfStats::Metric::HttpChannelCompletion_Cache,
890                                  channelCompletionDuration);
891   } else {
892     PerfStats::RecordMeasurement(
893         PerfStats::Metric::HttpChannelCompletion_Network,
894         channelCompletionDuration);
895   }
896   PerfStats::RecordMeasurement(PerfStats::Metric::HttpChannelCompletion,
897                                channelCompletionDuration);
898 
899   mResponseTrailers = MakeUnique<nsHttpHeaderArray>(aResponseTrailers);
900 
901   DoPreOnStopRequest(aChannelStatus);
902 
903   {  // We must flush the queue before we Send__delete__
904     // (although we really shouldn't receive any msgs after OnStop),
905     // so make sure this goes out of scope before then.
906     AutoEventEnqueuer ensureSerialDispatch(mEventQ);
907 
908     DoOnStopRequest(this, aChannelStatus, nullptr);
909     // DoOnStopRequest() calls ReleaseListeners()
910   }
911 }
912 
913 void HttpChannelChild::ContinueOnStopRequest() {
914   // If we're a multi-part stream, then don't cleanup yet, and we'll do so
915   // in OnAfterLastPart.
916   if (mMultiPartID) {
917     LOG(
918         ("HttpChannelChild::OnStopRequest  - Expecting future parts on a "
919          "multipart channel postpone cleaning up."));
920     return;
921   }
922 
923   CleanupBackgroundChannel();
924 
925   // If there is a possibility we might want to write alt data to the cache
926   // entry, we keep the channel alive. We still send the DocumentChannelCleanup
927   // message but request the cache entry to be kept by the parent.
928   // If the channel has failed, the cache entry is in a non-writtable state and
929   // we want to release it to not block following consumers.
930   if (NS_SUCCEEDED(mStatus) && !mPreferredCachedAltDataTypes.IsEmpty()) {
931     mKeptAlive = true;
932     SendDocumentChannelCleanup(false);  // don't clear cache entry
933     return;
934   }
935 
936   if (mLoadFlags & LOAD_DOCUMENT_URI) {
937     // Keep IPDL channel open, but only for updating security info.
938     // If IPDL is already closed, then do nothing.
939     if (CanSend()) {
940       mKeptAlive = true;
941       SendDocumentChannelCleanup(true);
942     }
943   } else {
944     // The parent process will respond by sending a DeleteSelf message and
945     // making sure not to send any more messages after that.
946     TrySendDeletingChannel();
947   }
948 }
949 
950 void HttpChannelChild::DoPreOnStopRequest(nsresult aStatus) {
951   AUTO_PROFILER_LABEL("HttpChannelChild::DoPreOnStopRequest", NETWORK);
952   LOG(("HttpChannelChild::DoPreOnStopRequest [this=%p status=%" PRIx32 "]\n",
953        this, static_cast<uint32_t>(aStatus)));
954   StoreIsPending(false);
955 
956   MaybeReportTimingData();
957 
958   if (!mCanceled && NS_SUCCEEDED(mStatus)) {
959     mStatus = aStatus;
960   }
961 
962   CollectOMTTelemetry();
963 }
964 
965 void HttpChannelChild::CollectOMTTelemetry() {
966   MOZ_ASSERT(NS_IsMainThread());
967 
968   // Only collect telemetry for HTTP channel that is loaded successfully and
969   // completely.
970   if (mCanceled || NS_FAILED(mStatus)) {
971     return;
972   }
973 
974   // Use content policy type to accumulate data by usage.
975   nsAutoCString key(
976       NS_CP_ContentTypeName(mLoadInfo->InternalContentPolicyType()));
977 
978   Telemetry::AccumulateCategoricalKeyed(key, mOMTResult);
979 }
980 
981 void HttpChannelChild::DoOnStopRequest(nsIRequest* aRequest,
982                                        nsresult aChannelStatus,
983                                        nsISupports* aContext) {
984   AUTO_PROFILER_LABEL("HttpChannelChild::DoOnStopRequest", NETWORK);
985   LOG(("HttpChannelChild::DoOnStopRequest [this=%p]\n", this));
986   MOZ_ASSERT(NS_IsMainThread());
987   MOZ_ASSERT(!LoadIsPending());
988 
989   auto checkForBlockedContent = [&]() {
990     // NB: We use aChannelStatus here instead of mStatus because if there was an
991     // nsCORSListenerProxy on this request, it will override the tracking
992     // protection's return value.
993     if (UrlClassifierFeatureFactory::IsClassifierBlockingErrorCode(
994             aChannelStatus) ||
995         aChannelStatus == NS_ERROR_MALWARE_URI ||
996         aChannelStatus == NS_ERROR_UNWANTED_URI ||
997         aChannelStatus == NS_ERROR_BLOCKED_URI ||
998         aChannelStatus == NS_ERROR_HARMFUL_URI ||
999         aChannelStatus == NS_ERROR_PHISHING_URI) {
1000       nsCString list, provider, fullhash;
1001 
1002       nsresult rv = GetMatchedList(list);
1003       NS_ENSURE_SUCCESS_VOID(rv);
1004 
1005       rv = GetMatchedProvider(provider);
1006       NS_ENSURE_SUCCESS_VOID(rv);
1007 
1008       rv = GetMatchedFullHash(fullhash);
1009       NS_ENSURE_SUCCESS_VOID(rv);
1010 
1011       UrlClassifierCommon::SetBlockedContent(this, aChannelStatus, list,
1012                                              provider, fullhash);
1013     }
1014   };
1015   checkForBlockedContent();
1016 
1017   // See bug 1587686. If the redirect setup is not completed, the post-redirect
1018   // channel will be not opened and mListener will be null.
1019   MOZ_ASSERT(mListener || !LoadWasOpened());
1020   if (!mListener) {
1021     return;
1022   }
1023 
1024   MOZ_ASSERT(!LoadOnStopRequestCalled(),
1025              "We should not call OnStopRequest twice");
1026 
1027   if (mListener) {
1028     nsCOMPtr<nsIStreamListener> listener(mListener);
1029     StoreOnStopRequestCalled(true);
1030     listener->OnStopRequest(aRequest, mStatus);
1031   }
1032   StoreOnStopRequestCalled(true);
1033 
1034   // If we're a multi-part stream, then don't cleanup yet, and we'll do so
1035   // in OnAfterLastPart.
1036   if (mMultiPartID) {
1037     LOG(
1038         ("HttpChannelChild::DoOnStopRequest  - Expecting future parts on a "
1039          "multipart channel not releasing listeners."));
1040     StoreOnStopRequestCalled(false);
1041     StoreOnStartRequestCalled(false);
1042     return;
1043   }
1044 
1045   // notify "http-on-stop-connect" observers
1046   gHttpHandler->OnStopRequest(this);
1047 
1048   ReleaseListeners();
1049 
1050   // If a preferred alt-data type was set, the parent would hold a reference to
1051   // the cache entry in case the child calls openAlternativeOutputStream().
1052   // (see nsHttpChannel::OnStopRequest)
1053   if (!mPreferredCachedAltDataTypes.IsEmpty()) {
1054     mAltDataCacheEntryAvailable = mCacheEntryAvailable;
1055   }
1056   mCacheEntryAvailable = false;
1057 
1058   if (mLoadGroup) mLoadGroup->RemoveRequest(this, nullptr, mStatus);
1059 }
1060 
1061 void HttpChannelChild::ProcessOnProgress(const int64_t& aProgress,
1062                                          const int64_t& aProgressMax) {
1063   MOZ_ASSERT(OnSocketThread());
1064   LOG(("HttpChannelChild::ProcessOnProgress [this=%p]\n", this));
1065   mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
1066       this,
1067       [self = UnsafePtr<HttpChannelChild>(this), aProgress, aProgressMax]() {
1068         AutoEventEnqueuer ensureSerialDispatch(self->mEventQ);
1069         self->DoOnProgress(self, aProgress, aProgressMax);
1070       }));
1071 }
1072 
1073 void HttpChannelChild::ProcessOnStatus(const nsresult& aStatus) {
1074   MOZ_ASSERT(OnSocketThread());
1075   LOG(("HttpChannelChild::ProcessOnStatus [this=%p]\n", this));
1076   mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
1077       this, [self = UnsafePtr<HttpChannelChild>(this), aStatus]() {
1078         AutoEventEnqueuer ensureSerialDispatch(self->mEventQ);
1079         self->DoOnStatus(self, aStatus);
1080       }));
1081 }
1082 
1083 mozilla::ipc::IPCResult HttpChannelChild::RecvFailedAsyncOpen(
1084     const nsresult& aStatus) {
1085   LOG(("HttpChannelChild::RecvFailedAsyncOpen [this=%p]\n", this));
1086   mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
1087       this, [self = UnsafePtr<HttpChannelChild>(this), aStatus]() {
1088         self->FailedAsyncOpen(aStatus);
1089       }));
1090   return IPC_OK();
1091 }
1092 
1093 // We need to have an implementation of this function just so that we can keep
1094 // all references to mCallOnResume of type HttpChannelChild:  it's not OK in C++
1095 // to set a member function ptr to a base class function.
1096 void HttpChannelChild::HandleAsyncAbort() {
1097   HttpAsyncAborter<HttpChannelChild>::HandleAsyncAbort();
1098 
1099   // Ignore all the messages from background channel after channel aborted.
1100   CleanupBackgroundChannel();
1101 }
1102 
1103 void HttpChannelChild::FailedAsyncOpen(const nsresult& status) {
1104   LOG(("HttpChannelChild::FailedAsyncOpen [this=%p status=%" PRIx32 "]\n", this,
1105        static_cast<uint32_t>(status)));
1106   MOZ_ASSERT(NS_IsMainThread());
1107 
1108   // Might be called twice in race condition in theory.
1109   // (one by RecvFailedAsyncOpen, another by
1110   // HttpBackgroundChannelChild::ActorFailed)
1111   if (LoadOnStartRequestCalled()) {
1112     return;
1113   }
1114 
1115   if (NS_SUCCEEDED(mStatus)) {
1116     mStatus = status;
1117   }
1118 
1119   // We're already being called from IPDL, therefore already "async"
1120   HandleAsyncAbort();
1121 
1122   if (CanSend()) {
1123     TrySendDeletingChannel();
1124   }
1125 }
1126 
1127 void HttpChannelChild::CleanupBackgroundChannel() {
1128   MutexAutoLock lock(mBgChildMutex);
1129 
1130   AUTO_PROFILER_LABEL("HttpChannelChild::CleanupBackgroundChannel", NETWORK);
1131   LOG(("HttpChannelChild::CleanupBackgroundChannel [this=%p bgChild=%p]\n",
1132        this, mBgChild.get()));
1133 
1134   mBgInitFailCallback = nullptr;
1135 
1136   if (!mBgChild) {
1137     return;
1138   }
1139 
1140   RefPtr<HttpBackgroundChannelChild> bgChild = std::move(mBgChild);
1141 
1142   MOZ_RELEASE_ASSERT(gSocketTransportService);
1143   if (!OnSocketThread()) {
1144     gSocketTransportService->Dispatch(
1145         NewRunnableMethod("HttpBackgroundChannelChild::OnChannelClosed",
1146                           bgChild,
1147                           &HttpBackgroundChannelChild::OnChannelClosed),
1148         NS_DISPATCH_NORMAL);
1149   } else {
1150     bgChild->OnChannelClosed();
1151   }
1152 }
1153 
1154 void HttpChannelChild::DoNotifyListenerCleanup() {
1155   LOG(("HttpChannelChild::DoNotifyListenerCleanup [this=%p]\n", this));
1156 }
1157 
1158 void HttpChannelChild::DoAsyncAbort(nsresult aStatus) {
1159   Unused << AsyncAbort(aStatus);
1160 }
1161 
1162 mozilla::ipc::IPCResult HttpChannelChild::RecvDeleteSelf() {
1163   LOG(("HttpChannelChild::RecvDeleteSelf [this=%p]\n", this));
1164   MOZ_ASSERT(NS_IsMainThread());
1165 
1166   // The redirection is vetoed. No need to suspend the event queue.
1167   if (mSuspendForWaitCompleteRedirectSetup) {
1168     mSuspendForWaitCompleteRedirectSetup = false;
1169     mEventQ->Resume();
1170   }
1171 
1172   mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
1173       this,
1174       [self = UnsafePtr<HttpChannelChild>(this)]() { self->DeleteSelf(); }));
1175   return IPC_OK();
1176 }
1177 
1178 void HttpChannelChild::DeleteSelf() { Send__delete__(this); }
1179 
1180 void HttpChannelChild::NotifyOrReleaseListeners(nsresult rv) {
1181   MOZ_ASSERT(NS_IsMainThread());
1182 
1183   if (NS_SUCCEEDED(rv) ||
1184       (LoadOnStartRequestCalled() && LoadOnStopRequestCalled())) {
1185     ReleaseListeners();
1186     return;
1187   }
1188 
1189   if (NS_SUCCEEDED(mStatus)) {
1190     mStatus = rv;
1191   }
1192 
1193   // This is enough what we need.  Undelivered notifications will be pushed.
1194   // DoNotifyListener ensures the call to ReleaseListeners when done.
1195   DoNotifyListener();
1196 }
1197 
1198 void HttpChannelChild::DoNotifyListener() {
1199   LOG(("HttpChannelChild::DoNotifyListener this=%p", this));
1200   MOZ_ASSERT(NS_IsMainThread());
1201 
1202   // In case nsHttpChannel::OnStartRequest wasn't called (e.g. due to flag
1203   // LOAD_ONLY_IF_MODIFIED) we want to set LoadAfterOnStartRequestBegun() to
1204   // true before notifying listener.
1205   if (!LoadAfterOnStartRequestBegun()) {
1206     StoreAfterOnStartRequestBegun(true);
1207   }
1208 
1209   if (mListener && !LoadOnStartRequestCalled()) {
1210     nsCOMPtr<nsIStreamListener> listener = mListener;
1211     StoreOnStartRequestCalled(
1212         true);  // avoid reentrancy bugs by setting this now
1213     listener->OnStartRequest(this);
1214   }
1215   StoreOnStartRequestCalled(true);
1216 
1217   mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
1218       this, [self = UnsafePtr<HttpChannelChild>(this)] {
1219         self->ContinueDoNotifyListener();
1220       }));
1221 }
1222 
1223 void HttpChannelChild::ContinueDoNotifyListener() {
1224   LOG(("HttpChannelChild::ContinueDoNotifyListener this=%p", this));
1225   MOZ_ASSERT(NS_IsMainThread());
1226 
1227   // Make sure IsPending is set to false. At this moment we are done from
1228   // the point of view of our consumer and we have to report our self
1229   // as not-pending.
1230   StoreIsPending(false);
1231 
1232   if (mListener && !LoadOnStopRequestCalled()) {
1233     nsCOMPtr<nsIStreamListener> listener = mListener;
1234     StoreOnStopRequestCalled(true);
1235     listener->OnStopRequest(this, mStatus);
1236   }
1237   StoreOnStopRequestCalled(true);
1238 
1239   // notify "http-on-stop-request" observers
1240   gHttpHandler->OnStopRequest(this);
1241 
1242   // This channel has finished its job, potentially release any tail-blocked
1243   // requests with this.
1244   RemoveAsNonTailRequest();
1245 
1246   // We have to make sure to drop the references to listeners and callbacks
1247   // no longer needed.
1248   ReleaseListeners();
1249 
1250   DoNotifyListenerCleanup();
1251 
1252   // If this is a navigation, then we must let the docshell flush the reports
1253   // to the console later.  The LoadDocument() is pointing at the detached
1254   // document that started the navigation.  We want to show the reports on the
1255   // new document.  Otherwise the console is wiped and the user never sees
1256   // the information.
1257   if (!IsNavigation()) {
1258     if (mLoadGroup) {
1259       FlushConsoleReports(mLoadGroup);
1260     } else {
1261       RefPtr<dom::Document> doc;
1262       mLoadInfo->GetLoadingDocument(getter_AddRefs(doc));
1263       FlushConsoleReports(doc);
1264     }
1265   }
1266 }
1267 
1268 mozilla::ipc::IPCResult HttpChannelChild::RecvReportSecurityMessage(
1269     const nsString& messageTag, const nsString& messageCategory) {
1270   DebugOnly<nsresult> rv = AddSecurityMessage(messageTag, messageCategory);
1271   MOZ_ASSERT(NS_SUCCEEDED(rv));
1272   return IPC_OK();
1273 }
1274 
1275 mozilla::ipc::IPCResult HttpChannelChild::RecvRedirect1Begin(
1276     const uint32_t& aRegistrarId, const URIParams& aNewUri,
1277     const uint32_t& aNewLoadFlags, const uint32_t& aRedirectFlags,
1278     const ParentLoadInfoForwarderArgs& aLoadInfoForwarder,
1279     const nsHttpResponseHead& aResponseHead,
1280     const nsCString& aSecurityInfoSerialization, const uint64_t& aChannelId,
1281     const NetAddr& aOldPeerAddr, const ResourceTimingStructArgs& aTiming) {
1282   // TODO: handle security info
1283   LOG(("HttpChannelChild::RecvRedirect1Begin [this=%p]\n", this));
1284   // We set peer address of child to the old peer,
1285   // Then it will be updated to new peer in OnStartRequest
1286   mPeerAddr = aOldPeerAddr;
1287 
1288   // Cookies headers should not be visible to the child process
1289   MOZ_ASSERT(!nsHttpResponseHead(aResponseHead).HasHeader(nsHttp::Set_Cookie));
1290 
1291   mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
1292       this, [self = UnsafePtr<HttpChannelChild>(this), aRegistrarId, aNewUri,
1293              aNewLoadFlags, aRedirectFlags, aLoadInfoForwarder, aResponseHead,
1294              aSecurityInfoSerialization, aChannelId, aTiming]() {
1295         self->Redirect1Begin(aRegistrarId, aNewUri, aNewLoadFlags,
1296                              aRedirectFlags, aLoadInfoForwarder, aResponseHead,
1297                              aSecurityInfoSerialization, aChannelId, aTiming);
1298       }));
1299   return IPC_OK();
1300 }
1301 
1302 nsresult HttpChannelChild::SetupRedirect(nsIURI* uri,
1303                                          const nsHttpResponseHead* responseHead,
1304                                          const uint32_t& redirectFlags,
1305                                          nsIChannel** outChannel) {
1306   LOG(("HttpChannelChild::SetupRedirect [this=%p]\n", this));
1307 
1308   if (mCanceled) {
1309     return NS_ERROR_ABORT;
1310   }
1311 
1312   nsresult rv;
1313   nsCOMPtr<nsIIOService> ioService;
1314   rv = gHttpHandler->GetIOService(getter_AddRefs(ioService));
1315   NS_ENSURE_SUCCESS(rv, rv);
1316 
1317   nsCOMPtr<nsIChannel> newChannel;
1318   nsCOMPtr<nsILoadInfo> redirectLoadInfo =
1319       CloneLoadInfoForRedirect(uri, redirectFlags);
1320   rv = NS_NewChannelInternal(getter_AddRefs(newChannel), uri, redirectLoadInfo,
1321                              nullptr,  // PerformanceStorage
1322                              nullptr,  // aLoadGroup
1323                              nullptr,  // aCallbacks
1324                              nsIRequest::LOAD_NORMAL, ioService);
1325   NS_ENSURE_SUCCESS(rv, rv);
1326 
1327   // We won't get OnStartRequest, set cookies here.
1328   mResponseHead = MakeUnique<nsHttpResponseHead>(*responseHead);
1329 
1330   bool rewriteToGET = HttpBaseChannel::ShouldRewriteRedirectToGET(
1331       mResponseHead->Status(), mRequestHead.ParsedMethod());
1332 
1333   rv = SetupReplacementChannel(uri, newChannel, !rewriteToGET, redirectFlags);
1334   NS_ENSURE_SUCCESS(rv, rv);
1335 
1336   mRedirectChannelChild = do_QueryInterface(newChannel);
1337   newChannel.forget(outChannel);
1338 
1339   return NS_OK;
1340 }
1341 
1342 void HttpChannelChild::Redirect1Begin(
1343     const uint32_t& registrarId, const URIParams& newOriginalURI,
1344     const uint32_t& newLoadFlags, const uint32_t& redirectFlags,
1345     const ParentLoadInfoForwarderArgs& loadInfoForwarder,
1346     const nsHttpResponseHead& responseHead,
1347     const nsACString& securityInfoSerialization, const uint64_t& channelId,
1348     const ResourceTimingStructArgs& timing) {
1349   nsresult rv;
1350 
1351   LOG(("HttpChannelChild::Redirect1Begin [this=%p]\n", this));
1352 
1353   ipc::MergeParentLoadInfoForwarder(loadInfoForwarder, mLoadInfo);
1354 
1355   nsCOMPtr<nsIURI> uri = DeserializeURI(newOriginalURI);
1356 
1357   ResourceTimingStructArgsToTimingsStruct(timing, mTransactionTimings);
1358 
1359 #ifdef MOZ_GECKO_PROFILER
1360   if (profiler_can_accept_markers()) {
1361     nsAutoCString requestMethod;
1362     GetRequestMethod(requestMethod);
1363     nsAutoCString contentType;
1364     responseHead.ContentType(contentType);
1365 
1366     profiler_add_network_marker(
1367         mURI, requestMethod, mPriority, mChannelId,
1368         NetworkLoadType::LOAD_REDIRECT, mLastStatusReported, TimeStamp::Now(),
1369         0, kCacheUnknown, mLoadInfo->GetInnerWindowID(), &mTransactionTimings,
1370         std::move(mSource), Some(nsDependentCString(contentType.get())), uri,
1371         redirectFlags, channelId);
1372   }
1373 #endif
1374 
1375   if (!securityInfoSerialization.IsEmpty()) {
1376     rv = NS_DeserializeObject(securityInfoSerialization,
1377                               getter_AddRefs(mSecurityInfo));
1378     MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
1379                           "Deserializing security info should not fail");
1380   }
1381 
1382   nsCOMPtr<nsIChannel> newChannel;
1383   rv = SetupRedirect(uri, &responseHead, redirectFlags,
1384                      getter_AddRefs(newChannel));
1385 
1386   if (NS_SUCCEEDED(rv)) {
1387     MOZ_ALWAYS_SUCCEEDS(newChannel->SetLoadFlags(newLoadFlags));
1388 
1389     if (mRedirectChannelChild) {
1390       // Set the channelId allocated in parent to the child instance
1391       nsCOMPtr<nsIHttpChannel> httpChannel =
1392           do_QueryInterface(mRedirectChannelChild);
1393       if (httpChannel) {
1394         rv = httpChannel->SetChannelId(channelId);
1395         MOZ_ASSERT(NS_SUCCEEDED(rv));
1396       }
1397       mRedirectChannelChild->ConnectParent(registrarId);
1398     }
1399 
1400     nsCOMPtr<nsISerialEventTarget> target = GetNeckoTarget();
1401     MOZ_ASSERT(target);
1402 
1403     rv = gHttpHandler->AsyncOnChannelRedirect(this, newChannel, redirectFlags,
1404                                               target);
1405   }
1406 
1407   if (NS_FAILED(rv)) OnRedirectVerifyCallback(rv);
1408 }
1409 
1410 mozilla::ipc::IPCResult HttpChannelChild::RecvRedirect3Complete() {
1411   LOG(("HttpChannelChild::RecvRedirect3Complete [this=%p]\n", this));
1412   nsCOMPtr<nsIChannel> redirectChannel =
1413       do_QueryInterface(mRedirectChannelChild);
1414   MOZ_ASSERT(redirectChannel);
1415   mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
1416       this, [self = UnsafePtr<HttpChannelChild>(this), redirectChannel]() {
1417         nsresult rv = NS_OK;
1418         Unused << self->GetStatus(&rv);
1419         if (NS_FAILED(rv)) {
1420           // Pre-redirect channel was canceled. Call |HandleAsyncAbort|, so
1421           // mListener's OnStart/StopRequest can be called. Nothing else will
1422           // trigger these notification after this point.
1423           // We do this before |CompleteRedirectSetup|, so post-redirect channel
1424           // stays unopened and we also make sure that OnStart/StopRequest won't
1425           // be called twice.
1426           self->HandleAsyncAbort();
1427 
1428           nsCOMPtr<nsIHttpChannelChild> chan =
1429               do_QueryInterface(redirectChannel);
1430           RefPtr<HttpChannelChild> httpChannelChild =
1431               static_cast<HttpChannelChild*>(chan.get());
1432           if (httpChannelChild) {
1433             // For sending an IPC message to parent channel so that the loading
1434             // can be cancelled.
1435             Unused << httpChannelChild->Cancel(rv);
1436 
1437             // The post-redirect channel could still get OnStart/StopRequest IPC
1438             // messages from parent, but the mListener is still null. So, we
1439             // call |DoNotifyListener| to pretend that OnStart/StopRequest are
1440             // already called.
1441             httpChannelChild->DoNotifyListener();
1442           }
1443           return;
1444         }
1445 
1446         self->Redirect3Complete();
1447       }));
1448   return IPC_OK();
1449 }
1450 
1451 void HttpChannelChild::ProcessNotifyClassificationFlags(
1452     uint32_t aClassificationFlags, bool aIsThirdParty) {
1453   LOG(
1454       ("HttpChannelChild::ProcessNotifyClassificationFlags thirdparty=%d "
1455        "flags=%" PRIu32 " [this=%p]\n",
1456        static_cast<int>(aIsThirdParty), aClassificationFlags, this));
1457   MOZ_ASSERT(OnSocketThread());
1458 
1459   mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
1460       this, [self = UnsafePtr<HttpChannelChild>(this), aClassificationFlags,
1461              aIsThirdParty]() {
1462         self->AddClassificationFlags(aClassificationFlags, aIsThirdParty);
1463       }));
1464 }
1465 
1466 void HttpChannelChild::ProcessNotifyFlashPluginStateChanged(
1467     nsIHttpChannel::FlashPluginState aState) {
1468   LOG(("HttpChannelChild::ProcessNotifyFlashPluginStateChanged [this=%p]\n",
1469        this));
1470   MOZ_ASSERT(OnSocketThread());
1471 
1472   mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
1473       this, [self = UnsafePtr<HttpChannelChild>(this), aState]() {
1474         self->SetFlashPluginState(aState);
1475       }));
1476 }
1477 
1478 void HttpChannelChild::ProcessSetClassifierMatchedInfo(
1479     const nsCString& aList, const nsCString& aProvider,
1480     const nsCString& aFullHash) {
1481   LOG(("HttpChannelChild::ProcessSetClassifierMatchedInfo [this=%p]\n", this));
1482   MOZ_ASSERT(OnSocketThread());
1483 
1484   mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
1485       this,
1486       [self = UnsafePtr<HttpChannelChild>(this), aList, aProvider,
1487        aFullHash]() { self->SetMatchedInfo(aList, aProvider, aFullHash); }));
1488 }
1489 
1490 void HttpChannelChild::ProcessSetClassifierMatchedTrackingInfo(
1491     const nsCString& aLists, const nsCString& aFullHashes) {
1492   LOG(("HttpChannelChild::ProcessSetClassifierMatchedTrackingInfo [this=%p]\n",
1493        this));
1494   MOZ_ASSERT(OnSocketThread());
1495 
1496   nsTArray<nsCString> lists, fullhashes;
1497   for (const nsACString& token : aLists.Split(',')) {
1498     lists.AppendElement(token);
1499   }
1500   for (const nsACString& token : aFullHashes.Split(',')) {
1501     fullhashes.AppendElement(token);
1502   }
1503 
1504   mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
1505       this, [self = UnsafePtr<HttpChannelChild>(this),
1506              lists = CopyableTArray{std::move(lists)},
1507              fullhashes = CopyableTArray{std::move(fullhashes)}]() {
1508         self->SetMatchedTrackingInfo(lists, fullhashes);
1509       }));
1510 }
1511 
1512 // Completes the redirect and cleans up the old channel.
1513 void HttpChannelChild::Redirect3Complete() {
1514   LOG(("HttpChannelChild::Redirect3Complete [this=%p]\n", this));
1515   MOZ_ASSERT(NS_IsMainThread());
1516 
1517   // Using an error as the default so that when we fail to forward this redirect
1518   // to the target channel, we make sure to notify the current listener from
1519   // CleanupRedirectingChannel.
1520   nsresult rv = NS_BINDING_ABORTED;
1521 
1522   nsCOMPtr<nsIRedirectResultListener> vetoHook;
1523   GetCallback(vetoHook);
1524   if (vetoHook) {
1525     vetoHook->OnRedirectResult(true);
1526   }
1527 
1528   // Chrome channel has been AsyncOpen'd.  Reflect this in child.
1529   if (mRedirectChannelChild) {
1530     rv = mRedirectChannelChild->CompleteRedirectSetup(mListener);
1531 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1532     mSuccesfullyRedirected = NS_SUCCEEDED(rv);
1533 #endif
1534   }
1535 
1536   CleanupRedirectingChannel(rv);
1537 }
1538 
1539 void HttpChannelChild::CleanupRedirectingChannel(nsresult rv) {
1540   // Redirecting to new channel: shut this down and init new channel
1541   if (mLoadGroup) mLoadGroup->RemoveRequest(this, nullptr, NS_BINDING_ABORTED);
1542 
1543   if (NS_SUCCEEDED(rv)) {
1544     nsCString remoteAddress;
1545     Unused << GetRemoteAddress(remoteAddress);
1546     nsCOMPtr<nsIURI> referrer;
1547     if (mReferrerInfo) {
1548       referrer = mReferrerInfo->GetComputedReferrer();
1549     }
1550 
1551     nsCOMPtr<nsIRedirectHistoryEntry> entry =
1552         new nsRedirectHistoryEntry(GetURIPrincipal(), referrer, remoteAddress);
1553 
1554     mLoadInfo->AppendRedirectHistoryEntry(entry, false);
1555   } else {
1556     NS_WARNING("CompleteRedirectSetup failed, HttpChannelChild already open?");
1557   }
1558 
1559   // Release ref to new channel.
1560   mRedirectChannelChild = nullptr;
1561 
1562   NotifyOrReleaseListeners(rv);
1563   CleanupBackgroundChannel();
1564 }
1565 
1566 //-----------------------------------------------------------------------------
1567 // HttpChannelChild::nsIChildChannel
1568 //-----------------------------------------------------------------------------
1569 
1570 NS_IMETHODIMP
1571 HttpChannelChild::ConnectParent(uint32_t registrarId) {
1572   LOG(("HttpChannelChild::ConnectParent [this=%p, id=%" PRIu32 "]\n", this,
1573        registrarId));
1574   MOZ_ASSERT(NS_IsMainThread());
1575   mozilla::dom::BrowserChild* browserChild = nullptr;
1576   nsCOMPtr<nsIBrowserChild> iBrowserChild;
1577   GetCallback(iBrowserChild);
1578   if (iBrowserChild) {
1579     browserChild =
1580         static_cast<mozilla::dom::BrowserChild*>(iBrowserChild.get());
1581   }
1582 
1583   if (browserChild && !browserChild->IPCOpen()) {
1584     return NS_ERROR_FAILURE;
1585   }
1586 
1587   ContentChild* cc = static_cast<ContentChild*>(gNeckoChild->Manager());
1588   if (cc->IsShuttingDown()) {
1589     return NS_ERROR_FAILURE;
1590   }
1591 
1592   HttpBaseChannel::SetDocshellUserAgentOverride();
1593 
1594   // This must happen before the constructor message is sent. Otherwise messages
1595   // from the parent could arrive quickly and be delivered to the wrong event
1596   // target.
1597   SetEventTarget();
1598 
1599   if (browserChild) {
1600     MOZ_ASSERT(browserChild->WebNavigation());
1601     if (BrowsingContext* bc = browserChild->GetBrowsingContext()) {
1602       mTopBrowsingContextId = bc->Top()->Id();
1603     }
1604   }
1605 
1606   HttpChannelConnectArgs connectArgs(registrarId);
1607   if (!gNeckoChild->SendPHttpChannelConstructor(
1608           this, browserChild, IPC::SerializedLoadContext(this), connectArgs)) {
1609     return NS_ERROR_FAILURE;
1610   }
1611 
1612   {
1613     MutexAutoLock lock(mBgChildMutex);
1614 
1615     MOZ_ASSERT(!mBgChild);
1616     MOZ_ASSERT(!mBgInitFailCallback);
1617 
1618     mBgInitFailCallback = NewRunnableMethod<nsresult>(
1619         "HttpChannelChild::OnRedirectVerifyCallback", this,
1620         &HttpChannelChild::OnRedirectVerifyCallback, NS_ERROR_FAILURE);
1621 
1622     RefPtr<HttpBackgroundChannelChild> bgChild =
1623         new HttpBackgroundChannelChild();
1624 
1625     MOZ_RELEASE_ASSERT(gSocketTransportService);
1626 
1627     RefPtr<HttpChannelChild> self = this;
1628     nsresult rv = gSocketTransportService->Dispatch(
1629         NewRunnableMethod<RefPtr<HttpChannelChild>>(
1630             "HttpBackgroundChannelChild::Init", bgChild,
1631             &HttpBackgroundChannelChild::Init, std::move(self)),
1632         NS_DISPATCH_NORMAL);
1633 
1634     if (NS_WARN_IF(NS_FAILED(rv))) {
1635       return rv;
1636     }
1637 
1638     mBgChild = std::move(bgChild);
1639 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1640     mEverHadBgChildAtConnectParent = true;
1641 #endif
1642   }
1643 
1644   // Should wait for CompleteRedirectSetup to set the listener.
1645   mEventQ->Suspend();
1646   MOZ_ASSERT(!mSuspendForWaitCompleteRedirectSetup);
1647   mSuspendForWaitCompleteRedirectSetup = true;
1648 
1649   // Connect to socket process after mEventQ is suspended.
1650   MaybeConnectToSocketProcess();
1651 
1652   return NS_OK;
1653 }
1654 
1655 NS_IMETHODIMP
1656 HttpChannelChild::CompleteRedirectSetup(nsIStreamListener* aListener) {
1657   LOG(("HttpChannelChild::CompleteRedirectSetup [this=%p]\n", this));
1658   MOZ_ASSERT(NS_IsMainThread());
1659 
1660   NS_ENSURE_TRUE(!LoadIsPending(), NS_ERROR_IN_PROGRESS);
1661   NS_ENSURE_TRUE(!LoadWasOpened(), NS_ERROR_ALREADY_OPENED);
1662 
1663   // Resume the suspension in ConnectParent.
1664   auto eventQueueResumeGuard = MakeScopeExit([&] {
1665     MOZ_ASSERT(mSuspendForWaitCompleteRedirectSetup);
1666     mEventQ->Resume();
1667     mSuspendForWaitCompleteRedirectSetup = false;
1668   });
1669 
1670   /*
1671    * No need to check for cancel: we don't get here if nsHttpChannel canceled
1672    * before AsyncOpen(); if it's canceled after that, OnStart/Stop will just
1673    * get called with error code as usual.  So just setup mListener and make the
1674    * channel reflect AsyncOpen'ed state.
1675    */
1676 
1677   mLastStatusReported = TimeStamp::Now();
1678 #ifdef MOZ_GECKO_PROFILER
1679   if (profiler_can_accept_markers()) {
1680     nsAutoCString requestMethod;
1681     GetRequestMethod(requestMethod);
1682 
1683     profiler_add_network_marker(
1684         mURI, requestMethod, mPriority, mChannelId, NetworkLoadType::LOAD_START,
1685         mChannelCreationTimestamp, mLastStatusReported, 0, kCacheUnknown,
1686         mLoadInfo->GetInnerWindowID());
1687   }
1688 #endif
1689   StoreIsPending(true);
1690   StoreWasOpened(true);
1691   mListener = aListener;
1692 
1693   // add ourselves to the load group.
1694   if (mLoadGroup) mLoadGroup->AddRequest(this, nullptr);
1695 
1696   // We already have an open IPDL connection to the parent. If on-modify-request
1697   // listeners or load group observers canceled us, let the parent handle it
1698   // and send it back to us naturally.
1699   return NS_OK;
1700 }
1701 
1702 //-----------------------------------------------------------------------------
1703 // HttpChannelChild::nsIAsyncVerifyRedirectCallback
1704 //-----------------------------------------------------------------------------
1705 
1706 NS_IMETHODIMP
1707 HttpChannelChild::OnRedirectVerifyCallback(nsresult aResult) {
1708   LOG(("HttpChannelChild::OnRedirectVerifyCallback [this=%p]\n", this));
1709   MOZ_ASSERT(NS_IsMainThread());
1710   Maybe<URIParams> redirectURI;
1711   nsresult rv;
1712 
1713   nsCOMPtr<nsIHttpChannel> newHttpChannel =
1714       do_QueryInterface(mRedirectChannelChild);
1715 
1716   if (NS_SUCCEEDED(aResult) && !mRedirectChannelChild) {
1717     // mRedirectChannelChild doesn't exist means we're redirecting to a protocol
1718     // that doesn't implement nsIChildChannel. The redirect result should be set
1719     // as failed by veto listeners and shouldn't enter this condition. As the
1720     // last resort, we synthesize the error result as NS_ERROR_DOM_BAD_URI here
1721     // to let nsHttpChannel::ContinueProcessResponse2 know it's redirecting to
1722     // another protocol and throw an error.
1723     LOG(("  redirecting to a protocol that doesn't implement nsIChildChannel"));
1724     aResult = NS_ERROR_DOM_BAD_URI;
1725   }
1726 
1727   nsCOMPtr<nsIReferrerInfo> referrerInfo;
1728   if (newHttpChannel) {
1729     // Must not be called until after redirect observers called.
1730     newHttpChannel->SetOriginalURI(mOriginalURI);
1731     referrerInfo = newHttpChannel->GetReferrerInfo();
1732   }
1733 
1734   RequestHeaderTuples emptyHeaders;
1735   RequestHeaderTuples* headerTuples = &emptyHeaders;
1736   nsLoadFlags loadFlags = 0;
1737   Maybe<CorsPreflightArgs> corsPreflightArgs;
1738 
1739   nsCOMPtr<nsIHttpChannelChild> newHttpChannelChild =
1740       do_QueryInterface(mRedirectChannelChild);
1741   if (newHttpChannelChild && NS_SUCCEEDED(aResult)) {
1742     rv = newHttpChannelChild->AddCookiesToRequest();
1743     MOZ_ASSERT(NS_SUCCEEDED(rv));
1744     rv = newHttpChannelChild->GetClientSetRequestHeaders(&headerTuples);
1745     MOZ_ASSERT(NS_SUCCEEDED(rv));
1746     newHttpChannelChild->GetClientSetCorsPreflightParameters(corsPreflightArgs);
1747   }
1748 
1749   /* If the redirect was canceled, bypass OMR and send an empty API
1750    * redirect URI */
1751   SerializeURI(nullptr, redirectURI);
1752 
1753   if (NS_SUCCEEDED(aResult)) {
1754     // Note: this is where we would notify "http-on-modify-response" observers.
1755     // We have deliberately disabled this for child processes (see bug 806753)
1756     //
1757     // After we verify redirect, nsHttpChannel may hit the network: must give
1758     // "http-on-modify-request" observers the chance to cancel before that.
1759     // base->CallOnModifyRequestObservers();
1760 
1761     nsCOMPtr<nsIHttpChannelInternal> newHttpChannelInternal =
1762         do_QueryInterface(mRedirectChannelChild);
1763     if (newHttpChannelInternal) {
1764       nsCOMPtr<nsIURI> apiRedirectURI;
1765       rv = newHttpChannelInternal->GetApiRedirectToURI(
1766           getter_AddRefs(apiRedirectURI));
1767       if (NS_SUCCEEDED(rv) && apiRedirectURI) {
1768         /* If there was an API redirect of this channel, we need to send it
1769          * up here, since it can't be sent via SendAsyncOpen. */
1770         SerializeURI(apiRedirectURI, redirectURI);
1771       }
1772     }
1773 
1774     nsCOMPtr<nsIRequest> request = do_QueryInterface(mRedirectChannelChild);
1775     if (request) {
1776       request->GetLoadFlags(&loadFlags);
1777     }
1778   }
1779 
1780   uint32_t sourceRequestBlockingReason = 0;
1781   mLoadInfo->GetRequestBlockingReason(&sourceRequestBlockingReason);
1782 
1783   Maybe<ChildLoadInfoForwarderArgs> targetLoadInfoForwarder;
1784   nsCOMPtr<nsIChannel> newChannel = do_QueryInterface(mRedirectChannelChild);
1785   if (newChannel) {
1786     ChildLoadInfoForwarderArgs args;
1787     nsCOMPtr<nsILoadInfo> loadInfo = newChannel->LoadInfo();
1788     LoadInfoToChildLoadInfoForwarder(loadInfo, &args);
1789     targetLoadInfoForwarder.emplace(args);
1790   }
1791 
1792   if (CanSend()) {
1793     SendRedirect2Verify(aResult, *headerTuples, sourceRequestBlockingReason,
1794                         targetLoadInfoForwarder, loadFlags, referrerInfo,
1795                         redirectURI, corsPreflightArgs);
1796   }
1797 
1798   return NS_OK;
1799 }
1800 
1801 //-----------------------------------------------------------------------------
1802 // HttpChannelChild::nsIRequest
1803 //-----------------------------------------------------------------------------
1804 
1805 NS_IMETHODIMP
1806 HttpChannelChild::Cancel(nsresult aStatus) {
1807   LOG(("HttpChannelChild::Cancel [this=%p, status=%" PRIx32 "]\n", this,
1808        static_cast<uint32_t>(aStatus)));
1809   LogCallingScriptLocation(this);
1810 
1811   MOZ_ASSERT(NS_IsMainThread());
1812 
1813   if (!mCanceled) {
1814     // If this cancel occurs before nsHttpChannel has been set up, AsyncOpen
1815     // is responsible for cleaning up.
1816     mCanceled = true;
1817     mStatus = aStatus;
1818 
1819     bool remoteChannelExists = RemoteChannelExists();
1820 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1821     mCanSendAtCancel = CanSend();
1822     mRemoteChannelExistedAtCancel = remoteChannelExists;
1823 #endif
1824 
1825     if (remoteChannelExists) {
1826       SendCancel(aStatus, mLoadInfo->GetRequestBlockingReason());
1827     } else if (MOZ_UNLIKELY(!LoadOnStartRequestCalled() ||
1828                             !LoadOnStopRequestCalled())) {
1829       Unused << AsyncAbort(mStatus);
1830     }
1831   }
1832   return NS_OK;
1833 }
1834 
1835 NS_IMETHODIMP
1836 HttpChannelChild::Suspend() {
1837   LOG(("HttpChannelChild::Suspend [this=%p, mSuspendCount=%" PRIu32 "\n", this,
1838        mSuspendCount + 1));
1839   MOZ_ASSERT(NS_IsMainThread());
1840 
1841   LogCallingScriptLocation(this);
1842 
1843   // SendSuspend only once, when suspend goes from 0 to 1.
1844   // Don't SendSuspend at all if we're diverting callbacks to the parent;
1845   // suspend will be called at the correct time in the parent itself.
1846   if (!mSuspendCount++) {
1847     if (RemoteChannelExists()) {
1848       SendSuspend();
1849       mSuspendSent = true;
1850     }
1851   }
1852   mEventQ->Suspend();
1853 
1854   return NS_OK;
1855 }
1856 
1857 NS_IMETHODIMP
1858 HttpChannelChild::Resume() {
1859   LOG(("HttpChannelChild::Resume [this=%p, mSuspendCount=%" PRIu32 "\n", this,
1860        mSuspendCount - 1));
1861   MOZ_ASSERT(NS_IsMainThread());
1862   NS_ENSURE_TRUE(mSuspendCount > 0, NS_ERROR_UNEXPECTED);
1863 
1864   LogCallingScriptLocation(this);
1865 
1866   nsresult rv = NS_OK;
1867 
1868   // SendResume only once, when suspend count drops to 0.
1869   // Don't SendResume at all if we're diverting callbacks to the parent (unless
1870   // suspend was sent earlier); otherwise, resume will be called at the correct
1871   // time in the parent itself.
1872   if (!--mSuspendCount) {
1873     if (RemoteChannelExists() && mSuspendSent) {
1874       SendResume();
1875     }
1876     if (mCallOnResume) {
1877       nsCOMPtr<nsISerialEventTarget> neckoTarget = GetNeckoTarget();
1878       MOZ_ASSERT(neckoTarget);
1879 
1880       RefPtr<HttpChannelChild> self = this;
1881       std::function<nsresult(HttpChannelChild*)> callOnResume = nullptr;
1882       std::swap(callOnResume, mCallOnResume);
1883       rv = neckoTarget->Dispatch(
1884           NS_NewRunnableFunction(
1885               "net::HttpChannelChild::mCallOnResume",
1886               [callOnResume, self{std::move(self)}]() { callOnResume(self); }),
1887           NS_DISPATCH_NORMAL);
1888     }
1889   }
1890   mEventQ->Resume();
1891 
1892   return rv;
1893 }
1894 
1895 //-----------------------------------------------------------------------------
1896 // HttpChannelChild::nsIChannel
1897 //-----------------------------------------------------------------------------
1898 
1899 NS_IMETHODIMP
1900 HttpChannelChild::GetSecurityInfo(nsISupports** aSecurityInfo) {
1901   NS_ENSURE_ARG_POINTER(aSecurityInfo);
1902   NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo);
1903   return NS_OK;
1904 }
1905 
1906 NS_IMETHODIMP
1907 HttpChannelChild::AsyncOpen(nsIStreamListener* aListener) {
1908   LOG(("HttpChannelChild::AsyncOpen [this=%p uri=%s]\n", this, mSpec.get()));
1909 
1910   nsresult rv = AsyncOpenInternal(aListener);
1911   if (NS_FAILED(rv)) {
1912     uint32_t blockingReason = 0;
1913     mLoadInfo->GetRequestBlockingReason(&blockingReason);
1914     LOG(
1915         ("HttpChannelChild::AsyncOpen failed [this=%p rv=0x%08x "
1916          "blocking-reason=%u]\n",
1917          this, static_cast<uint32_t>(rv), blockingReason));
1918 
1919     gHttpHandler->OnFailedOpeningRequest(this);
1920   }
1921 
1922 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1923   mAsyncOpenSucceeded = NS_SUCCEEDED(rv);
1924 #endif
1925   return rv;
1926 }
1927 
1928 nsresult HttpChannelChild::AsyncOpenInternal(nsIStreamListener* aListener) {
1929   nsresult rv;
1930 
1931   nsCOMPtr<nsIStreamListener> listener = aListener;
1932   rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
1933   if (NS_WARN_IF(NS_FAILED(rv))) {
1934     ReleaseListeners();
1935     return rv;
1936   }
1937 
1938   MOZ_ASSERT(
1939       mLoadInfo->GetSecurityMode() == 0 ||
1940           mLoadInfo->GetInitialSecurityCheckDone() ||
1941           (mLoadInfo->GetSecurityMode() ==
1942                nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL &&
1943            mLoadInfo->GetLoadingPrincipal() &&
1944            mLoadInfo->GetLoadingPrincipal()->IsSystemPrincipal()),
1945       "security flags in loadInfo but doContentSecurityCheck() not called");
1946 
1947   LogCallingScriptLocation(this);
1948 
1949   if (!mLoadGroup && !mCallbacks) {
1950     // If no one called SetLoadGroup or SetNotificationCallbacks, the private
1951     // state has not been updated on PrivateBrowsingChannel (which we derive
1952     // from) Hence, we have to call UpdatePrivateBrowsing() here
1953     UpdatePrivateBrowsing();
1954   }
1955 
1956 #ifdef DEBUG
1957   AssertPrivateBrowsingId();
1958 #endif
1959 
1960   if (mCanceled) {
1961     ReleaseListeners();
1962     return mStatus;
1963   }
1964 
1965   NS_ENSURE_TRUE(gNeckoChild != nullptr, NS_ERROR_FAILURE);
1966   NS_ENSURE_ARG_POINTER(listener);
1967   NS_ENSURE_TRUE(!LoadIsPending(), NS_ERROR_IN_PROGRESS);
1968   NS_ENSURE_TRUE(!LoadWasOpened(), NS_ERROR_ALREADY_OPENED);
1969 
1970   if (MaybeWaitForUploadStreamLength(listener, nullptr)) {
1971     return NS_OK;
1972   }
1973 
1974   if (!LoadAsyncOpenTimeOverriden()) {
1975     mAsyncOpenTime = TimeStamp::Now();
1976   }
1977 
1978   // Port checked in parent, but duplicate here so we can return with error
1979   // immediately
1980   rv = NS_CheckPortSafety(mURI);
1981   if (NS_FAILED(rv)) {
1982     ReleaseListeners();
1983     return rv;
1984   }
1985 
1986   nsAutoCString cookie;
1987   if (NS_SUCCEEDED(mRequestHead.GetHeader(nsHttp::Cookie, cookie))) {
1988     mUserSetCookieHeader = cookie;
1989   }
1990 
1991   DebugOnly<nsresult> check = AddCookiesToRequest();
1992   MOZ_ASSERT(NS_SUCCEEDED(check));
1993 
1994   //
1995   // NOTE: From now on we must return NS_OK; all errors must be handled via
1996   // OnStart/OnStopRequest
1997   //
1998 
1999   // We notify "http-on-opening-request" observers in the child
2000   // process so that devtools can capture a stack trace at the
2001   // appropriate spot.  See bug 806753 for some information about why
2002   // other http-* notifications are disabled in child processes.
2003   gHttpHandler->OnOpeningRequest(this);
2004 
2005   mLastStatusReported = TimeStamp::Now();
2006 #ifdef MOZ_GECKO_PROFILER
2007   if (profiler_can_accept_markers()) {
2008     nsAutoCString requestMethod;
2009     GetRequestMethod(requestMethod);
2010 
2011     profiler_add_network_marker(
2012         mURI, requestMethod, mPriority, mChannelId, NetworkLoadType::LOAD_START,
2013         mChannelCreationTimestamp, mLastStatusReported, 0, kCacheUnknown,
2014         mLoadInfo->GetInnerWindowID());
2015   }
2016 #endif
2017   StoreIsPending(true);
2018   StoreWasOpened(true);
2019   mListener = listener;
2020 
2021   // add ourselves to the load group.
2022   if (mLoadGroup) mLoadGroup->AddRequest(this, nullptr);
2023 
2024   if (mCanceled) {
2025     // We may have been canceled already, either by on-modify-request
2026     // listeners or by load group observers; in that case, don't create IPDL
2027     // connection. See nsHttpChannel::AsyncOpen().
2028     ReleaseListeners();
2029     return mStatus;
2030   }
2031 
2032   // Set user agent override from docshell
2033   HttpBaseChannel::SetDocshellUserAgentOverride();
2034 
2035   rv = ContinueAsyncOpen();
2036   if (NS_FAILED(rv)) {
2037     ReleaseListeners();
2038   }
2039   return rv;
2040 }
2041 
2042 // Assigns an nsISerialEventTarget to our IPDL actor so that IPC messages are
2043 // sent to the correct DocGroup/TabGroup.
2044 void HttpChannelChild::SetEventTarget() {
2045   nsCOMPtr<nsILoadInfo> loadInfo = LoadInfo();
2046 
2047   nsCOMPtr<nsISerialEventTarget> target =
2048       nsContentUtils::GetEventTargetByLoadInfo(loadInfo, TaskCategory::Network);
2049 
2050   if (!target) {
2051     return;
2052   }
2053 
2054   gNeckoChild->SetEventTargetForActor(this, target);
2055 
2056   {
2057     MutexAutoLock lock(mEventTargetMutex);
2058     mNeckoTarget = target;
2059   }
2060 }
2061 
2062 already_AddRefed<nsISerialEventTarget> HttpChannelChild::GetNeckoTarget() {
2063   nsCOMPtr<nsISerialEventTarget> target;
2064   {
2065     MutexAutoLock lock(mEventTargetMutex);
2066     target = mNeckoTarget;
2067   }
2068 
2069   if (!target) {
2070     target = GetMainThreadSerialEventTarget();
2071   }
2072   return target.forget();
2073 }
2074 
2075 already_AddRefed<nsIEventTarget> HttpChannelChild::GetODATarget() {
2076   nsCOMPtr<nsIEventTarget> target;
2077   {
2078     MutexAutoLock lock(mEventTargetMutex);
2079     if (mODATarget) {
2080       target = mODATarget;
2081     } else {
2082       target = mNeckoTarget;
2083     }
2084   }
2085 
2086   if (!target) {
2087     target = GetMainThreadEventTarget();
2088   }
2089   return target.forget();
2090 }
2091 
2092 nsresult HttpChannelChild::ContinueAsyncOpen() {
2093   nsresult rv;
2094   //
2095   // Send request to the chrome process...
2096   //
2097 
2098   mozilla::dom::BrowserChild* browserChild = nullptr;
2099   nsCOMPtr<nsIBrowserChild> iBrowserChild;
2100   GetCallback(iBrowserChild);
2101   if (iBrowserChild) {
2102     browserChild =
2103         static_cast<mozilla::dom::BrowserChild*>(iBrowserChild.get());
2104   }
2105 
2106   // This id identifies the inner window's top-level document,
2107   // which changes on every new load or navigation.
2108   uint64_t contentWindowId = 0;
2109   TimeStamp navigationStartTimeStamp;
2110   if (browserChild) {
2111     MOZ_ASSERT(browserChild->WebNavigation());
2112     if (RefPtr<Document> document = browserChild->GetTopLevelDocument()) {
2113       contentWindowId = document->InnerWindowID();
2114       nsDOMNavigationTiming* navigationTiming = document->GetNavigationTiming();
2115       if (navigationTiming) {
2116         navigationStartTimeStamp =
2117             navigationTiming->GetNavigationStartTimeStamp();
2118       }
2119     }
2120     if (BrowsingContext* bc = browserChild->GetBrowsingContext()) {
2121       mTopBrowsingContextId = bc->Top()->Id();
2122     }
2123   }
2124   SetTopLevelContentWindowId(contentWindowId);
2125 
2126   HttpChannelOpenArgs openArgs;
2127   // No access to HttpChannelOpenArgs members, but they each have a
2128   // function with the struct name that returns a ref.
2129   SerializeURI(mURI, openArgs.uri());
2130   SerializeURI(mOriginalURI, openArgs.original());
2131   SerializeURI(mDocumentURI, openArgs.doc());
2132   SerializeURI(mAPIRedirectToURI, openArgs.apiRedirectTo());
2133   openArgs.loadFlags() = mLoadFlags;
2134   openArgs.requestHeaders() = mClientSetRequestHeaders;
2135   mRequestHead.Method(openArgs.requestMethod());
2136   openArgs.preferredAlternativeTypes() = mPreferredCachedAltDataTypes.Clone();
2137   openArgs.referrerInfo() = mReferrerInfo;
2138 
2139   AutoIPCStream autoStream(openArgs.uploadStream());
2140   if (mUploadStream) {
2141     autoStream.Serialize(mUploadStream, ContentChild::GetSingleton());
2142     autoStream.TakeOptionalValue();
2143   }
2144 
2145   Maybe<CorsPreflightArgs> optionalCorsPreflightArgs;
2146   GetClientSetCorsPreflightParameters(optionalCorsPreflightArgs);
2147 
2148   // NB: This call forces us to cache mTopWindowURI if we haven't already.
2149   nsCOMPtr<nsIURI> uri;
2150   GetTopWindowURI(mURI, getter_AddRefs(uri));
2151 
2152   SerializeURI(mTopWindowURI, openArgs.topWindowURI());
2153 
2154   openArgs.preflightArgs() = optionalCorsPreflightArgs;
2155 
2156   openArgs.uploadStreamHasHeaders() = LoadUploadStreamHasHeaders();
2157   openArgs.priority() = mPriority;
2158   openArgs.classOfService() = mClassOfService;
2159   openArgs.redirectionLimit() = mRedirectionLimit;
2160   openArgs.allowSTS() = LoadAllowSTS();
2161   openArgs.thirdPartyFlags() = LoadThirdPartyFlags();
2162   openArgs.resumeAt() = mSendResumeAt;
2163   openArgs.startPos() = mStartPos;
2164   openArgs.entityID() = mEntityID;
2165   openArgs.allowSpdy() = LoadAllowSpdy();
2166   openArgs.allowHttp3() = LoadAllowHttp3();
2167   openArgs.allowAltSvc() = LoadAllowAltSvc();
2168   openArgs.beConservative() = LoadBeConservative();
2169   openArgs.tlsFlags() = mTlsFlags;
2170   openArgs.initialRwin() = mInitialRwin;
2171 
2172   openArgs.cacheKey() = mCacheKey;
2173 
2174   openArgs.blockAuthPrompt() = LoadBlockAuthPrompt();
2175 
2176   openArgs.allowStaleCacheContent() = LoadAllowStaleCacheContent();
2177   openArgs.preferCacheLoadOverBypass() = LoadPreferCacheLoadOverBypass();
2178 
2179   openArgs.contentTypeHint() = mContentTypeHint;
2180 
2181   rv = mozilla::ipc::LoadInfoToLoadInfoArgs(mLoadInfo, &openArgs.loadInfo());
2182   NS_ENSURE_SUCCESS(rv, rv);
2183 
2184   EnsureRequestContextID();
2185   openArgs.requestContextID() = mRequestContextID;
2186 
2187   openArgs.corsMode() = mCorsMode;
2188   openArgs.redirectMode() = mRedirectMode;
2189 
2190   openArgs.channelId() = mChannelId;
2191 
2192   openArgs.integrityMetadata() = mIntegrityMetadata;
2193 
2194   openArgs.contentWindowId() = contentWindowId;
2195   openArgs.topBrowsingContextId() = mTopBrowsingContextId;
2196 
2197   LOG(("HttpChannelChild::ContinueAsyncOpen this=%p gid=%" PRIu64
2198        " top bid=%" PRIx64,
2199        this, mChannelId, mTopBrowsingContextId));
2200 
2201   if (browserChild && !browserChild->IPCOpen()) {
2202     return NS_ERROR_FAILURE;
2203   }
2204 
2205   ContentChild* cc = static_cast<ContentChild*>(gNeckoChild->Manager());
2206   if (cc->IsShuttingDown()) {
2207     return NS_ERROR_FAILURE;
2208   }
2209 
2210   openArgs.launchServiceWorkerStart() = mLaunchServiceWorkerStart;
2211   openArgs.launchServiceWorkerEnd() = mLaunchServiceWorkerEnd;
2212   openArgs.dispatchFetchEventStart() = mDispatchFetchEventStart;
2213   openArgs.dispatchFetchEventEnd() = mDispatchFetchEventEnd;
2214   openArgs.handleFetchEventStart() = mHandleFetchEventStart;
2215   openArgs.handleFetchEventEnd() = mHandleFetchEventEnd;
2216 
2217   openArgs.forceMainDocumentChannel() = LoadForceMainDocumentChannel();
2218 
2219   openArgs.navigationStartTimeStamp() = navigationStartTimeStamp;
2220 
2221   // This must happen before the constructor message is sent. Otherwise messages
2222   // from the parent could arrive quickly and be delivered to the wrong event
2223   // target.
2224   SetEventTarget();
2225 
2226   if (!gNeckoChild->SendPHttpChannelConstructor(
2227           this, browserChild, IPC::SerializedLoadContext(this), openArgs)) {
2228     return NS_ERROR_FAILURE;
2229   }
2230 
2231   {
2232     MutexAutoLock lock(mBgChildMutex);
2233 
2234     MOZ_RELEASE_ASSERT(gSocketTransportService);
2235 
2236     // Service worker might use the same HttpChannelChild to do async open
2237     // twice. Need to disconnect with previous background channel before
2238     // creating the new one, to prevent receiving further notification
2239     // from it.
2240     if (mBgChild) {
2241       RefPtr<HttpBackgroundChannelChild> prevBgChild = std::move(mBgChild);
2242       gSocketTransportService->Dispatch(
2243           NewRunnableMethod("HttpBackgroundChannelChild::OnChannelClosed",
2244                             prevBgChild,
2245                             &HttpBackgroundChannelChild::OnChannelClosed),
2246           NS_DISPATCH_NORMAL);
2247     }
2248 
2249     MOZ_ASSERT(!mBgInitFailCallback);
2250 
2251     mBgInitFailCallback = NewRunnableMethod<nsresult>(
2252         "HttpChannelChild::FailedAsyncOpen", this,
2253         &HttpChannelChild::FailedAsyncOpen, NS_ERROR_FAILURE);
2254 
2255     RefPtr<HttpBackgroundChannelChild> bgChild =
2256         new HttpBackgroundChannelChild();
2257 
2258     RefPtr<HttpChannelChild> self = this;
2259     nsresult rv = gSocketTransportService->Dispatch(
2260         NewRunnableMethod<RefPtr<HttpChannelChild>>(
2261             "HttpBackgroundChannelChild::Init", bgChild,
2262             &HttpBackgroundChannelChild::Init, self),
2263         NS_DISPATCH_NORMAL);
2264 
2265     if (NS_WARN_IF(NS_FAILED(rv))) {
2266       return rv;
2267     }
2268 
2269     mBgChild = std::move(bgChild);
2270 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
2271     mEverHadBgChildAtAsyncOpen = true;
2272 #endif
2273   }
2274 
2275   MaybeConnectToSocketProcess();
2276 
2277   return NS_OK;
2278 }
2279 
2280 //-----------------------------------------------------------------------------
2281 // HttpChannelChild::nsIHttpChannel
2282 //-----------------------------------------------------------------------------
2283 
2284 NS_IMETHODIMP
2285 HttpChannelChild::SetRequestHeader(const nsACString& aHeader,
2286                                    const nsACString& aValue, bool aMerge) {
2287   LOG(("HttpChannelChild::SetRequestHeader [this=%p]\n", this));
2288   nsresult rv = HttpBaseChannel::SetRequestHeader(aHeader, aValue, aMerge);
2289   if (NS_FAILED(rv)) return rv;
2290 
2291   RequestHeaderTuple* tuple = mClientSetRequestHeaders.AppendElement();
2292   if (!tuple) return NS_ERROR_OUT_OF_MEMORY;
2293 
2294   tuple->mHeader = aHeader;
2295   tuple->mValue = aValue;
2296   tuple->mMerge = aMerge;
2297   tuple->mEmpty = false;
2298   return NS_OK;
2299 }
2300 
2301 NS_IMETHODIMP
2302 HttpChannelChild::SetEmptyRequestHeader(const nsACString& aHeader) {
2303   LOG(("HttpChannelChild::SetEmptyRequestHeader [this=%p]\n", this));
2304   nsresult rv = HttpBaseChannel::SetEmptyRequestHeader(aHeader);
2305   if (NS_FAILED(rv)) return rv;
2306 
2307   RequestHeaderTuple* tuple = mClientSetRequestHeaders.AppendElement();
2308   if (!tuple) return NS_ERROR_OUT_OF_MEMORY;
2309 
2310   tuple->mHeader = aHeader;
2311   tuple->mMerge = false;
2312   tuple->mEmpty = true;
2313   return NS_OK;
2314 }
2315 
2316 NS_IMETHODIMP
2317 HttpChannelChild::RedirectTo(nsIURI* newURI) {
2318   // disabled until/unless addons run in child or something else needs this
2319   return NS_ERROR_NOT_IMPLEMENTED;
2320 }
2321 
2322 NS_IMETHODIMP
2323 HttpChannelChild::UpgradeToSecure() {
2324   // disabled until/unless addons run in child or something else needs this
2325   return NS_ERROR_NOT_IMPLEMENTED;
2326 }
2327 
2328 NS_IMETHODIMP
2329 HttpChannelChild::GetProtocolVersion(nsACString& aProtocolVersion) {
2330   aProtocolVersion = mProtocolVersion;
2331   return NS_OK;
2332 }
2333 
2334 //-----------------------------------------------------------------------------
2335 // HttpChannelChild::nsIHttpChannelInternal
2336 //-----------------------------------------------------------------------------
2337 
2338 NS_IMETHODIMP
2339 HttpChannelChild::GetIsAuthChannel(bool* aIsAuthChannel) { DROP_DEAD(); }
2340 
2341 //-----------------------------------------------------------------------------
2342 // HttpChannelChild::nsICacheInfoChannel
2343 //-----------------------------------------------------------------------------
2344 
2345 NS_IMETHODIMP
2346 HttpChannelChild::GetCacheTokenFetchCount(int32_t* _retval) {
2347   NS_ENSURE_ARG_POINTER(_retval);
2348   MOZ_ASSERT(NS_IsMainThread());
2349 
2350   if (!mCacheEntryAvailable && !mAltDataCacheEntryAvailable) {
2351     return NS_ERROR_NOT_AVAILABLE;
2352   }
2353 
2354   *_retval = mCacheFetchCount;
2355   return NS_OK;
2356 }
2357 
2358 NS_IMETHODIMP
2359 HttpChannelChild::GetCacheTokenExpirationTime(uint32_t* _retval) {
2360   NS_ENSURE_ARG_POINTER(_retval);
2361   MOZ_ASSERT(NS_IsMainThread());
2362 
2363   if (!mCacheEntryAvailable) return NS_ERROR_NOT_AVAILABLE;
2364 
2365   *_retval = mCacheExpirationTime;
2366   return NS_OK;
2367 }
2368 
2369 NS_IMETHODIMP
2370 HttpChannelChild::IsFromCache(bool* value) {
2371   if (!LoadIsPending()) return NS_ERROR_NOT_AVAILABLE;
2372 
2373   *value = mIsFromCache;
2374   return NS_OK;
2375 }
2376 
2377 NS_IMETHODIMP
2378 HttpChannelChild::GetCacheEntryId(uint64_t* aCacheEntryId) {
2379   bool fromCache = false;
2380   if (NS_FAILED(IsFromCache(&fromCache)) || !fromCache ||
2381       !mCacheEntryAvailable) {
2382     return NS_ERROR_NOT_AVAILABLE;
2383   }
2384 
2385   *aCacheEntryId = mCacheEntryId;
2386   return NS_OK;
2387 }
2388 
2389 NS_IMETHODIMP
2390 HttpChannelChild::IsRacing(bool* aIsRacing) {
2391   if (!LoadAfterOnStartRequestBegun()) {
2392     return NS_ERROR_NOT_AVAILABLE;
2393   }
2394   *aIsRacing = mIsRacing;
2395   return NS_OK;
2396 }
2397 
2398 NS_IMETHODIMP
2399 HttpChannelChild::GetCacheKey(uint32_t* cacheKey) {
2400   MOZ_ASSERT(NS_IsMainThread());
2401 
2402   *cacheKey = mCacheKey;
2403   return NS_OK;
2404 }
2405 NS_IMETHODIMP
2406 HttpChannelChild::SetCacheKey(uint32_t cacheKey) {
2407   ENSURE_CALLED_BEFORE_ASYNC_OPEN();
2408 
2409   mCacheKey = cacheKey;
2410   return NS_OK;
2411 }
2412 
2413 NS_IMETHODIMP
2414 HttpChannelChild::SetAllowStaleCacheContent(bool aAllowStaleCacheContent) {
2415   StoreAllowStaleCacheContent(aAllowStaleCacheContent);
2416   return NS_OK;
2417 }
2418 NS_IMETHODIMP
2419 HttpChannelChild::GetAllowStaleCacheContent(bool* aAllowStaleCacheContent) {
2420   NS_ENSURE_ARG(aAllowStaleCacheContent);
2421   *aAllowStaleCacheContent = LoadAllowStaleCacheContent();
2422   return NS_OK;
2423 }
2424 
2425 NS_IMETHODIMP
2426 HttpChannelChild::SetPreferCacheLoadOverBypass(
2427     bool aPreferCacheLoadOverBypass) {
2428   StorePreferCacheLoadOverBypass(aPreferCacheLoadOverBypass);
2429   return NS_OK;
2430 }
2431 NS_IMETHODIMP
2432 HttpChannelChild::GetPreferCacheLoadOverBypass(
2433     bool* aPreferCacheLoadOverBypass) {
2434   NS_ENSURE_ARG(aPreferCacheLoadOverBypass);
2435   *aPreferCacheLoadOverBypass = LoadPreferCacheLoadOverBypass();
2436   return NS_OK;
2437 }
2438 
2439 NS_IMETHODIMP
2440 HttpChannelChild::PreferAlternativeDataType(const nsACString& aType,
2441                                             const nsACString& aContentType,
2442                                             bool aDeliverAltData) {
2443   ENSURE_CALLED_BEFORE_ASYNC_OPEN();
2444 
2445   mPreferredCachedAltDataTypes.AppendElement(PreferredAlternativeDataTypeParams(
2446       nsCString(aType), nsCString(aContentType), aDeliverAltData));
2447   return NS_OK;
2448 }
2449 
2450 const nsTArray<PreferredAlternativeDataTypeParams>&
2451 HttpChannelChild::PreferredAlternativeDataTypes() {
2452   return mPreferredCachedAltDataTypes;
2453 }
2454 
2455 NS_IMETHODIMP
2456 HttpChannelChild::GetAlternativeDataType(nsACString& aType) {
2457   // Must be called during or after OnStartRequest
2458   if (!LoadAfterOnStartRequestBegun()) {
2459     return NS_ERROR_NOT_AVAILABLE;
2460   }
2461 
2462   aType = mAvailableCachedAltDataType;
2463   return NS_OK;
2464 }
2465 
2466 NS_IMETHODIMP
2467 HttpChannelChild::OpenAlternativeOutputStream(const nsACString& aType,
2468                                               int64_t aPredictedSize,
2469                                               nsIAsyncOutputStream** _retval) {
2470   MOZ_ASSERT(NS_IsMainThread(), "Main thread only");
2471 
2472   if (!CanSend()) {
2473     return NS_ERROR_NOT_AVAILABLE;
2474   }
2475   if (static_cast<ContentChild*>(gNeckoChild->Manager())->IsShuttingDown()) {
2476     return NS_ERROR_NOT_AVAILABLE;
2477   }
2478 
2479   nsCOMPtr<nsISerialEventTarget> neckoTarget = GetNeckoTarget();
2480   MOZ_ASSERT(neckoTarget);
2481 
2482   RefPtr<AltDataOutputStreamChild> stream = new AltDataOutputStreamChild();
2483   stream->AddIPDLReference();
2484 
2485   gNeckoChild->SetEventTargetForActor(stream, neckoTarget);
2486 
2487   if (!gNeckoChild->SendPAltDataOutputStreamConstructor(
2488           stream, nsCString(aType), aPredictedSize, this)) {
2489     return NS_ERROR_FAILURE;
2490   }
2491 
2492   stream.forget(_retval);
2493   return NS_OK;
2494 }
2495 
2496 NS_IMETHODIMP
2497 HttpChannelChild::GetOriginalInputStream(nsIInputStreamReceiver* aReceiver) {
2498   if (aReceiver == nullptr) {
2499     return NS_ERROR_INVALID_ARG;
2500   }
2501 
2502   if (!CanSend()) {
2503     return NS_ERROR_NOT_AVAILABLE;
2504   }
2505 
2506   mOriginalInputStreamReceiver = aReceiver;
2507   Unused << SendOpenOriginalCacheInputStream();
2508 
2509   return NS_OK;
2510 }
2511 
2512 NS_IMETHODIMP
2513 HttpChannelChild::GetAltDataInputStream(const nsACString& aType,
2514                                         nsIInputStreamReceiver* aReceiver) {
2515   if (aReceiver == nullptr) {
2516     return NS_ERROR_INVALID_ARG;
2517   }
2518 
2519   if (!CanSend()) {
2520     return NS_ERROR_NOT_AVAILABLE;
2521   }
2522 
2523   mAltDataInputStreamReceiver = aReceiver;
2524   Unused << SendOpenAltDataCacheInputStream(nsCString(aType));
2525 
2526   return NS_OK;
2527 }
2528 
2529 mozilla::ipc::IPCResult HttpChannelChild::RecvOriginalCacheInputStreamAvailable(
2530     const Maybe<IPCStream>& aStream) {
2531   nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(aStream);
2532   nsCOMPtr<nsIInputStreamReceiver> receiver;
2533   receiver.swap(mOriginalInputStreamReceiver);
2534   if (receiver) {
2535     receiver->OnInputStreamReady(stream);
2536   }
2537 
2538   return IPC_OK();
2539 }
2540 
2541 mozilla::ipc::IPCResult HttpChannelChild::RecvAltDataCacheInputStreamAvailable(
2542     const Maybe<IPCStream>& aStream) {
2543   nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(aStream);
2544   nsCOMPtr<nsIInputStreamReceiver> receiver;
2545   receiver.swap(mAltDataInputStreamReceiver);
2546   if (receiver) {
2547     receiver->OnInputStreamReady(stream);
2548   }
2549 
2550   return IPC_OK();
2551 }
2552 
2553 //-----------------------------------------------------------------------------
2554 // HttpChannelChild::nsIResumableChannel
2555 //-----------------------------------------------------------------------------
2556 
2557 NS_IMETHODIMP
2558 HttpChannelChild::ResumeAt(uint64_t startPos, const nsACString& entityID) {
2559   LOG(("HttpChannelChild::ResumeAt [this=%p]\n", this));
2560   ENSURE_CALLED_BEFORE_CONNECT();
2561   mStartPos = startPos;
2562   mEntityID = entityID;
2563   mSendResumeAt = true;
2564   return NS_OK;
2565 }
2566 
2567 // GetEntityID is shared in HttpBaseChannel
2568 
2569 //-----------------------------------------------------------------------------
2570 // HttpChannelChild::nsISupportsPriority
2571 //-----------------------------------------------------------------------------
2572 
2573 NS_IMETHODIMP
2574 HttpChannelChild::SetPriority(int32_t aPriority) {
2575   LOG(("HttpChannelChild::SetPriority %p p=%d", this, aPriority));
2576 
2577   int16_t newValue = clamped<int32_t>(aPriority, INT16_MIN, INT16_MAX);
2578   if (mPriority == newValue) return NS_OK;
2579   mPriority = newValue;
2580   if (RemoteChannelExists()) SendSetPriority(mPriority);
2581   return NS_OK;
2582 }
2583 
2584 //-----------------------------------------------------------------------------
2585 // HttpChannelChild::nsIClassOfService
2586 //-----------------------------------------------------------------------------
2587 NS_IMETHODIMP
2588 HttpChannelChild::SetClassFlags(uint32_t inFlags) {
2589   if (mClassOfService == inFlags) {
2590     return NS_OK;
2591   }
2592 
2593   mClassOfService = inFlags;
2594 
2595   LOG(("HttpChannelChild %p ClassOfService=%u", this, mClassOfService));
2596 
2597   if (RemoteChannelExists()) {
2598     SendSetClassOfService(mClassOfService);
2599   }
2600   return NS_OK;
2601 }
2602 
2603 NS_IMETHODIMP
2604 HttpChannelChild::AddClassFlags(uint32_t inFlags) {
2605   mClassOfService |= inFlags;
2606 
2607   LOG(("HttpChannelChild %p ClassOfService=%u", this, mClassOfService));
2608 
2609   if (RemoteChannelExists()) {
2610     SendSetClassOfService(mClassOfService);
2611   }
2612   return NS_OK;
2613 }
2614 
2615 NS_IMETHODIMP
2616 HttpChannelChild::ClearClassFlags(uint32_t inFlags) {
2617   mClassOfService &= ~inFlags;
2618 
2619   LOG(("HttpChannelChild %p ClassOfService=%u", this, mClassOfService));
2620 
2621   if (RemoteChannelExists()) {
2622     SendSetClassOfService(mClassOfService);
2623   }
2624   return NS_OK;
2625 }
2626 
2627 //-----------------------------------------------------------------------------
2628 // HttpChannelChild::nsIProxiedChannel
2629 //-----------------------------------------------------------------------------
2630 
2631 NS_IMETHODIMP
2632 HttpChannelChild::GetProxyInfo(nsIProxyInfo** aProxyInfo) { DROP_DEAD(); }
2633 
2634 NS_IMETHODIMP HttpChannelChild::GetHttpProxyConnectResponseCode(
2635     int32_t* aResponseCode) {
2636   DROP_DEAD();
2637 }
2638 
2639 //-----------------------------------------------------------------------------
2640 // HttpChannelChild::nsIHttpChannelChild
2641 //-----------------------------------------------------------------------------
2642 
2643 NS_IMETHODIMP HttpChannelChild::AddCookiesToRequest() {
2644   HttpBaseChannel::AddCookiesToRequest();
2645   return NS_OK;
2646 }
2647 
2648 NS_IMETHODIMP HttpChannelChild::GetClientSetRequestHeaders(
2649     RequestHeaderTuples** aRequestHeaders) {
2650   *aRequestHeaders = &mClientSetRequestHeaders;
2651   return NS_OK;
2652 }
2653 
2654 void HttpChannelChild::GetClientSetCorsPreflightParameters(
2655     Maybe<CorsPreflightArgs>& aArgs) {
2656   if (LoadRequireCORSPreflight()) {
2657     CorsPreflightArgs args;
2658     args.unsafeHeaders() = mUnsafeHeaders.Clone();
2659     aArgs.emplace(args);
2660   } else {
2661     aArgs = Nothing();
2662   }
2663 }
2664 
2665 NS_IMETHODIMP
2666 HttpChannelChild::RemoveCorsPreflightCacheEntry(
2667     nsIURI* aURI, nsIPrincipal* aPrincipal,
2668     const OriginAttributes& aOriginAttributes) {
2669   URIParams uri;
2670   SerializeURI(aURI, uri);
2671   PrincipalInfo principalInfo;
2672   nsresult rv = PrincipalToPrincipalInfo(aPrincipal, &principalInfo);
2673   if (NS_WARN_IF(NS_FAILED(rv))) {
2674     return rv;
2675   }
2676   bool result = false;
2677   // Be careful to not attempt to send a message to the parent after the
2678   // actor has been destroyed.
2679   if (CanSend()) {
2680     result = SendRemoveCorsPreflightCacheEntry(uri, principalInfo,
2681                                                aOriginAttributes);
2682   }
2683   return result ? NS_OK : NS_ERROR_FAILURE;
2684 }
2685 
2686 //-----------------------------------------------------------------------------
2687 // HttpChannelChild::nsIMuliPartChannel
2688 //-----------------------------------------------------------------------------
2689 
2690 NS_IMETHODIMP
2691 HttpChannelChild::GetBaseChannel(nsIChannel** aBaseChannel) {
2692   if (!mMultiPartID) {
2693     MOZ_ASSERT(false, "Not a multipart channel");
2694     return NS_ERROR_NOT_AVAILABLE;
2695   }
2696   nsCOMPtr<nsIChannel> channel = this;
2697   channel.forget(aBaseChannel);
2698   return NS_OK;
2699 }
2700 
2701 NS_IMETHODIMP
2702 HttpChannelChild::GetPartID(uint32_t* aPartID) {
2703   if (!mMultiPartID) {
2704     MOZ_ASSERT(false, "Not a multipart channel");
2705     return NS_ERROR_NOT_AVAILABLE;
2706   }
2707   *aPartID = *mMultiPartID;
2708   return NS_OK;
2709 }
2710 
2711 NS_IMETHODIMP
2712 HttpChannelChild::GetIsLastPart(bool* aIsLastPart) {
2713   if (!mMultiPartID) {
2714     return NS_ERROR_NOT_AVAILABLE;
2715   }
2716   *aIsLastPart = mIsLastPartOfMultiPart;
2717   return NS_OK;
2718 }
2719 
2720 //-----------------------------------------------------------------------------
2721 // HttpChannelChild::nsIThreadRetargetableRequest
2722 //-----------------------------------------------------------------------------
2723 
2724 NS_IMETHODIMP
2725 HttpChannelChild::RetargetDeliveryTo(nsIEventTarget* aNewTarget) {
2726   LOG(("HttpChannelChild::RetargetDeliveryTo [this=%p, aNewTarget=%p]", this,
2727        aNewTarget));
2728 
2729   MOZ_ASSERT(NS_IsMainThread(), "Should be called on main thread only");
2730   MOZ_ASSERT(!mODATarget);
2731   MOZ_ASSERT(aNewTarget);
2732 
2733   NS_ENSURE_ARG(aNewTarget);
2734   if (aNewTarget->IsOnCurrentThread()) {
2735     NS_WARNING("Retargeting delivery to same thread");
2736     mOMTResult = LABELS_HTTP_CHILD_OMT_STATS::successMainThread;
2737     return NS_OK;
2738   }
2739 
2740   if (mMultiPartID) {
2741     // TODO: Maybe add a new label for this? Maybe it doesn't
2742     // matter though, since we also blocked QI, so we shouldn't
2743     // ever get here.
2744     mOMTResult = LABELS_HTTP_CHILD_OMT_STATS::failListener;
2745     return NS_ERROR_NO_INTERFACE;
2746   }
2747 
2748   // Ensure that |mListener| and any subsequent listeners can be retargeted
2749   // to another thread.
2750   nsresult rv = NS_OK;
2751   nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener =
2752       do_QueryInterface(mListener, &rv);
2753   if (!retargetableListener || NS_FAILED(rv)) {
2754     NS_WARNING("Listener is not retargetable");
2755     mOMTResult = LABELS_HTTP_CHILD_OMT_STATS::failListener;
2756     return NS_ERROR_NO_INTERFACE;
2757   }
2758 
2759   rv = retargetableListener->CheckListenerChain();
2760   if (NS_FAILED(rv)) {
2761     NS_WARNING("Subsequent listeners are not retargetable");
2762     mOMTResult = LABELS_HTTP_CHILD_OMT_STATS::failListenerChain;
2763     return rv;
2764   }
2765 
2766   {
2767     MutexAutoLock lock(mEventTargetMutex);
2768     mODATarget = aNewTarget;
2769   }
2770 
2771   mOMTResult = LABELS_HTTP_CHILD_OMT_STATS::success;
2772   return NS_OK;
2773 }
2774 
2775 NS_IMETHODIMP
2776 HttpChannelChild::GetDeliveryTarget(nsIEventTarget** aEventTarget) {
2777   MutexAutoLock lock(mEventTargetMutex);
2778 
2779   nsCOMPtr<nsIEventTarget> target = mODATarget;
2780   if (!mODATarget) {
2781     target = GetCurrentEventTarget();
2782   }
2783   target.forget(aEventTarget);
2784   return NS_OK;
2785 }
2786 
2787 void HttpChannelChild::TrySendDeletingChannel() {
2788   AUTO_PROFILER_LABEL("HttpChannelChild::TrySendDeletingChannel", NETWORK);
2789   if (!mDeletingChannelSent.compareExchange(false, true)) {
2790     // SendDeletingChannel is already sent.
2791     return;
2792   }
2793 
2794   if (NS_IsMainThread()) {
2795     if (NS_WARN_IF(!CanSend())) {
2796       // IPC actor is destroyed already, do not send more messages.
2797       return;
2798     }
2799 
2800     Unused << PHttpChannelChild::SendDeletingChannel();
2801     return;
2802   }
2803 
2804   nsCOMPtr<nsISerialEventTarget> neckoTarget = GetNeckoTarget();
2805   MOZ_ASSERT(neckoTarget);
2806 
2807   DebugOnly<nsresult> rv = neckoTarget->Dispatch(
2808       NewNonOwningRunnableMethod(
2809           "net::HttpChannelChild::TrySendDeletingChannel", this,
2810           &HttpChannelChild::TrySendDeletingChannel),
2811       NS_DISPATCH_NORMAL);
2812   MOZ_ASSERT(NS_SUCCEEDED(rv));
2813 }
2814 
2815 void HttpChannelChild::OnCopyComplete(nsresult aStatus) {
2816   nsCOMPtr<nsIRunnable> runnable = NewRunnableMethod<nsresult>(
2817       "net::HttpBaseChannel::EnsureUploadStreamIsCloneableComplete", this,
2818       &HttpChannelChild::EnsureUploadStreamIsCloneableComplete, aStatus);
2819   nsCOMPtr<nsISerialEventTarget> neckoTarget = GetNeckoTarget();
2820   MOZ_ASSERT(neckoTarget);
2821 
2822   Unused << neckoTarget->Dispatch(runnable, NS_DISPATCH_NORMAL);
2823 }
2824 
2825 nsresult HttpChannelChild::AsyncCallImpl(
2826     void (HttpChannelChild::*funcPtr)(),
2827     nsRunnableMethod<HttpChannelChild>** retval) {
2828   nsresult rv;
2829 
2830   RefPtr<nsRunnableMethod<HttpChannelChild>> event =
2831       NewRunnableMethod("net::HttpChannelChild::AsyncCall", this, funcPtr);
2832   nsCOMPtr<nsISerialEventTarget> neckoTarget = GetNeckoTarget();
2833   MOZ_ASSERT(neckoTarget);
2834 
2835   rv = neckoTarget->Dispatch(event, NS_DISPATCH_NORMAL);
2836 
2837   if (NS_SUCCEEDED(rv) && retval) {
2838     *retval = event;
2839   }
2840 
2841   return rv;
2842 }
2843 
2844 nsresult HttpChannelChild::SetReferrerHeader(const nsACString& aReferrer,
2845                                              bool aRespectBeforeConnect) {
2846   // Normally this would be ENSURE_CALLED_BEFORE_CONNECT, but since the
2847   // "connect" is done in the main process, and LoadRequestObserversCalled() is
2848   // never set in the ChannelChild, before connect basically means before
2849   // asyncOpen.
2850   if (aRespectBeforeConnect) {
2851     ENSURE_CALLED_BEFORE_ASYNC_OPEN();
2852   }
2853 
2854   // remove old referrer if any
2855   mClientSetRequestHeaders.RemoveElementsBy(
2856       [](const auto& header) { return "Referer"_ns.Equals(header.mHeader); });
2857 
2858   return HttpBaseChannel::SetReferrerHeader(aReferrer, aRespectBeforeConnect);
2859 }
2860 
2861 void HttpChannelChild::CancelOnMainThread(nsresult aRv) {
2862   LOG(("HttpChannelChild::CancelOnMainThread [this=%p]", this));
2863 
2864   if (NS_IsMainThread()) {
2865     Cancel(aRv);
2866     return;
2867   }
2868 
2869   mEventQ->Suspend();
2870   // Cancel is expected to preempt any other channel events, thus we put this
2871   // event in the front of mEventQ to make sure nsIStreamListener not receiving
2872   // any ODA/OnStopRequest callbacks.
2873   mEventQ->PrependEvent(MakeUnique<NeckoTargetChannelFunctionEvent>(
2874       this, [self = UnsafePtr<HttpChannelChild>(this), aRv]() {
2875         self->Cancel(aRv);
2876       }));
2877   mEventQ->Resume();
2878 }
2879 
2880 mozilla::ipc::IPCResult HttpChannelChild::RecvIssueDeprecationWarning(
2881     const uint32_t& warning, const bool& asError) {
2882   nsCOMPtr<nsIDeprecationWarner> warner;
2883   GetCallback(warner);
2884   if (warner) {
2885     warner->IssueWarning(warning, asError);
2886   }
2887   return IPC_OK();
2888 }
2889 
2890 mozilla::ipc::IPCResult HttpChannelChild::RecvSetPriority(
2891     const int16_t& aPriority) {
2892   mPriority = aPriority;
2893   return IPC_OK();
2894 }
2895 
2896 // We don't have a copyable Endpoint and NeckoTargetChannelFunctionEvent takes
2897 // std::function<void()>.  It's not possible to avoid the copy from the type of
2898 // lambda to std::function, so does the capture list. Hence, we're forced to
2899 // use the old-fashioned channel event inheritance.
2900 class AttachStreamFilterEvent : public ChannelEvent {
2901  public:
2902   AttachStreamFilterEvent(HttpChannelChild* aChild,
2903                           already_AddRefed<nsIEventTarget> aTarget,
2904                           Endpoint<extensions::PStreamFilterParent>&& aEndpoint)
2905       : mChild(aChild), mTarget(aTarget), mEndpoint(std::move(aEndpoint)) {}
2906 
2907   already_AddRefed<nsIEventTarget> GetEventTarget() override {
2908     nsCOMPtr<nsIEventTarget> target = mTarget;
2909     return target.forget();
2910   }
2911 
2912   void Run() override {
2913     extensions::StreamFilterParent::Attach(mChild, std::move(mEndpoint));
2914   }
2915 
2916  private:
2917   HttpChannelChild* mChild;
2918   nsCOMPtr<nsIEventTarget> mTarget;
2919   Endpoint<extensions::PStreamFilterParent> mEndpoint;
2920 };
2921 
2922 void HttpChannelChild::ProcessAttachStreamFilter(
2923     Endpoint<extensions::PStreamFilterParent>&& aEndpoint) {
2924   LOG(("HttpChannelChild::ProcessAttachStreamFilter [this=%p]\n", this));
2925   MOZ_ASSERT(OnSocketThread());
2926 
2927   mEventQ->RunOrEnqueue(new AttachStreamFilterEvent(this, GetNeckoTarget(),
2928                                                     std::move(aEndpoint)));
2929 }
2930 
2931 void HttpChannelChild::ActorDestroy(ActorDestroyReason aWhy) {
2932   MOZ_ASSERT(NS_IsMainThread());
2933 
2934 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
2935   mActorDestroyReason.emplace(aWhy);
2936 #endif
2937 
2938   // OnStartRequest might be dropped if IPDL is destroyed abnormally
2939   // and BackgroundChild might have pending IPC messages.
2940   // Clean up BackgroundChild at this time to prevent memleak.
2941   if (aWhy != Deletion) {
2942     // Make sure all the messages are processed.
2943     AutoEventEnqueuer ensureSerialDispatch(mEventQ);
2944 
2945     mStatus = NS_ERROR_DOCSHELL_DYING;
2946     HandleAsyncAbort();
2947 
2948     // Cleanup the background channel before we resume the eventQ so we don't
2949     // get any other events.
2950     CleanupBackgroundChannel();
2951 
2952     mIPCActorDeleted = true;
2953     mCanceled = true;
2954   }
2955 }
2956 
2957 mozilla::ipc::IPCResult HttpChannelChild::RecvLogBlockedCORSRequest(
2958     const nsString& aMessage, const nsCString& aCategory) {
2959   Unused << LogBlockedCORSRequest(aMessage, aCategory);
2960   return IPC_OK();
2961 }
2962 
2963 NS_IMETHODIMP
2964 HttpChannelChild::LogBlockedCORSRequest(const nsAString& aMessage,
2965                                         const nsACString& aCategory) {
2966   uint64_t innerWindowID = mLoadInfo->GetInnerWindowID();
2967   bool privateBrowsing = !!mLoadInfo->GetOriginAttributes().mPrivateBrowsingId;
2968   bool fromChromeContext =
2969       mLoadInfo->TriggeringPrincipal()->IsSystemPrincipal();
2970   nsCORSListenerProxy::LogBlockedCORSRequest(
2971       innerWindowID, privateBrowsing, fromChromeContext, aMessage, aCategory);
2972   return NS_OK;
2973 }
2974 
2975 mozilla::ipc::IPCResult HttpChannelChild::RecvLogMimeTypeMismatch(
2976     const nsCString& aMessageName, const bool& aWarning, const nsString& aURL,
2977     const nsString& aContentType) {
2978   Unused << LogMimeTypeMismatch(aMessageName, aWarning, aURL, aContentType);
2979   return IPC_OK();
2980 }
2981 
2982 NS_IMETHODIMP
2983 HttpChannelChild::LogMimeTypeMismatch(const nsACString& aMessageName,
2984                                       bool aWarning, const nsAString& aURL,
2985                                       const nsAString& aContentType) {
2986   RefPtr<Document> doc;
2987   mLoadInfo->GetLoadingDocument(getter_AddRefs(doc));
2988 
2989   AutoTArray<nsString, 2> params;
2990   params.AppendElement(aURL);
2991   params.AppendElement(aContentType);
2992   nsContentUtils::ReportToConsole(
2993       aWarning ? nsIScriptError::warningFlag : nsIScriptError::errorFlag,
2994       "MIMEMISMATCH"_ns, doc, nsContentUtils::eSECURITY_PROPERTIES,
2995       nsCString(aMessageName).get(), params);
2996   return NS_OK;
2997 }
2998 
2999 nsresult HttpChannelChild::CrossProcessRedirectFinished(nsresult aStatus) {
3000   if (!CanSend()) {
3001     return NS_BINDING_FAILED;
3002   }
3003 
3004   if (!mCanceled && NS_SUCCEEDED(mStatus)) {
3005     mStatus = aStatus;
3006   }
3007 
3008   return mStatus;
3009 }
3010 
3011 void HttpChannelChild::DoDiagnosticAssertWhenOnStopNotCalledOnDestroy() {
3012 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
3013   mDoDiagnosticAssertWhenOnStopNotCalledOnDestroy = true;
3014 #endif
3015 }
3016 
3017 void HttpChannelChild::MaybeConnectToSocketProcess() {
3018   if (!nsIOService::UseSocketProcess()) {
3019     return;
3020   }
3021 
3022   if (!StaticPrefs::network_send_ODA_to_content_directly()) {
3023     return;
3024   }
3025 
3026   RefPtr<HttpBackgroundChannelChild> bgChild = mBgChild;
3027   SocketProcessBridgeChild::GetSocketProcessBridge()->Then(
3028       GetCurrentSerialEventTarget(), __func__,
3029       [bgChild]() {
3030         gSocketTransportService->Dispatch(
3031             NewRunnableMethod("HttpBackgroundChannelChild::CreateDataBridge",
3032                               bgChild,
3033                               &HttpBackgroundChannelChild::CreateDataBridge),
3034             NS_DISPATCH_NORMAL);
3035       },
3036       []() { NS_WARNING("Failed to create SocketProcessBridgeChild"); });
3037 }
3038 
3039 }  // namespace net
3040 }  // namespace mozilla
3041