1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=8 et tw=80 : */
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/. */
8 // HttpLog.h should generally be included first
11 #include "mozilla/net/PBackgroundDataBridge.h"
13 #include "nsICacheEntry.h"
14 #include "mozilla/BasePrincipal.h"
15 #include "mozilla/PerfStats.h"
16 #include "mozilla/Unused.h"
17 #include "mozilla/dom/ContentChild.h"
18 #include "mozilla/dom/DocGroup.h"
19 #include "mozilla/dom/ServiceWorkerUtils.h"
20 #include "mozilla/dom/BrowserChild.h"
21 #include "mozilla/dom/LinkStyle.h"
22 #include "mozilla/extensions/StreamFilterParent.h"
23 #include "mozilla/ipc/IPCStreamUtils.h"
24 #include "mozilla/net/NeckoChild.h"
25 #include "mozilla/net/HttpChannelChild.h"
26 #include "mozilla/net/UrlClassifierCommon.h"
27 #include "mozilla/net/UrlClassifierFeatureFactory.h"
29 #include "AltDataOutputStreamChild.h"
30 #include "CookieServiceChild.h"
31 #include "HttpBackgroundChannelChild.h"
32 #include "NetworkMarker.h"
34 #include "nsContentPolicyUtils.h"
35 #include "nsDOMNavigationTiming.h"
36 #include "nsIThreadRetargetableStreamListener.h"
37 #include "nsStringStream.h"
38 #include "nsHttpChannel.h"
39 #include "nsHttpHandler.h"
40 #include "nsQueryObject.h"
41 #include "nsNetUtil.h"
42 #include "nsSerializationHelper.h"
43 #include "mozilla/Attributes.h"
44 #include "mozilla/Telemetry.h"
45 #include "mozilla/dom/PerformanceStorage.h"
46 #include "mozilla/ipc/InputStreamUtils.h"
47 #include "mozilla/ipc/URIUtils.h"
48 #include "mozilla/ipc/BackgroundUtils.h"
49 #include "mozilla/net/DNS.h"
50 #include "mozilla/net/SocketProcessBridgeChild.h"
51 #include "mozilla/ScopeExit.h"
52 #include "mozilla/StaticPrefs_network.h"
53 #include "mozilla/StoragePrincipalHelper.h"
54 #include "SerializedLoadContext.h"
55 #include "nsInputStreamPump.h"
56 #include "nsContentSecurityManager.h"
57 #include "nsICompressConvStats.h"
58 #include "mozilla/dom/Document.h"
59 #include "nsIScriptError.h"
60 #include "nsISerialEventTarget.h"
61 #include "nsRedirectHistoryEntry.h"
62 #include "nsSocketTransportService2.h"
63 #include "nsStreamUtils.h"
64 #include "nsThreadUtils.h"
65 #include "nsCORSListenerProxy.h"
66 #include "nsIOService.h"
70 using namespace mozilla::dom
;
71 using namespace mozilla::ipc
;
73 namespace mozilla::net
{
75 //-----------------------------------------------------------------------------
77 //-----------------------------------------------------------------------------
79 HttpChannelChild::HttpChannelChild()
80 : HttpAsyncAborter
<HttpChannelChild
>(this),
81 NeckoTargetHolder(nullptr),
82 mCacheEntryAvailable(false),
83 mAltDataCacheEntryAvailable(false),
86 mIPCActorDeleted(false),
88 mIsFirstPartOfMultiPart(false),
89 mIsLastPartOfMultiPart(false),
90 mSuspendForWaitCompleteRedirectSetup(false),
91 mRecvOnStartRequestSentCalled(false),
92 mSuspendedByWaitingForPermissionCookie(false) {
93 LOG(("Creating HttpChannelChild @%p\n", this));
95 mChannelCreationTime
= PR_Now();
96 mChannelCreationTimestamp
= TimeStamp::Now();
98 mChannelCreationTimestamp
; // in case we enable the profiler after Init()
99 mAsyncOpenTime
= TimeStamp::Now();
100 mEventQ
= new ChannelEventQueue(static_cast<nsIHttpChannel
*>(this));
102 // Ensure that the cookie service is initialized before the first
103 // IPC HTTP channel is created.
104 // We require that the parent cookie service actor exists while
105 // processing HTTP responses.
106 RefPtr
<CookieServiceChild
> cookieService
= CookieServiceChild::GetSingleton();
109 HttpChannelChild::~HttpChannelChild() {
110 LOG(("Destroying HttpChannelChild @%p\n", this));
112 // See HttpChannelChild::Release, HttpChannelChild should be always destroyed
113 // on the main thread.
114 MOZ_RELEASE_ASSERT(NS_IsMainThread());
116 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
117 if (mDoDiagnosticAssertWhenOnStopNotCalledOnDestroy
&& mAsyncOpenSucceeded
&&
118 !mSuccesfullyRedirected
&& !LoadOnStopRequestCalled()) {
119 bool emptyBgChildQueue
, nullBgChild
;
121 MutexAutoLock
lock(mBgChildMutex
);
122 nullBgChild
= !mBgChild
;
123 emptyBgChildQueue
= !nullBgChild
&& mBgChild
->IsQueueEmpty();
127 (mRedirectChannelChild
? 1 << 0 : 0) |
128 (mEventQ
->IsEmpty() ? 1 << 1 : 0) | (nullBgChild
? 1 << 2 : 0) |
129 (emptyBgChildQueue
? 1 << 3 : 0) |
130 (LoadOnStartRequestCalled() ? 1 << 4 : 0) |
131 (mBackgroundChildQueueFinalState
== BCKCHILD_EMPTY
? 1 << 5 : 0) |
132 (mBackgroundChildQueueFinalState
== BCKCHILD_NON_EMPTY
? 1 << 6 : 0) |
133 (mRemoteChannelExistedAtCancel
? 1 << 7 : 0) |
134 (mEverHadBgChildAtAsyncOpen
? 1 << 8 : 0) |
135 (mEverHadBgChildAtConnectParent
? 1 << 9 : 0) |
136 (mCreateBackgroundChannelFailed
? 1 << 10 : 0) |
137 (mBgInitFailCallbackTriggered
? 1 << 11 : 0) |
138 (mCanSendAtCancel
? 1 << 12 : 0) | (!!mSuspendCount
? 1 << 13 : 0) |
139 (!!mCallOnResume
? 1 << 14 : 0);
140 MOZ_CRASH_UNSAFE_PRINTF(
141 "~HttpChannelChild, LoadOnStopRequestCalled()=false, mStatus=0x%08x, "
142 "mActorDestroyReason=%d, 20200717 flags=%u",
143 static_cast<uint32_t>(nsresult(mStatus
)),
144 static_cast<int32_t>(mActorDestroyReason
? *mActorDestroyReason
: -1),
149 mEventQ
->NotifyReleasingOwner();
151 ReleaseMainThreadOnlyReferences();
154 void HttpChannelChild::ReleaseMainThreadOnlyReferences() {
155 if (NS_IsMainThread()) {
156 // Already on main thread, let dtor to
157 // take care of releasing references
161 NS_ReleaseOnMainThread("HttpChannelChild::mRedirectChannelChild",
162 mRedirectChannelChild
.forget());
164 //-----------------------------------------------------------------------------
165 // HttpChannelChild::nsISupports
166 //-----------------------------------------------------------------------------
168 NS_IMPL_ADDREF(HttpChannelChild
)
170 NS_IMETHODIMP_(MozExternalRefCountType
) HttpChannelChild::Release() {
171 if (!NS_IsMainThread()) {
172 nsrefcnt count
= mRefCnt
;
173 nsresult rv
= NS_DispatchToMainThread(NewNonOwningRunnableMethod(
174 "HttpChannelChild::Release", this, &HttpChannelChild::Release
));
176 // Continue Release procedure if failed to dispatch to main thread.
177 if (!NS_WARN_IF(NS_FAILED(rv
))) {
182 nsrefcnt count
= --mRefCnt
;
183 MOZ_ASSERT(int32_t(count
) >= 0, "dup release");
185 // Normally we Send_delete in OnStopRequest, but when we need to retain the
186 // remote channel for security info IPDL itself holds 1 reference, so we
187 // Send_delete when refCnt==1. But if !CanSend(), then there's nobody to send
188 // to, so we fall through.
189 if (mKeptAlive
&& count
== 1 && CanSend()) {
190 NS_LOG_RELEASE(this, 1, "HttpChannelChild");
192 // We send a message to the parent, which calls SendDelete, and then the
193 // child calling Send__delete__() to finally drop the refcount to 0.
194 TrySendDeletingChannel();
199 mRefCnt
= 1; /* stabilize */
201 // We don't have a listener when AsyncOpen has failed or when this channel
202 // has been sucessfully redirected.
203 if (MOZ_LIKELY(LoadOnStartRequestCalled() && LoadOnStopRequestCalled()) ||
205 NS_LOG_RELEASE(this, 0, "HttpChannelChild");
210 // This makes sure we fulfill the stream listener contract all the time.
211 if (NS_SUCCEEDED(mStatus
)) {
212 mStatus
= NS_ERROR_ABORT
;
215 // Turn the stabilization refcount into a regular strong reference.
217 // 1) We tell refcount logging about the "stabilization" AddRef, which
218 // will become the reference for |channel|. We do this first so that we
219 // don't tell refcount logging that the refcount has dropped to zero, which
220 // it will interpret as destroying the object.
221 NS_LOG_ADDREF(this, 2, "HttpChannelChild", sizeof(*this));
223 // 2) We tell refcount logging about the original call to Release().
224 NS_LOG_RELEASE(this, 1, "HttpChannelChild");
226 // 3) Finally, we turn the reference into a regular smart pointer.
227 RefPtr
<HttpChannelChild
> channel
= dont_AddRef(this);
229 // This runnable will create a strong reference to |this|.
230 NS_DispatchToMainThread(
231 NewRunnableMethod("~HttpChannelChild>DoNotifyListener", channel
,
232 &HttpChannelChild::DoNotifyListener
));
234 // If NS_DispatchToMainThread failed then we're going to leak the runnable,
235 // and thus the channel, so there's no need to do anything else.
237 // We should have already done any special handling for the refcount = 1
238 // case when the refcount first went from 2 to 1. We don't want it to happen
239 // when |channel| is destroyed.
240 MOZ_ASSERT(!mKeptAlive
|| !CanSend());
242 // XXX If std::move(channel) is allowed, then we don't have to have extra
243 // checks for the refcount going from 2 to 1. See bug 1680217.
245 // This will release the stabilization refcount, which is necessary to avoid
252 NS_LOG_RELEASE(this, count
, "HttpChannelChild");
256 NS_INTERFACE_MAP_BEGIN(HttpChannelChild
)
257 NS_INTERFACE_MAP_ENTRY(nsIRequest
)
258 NS_INTERFACE_MAP_ENTRY(nsIChannel
)
259 NS_INTERFACE_MAP_ENTRY(nsIHttpChannel
)
260 NS_INTERFACE_MAP_ENTRY(nsIHttpChannelInternal
)
261 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsICacheInfoChannel
,
262 !mMultiPartID
.isSome())
263 NS_INTERFACE_MAP_ENTRY(nsIResumableChannel
)
264 NS_INTERFACE_MAP_ENTRY(nsISupportsPriority
)
265 NS_INTERFACE_MAP_ENTRY(nsIClassOfService
)
266 NS_INTERFACE_MAP_ENTRY(nsIProxiedChannel
)
267 NS_INTERFACE_MAP_ENTRY(nsITraceableChannel
)
268 NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectCallback
)
269 NS_INTERFACE_MAP_ENTRY(nsIChildChannel
)
270 NS_INTERFACE_MAP_ENTRY(nsIHttpChannelChild
)
271 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIMultiPartChannel
, mMultiPartID
.isSome())
272 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIThreadRetargetableRequest
,
273 !mMultiPartID
.isSome())
274 NS_INTERFACE_MAP_ENTRY_CONCRETE(HttpChannelChild
)
275 NS_INTERFACE_MAP_END_INHERITING(HttpBaseChannel
)
277 //-----------------------------------------------------------------------------
278 // HttpChannelChild::PHttpChannelChild
279 //-----------------------------------------------------------------------------
281 void HttpChannelChild::OnBackgroundChildReady(
282 HttpBackgroundChannelChild
* aBgChild
) {
283 LOG(("HttpChannelChild::OnBackgroundChildReady [this=%p, bgChild=%p]\n", this,
285 MOZ_ASSERT(OnSocketThread());
288 MutexAutoLock
lock(mBgChildMutex
);
290 // mBgChild might be removed or replaced while the original background
291 // channel is inited on STS thread.
292 if (mBgChild
!= aBgChild
) {
296 MOZ_ASSERT(mBgInitFailCallback
);
297 mBgInitFailCallback
= nullptr;
301 void HttpChannelChild::OnBackgroundChildDestroyed(
302 HttpBackgroundChannelChild
* aBgChild
) {
303 LOG(("HttpChannelChild::OnBackgroundChildDestroyed [this=%p]\n", this));
304 // This function might be called during shutdown phase, so OnSocketThread()
305 // might return false even on STS thread. Use IsOnCurrentThreadInfallible()
306 // to get correct information.
307 MOZ_ASSERT(gSocketTransportService
);
308 MOZ_ASSERT(gSocketTransportService
->IsOnCurrentThreadInfallible());
310 nsCOMPtr
<nsIRunnable
> callback
;
312 MutexAutoLock
lock(mBgChildMutex
);
314 // mBgChild might be removed or replaced while the original background
315 // channel is destroyed on STS thread.
316 if (aBgChild
!= mBgChild
) {
321 callback
= std::move(mBgInitFailCallback
);
325 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
326 mBgInitFailCallbackTriggered
= true;
328 nsCOMPtr
<nsISerialEventTarget
> neckoTarget
= GetNeckoTarget();
329 neckoTarget
->Dispatch(callback
, NS_DISPATCH_NORMAL
);
333 mozilla::ipc::IPCResult
HttpChannelChild::RecvOnStartRequestSent() {
334 LOG(("HttpChannelChild::RecvOnStartRequestSent [this=%p]\n", this));
335 MOZ_ASSERT(NS_IsMainThread());
336 MOZ_ASSERT(!mRecvOnStartRequestSentCalled
);
338 mRecvOnStartRequestSentCalled
= true;
340 if (mSuspendedByWaitingForPermissionCookie
) {
341 mSuspendedByWaitingForPermissionCookie
= false;
347 void HttpChannelChild::ProcessOnStartRequest(
348 const nsHttpResponseHead
& aResponseHead
, const bool& aUseResponseHead
,
349 const nsHttpHeaderArray
& aRequestHeaders
,
350 const HttpChannelOnStartRequestArgs
& aArgs
,
351 const HttpChannelAltDataStream
& aAltData
,
352 const TimeStamp
& aOnStartRequestStartTime
) {
353 LOG(("HttpChannelChild::ProcessOnStartRequest [this=%p]\n", this));
354 MOZ_ASSERT(OnSocketThread());
356 TimeStamp start
= TimeStamp::Now();
358 mAltDataInputStream
= DeserializeIPCStream(aAltData
.altDataInputStream());
360 mEventQ
->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
361 this, [self
= UnsafePtr
<HttpChannelChild
>(this), aResponseHead
,
362 aUseResponseHead
, aRequestHeaders
, aArgs
, start
]() {
363 TimeDuration delay
= TimeStamp::Now() - start
;
364 glean::networking::http_content_onstart_delay
.AccumulateRawDuration(
367 self
->OnStartRequest(aResponseHead
, aUseResponseHead
, aRequestHeaders
,
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 aTimings
.transactionPending
= aArgs
.transactionPending();
386 void HttpChannelChild::OnStartRequest(
387 const nsHttpResponseHead
& aResponseHead
, const bool& aUseResponseHead
,
388 const nsHttpHeaderArray
& aRequestHeaders
,
389 const HttpChannelOnStartRequestArgs
& aArgs
) {
390 LOG(("HttpChannelChild::OnStartRequest [this=%p]\n", this));
392 // If this channel was aborted by ActorDestroy, then there may be other
393 // OnStartRequest/OnStopRequest/OnDataAvailable IPC messages that need to
394 // be handled. In that case we just ignore them to avoid calling the listener
396 if (LoadOnStartRequestCalled() && mIPCActorDeleted
) {
400 // Copy arguments only. It's possible to handle other IPC between
401 // OnStartRequest and DoOnStartRequest.
402 mComputedCrossOriginOpenerPolicy
= aArgs
.openerPolicy();
404 if (!mCanceled
&& NS_SUCCEEDED(mStatus
)) {
405 mStatus
= aArgs
.channelStatus();
408 // Cookies headers should not be visible to the child process
409 MOZ_ASSERT(!aRequestHeaders
.HasHeader(nsHttp::Cookie
));
410 MOZ_ASSERT(!nsHttpResponseHead(aResponseHead
).HasHeader(nsHttp::Set_Cookie
));
412 if (aUseResponseHead
&& !mCanceled
) {
413 mResponseHead
= MakeUnique
<nsHttpResponseHead
>(aResponseHead
);
416 mSecurityInfo
= aArgs
.securityInfo();
418 ipc::MergeParentLoadInfoForwarder(aArgs
.loadInfoForwarder(), mLoadInfo
);
420 mIsFromCache
= aArgs
.isFromCache();
421 mIsRacing
= aArgs
.isRacing();
422 mCacheEntryAvailable
= aArgs
.cacheEntryAvailable();
423 mCacheEntryId
= aArgs
.cacheEntryId();
424 mCacheFetchCount
= aArgs
.cacheFetchCount();
425 mProtocolVersion
= aArgs
.protocolVersion();
426 mCacheExpirationTime
= aArgs
.cacheExpirationTime();
427 mSelfAddr
= aArgs
.selfAddr();
428 mPeerAddr
= aArgs
.peerAddr();
430 mRedirectCount
= aArgs
.redirectCount();
431 mAvailableCachedAltDataType
= aArgs
.altDataType();
432 StoreDeliveringAltData(aArgs
.deliveringAltData());
433 mAltDataLength
= aArgs
.altDataLength();
434 StoreResolvedByTRR(aArgs
.isResolvedByTRR());
435 mEffectiveTRRMode
= aArgs
.effectiveTRRMode();
436 mTRRSkipReason
= aArgs
.trrSkipReason();
438 SetApplyConversion(aArgs
.applyConversion());
440 StoreAfterOnStartRequestBegun(true);
441 StoreHasHTTPSRR(aArgs
.hasHTTPSRR());
443 AutoEventEnqueuer
ensureSerialDispatch(mEventQ
);
445 mCacheKey
= aArgs
.cacheKey();
447 StoreIsProxyUsed(aArgs
.isProxyUsed());
449 // replace our request headers with what actually got sent in the parent
450 mRequestHead
.SetHeaders(aRequestHeaders
);
452 // Note: this is where we would notify "http-on-examine-response" observers.
453 // We have deliberately disabled this for child processes (see bug 806753)
455 // gHttpHandler->OnExamineResponse(this);
457 ResourceTimingStructArgsToTimingsStruct(aArgs
.timing(), mTransactionTimings
);
459 nsAutoCString cosString
;
460 ClassOfService::ToString(mClassOfService
, cosString
);
461 if (!mAsyncOpenTime
.IsNull() &&
462 !aArgs
.timing().transactionPending().IsNull()) {
463 Telemetry::AccumulateTimeDelta(
464 Telemetry::NETWORK_ASYNC_OPEN_CHILD_TO_TRANSACTION_PENDING_EXP_MS
,
465 cosString
, mAsyncOpenTime
, aArgs
.timing().transactionPending());
466 PerfStats::RecordMeasurement(
467 PerfStats::Metric::HttpChannelAsyncOpenToTransactionPending
,
468 aArgs
.timing().transactionPending() - mAsyncOpenTime
);
471 const TimeStamp now
= TimeStamp::Now();
472 if (!aArgs
.timing().responseStart().IsNull()) {
473 Telemetry::AccumulateTimeDelta(
474 Telemetry::NETWORK_RESPONSE_START_PARENT_TO_CONTENT_EXP_MS
, cosString
,
475 aArgs
.timing().responseStart(), now
);
476 PerfStats::RecordMeasurement(
477 PerfStats::Metric::HttpChannelResponseStartParentToContent
,
478 now
- aArgs
.timing().responseStart());
480 if (!mOnStartRequestStartTime
.IsNull()) {
481 PerfStats::RecordMeasurement(PerfStats::Metric::OnStartRequestToContent
,
482 now
- mOnStartRequestStartTime
);
485 StoreAllRedirectsSameOrigin(aArgs
.allRedirectsSameOrigin());
487 mMultiPartID
= aArgs
.multiPartID();
488 mIsFirstPartOfMultiPart
= aArgs
.isFirstPartOfMultiPart();
489 mIsLastPartOfMultiPart
= aArgs
.isLastPartOfMultiPart();
491 if (aArgs
.overrideReferrerInfo()) {
492 // The arguments passed to SetReferrerInfoInternal here should mirror the
493 // arguments passed in
494 // nsHttpChannel::ReEvaluateReferrerAfterTrackingStatusIsKnown(), except for
495 // aRespectBeforeConnect which we pass false here since we're intentionally
496 // overriding the referrer after BeginConnect().
497 Unused
<< SetReferrerInfoInternal(aArgs
.overrideReferrerInfo(), false, true,
501 if (!aArgs
.cookie().IsEmpty()) {
502 SetCookie(aArgs
.cookie());
505 if (aArgs
.shouldWaitForOnStartRequestSent() &&
506 !mRecvOnStartRequestSentCalled
) {
507 LOG((" > pending DoOnStartRequest until RecvOnStartRequestSent\n"));
508 MOZ_ASSERT(NS_IsMainThread());
511 mSuspendedByWaitingForPermissionCookie
= true;
512 mEventQ
->PrependEvent(MakeUnique
<NeckoTargetChannelFunctionEvent
>(
513 this, [self
= UnsafePtr
<HttpChannelChild
>(this)]() {
514 self
->DoOnStartRequest(self
);
519 // Remember whether HTTP3 is supported
522 nsHttpHandler::IsHttp3SupportedByServer(mResponseHead
.get());
525 DoOnStartRequest(this);
528 void HttpChannelChild::ProcessOnAfterLastPart(const nsresult
& aStatus
) {
529 LOG(("HttpChannelChild::ProcessOnAfterLastPart [this=%p]\n", this));
530 MOZ_ASSERT(OnSocketThread());
531 mEventQ
->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
532 this, [self
= UnsafePtr
<HttpChannelChild
>(this), aStatus
]() {
533 self
->OnAfterLastPart(aStatus
);
537 void HttpChannelChild::OnAfterLastPart(const nsresult
& aStatus
) {
538 if (LoadOnStopRequestCalled()) {
541 StoreOnStopRequestCalled(true);
543 // notify "http-on-stop-connect" observers
544 gHttpHandler
->OnStopRequest(this);
548 // If a preferred alt-data type was set, the parent would hold a reference to
549 // the cache entry in case the child calls openAlternativeOutputStream().
550 // (see nsHttpChannel::OnStopRequest)
551 if (!mPreferredCachedAltDataTypes
.IsEmpty()) {
552 mAltDataCacheEntryAvailable
= mCacheEntryAvailable
;
554 mCacheEntryAvailable
= false;
556 if (mLoadGroup
) mLoadGroup
->RemoveRequest(this, nullptr, mStatus
);
557 CleanupBackgroundChannel();
559 if (mLoadFlags
& LOAD_DOCUMENT_URI
) {
560 // Keep IPDL channel open, but only for updating security info.
561 // If IPDL is already closed, then do nothing.
564 SendDocumentChannelCleanup(true);
567 // The parent process will respond by sending a DeleteSelf message and
568 // making sure not to send any more messages after that.
569 TrySendDeletingChannel();
573 void HttpChannelChild::DoOnStartRequest(nsIRequest
* aRequest
) {
576 LOG(("HttpChannelChild::DoOnStartRequest [this=%p]\n", this));
578 // We handle all the listener chaining before OnStartRequest at this moment.
579 // Prevent additional listeners being added to the chain after the request
581 StoreTracingEnabled(false);
583 // mListener could be null if the redirect setup is not completed.
584 MOZ_ASSERT(mListener
|| LoadOnStartRequestCalled());
586 Cancel(NS_ERROR_FAILURE
);
591 nsCOMPtr
<nsIStreamListener
> listener(mListener
);
592 StoreOnStartRequestCalled(true);
593 rv
= listener
->OnStartRequest(aRequest
);
595 rv
= NS_ERROR_UNEXPECTED
;
597 StoreOnStartRequestCalled(true);
600 CancelWithReason(rv
, "HttpChannelChild listener->OnStartRequest failed"_ns
);
604 nsCOMPtr
<nsIStreamListener
> listener
;
605 rv
= DoApplyContentConversions(mListener
, getter_AddRefs(listener
), nullptr);
608 "HttpChannelChild DoApplyContentConversions failed"_ns
);
609 } else if (listener
) {
610 mListener
= listener
;
611 mCompressListener
= listener
;
615 void HttpChannelChild::ProcessOnTransportAndData(
616 const nsresult
& aChannelStatus
, const nsresult
& aTransportStatus
,
617 const uint64_t& aOffset
, const uint32_t& aCount
, const nsACString
& aData
,
618 const TimeStamp
& aOnDataAvailableStartTime
) {
619 LOG(("HttpChannelChild::ProcessOnTransportAndData [this=%p]\n", this));
620 MOZ_ASSERT(OnSocketThread());
621 mEventQ
->RunOrEnqueue(new ChannelFunctionEvent(
622 [self
= UnsafePtr
<HttpChannelChild
>(this)]() {
623 return self
->GetODATarget();
625 [self
= UnsafePtr
<HttpChannelChild
>(this), aChannelStatus
,
626 aTransportStatus
, aOffset
, aCount
, aData
= nsCString(aData
),
627 aOnDataAvailableStartTime
]() {
628 self
->mOnDataAvailableStartTime
= aOnDataAvailableStartTime
;
629 self
->OnTransportAndData(aChannelStatus
, aTransportStatus
, aOffset
,
634 void HttpChannelChild::OnTransportAndData(const nsresult
& aChannelStatus
,
635 const nsresult
& aTransportStatus
,
636 const uint64_t& aOffset
,
637 const uint32_t& aCount
,
638 const nsACString
& aData
) {
639 LOG(("HttpChannelChild::OnTransportAndData [this=%p]\n", this));
641 if (!mCanceled
&& NS_SUCCEEDED(mStatus
)) {
642 mStatus
= aChannelStatus
;
645 if (mCanceled
|| NS_FAILED(mStatus
)) {
649 if (!mOnDataAvailableStartTime
.IsNull()) {
650 PerfStats::RecordMeasurement(PerfStats::Metric::OnDataAvailableToContent
,
651 TimeStamp::Now() - mOnDataAvailableStartTime
);
654 // Hold queue lock throughout all three calls, else we might process a later
655 // necko msg in between them.
656 AutoEventEnqueuer
ensureSerialDispatch(mEventQ
);
659 if (NS_FAILED(GetContentLength(&progressMax
))) {
663 const int64_t progress
= aOffset
+ aCount
;
665 // OnTransportAndData will be run on retargeted thread if applicable, however
666 // OnStatus/OnProgress event can only be fired on main thread. We need to
667 // dispatch the status/progress event handling back to main thread with the
668 // appropriate event target for networking.
669 if (NS_IsMainThread()) {
670 DoOnStatus(this, aTransportStatus
);
671 DoOnProgress(this, progress
, progressMax
);
673 RefPtr
<HttpChannelChild
> self
= this;
674 nsCOMPtr
<nsISerialEventTarget
> neckoTarget
= GetNeckoTarget();
675 MOZ_ASSERT(neckoTarget
);
677 DebugOnly
<nsresult
> rv
= neckoTarget
->Dispatch(
678 NS_NewRunnableFunction(
679 "net::HttpChannelChild::OnTransportAndData",
680 [self
, aTransportStatus
, progress
, progressMax
]() {
681 self
->DoOnStatus(self
, aTransportStatus
);
682 self
->DoOnProgress(self
, progress
, progressMax
);
685 MOZ_ASSERT(NS_SUCCEEDED(rv
));
690 // NOTE: the OnDataAvailable contract requires the client to read all the data
691 // in the inputstream. This code relies on that ('data' will go away after
692 // this function). Apparently the previous, non-e10s behavior was to actually
693 // support only reading part of the data, allowing later calls to read the
695 nsCOMPtr
<nsIInputStream
> stringStream
;
697 NS_NewByteInputStream(getter_AddRefs(stringStream
),
698 Span(aData
).To(aCount
), NS_ASSIGNMENT_DEPEND
);
700 CancelWithReason(rv
, "HttpChannelChild NS_NewByteInputStream failed"_ns
);
704 DoOnDataAvailable(this, stringStream
, aOffset
, aCount
);
705 stringStream
->Close();
707 // TODO: Bug 1523916 backpressure needs to take into account if the data is
708 // coming from the main process or from the socket process via PBackground.
709 if (NeedToReportBytesRead()) {
710 mUnreportBytesRead
+= aCount
;
711 if (mUnreportBytesRead
>= gHttpHandler
->SendWindowSize() >> 2) {
712 if (NS_IsMainThread()) {
713 Unused
<< SendBytesRead(mUnreportBytesRead
);
715 // PHttpChannel connects to the main thread
716 RefPtr
<HttpChannelChild
> self
= this;
717 int32_t bytesRead
= mUnreportBytesRead
;
718 nsCOMPtr
<nsISerialEventTarget
> neckoTarget
= GetNeckoTarget();
719 MOZ_ASSERT(neckoTarget
);
721 DebugOnly
<nsresult
> rv
= neckoTarget
->Dispatch(
722 NS_NewRunnableFunction("net::HttpChannelChild::SendBytesRead",
723 [self
, bytesRead
]() {
724 Unused
<< self
->SendBytesRead(bytesRead
);
727 MOZ_ASSERT(NS_SUCCEEDED(rv
));
729 mUnreportBytesRead
= 0;
734 bool HttpChannelChild::NeedToReportBytesRead() {
735 if (mCacheNeedToReportBytesReadInitialized
) {
736 return mNeedToReportBytesRead
;
739 // Might notify parent for partial cache, and the IPC message is ignored by
741 int64_t contentLength
= -1;
742 if (gHttpHandler
->SendWindowSize() == 0 || mIsFromCache
||
743 NS_FAILED(GetContentLength(&contentLength
)) ||
744 contentLength
< gHttpHandler
->SendWindowSize()) {
745 mNeedToReportBytesRead
= false;
748 mCacheNeedToReportBytesReadInitialized
= true;
749 return mNeedToReportBytesRead
;
752 void HttpChannelChild::DoOnStatus(nsIRequest
* aRequest
, nsresult status
) {
753 LOG(("HttpChannelChild::DoOnStatus [this=%p]\n", this));
754 MOZ_ASSERT(NS_IsMainThread());
756 if (mCanceled
) return;
758 // cache the progress sink so we don't have to query for it each time.
759 if (!mProgressSink
) GetCallback(mProgressSink
);
761 // block status/progress after Cancel or OnStopRequest has been called,
762 // or if channel has LOAD_BACKGROUND set.
763 if (mProgressSink
&& NS_SUCCEEDED(mStatus
) && LoadIsPending() &&
764 !(mLoadFlags
& LOAD_BACKGROUND
)) {
767 mProgressSink
->OnStatus(aRequest
, status
,
768 NS_ConvertUTF8toUTF16(host
).get());
772 void HttpChannelChild::DoOnProgress(nsIRequest
* aRequest
, int64_t progress
,
773 int64_t progressMax
) {
774 LOG(("HttpChannelChild::DoOnProgress [this=%p]\n", this));
775 MOZ_ASSERT(NS_IsMainThread());
777 if (mCanceled
) return;
779 // cache the progress sink so we don't have to query for it each time.
780 if (!mProgressSink
) GetCallback(mProgressSink
);
782 // block status/progress after Cancel or OnStopRequest has been called,
783 // or if channel has LOAD_BACKGROUND set.
784 if (mProgressSink
&& NS_SUCCEEDED(mStatus
) && LoadIsPending()) {
788 mProgressSink
->OnProgress(aRequest
, progress
, progressMax
);
792 // mOnProgressEventSent indicates we have flushed all the
793 // progress events on the main thread. It is needed if
794 // we do not want to dispatch OnDataFinished before sending
795 // all of the progress updates.
796 if (progress
== progressMax
) {
797 mOnProgressEventSent
= true;
801 void HttpChannelChild::DoOnDataAvailable(nsIRequest
* aRequest
,
802 nsIInputStream
* aStream
,
803 uint64_t aOffset
, uint32_t aCount
) {
804 AUTO_PROFILER_LABEL("HttpChannelChild::DoOnDataAvailable", NETWORK
);
805 LOG(("HttpChannelChild::DoOnDataAvailable [this=%p]\n", this));
806 if (mCanceled
) return;
809 nsCOMPtr
<nsIStreamListener
> listener(mListener
);
810 nsresult rv
= listener
->OnDataAvailable(aRequest
, aStream
, aOffset
, aCount
);
812 CancelOnMainThread(rv
, "HttpChannelChild OnDataAvailable failed"_ns
);
817 void HttpChannelChild::SendOnDataFinished(const nsresult
& aChannelStatus
) {
818 LOG(("HttpChannelChild::SendOnDataFinished [this=%p]\n", this));
819 if (MOZ_UNLIKELY(NS_IsMainThread())) {
820 MOZ_ASSERT(false, "SendOnDataFinished should not be called on main thread");
824 if (mCanceled
) return;
826 // we need to ensure we OnDataFinished only after all the progress
827 // updates are dispatched on the main thread
828 if (StaticPrefs::network_send_OnDataFinished_after_progress_updates() &&
829 !mOnProgressEventSent
) {
834 nsCOMPtr
<nsIThreadRetargetableStreamListener
> omtEventListener
=
835 do_QueryInterface(mListener
);
836 if (omtEventListener
) {
838 ("HttpChannelChild::SendOnDataFinished sending data end "
839 "notification[this=%p]\n",
841 // We want to calculate the delta time between this call and
842 // ProcessOnStopRequest. Complicating things is that OnStopRequest
843 // could come first, and that it will run on a different thread, so
844 // we need to synchronize and lock data.
845 omtEventListener
->OnDataFinished(aChannelStatus
);
848 ("HttpChannelChild::SendOnDataFinished missing "
849 "nsIThreadRetargetableStreamListener "
850 "implementation [this=%p]\n",
856 class RecordStopRequestDelta final
{
858 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RecordStopRequestDelta
);
860 TimeStamp mOnStopRequestTime
;
861 TimeStamp mOnDataFinishedTime
;
864 ~RecordStopRequestDelta() {
865 if (mOnDataFinishedTime
.IsNull() || mOnStopRequestTime
.IsNull()) {
869 TimeDuration delta
= (mOnStopRequestTime
- mOnDataFinishedTime
);
870 if (delta
.ToMilliseconds() < 0) {
871 // Because Telemetry can't handle negatives
873 glean::networking::http_content_ondatafinished_to_onstop_delay_negative
874 .AccumulateRawDuration(delta
);
876 glean::networking::http_content_ondatafinished_to_onstop_delay
877 .AccumulateRawDuration(delta
);
882 void HttpChannelChild::ProcessOnStopRequest(
883 const nsresult
& aChannelStatus
, const ResourceTimingStructArgs
& aTiming
,
884 const nsHttpHeaderArray
& aResponseTrailers
,
885 nsTArray
<ConsoleReportCollected
>&& aConsoleReports
, bool aFromSocketProcess
,
886 const TimeStamp
& aOnStopRequestStartTime
) {
888 ("HttpChannelChild::ProcessOnStopRequest [this=%p, "
889 "aFromSocketProcess=%d]\n",
890 this, aFromSocketProcess
));
891 MOZ_ASSERT(OnSocketThread());
892 { // assign some of the members that would be accessed by the listeners
893 // upon getting OnDataFinished notications
894 MutexAutoLock
lock(mOnDataFinishedMutex
);
895 mTransferSize
= aTiming
.transferSize();
896 mEncodedBodySize
= aTiming
.encodedBodySize();
899 RefPtr
<RecordStopRequestDelta
> timing
;
900 TimeStamp start
= TimeStamp::Now();
901 if (StaticPrefs::network_send_OnDataFinished() &&
902 mOMTResult
== LABELS_HTTP_CHILD_OMT_STATS::success
) {
903 timing
= new RecordStopRequestDelta
;
904 mEventQ
->RunOrEnqueue(new ChannelFunctionEvent(
905 [self
= UnsafePtr
<HttpChannelChild
>(this)]() {
906 return self
->GetODATarget();
908 [self
= UnsafePtr
<HttpChannelChild
>(this), status
= aChannelStatus
,
910 TimeStamp now
= TimeStamp::Now();
911 TimeDuration delay
= now
- start
;
912 glean::networking::http_content_ondatafinished_delay
913 .AccumulateRawDuration(delay
);
914 timing
->mOnDataFinishedTime
= now
;
915 self
->SendOnDataFinished(status
);
918 mEventQ
->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
919 this, [self
= UnsafePtr
<HttpChannelChild
>(this), aChannelStatus
, aTiming
,
921 consoleReports
= CopyableTArray
{aConsoleReports
.Clone()},
922 aFromSocketProcess
, start
, timing
]() mutable {
923 TimeStamp now
= TimeStamp::Now();
924 TimeDuration delay
= now
- start
;
925 glean::networking::http_content_onstop_delay
.AccumulateRawDuration(
928 timing
->mOnStopRequestTime
= now
;
930 self
->OnStopRequest(aChannelStatus
, aTiming
, aResponseTrailers
);
931 if (!aFromSocketProcess
) {
932 self
->DoOnConsoleReport(std::move(consoleReports
));
933 self
->ContinueOnStopRequest();
938 void HttpChannelChild::ProcessOnConsoleReport(
939 nsTArray
<ConsoleReportCollected
>&& aConsoleReports
) {
940 LOG(("HttpChannelChild::ProcessOnConsoleReport [this=%p]\n", this));
941 MOZ_ASSERT(OnSocketThread());
943 mEventQ
->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
945 [self
= UnsafePtr
<HttpChannelChild
>(this),
946 consoleReports
= CopyableTArray
{aConsoleReports
.Clone()}]() mutable {
947 self
->DoOnConsoleReport(std::move(consoleReports
));
948 self
->ContinueOnStopRequest();
952 void HttpChannelChild::DoOnConsoleReport(
953 nsTArray
<ConsoleReportCollected
>&& aConsoleReports
) {
954 if (aConsoleReports
.IsEmpty()) {
958 for (ConsoleReportCollected
& report
: aConsoleReports
) {
959 if (report
.propertiesFile() <
960 nsContentUtils::PropertiesFile::PropertiesFile_COUNT
) {
961 AddConsoleReport(report
.errorFlags(), report
.category(),
962 nsContentUtils::PropertiesFile(report
.propertiesFile()),
963 report
.sourceFileURI(), report
.lineNumber(),
964 report
.columnNumber(), report
.messageName(),
965 report
.stringParams());
968 MaybeFlushConsoleReports();
971 void HttpChannelChild::RecordChannelCompletionDurationForEarlyHint() {
976 uint32_t earlyHintType
= 0;
977 nsCOMPtr
<nsIRequest
> req
;
978 Unused
<< mLoadGroup
->GetDefaultLoadRequest(getter_AddRefs(req
));
979 if (nsCOMPtr
<nsIHttpChannelInternal
> httpChannel
= do_QueryInterface(req
)) {
980 Unused
<< httpChannel
->GetEarlyHintLinkType(&earlyHintType
);
983 if (!earlyHintType
) {
987 nsAutoCString earlyHintKey
;
989 earlyHintKey
.Append("cache_"_ns
);
991 earlyHintKey
.Append("net_"_ns
);
993 if (earlyHintType
& LinkStyle::ePRECONNECT
) {
994 earlyHintKey
.Append("preconnect_"_ns
);
996 if (earlyHintType
& LinkStyle::ePRELOAD
) {
997 earlyHintKey
.Append("preload_"_ns
);
998 earlyHintKey
.Append(mEarlyHintPreloaderId
? "1"_ns
: "0"_ns
);
1001 Telemetry::AccumulateTimeDelta(Telemetry::EH_PERF_CHANNEL_COMPLETION_TIME
,
1002 earlyHintKey
, mAsyncOpenTime
,
1006 void HttpChannelChild::OnStopRequest(
1007 const nsresult
& aChannelStatus
, const ResourceTimingStructArgs
& aTiming
,
1008 const nsHttpHeaderArray
& aResponseTrailers
) {
1009 LOG(("HttpChannelChild::OnStopRequest [this=%p status=%" PRIx32
"]\n", this,
1010 static_cast<uint32_t>(aChannelStatus
)));
1011 MOZ_ASSERT(NS_IsMainThread());
1013 // If this channel was aborted by ActorDestroy, then there may be other
1014 // OnStartRequest/OnStopRequest/OnDataAvailable IPC messages that need to
1015 // be handled. In that case we just ignore them to avoid calling the listener
1017 if (LoadOnStopRequestCalled() && mIPCActorDeleted
) {
1021 nsCOMPtr
<nsICompressConvStats
> conv
= do_QueryInterface(mCompressListener
);
1023 conv
->GetDecodedDataLength(&mDecodedBodySize
);
1026 ResourceTimingStructArgsToTimingsStruct(aTiming
, mTransactionTimings
);
1028 // Do not overwrite or adjust the original mAsyncOpenTime by timing.fetchStart
1029 // We must use the original child process time in order to account for child
1030 // side work and IPC transit overhead.
1031 // XXX: This depends on TimeStamp being equivalent across processes.
1032 // This is true for modern hardware but for older platforms it is not always
1035 mRedirectStartTimeStamp
= aTiming
.redirectStart();
1036 mRedirectEndTimeStamp
= aTiming
.redirectEnd();
1037 // mTransferSize and mEncodedBodySize are set in ProcessOnStopRequest
1038 // TODO: check if we need to move assignments of other members to
1039 // ProcessOnStopRequest
1041 mCacheReadStart
= aTiming
.cacheReadStart();
1042 mCacheReadEnd
= aTiming
.cacheReadEnd();
1044 const TimeStamp now
= TimeStamp::Now();
1046 if (profiler_thread_is_being_profiled_for_markers()) {
1047 nsAutoCString requestMethod
;
1048 GetRequestMethod(requestMethod
);
1049 nsAutoCString contentType
;
1050 if (mResponseHead
) {
1051 mResponseHead
->ContentType(contentType
);
1053 int32_t priority
= PRIORITY_NORMAL
;
1054 GetPriority(&priority
);
1055 profiler_add_network_marker(
1056 mURI
, requestMethod
, priority
, mChannelId
, NetworkLoadType::LOAD_STOP
,
1057 mLastStatusReported
, now
, mTransferSize
, kCacheUnknown
,
1058 mLoadInfo
->GetInnerWindowID(),
1059 mLoadInfo
->GetOriginAttributes().mPrivateBrowsingId
> 0,
1060 &mTransactionTimings
, std::move(mSource
),
1061 Some(nsDependentCString(contentType
.get())));
1064 RecordChannelCompletionDurationForEarlyHint();
1066 TimeDuration channelCompletionDuration
= now
- mAsyncOpenTime
;
1068 PerfStats::RecordMeasurement(PerfStats::Metric::HttpChannelCompletion_Cache
,
1069 channelCompletionDuration
);
1071 PerfStats::RecordMeasurement(
1072 PerfStats::Metric::HttpChannelCompletion_Network
,
1073 channelCompletionDuration
);
1075 PerfStats::RecordMeasurement(PerfStats::Metric::HttpChannelCompletion
,
1076 channelCompletionDuration
);
1078 if (!aTiming
.responseEnd().IsNull()) {
1079 nsAutoCString cosString
;
1080 ClassOfService::ToString(mClassOfService
, cosString
);
1081 Telemetry::AccumulateTimeDelta(
1082 Telemetry::NETWORK_RESPONSE_END_PARENT_TO_CONTENT_MS
, cosString
,
1083 aTiming
.responseEnd(), now
);
1084 PerfStats::RecordMeasurement(
1085 PerfStats::Metric::HttpChannelResponseEndParentToContent
,
1086 now
- aTiming
.responseEnd());
1089 if (!mOnStopRequestStartTime
.IsNull()) {
1090 PerfStats::RecordMeasurement(PerfStats::Metric::OnStopRequestToContent
,
1091 now
- mOnStopRequestStartTime
);
1094 mResponseTrailers
= MakeUnique
<nsHttpHeaderArray
>(aResponseTrailers
);
1096 DoPreOnStopRequest(aChannelStatus
);
1098 { // We must flush the queue before we Send__delete__
1099 // (although we really shouldn't receive any msgs after OnStop),
1100 // so make sure this goes out of scope before then.
1101 AutoEventEnqueuer
ensureSerialDispatch(mEventQ
);
1103 DoOnStopRequest(this, aChannelStatus
);
1104 // DoOnStopRequest() calls ReleaseListeners()
1108 void HttpChannelChild::ContinueOnStopRequest() {
1109 // If we're a multi-part stream, then don't cleanup yet, and we'll do so
1110 // in OnAfterLastPart.
1113 ("HttpChannelChild::OnStopRequest - Expecting future parts on a "
1114 "multipart channel postpone cleaning up."));
1118 CollectMixedContentTelemetry();
1120 CleanupBackgroundChannel();
1122 // If there is a possibility we might want to write alt data to the cache
1123 // entry, we keep the channel alive. We still send the DocumentChannelCleanup
1124 // message but request the cache entry to be kept by the parent.
1125 // If the channel has failed, the cache entry is in a non-writtable state and
1126 // we want to release it to not block following consumers.
1127 if (NS_SUCCEEDED(mStatus
) && !mPreferredCachedAltDataTypes
.IsEmpty()) {
1129 SendDocumentChannelCleanup(false); // don't clear cache entry
1133 if (mLoadFlags
& LOAD_DOCUMENT_URI
) {
1134 // Keep IPDL channel open, but only for updating security info.
1135 // If IPDL is already closed, then do nothing.
1138 SendDocumentChannelCleanup(true);
1141 // The parent process will respond by sending a DeleteSelf message and
1142 // making sure not to send any more messages after that.
1143 TrySendDeletingChannel();
1147 void HttpChannelChild::DoPreOnStopRequest(nsresult aStatus
) {
1148 AUTO_PROFILER_LABEL("HttpChannelChild::DoPreOnStopRequest", NETWORK
);
1149 LOG(("HttpChannelChild::DoPreOnStopRequest [this=%p status=%" PRIx32
"]\n",
1150 this, static_cast<uint32_t>(aStatus
)));
1151 StoreIsPending(false);
1153 MaybeReportTimingData();
1155 if (!mCanceled
&& NS_SUCCEEDED(mStatus
)) {
1159 CollectOMTTelemetry();
1162 void HttpChannelChild::CollectOMTTelemetry() {
1163 MOZ_ASSERT(NS_IsMainThread());
1165 // Only collect telemetry for HTTP channel that is loaded successfully and
1167 if (mCanceled
|| NS_FAILED(mStatus
)) {
1171 // Use content policy type to accumulate data by usage.
1173 NS_CP_ContentTypeName(mLoadInfo
->InternalContentPolicyType()));
1175 Telemetry::AccumulateCategoricalKeyed(
1176 key
, static_cast<LABELS_HTTP_CHILD_OMT_STATS
>(mOMTResult
));
1179 void HttpChannelChild::CollectMixedContentTelemetry() {
1180 MOZ_ASSERT(NS_IsMainThread());
1182 nsContentPolicyType internalLoadType
;
1183 mLoadInfo
->GetInternalContentPolicyType(&internalLoadType
);
1184 bool statusIsSuccess
= NS_SUCCEEDED(mStatus
);
1185 RefPtr
<Document
> doc
;
1186 mLoadInfo
->GetLoadingDocument(getter_AddRefs(doc
));
1190 if (internalLoadType
== nsIContentPolicy::TYPE_INTERNAL_IMAGE
||
1191 internalLoadType
== nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD
) {
1192 if (mLoadInfo
->GetBrowserUpgradeInsecureRequests()) {
1195 ? eUseCounter_custom_MixedContentUpgradedImageSuccess
1196 : eUseCounter_custom_MixedContentUpgradedImageFailure
);
1197 } else if (mLoadInfo
->GetBrowserWouldUpgradeInsecureRequests()) {
1200 ? eUseCounter_custom_MixedContentNotUpgradedImageSuccess
1201 : eUseCounter_custom_MixedContentNotUpgradedImageFailure
);
1205 if (internalLoadType
== nsIContentPolicy::TYPE_INTERNAL_VIDEO
) {
1206 if (mLoadInfo
->GetBrowserUpgradeInsecureRequests()) {
1209 ? eUseCounter_custom_MixedContentUpgradedVideoSuccess
1210 : eUseCounter_custom_MixedContentUpgradedVideoFailure
);
1211 } else if (mLoadInfo
->GetBrowserWouldUpgradeInsecureRequests()) {
1214 ? eUseCounter_custom_MixedContentNotUpgradedVideoSuccess
1215 : eUseCounter_custom_MixedContentNotUpgradedVideoFailure
);
1219 if (internalLoadType
== nsIContentPolicy::TYPE_INTERNAL_AUDIO
) {
1220 if (mLoadInfo
->GetBrowserUpgradeInsecureRequests()) {
1223 ? eUseCounter_custom_MixedContentUpgradedAudioSuccess
1224 : eUseCounter_custom_MixedContentUpgradedAudioFailure
);
1225 } else if (mLoadInfo
->GetBrowserWouldUpgradeInsecureRequests()) {
1228 ? eUseCounter_custom_MixedContentNotUpgradedAudioSuccess
1229 : eUseCounter_custom_MixedContentNotUpgradedAudioFailure
);
1234 void HttpChannelChild::DoOnStopRequest(nsIRequest
* aRequest
,
1235 nsresult aChannelStatus
) {
1236 AUTO_PROFILER_LABEL("HttpChannelChild::DoOnStopRequest", NETWORK
);
1237 LOG(("HttpChannelChild::DoOnStopRequest [this=%p]\n", this));
1238 MOZ_ASSERT(NS_IsMainThread());
1239 MOZ_ASSERT(!LoadIsPending());
1241 auto checkForBlockedContent
= [&]() {
1242 // NB: We use aChannelStatus here instead of mStatus because if there was an
1243 // nsCORSListenerProxy on this request, it will override the tracking
1244 // protection's return value.
1245 if (UrlClassifierFeatureFactory::IsClassifierBlockingErrorCode(
1247 aChannelStatus
== NS_ERROR_MALWARE_URI
||
1248 aChannelStatus
== NS_ERROR_UNWANTED_URI
||
1249 aChannelStatus
== NS_ERROR_BLOCKED_URI
||
1250 aChannelStatus
== NS_ERROR_HARMFUL_URI
||
1251 aChannelStatus
== NS_ERROR_PHISHING_URI
) {
1252 nsCString list
, provider
, fullhash
;
1254 nsresult rv
= GetMatchedList(list
);
1255 NS_ENSURE_SUCCESS_VOID(rv
);
1257 rv
= GetMatchedProvider(provider
);
1258 NS_ENSURE_SUCCESS_VOID(rv
);
1260 rv
= GetMatchedFullHash(fullhash
);
1261 NS_ENSURE_SUCCESS_VOID(rv
);
1263 UrlClassifierCommon::SetBlockedContent(this, aChannelStatus
, list
,
1264 provider
, fullhash
);
1267 checkForBlockedContent();
1269 MaybeLogCOEPError(aChannelStatus
);
1271 // See bug 1587686. If the redirect setup is not completed, the post-redirect
1272 // channel will be not opened and mListener will be null.
1273 MOZ_ASSERT(mListener
|| !LoadWasOpened());
1278 MOZ_ASSERT(!LoadOnStopRequestCalled(),
1279 "We should not call OnStopRequest twice");
1282 nsCOMPtr
<nsIStreamListener
> listener(mListener
);
1283 StoreOnStopRequestCalled(true);
1284 listener
->OnStopRequest(aRequest
, mStatus
);
1286 StoreOnStopRequestCalled(true);
1288 // If we're a multi-part stream, then don't cleanup yet, and we'll do so
1289 // in OnAfterLastPart.
1292 ("HttpChannelChild::DoOnStopRequest - Expecting future parts on a "
1293 "multipart channel not releasing listeners."));
1294 StoreOnStopRequestCalled(false);
1295 StoreOnStartRequestCalled(false);
1299 // notify "http-on-stop-connect" observers
1300 gHttpHandler
->OnStopRequest(this);
1304 // If a preferred alt-data type was set, the parent would hold a reference to
1305 // the cache entry in case the child calls openAlternativeOutputStream().
1306 // (see nsHttpChannel::OnStopRequest)
1307 if (!mPreferredCachedAltDataTypes
.IsEmpty()) {
1308 mAltDataCacheEntryAvailable
= mCacheEntryAvailable
;
1310 mCacheEntryAvailable
= false;
1312 if (mLoadGroup
) mLoadGroup
->RemoveRequest(this, nullptr, mStatus
);
1315 void HttpChannelChild::ProcessOnProgress(const int64_t& aProgress
,
1316 const int64_t& aProgressMax
) {
1317 MOZ_ASSERT(OnSocketThread());
1318 LOG(("HttpChannelChild::ProcessOnProgress [this=%p]\n", this));
1319 mEventQ
->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
1321 [self
= UnsafePtr
<HttpChannelChild
>(this), aProgress
, aProgressMax
]() {
1322 AutoEventEnqueuer
ensureSerialDispatch(self
->mEventQ
);
1323 self
->DoOnProgress(self
, aProgress
, aProgressMax
);
1327 void HttpChannelChild::ProcessOnStatus(const nsresult
& aStatus
) {
1328 MOZ_ASSERT(OnSocketThread());
1329 LOG(("HttpChannelChild::ProcessOnStatus [this=%p]\n", this));
1330 mEventQ
->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
1331 this, [self
= UnsafePtr
<HttpChannelChild
>(this), aStatus
]() {
1332 AutoEventEnqueuer
ensureSerialDispatch(self
->mEventQ
);
1333 self
->DoOnStatus(self
, aStatus
);
1337 mozilla::ipc::IPCResult
HttpChannelChild::RecvFailedAsyncOpen(
1338 const nsresult
& aStatus
) {
1339 LOG(("HttpChannelChild::RecvFailedAsyncOpen [this=%p]\n", this));
1340 mEventQ
->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
1341 this, [self
= UnsafePtr
<HttpChannelChild
>(this), aStatus
]() {
1342 self
->FailedAsyncOpen(aStatus
);
1347 // We need to have an implementation of this function just so that we can keep
1348 // all references to mCallOnResume of type HttpChannelChild: it's not OK in C++
1349 // to set a member function ptr to a base class function.
1350 void HttpChannelChild::HandleAsyncAbort() {
1351 HttpAsyncAborter
<HttpChannelChild
>::HandleAsyncAbort();
1353 // Ignore all the messages from background channel after channel aborted.
1354 CleanupBackgroundChannel();
1357 void HttpChannelChild::FailedAsyncOpen(const nsresult
& status
) {
1358 LOG(("HttpChannelChild::FailedAsyncOpen [this=%p status=%" PRIx32
"]\n", this,
1359 static_cast<uint32_t>(status
)));
1360 MOZ_ASSERT(NS_IsMainThread());
1362 // Might be called twice in race condition in theory.
1363 // (one by RecvFailedAsyncOpen, another by
1364 // HttpBackgroundChannelChild::ActorFailed)
1365 if (LoadOnStartRequestCalled()) {
1369 if (NS_SUCCEEDED(mStatus
)) {
1373 // We're already being called from IPDL, therefore already "async"
1377 TrySendDeletingChannel();
1381 void HttpChannelChild::CleanupBackgroundChannel() {
1382 MutexAutoLock
lock(mBgChildMutex
);
1384 AUTO_PROFILER_LABEL("HttpChannelChild::CleanupBackgroundChannel", NETWORK
);
1385 LOG(("HttpChannelChild::CleanupBackgroundChannel [this=%p bgChild=%p]\n",
1386 this, mBgChild
.get()));
1388 mBgInitFailCallback
= nullptr;
1394 RefPtr
<HttpBackgroundChannelChild
> bgChild
= std::move(mBgChild
);
1396 MOZ_RELEASE_ASSERT(gSocketTransportService
);
1397 if (!OnSocketThread()) {
1398 gSocketTransportService
->Dispatch(
1399 NewRunnableMethod("HttpBackgroundChannelChild::OnChannelClosed",
1401 &HttpBackgroundChannelChild::OnChannelClosed
),
1402 NS_DISPATCH_NORMAL
);
1404 bgChild
->OnChannelClosed();
1408 void HttpChannelChild::DoNotifyListenerCleanup() {
1409 LOG(("HttpChannelChild::DoNotifyListenerCleanup [this=%p]\n", this));
1412 void HttpChannelChild::DoAsyncAbort(nsresult aStatus
) {
1413 Unused
<< AsyncAbort(aStatus
);
1416 mozilla::ipc::IPCResult
HttpChannelChild::RecvDeleteSelf() {
1417 LOG(("HttpChannelChild::RecvDeleteSelf [this=%p]\n", this));
1418 MOZ_ASSERT(NS_IsMainThread());
1420 // The redirection is vetoed. No need to suspend the event queue.
1421 if (mSuspendForWaitCompleteRedirectSetup
) {
1422 mSuspendForWaitCompleteRedirectSetup
= false;
1426 mEventQ
->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
1428 [self
= UnsafePtr
<HttpChannelChild
>(this)]() { self
->DeleteSelf(); }));
1432 void HttpChannelChild::DeleteSelf() { Send__delete__(this); }
1434 void HttpChannelChild::NotifyOrReleaseListeners(nsresult rv
) {
1435 MOZ_ASSERT(NS_IsMainThread());
1437 if (NS_SUCCEEDED(rv
) ||
1438 (LoadOnStartRequestCalled() && LoadOnStopRequestCalled())) {
1443 if (NS_SUCCEEDED(mStatus
)) {
1447 // This is enough what we need. Undelivered notifications will be pushed.
1448 // DoNotifyListener ensures the call to ReleaseListeners when done.
1452 void HttpChannelChild::DoNotifyListener() {
1453 LOG(("HttpChannelChild::DoNotifyListener this=%p", this));
1454 MOZ_ASSERT(NS_IsMainThread());
1456 // In case nsHttpChannel::OnStartRequest wasn't called (e.g. due to flag
1457 // LOAD_ONLY_IF_MODIFIED) we want to set LoadAfterOnStartRequestBegun() to
1458 // true before notifying listener.
1459 if (!LoadAfterOnStartRequestBegun()) {
1460 StoreAfterOnStartRequestBegun(true);
1463 if (mListener
&& !LoadOnStartRequestCalled()) {
1464 nsCOMPtr
<nsIStreamListener
> listener
= mListener
;
1465 StoreOnStartRequestCalled(
1466 true); // avoid reentrancy bugs by setting this now
1467 listener
->OnStartRequest(this);
1469 StoreOnStartRequestCalled(true);
1471 mEventQ
->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
1472 this, [self
= UnsafePtr
<HttpChannelChild
>(this)] {
1473 self
->ContinueDoNotifyListener();
1477 void HttpChannelChild::ContinueDoNotifyListener() {
1478 LOG(("HttpChannelChild::ContinueDoNotifyListener this=%p", this));
1479 MOZ_ASSERT(NS_IsMainThread());
1481 // Make sure IsPending is set to false. At this moment we are done from
1482 // the point of view of our consumer and we have to report our self
1484 StoreIsPending(false);
1486 if (mListener
&& !LoadOnStopRequestCalled()) {
1487 nsCOMPtr
<nsIStreamListener
> listener
= mListener
;
1488 StoreOnStopRequestCalled(true);
1489 listener
->OnStopRequest(this, mStatus
);
1491 StoreOnStopRequestCalled(true);
1493 // notify "http-on-stop-request" observers
1494 gHttpHandler
->OnStopRequest(this);
1496 // This channel has finished its job, potentially release any tail-blocked
1497 // requests with this.
1498 RemoveAsNonTailRequest();
1500 // We have to make sure to drop the references to listeners and callbacks
1501 // no longer needed.
1504 DoNotifyListenerCleanup();
1506 // If this is a navigation, then we must let the docshell flush the reports
1507 // to the console later. The LoadDocument() is pointing at the detached
1508 // document that started the navigation. We want to show the reports on the
1509 // new document. Otherwise the console is wiped and the user never sees
1511 if (!IsNavigation()) {
1513 FlushConsoleReports(mLoadGroup
);
1515 RefPtr
<dom::Document
> doc
;
1516 mLoadInfo
->GetLoadingDocument(getter_AddRefs(doc
));
1517 FlushConsoleReports(doc
);
1522 mozilla::ipc::IPCResult
HttpChannelChild::RecvReportSecurityMessage(
1523 const nsAString
& messageTag
, const nsAString
& messageCategory
) {
1524 DebugOnly
<nsresult
> rv
= AddSecurityMessage(messageTag
, messageCategory
);
1525 MOZ_ASSERT(NS_SUCCEEDED(rv
));
1529 mozilla::ipc::IPCResult
HttpChannelChild::RecvRedirect1Begin(
1530 const uint32_t& aRegistrarId
, nsIURI
* aNewUri
,
1531 const uint32_t& aNewLoadFlags
, const uint32_t& aRedirectFlags
,
1532 const ParentLoadInfoForwarderArgs
& aLoadInfoForwarder
,
1533 const nsHttpResponseHead
& aResponseHead
,
1534 nsITransportSecurityInfo
* aSecurityInfo
, const uint64_t& aChannelId
,
1535 const NetAddr
& aOldPeerAddr
, const ResourceTimingStructArgs
& aTiming
) {
1536 // TODO: handle security info
1537 LOG(("HttpChannelChild::RecvRedirect1Begin [this=%p]\n", this));
1538 // We set peer address of child to the old peer,
1539 // Then it will be updated to new peer in OnStartRequest
1540 mPeerAddr
= aOldPeerAddr
;
1542 // Cookies headers should not be visible to the child process
1543 MOZ_ASSERT(!nsHttpResponseHead(aResponseHead
).HasHeader(nsHttp::Set_Cookie
));
1545 mEventQ
->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
1546 this, [self
= UnsafePtr
<HttpChannelChild
>(this), aRegistrarId
,
1547 newUri
= RefPtr
{aNewUri
}, aNewLoadFlags
, aRedirectFlags
,
1548 aLoadInfoForwarder
, aResponseHead
,
1549 aSecurityInfo
= nsCOMPtr
{aSecurityInfo
}, aChannelId
, aTiming
]() {
1550 self
->Redirect1Begin(aRegistrarId
, newUri
, aNewLoadFlags
,
1551 aRedirectFlags
, aLoadInfoForwarder
, aResponseHead
,
1552 aSecurityInfo
, aChannelId
, aTiming
);
1557 nsresult
HttpChannelChild::SetupRedirect(nsIURI
* uri
,
1558 const nsHttpResponseHead
* responseHead
,
1559 const uint32_t& redirectFlags
,
1560 nsIChannel
** outChannel
) {
1561 LOG(("HttpChannelChild::SetupRedirect [this=%p]\n", this));
1564 return NS_ERROR_ABORT
;
1568 nsCOMPtr
<nsIIOService
> ioService
;
1569 rv
= gHttpHandler
->GetIOService(getter_AddRefs(ioService
));
1570 NS_ENSURE_SUCCESS(rv
, rv
);
1572 nsCOMPtr
<nsIChannel
> newChannel
;
1573 nsCOMPtr
<nsILoadInfo
> redirectLoadInfo
=
1574 CloneLoadInfoForRedirect(uri
, redirectFlags
);
1575 rv
= NS_NewChannelInternal(getter_AddRefs(newChannel
), uri
, redirectLoadInfo
,
1576 nullptr, // PerformanceStorage
1577 nullptr, // aLoadGroup
1578 nullptr, // aCallbacks
1579 nsIRequest::LOAD_NORMAL
, ioService
);
1580 NS_ENSURE_SUCCESS(rv
, rv
);
1582 // We won't get OnStartRequest, set cookies here.
1583 mResponseHead
= MakeUnique
<nsHttpResponseHead
>(*responseHead
);
1585 bool rewriteToGET
= HttpBaseChannel::ShouldRewriteRedirectToGET(
1586 mResponseHead
->Status(), mRequestHead
.ParsedMethod());
1588 rv
= SetupReplacementChannel(uri
, newChannel
, !rewriteToGET
, redirectFlags
);
1589 NS_ENSURE_SUCCESS(rv
, rv
);
1591 mRedirectChannelChild
= do_QueryInterface(newChannel
);
1592 newChannel
.forget(outChannel
);
1597 void HttpChannelChild::Redirect1Begin(
1598 const uint32_t& registrarId
, nsIURI
* newOriginalURI
,
1599 const uint32_t& newLoadFlags
, const uint32_t& redirectFlags
,
1600 const ParentLoadInfoForwarderArgs
& loadInfoForwarder
,
1601 const nsHttpResponseHead
& responseHead
,
1602 nsITransportSecurityInfo
* securityInfo
, const uint64_t& channelId
,
1603 const ResourceTimingStructArgs
& timing
) {
1606 LOG(("HttpChannelChild::Redirect1Begin [this=%p]\n", this));
1608 MOZ_ASSERT(newOriginalURI
, "newOriginalURI should not be null");
1610 ipc::MergeParentLoadInfoForwarder(loadInfoForwarder
, mLoadInfo
);
1611 ResourceTimingStructArgsToTimingsStruct(timing
, mTransactionTimings
);
1613 if (profiler_thread_is_being_profiled_for_markers()) {
1614 nsAutoCString requestMethod
;
1615 GetRequestMethod(requestMethod
);
1616 nsAutoCString contentType
;
1617 responseHead
.ContentType(contentType
);
1619 profiler_add_network_marker(
1620 mURI
, requestMethod
, mPriority
, mChannelId
,
1621 NetworkLoadType::LOAD_REDIRECT
, mLastStatusReported
, TimeStamp::Now(),
1622 0, kCacheUnknown
, mLoadInfo
->GetInnerWindowID(),
1623 mLoadInfo
->GetOriginAttributes().mPrivateBrowsingId
> 0,
1624 &mTransactionTimings
, std::move(mSource
),
1625 Some(nsDependentCString(contentType
.get())), newOriginalURI
,
1626 redirectFlags
, channelId
);
1629 mSecurityInfo
= securityInfo
;
1631 nsCOMPtr
<nsIChannel
> newChannel
;
1632 rv
= SetupRedirect(newOriginalURI
, &responseHead
, redirectFlags
,
1633 getter_AddRefs(newChannel
));
1635 if (NS_SUCCEEDED(rv
)) {
1636 MOZ_ALWAYS_SUCCEEDS(newChannel
->SetLoadFlags(newLoadFlags
));
1638 if (mRedirectChannelChild
) {
1639 // Set the channelId allocated in parent to the child instance
1640 nsCOMPtr
<nsIHttpChannel
> httpChannel
=
1641 do_QueryInterface(mRedirectChannelChild
);
1643 rv
= httpChannel
->SetChannelId(channelId
);
1644 MOZ_ASSERT(NS_SUCCEEDED(rv
));
1646 mRedirectChannelChild
->ConnectParent(registrarId
);
1649 nsCOMPtr
<nsISerialEventTarget
> target
= GetNeckoTarget();
1652 rv
= gHttpHandler
->AsyncOnChannelRedirect(this, newChannel
, redirectFlags
,
1656 if (NS_FAILED(rv
)) OnRedirectVerifyCallback(rv
);
1659 mozilla::ipc::IPCResult
HttpChannelChild::RecvRedirect3Complete() {
1660 LOG(("HttpChannelChild::RecvRedirect3Complete [this=%p]\n", this));
1661 nsCOMPtr
<nsIChannel
> redirectChannel
=
1662 do_QueryInterface(mRedirectChannelChild
);
1663 MOZ_ASSERT(redirectChannel
);
1664 mEventQ
->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
1665 this, [self
= UnsafePtr
<HttpChannelChild
>(this), redirectChannel
]() {
1666 nsresult rv
= NS_OK
;
1667 Unused
<< self
->GetStatus(&rv
);
1668 if (NS_FAILED(rv
)) {
1669 // Pre-redirect channel was canceled. Call |HandleAsyncAbort|, so
1670 // mListener's OnStart/StopRequest can be called. Nothing else will
1671 // trigger these notification after this point.
1672 // We do this before |CompleteRedirectSetup|, so post-redirect channel
1673 // stays unopened and we also make sure that OnStart/StopRequest won't
1675 self
->HandleAsyncAbort();
1677 nsCOMPtr
<nsIHttpChannelChild
> chan
=
1678 do_QueryInterface(redirectChannel
);
1679 RefPtr
<HttpChannelChild
> httpChannelChild
=
1680 static_cast<HttpChannelChild
*>(chan
.get());
1681 if (httpChannelChild
) {
1682 // For sending an IPC message to parent channel so that the loading
1683 // can be cancelled.
1684 Unused
<< httpChannelChild
->CancelWithReason(
1685 rv
, "HttpChannelChild Redirect3 failed"_ns
);
1687 // The post-redirect channel could still get OnStart/StopRequest IPC
1688 // messages from parent, but the mListener is still null. So, we
1689 // call |DoNotifyListener| to pretend that OnStart/StopRequest are
1691 httpChannelChild
->DoNotifyListener();
1696 self
->Redirect3Complete();
1701 mozilla::ipc::IPCResult
HttpChannelChild::RecvRedirectFailed(
1702 const nsresult
& status
) {
1703 LOG(("HttpChannelChild::RecvRedirectFailed this=%p status=%X\n", this,
1704 static_cast<uint32_t>(status
)));
1705 mEventQ
->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
1706 this, [self
= UnsafePtr
<HttpChannelChild
>(this), status
]() {
1707 nsCOMPtr
<nsIRedirectResultListener
> vetoHook
;
1708 self
->GetCallback(vetoHook
);
1710 vetoHook
->OnRedirectResult(status
);
1713 if (RefPtr
<HttpChannelChild
> httpChannelChild
=
1714 do_QueryObject(self
->mRedirectChannelChild
)) {
1715 // For sending an IPC message to parent channel so that the loading
1716 // can be cancelled.
1717 Unused
<< httpChannelChild
->CancelWithReason(
1718 status
, "HttpChannelChild RecvRedirectFailed"_ns
);
1720 // The post-redirect channel could still get OnStart/StopRequest IPC
1721 // messages from parent, but the mListener is still null. So, we
1722 // call |DoNotifyListener| to pretend that OnStart/StopRequest are
1724 httpChannelChild
->DoNotifyListener();
1731 void HttpChannelChild::ProcessNotifyClassificationFlags(
1732 uint32_t aClassificationFlags
, bool aIsThirdParty
) {
1734 ("HttpChannelChild::ProcessNotifyClassificationFlags thirdparty=%d "
1735 "flags=%" PRIu32
" [this=%p]\n",
1736 static_cast<int>(aIsThirdParty
), aClassificationFlags
, this));
1737 MOZ_ASSERT(OnSocketThread());
1739 mEventQ
->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
1740 this, [self
= UnsafePtr
<HttpChannelChild
>(this), aClassificationFlags
,
1742 self
->AddClassificationFlags(aClassificationFlags
, aIsThirdParty
);
1746 void HttpChannelChild::ProcessSetClassifierMatchedInfo(
1747 const nsACString
& aList
, const nsACString
& aProvider
,
1748 const nsACString
& aFullHash
) {
1749 LOG(("HttpChannelChild::ProcessSetClassifierMatchedInfo [this=%p]\n", this));
1750 MOZ_ASSERT(OnSocketThread());
1752 mEventQ
->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
1754 [self
= UnsafePtr
<HttpChannelChild
>(this), aList
= nsCString(aList
),
1755 aProvider
= nsCString(aProvider
), aFullHash
= nsCString(aFullHash
)]() {
1756 self
->SetMatchedInfo(aList
, aProvider
, aFullHash
);
1760 void HttpChannelChild::ProcessSetClassifierMatchedTrackingInfo(
1761 const nsACString
& aLists
, const nsACString
& aFullHashes
) {
1762 LOG(("HttpChannelChild::ProcessSetClassifierMatchedTrackingInfo [this=%p]\n",
1764 MOZ_ASSERT(OnSocketThread());
1766 nsTArray
<nsCString
> lists
, fullhashes
;
1767 for (const nsACString
& token
: aLists
.Split(',')) {
1768 lists
.AppendElement(token
);
1770 for (const nsACString
& token
: aFullHashes
.Split(',')) {
1771 fullhashes
.AppendElement(token
);
1774 mEventQ
->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
1775 this, [self
= UnsafePtr
<HttpChannelChild
>(this),
1776 lists
= CopyableTArray
{std::move(lists
)},
1777 fullhashes
= CopyableTArray
{std::move(fullhashes
)}]() {
1778 self
->SetMatchedTrackingInfo(lists
, fullhashes
);
1782 // Completes the redirect and cleans up the old channel.
1783 void HttpChannelChild::Redirect3Complete() {
1784 LOG(("HttpChannelChild::Redirect3Complete [this=%p]\n", this));
1785 MOZ_ASSERT(NS_IsMainThread());
1787 // Using an error as the default so that when we fail to forward this redirect
1788 // to the target channel, we make sure to notify the current listener from
1789 // CleanupRedirectingChannel.
1790 nsresult rv
= NS_BINDING_ABORTED
;
1792 nsCOMPtr
<nsIRedirectResultListener
> vetoHook
;
1793 GetCallback(vetoHook
);
1795 vetoHook
->OnRedirectResult(NS_OK
);
1798 // Chrome channel has been AsyncOpen'd. Reflect this in child.
1799 if (mRedirectChannelChild
) {
1800 rv
= mRedirectChannelChild
->CompleteRedirectSetup(mListener
);
1801 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1802 mSuccesfullyRedirected
= NS_SUCCEEDED(rv
);
1806 CleanupRedirectingChannel(rv
);
1809 void HttpChannelChild::CleanupRedirectingChannel(nsresult rv
) {
1810 // Redirecting to new channel: shut this down and init new channel
1811 if (mLoadGroup
) mLoadGroup
->RemoveRequest(this, nullptr, NS_BINDING_ABORTED
);
1813 if (NS_SUCCEEDED(rv
)) {
1814 mLoadInfo
->AppendRedirectHistoryEntry(this, false);
1816 NS_WARNING("CompleteRedirectSetup failed, HttpChannelChild already open?");
1819 // Release ref to new channel.
1820 mRedirectChannelChild
= nullptr;
1822 NotifyOrReleaseListeners(rv
);
1823 CleanupBackgroundChannel();
1826 //-----------------------------------------------------------------------------
1827 // HttpChannelChild::nsIChildChannel
1828 //-----------------------------------------------------------------------------
1831 HttpChannelChild::ConnectParent(uint32_t registrarId
) {
1832 LOG(("HttpChannelChild::ConnectParent [this=%p, id=%" PRIu32
"]\n", this,
1834 MOZ_ASSERT(NS_IsMainThread());
1835 mozilla::dom::BrowserChild
* browserChild
= nullptr;
1836 nsCOMPtr
<nsIBrowserChild
> iBrowserChild
;
1837 GetCallback(iBrowserChild
);
1838 if (iBrowserChild
) {
1840 static_cast<mozilla::dom::BrowserChild
*>(iBrowserChild
.get());
1843 if (browserChild
&& !browserChild
->IPCOpen()) {
1844 return NS_ERROR_FAILURE
;
1847 ContentChild
* cc
= static_cast<ContentChild
*>(gNeckoChild
->Manager());
1848 if (cc
->IsShuttingDown()) {
1849 return NS_ERROR_FAILURE
;
1852 HttpBaseChannel::SetDocshellUserAgentOverride();
1854 // This must happen before the constructor message is sent. Otherwise messages
1855 // from the parent could arrive quickly and be delivered to the wrong event
1860 MOZ_ASSERT(browserChild
->WebNavigation());
1861 if (BrowsingContext
* bc
= browserChild
->GetBrowsingContext()) {
1862 mBrowserId
= bc
->BrowserId();
1866 HttpChannelConnectArgs
connectArgs(registrarId
);
1867 if (!gNeckoChild
->SendPHttpChannelConstructor(
1868 this, browserChild
, IPC::SerializedLoadContext(this), connectArgs
)) {
1869 return NS_ERROR_FAILURE
;
1873 MutexAutoLock
lock(mBgChildMutex
);
1875 MOZ_ASSERT(!mBgChild
);
1876 MOZ_ASSERT(!mBgInitFailCallback
);
1878 mBgInitFailCallback
= NewRunnableMethod
<nsresult
>(
1879 "HttpChannelChild::OnRedirectVerifyCallback", this,
1880 &HttpChannelChild::OnRedirectVerifyCallback
, NS_ERROR_FAILURE
);
1882 RefPtr
<HttpBackgroundChannelChild
> bgChild
=
1883 new HttpBackgroundChannelChild();
1885 MOZ_RELEASE_ASSERT(gSocketTransportService
);
1887 RefPtr
<HttpChannelChild
> self
= this;
1888 nsresult rv
= gSocketTransportService
->Dispatch(
1889 NewRunnableMethod
<RefPtr
<HttpChannelChild
>>(
1890 "HttpBackgroundChannelChild::Init", bgChild
,
1891 &HttpBackgroundChannelChild::Init
, std::move(self
)),
1892 NS_DISPATCH_NORMAL
);
1894 if (NS_WARN_IF(NS_FAILED(rv
))) {
1898 mBgChild
= std::move(bgChild
);
1899 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1900 mEverHadBgChildAtConnectParent
= true;
1904 // Should wait for CompleteRedirectSetup to set the listener.
1906 MOZ_ASSERT(!mSuspendForWaitCompleteRedirectSetup
);
1907 mSuspendForWaitCompleteRedirectSetup
= true;
1909 // Connect to socket process after mEventQ is suspended.
1910 MaybeConnectToSocketProcess();
1916 HttpChannelChild::CompleteRedirectSetup(nsIStreamListener
* aListener
) {
1917 LOG(("HttpChannelChild::CompleteRedirectSetup [this=%p]\n", this));
1918 MOZ_ASSERT(NS_IsMainThread());
1920 NS_ENSURE_TRUE(!LoadIsPending(), NS_ERROR_IN_PROGRESS
);
1921 NS_ENSURE_TRUE(!LoadWasOpened(), NS_ERROR_ALREADY_OPENED
);
1923 // Resume the suspension in ConnectParent.
1924 auto eventQueueResumeGuard
= MakeScopeExit([&] {
1925 MOZ_ASSERT(mSuspendForWaitCompleteRedirectSetup
);
1927 mSuspendForWaitCompleteRedirectSetup
= false;
1931 * No need to check for cancel: we don't get here if nsHttpChannel canceled
1932 * before AsyncOpen(); if it's canceled after that, OnStart/Stop will just
1933 * get called with error code as usual. So just setup mListener and make the
1934 * channel reflect AsyncOpen'ed state.
1937 mLastStatusReported
= TimeStamp::Now();
1938 if (profiler_thread_is_being_profiled_for_markers()) {
1939 nsAutoCString requestMethod
;
1940 GetRequestMethod(requestMethod
);
1942 profiler_add_network_marker(
1943 mURI
, requestMethod
, mPriority
, mChannelId
, NetworkLoadType::LOAD_START
,
1944 mChannelCreationTimestamp
, mLastStatusReported
, 0, kCacheUnknown
,
1945 mLoadInfo
->GetInnerWindowID(),
1946 mLoadInfo
->GetOriginAttributes().mPrivateBrowsingId
> 0);
1948 StoreIsPending(true);
1949 StoreWasOpened(true);
1950 mListener
= aListener
;
1952 // add ourselves to the load group.
1953 if (mLoadGroup
) mLoadGroup
->AddRequest(this, nullptr);
1955 // We already have an open IPDL connection to the parent. If on-modify-request
1956 // listeners or load group observers canceled us, let the parent handle it
1957 // and send it back to us naturally.
1961 //-----------------------------------------------------------------------------
1962 // HttpChannelChild::nsIAsyncVerifyRedirectCallback
1963 //-----------------------------------------------------------------------------
1966 HttpChannelChild::OnRedirectVerifyCallback(nsresult aResult
) {
1967 LOG(("HttpChannelChild::OnRedirectVerifyCallback [this=%p]\n", this));
1968 MOZ_ASSERT(NS_IsMainThread());
1969 nsCOMPtr
<nsIURI
> redirectURI
;
1971 DebugOnly
<nsresult
> rv
= NS_OK
;
1973 nsCOMPtr
<nsIHttpChannel
> newHttpChannel
=
1974 do_QueryInterface(mRedirectChannelChild
);
1976 if (NS_SUCCEEDED(aResult
) && !mRedirectChannelChild
) {
1977 // mRedirectChannelChild doesn't exist means we're redirecting to a protocol
1978 // that doesn't implement nsIChildChannel. The redirect result should be set
1979 // as failed by veto listeners and shouldn't enter this condition. As the
1980 // last resort, we synthesize the error result as NS_ERROR_DOM_BAD_URI here
1981 // to let nsHttpChannel::ContinueProcessResponse2 know it's redirecting to
1982 // another protocol and throw an error.
1983 LOG((" redirecting to a protocol that doesn't implement nsIChildChannel"));
1984 aResult
= NS_ERROR_DOM_BAD_URI
;
1987 nsCOMPtr
<nsIReferrerInfo
> referrerInfo
;
1988 if (newHttpChannel
) {
1989 // Must not be called until after redirect observers called.
1990 newHttpChannel
->SetOriginalURI(mOriginalURI
);
1991 referrerInfo
= newHttpChannel
->GetReferrerInfo();
1994 RequestHeaderTuples emptyHeaders
;
1995 RequestHeaderTuples
* headerTuples
= &emptyHeaders
;
1996 nsLoadFlags loadFlags
= 0;
1997 Maybe
<CorsPreflightArgs
> corsPreflightArgs
;
1999 nsCOMPtr
<nsIHttpChannelChild
> newHttpChannelChild
=
2000 do_QueryInterface(mRedirectChannelChild
);
2001 if (newHttpChannelChild
&& NS_SUCCEEDED(aResult
)) {
2002 rv
= newHttpChannelChild
->AddCookiesToRequest();
2003 MOZ_ASSERT(NS_SUCCEEDED(rv
));
2004 rv
= newHttpChannelChild
->GetClientSetRequestHeaders(&headerTuples
);
2005 MOZ_ASSERT(NS_SUCCEEDED(rv
));
2006 newHttpChannelChild
->GetClientSetCorsPreflightParameters(corsPreflightArgs
);
2009 if (NS_SUCCEEDED(aResult
)) {
2010 // Note: this is where we would notify "http-on-modify-response" observers.
2011 // We have deliberately disabled this for child processes (see bug 806753)
2013 // After we verify redirect, nsHttpChannel may hit the network: must give
2014 // "http-on-modify-request" observers the chance to cancel before that.
2015 // base->CallOnModifyRequestObservers();
2017 nsCOMPtr
<nsIHttpChannelInternal
> newHttpChannelInternal
=
2018 do_QueryInterface(mRedirectChannelChild
);
2019 if (newHttpChannelInternal
) {
2020 Unused
<< newHttpChannelInternal
->GetApiRedirectToURI(
2021 getter_AddRefs(redirectURI
));
2024 nsCOMPtr
<nsIRequest
> request
= do_QueryInterface(mRedirectChannelChild
);
2026 request
->GetLoadFlags(&loadFlags
);
2030 uint32_t sourceRequestBlockingReason
= 0;
2031 mLoadInfo
->GetRequestBlockingReason(&sourceRequestBlockingReason
);
2033 Maybe
<ChildLoadInfoForwarderArgs
> targetLoadInfoForwarder
;
2034 nsCOMPtr
<nsIChannel
> newChannel
= do_QueryInterface(mRedirectChannelChild
);
2036 ChildLoadInfoForwarderArgs args
;
2037 nsCOMPtr
<nsILoadInfo
> loadInfo
= newChannel
->LoadInfo();
2038 LoadInfoToChildLoadInfoForwarder(loadInfo
, &args
);
2039 targetLoadInfoForwarder
.emplace(args
);
2043 SendRedirect2Verify(aResult
, *headerTuples
, sourceRequestBlockingReason
,
2044 targetLoadInfoForwarder
, loadFlags
, referrerInfo
,
2045 redirectURI
, corsPreflightArgs
);
2051 //-----------------------------------------------------------------------------
2052 // HttpChannelChild::nsIRequest
2053 //-----------------------------------------------------------------------------
2055 NS_IMETHODIMP
HttpChannelChild::SetCanceledReason(const nsACString
& aReason
) {
2056 return SetCanceledReasonImpl(aReason
);
2059 NS_IMETHODIMP
HttpChannelChild::GetCanceledReason(nsACString
& aReason
) {
2060 return GetCanceledReasonImpl(aReason
);
2064 HttpChannelChild::CancelWithReason(nsresult aStatus
,
2065 const nsACString
& aReason
) {
2066 return CancelWithReasonImpl(aStatus
, aReason
);
2070 HttpChannelChild::Cancel(nsresult aStatus
) {
2071 LOG(("HttpChannelChild::Cancel [this=%p, status=%" PRIx32
"]\n", this,
2072 static_cast<uint32_t>(aStatus
)));
2073 // only logging on parent is necessary
2074 Maybe
<nsCString
> logStack
= CallingScriptLocationString();
2075 Maybe
<nsCString
> logOnParent
;
2076 if (logStack
.isSome()) {
2077 logOnParent
= Some(""_ns
);
2078 logOnParent
->AppendPrintf(
2079 "[this=%p] cancelled call in child process from script: %s", this,
2083 MOZ_ASSERT(NS_IsMainThread());
2086 // If this cancel occurs before nsHttpChannel has been set up, AsyncOpen
2087 // is responsible for cleaning up.
2091 bool remoteChannelExists
= RemoteChannelExists();
2092 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
2093 mCanSendAtCancel
= CanSend();
2094 mRemoteChannelExistedAtCancel
= remoteChannelExists
;
2097 if (remoteChannelExists
) {
2098 SendCancel(aStatus
, mLoadInfo
->GetRequestBlockingReason(),
2099 mCanceledReason
, logOnParent
);
2100 } else if (MOZ_UNLIKELY(!LoadOnStartRequestCalled() ||
2101 !LoadOnStopRequestCalled())) {
2102 Unused
<< AsyncAbort(mStatus
);
2109 HttpChannelChild::Suspend() {
2110 LOG(("HttpChannelChild::Suspend [this=%p, mSuspendCount=%" PRIu32
"\n", this,
2111 mSuspendCount
+ 1));
2112 MOZ_ASSERT(NS_IsMainThread());
2114 LogCallingScriptLocation(this);
2116 // SendSuspend only once, when suspend goes from 0 to 1.
2117 // Don't SendSuspend at all if we're diverting callbacks to the parent;
2118 // suspend will be called at the correct time in the parent itself.
2119 if (!mSuspendCount
++) {
2120 if (RemoteChannelExists()) {
2122 mSuspendSent
= true;
2131 HttpChannelChild::Resume() {
2132 LOG(("HttpChannelChild::Resume [this=%p, mSuspendCount=%" PRIu32
"\n", this,
2133 mSuspendCount
- 1));
2134 MOZ_ASSERT(NS_IsMainThread());
2135 NS_ENSURE_TRUE(mSuspendCount
> 0, NS_ERROR_UNEXPECTED
);
2137 LogCallingScriptLocation(this);
2139 nsresult rv
= NS_OK
;
2141 // SendResume only once, when suspend count drops to 0.
2142 // Don't SendResume at all if we're diverting callbacks to the parent (unless
2143 // suspend was sent earlier); otherwise, resume will be called at the correct
2144 // time in the parent itself.
2145 if (!--mSuspendCount
) {
2146 if (RemoteChannelExists() && mSuspendSent
) {
2149 if (mCallOnResume
) {
2150 nsCOMPtr
<nsISerialEventTarget
> neckoTarget
= GetNeckoTarget();
2151 MOZ_ASSERT(neckoTarget
);
2153 RefPtr
<HttpChannelChild
> self
= this;
2154 std::function
<nsresult(HttpChannelChild
*)> callOnResume
= nullptr;
2155 std::swap(callOnResume
, mCallOnResume
);
2156 rv
= neckoTarget
->Dispatch(
2157 NS_NewRunnableFunction(
2158 "net::HttpChannelChild::mCallOnResume",
2159 [callOnResume
, self
{std::move(self
)}]() { callOnResume(self
); }),
2160 NS_DISPATCH_NORMAL
);
2168 //-----------------------------------------------------------------------------
2169 // HttpChannelChild::nsIChannel
2170 //-----------------------------------------------------------------------------
2173 HttpChannelChild::GetSecurityInfo(nsITransportSecurityInfo
** aSecurityInfo
) {
2174 NS_ENSURE_ARG_POINTER(aSecurityInfo
);
2175 *aSecurityInfo
= do_AddRef(mSecurityInfo
).take();
2180 HttpChannelChild::AsyncOpen(nsIStreamListener
* aListener
) {
2181 LOG(("HttpChannelChild::AsyncOpen [this=%p uri=%s]\n", this, mSpec
.get()));
2183 nsresult rv
= AsyncOpenInternal(aListener
);
2184 if (NS_FAILED(rv
)) {
2185 uint32_t blockingReason
= 0;
2186 mLoadInfo
->GetRequestBlockingReason(&blockingReason
);
2188 ("HttpChannelChild::AsyncOpen failed [this=%p rv=0x%08x "
2189 "blocking-reason=%u]\n",
2190 this, static_cast<uint32_t>(rv
), blockingReason
));
2192 gHttpHandler
->OnFailedOpeningRequest(this);
2195 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
2196 mAsyncOpenSucceeded
= NS_SUCCEEDED(rv
);
2201 nsresult
HttpChannelChild::AsyncOpenInternal(nsIStreamListener
* aListener
) {
2204 nsCOMPtr
<nsIStreamListener
> listener
= aListener
;
2205 rv
= nsContentSecurityManager::doContentSecurityCheck(this, listener
);
2206 if (NS_WARN_IF(NS_FAILED(rv
))) {
2212 mLoadInfo
->GetSecurityMode() == 0 ||
2213 mLoadInfo
->GetInitialSecurityCheckDone() ||
2214 (mLoadInfo
->GetSecurityMode() ==
2215 nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL
&&
2216 mLoadInfo
->GetLoadingPrincipal() &&
2217 mLoadInfo
->GetLoadingPrincipal()->IsSystemPrincipal()),
2218 "security flags in loadInfo but doContentSecurityCheck() not called");
2220 LogCallingScriptLocation(this);
2222 if (!mLoadGroup
&& !mCallbacks
) {
2223 // If no one called SetLoadGroup or SetNotificationCallbacks, the private
2224 // state has not been updated on PrivateBrowsingChannel (which we derive
2225 // from) Hence, we have to call UpdatePrivateBrowsing() here
2226 UpdatePrivateBrowsing();
2230 AssertPrivateBrowsingId();
2238 NS_ENSURE_TRUE(gNeckoChild
!= nullptr, NS_ERROR_FAILURE
);
2239 NS_ENSURE_ARG_POINTER(listener
);
2240 NS_ENSURE_TRUE(!LoadIsPending(), NS_ERROR_IN_PROGRESS
);
2241 NS_ENSURE_TRUE(!LoadWasOpened(), NS_ERROR_ALREADY_OPENED
);
2243 if (MaybeWaitForUploadStreamNormalization(listener
, nullptr)) {
2247 if (!LoadAsyncOpenTimeOverriden()) {
2248 mAsyncOpenTime
= TimeStamp::Now();
2251 // Port checked in parent, but duplicate here so we can return with error
2253 rv
= NS_CheckPortSafety(mURI
);
2254 if (NS_FAILED(rv
)) {
2259 nsAutoCString cookie
;
2260 if (NS_SUCCEEDED(mRequestHead
.GetHeader(nsHttp::Cookie
, cookie
))) {
2261 mUserSetCookieHeader
= cookie
;
2264 DebugOnly
<nsresult
> check
= AddCookiesToRequest();
2265 MOZ_ASSERT(NS_SUCCEEDED(check
));
2268 // NOTE: From now on we must return NS_OK; all errors must be handled via
2269 // OnStart/OnStopRequest
2272 // We notify "http-on-opening-request" observers in the child
2273 // process so that devtools can capture a stack trace at the
2274 // appropriate spot. See bug 806753 for some information about why
2275 // other http-* notifications are disabled in child processes.
2276 gHttpHandler
->OnOpeningRequest(this);
2278 mLastStatusReported
= TimeStamp::Now();
2279 if (profiler_thread_is_being_profiled_for_markers()) {
2280 nsAutoCString requestMethod
;
2281 GetRequestMethod(requestMethod
);
2283 profiler_add_network_marker(
2284 mURI
, requestMethod
, mPriority
, mChannelId
, NetworkLoadType::LOAD_START
,
2285 mChannelCreationTimestamp
, mLastStatusReported
, 0, kCacheUnknown
,
2286 mLoadInfo
->GetInnerWindowID(),
2287 mLoadInfo
->GetOriginAttributes().mPrivateBrowsingId
> 0);
2289 StoreIsPending(true);
2290 StoreWasOpened(true);
2291 mListener
= listener
;
2294 // We may have been canceled already, either by on-modify-request
2295 // listeners or by load group observers; in that case, don't create IPDL
2296 // connection. See nsHttpChannel::AsyncOpen().
2301 // Set user agent override from docshell
2302 HttpBaseChannel::SetDocshellUserAgentOverride();
2304 rv
= ContinueAsyncOpen();
2305 if (NS_FAILED(rv
)) {
2311 // Assigns an nsISerialEventTarget to our IPDL actor so that IPC messages are
2312 // sent to the correct DocGroup/TabGroup.
2313 void HttpChannelChild::SetEventTarget() {
2314 MutexAutoLock
lock(mEventTargetMutex
);
2315 mNeckoTarget
= GetMainThreadSerialEventTarget();
2318 already_AddRefed
<nsISerialEventTarget
> HttpChannelChild::GetNeckoTarget() {
2319 nsCOMPtr
<nsISerialEventTarget
> target
;
2321 MutexAutoLock
lock(mEventTargetMutex
);
2322 target
= mNeckoTarget
;
2326 target
= GetMainThreadSerialEventTarget();
2328 return target
.forget();
2331 already_AddRefed
<nsIEventTarget
> HttpChannelChild::GetODATarget() {
2332 nsCOMPtr
<nsIEventTarget
> target
;
2334 MutexAutoLock
lock(mEventTargetMutex
);
2336 target
= mODATarget
;
2338 target
= mNeckoTarget
;
2343 target
= GetMainThreadSerialEventTarget();
2345 return target
.forget();
2348 nsresult
HttpChannelChild::ContinueAsyncOpen() {
2351 // Send request to the chrome process...
2354 mozilla::dom::BrowserChild
* browserChild
= nullptr;
2355 nsCOMPtr
<nsIBrowserChild
> iBrowserChild
;
2356 GetCallback(iBrowserChild
);
2357 if (iBrowserChild
) {
2359 static_cast<mozilla::dom::BrowserChild
*>(iBrowserChild
.get());
2362 // This id identifies the inner window's top-level document,
2363 // which changes on every new load or navigation.
2364 uint64_t contentWindowId
= 0;
2365 TimeStamp navigationStartTimeStamp
;
2367 MOZ_ASSERT(browserChild
->WebNavigation());
2368 if (RefPtr
<Document
> document
= browserChild
->GetTopLevelDocument()) {
2369 contentWindowId
= document
->InnerWindowID();
2370 nsDOMNavigationTiming
* navigationTiming
= document
->GetNavigationTiming();
2371 if (navigationTiming
) {
2372 navigationStartTimeStamp
=
2373 navigationTiming
->GetNavigationStartTimeStamp();
2376 if (BrowsingContext
* bc
= browserChild
->GetBrowsingContext()) {
2377 mBrowserId
= bc
->BrowserId();
2380 SetTopLevelContentWindowId(contentWindowId
);
2382 if (browserChild
&& !browserChild
->IPCOpen()) {
2383 return NS_ERROR_FAILURE
;
2386 ContentChild
* cc
= static_cast<ContentChild
*>(gNeckoChild
->Manager());
2387 if (cc
->IsShuttingDown()) {
2388 return NS_ERROR_FAILURE
;
2391 // add ourselves to the load group.
2393 mLoadGroup
->AddRequest(this, nullptr);
2396 HttpChannelOpenArgs openArgs
;
2397 // No access to HttpChannelOpenArgs members, but they each have a
2398 // function with the struct name that returns a ref.
2399 openArgs
.uri() = mURI
;
2400 openArgs
.original() = mOriginalURI
;
2401 openArgs
.doc() = mDocumentURI
;
2402 openArgs
.apiRedirectTo() = mAPIRedirectToURI
;
2403 openArgs
.loadFlags() = mLoadFlags
;
2404 openArgs
.requestHeaders() = mClientSetRequestHeaders
;
2405 mRequestHead
.Method(openArgs
.requestMethod());
2406 openArgs
.preferredAlternativeTypes() = mPreferredCachedAltDataTypes
.Clone();
2407 openArgs
.referrerInfo() = mReferrerInfo
;
2409 if (mUploadStream
) {
2410 MOZ_ALWAYS_TRUE(SerializeIPCStream(do_AddRef(mUploadStream
),
2411 openArgs
.uploadStream(),
2412 /* aAllowLazy */ false));
2415 Maybe
<CorsPreflightArgs
> optionalCorsPreflightArgs
;
2416 GetClientSetCorsPreflightParameters(optionalCorsPreflightArgs
);
2418 // NB: This call forces us to cache mTopWindowURI if we haven't already.
2419 nsCOMPtr
<nsIURI
> uri
;
2420 GetTopWindowURI(mURI
, getter_AddRefs(uri
));
2422 openArgs
.topWindowURI() = mTopWindowURI
;
2424 openArgs
.preflightArgs() = optionalCorsPreflightArgs
;
2426 openArgs
.uploadStreamHasHeaders() = LoadUploadStreamHasHeaders();
2427 openArgs
.priority() = mPriority
;
2428 openArgs
.classOfService() = mClassOfService
;
2429 openArgs
.redirectionLimit() = mRedirectionLimit
;
2430 openArgs
.allowSTS() = LoadAllowSTS();
2431 openArgs
.thirdPartyFlags() = LoadThirdPartyFlags();
2432 openArgs
.resumeAt() = mSendResumeAt
;
2433 openArgs
.startPos() = mStartPos
;
2434 openArgs
.entityID() = mEntityID
;
2435 openArgs
.allowSpdy() = LoadAllowSpdy();
2436 openArgs
.allowHttp3() = LoadAllowHttp3();
2437 openArgs
.allowAltSvc() = LoadAllowAltSvc();
2438 openArgs
.beConservative() = LoadBeConservative();
2439 openArgs
.bypassProxy() = BypassProxy();
2440 openArgs
.tlsFlags() = mTlsFlags
;
2441 openArgs
.initialRwin() = mInitialRwin
;
2443 openArgs
.cacheKey() = mCacheKey
;
2445 openArgs
.blockAuthPrompt() = LoadBlockAuthPrompt();
2447 openArgs
.allowStaleCacheContent() = LoadAllowStaleCacheContent();
2448 openArgs
.preferCacheLoadOverBypass() = LoadPreferCacheLoadOverBypass();
2450 openArgs
.contentTypeHint() = mContentTypeHint
;
2452 rv
= mozilla::ipc::LoadInfoToLoadInfoArgs(mLoadInfo
, &openArgs
.loadInfo());
2453 NS_ENSURE_SUCCESS(rv
, rv
);
2455 EnsureRequestContextID();
2456 openArgs
.requestContextID() = mRequestContextID
;
2458 openArgs
.requestMode() = mRequestMode
;
2459 openArgs
.redirectMode() = mRedirectMode
;
2461 openArgs
.channelId() = mChannelId
;
2463 openArgs
.integrityMetadata() = mIntegrityMetadata
;
2465 openArgs
.contentWindowId() = contentWindowId
;
2466 openArgs
.browserId() = mBrowserId
;
2468 LOG(("HttpChannelChild::ContinueAsyncOpen this=%p gid=%" PRIu64
2469 " browser id=%" PRIx64
,
2470 this, mChannelId
, mBrowserId
));
2472 openArgs
.launchServiceWorkerStart() = mLaunchServiceWorkerStart
;
2473 openArgs
.launchServiceWorkerEnd() = mLaunchServiceWorkerEnd
;
2474 openArgs
.dispatchFetchEventStart() = mDispatchFetchEventStart
;
2475 openArgs
.dispatchFetchEventEnd() = mDispatchFetchEventEnd
;
2476 openArgs
.handleFetchEventStart() = mHandleFetchEventStart
;
2477 openArgs
.handleFetchEventEnd() = mHandleFetchEventEnd
;
2479 openArgs
.forceMainDocumentChannel() = LoadForceMainDocumentChannel();
2481 openArgs
.navigationStartTimeStamp() = navigationStartTimeStamp
;
2482 openArgs
.earlyHintPreloaderId() = mEarlyHintPreloaderId
;
2484 openArgs
.classicScriptHintCharset() = mClassicScriptHintCharset
;
2486 RefPtr
<Document
> doc
;
2487 mLoadInfo
->GetLoadingDocument(getter_AddRefs(doc
));
2490 nsAutoString documentCharacterSet
;
2491 doc
->GetCharacterSet(documentCharacterSet
);
2492 openArgs
.documentCharacterSet() = documentCharacterSet
;
2495 // This must happen before the constructor message is sent. Otherwise messages
2496 // from the parent could arrive quickly and be delivered to the wrong event
2500 if (!gNeckoChild
->SendPHttpChannelConstructor(
2501 this, browserChild
, IPC::SerializedLoadContext(this), openArgs
)) {
2502 return NS_ERROR_FAILURE
;
2506 MutexAutoLock
lock(mBgChildMutex
);
2508 MOZ_RELEASE_ASSERT(gSocketTransportService
);
2510 // Service worker might use the same HttpChannelChild to do async open
2511 // twice. Need to disconnect with previous background channel before
2512 // creating the new one, to prevent receiving further notification
2515 RefPtr
<HttpBackgroundChannelChild
> prevBgChild
= std::move(mBgChild
);
2516 gSocketTransportService
->Dispatch(
2517 NewRunnableMethod("HttpBackgroundChannelChild::OnChannelClosed",
2519 &HttpBackgroundChannelChild::OnChannelClosed
),
2520 NS_DISPATCH_NORMAL
);
2523 MOZ_ASSERT(!mBgInitFailCallback
);
2525 mBgInitFailCallback
= NewRunnableMethod
<nsresult
>(
2526 "HttpChannelChild::FailedAsyncOpen", this,
2527 &HttpChannelChild::FailedAsyncOpen
, NS_ERROR_FAILURE
);
2529 RefPtr
<HttpBackgroundChannelChild
> bgChild
=
2530 new HttpBackgroundChannelChild();
2532 RefPtr
<HttpChannelChild
> self
= this;
2533 nsresult rv
= gSocketTransportService
->Dispatch(
2534 NewRunnableMethod
<RefPtr
<HttpChannelChild
>>(
2535 "HttpBackgroundChannelChild::Init", bgChild
,
2536 &HttpBackgroundChannelChild::Init
, self
),
2537 NS_DISPATCH_NORMAL
);
2539 if (NS_WARN_IF(NS_FAILED(rv
))) {
2543 mBgChild
= std::move(bgChild
);
2544 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
2545 mEverHadBgChildAtAsyncOpen
= true;
2549 MaybeConnectToSocketProcess();
2554 //-----------------------------------------------------------------------------
2555 // HttpChannelChild::nsIHttpChannel
2556 //-----------------------------------------------------------------------------
2559 HttpChannelChild::SetRequestHeader(const nsACString
& aHeader
,
2560 const nsACString
& aValue
, bool aMerge
) {
2561 LOG(("HttpChannelChild::SetRequestHeader [this=%p]\n", this));
2562 nsresult rv
= HttpBaseChannel::SetRequestHeader(aHeader
, aValue
, aMerge
);
2563 if (NS_FAILED(rv
)) return rv
;
2565 RequestHeaderTuple
* tuple
= mClientSetRequestHeaders
.AppendElement();
2566 if (!tuple
) return NS_ERROR_OUT_OF_MEMORY
;
2568 tuple
->mHeader
= aHeader
;
2569 tuple
->mValue
= aValue
;
2570 tuple
->mMerge
= aMerge
;
2571 tuple
->mEmpty
= false;
2576 HttpChannelChild::SetEmptyRequestHeader(const nsACString
& aHeader
) {
2577 LOG(("HttpChannelChild::SetEmptyRequestHeader [this=%p]\n", this));
2578 nsresult rv
= HttpBaseChannel::SetEmptyRequestHeader(aHeader
);
2579 if (NS_FAILED(rv
)) return rv
;
2581 RequestHeaderTuple
* tuple
= mClientSetRequestHeaders
.AppendElement();
2582 if (!tuple
) return NS_ERROR_OUT_OF_MEMORY
;
2584 tuple
->mHeader
= aHeader
;
2585 tuple
->mMerge
= false;
2586 tuple
->mEmpty
= true;
2591 HttpChannelChild::RedirectTo(nsIURI
* newURI
) {
2592 // disabled until/unless addons run in child or something else needs this
2593 return NS_ERROR_NOT_IMPLEMENTED
;
2597 HttpChannelChild::UpgradeToSecure() {
2598 // disabled until/unless addons run in child or something else needs this
2599 return NS_ERROR_NOT_IMPLEMENTED
;
2603 HttpChannelChild::GetProtocolVersion(nsACString
& aProtocolVersion
) {
2604 aProtocolVersion
= mProtocolVersion
;
2608 //-----------------------------------------------------------------------------
2609 // HttpChannelChild::nsIHttpChannelInternal
2610 //-----------------------------------------------------------------------------
2613 HttpChannelChild::GetIsAuthChannel(bool* aIsAuthChannel
) { DROP_DEAD(); }
2615 //-----------------------------------------------------------------------------
2616 // HttpChannelChild::nsICacheInfoChannel
2617 //-----------------------------------------------------------------------------
2620 HttpChannelChild::GetCacheTokenFetchCount(uint32_t* _retval
) {
2621 NS_ENSURE_ARG_POINTER(_retval
);
2622 MOZ_ASSERT(NS_IsMainThread());
2624 if (!mCacheEntryAvailable
&& !mAltDataCacheEntryAvailable
) {
2625 return NS_ERROR_NOT_AVAILABLE
;
2628 *_retval
= mCacheFetchCount
;
2633 HttpChannelChild::GetCacheTokenExpirationTime(uint32_t* _retval
) {
2634 NS_ENSURE_ARG_POINTER(_retval
);
2635 MOZ_ASSERT(NS_IsMainThread());
2637 if (!mCacheEntryAvailable
) return NS_ERROR_NOT_AVAILABLE
;
2639 *_retval
= mCacheExpirationTime
;
2644 HttpChannelChild::IsFromCache(bool* value
) {
2645 if (!LoadIsPending()) return NS_ERROR_NOT_AVAILABLE
;
2647 *value
= mIsFromCache
;
2652 HttpChannelChild::GetCacheEntryId(uint64_t* aCacheEntryId
) {
2653 bool fromCache
= false;
2654 if (NS_FAILED(IsFromCache(&fromCache
)) || !fromCache
||
2655 !mCacheEntryAvailable
) {
2656 return NS_ERROR_NOT_AVAILABLE
;
2659 *aCacheEntryId
= mCacheEntryId
;
2664 HttpChannelChild::IsRacing(bool* aIsRacing
) {
2665 if (!LoadAfterOnStartRequestBegun()) {
2666 return NS_ERROR_NOT_AVAILABLE
;
2668 *aIsRacing
= mIsRacing
;
2673 HttpChannelChild::GetCacheKey(uint32_t* cacheKey
) {
2674 MOZ_ASSERT(NS_IsMainThread());
2676 *cacheKey
= mCacheKey
;
2680 HttpChannelChild::SetCacheKey(uint32_t cacheKey
) {
2681 ENSURE_CALLED_BEFORE_ASYNC_OPEN();
2683 mCacheKey
= cacheKey
;
2688 HttpChannelChild::SetAllowStaleCacheContent(bool aAllowStaleCacheContent
) {
2689 StoreAllowStaleCacheContent(aAllowStaleCacheContent
);
2693 HttpChannelChild::GetAllowStaleCacheContent(bool* aAllowStaleCacheContent
) {
2694 NS_ENSURE_ARG(aAllowStaleCacheContent
);
2695 *aAllowStaleCacheContent
= LoadAllowStaleCacheContent();
2700 HttpChannelChild::SetForceValidateCacheContent(
2701 bool aForceValidateCacheContent
) {
2702 StoreForceValidateCacheContent(aForceValidateCacheContent
);
2706 HttpChannelChild::GetForceValidateCacheContent(
2707 bool* aForceValidateCacheContent
) {
2708 NS_ENSURE_ARG(aForceValidateCacheContent
);
2709 *aForceValidateCacheContent
= LoadForceValidateCacheContent();
2714 HttpChannelChild::SetPreferCacheLoadOverBypass(
2715 bool aPreferCacheLoadOverBypass
) {
2716 StorePreferCacheLoadOverBypass(aPreferCacheLoadOverBypass
);
2720 HttpChannelChild::GetPreferCacheLoadOverBypass(
2721 bool* aPreferCacheLoadOverBypass
) {
2722 NS_ENSURE_ARG(aPreferCacheLoadOverBypass
);
2723 *aPreferCacheLoadOverBypass
= LoadPreferCacheLoadOverBypass();
2728 HttpChannelChild::PreferAlternativeDataType(
2729 const nsACString
& aType
, const nsACString
& aContentType
,
2730 PreferredAlternativeDataDeliveryType aDeliverAltData
) {
2731 ENSURE_CALLED_BEFORE_ASYNC_OPEN();
2733 mPreferredCachedAltDataTypes
.AppendElement(PreferredAlternativeDataTypeParams(
2734 nsCString(aType
), nsCString(aContentType
), aDeliverAltData
));
2738 const nsTArray
<PreferredAlternativeDataTypeParams
>&
2739 HttpChannelChild::PreferredAlternativeDataTypes() {
2740 return mPreferredCachedAltDataTypes
;
2744 HttpChannelChild::GetAlternativeDataType(nsACString
& aType
) {
2745 // Must be called during or after OnStartRequest
2746 if (!LoadAfterOnStartRequestBegun()) {
2747 return NS_ERROR_NOT_AVAILABLE
;
2750 aType
= mAvailableCachedAltDataType
;
2755 HttpChannelChild::OpenAlternativeOutputStream(const nsACString
& aType
,
2756 int64_t aPredictedSize
,
2757 nsIAsyncOutputStream
** _retval
) {
2758 MOZ_ASSERT(NS_IsMainThread(), "Main thread only");
2761 return NS_ERROR_NOT_AVAILABLE
;
2763 if (static_cast<ContentChild
*>(gNeckoChild
->Manager())->IsShuttingDown()) {
2764 return NS_ERROR_NOT_AVAILABLE
;
2767 nsCOMPtr
<nsISerialEventTarget
> neckoTarget
= GetNeckoTarget();
2768 MOZ_ASSERT(neckoTarget
);
2770 RefPtr
<AltDataOutputStreamChild
> stream
= new AltDataOutputStreamChild();
2771 stream
->AddIPDLReference();
2773 if (!gNeckoChild
->SendPAltDataOutputStreamConstructor(
2774 stream
, nsCString(aType
), aPredictedSize
, WrapNotNull(this))) {
2775 return NS_ERROR_FAILURE
;
2778 stream
.forget(_retval
);
2783 HttpChannelChild::GetOriginalInputStream(nsIInputStreamReceiver
* aReceiver
) {
2784 if (aReceiver
== nullptr) {
2785 return NS_ERROR_INVALID_ARG
;
2789 return NS_ERROR_NOT_AVAILABLE
;
2792 mOriginalInputStreamReceiver
= aReceiver
;
2793 Unused
<< SendOpenOriginalCacheInputStream();
2799 HttpChannelChild::GetAlternativeDataInputStream(nsIInputStream
** aInputStream
) {
2800 NS_ENSURE_ARG_POINTER(aInputStream
);
2802 nsCOMPtr
<nsIInputStream
> is
= mAltDataInputStream
;
2803 is
.forget(aInputStream
);
2808 mozilla::ipc::IPCResult
HttpChannelChild::RecvOriginalCacheInputStreamAvailable(
2809 const Maybe
<IPCStream
>& aStream
) {
2810 nsCOMPtr
<nsIInputStream
> stream
= DeserializeIPCStream(aStream
);
2811 nsCOMPtr
<nsIInputStreamReceiver
> receiver
;
2812 receiver
.swap(mOriginalInputStreamReceiver
);
2814 receiver
->OnInputStreamReady(stream
);
2820 //-----------------------------------------------------------------------------
2821 // HttpChannelChild::nsIResumableChannel
2822 //-----------------------------------------------------------------------------
2825 HttpChannelChild::ResumeAt(uint64_t startPos
, const nsACString
& entityID
) {
2826 LOG(("HttpChannelChild::ResumeAt [this=%p]\n", this));
2827 ENSURE_CALLED_BEFORE_CONNECT();
2828 mStartPos
= startPos
;
2829 mEntityID
= entityID
;
2830 mSendResumeAt
= true;
2834 // GetEntityID is shared in HttpBaseChannel
2836 //-----------------------------------------------------------------------------
2837 // HttpChannelChild::nsISupportsPriority
2838 //-----------------------------------------------------------------------------
2841 HttpChannelChild::SetPriority(int32_t aPriority
) {
2842 LOG(("HttpChannelChild::SetPriority %p p=%d", this, aPriority
));
2843 int16_t newValue
= clamped
<int32_t>(aPriority
, INT16_MIN
, INT16_MAX
);
2844 if (mPriority
== newValue
) return NS_OK
;
2845 mPriority
= newValue
;
2846 if (RemoteChannelExists()) SendSetPriority(mPriority
);
2850 //-----------------------------------------------------------------------------
2851 // HttpChannelChild::nsIClassOfService
2852 //-----------------------------------------------------------------------------
2854 HttpChannelChild::SetClassFlags(uint32_t inFlags
) {
2855 if (mClassOfService
.Flags() == inFlags
) {
2859 mClassOfService
.SetFlags(inFlags
);
2861 LOG(("HttpChannelChild %p ClassOfService flags=%lu inc=%d", this,
2862 mClassOfService
.Flags(), mClassOfService
.Incremental()));
2864 if (RemoteChannelExists()) {
2865 SendSetClassOfService(mClassOfService
);
2871 HttpChannelChild::AddClassFlags(uint32_t inFlags
) {
2872 mClassOfService
.SetFlags(inFlags
| mClassOfService
.Flags());
2874 LOG(("HttpChannelChild %p ClassOfService flags=%lu inc=%d", this,
2875 mClassOfService
.Flags(), mClassOfService
.Incremental()));
2877 if (RemoteChannelExists()) {
2878 SendSetClassOfService(mClassOfService
);
2884 HttpChannelChild::ClearClassFlags(uint32_t inFlags
) {
2885 mClassOfService
.SetFlags(~inFlags
& mClassOfService
.Flags());
2887 LOG(("HttpChannelChild %p ClassOfService=%lu", this,
2888 mClassOfService
.Flags()));
2890 if (RemoteChannelExists()) {
2891 SendSetClassOfService(mClassOfService
);
2897 HttpChannelChild::SetClassOfService(ClassOfService inCos
) {
2898 mClassOfService
= inCos
;
2899 LOG(("HttpChannelChild %p ClassOfService flags=%lu inc=%d", this,
2900 mClassOfService
.Flags(), mClassOfService
.Incremental()));
2901 if (RemoteChannelExists()) {
2902 SendSetClassOfService(mClassOfService
);
2907 HttpChannelChild::SetIncremental(bool inIncremental
) {
2908 mClassOfService
.SetIncremental(inIncremental
);
2909 LOG(("HttpChannelChild %p ClassOfService flags=%lu inc=%d", this,
2910 mClassOfService
.Flags(), mClassOfService
.Incremental()));
2911 if (RemoteChannelExists()) {
2912 SendSetClassOfService(mClassOfService
);
2917 //-----------------------------------------------------------------------------
2918 // HttpChannelChild::nsIProxiedChannel
2919 //-----------------------------------------------------------------------------
2922 HttpChannelChild::GetProxyInfo(nsIProxyInfo
** aProxyInfo
) { DROP_DEAD(); }
2924 NS_IMETHODIMP
HttpChannelChild::GetHttpProxyConnectResponseCode(
2925 int32_t* aResponseCode
) {
2929 //-----------------------------------------------------------------------------
2930 // HttpChannelChild::nsIHttpChannelChild
2931 //-----------------------------------------------------------------------------
2933 NS_IMETHODIMP
HttpChannelChild::AddCookiesToRequest() {
2934 HttpBaseChannel::AddCookiesToRequest();
2938 NS_IMETHODIMP
HttpChannelChild::GetClientSetRequestHeaders(
2939 RequestHeaderTuples
** aRequestHeaders
) {
2940 *aRequestHeaders
= &mClientSetRequestHeaders
;
2944 void HttpChannelChild::GetClientSetCorsPreflightParameters(
2945 Maybe
<CorsPreflightArgs
>& aArgs
) {
2946 if (LoadRequireCORSPreflight()) {
2947 CorsPreflightArgs args
;
2948 args
.unsafeHeaders() = mUnsafeHeaders
.Clone();
2949 aArgs
.emplace(args
);
2956 HttpChannelChild::RemoveCorsPreflightCacheEntry(
2957 nsIURI
* aURI
, nsIPrincipal
* aPrincipal
,
2958 const OriginAttributes
& aOriginAttributes
) {
2959 PrincipalInfo principalInfo
;
2960 MOZ_ASSERT(aURI
, "aURI should not be null");
2961 nsresult rv
= PrincipalToPrincipalInfo(aPrincipal
, &principalInfo
);
2962 if (NS_WARN_IF(NS_FAILED(rv
))) {
2965 bool result
= false;
2966 // Be careful to not attempt to send a message to the parent after the
2967 // actor has been destroyed.
2969 result
= SendRemoveCorsPreflightCacheEntry(aURI
, principalInfo
,
2972 return result
? NS_OK
: NS_ERROR_FAILURE
;
2975 //-----------------------------------------------------------------------------
2976 // HttpChannelChild::nsIMuliPartChannel
2977 //-----------------------------------------------------------------------------
2980 HttpChannelChild::GetBaseChannel(nsIChannel
** aBaseChannel
) {
2981 if (!mMultiPartID
) {
2982 MOZ_ASSERT(false, "Not a multipart channel");
2983 return NS_ERROR_NOT_AVAILABLE
;
2985 nsCOMPtr
<nsIChannel
> channel
= this;
2986 channel
.forget(aBaseChannel
);
2991 HttpChannelChild::GetPartID(uint32_t* aPartID
) {
2992 if (!mMultiPartID
) {
2993 MOZ_ASSERT(false, "Not a multipart channel");
2994 return NS_ERROR_NOT_AVAILABLE
;
2996 *aPartID
= *mMultiPartID
;
3001 HttpChannelChild::GetIsFirstPart(bool* aIsFirstPart
) {
3002 if (!mMultiPartID
) {
3003 return NS_ERROR_NOT_AVAILABLE
;
3005 *aIsFirstPart
= mIsFirstPartOfMultiPart
;
3010 HttpChannelChild::GetIsLastPart(bool* aIsLastPart
) {
3011 if (!mMultiPartID
) {
3012 return NS_ERROR_NOT_AVAILABLE
;
3014 *aIsLastPart
= mIsLastPartOfMultiPart
;
3018 //-----------------------------------------------------------------------------
3019 // HttpChannelChild::nsIThreadRetargetableRequest
3020 //-----------------------------------------------------------------------------
3023 HttpChannelChild::RetargetDeliveryTo(nsISerialEventTarget
* aNewTarget
) {
3024 LOG(("HttpChannelChild::RetargetDeliveryTo [this=%p, aNewTarget=%p]", this,
3026 MOZ_ASSERT(NS_IsMainThread(), "Should be called on main thread only");
3027 MOZ_ASSERT(aNewTarget
);
3029 NS_ENSURE_ARG(aNewTarget
);
3030 if (aNewTarget
->IsOnCurrentThread()) {
3031 NS_WARNING("Retargeting delivery to same thread");
3032 mOMTResult
= LABELS_HTTP_CHILD_OMT_STATS::successMainThread
;
3037 // TODO: Maybe add a new label for this? Maybe it doesn't
3038 // matter though, since we also blocked QI, so we shouldn't
3040 mOMTResult
= LABELS_HTTP_CHILD_OMT_STATS::failListener
;
3041 return NS_ERROR_NO_INTERFACE
;
3044 // Ensure that |mListener| and any subsequent listeners can be retargeted
3045 // to another thread.
3046 nsresult rv
= NS_OK
;
3047 nsCOMPtr
<nsIThreadRetargetableStreamListener
> retargetableListener
=
3048 do_QueryInterface(mListener
, &rv
);
3049 if (!retargetableListener
|| NS_FAILED(rv
)) {
3050 NS_WARNING("Listener is not retargetable");
3051 mOMTResult
= LABELS_HTTP_CHILD_OMT_STATS::failListener
;
3052 return NS_ERROR_NO_INTERFACE
;
3055 rv
= retargetableListener
->CheckListenerChain();
3056 if (NS_FAILED(rv
)) {
3057 NS_WARNING("Subsequent listeners are not retargetable");
3058 mOMTResult
= LABELS_HTTP_CHILD_OMT_STATS::failListenerChain
;
3063 MutexAutoLock
lock(mEventTargetMutex
);
3064 MOZ_ASSERT(!mODATarget
);
3065 mODATarget
= aNewTarget
;
3068 mOMTResult
= LABELS_HTTP_CHILD_OMT_STATS::success
;
3073 HttpChannelChild::GetDeliveryTarget(nsISerialEventTarget
** aEventTarget
) {
3074 MutexAutoLock
lock(mEventTargetMutex
);
3076 nsCOMPtr
<nsISerialEventTarget
> target
= mODATarget
;
3078 target
= GetCurrentSerialEventTarget();
3080 target
.forget(aEventTarget
);
3084 void HttpChannelChild::TrySendDeletingChannel() {
3085 AUTO_PROFILER_LABEL("HttpChannelChild::TrySendDeletingChannel", NETWORK
);
3086 if (!mDeletingChannelSent
.compareExchange(false, true)) {
3087 // SendDeletingChannel is already sent.
3091 if (NS_IsMainThread()) {
3092 if (NS_WARN_IF(!CanSend())) {
3093 // IPC actor is destroyed already, do not send more messages.
3097 Unused
<< PHttpChannelChild::SendDeletingChannel();
3101 nsCOMPtr
<nsISerialEventTarget
> neckoTarget
= GetNeckoTarget();
3102 MOZ_ASSERT(neckoTarget
);
3104 DebugOnly
<nsresult
> rv
= neckoTarget
->Dispatch(
3105 NewNonOwningRunnableMethod(
3106 "net::HttpChannelChild::TrySendDeletingChannel", this,
3107 &HttpChannelChild::TrySendDeletingChannel
),
3108 NS_DISPATCH_NORMAL
);
3109 MOZ_ASSERT(NS_SUCCEEDED(rv
));
3112 nsresult
HttpChannelChild::AsyncCallImpl(
3113 void (HttpChannelChild::*funcPtr
)(),
3114 nsRunnableMethod
<HttpChannelChild
>** retval
) {
3117 RefPtr
<nsRunnableMethod
<HttpChannelChild
>> event
=
3118 NewRunnableMethod("net::HttpChannelChild::AsyncCall", this, funcPtr
);
3119 nsCOMPtr
<nsISerialEventTarget
> neckoTarget
= GetNeckoTarget();
3120 MOZ_ASSERT(neckoTarget
);
3122 rv
= neckoTarget
->Dispatch(event
, NS_DISPATCH_NORMAL
);
3124 if (NS_SUCCEEDED(rv
) && retval
) {
3131 nsresult
HttpChannelChild::SetReferrerHeader(const nsACString
& aReferrer
,
3132 bool aRespectBeforeConnect
) {
3133 // Normally this would be ENSURE_CALLED_BEFORE_CONNECT, but since the
3134 // "connect" is done in the main process, and LoadRequestObserversCalled() is
3135 // never set in the ChannelChild, before connect basically means before
3137 if (aRespectBeforeConnect
) {
3138 ENSURE_CALLED_BEFORE_ASYNC_OPEN();
3141 // remove old referrer if any
3142 mClientSetRequestHeaders
.RemoveElementsBy(
3143 [](const auto& header
) { return "Referer"_ns
.Equals(header
.mHeader
); });
3145 return HttpBaseChannel::SetReferrerHeader(aReferrer
, aRespectBeforeConnect
);
3148 void HttpChannelChild::CancelOnMainThread(nsresult aRv
,
3149 const nsACString
& aReason
) {
3150 LOG(("HttpChannelChild::CancelOnMainThread [this=%p]", this));
3152 if (NS_IsMainThread()) {
3153 CancelWithReason(aRv
, aReason
);
3158 // Cancel is expected to preempt any other channel events, thus we put this
3159 // event in the front of mEventQ to make sure nsIStreamListener not receiving
3160 // any ODA/OnStopRequest callbacks.
3161 nsCString
reason(aReason
);
3162 mEventQ
->PrependEvent(MakeUnique
<NeckoTargetChannelFunctionEvent
>(
3163 this, [self
= UnsafePtr
<HttpChannelChild
>(this), aRv
, reason
]() {
3164 self
->CancelWithReason(aRv
, reason
);
3169 mozilla::ipc::IPCResult
HttpChannelChild::RecvSetPriority(
3170 const int16_t& aPriority
) {
3171 mPriority
= aPriority
;
3175 // We don't have a copyable Endpoint and NeckoTargetChannelFunctionEvent takes
3176 // std::function<void()>. It's not possible to avoid the copy from the type of
3177 // lambda to std::function, so does the capture list. Hence, we're forced to
3178 // use the old-fashioned channel event inheritance.
3179 class AttachStreamFilterEvent
: public ChannelEvent
{
3181 AttachStreamFilterEvent(HttpChannelChild
* aChild
,
3182 already_AddRefed
<nsIEventTarget
> aTarget
,
3183 Endpoint
<extensions::PStreamFilterParent
>&& aEndpoint
)
3184 : mChild(aChild
), mTarget(aTarget
), mEndpoint(std::move(aEndpoint
)) {}
3186 already_AddRefed
<nsIEventTarget
> GetEventTarget() override
{
3187 nsCOMPtr
<nsIEventTarget
> target
= mTarget
;
3188 return target
.forget();
3191 void Run() override
{
3192 extensions::StreamFilterParent::Attach(mChild
, std::move(mEndpoint
));
3196 HttpChannelChild
* mChild
;
3197 nsCOMPtr
<nsIEventTarget
> mTarget
;
3198 Endpoint
<extensions::PStreamFilterParent
> mEndpoint
;
3201 void HttpChannelChild::RegisterStreamFilter(
3202 RefPtr
<extensions::StreamFilterParent
>& aStreamFilter
) {
3203 MOZ_ASSERT(NS_IsMainThread());
3204 mStreamFilters
.AppendElement(aStreamFilter
);
3207 void HttpChannelChild::ProcessAttachStreamFilter(
3208 Endpoint
<extensions::PStreamFilterParent
>&& aEndpoint
) {
3209 LOG(("HttpChannelChild::ProcessAttachStreamFilter [this=%p]\n", this));
3210 MOZ_ASSERT(OnSocketThread());
3212 mEventQ
->RunOrEnqueue(new AttachStreamFilterEvent(this, GetNeckoTarget(),
3213 std::move(aEndpoint
)));
3216 void HttpChannelChild::OnDetachStreamFilters() {
3217 LOG(("HttpChannelChild::OnDetachStreamFilters [this=%p]\n", this));
3218 MOZ_ASSERT(NS_IsMainThread());
3219 for (auto& StreamFilter
: mStreamFilters
) {
3220 StreamFilter
->Disconnect("ServiceWorker fallback redirection"_ns
);
3222 mStreamFilters
.Clear();
3225 void HttpChannelChild::ProcessDetachStreamFilters() {
3226 LOG(("HttpChannelChild::ProcessDetachStreamFilter [this=%p]\n", this));
3227 MOZ_ASSERT(OnSocketThread());
3229 mEventQ
->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
3230 this, [self
= UnsafePtr
<HttpChannelChild
>(this)]() {
3231 self
->OnDetachStreamFilters();
3235 void HttpChannelChild::ActorDestroy(ActorDestroyReason aWhy
) {
3236 MOZ_ASSERT(NS_IsMainThread());
3238 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
3239 mActorDestroyReason
.emplace(aWhy
);
3242 // OnStartRequest might be dropped if IPDL is destroyed abnormally
3243 // and BackgroundChild might have pending IPC messages.
3244 // Clean up BackgroundChild at this time to prevent memleak.
3245 if (aWhy
!= Deletion
) {
3246 // Make sure all the messages are processed.
3247 AutoEventEnqueuer
ensureSerialDispatch(mEventQ
);
3249 mStatus
= NS_ERROR_DOCSHELL_DYING
;
3252 // Cleanup the background channel before we resume the eventQ so we don't
3253 // get any other events.
3254 CleanupBackgroundChannel();
3256 mIPCActorDeleted
= true;
3261 mozilla::ipc::IPCResult
HttpChannelChild::RecvLogBlockedCORSRequest(
3262 const nsAString
& aMessage
, const nsACString
& aCategory
,
3263 const bool& aIsWarning
) {
3264 Unused
<< LogBlockedCORSRequest(aMessage
, aCategory
, aIsWarning
);
3269 HttpChannelChild::LogBlockedCORSRequest(const nsAString
& aMessage
,
3270 const nsACString
& aCategory
,
3272 uint64_t innerWindowID
= mLoadInfo
->GetInnerWindowID();
3273 bool privateBrowsing
= !!mLoadInfo
->GetOriginAttributes().mPrivateBrowsingId
;
3274 bool fromChromeContext
=
3275 mLoadInfo
->TriggeringPrincipal()->IsSystemPrincipal();
3276 nsCORSListenerProxy::LogBlockedCORSRequest(innerWindowID
, privateBrowsing
,
3277 fromChromeContext
, aMessage
,
3278 aCategory
, aIsWarning
);
3282 mozilla::ipc::IPCResult
HttpChannelChild::RecvLogMimeTypeMismatch(
3283 const nsACString
& aMessageName
, const bool& aWarning
, const nsAString
& aURL
,
3284 const nsAString
& aContentType
) {
3285 Unused
<< LogMimeTypeMismatch(aMessageName
, aWarning
, aURL
, aContentType
);
3290 HttpChannelChild::LogMimeTypeMismatch(const nsACString
& aMessageName
,
3291 bool aWarning
, const nsAString
& aURL
,
3292 const nsAString
& aContentType
) {
3293 RefPtr
<Document
> doc
;
3294 mLoadInfo
->GetLoadingDocument(getter_AddRefs(doc
));
3296 AutoTArray
<nsString
, 2> params
;
3297 params
.AppendElement(aURL
);
3298 params
.AppendElement(aContentType
);
3299 nsContentUtils::ReportToConsole(
3300 aWarning
? nsIScriptError::warningFlag
: nsIScriptError::errorFlag
,
3301 "MIMEMISMATCH"_ns
, doc
, nsContentUtils::eSECURITY_PROPERTIES
,
3302 nsCString(aMessageName
).get(), params
);
3306 nsresult
HttpChannelChild::MaybeLogCOEPError(nsresult aStatus
) {
3307 if (aStatus
== NS_ERROR_DOM_CORP_FAILED
) {
3308 RefPtr
<Document
> doc
;
3309 mLoadInfo
->GetLoadingDocument(getter_AddRefs(doc
));
3314 AutoTArray
<nsString
, 2> params
;
3315 params
.AppendElement(NS_ConvertUTF8toUTF16(url
));
3316 // The MDN URL intentionally ends with a # so the webconsole linkification
3317 // doesn't ignore the final ) of the URL
3318 params
.AppendElement(
3319 u
"https://developer.mozilla.org/docs/Web/HTTP/Cross-Origin_Resource_Policy_(CORP)#"_ns
);
3320 nsContentUtils::ReportToConsole(nsIScriptError::errorFlag
, "COEP"_ns
, doc
,
3321 nsContentUtils::eNECKO_PROPERTIES
,
3322 "CORPBlocked", params
);
3328 nsresult
HttpChannelChild::CrossProcessRedirectFinished(nsresult aStatus
) {
3330 return NS_BINDING_FAILED
;
3333 if (!mCanceled
&& NS_SUCCEEDED(mStatus
)) {
3340 void HttpChannelChild::DoDiagnosticAssertWhenOnStopNotCalledOnDestroy() {
3341 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
3342 mDoDiagnosticAssertWhenOnStopNotCalledOnDestroy
= true;
3346 void HttpChannelChild::MaybeConnectToSocketProcess() {
3347 if (!nsIOService::UseSocketProcess()) {
3351 if (!StaticPrefs::network_send_ODA_to_content_directly()) {
3355 RefPtr
<HttpBackgroundChannelChild
> bgChild
;
3357 MutexAutoLock
lock(mBgChildMutex
);
3360 SocketProcessBridgeChild::GetSocketProcessBridge()->Then(
3361 GetCurrentSerialEventTarget(), __func__
,
3362 [bgChild
, channelId
= ChannelId()](
3363 const RefPtr
<SocketProcessBridgeChild
>& aBridge
) {
3364 Endpoint
<PBackgroundDataBridgeParent
> parentEndpoint
;
3365 Endpoint
<PBackgroundDataBridgeChild
> childEndpoint
;
3366 PBackgroundDataBridge::CreateEndpoints(&parentEndpoint
, &childEndpoint
);
3367 aBridge
->SendInitBackgroundDataBridge(std::move(parentEndpoint
),
3370 gSocketTransportService
->Dispatch(
3371 NS_NewRunnableFunction(
3372 "HttpBackgroundChannelChild::CreateDataBridge",
3373 [bgChild
, endpoint
= std::move(childEndpoint
)]() mutable {
3374 bgChild
->CreateDataBridge(std::move(endpoint
));
3376 NS_DISPATCH_NORMAL
);
3378 []() { NS_WARNING("Failed to create SocketProcessBridgeChild"); });
3382 HttpChannelChild::SetEarlyHintObserver(nsIEarlyHintObserver
* aObserver
) {
3386 NS_IMETHODIMP
HttpChannelChild::SetWebTransportSessionEventListener(
3387 WebTransportSessionEventListener
* aListener
) {
3391 } // namespace mozilla::net