1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=8 et tw=80 : */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 // HttpLog.h should generally be included first
11 #include "mozilla/ConsoleReportCollector.h"
12 #include "mozilla/dom/BrowsingContext.h"
13 #include "mozilla/ipc/IPCStreamUtils.h"
14 #include "mozilla/net/EarlyHintRegistrar.h"
15 #include "mozilla/net/HttpChannelParent.h"
16 #include "mozilla/dom/ContentParent.h"
17 #include "mozilla/dom/ContentProcessManager.h"
18 #include "mozilla/dom/Element.h"
19 #include "mozilla/dom/ServiceWorkerUtils.h"
20 #include "mozilla/dom/BrowserParent.h"
21 #include "mozilla/dom/WindowGlobalParent.h"
22 #include "mozilla/net/NeckoParent.h"
23 #include "mozilla/net/CookieServiceParent.h"
24 #include "mozilla/InputStreamLengthHelper.h"
25 #include "mozilla/IntegerPrintfMacros.h"
26 #include "mozilla/Preferences.h"
27 #include "mozilla/ProfilerLabels.h"
28 #include "mozilla/ProfilerMarkers.h"
29 #include "mozilla/StoragePrincipalHelper.h"
30 #include "mozilla/UniquePtr.h"
31 #include "mozilla/Unused.h"
32 #include "HttpBackgroundChannelParent.h"
33 #include "ParentChannelListener.h"
35 #include "nsICacheInfoChannel.h"
36 #include "nsHttpHandler.h"
38 #include "nsNetUtil.h"
39 #include "nsISupportsPriority.h"
40 #include "mozilla/net/BackgroundChannelRegistrar.h"
41 #include "nsSerializationHelper.h"
42 #include "nsISerializable.h"
43 #include "mozilla/ipc/InputStreamUtils.h"
44 #include "mozilla/ipc/URIUtils.h"
45 #include "SerializedLoadContext.h"
46 #include "nsIAuthPrompt.h"
47 #include "nsIAuthPrompt2.h"
48 #include "mozilla/ipc/BackgroundUtils.h"
49 #include "mozilla/LoadInfo.h"
50 #include "nsQueryObject.h"
51 #include "mozilla/BasePrincipal.h"
52 #include "nsCORSListenerProxy.h"
53 #include "nsIIPCSerializableInputStream.h"
54 #include "nsIPrompt.h"
55 #include "nsIPromptFactory.h"
56 #include "mozilla/net/ChannelEventQueue.h"
57 #include "mozilla/net/RedirectChannelRegistrar.h"
58 #include "nsIWindowWatcher.h"
59 #include "mozilla/dom/Document.h"
60 #include "nsISecureBrowserUI.h"
61 #include "nsStreamUtils.h"
62 #include "nsStringStream.h"
63 #include "nsThreadUtils.h"
64 #include "nsQueryObject.h"
65 #include "nsIMultiPartChannel.h"
66 #include "nsIViewSourceChannel.h"
68 using namespace mozilla
;
70 namespace geckoprofiler::markers
{
72 struct ChannelMarker
{
73 static constexpr Span
<const char> MarkerTypeName() {
74 return MakeStringSpan("ChannelMarker");
76 static void StreamJSONMarkerData(
77 mozilla::baseprofiler::SpliceableJSONWriter
& aWriter
,
78 const mozilla::ProfilerString8View
& aURL
, uint64_t aChannelId
) {
79 if (aURL
.Length() != 0) {
80 aWriter
.StringProperty("url", aURL
);
82 aWriter
.IntProperty("channelId", static_cast<int64_t>(aChannelId
));
84 static MarkerSchema
MarkerTypeDisplay() {
85 using MS
= MarkerSchema
;
86 MS
schema(MS::Location::MarkerChart
, MS::Location::MarkerTable
);
87 schema
.SetTableLabel("{marker.name} - {marker.data.url}");
88 schema
.AddKeyFormatSearchable("url", MS::Format::Url
,
89 MS::Searchable::Searchable
);
90 schema
.AddStaticLabelValue(
92 "Timestamp capturing various phases of a network channel's lifespan.");
97 } // namespace geckoprofiler::markers
99 using mozilla::BasePrincipal
;
100 using namespace mozilla::dom
;
101 using namespace mozilla::ipc
;
103 namespace mozilla::net
{
105 HttpChannelParent::HttpChannelParent(dom::BrowserParent
* iframeEmbedding
,
106 nsILoadContext
* aLoadContext
,
107 PBOverrideStatus aOverrideStatus
)
108 : mLoadContext(aLoadContext
),
110 mPBOverride(aOverrideStatus
),
112 mIgnoreProgress(false),
113 mHasSuspendedByBackPressure(false),
114 mCacheNeedFlowControlInitialized(false),
115 mNeedFlowControl(true),
116 mSuspendedForFlowControl(false),
117 mAfterOnStartRequestBegun(false),
118 mDataSentToChildProcess(false) {
119 LOG(("Creating HttpChannelParent [this=%p]\n", this));
121 // Ensure gHttpHandler is initialized: we need the atom table up and running.
122 nsCOMPtr
<nsIHttpProtocolHandler
> dummyInitializer
=
123 do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX
"http");
125 MOZ_ASSERT(gHttpHandler
);
126 mHttpHandler
= gHttpHandler
;
128 mBrowserParent
= iframeEmbedding
;
130 mSendWindowSize
= gHttpHandler
->SendWindowSize();
133 new ChannelEventQueue(static_cast<nsIParentRedirectingChannel
*>(this));
136 HttpChannelParent::~HttpChannelParent() {
137 LOG(("Destroying HttpChannelParent [this=%p]\n", this));
138 CleanupBackgroundChannel();
140 MOZ_ASSERT(!mRedirectCallback
);
141 if (NS_WARN_IF(mRedirectCallback
)) {
142 mRedirectCallback
->OnRedirectVerifyCallback(NS_ERROR_UNEXPECTED
);
143 mRedirectCallback
= nullptr;
145 mEventQ
->NotifyReleasingOwner();
148 void HttpChannelParent::ActorDestroy(ActorDestroyReason why
) {
149 // We may still have refcount>0 if nsHttpChannel hasn't called OnStopRequest
150 // yet, but child process has crashed. We must not try to send any more msgs
151 // to child, or IPDL will kill chrome process, too.
153 CleanupBackgroundChannel();
156 bool HttpChannelParent::Init(const HttpChannelCreationArgs
& aArgs
) {
157 LOG(("HttpChannelParent::Init [this=%p]\n", this));
158 AUTO_PROFILER_LABEL("HttpChannelParent::Init", NETWORK
);
159 switch (aArgs
.type()) {
160 case HttpChannelCreationArgs::THttpChannelOpenArgs
: {
161 const HttpChannelOpenArgs
& a
= aArgs
.get_HttpChannelOpenArgs();
163 a
.uri(), a
.original(), a
.doc(), a
.referrerInfo(), a
.apiRedirectTo(),
164 a
.topWindowURI(), a
.loadFlags(), a
.requestHeaders(),
165 a
.requestMethod(), a
.uploadStream(), a
.uploadStreamHasHeaders(),
166 a
.priority(), a
.classOfService(), a
.redirectionLimit(), a
.allowSTS(),
167 a
.thirdPartyFlags(), a
.resumeAt(), a
.startPos(), a
.entityID(),
168 a
.allowSpdy(), a
.allowHttp3(), a
.allowAltSvc(), a
.beConservative(),
169 a
.bypassProxy(), a
.tlsFlags(), a
.loadInfo(), a
.cacheKey(),
170 a
.requestContextID(), a
.preflightArgs(), a
.initialRwin(),
171 a
.blockAuthPrompt(), a
.allowStaleCacheContent(),
172 a
.preferCacheLoadOverBypass(), a
.contentTypeHint(), a
.requestMode(),
173 a
.redirectMode(), a
.channelId(), a
.integrityMetadata(),
174 a
.contentWindowId(), a
.preferredAlternativeTypes(), a
.browserId(),
175 a
.launchServiceWorkerStart(), a
.launchServiceWorkerEnd(),
176 a
.dispatchFetchEventStart(), a
.dispatchFetchEventEnd(),
177 a
.handleFetchEventStart(), a
.handleFetchEventEnd(),
178 a
.forceMainDocumentChannel(), a
.navigationStartTimeStamp(),
179 a
.earlyHintPreloaderId(), a
.classicScriptHintCharset(),
180 a
.documentCharacterSet());
182 case HttpChannelCreationArgs::THttpChannelConnectArgs
: {
183 const HttpChannelConnectArgs
& cArgs
= aArgs
.get_HttpChannelConnectArgs();
184 return ConnectChannel(cArgs
.registrarId());
187 MOZ_ASSERT_UNREACHABLE("unknown open type");
192 void HttpChannelParent::TryInvokeAsyncOpen(nsresult aRv
) {
193 LOG(("HttpChannelParent::TryInvokeAsyncOpen [this=%p barrier=%u rv=%" PRIx32
195 this, mAsyncOpenBarrier
, static_cast<uint32_t>(aRv
)));
196 MOZ_ASSERT(NS_IsMainThread());
197 AUTO_PROFILER_LABEL("HttpChannelParent::TryInvokeAsyncOpen", NETWORK
);
199 // TryInvokeAsyncOpen is called more than we expected.
200 // Assert in nightly build but ignore it in release channel.
201 MOZ_DIAGNOSTIC_ASSERT(mAsyncOpenBarrier
> 0);
202 if (NS_WARN_IF(!mAsyncOpenBarrier
)) {
206 if (--mAsyncOpenBarrier
> 0 && NS_SUCCEEDED(aRv
)) {
207 // Need to wait for more events.
211 InvokeAsyncOpen(aRv
);
214 void HttpChannelParent::OnBackgroundParentReady(
215 HttpBackgroundChannelParent
* aBgParent
) {
216 LOG(("HttpChannelParent::OnBackgroundParentReady [this=%p bgParent=%p]\n",
218 MOZ_ASSERT(NS_IsMainThread());
219 MOZ_ASSERT(!mBgParent
);
221 mBgParent
= aBgParent
;
223 mPromise
.ResolveIfExists(true, __func__
);
226 void HttpChannelParent::OnBackgroundParentDestroyed() {
227 LOG(("HttpChannelParent::OnBackgroundParentDestroyed [this=%p]\n", this));
228 MOZ_ASSERT(NS_IsMainThread());
230 if (!mPromise
.IsEmpty()) {
231 MOZ_ASSERT(!mBgParent
);
232 mPromise
.Reject(NS_ERROR_FAILURE
, __func__
);
240 // Background channel is closed unexpectly, abort PHttpChannel operation.
245 void HttpChannelParent::CleanupBackgroundChannel() {
246 LOG(("HttpChannelParent::CleanupBackgroundChannel [this=%p bgParent=%p]\n",
247 this, mBgParent
.get()));
248 MOZ_ASSERT(NS_IsMainThread());
251 RefPtr
<HttpBackgroundChannelParent
> bgParent
= std::move(mBgParent
);
252 bgParent
->OnChannelClosed();
256 // The nsHttpChannel may have a reference to this parent, release it
257 // to avoid circular references.
258 RefPtr
<nsHttpChannel
> httpChannelImpl
= do_QueryObject(mChannel
);
259 if (httpChannelImpl
) {
260 httpChannelImpl
->SetWarningReporter(nullptr);
263 if (!mPromise
.IsEmpty()) {
264 mRequest
.DisconnectIfExists();
265 mPromise
.Reject(NS_ERROR_FAILURE
, __func__
);
271 // This HttpChannelParent might still have a reference from
272 // BackgroundChannelRegistrar.
273 nsCOMPtr
<nsIBackgroundChannelRegistrar
> registrar
=
274 BackgroundChannelRegistrar::GetOrCreate();
275 MOZ_ASSERT(registrar
);
277 registrar
->DeleteChannel(mChannel
->ChannelId());
279 // If mAsyncOpenBarrier is greater than zero, it means AsyncOpen procedure
280 // is still on going. we need to abort AsyncOpen with failure to destroy
281 // PHttpChannel actor.
282 if (mAsyncOpenBarrier
) {
283 TryInvokeAsyncOpen(NS_ERROR_FAILURE
);
288 base::ProcessId
HttpChannelParent::OtherPid() const {
292 return PHttpChannelParent::OtherPid();
295 //-----------------------------------------------------------------------------
296 // HttpChannelParent::nsISupports
297 //-----------------------------------------------------------------------------
299 NS_IMPL_ADDREF(HttpChannelParent
)
300 NS_IMPL_RELEASE(HttpChannelParent
)
301 NS_INTERFACE_MAP_BEGIN(HttpChannelParent
)
302 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor
)
303 NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink
)
304 NS_INTERFACE_MAP_ENTRY(nsIRequestObserver
)
305 NS_INTERFACE_MAP_ENTRY(nsIStreamListener
)
306 NS_INTERFACE_MAP_ENTRY(nsIParentChannel
)
307 NS_INTERFACE_MAP_ENTRY(nsIParentRedirectingChannel
)
308 NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectReadyCallback
)
309 NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink
)
310 NS_INTERFACE_MAP_ENTRY(nsIRedirectResultListener
)
311 NS_INTERFACE_MAP_ENTRY(nsIMultiPartChannelListener
)
312 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIParentRedirectingChannel
)
313 NS_INTERFACE_MAP_ENTRY_CONCRETE(HttpChannelParent
)
316 //-----------------------------------------------------------------------------
317 // HttpChannelParent::nsIInterfaceRequestor
318 //-----------------------------------------------------------------------------
321 HttpChannelParent::GetInterface(const nsIID
& aIID
, void** result
) {
322 // A system XHR can be created without reference to a window, hence mTabParent
323 // may be null. In that case we want to let the window watcher pick a prompt
325 if (!mBrowserParent
&& (aIID
.Equals(NS_GET_IID(nsIAuthPrompt
)) ||
326 aIID
.Equals(NS_GET_IID(nsIAuthPrompt2
)))) {
328 nsCOMPtr
<nsIWindowWatcher
> wwatch
=
329 do_GetService(NS_WINDOWWATCHER_CONTRACTID
, &rv
);
330 NS_ENSURE_SUCCESS(rv
, NS_ERROR_NO_INTERFACE
);
332 bool hasWindowCreator
= false;
333 Unused
<< wwatch
->HasWindowCreator(&hasWindowCreator
);
334 if (!hasWindowCreator
) {
335 return NS_ERROR_NO_INTERFACE
;
338 nsCOMPtr
<nsIPromptFactory
> factory
= do_QueryInterface(wwatch
);
340 return NS_ERROR_NO_INTERFACE
;
342 rv
= factory
->GetPrompt(nullptr, aIID
, reinterpret_cast<void**>(result
));
344 return NS_ERROR_NO_INTERFACE
;
349 // Only support nsILoadContext if child channel's callbacks did too
350 if (aIID
.Equals(NS_GET_IID(nsILoadContext
)) && mLoadContext
) {
351 nsCOMPtr
<nsILoadContext
> copy
= mLoadContext
;
356 return QueryInterface(aIID
, result
);
359 //-----------------------------------------------------------------------------
360 // HttpChannelParent::PHttpChannelParent
361 //-----------------------------------------------------------------------------
363 void HttpChannelParent::AsyncOpenFailed(nsresult aRv
) {
364 MOZ_ASSERT(NS_IsMainThread());
365 MOZ_ASSERT(NS_FAILED(aRv
));
367 // Break the reference cycle among HttpChannelParent,
368 // ParentChannelListener, and nsHttpChannel to avoid memory leakage.
370 mParentListener
= nullptr;
373 Unused
<< SendFailedAsyncOpen(aRv
);
377 void HttpChannelParent::InvokeAsyncOpen(nsresult rv
) {
378 LOG(("HttpChannelParent::InvokeAsyncOpen [this=%p rv=%" PRIx32
"]\n", this,
379 static_cast<uint32_t>(rv
)));
380 MOZ_ASSERT(NS_IsMainThread());
387 rv
= mChannel
->AsyncOpen(mParentListener
);
393 void HttpChannelParent::InvokeEarlyHintPreloader(
394 nsresult rv
, uint64_t aEarlyHintPreloaderId
) {
395 LOG(("HttpChannelParent::InvokeEarlyHintPreloader [this=%p rv=%" PRIx32
"]\n",
396 this, static_cast<uint32_t>(rv
)));
397 MOZ_ASSERT(NS_IsMainThread());
399 ContentParentId cpId
=
400 static_cast<ContentParent
*>(Manager()->Manager())->ChildID();
402 RefPtr
<EarlyHintRegistrar
> ehr
= EarlyHintRegistrar::GetOrCreate();
403 if (NS_SUCCEEDED(rv
)) {
404 rv
= ehr
->LinkParentChannel(cpId
, aEarlyHintPreloaderId
, this)
410 ehr
->DeleteEntry(cpId
, aEarlyHintPreloaderId
);
411 AsyncOpenFailed(NS_ERROR_FAILURE
);
415 bool HttpChannelParent::DoAsyncOpen(
416 nsIURI
* aURI
, nsIURI
* aOriginalURI
, nsIURI
* aDocURI
,
417 nsIReferrerInfo
* aReferrerInfo
, nsIURI
* aAPIRedirectToURI
,
418 nsIURI
* aTopWindowURI
, const uint32_t& aLoadFlags
,
419 const RequestHeaderTuples
& requestHeaders
, const nsCString
& requestMethod
,
420 const Maybe
<IPCStream
>& uploadStream
, const bool& uploadStreamHasHeaders
,
421 const int16_t& priority
, const ClassOfService
& classOfService
,
422 const uint8_t& redirectionLimit
, const bool& allowSTS
,
423 const uint32_t& thirdPartyFlags
, const bool& doResumeAt
,
424 const uint64_t& startPos
, const nsCString
& entityID
, const bool& allowSpdy
,
425 const bool& allowHttp3
, const bool& allowAltSvc
, const bool& beConservative
,
426 const bool& bypassProxy
, const uint32_t& tlsFlags
,
427 const LoadInfoArgs
& aLoadInfoArgs
, const uint32_t& aCacheKey
,
428 const uint64_t& aRequestContextID
,
429 const Maybe
<CorsPreflightArgs
>& aCorsPreflightArgs
,
430 const uint32_t& aInitialRwin
, const bool& aBlockAuthPrompt
,
431 const bool& aAllowStaleCacheContent
, const bool& aPreferCacheLoadOverBypass
,
432 const nsCString
& aContentTypeHint
, const dom::RequestMode
& aRequestMode
,
433 const uint32_t& aRedirectMode
, const uint64_t& aChannelId
,
434 const nsString
& aIntegrityMetadata
, const uint64_t& aContentWindowId
,
435 const nsTArray
<PreferredAlternativeDataTypeParams
>&
436 aPreferredAlternativeTypes
,
437 const uint64_t& aBrowserId
, const TimeStamp
& aLaunchServiceWorkerStart
,
438 const TimeStamp
& aLaunchServiceWorkerEnd
,
439 const TimeStamp
& aDispatchFetchEventStart
,
440 const TimeStamp
& aDispatchFetchEventEnd
,
441 const TimeStamp
& aHandleFetchEventStart
,
442 const TimeStamp
& aHandleFetchEventEnd
,
443 const bool& aForceMainDocumentChannel
,
444 const TimeStamp
& aNavigationStartTimeStamp
,
445 const uint64_t& aEarlyHintPreloaderId
,
446 const nsAString
& aClassicScriptHintCharset
,
447 const nsAString
& aDocumentCharacterSet
) {
448 MOZ_ASSERT(aURI
, "aURI should not be NULL");
450 if (aEarlyHintPreloaderId
) {
451 // Wait for HttpBackgrounChannel to continue the async open procedure.
452 mEarlyHintPreloaderId
= aEarlyHintPreloaderId
;
453 RefPtr
<HttpChannelParent
> self
= this;
454 WaitForBgParent(aChannelId
)
456 GetMainThreadSerialEventTarget(), __func__
,
457 [self
, aEarlyHintPreloaderId
]() {
458 self
->mRequest
.Complete();
459 self
->InvokeEarlyHintPreloader(NS_OK
, aEarlyHintPreloaderId
);
461 [self
, aEarlyHintPreloaderId
](nsresult aStatus
) {
462 self
->mRequest
.Complete();
463 self
->InvokeEarlyHintPreloader(aStatus
, aEarlyHintPreloaderId
);
470 // this check is neccessary to prevent null deref
475 LOG(("HttpChannelParent RecvAsyncOpen [this=%p uri=%s, gid=%" PRIu64
476 " browserid=%" PRIx64
"]\n",
477 this, aURI
->GetSpecOrDefault().get(), aChannelId
, aBrowserId
));
479 PROFILER_MARKER("Receive AsyncOpen in Parent", NETWORK
, {}, ChannelMarker
,
480 aURI
->GetSpecOrDefault(), aChannelId
);
484 nsCOMPtr
<nsIIOService
> ios(do_GetIOService(&rv
));
486 return SendFailedAsyncOpen(rv
);
489 nsAutoCString remoteType
;
490 rv
= GetRemoteType(remoteType
);
492 return SendFailedAsyncOpen(rv
);
495 nsCOMPtr
<nsILoadInfo
> loadInfo
;
496 rv
= mozilla::ipc::LoadInfoArgsToLoadInfo(aLoadInfoArgs
, remoteType
,
497 getter_AddRefs(loadInfo
));
499 return SendFailedAsyncOpen(rv
);
502 nsCOMPtr
<nsIChannel
> channel
;
503 rv
= NS_NewChannelInternal(getter_AddRefs(channel
), aURI
, loadInfo
, nullptr,
504 nullptr, nullptr, aLoadFlags
, ios
);
506 return SendFailedAsyncOpen(rv
);
509 RefPtr
<HttpBaseChannel
> httpChannel
= do_QueryObject(channel
, &rv
);
511 return SendFailedAsyncOpen(rv
);
514 // Set attributes needed to create a FetchEvent from this channel.
515 httpChannel
->SetRequestMode(aRequestMode
);
516 httpChannel
->SetRedirectMode(aRedirectMode
);
518 // Set the channelId allocated in child to the parent instance
519 httpChannel
->SetChannelId(aChannelId
);
520 httpChannel
->SetTopLevelContentWindowId(aContentWindowId
);
521 httpChannel
->SetBrowserId(aBrowserId
);
523 httpChannel
->SetIntegrityMetadata(aIntegrityMetadata
);
525 RefPtr
<nsHttpChannel
> httpChannelImpl
= do_QueryObject(httpChannel
);
526 if (httpChannelImpl
) {
527 httpChannelImpl
->SetWarningReporter(this);
529 httpChannel
->SetTimingEnabled(true);
530 if (mPBOverride
!= kPBOverride_Unset
) {
531 httpChannel
->SetPrivate(mPBOverride
== kPBOverride_Private
);
534 if (doResumeAt
) httpChannel
->ResumeAt(startPos
, entityID
);
537 httpChannel
->SetOriginalURI(aOriginalURI
);
541 httpChannel
->SetDocumentURI(aDocURI
);
545 // Referrer header is computed in child no need to recompute here
547 httpChannel
->SetReferrerInfoInternal(aReferrerInfo
, false, false, true);
548 MOZ_ASSERT(NS_SUCCEEDED(rv
));
551 httpChannel
->SetClassicScriptHintCharset(aClassicScriptHintCharset
);
552 httpChannel
->SetDocumentCharacterSet(aDocumentCharacterSet
);
554 if (aAPIRedirectToURI
) {
555 httpChannel
->RedirectTo(aAPIRedirectToURI
);
559 httpChannel
->SetTopWindowURI(aTopWindowURI
);
562 if (aLoadFlags
!= nsIRequest::LOAD_NORMAL
) {
563 httpChannel
->SetLoadFlags(aLoadFlags
);
566 if (aForceMainDocumentChannel
) {
567 httpChannel
->SetIsMainDocumentChannel(true);
570 for (uint32_t i
= 0; i
< requestHeaders
.Length(); i
++) {
571 if (requestHeaders
[i
].mEmpty
) {
572 httpChannel
->SetEmptyRequestHeader(requestHeaders
[i
].mHeader
);
574 httpChannel
->SetRequestHeader(requestHeaders
[i
].mHeader
,
575 requestHeaders
[i
].mValue
,
576 requestHeaders
[i
].mMerge
);
580 RefPtr
<ParentChannelListener
> parentListener
= new ParentChannelListener(
581 this, mBrowserParent
? mBrowserParent
->GetBrowsingContext() : nullptr);
583 httpChannel
->SetRequestMethod(nsDependentCString(requestMethod
.get()));
585 if (aCorsPreflightArgs
.isSome()) {
586 const CorsPreflightArgs
& args
= aCorsPreflightArgs
.ref();
587 httpChannel
->SetCorsPreflightParameters(args
.unsafeHeaders(), false);
590 nsCOMPtr
<nsIInputStream
> stream
= DeserializeIPCStream(uploadStream
);
592 rv
= httpChannel
->InternalSetUploadStream(stream
);
594 return SendFailedAsyncOpen(rv
);
597 httpChannel
->SetUploadStreamHasHeaders(uploadStreamHasHeaders
);
600 nsCOMPtr
<nsICacheInfoChannel
> cacheChannel
=
601 do_QueryInterface(static_cast<nsIChannel
*>(httpChannel
.get()));
603 cacheChannel
->SetCacheKey(aCacheKey
);
604 for (const auto& data
: aPreferredAlternativeTypes
) {
605 cacheChannel
->PreferAlternativeDataType(data
.type(), data
.contentType(),
606 data
.deliverAltData());
609 cacheChannel
->SetAllowStaleCacheContent(aAllowStaleCacheContent
);
610 cacheChannel
->SetPreferCacheLoadOverBypass(aPreferCacheLoadOverBypass
);
612 // This is to mark that the results are going to the content process.
613 if (httpChannelImpl
) {
614 httpChannelImpl
->SetAltDataForChild(true);
618 httpChannel
->SetContentType(aContentTypeHint
);
620 if (priority
!= nsISupportsPriority::PRIORITY_NORMAL
) {
621 httpChannel
->SetPriority(priority
);
623 if (classOfService
.Flags() || classOfService
.Incremental()) {
624 httpChannel
->SetClassOfService(classOfService
);
626 httpChannel
->SetRedirectionLimit(redirectionLimit
);
627 httpChannel
->SetAllowSTS(allowSTS
);
628 httpChannel
->SetThirdPartyFlags(thirdPartyFlags
);
629 httpChannel
->SetAllowSpdy(allowSpdy
);
630 httpChannel
->SetAllowHttp3(allowHttp3
);
631 httpChannel
->SetAllowAltSvc(allowAltSvc
);
632 httpChannel
->SetBeConservative(beConservative
);
633 httpChannel
->SetTlsFlags(tlsFlags
);
634 httpChannel
->SetInitialRwin(aInitialRwin
);
635 httpChannel
->SetBlockAuthPrompt(aBlockAuthPrompt
);
637 httpChannel
->SetLaunchServiceWorkerStart(aLaunchServiceWorkerStart
);
638 httpChannel
->SetLaunchServiceWorkerEnd(aLaunchServiceWorkerEnd
);
639 httpChannel
->SetDispatchFetchEventStart(aDispatchFetchEventStart
);
640 httpChannel
->SetDispatchFetchEventEnd(aDispatchFetchEventEnd
);
641 httpChannel
->SetHandleFetchEventStart(aHandleFetchEventStart
);
642 httpChannel
->SetHandleFetchEventEnd(aHandleFetchEventEnd
);
644 httpChannel
->SetNavigationStartTimeStamp(aNavigationStartTimeStamp
);
645 httpChannel
->SetRequestContextID(aRequestContextID
);
647 // Store the strong reference of channel and parent listener object until
648 // all the initialization procedure is complete without failure, to remove
649 // cycle reference in fail case and to avoid memory leakage.
650 mChannel
= std::move(httpChannel
);
651 mParentListener
= std::move(parentListener
);
652 mChannel
->SetNotificationCallbacks(mParentListener
);
654 MOZ_ASSERT(!mBgParent
);
655 MOZ_ASSERT(mPromise
.IsEmpty());
656 // Wait for HttpBackgrounChannel to continue the async open procedure.
658 RefPtr
<HttpChannelParent
> self
= this;
659 WaitForBgParent(mChannel
->ChannelId())
661 GetMainThreadSerialEventTarget(), __func__
,
663 self
->mRequest
.Complete();
664 self
->TryInvokeAsyncOpen(NS_OK
);
666 [self
](nsresult aStatus
) {
667 self
->mRequest
.Complete();
668 self
->TryInvokeAsyncOpen(aStatus
);
674 RefPtr
<GenericNonExclusivePromise
> HttpChannelParent::WaitForBgParent(
675 uint64_t aChannelId
) {
676 LOG(("HttpChannelParent::WaitForBgParent [this=%p]\n", this));
677 MOZ_ASSERT(!mBgParent
);
679 if (!mChannel
&& !mEarlyHintPreloaderId
) {
680 return GenericNonExclusivePromise::CreateAndReject(NS_ERROR_FAILURE
,
684 nsCOMPtr
<nsIBackgroundChannelRegistrar
> registrar
=
685 BackgroundChannelRegistrar::GetOrCreate();
686 MOZ_ASSERT(registrar
);
687 registrar
->LinkHttpChannel(aChannelId
, this);
690 return GenericNonExclusivePromise::CreateAndResolve(true, __func__
);
693 return mPromise
.Ensure(__func__
);
696 bool HttpChannelParent::ConnectChannel(const uint32_t& registrarId
) {
700 ("HttpChannelParent::ConnectChannel: Looking for a registered channel "
701 "[this=%p, id=%" PRIu32
"]\n",
703 nsCOMPtr
<nsIChannel
> channel
;
704 rv
= NS_LinkRedirectChannels(registrarId
, this, getter_AddRefs(channel
));
706 NS_WARNING("Could not find the http channel to connect its IPC parent");
707 // This makes the channel delete itself safely. It's the only thing
708 // we can do now, since this parent channel cannot be used and there is
709 // no other way to tell the child side there were something wrong.
714 LOG((" found channel %p, rv=%08" PRIx32
, channel
.get(),
715 static_cast<uint32_t>(rv
)));
716 mChannel
= do_QueryObject(channel
);
718 LOG((" but it's not HttpBaseChannel"));
723 LOG((" and it is HttpBaseChannel %p", mChannel
.get()));
725 RefPtr
<nsHttpChannel
> httpChannelImpl
= do_QueryObject(mChannel
);
726 if (httpChannelImpl
) {
727 httpChannelImpl
->SetWarningReporter(this);
730 if (mPBOverride
!= kPBOverride_Unset
) {
731 // redirected-to channel may not support PB
732 nsCOMPtr
<nsIPrivateBrowsingChannel
> pbChannel
= do_QueryObject(mChannel
);
734 pbChannel
->SetPrivate(mPBOverride
== kPBOverride_Private
);
738 MOZ_ASSERT(!mBgParent
);
739 MOZ_ASSERT(mPromise
.IsEmpty());
740 // Waiting for background channel
741 RefPtr
<HttpChannelParent
> self
= this;
742 WaitForBgParent(mChannel
->ChannelId())
744 GetMainThreadSerialEventTarget(), __func__
,
745 [self
]() { self
->mRequest
.Complete(); },
746 [self
](const nsresult
& aResult
) {
747 NS_ERROR("failed to establish the background channel");
748 self
->mRequest
.Complete();
754 mozilla::ipc::IPCResult
HttpChannelParent::RecvSetPriority(
755 const int16_t& priority
) {
756 LOG(("HttpChannelParent::RecvSetPriority [this=%p, priority=%d]\n", this,
758 AUTO_PROFILER_LABEL("HttpChannelParent::RecvSetPriority", NETWORK
);
761 mChannel
->SetPriority(priority
);
764 nsCOMPtr
<nsISupportsPriority
> priorityRedirectChannel
=
765 do_QueryInterface(mRedirectChannel
);
766 if (priorityRedirectChannel
) priorityRedirectChannel
->SetPriority(priority
);
771 mozilla::ipc::IPCResult
HttpChannelParent::RecvSetClassOfService(
772 const ClassOfService
& cos
) {
774 mChannel
->SetClassOfService(cos
);
779 mozilla::ipc::IPCResult
HttpChannelParent::RecvSuspend() {
780 LOG(("HttpChannelParent::RecvSuspend [this=%p]\n", this));
788 mozilla::ipc::IPCResult
HttpChannelParent::RecvResume() {
789 LOG(("HttpChannelParent::RecvResume [this=%p]\n", this));
797 mozilla::ipc::IPCResult
HttpChannelParent::RecvCancel(
798 const nsresult
& status
, const uint32_t& requestBlockingReason
,
799 const nsACString
& reason
, const mozilla::Maybe
<nsCString
>& logString
) {
800 LOG(("HttpChannelParent::RecvCancel [this=%p, reason=%s]\n", this,
801 PromiseFlatCString(reason
).get()));
803 // logging child cancel reason on the parent side
804 if (logString
.isSome()) {
805 LOG(("HttpChannelParent::RecvCancel: %s", logString
->get()));
808 // May receive cancel before channel has been constructed!
810 mChannel
->CancelWithReason(status
, reason
);
812 if (MOZ_UNLIKELY(requestBlockingReason
!=
813 nsILoadInfo::BLOCKING_REASON_NONE
)) {
814 nsCOMPtr
<nsILoadInfo
> loadInfo
= mChannel
->LoadInfo();
815 loadInfo
->SetRequestBlockingReason(requestBlockingReason
);
818 // Once we receive |Cancel|, child will stop sending RecvBytesRead. Force
819 // the channel resumed if needed.
820 if (mSuspendedForFlowControl
) {
821 LOG((" resume the channel due to e10s backpressure relief by cancel"));
822 Unused
<< mChannel
->Resume();
823 mSuspendedForFlowControl
= false;
825 } else if (!mIPCClosed
) {
826 // Make sure that the child correctly delivers all stream listener
828 Unused
<< SendFailedAsyncOpen(status
);
831 // We won't need flow control anymore. Toggle the flag to avoid |Suspend|
832 // since OnDataAvailable could be off-main-thread.
833 mCacheNeedFlowControlInitialized
= true;
834 mNeedFlowControl
= false;
836 // If the channel is cancelled before the redirect is completed
837 // RecvRedirect2Verify will not be called, so we must clear the callback.
838 if (mRedirectCallback
) {
839 mRedirectCallback
->OnRedirectVerifyCallback(NS_ERROR_UNEXPECTED
);
840 mRedirectCallback
= nullptr;
846 mozilla::ipc::IPCResult
HttpChannelParent::RecvRedirect2Verify(
847 const nsresult
& aResult
, const RequestHeaderTuples
& changedHeaders
,
848 const uint32_t& aSourceRequestBlockingReason
,
849 const Maybe
<ChildLoadInfoForwarderArgs
>& aTargetLoadInfoForwarder
,
850 const uint32_t& loadFlags
, nsIReferrerInfo
* aReferrerInfo
,
851 nsIURI
* aAPIRedirectURI
,
852 const Maybe
<CorsPreflightArgs
>& aCorsPreflightArgs
) {
853 LOG(("HttpChannelParent::RecvRedirect2Verify [this=%p result=%" PRIx32
"]\n",
854 this, static_cast<uint32_t>(aResult
)));
856 // Result from the child. If something fails here, we might overwrite a
857 // success with a further failure.
858 nsresult result
= aResult
;
863 if (NS_SUCCEEDED(result
)) {
864 nsCOMPtr
<nsIHttpChannel
> newHttpChannel
=
865 do_QueryInterface(mRedirectChannel
);
867 if (newHttpChannel
) {
868 if (aAPIRedirectURI
) {
869 rv
= newHttpChannel
->RedirectTo(aAPIRedirectURI
);
870 MOZ_ASSERT(NS_SUCCEEDED(rv
));
873 for (uint32_t i
= 0; i
< changedHeaders
.Length(); i
++) {
874 if (changedHeaders
[i
].mEmpty
) {
875 rv
= newHttpChannel
->SetEmptyRequestHeader(changedHeaders
[i
].mHeader
);
877 rv
= newHttpChannel
->SetRequestHeader(changedHeaders
[i
].mHeader
,
878 changedHeaders
[i
].mValue
,
879 changedHeaders
[i
].mMerge
);
881 MOZ_ASSERT(NS_SUCCEEDED(rv
));
884 // A successfully redirected channel must have the LOAD_REPLACE flag.
885 MOZ_ASSERT(loadFlags
& nsIChannel::LOAD_REPLACE
);
886 if (loadFlags
& nsIChannel::LOAD_REPLACE
) {
887 newHttpChannel
->SetLoadFlags(loadFlags
);
890 if (aCorsPreflightArgs
.isSome()) {
891 nsCOMPtr
<nsIHttpChannelInternal
> newInternalChannel
=
892 do_QueryInterface(newHttpChannel
);
893 MOZ_RELEASE_ASSERT(newInternalChannel
);
894 const CorsPreflightArgs
& args
= aCorsPreflightArgs
.ref();
895 newInternalChannel
->SetCorsPreflightParameters(args
.unsafeHeaders(),
900 RefPtr
<HttpBaseChannel
> baseChannel
= do_QueryObject(newHttpChannel
);
901 MOZ_ASSERT(baseChannel
);
903 // Referrer header is computed in child no need to recompute here
904 rv
= baseChannel
->SetReferrerInfoInternal(aReferrerInfo
, false, false,
906 MOZ_ASSERT(NS_SUCCEEDED(rv
));
910 if (aTargetLoadInfoForwarder
.isSome()) {
911 nsCOMPtr
<nsILoadInfo
> newLoadInfo
= newHttpChannel
->LoadInfo();
912 rv
= MergeChildLoadInfoForwarder(aTargetLoadInfoForwarder
.ref(),
914 if (NS_FAILED(rv
) && NS_SUCCEEDED(result
)) {
921 // If the redirect is vetoed, reason is set on the source (current) channel's
922 // load info, so we must carry iver the change.
923 // The channel may have already been cleaned up, so there is nothing we can
925 if (MOZ_UNLIKELY(aSourceRequestBlockingReason
!=
926 nsILoadInfo::BLOCKING_REASON_NONE
) &&
928 nsCOMPtr
<nsILoadInfo
> sourceLoadInfo
= mChannel
->LoadInfo();
929 sourceLoadInfo
->SetRequestBlockingReason(aSourceRequestBlockingReason
);
932 // Continue the verification procedure if child has veto the redirection.
933 if (NS_FAILED(result
)) {
934 ContinueRedirect2Verify(result
);
938 // Wait for background channel ready on target channel
939 nsCOMPtr
<nsIRedirectChannelRegistrar
> redirectReg
=
940 RedirectChannelRegistrar::GetOrCreate();
941 MOZ_ASSERT(redirectReg
);
943 nsCOMPtr
<nsIParentChannel
> redirectParentChannel
;
944 rv
= redirectReg
->GetParentChannel(mRedirectChannelId
,
945 getter_AddRefs(redirectParentChannel
));
946 if (!redirectParentChannel
) {
947 ContinueRedirect2Verify(rv
);
951 nsCOMPtr
<nsIParentRedirectingChannel
> redirectedParent
=
952 do_QueryInterface(redirectParentChannel
);
953 if (!redirectedParent
) {
954 // Continue verification procedure if redirecting to non-Http protocol
955 ContinueRedirect2Verify(result
);
959 // Ask redirected channel if verification can proceed.
960 // ContinueRedirect2Verify will be invoked when redirected channel is ready.
961 redirectedParent
->ContinueVerification(this);
966 // from nsIParentRedirectingChannel
968 HttpChannelParent::ContinueVerification(
969 nsIAsyncVerifyRedirectReadyCallback
* aCallback
) {
970 LOG(("HttpChannelParent::ContinueVerification [this=%p callback=%p]\n", this,
973 MOZ_ASSERT(NS_IsMainThread());
974 MOZ_ASSERT(aCallback
);
976 // Continue the verification procedure if background channel is ready.
978 aCallback
->ReadyToVerify(NS_OK
);
982 // ConnectChannel must be received before Redirect2Verify.
983 MOZ_ASSERT(!mPromise
.IsEmpty());
985 // Otherwise, wait for the background channel.
986 nsCOMPtr
<nsIAsyncVerifyRedirectReadyCallback
> callback
= aCallback
;
988 WaitForBgParent(mChannel
->ChannelId())
990 GetMainThreadSerialEventTarget(), __func__
,
991 [callback
]() { callback
->ReadyToVerify(NS_OK
); },
992 [callback
](const nsresult
& aResult
) {
993 NS_ERROR("failed to establish the background channel");
994 callback
->ReadyToVerify(aResult
);
997 // mChannel can be null for several reasons (AsyncOpenFailed, etc)
998 NS_ERROR("No channel for ContinueVerification");
999 GetMainThreadSerialEventTarget()->Dispatch(NS_NewRunnableFunction(
1000 __func__
, [callback
] { callback
->ReadyToVerify(NS_ERROR_FAILURE
); }));
1005 void HttpChannelParent::ContinueRedirect2Verify(const nsresult
& aResult
) {
1007 ("HttpChannelParent::ContinueRedirect2Verify "
1008 "[this=%p result=%" PRIx32
"]\n",
1009 this, static_cast<uint32_t>(aResult
)));
1011 if (mRedirectCallback
) {
1013 ("HttpChannelParent::ContinueRedirect2Verify call "
1014 "OnRedirectVerifyCallback"
1015 " [this=%p result=%" PRIx32
", mRedirectCallback=%p]\n",
1016 this, static_cast<uint32_t>(aResult
), mRedirectCallback
.get()));
1017 mRedirectCallback
->OnRedirectVerifyCallback(aResult
);
1018 mRedirectCallback
= nullptr;
1021 ("RecvRedirect2Verify[%p]: NO CALLBACKS! | "
1022 "mRedirectChannelId: %" PRIx64
", mRedirectChannel: %p",
1023 this, mRedirectChannelId
, mRedirectChannel
.get()));
1027 mozilla::ipc::IPCResult
HttpChannelParent::RecvDocumentChannelCleanup(
1028 const bool& clearCacheEntry
) {
1029 CleanupBackgroundChannel(); // Background channel can be closed.
1030 mChannel
= nullptr; // Reclaim some memory sooner.
1031 if (clearCacheEntry
) {
1032 mCacheEntry
= nullptr; // Else we'll block other channels reading same URI
1037 mozilla::ipc::IPCResult
HttpChannelParent::RecvRemoveCorsPreflightCacheEntry(
1038 nsIURI
* uri
, const mozilla::ipc::PrincipalInfo
& requestingPrincipal
,
1039 const OriginAttributes
& originAttributes
) {
1041 return IPC_FAIL_NO_REASON(this);
1043 auto principalOrErr
= PrincipalInfoToPrincipal(requestingPrincipal
);
1044 if (NS_WARN_IF(principalOrErr
.isErr())) {
1045 return IPC_FAIL_NO_REASON(this);
1047 nsCOMPtr
<nsIPrincipal
> principal
= principalOrErr
.unwrap();
1048 nsCORSListenerProxy::RemoveFromCorsPreflightCache(uri
, principal
,
1053 mozilla::ipc::IPCResult
HttpChannelParent::RecvSetCookies(
1054 const nsACString
& aBaseDomain
, const OriginAttributes
& aOriginAttributes
,
1055 nsIURI
* aHost
, const bool& aFromHttp
, nsTArray
<CookieStruct
>&& aCookies
) {
1056 net::PCookieServiceParent
* csParent
=
1057 LoneManagedOrNullAsserts(Manager()->ManagedPCookieServiceParent());
1058 NS_ENSURE_TRUE(csParent
, IPC_OK());
1060 auto* cs
= static_cast<net::CookieServiceParent
*>(csParent
);
1062 BrowsingContext
* browsingContext
= nullptr;
1063 if (mBrowserParent
) {
1064 browsingContext
= mBrowserParent
->GetBrowsingContext();
1067 return cs
->SetCookies(nsCString(aBaseDomain
), aOriginAttributes
, aHost
,
1068 aFromHttp
, aCookies
, browsingContext
);
1071 //-----------------------------------------------------------------------------
1072 // HttpChannelParent::nsIRequestObserver
1073 //-----------------------------------------------------------------------------
1075 static ResourceTimingStructArgs
GetTimingAttributes(HttpBaseChannel
* aChannel
) {
1076 ResourceTimingStructArgs args
;
1077 TimeStamp timeStamp
;
1078 aChannel
->GetDomainLookupStart(&timeStamp
);
1079 args
.domainLookupStart() = timeStamp
;
1080 aChannel
->GetDomainLookupEnd(&timeStamp
);
1081 args
.domainLookupEnd() = timeStamp
;
1082 aChannel
->GetConnectStart(&timeStamp
);
1083 args
.connectStart() = timeStamp
;
1084 aChannel
->GetTcpConnectEnd(&timeStamp
);
1085 args
.tcpConnectEnd() = timeStamp
;
1086 aChannel
->GetSecureConnectionStart(&timeStamp
);
1087 args
.secureConnectionStart() = timeStamp
;
1088 aChannel
->GetConnectEnd(&timeStamp
);
1089 args
.connectEnd() = timeStamp
;
1090 aChannel
->GetRequestStart(&timeStamp
);
1091 args
.requestStart() = timeStamp
;
1092 aChannel
->GetResponseStart(&timeStamp
);
1093 args
.responseStart() = timeStamp
;
1094 aChannel
->GetResponseEnd(&timeStamp
);
1095 args
.responseEnd() = timeStamp
;
1096 aChannel
->GetAsyncOpen(&timeStamp
);
1097 args
.fetchStart() = timeStamp
;
1098 aChannel
->GetRedirectStart(&timeStamp
);
1099 args
.redirectStart() = timeStamp
;
1100 aChannel
->GetRedirectEnd(&timeStamp
);
1101 args
.redirectEnd() = timeStamp
;
1104 aChannel
->GetTransferSize(&size
);
1105 args
.transferSize() = size
;
1107 aChannel
->GetEncodedBodySize(&size
);
1108 args
.encodedBodySize() = size
;
1109 // decodedBodySize can be computed in the child process so it doesn't need
1110 // to be passed down.
1112 aChannel
->GetCacheReadStart(&timeStamp
);
1113 args
.cacheReadStart() = timeStamp
;
1115 aChannel
->GetCacheReadEnd(&timeStamp
);
1116 args
.cacheReadEnd() = timeStamp
;
1118 aChannel
->GetTransactionPending(&timeStamp
);
1119 args
.transactionPending() = timeStamp
;
1124 HttpChannelParent::OnStartRequest(nsIRequest
* aRequest
) {
1127 LOG(("HttpChannelParent::OnStartRequest [this=%p, aRequest=%p]\n", this,
1129 MOZ_ASSERT(NS_IsMainThread());
1131 Maybe
<uint32_t> multiPartID
;
1132 bool isFirstPartOfMultiPart
= false;
1133 bool isLastPartOfMultiPart
= false;
1134 DebugOnly
<bool> isMultiPart
= false;
1136 RefPtr
<HttpBaseChannel
> chan
= do_QueryObject(aRequest
);
1138 if (nsCOMPtr
<nsIMultiPartChannel
> multiPartChannel
=
1139 do_QueryInterface(aRequest
)) {
1141 nsCOMPtr
<nsIChannel
> baseChannel
;
1142 multiPartChannel
->GetBaseChannel(getter_AddRefs(baseChannel
));
1143 chan
= do_QueryObject(baseChannel
);
1145 uint32_t partID
= 0;
1146 multiPartChannel
->GetPartID(&partID
);
1147 multiPartID
= Some(partID
);
1148 multiPartChannel
->GetIsFirstPart(&isFirstPartOfMultiPart
);
1149 multiPartChannel
->GetIsLastPart(&isLastPartOfMultiPart
);
1150 } else if (nsCOMPtr
<nsIViewSourceChannel
> viewSourceChannel
=
1151 do_QueryInterface(aRequest
)) {
1152 chan
= do_QueryObject(viewSourceChannel
->GetInnerChannel());
1155 MOZ_ASSERT(multiPartID
|| !isMultiPart
, "Changed multi-part state?");
1158 LOG((" aRequest is not HttpBaseChannel"));
1160 "Expecting only HttpBaseChannel as aRequest in "
1161 "HttpChannelParent::OnStartRequest");
1162 return NS_ERROR_UNEXPECTED
;
1165 mAfterOnStartRequestBegun
= true;
1167 // Todo: re-enable when bug 1589749 is fixed.
1168 /*MOZ_ASSERT(mChannel == chan,
1169 "HttpChannelParent getting OnStartRequest from a different "
1170 "HttpBaseChannel instance");*/
1172 HttpChannelOnStartRequestArgs args
;
1174 // Send down any permissions/cookies which are relevant to this URL if we are
1175 // performing a document load. We can't do that if mIPCClosed is set.
1177 PContentParent
* pcp
= Manager()->Manager();
1178 MOZ_ASSERT(pcp
, "We should have a manager if our IPC isn't closed");
1179 DebugOnly
<nsresult
> rv
=
1180 static_cast<ContentParent
*>(pcp
)->AboutToLoadHttpFtpDocumentForChild(
1181 chan
, &args
.shouldWaitForOnStartRequestSent());
1182 MOZ_ASSERT(NS_SUCCEEDED(rv
));
1185 args
.multiPartID() = multiPartID
;
1186 args
.isFirstPartOfMultiPart() = isFirstPartOfMultiPart
;
1187 args
.isLastPartOfMultiPart() = isLastPartOfMultiPart
;
1189 args
.cacheExpirationTime() = nsICacheEntry::NO_EXPIRATION_TIME
;
1191 RefPtr
<nsHttpChannel
> httpChannelImpl
= do_QueryObject(chan
);
1193 if (httpChannelImpl
) {
1194 httpChannelImpl
->IsFromCache(&args
.isFromCache());
1195 httpChannelImpl
->IsRacing(&args
.isRacing());
1196 httpChannelImpl
->GetCacheEntryId(&args
.cacheEntryId());
1197 httpChannelImpl
->GetCacheTokenFetchCount(&args
.cacheFetchCount());
1198 httpChannelImpl
->GetCacheTokenExpirationTime(&args
.cacheExpirationTime());
1199 httpChannelImpl
->GetProtocolVersion(args
.protocolVersion());
1201 mDataSentToChildProcess
= httpChannelImpl
->DataSentToChildProcess();
1203 // If RCWN is enabled and cache wins, we can't use the ODA from socket
1205 if (args
.isRacing()) {
1206 mDataSentToChildProcess
=
1207 httpChannelImpl
->DataSentToChildProcess() && !args
.isFromCache();
1209 args
.dataFromSocketProcess() = mDataSentToChildProcess
;
1212 // Propagate whether or not conversion should occur from the parent-side
1213 // channel to the child-side channel. Then disable the parent-side
1214 // conversion so that it only occurs in the child.
1215 Unused
<< chan
->GetApplyConversion(&args
.applyConversion());
1216 chan
->SetApplyConversion(false);
1218 // If we've already applied the conversion (as can happen if we installed
1219 // a multipart converted), then don't apply it again on the child.
1220 if (chan
->HasAppliedConversion()) {
1221 args
.applyConversion() = false;
1224 chan
->GetStatus(&args
.channelStatus());
1226 // Keep the cache entry for future use when opening alternative streams.
1227 // It could be already released by nsHttpChannel at that time.
1228 nsCOMPtr
<nsISupports
> cacheEntry
;
1230 if (httpChannelImpl
) {
1231 httpChannelImpl
->GetCacheToken(getter_AddRefs(cacheEntry
));
1232 mCacheEntry
= do_QueryInterface(cacheEntry
);
1233 args
.cacheEntryAvailable() = static_cast<bool>(mCacheEntry
);
1235 httpChannelImpl
->GetCacheKey(&args
.cacheKey());
1236 httpChannelImpl
->GetAlternativeDataType(args
.altDataType());
1239 args
.altDataLength() = chan
->GetAltDataLength();
1240 args
.deliveringAltData() = chan
->IsDeliveringAltData();
1242 args
.securityInfo() = SecurityInfo();
1244 chan
->GetRedirectCount(&args
.redirectCount());
1245 chan
->GetHasHTTPSRR(&args
.hasHTTPSRR());
1247 chan
->GetIsProxyUsed(&args
.isProxyUsed());
1249 nsCOMPtr
<nsILoadInfo
> loadInfo
= chan
->LoadInfo();
1250 mozilla::ipc::LoadInfoToParentLoadInfoForwarder(loadInfo
,
1251 &args
.loadInfoForwarder());
1253 nsHttpResponseHead
* responseHead
= chan
->GetResponseHead();
1254 bool useResponseHead
= !!responseHead
;
1255 nsHttpResponseHead cleanedUpResponseHead
;
1258 (responseHead
->HasHeader(nsHttp::Set_Cookie
) || multiPartID
)) {
1259 cleanedUpResponseHead
= *responseHead
;
1260 cleanedUpResponseHead
.ClearHeader(nsHttp::Set_Cookie
);
1262 nsCOMPtr
<nsIChannel
> multiPartChannel
= do_QueryInterface(aRequest
);
1263 // For the multipart channel, use the parsed subtype instead. Note that
1264 // `chan` is the underlying base channel of the multipart channel in this
1265 // case, which is different from `multiPartChannel`.
1266 MOZ_ASSERT(multiPartChannel
);
1267 nsAutoCString contentType
;
1268 multiPartChannel
->GetContentType(contentType
);
1269 cleanedUpResponseHead
.SetContentType(contentType
);
1271 responseHead
= &cleanedUpResponseHead
;
1274 if (!responseHead
) {
1275 responseHead
= &cleanedUpResponseHead
;
1278 if (chan
->ChannelBlockedByOpaqueResponse() &&
1279 chan
->CachedOpaqueResponseBlockingPref()) {
1280 responseHead
->ClearHeaders();
1283 chan
->GetIsResolvedByTRR(&args
.isResolvedByTRR());
1284 chan
->GetAllRedirectsSameOrigin(&args
.allRedirectsSameOrigin());
1285 chan
->GetCrossOriginOpenerPolicy(&args
.openerPolicy());
1286 args
.selfAddr() = chan
->GetSelfAddr();
1287 args
.peerAddr() = chan
->GetPeerAddr();
1288 args
.timing() = GetTimingAttributes(mChannel
);
1289 if (mOverrideReferrerInfo
) {
1290 args
.overrideReferrerInfo() = ToRefPtr(std::move(mOverrideReferrerInfo
));
1292 if (!mCookie
.IsEmpty()) {
1293 args
.cookie() = std::move(mCookie
);
1296 nsHttpRequestHead
* requestHead
= chan
->GetRequestHead();
1297 // !!! We need to lock headers and please don't forget to unlock them !!!
1298 requestHead
->Enter();
1300 nsHttpHeaderArray cleanedUpRequestHeaders
;
1301 bool cleanedUpRequest
= false;
1302 if (requestHead
->HasHeader(nsHttp::Cookie
)) {
1303 cleanedUpRequestHeaders
= requestHead
->Headers();
1304 cleanedUpRequestHeaders
.ClearHeader(nsHttp::Cookie
);
1305 cleanedUpRequest
= true;
1310 nsCOMPtr
<nsICacheEntry
> altDataSource
;
1311 nsCOMPtr
<nsICacheInfoChannel
> cacheChannel
=
1312 do_QueryInterface(static_cast<nsIChannel
*>(mChannel
.get()));
1314 for (const auto& pref
: cacheChannel
->PreferredAlternativeDataTypes()) {
1315 if (pref
.type() == args
.altDataType() &&
1316 pref
.deliverAltData() ==
1317 nsICacheInfoChannel::PreferredAlternativeDataDeliveryType::
1319 altDataSource
= mCacheEntry
;
1325 nsIRequest::TRRMode effectiveMode
= nsIRequest::TRR_DEFAULT_MODE
;
1326 mChannel
->GetEffectiveTRRMode(&effectiveMode
);
1327 args
.effectiveTRRMode() = effectiveMode
;
1329 TRRSkippedReason reason
= TRRSkippedReason::TRR_UNSET
;
1330 mChannel
->GetTrrSkipReason(&reason
);
1331 args
.trrSkipReason() = reason
;
1334 !mBgParent
->OnStartRequest(
1335 *responseHead
, useResponseHead
,
1336 cleanedUpRequest
? cleanedUpRequestHeaders
: requestHead
->Headers(),
1337 args
, altDataSource
, chan
->GetOnStartRequestStartTime())) {
1338 rv
= NS_ERROR_UNEXPECTED
;
1340 requestHead
->Exit();
1342 // Need to wait for the cookies/permissions to content process, which is sent
1343 // via PContent in AboutToLoadHttpFtpDocumentForChild. For multipart channel,
1344 // send only one time since the cookies/permissions are the same.
1345 if (NS_SUCCEEDED(rv
) && args
.shouldWaitForOnStartRequestSent() &&
1346 multiPartID
.valueOr(0) == 0) {
1347 LOG(("HttpChannelParent::SendOnStartRequestSent\n"));
1348 Unused
<< SendOnStartRequestSent();
1351 if (!args
.timing().domainLookupEnd().IsNull() &&
1352 !args
.timing().connectStart().IsNull()) {
1353 nsAutoCString protocolVersion
;
1354 mChannel
->GetProtocolVersion(protocolVersion
);
1355 uint32_t classOfServiceFlags
= 0;
1356 mChannel
->GetClassFlags(&classOfServiceFlags
);
1357 nsAutoCString cosString
;
1358 ClassOfService::ToString(classOfServiceFlags
, cosString
);
1360 nsPrintfCString("%s_%s", protocolVersion
.get(), cosString
.get()));
1361 Telemetry::AccumulateTimeDelta(
1362 Telemetry::NETWORK_DNS_END_TO_CONNECT_START_EXP_MS
, key
,
1363 args
.timing().domainLookupEnd(), args
.timing().connectStart());
1370 HttpChannelParent::OnStopRequest(nsIRequest
* aRequest
, nsresult aStatusCode
) {
1371 LOG(("HttpChannelParent::OnStopRequest: [this=%p aRequest=%p status=%" PRIx32
1373 this, aRequest
, static_cast<uint32_t>(aStatusCode
)));
1374 MOZ_ASSERT(NS_IsMainThread());
1376 RefPtr
<nsHttpChannel
> httpChannelImpl
= do_QueryObject(mChannel
);
1377 if (httpChannelImpl
) {
1378 httpChannelImpl
->SetWarningReporter(nullptr);
1381 nsHttpHeaderArray
* responseTrailer
= mChannel
->GetResponseTrailers();
1383 nsTArray
<ConsoleReportCollected
> consoleReports
;
1385 RefPtr
<HttpBaseChannel
> httpChannel
= do_QueryObject(mChannel
);
1386 TimeStamp onStopRequestStart
;
1388 httpChannel
->StealConsoleReports(consoleReports
);
1389 onStopRequestStart
= httpChannel
->GetOnStopRequestStartTime();
1392 // Either IPC channel is closed or background channel
1393 // is ready to send OnStopRequest.
1394 MOZ_ASSERT(mIPCClosed
|| mBgParent
);
1396 if (mDataSentToChildProcess
) {
1397 if (mIPCClosed
|| !mBgParent
||
1398 !mBgParent
->OnConsoleReport(consoleReports
)) {
1399 return NS_ERROR_UNEXPECTED
;
1404 // If we're handling a multi-part stream, then send this directly
1405 // over PHttpChannel to make synchronization easier.
1406 if (mIPCClosed
|| !mBgParent
||
1407 !mBgParent
->OnStopRequest(
1408 aStatusCode
, GetTimingAttributes(mChannel
),
1409 responseTrailer
? *responseTrailer
: nsHttpHeaderArray(),
1410 consoleReports
, onStopRequestStart
)) {
1411 return NS_ERROR_UNEXPECTED
;
1414 if (NeedFlowControl()) {
1415 bool isLocal
= false;
1416 NetAddr peerAddr
= mChannel
->GetPeerAddr();
1418 #if defined(XP_UNIX)
1419 // Unix-domain sockets are always local.
1420 isLocal
= (peerAddr
.raw
.family
== PR_AF_LOCAL
);
1423 isLocal
= isLocal
|| peerAddr
.IsLoopbackAddr();
1426 if (!mHasSuspendedByBackPressure
) {
1427 AccumulateCategorical(
1428 Telemetry::LABELS_NETWORK_BACK_PRESSURE_SUSPENSION_RATE_V2::
1431 AccumulateCategorical(
1432 Telemetry::LABELS_NETWORK_BACK_PRESSURE_SUSPENSION_RATE_V2::
1435 // Only analyze non-local suspended cases, which we are interested in.
1436 nsCOMPtr
<nsILoadInfo
> loadInfo
= mChannel
->LoadInfo();
1437 Telemetry::Accumulate(
1438 Telemetry::NETWORK_BACK_PRESSURE_SUSPENSION_CP_TYPE
,
1439 loadInfo
->InternalContentPolicyType());
1442 if (!mHasSuspendedByBackPressure
) {
1443 AccumulateCategorical(
1444 Telemetry::LABELS_NETWORK_BACK_PRESSURE_SUSPENSION_RATE_V2::
1447 AccumulateCategorical(
1448 Telemetry::LABELS_NETWORK_BACK_PRESSURE_SUSPENSION_RATE_V2::
1456 //-----------------------------------------------------------------------------
1457 // HttpChannelParent::nsIMultiPartChannelListener
1458 //-----------------------------------------------------------------------------
1461 HttpChannelParent::OnAfterLastPart(nsresult aStatus
) {
1462 LOG(("HttpChannelParent::OnAfterLastPart [this=%p]\n", this));
1463 MOZ_ASSERT(NS_IsMainThread());
1465 // If IPC channel is closed, there is nothing we can do. Just return NS_OK.
1470 // If IPC channel is open, background channel should be ready to send
1472 MOZ_ASSERT(mBgParent
);
1474 if (!mBgParent
|| !mBgParent
->OnAfterLastPart(aStatus
)) {
1475 return NS_ERROR_UNEXPECTED
;
1481 //-----------------------------------------------------------------------------
1482 // HttpChannelParent::nsIStreamListener
1483 //-----------------------------------------------------------------------------
1486 HttpChannelParent::OnDataAvailable(nsIRequest
* aRequest
,
1487 nsIInputStream
* aInputStream
,
1488 uint64_t aOffset
, uint32_t aCount
) {
1489 LOG(("HttpChannelParent::OnDataAvailable [this=%p aRequest=%p offset=%" PRIu64
1490 " count=%" PRIu32
"]\n",
1491 this, aRequest
, aOffset
, aCount
));
1492 MOZ_ASSERT(NS_IsMainThread());
1494 if (mDataSentToChildProcess
) {
1496 return aInputStream
->ReadSegments(NS_DiscardSegment
, nullptr, aCount
, &n
);
1499 nsresult channelStatus
= NS_OK
;
1500 mChannel
->GetStatus(&channelStatus
);
1502 nsresult transportStatus
= NS_NET_STATUS_RECEIVING_FROM
;
1503 RefPtr
<nsHttpChannel
> httpChannelImpl
= do_QueryObject(mChannel
);
1504 TimeStamp onDataAvailableStart
= TimeStamp::Now();
1505 if (httpChannelImpl
) {
1506 if (httpChannelImpl
->IsReadingFromCache()) {
1507 transportStatus
= NS_NET_STATUS_READING
;
1509 onDataAvailableStart
= httpChannelImpl
->GetDataAvailableStartTime();
1513 nsresult rv
= NS_ReadInputStreamToString(aInputStream
, data
, aCount
);
1514 if (NS_FAILED(rv
)) {
1518 // Either IPC channel is closed or background channel
1519 // is ready to send OnTransportAndData.
1520 MOZ_ASSERT(mIPCClosed
|| mBgParent
);
1522 if (mIPCClosed
|| !mBgParent
||
1523 !mBgParent
->OnTransportAndData(channelStatus
, transportStatus
, aOffset
,
1524 aCount
, data
, onDataAvailableStart
)) {
1525 return NS_ERROR_UNEXPECTED
;
1528 int32_t count
= static_cast<int32_t>(aCount
);
1530 if (NeedFlowControl()) {
1531 // We're going to run out of sending window size
1532 if (mSendWindowSize
> 0 && mSendWindowSize
<= count
) {
1533 MOZ_ASSERT(!mSuspendedForFlowControl
);
1534 LOG((" suspend the channel due to e10s backpressure"));
1535 Unused
<< mChannel
->Suspend();
1536 mSuspendedForFlowControl
= true;
1537 mHasSuspendedByBackPressure
= true;
1538 } else if (!mResumedTimestamp
.IsNull()) {
1539 // Calculate the delay when the first packet arrived after resume
1540 Telemetry::AccumulateTimeDelta(
1541 Telemetry::NETWORK_BACK_PRESSURE_SUSPENSION_DELAY_TIME_MS
,
1543 mResumedTimestamp
= TimeStamp();
1545 mSendWindowSize
-= count
;
1551 bool HttpChannelParent::NeedFlowControl() {
1552 if (mCacheNeedFlowControlInitialized
) {
1553 return mNeedFlowControl
;
1556 int64_t contentLength
= -1;
1558 RefPtr
<nsHttpChannel
> httpChannelImpl
= do_QueryObject(mChannel
);
1560 // By design, we won't trigger the flow control if
1562 // b. the resource is from cache or partial cache
1563 // c. the resource is small
1564 // d. data will be sent from socket process to child process directly
1565 // Note that we served the cached resource first for partical cache, which is
1566 // ignored here since we only take the first ODA into consideration.
1567 if (gHttpHandler
->SendWindowSize() == 0 || !httpChannelImpl
||
1568 httpChannelImpl
->IsReadingFromCache() ||
1569 NS_FAILED(httpChannelImpl
->GetContentLength(&contentLength
)) ||
1570 contentLength
< gHttpHandler
->SendWindowSize() ||
1571 mDataSentToChildProcess
) {
1572 mNeedFlowControl
= false;
1574 mCacheNeedFlowControlInitialized
= true;
1575 return mNeedFlowControl
;
1578 mozilla::ipc::IPCResult
HttpChannelParent::RecvBytesRead(
1579 const int32_t& aCount
) {
1580 if (!NeedFlowControl()) {
1584 LOG(("HttpChannelParent::RecvBytesRead [this=%p count=%" PRId32
"]\n", this,
1587 if (mSendWindowSize
<= 0 && mSendWindowSize
+ aCount
> 0) {
1588 MOZ_ASSERT(mSuspendedForFlowControl
);
1589 LOG((" resume the channel due to e10s backpressure relief"));
1590 Unused
<< mChannel
->Resume();
1591 mSuspendedForFlowControl
= false;
1593 mResumedTimestamp
= TimeStamp::Now();
1595 mSendWindowSize
+= aCount
;
1599 mozilla::ipc::IPCResult
HttpChannelParent::RecvOpenOriginalCacheInputStream() {
1603 Maybe
<IPCStream
> ipcStream
;
1605 nsCOMPtr
<nsIInputStream
> inputStream
;
1606 nsresult rv
= mCacheEntry
->OpenInputStream(0, getter_AddRefs(inputStream
));
1607 if (NS_SUCCEEDED(rv
)) {
1608 Unused
<< mozilla::ipc::SerializeIPCStream(
1609 inputStream
.forget(), ipcStream
, /* aAllowLazy */ false);
1613 Unused
<< SendOriginalCacheInputStreamAvailable(ipcStream
);
1617 //-----------------------------------------------------------------------------
1618 // HttpChannelParent::nsIProgressEventSink
1619 //-----------------------------------------------------------------------------
1622 HttpChannelParent::OnProgress(nsIRequest
* aRequest
, int64_t aProgress
,
1623 int64_t aProgressMax
) {
1624 LOG(("HttpChannelParent::OnProgress [this=%p progress=%" PRId64
"max=%" PRId64
1626 this, aProgress
, aProgressMax
));
1627 MOZ_ASSERT(NS_IsMainThread());
1629 // If IPC channel is closed, there is nothing we can do. Just return NS_OK.
1634 // If it indicates this precedes OnDataAvailable, child can derive the value
1636 if (mIgnoreProgress
) {
1637 mIgnoreProgress
= false;
1641 // If IPC channel is open, background channel should be ready to send
1643 MOZ_ASSERT(mBgParent
);
1645 // Send OnProgress events to the child for data upload progress notifications
1646 // (i.e. status == NS_NET_STATUS_SENDING_TO) or if the channel has
1647 // LOAD_BACKGROUND set.
1648 if (!mBgParent
|| !mBgParent
->OnProgress(aProgress
, aProgressMax
)) {
1649 return NS_ERROR_UNEXPECTED
;
1656 HttpChannelParent::OnStatus(nsIRequest
* aRequest
, nsresult aStatus
,
1657 const char16_t
* aStatusArg
) {
1658 LOG(("HttpChannelParent::OnStatus [this=%p status=%" PRIx32
"]\n", this,
1659 static_cast<uint32_t>(aStatus
)));
1660 MOZ_ASSERT(NS_IsMainThread());
1662 // If IPC channel is closed, there is nothing we can do. Just return NS_OK.
1667 // If this precedes OnDataAvailable, transportStatus will be derived in ODA.
1668 if (aStatus
== NS_NET_STATUS_RECEIVING_FROM
||
1669 aStatus
== NS_NET_STATUS_READING
) {
1670 // The transport status and progress generated by ODA will be coalesced
1671 // into one IPC message. Therefore, we can ignore the next OnProgress event
1672 // since it is generated by ODA as well.
1673 mIgnoreProgress
= true;
1677 // If IPC channel is open, background channel should be ready to send
1679 MOZ_ASSERT(mIPCClosed
|| mBgParent
);
1681 // Otherwise, send to child now
1682 if (!mBgParent
|| !mBgParent
->OnStatus(aStatus
)) {
1683 return NS_ERROR_UNEXPECTED
;
1689 //-----------------------------------------------------------------------------
1690 // HttpChannelParent::nsIParentChannel
1691 //-----------------------------------------------------------------------------
1694 HttpChannelParent::SetParentListener(ParentChannelListener
* aListener
) {
1695 LOG(("HttpChannelParent::SetParentListener [this=%p aListener=%p]\n", this,
1697 MOZ_ASSERT(aListener
);
1698 MOZ_ASSERT(!mParentListener
,
1699 "SetParentListener should only be called for "
1700 "new HttpChannelParents after a redirect, when "
1701 "mParentListener is null.");
1702 mParentListener
= aListener
;
1707 HttpChannelParent::SetClassifierMatchedInfo(const nsACString
& aList
,
1708 const nsACString
& aProvider
,
1709 const nsACString
& aFullHash
) {
1710 LOG(("HttpChannelParent::SetClassifierMatchedInfo [this=%p]\n", this));
1712 MOZ_ASSERT(mBgParent
);
1713 Unused
<< mBgParent
->OnSetClassifierMatchedInfo(aList
, aProvider
,
1720 HttpChannelParent::SetClassifierMatchedTrackingInfo(
1721 const nsACString
& aLists
, const nsACString
& aFullHashes
) {
1722 LOG(("HttpChannelParent::SetClassifierMatchedTrackingInfo [this=%p]\n",
1725 MOZ_ASSERT(mBgParent
);
1726 Unused
<< mBgParent
->OnSetClassifierMatchedTrackingInfo(aLists
,
1733 HttpChannelParent::NotifyClassificationFlags(uint32_t aClassificationFlags
,
1734 bool aIsThirdParty
) {
1736 ("HttpChannelParent::NotifyClassificationFlags "
1737 "classificationFlags=%" PRIu32
", thirdparty=%d [this=%p]\n",
1738 aClassificationFlags
, static_cast<int>(aIsThirdParty
), this));
1740 MOZ_ASSERT(mBgParent
);
1741 Unused
<< mBgParent
->OnNotifyClassificationFlags(aClassificationFlags
,
1748 HttpChannelParent::Delete() {
1749 if (!mIPCClosed
) Unused
<< DoSendDeleteSelf();
1755 HttpChannelParent::GetRemoteType(nsACString
& aRemoteType
) {
1757 return NS_ERROR_UNEXPECTED
;
1760 dom::PContentParent
* pcp
= Manager()->Manager();
1761 aRemoteType
= static_cast<dom::ContentParent
*>(pcp
)->GetRemoteType();
1765 bool HttpChannelParent::IsRedirectDueToAuthRetry(uint32_t redirectFlags
) {
1766 return (redirectFlags
& nsIChannelEventSink::REDIRECT_AUTH_RETRY
);
1769 //-----------------------------------------------------------------------------
1770 // HttpChannelParent::nsIParentRedirectingChannel
1771 //-----------------------------------------------------------------------------
1774 HttpChannelParent::StartRedirect(nsIChannel
* newChannel
, uint32_t redirectFlags
,
1775 nsIAsyncVerifyRedirectCallback
* callback
) {
1778 LOG(("HttpChannelParent::StartRedirect [this=%p, newChannel=%p callback=%p]",
1779 this, newChannel
, callback
));
1781 // Register the new channel and obtain id for it
1782 nsCOMPtr
<nsIRedirectChannelRegistrar
> registrar
=
1783 RedirectChannelRegistrar::GetOrCreate();
1784 MOZ_ASSERT(registrar
);
1786 mRedirectChannelId
= nsContentUtils::GenerateLoadIdentifier();
1787 rv
= registrar
->RegisterChannel(newChannel
, mRedirectChannelId
);
1788 NS_ENSURE_SUCCESS(rv
, rv
);
1790 LOG(("Registered %p channel under id=%" PRIx64
, newChannel
,
1791 mRedirectChannelId
));
1794 return NS_BINDING_ABORTED
;
1797 // If this is an internal redirect for service worker interception or
1798 // internal redirect due to auth retries, then hide it from the child
1799 // process. The original e10s interception code was not designed with this
1800 // in mind and its not necessary to replace the HttpChannelChild/Parent
1801 // objects in this case.
1802 if (redirectFlags
& nsIChannelEventSink::REDIRECT_INTERNAL
) {
1803 nsCOMPtr
<nsIInterceptedChannel
> oldIntercepted
=
1804 do_QueryInterface(static_cast<nsIChannel
*>(mChannel
.get()));
1805 nsCOMPtr
<nsIInterceptedChannel
> newIntercepted
=
1806 do_QueryInterface(newChannel
);
1808 // 1. We only want to hide the special internal redirects from
1809 // nsHttpChannel to InterceptedHttpChannel.
1810 // 2. We want to allow through internal redirects
1811 // initiated from the InterceptedHttpChannel even if they are to another
1812 // InterceptedHttpChannel, except the interception reset, since
1813 // corresponding HttpChannelChild/Parent objects can be reused for reset
1815 // 3. If this is an internal redirect due to auth retry then we will
1816 // hide it from the child process
1818 if ((!oldIntercepted
&& newIntercepted
) ||
1819 (oldIntercepted
&& !newIntercepted
&& oldIntercepted
->IsReset()) ||
1820 (IsRedirectDueToAuthRetry(redirectFlags
))) {
1821 // We need to move across the reserved and initial client information
1822 // to the new channel. Normally this would be handled by the child
1823 // ClientChannelHelper, but that is not notified of this redirect since
1824 // we're not propagating it back to the child process.
1825 nsCOMPtr
<nsILoadInfo
> oldLoadInfo
= mChannel
->LoadInfo();
1827 nsCOMPtr
<nsILoadInfo
> newLoadInfo
= newChannel
->LoadInfo();
1829 Maybe
<ClientInfo
> reservedClientInfo(
1830 oldLoadInfo
->GetReservedClientInfo());
1831 if (reservedClientInfo
.isSome()) {
1832 newLoadInfo
->SetReservedClientInfo(reservedClientInfo
.ref());
1835 Maybe
<ClientInfo
> initialClientInfo(oldLoadInfo
->GetInitialClientInfo());
1836 if (initialClientInfo
.isSome()) {
1837 newLoadInfo
->SetInitialClientInfo(initialClientInfo
.ref());
1840 // If this is ServiceWorker fallback redirect, info HttpChannelChild to
1841 // detach StreamFilters. Otherwise StreamFilters will be attached twice
1842 // on the same HttpChannelChild when opening the new nsHttpChannel.
1843 if (oldIntercepted
) {
1844 Unused
<< DetachStreamFilters();
1847 // Re-link the HttpChannelParent to the new channel.
1848 nsCOMPtr
<nsIChannel
> linkedChannel
;
1849 rv
= NS_LinkRedirectChannels(mRedirectChannelId
, this,
1850 getter_AddRefs(linkedChannel
));
1851 NS_ENSURE_SUCCESS(rv
, rv
);
1852 MOZ_ASSERT(linkedChannel
== newChannel
);
1854 // We immediately store the channel as our nested mChannel.
1855 // None of the redirect IPC messaging takes place.
1856 mChannel
= do_QueryObject(newChannel
);
1858 callback
->OnRedirectVerifyCallback(NS_OK
);
1863 // Sending down the original URI, because that is the URI we have
1864 // to construct the channel from - this is the URI we've been actually
1865 // redirected to. URI of the channel may be an inner channel URI.
1866 // URI of the channel will be reconstructed by the protocol handler
1867 // on the child process, no need to send it then.
1868 nsCOMPtr
<nsIURI
> newOriginalURI
;
1869 newChannel
->GetOriginalURI(getter_AddRefs(newOriginalURI
));
1871 uint32_t newLoadFlags
= nsIRequest::LOAD_NORMAL
;
1872 MOZ_ALWAYS_SUCCEEDS(newChannel
->GetLoadFlags(&newLoadFlags
));
1874 nsCOMPtr
<nsITransportSecurityInfo
> securityInfo(SecurityInfo());
1876 // If the channel is a HTTP channel, we also want to inform the child
1877 // about the parent's channelId attribute, so that both parent and child
1878 // share the same ID. Useful for monitoring channel activity in devtools.
1879 uint64_t channelId
= 0;
1880 nsCOMPtr
<nsIHttpChannel
> httpChannel
= do_QueryInterface(newChannel
);
1882 rv
= httpChannel
->GetChannelId(&channelId
);
1883 NS_ENSURE_SUCCESS(rv
, NS_BINDING_ABORTED
);
1886 nsCOMPtr
<nsILoadInfo
> loadInfo
= mChannel
->LoadInfo();
1888 ParentLoadInfoForwarderArgs loadInfoForwarderArg
;
1889 mozilla::ipc::LoadInfoToParentLoadInfoForwarder(loadInfo
,
1890 &loadInfoForwarderArg
);
1892 nsHttpResponseHead
* responseHead
= mChannel
->GetResponseHead();
1894 nsHttpResponseHead cleanedUpResponseHead
;
1895 if (responseHead
&& responseHead
->HasHeader(nsHttp::Set_Cookie
)) {
1896 cleanedUpResponseHead
= *responseHead
;
1897 cleanedUpResponseHead
.ClearHeader(nsHttp::Set_Cookie
);
1898 responseHead
= &cleanedUpResponseHead
;
1901 if (!responseHead
) {
1902 responseHead
= &cleanedUpResponseHead
;
1906 if (!SendRedirect1Begin(mRedirectChannelId
, newOriginalURI
, newLoadFlags
,
1907 redirectFlags
, loadInfoForwarderArg
, *responseHead
,
1908 securityInfo
, channelId
, mChannel
->GetPeerAddr(),
1909 GetTimingAttributes(mChannel
))) {
1910 return NS_BINDING_ABORTED
;
1914 // Result is handled in RecvRedirect2Verify above
1916 mRedirectChannel
= newChannel
;
1917 mRedirectCallback
= callback
;
1922 HttpChannelParent::CompleteRedirect(nsresult status
) {
1923 LOG(("HttpChannelParent::CompleteRedirect [this=%p status=0x%X]\n", this,
1924 static_cast<uint32_t>(status
)));
1926 // If this was an internal redirect for a service worker interception then
1927 // we will not have a redirecting channel here. Hide this redirect from
1929 if (!mRedirectChannel
) {
1934 // TODO: check return value: assume child dead if failed
1935 if (NS_SUCCEEDED(status
)) {
1936 Unused
<< SendRedirect3Complete();
1938 Unused
<< SendRedirectFailed(status
);
1942 mRedirectChannel
= nullptr;
1946 nsresult
HttpChannelParent::OpenAlternativeOutputStream(
1947 const nsACString
& type
, int64_t predictedSize
,
1948 nsIAsyncOutputStream
** _retval
) {
1949 // We need to make sure the child does not call SendDocumentChannelCleanup()
1950 // before opening the altOutputStream, because that clears mCacheEntry.
1952 return NS_ERROR_NOT_AVAILABLE
;
1955 mCacheEntry
->OpenAlternativeOutputStream(type
, predictedSize
, _retval
);
1956 if (NS_SUCCEEDED(rv
)) {
1957 mCacheEntry
->SetMetaDataElement("alt-data-from-child", "1");
1962 already_AddRefed
<nsITransportSecurityInfo
> HttpChannelParent::SecurityInfo() {
1966 nsCOMPtr
<nsITransportSecurityInfo
> securityInfo
;
1967 mChannel
->GetSecurityInfo(getter_AddRefs(securityInfo
));
1968 return securityInfo
.forget();
1971 bool HttpChannelParent::DoSendDeleteSelf() {
1973 bool rv
= SendDeleteSelf();
1975 CleanupBackgroundChannel();
1980 mozilla::ipc::IPCResult
HttpChannelParent::RecvDeletingChannel() {
1981 // We need to ensure that the parent channel will not be sending any more IPC
1982 // messages after this, as the child is going away. DoSendDeleteSelf will
1983 // set mIPCClosed = true;
1984 if (!DoSendDeleteSelf()) {
1985 return IPC_FAIL_NO_REASON(this);
1990 //-----------------------------------------------------------------------------
1991 // HttpChannelSecurityWarningReporter
1992 //-----------------------------------------------------------------------------
1994 nsresult
HttpChannelParent::ReportSecurityMessage(
1995 const nsAString
& aMessageTag
, const nsAString
& aMessageCategory
) {
1996 if (mIPCClosed
|| NS_WARN_IF(!SendReportSecurityMessage(
1997 nsString(aMessageTag
), nsString(aMessageCategory
)))) {
1998 return NS_ERROR_UNEXPECTED
;
2003 //-----------------------------------------------------------------------------
2004 // nsIAsyncVerifyRedirectReadyCallback
2005 //-----------------------------------------------------------------------------
2008 HttpChannelParent::ReadyToVerify(nsresult aResult
) {
2009 LOG(("HttpChannelParent::ReadyToVerify [this=%p result=%" PRIx32
"]\n", this,
2010 static_cast<uint32_t>(aResult
)));
2011 MOZ_ASSERT(NS_IsMainThread());
2013 ContinueRedirect2Verify(aResult
);
2018 void HttpChannelParent::DoSendSetPriority(int16_t aValue
) {
2020 Unused
<< SendSetPriority(aValue
);
2024 nsresult
HttpChannelParent::LogBlockedCORSRequest(const nsAString
& aMessage
,
2025 const nsACString
& aCategory
,
2028 NS_WARN_IF(!SendLogBlockedCORSRequest(
2029 nsString(aMessage
), nsCString(aCategory
), aIsWarning
))) {
2030 return NS_ERROR_UNEXPECTED
;
2035 nsresult
HttpChannelParent::LogMimeTypeMismatch(const nsACString
& aMessageName
,
2037 const nsAString
& aURL
,
2038 const nsAString
& aContentType
) {
2039 if (mIPCClosed
|| NS_WARN_IF(!SendLogMimeTypeMismatch(
2040 nsCString(aMessageName
), aWarning
, nsString(aURL
),
2041 nsString(aContentType
)))) {
2042 return NS_ERROR_UNEXPECTED
;
2047 //-----------------------------------------------------------------------------
2048 // nsIChannelEventSink
2049 //-----------------------------------------------------------------------------
2052 HttpChannelParent::AsyncOnChannelRedirect(
2053 nsIChannel
* aOldChannel
, nsIChannel
* aNewChannel
, uint32_t aRedirectFlags
,
2054 nsIAsyncVerifyRedirectCallback
* aCallback
) {
2056 ("HttpChannelParent::AsyncOnChannelRedirect [this=%p, old=%p, "
2057 "new=%p, flags=%u]",
2058 this, aOldChannel
, aNewChannel
, aRedirectFlags
));
2060 return StartRedirect(aNewChannel
, aRedirectFlags
, aCallback
);
2063 //-----------------------------------------------------------------------------
2064 // nsIRedirectResultListener
2065 //-----------------------------------------------------------------------------
2068 HttpChannelParent::OnRedirectResult(nsresult status
) {
2069 LOG(("HttpChannelParent::OnRedirectResult [this=%p, status=0x%X]", this,
2070 static_cast<uint32_t>(status
)));
2072 nsresult rv
= NS_OK
;
2074 nsCOMPtr
<nsIParentChannel
> redirectChannel
;
2075 if (mRedirectChannelId
) {
2076 nsCOMPtr
<nsIRedirectChannelRegistrar
> registrar
=
2077 RedirectChannelRegistrar::GetOrCreate();
2078 MOZ_ASSERT(registrar
);
2080 rv
= registrar
->GetParentChannel(mRedirectChannelId
,
2081 getter_AddRefs(redirectChannel
));
2082 if (NS_FAILED(rv
) || !redirectChannel
) {
2083 // Redirect might get canceled before we got AsyncOnChannelRedirect
2084 LOG(("Registered parent channel not found under id=%" PRIx64
,
2085 mRedirectChannelId
));
2087 nsCOMPtr
<nsIChannel
> newChannel
;
2088 rv
= registrar
->GetRegisteredChannel(mRedirectChannelId
,
2089 getter_AddRefs(newChannel
));
2090 MOZ_ASSERT(newChannel
, "Already registered channel not found");
2092 if (NS_SUCCEEDED(rv
)) {
2093 newChannel
->Cancel(NS_BINDING_ABORTED
);
2097 // Release all previously registered channels, they are no longer need to be
2098 // kept in the registrar from this moment.
2099 registrar
->DeregisterChannels(mRedirectChannelId
);
2101 mRedirectChannelId
= 0;
2104 if (!redirectChannel
) {
2105 if (NS_FAILED(rv
)) {
2108 status
= NS_ERROR_NULL_POINTER
;
2112 CompleteRedirect(status
);
2114 if (NS_SUCCEEDED(status
)) {
2115 if (!SameCOMIdentity(redirectChannel
,
2116 static_cast<nsIParentRedirectingChannel
*>(this))) {
2118 mParentListener
->SetListenerAfterRedirect(redirectChannel
);
2119 redirectChannel
->SetParentListener(mParentListener
);
2121 } else if (redirectChannel
) {
2122 // Delete the redirect target channel: continue using old channel
2123 redirectChannel
->Delete();
2129 void HttpChannelParent::OverrideReferrerInfoDuringBeginConnect(
2130 nsIReferrerInfo
* aReferrerInfo
) {
2131 MOZ_ASSERT(aReferrerInfo
);
2132 MOZ_ASSERT(!mAfterOnStartRequestBegun
);
2134 mOverrideReferrerInfo
= aReferrerInfo
;
2137 auto HttpChannelParent::AttachStreamFilter(
2138 Endpoint
<extensions::PStreamFilterParent
>&& aParentEndpoint
,
2139 Endpoint
<extensions::PStreamFilterChild
>&& aChildEndpoint
)
2140 -> RefPtr
<ChildEndpointPromise
> {
2141 LOG(("HttpChannelParent::AttachStreamFilter [this=%p]", this));
2142 MOZ_ASSERT(!mAfterOnStartRequestBegun
);
2145 return ChildEndpointPromise::CreateAndReject(false, __func__
);
2148 // If IPC channel is open, background channel should be ready to send
2149 // SendAttachStreamFilter.
2150 MOZ_ASSERT(mBgParent
);
2151 return InvokeAsync(mBgParent
->GetBackgroundTarget(), mBgParent
.get(),
2152 __func__
, &HttpBackgroundChannelParent::AttachStreamFilter
,
2153 std::move(aParentEndpoint
), std::move(aChildEndpoint
));
2156 auto HttpChannelParent::DetachStreamFilters() -> RefPtr
<GenericPromise
> {
2157 LOG(("HttpChannelParent::DeattachStreamFilter [this=%p]", this));
2158 MOZ_ASSERT(!mAfterOnStartRequestBegun
);
2160 if (NS_WARN_IF(mIPCClosed
)) {
2161 return GenericPromise::CreateAndReject(NS_ERROR_FAILURE
, __func__
);
2164 MOZ_ASSERT(mBgParent
);
2165 return InvokeAsync(mBgParent
->GetBackgroundTarget(), mBgParent
.get(),
2167 &HttpBackgroundChannelParent::DetachStreamFilters
);
2170 void HttpChannelParent::SetHttpChannelFromEarlyHintPreloader(
2171 HttpBaseChannel
* aChannel
) {
2172 MOZ_ASSERT(aChannel
);
2174 MOZ_ASSERT(false, "SetHttpChannel called with mChannel aready set");
2178 mChannel
= aChannel
;
2181 void HttpChannelParent::SetCookie(nsCString
&& aCookie
) {
2182 LOG(("HttpChannelParent::SetCookie [this=%p]", this));
2183 MOZ_ASSERT(!mAfterOnStartRequestBegun
);
2184 MOZ_ASSERT(mCookie
.IsEmpty());
2186 // The loadGroup of the channel in the parent process could be null in the
2187 // XPCShell content process test, see test_cookiejars_wrap.js. In this case,
2188 // we cannot explicitly set the loadGroup for the parent channel because it's
2189 // created from the content process. To workaround this, we add a testing pref
2190 // to skip this check.
2191 if (!Preferences::GetBool(
2192 "network.cookie.skip_browsing_context_check_in_parent_for_testing") &&
2193 mChannel
->IsBrowsingContextDiscarded()) {
2196 mCookie
= std::move(aCookie
);
2199 } // namespace mozilla::net