HttpChannelParent.cpp (79190B)
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/. */ 6 7 // HttpLog.h should generally be included first 8 #include "ErrorList.h" 9 #include "HttpLog.h" 10 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/net/CacheEntryWriteHandleParent.h" 17 #include "mozilla/dom/ContentParent.h" 18 #include "mozilla/dom/ContentProcessManager.h" 19 #include "mozilla/dom/Element.h" 20 #include "mozilla/dom/ServiceWorkerUtils.h" 21 #include "mozilla/dom/BrowserParent.h" 22 #include "mozilla/dom/WindowGlobalParent.h" 23 #include "mozilla/net/NeckoParent.h" 24 #include "mozilla/net/ExecuteIfOnMainThreadEventTarget.h" 25 #include "mozilla/net/CookieServiceParent.h" 26 #include "nsIClassOfService.h" 27 #include "mozilla/Components.h" 28 #include "mozilla/InputStreamLengthHelper.h" 29 #include "mozilla/IntegerPrintfMacros.h" 30 #include "mozilla/ProfilerLabels.h" 31 #include "mozilla/ProfilerMarkers.h" 32 #include "mozilla/StaticPrefs_network.h" 33 #include "mozilla/StoragePrincipalHelper.h" 34 #include "HttpBackgroundChannelParent.h" 35 #include "ParentChannelListener.h" 36 #include "nsDebug.h" 37 #include "nsICacheInfoChannel.h" 38 #include "nsHttpHandler.h" 39 #include "nsNetCID.h" 40 #include "nsNetUtil.h" 41 #include "nsISupportsPriority.h" 42 #include "mozilla/net/BackgroundChannelRegistrar.h" 43 #include "nsSerializationHelper.h" 44 #include "nsISerializable.h" 45 #include "mozilla/ipc/InputStreamUtils.h" 46 #include "mozilla/ipc/URIUtils.h" 47 #include "SerializedLoadContext.h" 48 #include "nsIAuthPrompt.h" 49 #include "nsIAuthPrompt2.h" 50 #include "mozilla/ipc/BackgroundUtils.h" 51 #include "mozilla/LoadInfo.h" 52 #include "nsQueryObject.h" 53 #include "mozilla/BasePrincipal.h" 54 #include "nsCORSListenerProxy.h" 55 #include "nsIIPCSerializableInputStream.h" 56 #include "nsIPrompt.h" 57 #include "nsIPromptFactory.h" 58 #include "mozilla/net/ChannelEventQueue.h" 59 #include "mozilla/net/RedirectChannelRegistrar.h" 60 #include "nsIWindowWatcher.h" 61 #include "mozilla/dom/Document.h" 62 #include "nsISecureBrowserUI.h" 63 #include "nsStreamUtils.h" 64 #include "nsStringStream.h" 65 #include "nsThreadUtils.h" 66 #include "nsQueryObject.h" 67 #include "nsIMultiPartChannel.h" 68 #include "nsIViewSourceChannel.h" 69 70 using namespace mozilla; 71 72 namespace geckoprofiler::markers { 73 74 struct ChannelMarker { 75 static constexpr Span<const char> MarkerTypeName() { 76 return MakeStringSpan("ChannelMarker"); 77 } 78 static void StreamJSONMarkerData( 79 mozilla::baseprofiler::SpliceableJSONWriter& aWriter, 80 const mozilla::ProfilerString8View& aURL, uint64_t aChannelId) { 81 if (aURL.Length() != 0) { 82 aWriter.StringProperty("url", aURL); 83 } 84 aWriter.IntProperty("channelId", static_cast<int64_t>(aChannelId)); 85 } 86 static MarkerSchema MarkerTypeDisplay() { 87 using MS = MarkerSchema; 88 MS schema(MS::Location::MarkerChart, MS::Location::MarkerTable); 89 schema.SetTableLabel("{marker.data.url}"); 90 schema.AddKeyFormat("url", MS::Format::Url, MS::PayloadFlags::Searchable); 91 schema.AddStaticLabelValue( 92 "Description", 93 "Timestamp capturing various phases of a network channel's lifespan."); 94 return schema; 95 } 96 }; 97 98 } // namespace geckoprofiler::markers 99 100 using mozilla::BasePrincipal; 101 using namespace mozilla::dom; 102 using namespace mozilla::ipc; 103 104 namespace mozilla::net { 105 106 HttpChannelParent::HttpChannelParent(dom::BrowserParent* iframeEmbedding, 107 nsILoadContext* aLoadContext, 108 PBOverrideStatus aOverrideStatus) 109 : mLoadContext(aLoadContext), 110 mIPCClosed(false), 111 mPBOverride(aOverrideStatus), 112 mStatus(NS_OK), 113 mIgnoreProgress(false), 114 mHasSuspendedByBackPressure(false), 115 mCacheNeedFlowControlInitialized(false), 116 mNeedFlowControl(true), 117 mSuspendedForFlowControl(false), 118 mAfterOnStartRequestBegun(false), 119 mDataSentToChildProcess(false) { 120 LOG(("Creating HttpChannelParent [this=%p]\n", this)); 121 122 // Ensure gHttpHandler is initialized: we need the atom table up and running. 123 nsCOMPtr<nsIHttpProtocolHandler> dummyInitializer = 124 do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http"); 125 126 MOZ_ASSERT(gHttpHandler); 127 mHttpHandler = gHttpHandler; 128 129 mBrowserParent = iframeEmbedding; 130 131 mSendWindowSize = gHttpHandler->SendWindowSize(); 132 133 mEventQ = 134 new ChannelEventQueue(static_cast<nsIParentRedirectingChannel*>(this)); 135 } 136 137 HttpChannelParent::~HttpChannelParent() { 138 LOG(("Destroying HttpChannelParent [this=%p]\n", this)); 139 CleanupBackgroundChannel(); 140 141 MOZ_ASSERT(!mRedirectCallback); 142 if (NS_WARN_IF(mRedirectCallback)) { 143 mRedirectCallback->OnRedirectVerifyCallback(NS_ERROR_UNEXPECTED); 144 mRedirectCallback = nullptr; 145 } 146 mEventQ->NotifyReleasingOwner(); 147 } 148 149 void HttpChannelParent::ActorDestroy(ActorDestroyReason why) { 150 // We may still have refcount>0 if nsHttpChannel hasn't called OnStopRequest 151 // yet, but child process has crashed. We must not try to send any more msgs 152 // to child, or IPDL will kill chrome process, too. 153 mIPCClosed = true; 154 CleanupBackgroundChannel(); 155 } 156 157 bool HttpChannelParent::Init(const HttpChannelCreationArgs& aArgs) { 158 LOG(("HttpChannelParent::Init [this=%p]\n", this)); 159 AUTO_PROFILER_LABEL("HttpChannelParent::Init", NETWORK); 160 switch (aArgs.type()) { 161 case HttpChannelCreationArgs::THttpChannelOpenArgs: { 162 const HttpChannelOpenArgs& a = aArgs.get_HttpChannelOpenArgs(); 163 return DoAsyncOpen( 164 a.uri(), a.original(), a.doc(), a.referrerInfo(), a.apiRedirectTo(), 165 a.topWindowURI(), a.loadFlags(), a.requestHeaders(), 166 a.requestMethod(), a.uploadStream(), a.uploadStreamHasHeaders(), 167 a.priority(), a.classOfService(), a.redirectionLimit(), a.allowSTS(), 168 a.thirdPartyFlags(), a.resumeAt(), a.startPos(), a.entityID(), 169 a.allowSpdy(), a.allowHttp3(), a.allowAltSvc(), a.beConservative(), 170 a.bypassProxy(), a.tlsFlags(), a.loadInfo(), a.cacheKey(), 171 a.requestContextID(), a.preflightArgs(), a.initialRwin(), 172 a.blockAuthPrompt(), a.allowStaleCacheContent(), 173 a.preferCacheLoadOverBypass(), a.contentTypeHint(), a.requestMode(), 174 a.redirectMode(), a.channelId(), a.contentWindowId(), 175 a.preferredAlternativeTypes(), a.browserId(), 176 a.launchServiceWorkerStart(), a.launchServiceWorkerEnd(), 177 a.dispatchFetchEventStart(), a.dispatchFetchEventEnd(), 178 a.handleFetchEventStart(), a.handleFetchEventEnd(), 179 a.forceMainDocumentChannel(), a.navigationStartTimeStamp(), 180 a.earlyHintPreloaderId(), a.classicScriptHintCharset(), 181 a.documentCharacterSet(), a.isUserAgentHeaderModified(), 182 a.initiatorType()); 183 } 184 case HttpChannelCreationArgs::THttpChannelConnectArgs: { 185 const HttpChannelConnectArgs& cArgs = aArgs.get_HttpChannelConnectArgs(); 186 return ConnectChannel(cArgs.registrarId()); 187 } 188 default: 189 MOZ_ASSERT_UNREACHABLE("unknown open type"); 190 return false; 191 } 192 } 193 194 void HttpChannelParent::TryInvokeAsyncOpen(nsresult aRv) { 195 LOG(("HttpChannelParent::TryInvokeAsyncOpen [this=%p barrier=%u rv=%" PRIx32 196 "]\n", 197 this, mAsyncOpenBarrier, static_cast<uint32_t>(aRv))); 198 MOZ_ASSERT(NS_IsMainThread()); 199 AUTO_PROFILER_LABEL("HttpChannelParent::TryInvokeAsyncOpen", NETWORK); 200 201 // TryInvokeAsyncOpen is called more than we expected. 202 // Assert in nightly build but ignore it in release channel. 203 MOZ_DIAGNOSTIC_ASSERT(mAsyncOpenBarrier > 0); 204 if (NS_WARN_IF(!mAsyncOpenBarrier)) { 205 return; 206 } 207 208 if (--mAsyncOpenBarrier > 0 && NS_SUCCEEDED(aRv)) { 209 // Need to wait for more events. 210 return; 211 } 212 213 InvokeAsyncOpen(aRv); 214 } 215 216 void HttpChannelParent::OnBackgroundParentReady( 217 HttpBackgroundChannelParent* aBgParent) { 218 LOG(("HttpChannelParent::OnBackgroundParentReady [this=%p bgParent=%p]\n", 219 this, aBgParent)); 220 MOZ_ASSERT(NS_IsMainThread()); 221 MOZ_ASSERT(!mBgParent); 222 223 mBgParent = aBgParent; 224 225 mPromise.ResolveIfExists(true, __func__); 226 } 227 228 void HttpChannelParent::OnBackgroundParentDestroyed() { 229 LOG(("HttpChannelParent::OnBackgroundParentDestroyed [this=%p]\n", this)); 230 MOZ_ASSERT(NS_IsMainThread()); 231 232 if (!mPromise.IsEmpty()) { 233 MOZ_ASSERT(!mBgParent); 234 mPromise.Reject(NS_ERROR_FAILURE, __func__); 235 return; 236 } 237 238 if (!mBgParent) { 239 return; 240 } 241 242 // Background channel is closed unexpectly, abort PHttpChannel operation. 243 mBgParent = nullptr; 244 Delete(); 245 } 246 247 void HttpChannelParent::CleanupBackgroundChannel() { 248 LOG(("HttpChannelParent::CleanupBackgroundChannel [this=%p bgParent=%p]\n", 249 this, mBgParent.get())); 250 MOZ_ASSERT(NS_IsMainThread()); 251 252 if (mBgParent) { 253 RefPtr<HttpBackgroundChannelParent> bgParent = std::move(mBgParent); 254 bgParent->OnChannelClosed(); 255 return; 256 } 257 258 // The nsHttpChannel may have a reference to this parent, release it 259 // to avoid circular references. 260 RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(mChannel); 261 if (httpChannelImpl) { 262 httpChannelImpl->SetWarningReporter(nullptr); 263 } 264 265 if (!mPromise.IsEmpty()) { 266 mRequest.DisconnectIfExists(); 267 mPromise.Reject(NS_ERROR_FAILURE, __func__); 268 269 if (!mChannel) { 270 return; 271 } 272 273 // This HttpChannelParent might still have a reference from 274 // BackgroundChannelRegistrar. 275 nsCOMPtr<nsIBackgroundChannelRegistrar> registrar = 276 BackgroundChannelRegistrar::GetOrCreate(); 277 MOZ_ASSERT(registrar); 278 279 registrar->DeleteChannel(mChannel->ChannelId()); 280 281 // If mAsyncOpenBarrier is greater than zero, it means AsyncOpen procedure 282 // is still on going. we need to abort AsyncOpen with failure to destroy 283 // PHttpChannel actor. 284 if (mAsyncOpenBarrier) { 285 TryInvokeAsyncOpen(NS_ERROR_FAILURE); 286 } 287 } 288 } 289 290 base::ProcessId HttpChannelParent::OtherPid() const { 291 if (mIPCClosed) { 292 return 0; 293 } 294 return PHttpChannelParent::OtherPid(); 295 } 296 297 //----------------------------------------------------------------------------- 298 // HttpChannelParent::nsISupports 299 //----------------------------------------------------------------------------- 300 301 NS_IMPL_ADDREF(HttpChannelParent) 302 NS_IMPL_RELEASE(HttpChannelParent) 303 NS_INTERFACE_MAP_BEGIN(HttpChannelParent) 304 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) 305 NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink) 306 NS_INTERFACE_MAP_ENTRY(nsIRequestObserver) 307 NS_INTERFACE_MAP_ENTRY(nsIStreamListener) 308 NS_INTERFACE_MAP_ENTRY(nsIParentChannel) 309 NS_INTERFACE_MAP_ENTRY(nsIParentRedirectingChannel) 310 NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectReadyCallback) 311 NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink) 312 NS_INTERFACE_MAP_ENTRY(nsIRedirectResultListener) 313 NS_INTERFACE_MAP_ENTRY(nsIMultiPartChannelListener) 314 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIParentRedirectingChannel) 315 NS_INTERFACE_MAP_ENTRY_CONCRETE(HttpChannelParent) 316 NS_INTERFACE_MAP_END 317 318 //----------------------------------------------------------------------------- 319 // HttpChannelParent::nsIInterfaceRequestor 320 //----------------------------------------------------------------------------- 321 322 NS_IMETHODIMP 323 HttpChannelParent::GetInterface(const nsIID& aIID, void** result) { 324 // A system XHR can be created without reference to a window, hence mTabParent 325 // may be null. In that case we want to let the window watcher pick a prompt 326 // directly. 327 if (!mBrowserParent && (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) || 328 aIID.Equals(NS_GET_IID(nsIAuthPrompt2)))) { 329 nsresult rv; 330 nsCOMPtr<nsIWindowWatcher> wwatch; 331 wwatch = mozilla::components::WindowWatcher::Service(&rv); 332 NS_ENSURE_SUCCESS(rv, NS_ERROR_NO_INTERFACE); 333 334 bool hasWindowCreator = false; 335 (void)wwatch->HasWindowCreator(&hasWindowCreator); 336 if (!hasWindowCreator) { 337 return NS_ERROR_NO_INTERFACE; 338 } 339 340 nsCOMPtr<nsIPromptFactory> factory = do_QueryInterface(wwatch); 341 if (!factory) { 342 return NS_ERROR_NO_INTERFACE; 343 } 344 rv = factory->GetPrompt(nullptr, aIID, reinterpret_cast<void**>(result)); 345 if (NS_FAILED(rv)) { 346 return NS_ERROR_NO_INTERFACE; 347 } 348 return NS_OK; 349 } 350 351 // Only support nsILoadContext if child channel's callbacks did too 352 if (aIID.Equals(NS_GET_IID(nsILoadContext)) && mLoadContext) { 353 nsCOMPtr<nsILoadContext> copy = mLoadContext; 354 copy.forget(result); 355 return NS_OK; 356 } 357 358 return QueryInterface(aIID, result); 359 } 360 361 //----------------------------------------------------------------------------- 362 // HttpChannelParent::PHttpChannelParent 363 //----------------------------------------------------------------------------- 364 365 void HttpChannelParent::AsyncOpenFailed(nsresult aRv) { 366 MOZ_ASSERT(NS_IsMainThread()); 367 MOZ_ASSERT(NS_FAILED(aRv)); 368 369 // Break the reference cycle among HttpChannelParent, 370 // ParentChannelListener, and nsHttpChannel to avoid memory leakage. 371 mChannel = nullptr; 372 mParentListener = nullptr; 373 374 if (!mIPCClosed) { 375 (void)SendFailedAsyncOpen(aRv); 376 } 377 } 378 379 void HttpChannelParent::InvokeAsyncOpen(nsresult rv) { 380 LOG(("HttpChannelParent::InvokeAsyncOpen [this=%p rv=%" PRIx32 "]\n", this, 381 static_cast<uint32_t>(rv))); 382 MOZ_ASSERT(NS_IsMainThread()); 383 384 if (NS_FAILED(rv)) { 385 AsyncOpenFailed(rv); 386 return; 387 } 388 389 rv = mChannel->AsyncOpen(mParentListener); 390 if (NS_FAILED(rv)) { 391 AsyncOpenFailed(rv); 392 } 393 } 394 395 void HttpChannelParent::InvokeEarlyHintPreloader( 396 nsresult rv, uint64_t aEarlyHintPreloaderId) { 397 LOG(("HttpChannelParent::InvokeEarlyHintPreloader [this=%p rv=%" PRIx32 "]\n", 398 this, static_cast<uint32_t>(rv))); 399 MOZ_ASSERT(NS_IsMainThread()); 400 401 ContentParentId cpId = 402 static_cast<ContentParent*>(Manager()->Manager())->ChildID(); 403 404 RefPtr<EarlyHintRegistrar> ehr = EarlyHintRegistrar::GetOrCreate(); 405 if (NS_SUCCEEDED(rv)) { 406 rv = ehr->LinkParentChannel(cpId, aEarlyHintPreloaderId, this) 407 ? NS_OK 408 : NS_ERROR_FAILURE; 409 } 410 411 if (NS_FAILED(rv)) { 412 ehr->DeleteEntry(cpId, aEarlyHintPreloaderId); 413 AsyncOpenFailed(NS_ERROR_FAILURE); 414 } 415 } 416 417 bool HttpChannelParent::DoAsyncOpen( 418 nsIURI* aURI, nsIURI* aOriginalURI, nsIURI* aDocURI, 419 nsIReferrerInfo* aReferrerInfo, nsIURI* aAPIRedirectToURI, 420 nsIURI* aTopWindowURI, const uint32_t& aLoadFlags, 421 const RequestHeaderTuples& requestHeaders, const nsCString& requestMethod, 422 const Maybe<IPCStream>& uploadStream, const bool& uploadStreamHasHeaders, 423 const int16_t& priority, const ClassOfService& classOfService, 424 const uint8_t& redirectionLimit, const bool& allowSTS, 425 const uint32_t& thirdPartyFlags, const bool& doResumeAt, 426 const uint64_t& startPos, const nsCString& entityID, const bool& allowSpdy, 427 const bool& allowHttp3, const bool& allowAltSvc, const bool& beConservative, 428 const bool& bypassProxy, const uint32_t& tlsFlags, 429 const LoadInfoArgs& aLoadInfoArgs, const uint32_t& aCacheKey, 430 const uint64_t& aRequestContextID, 431 const Maybe<CorsPreflightArgs>& aCorsPreflightArgs, 432 const uint32_t& aInitialRwin, const bool& aBlockAuthPrompt, 433 const bool& aAllowStaleCacheContent, const bool& aPreferCacheLoadOverBypass, 434 const nsCString& aContentTypeHint, const dom::RequestMode& aRequestMode, 435 const uint32_t& aRedirectMode, const uint64_t& aChannelId, 436 const uint64_t& aContentWindowId, 437 const nsTArray<PreferredAlternativeDataTypeParams>& 438 aPreferredAlternativeTypes, 439 const uint64_t& aBrowserId, const TimeStamp& aLaunchServiceWorkerStart, 440 const TimeStamp& aLaunchServiceWorkerEnd, 441 const TimeStamp& aDispatchFetchEventStart, 442 const TimeStamp& aDispatchFetchEventEnd, 443 const TimeStamp& aHandleFetchEventStart, 444 const TimeStamp& aHandleFetchEventEnd, 445 const bool& aForceMainDocumentChannel, 446 const TimeStamp& aNavigationStartTimeStamp, 447 const uint64_t& aEarlyHintPreloaderId, 448 const nsAString& aClassicScriptHintCharset, 449 const nsAString& aDocumentCharacterSet, 450 const bool& aIsUserAgentHeaderModified, const nsString& aInitiatorType) { 451 MOZ_ASSERT(aURI, "aURI should not be NULL"); 452 453 if (aEarlyHintPreloaderId) { 454 // Wait for HttpBackgrounChannel to continue the async open procedure. 455 mEarlyHintPreloaderId = aEarlyHintPreloaderId; 456 RefPtr<HttpChannelParent> self = this; 457 WaitForBgParent(aChannelId) 458 ->Then( 459 GetMainThreadSerialEventTarget(), __func__, 460 [self, aEarlyHintPreloaderId]() { 461 self->mRequest.Complete(); 462 self->InvokeEarlyHintPreloader(NS_OK, aEarlyHintPreloaderId); 463 }, 464 [self, aEarlyHintPreloaderId](nsresult aStatus) { 465 self->mRequest.Complete(); 466 self->InvokeEarlyHintPreloader(aStatus, aEarlyHintPreloaderId); 467 }) 468 ->Track(mRequest); 469 return true; 470 } 471 472 if (!aURI) { 473 // this check is neccessary to prevent null deref 474 // in opt builds 475 return false; 476 } 477 478 LOG(("HttpChannelParent RecvAsyncOpen [this=%p uri=%s, gid=%" PRIu64 479 " browserid=%" PRIx64 "]\n", 480 this, aURI->GetSpecOrDefault().get(), aChannelId, aBrowserId)); 481 482 PROFILER_MARKER("Receive AsyncOpen in Parent", NETWORK, 483 MarkerThreadId::MainThread(), ChannelMarker, 484 aURI->GetSpecOrDefault(), aChannelId); 485 486 nsresult rv; 487 nsAutoCString remoteType; 488 rv = GetRemoteType(remoteType); 489 if (NS_FAILED(rv)) { 490 return SendFailedAsyncOpen(rv); 491 } 492 493 nsCOMPtr<nsILoadInfo> loadInfo; 494 rv = mozilla::ipc::LoadInfoArgsToLoadInfo(aLoadInfoArgs, remoteType, 495 getter_AddRefs(loadInfo)); 496 if (NS_FAILED(rv)) { 497 return SendFailedAsyncOpen(rv); 498 } 499 500 nsCOMPtr<nsIChannel> channel; 501 rv = mHttpHandler->NewProxiedChannel(aURI, nullptr, 0, nullptr, loadInfo, 502 getter_AddRefs(channel)); 503 if (NS_FAILED(rv)) { 504 return SendFailedAsyncOpen(rv); 505 } 506 507 RefPtr<HttpBaseChannel> httpChannel = do_QueryObject(channel, &rv); 508 if (NS_FAILED(rv)) { 509 return SendFailedAsyncOpen(rv); 510 } 511 512 // Set attributes needed to create a FetchEvent from this channel. 513 httpChannel->SetRequestMode(aRequestMode); 514 httpChannel->SetRedirectMode(aRedirectMode); 515 516 // Set the channelId allocated in child to the parent instance 517 httpChannel->SetChannelId(aChannelId); 518 httpChannel->SetTopLevelContentWindowId(aContentWindowId); 519 httpChannel->SetBrowserId(aBrowserId); 520 521 RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(httpChannel); 522 if (httpChannelImpl) { 523 httpChannelImpl->SetWarningReporter(this); 524 } 525 if (mPBOverride != kPBOverride_Unset) { 526 httpChannel->SetPrivate(mPBOverride == kPBOverride_Private); 527 } 528 529 if (doResumeAt) httpChannel->ResumeAt(startPos, entityID); 530 531 if (aOriginalURI) { 532 httpChannel->SetOriginalURI(aOriginalURI); 533 } 534 535 if (aDocURI) { 536 httpChannel->SetDocumentURI(aDocURI); 537 } 538 539 if (aReferrerInfo) { 540 // Referrer header is computed in child no need to recompute here 541 rv = 542 httpChannel->SetReferrerInfoInternal(aReferrerInfo, false, false, true); 543 MOZ_ASSERT(NS_SUCCEEDED(rv)); 544 } 545 546 httpChannel->SetClassicScriptHintCharset(aClassicScriptHintCharset); 547 httpChannel->SetDocumentCharacterSet(aDocumentCharacterSet); 548 549 if (aAPIRedirectToURI) { 550 httpChannel->RedirectTo(aAPIRedirectToURI); 551 } 552 553 if (aTopWindowURI) { 554 httpChannel->SetTopWindowURI(aTopWindowURI); 555 } 556 557 if (aLoadFlags != nsIRequest::LOAD_NORMAL) { 558 httpChannel->SetLoadFlags(aLoadFlags); 559 } 560 561 if (aForceMainDocumentChannel) { 562 httpChannel->SetIsMainDocumentChannel(true); 563 } 564 565 for (uint32_t i = 0; i < requestHeaders.Length(); i++) { 566 if (requestHeaders[i].mEmpty) { 567 httpChannel->SetEmptyRequestHeader(requestHeaders[i].mHeader); 568 } else { 569 httpChannel->SetRequestHeader(requestHeaders[i].mHeader, 570 requestHeaders[i].mValue, 571 requestHeaders[i].mMerge); 572 } 573 } 574 575 httpChannel->SetIsUserAgentHeaderModified(aIsUserAgentHeaderModified); 576 577 httpChannel->SetInitiatorType(aInitiatorType); 578 579 RefPtr<ParentChannelListener> parentListener = new ParentChannelListener( 580 this, mBrowserParent ? mBrowserParent->GetBrowsingContext() : nullptr); 581 582 httpChannel->SetRequestMethod(nsDependentCString(requestMethod.get())); 583 584 if (aCorsPreflightArgs.isSome()) { 585 const CorsPreflightArgs& args = aCorsPreflightArgs.ref(); 586 httpChannel->SetCorsPreflightParameters(args.unsafeHeaders(), false, false); 587 } 588 589 nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(uploadStream); 590 if (stream) { 591 rv = httpChannel->InternalSetUploadStream(stream); 592 if (NS_FAILED(rv)) { 593 return SendFailedAsyncOpen(rv); 594 } 595 596 httpChannel->SetUploadStreamHasHeaders(uploadStreamHasHeaders); 597 } 598 599 nsCOMPtr<nsICacheInfoChannel> cacheChannel = 600 do_QueryInterface(static_cast<nsIChannel*>(httpChannel.get())); 601 if (cacheChannel) { 602 cacheChannel->SetCacheKey(aCacheKey); 603 for (const auto& data : aPreferredAlternativeTypes) { 604 cacheChannel->PreferAlternativeDataType(data.type(), data.contentType(), 605 data.deliverAltData()); 606 } 607 608 cacheChannel->SetAllowStaleCacheContent(aAllowStaleCacheContent); 609 cacheChannel->SetPreferCacheLoadOverBypass(aPreferCacheLoadOverBypass); 610 611 // This is to mark that the results are going to the content process. 612 if (httpChannelImpl) { 613 httpChannelImpl->SetAltDataForChild(true); 614 } 615 } 616 617 httpChannel->SetContentType(aContentTypeHint); 618 619 if (priority != nsISupportsPriority::PRIORITY_NORMAL) { 620 httpChannel->SetPriority(priority); 621 } 622 if (classOfService.Flags() || classOfService.Incremental()) { 623 httpChannel->SetClassOfService(classOfService); 624 } 625 httpChannel->SetRedirectionLimit(redirectionLimit); 626 httpChannel->SetAllowSTS(allowSTS); 627 httpChannel->SetThirdPartyFlags(thirdPartyFlags); 628 httpChannel->SetAllowSpdy(allowSpdy); 629 httpChannel->SetAllowHttp3(allowHttp3); 630 httpChannel->SetAllowAltSvc(allowAltSvc); 631 httpChannel->SetBeConservative(beConservative); 632 httpChannel->SetTlsFlags(tlsFlags); 633 httpChannel->SetInitialRwin(aInitialRwin); 634 httpChannel->SetBlockAuthPrompt(aBlockAuthPrompt); 635 636 httpChannel->SetLaunchServiceWorkerStart(aLaunchServiceWorkerStart); 637 httpChannel->SetLaunchServiceWorkerEnd(aLaunchServiceWorkerEnd); 638 httpChannel->SetDispatchFetchEventStart(aDispatchFetchEventStart); 639 httpChannel->SetDispatchFetchEventEnd(aDispatchFetchEventEnd); 640 httpChannel->SetHandleFetchEventStart(aHandleFetchEventStart); 641 httpChannel->SetHandleFetchEventEnd(aHandleFetchEventEnd); 642 643 httpChannel->SetNavigationStartTimeStamp(aNavigationStartTimeStamp); 644 httpChannel->SetRequestContextID(aRequestContextID); 645 646 // Store the strong reference of channel and parent listener object until 647 // all the initialization procedure is complete without failure, to remove 648 // cycle reference in fail case and to avoid memory leakage. 649 mChannel = std::move(httpChannel); 650 mParentListener = std::move(parentListener); 651 mChannel->SetNotificationCallbacks(mParentListener); 652 653 MOZ_ASSERT(!mBgParent); 654 MOZ_ASSERT(mPromise.IsEmpty()); 655 // Wait for HttpBackgroundChannel to continue the async open procedure. 656 ++mAsyncOpenBarrier; 657 RefPtr<HttpChannelParent> self = this; 658 nsCOMPtr<nsISerialEventTarget> eventTarget = GetEventTargetForBgParentWait(); 659 WaitForBgParent(mChannel->ChannelId()) 660 ->Then( 661 eventTarget, __func__, 662 [self]() { 663 self->mRequest.Complete(); 664 self->TryInvokeAsyncOpen(NS_OK); 665 }, 666 [self](nsresult aStatus) { 667 self->mRequest.Complete(); 668 self->TryInvokeAsyncOpen(aStatus); 669 }) 670 ->Track(mRequest); 671 return true; 672 } 673 674 RefPtr<GenericNonExclusivePromise> HttpChannelParent::WaitForBgParent( 675 uint64_t aChannelId) { 676 LOG(("HttpChannelParent::WaitForBgParent [this=%p]\n", this)); 677 MOZ_ASSERT(!mBgParent); 678 679 if (!mChannel && !mEarlyHintPreloaderId) { 680 return GenericNonExclusivePromise::CreateAndReject(NS_ERROR_FAILURE, 681 __func__); 682 } 683 684 nsCOMPtr<nsIBackgroundChannelRegistrar> registrar = 685 BackgroundChannelRegistrar::GetOrCreate(); 686 MOZ_ASSERT(registrar); 687 registrar->LinkHttpChannel(aChannelId, this); 688 689 if (mBgParent) { 690 return GenericNonExclusivePromise::CreateAndResolve(true, __func__); 691 } 692 693 return mPromise.Ensure(__func__); 694 } 695 696 bool HttpChannelParent::ConnectChannel(const uint32_t& registrarId) { 697 nsresult rv; 698 699 LOG( 700 ("HttpChannelParent::ConnectChannel: Looking for a registered channel " 701 "[this=%p, id=%" PRIu32 "]\n", 702 this, registrarId)); 703 nsCOMPtr<nsIChannel> channel; 704 rv = NS_LinkRedirectChannels(registrarId, this, getter_AddRefs(channel)); 705 if (NS_FAILED(rv)) { 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. 710 Delete(); 711 return true; 712 } 713 714 LOG((" found channel %p, rv=%08" PRIx32, channel.get(), 715 static_cast<uint32_t>(rv))); 716 mChannel = do_QueryObject(channel); 717 if (!mChannel) { 718 LOG((" but it's not HttpBaseChannel")); 719 Delete(); 720 return true; 721 } 722 723 LOG((" and it is HttpBaseChannel %p", mChannel.get())); 724 725 RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(mChannel); 726 if (httpChannelImpl) { 727 httpChannelImpl->SetWarningReporter(this); 728 } 729 730 if (mPBOverride != kPBOverride_Unset) { 731 // redirected-to channel may not support PB 732 nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel = do_QueryObject(mChannel); 733 if (pbChannel) { 734 pbChannel->SetPrivate(mPBOverride == kPBOverride_Private); 735 } 736 } 737 738 MOZ_ASSERT(!mBgParent); 739 MOZ_ASSERT(mPromise.IsEmpty()); 740 // Waiting for background channel 741 RefPtr<HttpChannelParent> self = this; 742 nsCOMPtr<nsISerialEventTarget> eventTarget = GetEventTargetForBgParentWait(); 743 WaitForBgParent(mChannel->ChannelId()) 744 ->Then( 745 eventTarget, __func__, [self]() { self->mRequest.Complete(); }, 746 [self](const nsresult& aResult) { 747 NS_ERROR("failed to establish the background channel"); 748 self->mRequest.Complete(); 749 }) 750 ->Track(mRequest); 751 return true; 752 } 753 754 mozilla::ipc::IPCResult HttpChannelParent::RecvSetPriority( 755 const int16_t& priority) { 756 LOG(("HttpChannelParent::RecvSetPriority [this=%p, priority=%d]\n", this, 757 priority)); 758 AUTO_PROFILER_LABEL("HttpChannelParent::RecvSetPriority", NETWORK); 759 760 if (mChannel) { 761 mChannel->SetPriority(priority); 762 } 763 764 nsCOMPtr<nsISupportsPriority> priorityRedirectChannel = 765 do_QueryInterface(mRedirectChannel); 766 if (priorityRedirectChannel) priorityRedirectChannel->SetPriority(priority); 767 768 return IPC_OK(); 769 } 770 771 mozilla::ipc::IPCResult HttpChannelParent::RecvSetClassOfService( 772 const ClassOfService& cos) { 773 if (mChannel) { 774 mChannel->SetClassOfService(cos); 775 } 776 return IPC_OK(); 777 } 778 779 mozilla::ipc::IPCResult HttpChannelParent::RecvSuspend() { 780 LOG(("HttpChannelParent::RecvSuspend [this=%p]\n", this)); 781 782 if (mChannel) { 783 mChannel->Suspend(); 784 } 785 return IPC_OK(); 786 } 787 788 mozilla::ipc::IPCResult HttpChannelParent::RecvResume() { 789 LOG(("HttpChannelParent::RecvResume [this=%p]\n", this)); 790 791 if (mChannel) { 792 mChannel->Resume(); 793 } 794 return IPC_OK(); 795 } 796 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())); 802 803 // logging child cancel reason on the parent side 804 if (logString.isSome()) { 805 LOG(("HttpChannelParent::RecvCancel: %s", logString->get())); 806 } 807 808 // May receive cancel before channel has been constructed! 809 if (mChannel) { 810 mChannel->CancelWithReason(status, reason); 811 812 if (MOZ_UNLIKELY(requestBlockingReason != 813 nsILoadInfo::BLOCKING_REASON_NONE)) { 814 nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo(); 815 loadInfo->SetRequestBlockingReason(requestBlockingReason); 816 } 817 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 (void)mChannel->Resume(); 823 mSuspendedForFlowControl = false; 824 } 825 } else if (!mIPCClosed) { 826 // Make sure that the child correctly delivers all stream listener 827 // notifications. 828 (void)SendFailedAsyncOpen(status); 829 } 830 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; 835 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; 841 } 842 843 return IPC_OK(); 844 } 845 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))); 855 856 // Result from the child. If something fails here, we might overwrite a 857 // success with a further failure. 858 nsresult result = aResult; 859 860 // Local results. 861 nsresult rv; 862 863 if (NS_SUCCEEDED(result)) { 864 nsCOMPtr<nsIHttpChannel> newHttpChannel = 865 do_QueryInterface(mRedirectChannel); 866 867 if (newHttpChannel) { 868 if (aAPIRedirectURI) { 869 rv = newHttpChannel->RedirectTo(aAPIRedirectURI); 870 MOZ_ASSERT(NS_SUCCEEDED(rv)); 871 } 872 873 for (uint32_t i = 0; i < changedHeaders.Length(); i++) { 874 if (changedHeaders[i].mEmpty) { 875 rv = newHttpChannel->SetEmptyRequestHeader(changedHeaders[i].mHeader); 876 } else { 877 rv = newHttpChannel->SetRequestHeader(changedHeaders[i].mHeader, 878 changedHeaders[i].mValue, 879 changedHeaders[i].mMerge); 880 } 881 MOZ_ASSERT(NS_SUCCEEDED(rv)); 882 } 883 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); 888 } 889 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(), 896 false, false); 897 } 898 899 if (aReferrerInfo) { 900 RefPtr<HttpBaseChannel> baseChannel = do_QueryObject(newHttpChannel); 901 MOZ_ASSERT(baseChannel); 902 if (baseChannel) { 903 // Referrer header is computed in child no need to recompute here 904 rv = baseChannel->SetReferrerInfoInternal(aReferrerInfo, false, false, 905 true); 906 MOZ_ASSERT(NS_SUCCEEDED(rv)); 907 } 908 } 909 910 if (aTargetLoadInfoForwarder.isSome()) { 911 nsCOMPtr<nsILoadInfo> newLoadInfo = newHttpChannel->LoadInfo(); 912 rv = MergeChildLoadInfoForwarder(aTargetLoadInfoForwarder.ref(), 913 newLoadInfo); 914 if (NS_FAILED(rv) && NS_SUCCEEDED(result)) { 915 result = rv; 916 } 917 } 918 } 919 } 920 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 924 // do. 925 if (MOZ_UNLIKELY(aSourceRequestBlockingReason != 926 nsILoadInfo::BLOCKING_REASON_NONE) && 927 mChannel) { 928 nsCOMPtr<nsILoadInfo> sourceLoadInfo = mChannel->LoadInfo(); 929 sourceLoadInfo->SetRequestBlockingReason(aSourceRequestBlockingReason); 930 } 931 932 // Continue the verification procedure if child has veto the redirection. 933 if (NS_FAILED(result)) { 934 ContinueRedirect2Verify(result); 935 return IPC_OK(); 936 } 937 938 // Wait for background channel ready on target channel 939 nsCOMPtr<nsIRedirectChannelRegistrar> redirectReg = 940 RedirectChannelRegistrar::GetOrCreate(); 941 MOZ_ASSERT(redirectReg); 942 943 nsCOMPtr<nsIParentChannel> redirectParentChannel; 944 rv = redirectReg->GetParentChannel(mRedirectChannelId, 945 getter_AddRefs(redirectParentChannel)); 946 if (!redirectParentChannel) { 947 ContinueRedirect2Verify(rv); 948 return IPC_OK(); 949 } 950 951 nsCOMPtr<nsIParentRedirectingChannel> redirectedParent = 952 do_QueryInterface(redirectParentChannel); 953 if (!redirectedParent) { 954 // Continue verification procedure if redirecting to non-Http protocol 955 ContinueRedirect2Verify(result); 956 return IPC_OK(); 957 } 958 959 // Ask redirected channel if verification can proceed. 960 // ContinueRedirect2Verify will be invoked when redirected channel is ready. 961 redirectedParent->ContinueVerification(this); 962 963 return IPC_OK(); 964 } 965 966 // from nsIParentRedirectingChannel 967 NS_IMETHODIMP 968 HttpChannelParent::ContinueVerification( 969 nsIAsyncVerifyRedirectReadyCallback* aCallback) { 970 LOG(("HttpChannelParent::ContinueVerification [this=%p callback=%p]\n", this, 971 aCallback)); 972 973 MOZ_ASSERT(NS_IsMainThread()); 974 MOZ_ASSERT(aCallback); 975 976 // Continue the verification procedure if background channel is ready. 977 if (mBgParent) { 978 aCallback->ReadyToVerify(NS_OK); 979 return NS_OK; 980 } 981 982 // ConnectChannel must be received before Redirect2Verify. 983 MOZ_ASSERT(!mPromise.IsEmpty()); 984 985 // Otherwise, wait for the background channel. 986 nsCOMPtr<nsIAsyncVerifyRedirectReadyCallback> callback = aCallback; 987 if (mChannel) { 988 nsCOMPtr<nsISerialEventTarget> eventTarget = 989 GetEventTargetForBgParentWait(); 990 WaitForBgParent(mChannel->ChannelId()) 991 ->Then( 992 eventTarget, __func__, 993 [callback]() { callback->ReadyToVerify(NS_OK); }, 994 [callback](const nsresult& aResult) { 995 NS_ERROR("failed to establish the background channel"); 996 callback->ReadyToVerify(aResult); 997 }); 998 } else { 999 // mChannel can be null for several reasons (AsyncOpenFailed, etc) 1000 NS_ERROR("No channel for ContinueVerification"); 1001 GetMainThreadSerialEventTarget()->Dispatch(NS_NewRunnableFunction( 1002 __func__, [callback] { callback->ReadyToVerify(NS_ERROR_FAILURE); })); 1003 } 1004 return NS_OK; 1005 } 1006 1007 void HttpChannelParent::ContinueRedirect2Verify(const nsresult& aResult) { 1008 LOG( 1009 ("HttpChannelParent::ContinueRedirect2Verify " 1010 "[this=%p result=%" PRIx32 "]\n", 1011 this, static_cast<uint32_t>(aResult))); 1012 1013 if (mRedirectCallback) { 1014 LOG( 1015 ("HttpChannelParent::ContinueRedirect2Verify call " 1016 "OnRedirectVerifyCallback" 1017 " [this=%p result=%" PRIx32 ", mRedirectCallback=%p]\n", 1018 this, static_cast<uint32_t>(aResult), mRedirectCallback.get())); 1019 mRedirectCallback->OnRedirectVerifyCallback(aResult); 1020 mRedirectCallback = nullptr; 1021 } else { 1022 LOG( 1023 ("RecvRedirect2Verify[%p]: NO CALLBACKS! | " 1024 "mRedirectChannelId: %" PRIx64 ", mRedirectChannel: %p", 1025 this, mRedirectChannelId, mRedirectChannel.get())); 1026 } 1027 } 1028 1029 mozilla::ipc::IPCResult HttpChannelParent::RecvDocumentChannelCleanup( 1030 const bool& clearCacheEntry) { 1031 CleanupBackgroundChannel(); // Background channel can be closed. 1032 mChannel = nullptr; // Reclaim some memory sooner. 1033 if (clearCacheEntry) { 1034 mCacheEntry = nullptr; // Else we'll block other channels reading same URI 1035 } 1036 return IPC_OK(); 1037 } 1038 1039 mozilla::ipc::IPCResult HttpChannelParent::RecvRemoveCorsPreflightCacheEntry( 1040 nsIURI* uri, const mozilla::ipc::PrincipalInfo& requestingPrincipal, 1041 const OriginAttributes& originAttributes) { 1042 if (!uri) { 1043 return IPC_FAIL_NO_REASON(this); 1044 } 1045 auto principalOrErr = PrincipalInfoToPrincipal(requestingPrincipal); 1046 if (NS_WARN_IF(principalOrErr.isErr())) { 1047 return IPC_FAIL_NO_REASON(this); 1048 } 1049 nsCOMPtr<nsIPrincipal> principal = principalOrErr.unwrap(); 1050 nsCORSListenerProxy::RemoveFromCorsPreflightCache(uri, principal, 1051 originAttributes); 1052 return IPC_OK(); 1053 } 1054 1055 mozilla::ipc::IPCResult HttpChannelParent::RecvSetCookies( 1056 const nsACString& aBaseDomain, const OriginAttributes& aOriginAttributes, 1057 nsIURI* aHost, const bool& aFromHttp, const bool& aIsThirdParty, 1058 nsTArray<CookieStruct>&& aCookies) { 1059 net::PCookieServiceParent* csParent = 1060 LoneManagedOrNullAsserts(Manager()->ManagedPCookieServiceParent()); 1061 NS_ENSURE_TRUE(csParent, IPC_OK()); 1062 1063 auto* cs = static_cast<net::CookieServiceParent*>(csParent); 1064 1065 BrowsingContext* browsingContext = nullptr; 1066 if (mBrowserParent) { 1067 browsingContext = mBrowserParent->GetBrowsingContext(); 1068 } 1069 1070 return cs->SetCookies(nsCString(aBaseDomain), aOriginAttributes, aHost, 1071 aFromHttp, aIsThirdParty, aCookies, browsingContext); 1072 } 1073 1074 //----------------------------------------------------------------------------- 1075 // HttpChannelParent::nsIRequestObserver 1076 //----------------------------------------------------------------------------- 1077 1078 static ResourceTimingStructArgs GetTimingAttributes(HttpBaseChannel* aChannel) { 1079 ResourceTimingStructArgs args; 1080 TimeStamp timeStamp; 1081 aChannel->GetDomainLookupStart(&timeStamp); 1082 args.domainLookupStart() = timeStamp; 1083 aChannel->GetDomainLookupEnd(&timeStamp); 1084 args.domainLookupEnd() = timeStamp; 1085 aChannel->GetConnectStart(&timeStamp); 1086 args.connectStart() = timeStamp; 1087 aChannel->GetTcpConnectEnd(&timeStamp); 1088 args.tcpConnectEnd() = timeStamp; 1089 aChannel->GetSecureConnectionStart(&timeStamp); 1090 args.secureConnectionStart() = timeStamp; 1091 aChannel->GetConnectEnd(&timeStamp); 1092 args.connectEnd() = timeStamp; 1093 aChannel->GetRequestStart(&timeStamp); 1094 args.requestStart() = timeStamp; 1095 aChannel->GetResponseStart(&timeStamp); 1096 args.responseStart() = timeStamp; 1097 aChannel->GetResponseEnd(&timeStamp); 1098 args.responseEnd() = timeStamp; 1099 aChannel->GetAsyncOpen(&timeStamp); 1100 args.fetchStart() = timeStamp; 1101 aChannel->GetRedirectStart(&timeStamp); 1102 args.redirectStart() = timeStamp; 1103 aChannel->GetRedirectEnd(&timeStamp); 1104 args.redirectEnd() = timeStamp; 1105 1106 uint64_t size = 0; 1107 aChannel->GetTransferSize(&size); 1108 args.transferSize() = size; 1109 1110 aChannel->GetEncodedBodySize(&size); 1111 args.encodedBodySize() = size; 1112 1113 aChannel->GetDecodedBodySize(&size); 1114 args.decodedBodySize() = size; 1115 1116 aChannel->GetCacheReadStart(&timeStamp); 1117 args.cacheReadStart() = timeStamp; 1118 1119 aChannel->GetCacheReadEnd(&timeStamp); 1120 args.cacheReadEnd() = timeStamp; 1121 1122 aChannel->GetTransactionPending(&timeStamp); 1123 args.transactionPending() = timeStamp; 1124 return args; 1125 } 1126 1127 NS_IMETHODIMP 1128 HttpChannelParent::OnStartRequest(nsIRequest* aRequest) { 1129 nsresult rv; 1130 1131 LOG(("HttpChannelParent::OnStartRequest [this=%p, aRequest=%p]\n", this, 1132 aRequest)); 1133 MOZ_ASSERT(NS_IsMainThread()); 1134 1135 Maybe<uint32_t> multiPartID; 1136 bool isFirstPartOfMultiPart = false; 1137 bool isLastPartOfMultiPart = false; 1138 DebugOnly<bool> isMultiPart = false; 1139 1140 RefPtr<HttpBaseChannel> chan = do_QueryObject(aRequest); 1141 if (!chan) { 1142 if (nsCOMPtr<nsIMultiPartChannel> multiPartChannel = 1143 do_QueryInterface(aRequest)) { 1144 isMultiPart = true; 1145 nsCOMPtr<nsIChannel> baseChannel; 1146 multiPartChannel->GetBaseChannel(getter_AddRefs(baseChannel)); 1147 chan = do_QueryObject(baseChannel); 1148 1149 uint32_t partID = 0; 1150 multiPartChannel->GetPartID(&partID); 1151 multiPartID = Some(partID); 1152 multiPartChannel->GetIsFirstPart(&isFirstPartOfMultiPart); 1153 multiPartChannel->GetIsLastPart(&isLastPartOfMultiPart); 1154 } else if (nsCOMPtr<nsIViewSourceChannel> viewSourceChannel = 1155 do_QueryInterface(aRequest)) { 1156 chan = do_QueryObject(viewSourceChannel->GetInnerChannel()); 1157 } 1158 } 1159 MOZ_ASSERT(multiPartID || !isMultiPart, "Changed multi-part state?"); 1160 1161 if (!chan) { 1162 LOG((" aRequest is not HttpBaseChannel")); 1163 NS_ERROR( 1164 "Expecting only HttpBaseChannel as aRequest in " 1165 "HttpChannelParent::OnStartRequest"); 1166 return NS_ERROR_UNEXPECTED; 1167 } 1168 1169 mAfterOnStartRequestBegun = true; 1170 1171 // Todo: re-enable when bug 1589749 is fixed. 1172 /*MOZ_ASSERT(mChannel == chan, 1173 "HttpChannelParent getting OnStartRequest from a different " 1174 "HttpBaseChannel instance");*/ 1175 1176 HttpChannelOnStartRequestArgs args; 1177 1178 // Send down any permissions/cookies which are relevant to this URL if we are 1179 // performing a document load. We can't do that if mIPCClosed is set. 1180 if (!mIPCClosed) { 1181 PContentParent* pcp = Manager()->Manager(); 1182 MOZ_ASSERT(pcp, "We should have a manager if our IPC isn't closed"); 1183 DebugOnly<nsresult> rv = 1184 static_cast<ContentParent*>(pcp)->AboutToLoadHttpDocumentForChild( 1185 chan, &args.shouldWaitForOnStartRequestSent()); 1186 MOZ_ASSERT(NS_SUCCEEDED(rv)); 1187 } 1188 1189 args.multiPartID() = multiPartID; 1190 args.isFirstPartOfMultiPart() = isFirstPartOfMultiPart; 1191 args.isLastPartOfMultiPart() = isLastPartOfMultiPart; 1192 1193 args.cacheExpirationTime() = nsICacheEntry::NO_EXPIRATION_TIME; 1194 1195 RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(chan); 1196 1197 if (httpChannelImpl) { 1198 httpChannelImpl->IsFromCache(&args.isFromCache()); 1199 httpChannelImpl->GetCacheDisposition(&args.cacheDisposition()); 1200 httpChannelImpl->IsRacing(&args.isRacing()); 1201 httpChannelImpl->GetCacheEntryId(&args.cacheEntryId()); 1202 httpChannelImpl->GetCacheTokenFetchCount(&args.cacheFetchCount()); 1203 httpChannelImpl->GetCacheTokenExpirationTime(&args.cacheExpirationTime()); 1204 httpChannelImpl->GetProtocolVersion(args.protocolVersion()); 1205 1206 mDataSentToChildProcess = httpChannelImpl->DataSentToChildProcess(); 1207 1208 // If RCWN is enabled and cache wins, we can't use the ODA from socket 1209 // process. 1210 if (args.isRacing()) { 1211 mDataSentToChildProcess = 1212 httpChannelImpl->DataSentToChildProcess() && !args.isFromCache(); 1213 } 1214 args.dataFromSocketProcess() = mDataSentToChildProcess; 1215 } 1216 1217 // Propagate whether or not conversion should occur from the parent-side 1218 // channel to the child-side channel. Then disable the parent-side 1219 // conversion so that it only occurs in the child. 1220 (void)chan->GetApplyConversion(&args.applyConversion()); 1221 chan->SetApplyConversion(false); 1222 1223 // If we've already applied the conversion (as can happen if we installed 1224 // a multipart converted), then don't apply it again on the child. 1225 if (chan->HasAppliedConversion()) { 1226 args.applyConversion() = false; 1227 } 1228 1229 chan->GetStatus(&args.channelStatus()); 1230 1231 // Keep the cache entry for future use when opening alternative streams. 1232 // It could be already released by nsHttpChannel at that time. 1233 nsCOMPtr<nsISupports> cacheEntry; 1234 1235 if (httpChannelImpl) { 1236 httpChannelImpl->GetCacheToken(getter_AddRefs(cacheEntry)); 1237 mCacheEntry = do_QueryInterface(cacheEntry); 1238 args.cacheEntryAvailable() = static_cast<bool>(mCacheEntry); 1239 1240 httpChannelImpl->GetCacheKey(&args.cacheKey()); 1241 httpChannelImpl->GetAlternativeDataType(args.altDataType()); 1242 } 1243 1244 args.altDataLength() = chan->GetAltDataLength(); 1245 args.deliveringAltData() = chan->IsDeliveringAltData(); 1246 1247 args.securityInfo() = SecurityInfo(); 1248 1249 chan->GetRedirectCount(&args.redirectCount()); 1250 chan->GetHasHTTPSRR(&args.hasHTTPSRR()); 1251 1252 chan->GetIsProxyUsed(&args.isProxyUsed()); 1253 1254 nsCOMPtr<nsILoadInfo> loadInfo = chan->LoadInfo(); 1255 mozilla::ipc::LoadInfoToParentLoadInfoForwarder(loadInfo, 1256 &args.loadInfoForwarder()); 1257 1258 nsHttpResponseHead* responseHead = chan->GetResponseHead(); 1259 bool useResponseHead = !!responseHead; 1260 nsHttpResponseHead cleanedUpResponseHead; 1261 1262 if (responseHead && 1263 (responseHead->HasHeader(nsHttp::Set_Cookie) || multiPartID)) { 1264 cleanedUpResponseHead = *responseHead; 1265 cleanedUpResponseHead.ClearHeader(nsHttp::Set_Cookie); 1266 if (multiPartID) { 1267 nsCOMPtr<nsIChannel> multiPartChannel = do_QueryInterface(aRequest); 1268 // For the multipart channel, use the parsed subtype instead. Note that 1269 // `chan` is the underlying base channel of the multipart channel in this 1270 // case, which is different from `multiPartChannel`. 1271 MOZ_ASSERT(multiPartChannel); 1272 nsAutoCString contentType; 1273 multiPartChannel->GetContentType(contentType); 1274 cleanedUpResponseHead.SetContentType(contentType); 1275 } 1276 responseHead = &cleanedUpResponseHead; 1277 } 1278 1279 if (!responseHead) { 1280 responseHead = &cleanedUpResponseHead; 1281 } 1282 1283 if (chan->ChannelBlockedByOpaqueResponse() && 1284 chan->CachedOpaqueResponseBlockingPref()) { 1285 responseHead->ClearHeaders(); 1286 } 1287 1288 chan->GetIsResolvedByTRR(&args.isResolvedByTRR()); 1289 chan->GetAllRedirectsSameOrigin(&args.allRedirectsSameOrigin()); 1290 chan->GetCrossOriginOpenerPolicy(&args.openerPolicy()); 1291 args.selfAddr() = chan->GetSelfAddr(); 1292 args.peerAddr() = chan->GetPeerAddr(); 1293 args.timing() = GetTimingAttributes(mChannel); 1294 if (mOverrideReferrerInfo) { 1295 args.overrideReferrerInfo() = ToRefPtr(std::move(mOverrideReferrerInfo)); 1296 } 1297 args.cookieChanges().SwapElements(mCookieChanges); 1298 1299 nsHttpRequestHead* requestHead = chan->GetRequestHead(); 1300 // !!! We need to lock headers and please don't forget to unlock them !!! 1301 requestHead->Enter(); 1302 1303 nsHttpHeaderArray cleanedUpRequestHeaders; 1304 bool cleanedUpRequest = false; 1305 if (requestHead->HasHeader(nsHttp::Cookie)) { 1306 cleanedUpRequestHeaders = requestHead->Headers(); 1307 cleanedUpRequestHeaders.ClearHeader(nsHttp::Cookie); 1308 cleanedUpRequest = true; 1309 } 1310 1311 rv = NS_OK; 1312 1313 nsCOMPtr<nsICacheEntry> altDataSource; 1314 nsCOMPtr<nsICacheInfoChannel> cacheChannel = 1315 do_QueryInterface(static_cast<nsIChannel*>(mChannel.get())); 1316 if (cacheChannel) { 1317 for (const auto& pref : cacheChannel->PreferredAlternativeDataTypes()) { 1318 if (pref.type() == args.altDataType() && 1319 pref.deliverAltData() == 1320 nsICacheInfoChannel::PreferredAlternativeDataDeliveryType:: 1321 SERIALIZE) { 1322 altDataSource = mCacheEntry; 1323 break; 1324 } 1325 } 1326 } 1327 1328 nsIRequest::TRRMode effectiveMode = nsIRequest::TRR_DEFAULT_MODE; 1329 mChannel->GetEffectiveTRRMode(&effectiveMode); 1330 args.effectiveTRRMode() = effectiveMode; 1331 1332 TRRSkippedReason reason = TRRSkippedReason::TRR_UNSET; 1333 mChannel->GetTrrSkipReason(&reason); 1334 args.trrSkipReason() = reason; 1335 1336 if (mIPCClosed) { 1337 rv = NS_ERROR_UNEXPECTED; 1338 } else { 1339 nsHttpResponseHead newResponseHead = *responseHead; 1340 if (!mBgParent->OnStartRequest( 1341 std::move(newResponseHead), useResponseHead, 1342 cleanedUpRequest ? cleanedUpRequestHeaders : requestHead->Headers(), 1343 args, altDataSource, chan->GetOnStartRequestStartTime())) { 1344 rv = NS_ERROR_UNEXPECTED; 1345 } 1346 } 1347 1348 requestHead->Exit(); 1349 1350 // Need to wait for the cookies/permissions to content process, which is sent 1351 // via PContent in AboutToLoadHttpFtpDocumentForChild. For multipart channel, 1352 // send only one time since the cookies/permissions are the same. 1353 if (NS_SUCCEEDED(rv) && args.shouldWaitForOnStartRequestSent() && 1354 multiPartID.valueOr(0) == 0) { 1355 LOG(("HttpChannelParent::SendOnStartRequestSent\n")); 1356 (void)SendOnStartRequestSent(); 1357 } 1358 1359 return rv; 1360 } 1361 1362 NS_IMETHODIMP 1363 HttpChannelParent::OnStopRequest(nsIRequest* aRequest, nsresult aStatusCode) { 1364 LOG(("HttpChannelParent::OnStopRequest: [this=%p aRequest=%p status=%" PRIx32 1365 "]\n", 1366 this, aRequest, static_cast<uint32_t>(aStatusCode))); 1367 MOZ_ASSERT(NS_IsMainThread()); 1368 1369 RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(mChannel); 1370 if (httpChannelImpl) { 1371 httpChannelImpl->SetWarningReporter(nullptr); 1372 } 1373 1374 nsHttpHeaderArray* responseTrailer = mChannel->GetResponseTrailers(); 1375 1376 nsTArray<ConsoleReportCollected> consoleReports; 1377 1378 RefPtr<HttpBaseChannel> httpChannel = do_QueryObject(mChannel); 1379 TimeStamp onStopRequestStart; 1380 if (httpChannel) { 1381 httpChannel->StealConsoleReports(consoleReports); 1382 onStopRequestStart = httpChannel->GetOnStopRequestStartTime(); 1383 } 1384 1385 // Either IPC channel is closed or background channel 1386 // is ready to send OnStopRequest. 1387 MOZ_ASSERT(mIPCClosed || mBgParent); 1388 1389 if (mDataSentToChildProcess) { 1390 if (mIPCClosed || !mBgParent || 1391 !mBgParent->OnConsoleReport(consoleReports)) { 1392 return NS_ERROR_UNEXPECTED; 1393 } 1394 return NS_OK; 1395 } 1396 1397 // If we're handling a multi-part stream, then send this directly 1398 // over PHttpChannel to make synchronization easier. 1399 if (mIPCClosed || !mBgParent || 1400 !mBgParent->OnStopRequest( 1401 aStatusCode, GetTimingAttributes(mChannel), 1402 responseTrailer ? *responseTrailer : nsHttpHeaderArray(), 1403 consoleReports, onStopRequestStart)) { 1404 return NS_ERROR_UNEXPECTED; 1405 } 1406 1407 if (NeedFlowControl()) { 1408 bool isLocal = false; 1409 NetAddr peerAddr = mChannel->GetPeerAddr(); 1410 1411 #if defined(XP_UNIX) 1412 // Unix-domain sockets are always local. 1413 isLocal = (peerAddr.raw.family == PR_AF_LOCAL); 1414 #endif 1415 1416 isLocal = isLocal || peerAddr.IsLoopbackAddr(); 1417 1418 if (!isLocal) { 1419 if (!mHasSuspendedByBackPressure) { 1420 glean::network::back_pressure_suspension_rate 1421 .EnumGet( 1422 glean::network::BackPressureSuspensionRateLabel::eNotsuspended) 1423 .Add(); 1424 } else { 1425 glean::network::back_pressure_suspension_rate 1426 .EnumGet( 1427 glean::network::BackPressureSuspensionRateLabel::eSuspended) 1428 .Add(); 1429 1430 // Only analyze non-local suspended cases, which we are interested in. 1431 nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo(); 1432 glean::network::back_pressure_suspension_cp_type.AccumulateSingleSample( 1433 loadInfo->InternalContentPolicyType()); 1434 } 1435 } else { 1436 if (!mHasSuspendedByBackPressure) { 1437 glean::network::back_pressure_suspension_rate 1438 .EnumGet(glean::network::BackPressureSuspensionRateLabel:: 1439 eNotsuspendedlocal) 1440 .Add(); 1441 } else { 1442 glean::network::back_pressure_suspension_rate 1443 .EnumGet(glean::network::BackPressureSuspensionRateLabel:: 1444 eSuspendedlocal) 1445 .Add(); 1446 } 1447 } 1448 } 1449 return NS_OK; 1450 } 1451 1452 //----------------------------------------------------------------------------- 1453 // HttpChannelParent::nsIMultiPartChannelListener 1454 //----------------------------------------------------------------------------- 1455 1456 NS_IMETHODIMP 1457 HttpChannelParent::OnAfterLastPart(nsresult aStatus) { 1458 LOG(("HttpChannelParent::OnAfterLastPart [this=%p]\n", this)); 1459 MOZ_ASSERT(NS_IsMainThread()); 1460 1461 // If IPC channel is closed, there is nothing we can do. Just return NS_OK. 1462 if (mIPCClosed) { 1463 return NS_OK; 1464 } 1465 1466 // If IPC channel is open, background channel should be ready to send 1467 // OnAfterLastPart. 1468 MOZ_ASSERT(mBgParent); 1469 1470 if (!mBgParent || !mBgParent->OnAfterLastPart(aStatus)) { 1471 return NS_ERROR_UNEXPECTED; 1472 } 1473 1474 return NS_OK; 1475 } 1476 1477 //----------------------------------------------------------------------------- 1478 // HttpChannelParent::nsIStreamListener 1479 //----------------------------------------------------------------------------- 1480 1481 NS_IMETHODIMP 1482 HttpChannelParent::OnDataAvailable(nsIRequest* aRequest, 1483 nsIInputStream* aInputStream, 1484 uint64_t aOffset, uint32_t aCount) { 1485 LOG(("HttpChannelParent::OnDataAvailable [this=%p aRequest=%p offset=%" PRIu64 1486 " count=%" PRIu32 "]\n", 1487 this, aRequest, aOffset, aCount)); 1488 MOZ_ASSERT(NS_IsMainThread()); 1489 1490 if (mDataSentToChildProcess) { 1491 uint32_t n; 1492 return aInputStream->ReadSegments(NS_DiscardSegment, nullptr, aCount, &n); 1493 } 1494 1495 nsresult channelStatus = NS_OK; 1496 mChannel->GetStatus(&channelStatus); 1497 1498 nsresult transportStatus = NS_NET_STATUS_RECEIVING_FROM; 1499 RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(mChannel); 1500 TimeStamp onDataAvailableStart = TimeStamp::Now(); 1501 if (httpChannelImpl) { 1502 if (httpChannelImpl->IsReadingFromCache()) { 1503 transportStatus = NS_NET_STATUS_READING; 1504 } 1505 onDataAvailableStart = httpChannelImpl->GetDataAvailableStartTime(); 1506 } 1507 1508 nsCString data; 1509 nsresult rv = NS_ReadInputStreamToString(aInputStream, data, aCount); 1510 if (NS_FAILED(rv)) { 1511 return rv; 1512 } 1513 1514 // Either IPC channel is closed or background channel 1515 // is ready to send OnTransportAndData. 1516 MOZ_ASSERT(mIPCClosed || mBgParent); 1517 1518 if (mIPCClosed || !mBgParent || 1519 !mBgParent->OnTransportAndData(channelStatus, transportStatus, aOffset, 1520 aCount, data, onDataAvailableStart)) { 1521 return NS_ERROR_UNEXPECTED; 1522 } 1523 1524 int32_t count = static_cast<int32_t>(aCount); 1525 1526 if (NeedFlowControl()) { 1527 // We're going to run out of sending window size 1528 if (mSendWindowSize > 0 && mSendWindowSize <= count) { 1529 MOZ_ASSERT(!mSuspendedForFlowControl); 1530 LOG((" suspend the channel due to e10s backpressure")); 1531 (void)mChannel->Suspend(); 1532 mSuspendedForFlowControl = true; 1533 mHasSuspendedByBackPressure = true; 1534 } else if (!mResumedTimestamp.IsNull()) { 1535 // Calculate the delay when the first packet arrived after resume 1536 glean::network::back_pressure_suspension_delay_time.AccumulateRawDuration( 1537 TimeStamp::Now() - mResumedTimestamp); 1538 mResumedTimestamp = TimeStamp(); 1539 } 1540 mSendWindowSize -= count; 1541 } 1542 1543 return NS_OK; 1544 } 1545 1546 // Get the appropriate event target for background parent operations based on 1547 // the channel's class of service flags: Urgent channels use 1548 // ExecuteIfOnMainThreadEventTarget to avoid the async main-thread dispatch 1549 // overhead when already on the main thread. Non-urgent channels use the regular 1550 // event queue to prevent head-of-line blocking that would delay other main 1551 // thread events. 1552 nsCOMPtr<nsISerialEventTarget> 1553 HttpChannelParent::GetEventTargetForBgParentWait() { 1554 uint32_t classOfServiceFlags = 0; 1555 mChannel->GetClassFlags(&classOfServiceFlags); 1556 return (classOfServiceFlags & nsIClassOfService::UrgentStart) 1557 ? ExecuteIfOnMainThreadEventTarget::Get() 1558 : GetMainThreadSerialEventTarget(); 1559 } 1560 1561 bool HttpChannelParent::NeedFlowControl() { 1562 if (mCacheNeedFlowControlInitialized) { 1563 return mNeedFlowControl; 1564 } 1565 1566 int64_t contentLength = -1; 1567 1568 RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(mChannel); 1569 1570 // By design, we won't trigger the flow control if 1571 // a. pref-out 1572 // b. the resource is from cache or partial cache 1573 // c. the resource is small 1574 // d. data will be sent from socket process to child process directly 1575 // Note that we served the cached resource first for partical cache, which is 1576 // ignored here since we only take the first ODA into consideration. 1577 if (gHttpHandler->SendWindowSize() == 0 || !httpChannelImpl || 1578 httpChannelImpl->IsReadingFromCache() || 1579 NS_FAILED(httpChannelImpl->GetContentLength(&contentLength)) || 1580 contentLength < gHttpHandler->SendWindowSize() || 1581 mDataSentToChildProcess) { 1582 mNeedFlowControl = false; 1583 } 1584 mCacheNeedFlowControlInitialized = true; 1585 return mNeedFlowControl; 1586 } 1587 1588 mozilla::ipc::IPCResult HttpChannelParent::RecvBytesRead( 1589 const int32_t& aCount) { 1590 if (!NeedFlowControl()) { 1591 return IPC_OK(); 1592 } 1593 1594 LOG(("HttpChannelParent::RecvBytesRead [this=%p count=%" PRId32 "]\n", this, 1595 aCount)); 1596 1597 if (mSendWindowSize <= 0 && mSendWindowSize + aCount > 0) { 1598 MOZ_ASSERT(mSuspendedForFlowControl); 1599 LOG((" resume the channel due to e10s backpressure relief")); 1600 (void)mChannel->Resume(); 1601 mSuspendedForFlowControl = false; 1602 1603 mResumedTimestamp = TimeStamp::Now(); 1604 } 1605 mSendWindowSize += aCount; 1606 return IPC_OK(); 1607 } 1608 1609 mozilla::ipc::IPCResult HttpChannelParent::RecvOpenOriginalCacheInputStream() { 1610 if (mIPCClosed) { 1611 return IPC_OK(); 1612 } 1613 Maybe<IPCStream> ipcStream; 1614 if (mCacheEntry) { 1615 nsCOMPtr<nsIInputStream> inputStream; 1616 nsresult rv = mCacheEntry->OpenInputStream(0, getter_AddRefs(inputStream)); 1617 if (NS_SUCCEEDED(rv)) { 1618 (void)mozilla::ipc::SerializeIPCStream(inputStream.forget(), ipcStream, 1619 /* aAllowLazy */ false); 1620 } 1621 } 1622 1623 (void)SendOriginalCacheInputStreamAvailable(ipcStream); 1624 return IPC_OK(); 1625 } 1626 1627 //----------------------------------------------------------------------------- 1628 // HttpChannelParent::nsIProgressEventSink 1629 //----------------------------------------------------------------------------- 1630 1631 NS_IMETHODIMP 1632 HttpChannelParent::OnProgress(nsIRequest* aRequest, int64_t aProgress, 1633 int64_t aProgressMax) { 1634 LOG(("HttpChannelParent::OnProgress [this=%p progress=%" PRId64 "max=%" PRId64 1635 "]\n", 1636 this, aProgress, aProgressMax)); 1637 MOZ_ASSERT(NS_IsMainThread()); 1638 1639 // If IPC channel is closed, there is nothing we can do. Just return NS_OK. 1640 if (mIPCClosed) { 1641 return NS_OK; 1642 } 1643 1644 // If it indicates this precedes OnDataAvailable, child can derive the value 1645 // in ODA. 1646 if (mIgnoreProgress) { 1647 mIgnoreProgress = false; 1648 return NS_OK; 1649 } 1650 1651 // If IPC channel is open, background channel should be ready to send 1652 // OnProgress. 1653 MOZ_ASSERT(mBgParent); 1654 1655 // Send OnProgress events to the child for data upload progress notifications 1656 // (i.e. status == NS_NET_STATUS_SENDING_TO) or if the channel has 1657 // LOAD_BACKGROUND set. 1658 if (!mBgParent || !mBgParent->OnProgress(aProgress, aProgressMax)) { 1659 return NS_ERROR_UNEXPECTED; 1660 } 1661 1662 return NS_OK; 1663 } 1664 1665 NS_IMETHODIMP 1666 HttpChannelParent::OnStatus(nsIRequest* aRequest, nsresult aStatus, 1667 const char16_t* aStatusArg) { 1668 LOG(("HttpChannelParent::OnStatus [this=%p status=%" PRIx32 "]\n", this, 1669 static_cast<uint32_t>(aStatus))); 1670 MOZ_ASSERT(NS_IsMainThread()); 1671 1672 // If IPC channel is closed, there is nothing we can do. Just return NS_OK. 1673 if (mIPCClosed) { 1674 return NS_OK; 1675 } 1676 1677 // If this precedes OnDataAvailable, transportStatus will be derived in ODA. 1678 if (aStatus == NS_NET_STATUS_RECEIVING_FROM || 1679 aStatus == NS_NET_STATUS_READING) { 1680 // The transport status and progress generated by ODA will be coalesced 1681 // into one IPC message. Therefore, we can ignore the next OnProgress event 1682 // since it is generated by ODA as well. 1683 mIgnoreProgress = true; 1684 return NS_OK; 1685 } 1686 1687 // If IPC channel is open, background channel should be ready to send 1688 // OnStatus. 1689 MOZ_ASSERT(mIPCClosed || mBgParent); 1690 1691 // Otherwise, send to child now 1692 if (!mBgParent || !mBgParent->OnStatus(aStatus)) { 1693 return NS_ERROR_UNEXPECTED; 1694 } 1695 1696 return NS_OK; 1697 } 1698 1699 //----------------------------------------------------------------------------- 1700 // HttpChannelParent::nsIParentChannel 1701 //----------------------------------------------------------------------------- 1702 1703 NS_IMETHODIMP 1704 HttpChannelParent::SetParentListener(ParentChannelListener* aListener) { 1705 LOG(("HttpChannelParent::SetParentListener [this=%p aListener=%p]\n", this, 1706 aListener)); 1707 MOZ_ASSERT(aListener); 1708 MOZ_ASSERT(!mParentListener, 1709 "SetParentListener should only be called for " 1710 "new HttpChannelParents after a redirect, when " 1711 "mParentListener is null."); 1712 mParentListener = aListener; 1713 return NS_OK; 1714 } 1715 1716 NS_IMETHODIMP 1717 HttpChannelParent::SetClassifierMatchedInfo(const nsACString& aList, 1718 const nsACString& aProvider, 1719 const nsACString& aFullHash) { 1720 LOG(("HttpChannelParent::SetClassifierMatchedInfo [this=%p]\n", this)); 1721 if (!mIPCClosed) { 1722 MOZ_ASSERT(mBgParent); 1723 (void)mBgParent->OnSetClassifierMatchedInfo(aList, aProvider, aFullHash); 1724 } 1725 return NS_OK; 1726 } 1727 1728 NS_IMETHODIMP 1729 HttpChannelParent::SetClassifierMatchedTrackingInfo( 1730 const nsACString& aLists, const nsACString& aFullHashes) { 1731 LOG(("HttpChannelParent::SetClassifierMatchedTrackingInfo [this=%p]\n", 1732 this)); 1733 if (!mIPCClosed) { 1734 MOZ_ASSERT(mBgParent); 1735 (void)mBgParent->OnSetClassifierMatchedTrackingInfo(aLists, aFullHashes); 1736 } 1737 return NS_OK; 1738 } 1739 1740 NS_IMETHODIMP 1741 HttpChannelParent::NotifyClassificationFlags(uint32_t aClassificationFlags, 1742 bool aIsThirdParty) { 1743 LOG( 1744 ("HttpChannelParent::NotifyClassificationFlags " 1745 "classificationFlags=%" PRIu32 ", thirdparty=%d [this=%p]\n", 1746 aClassificationFlags, static_cast<int>(aIsThirdParty), this)); 1747 if (!mIPCClosed) { 1748 MOZ_ASSERT(mBgParent); 1749 (void)mBgParent->OnNotifyClassificationFlags(aClassificationFlags, 1750 aIsThirdParty); 1751 } 1752 return NS_OK; 1753 } 1754 1755 NS_IMETHODIMP 1756 HttpChannelParent::Delete() { 1757 if (!mIPCClosed) (void)DoSendDeleteSelf(); 1758 1759 return NS_OK; 1760 } 1761 1762 NS_IMETHODIMP 1763 HttpChannelParent::GetRemoteType(nsACString& aRemoteType) { 1764 if (!CanSend()) { 1765 return NS_ERROR_UNEXPECTED; 1766 } 1767 1768 dom::PContentParent* pcp = Manager()->Manager(); 1769 aRemoteType = static_cast<dom::ContentParent*>(pcp)->GetRemoteType(); 1770 return NS_OK; 1771 } 1772 1773 bool HttpChannelParent::IsRedirectDueToAuthRetry(uint32_t redirectFlags) { 1774 return (redirectFlags & nsIChannelEventSink::REDIRECT_AUTH_RETRY); 1775 } 1776 1777 //----------------------------------------------------------------------------- 1778 // HttpChannelParent::nsIParentRedirectingChannel 1779 //----------------------------------------------------------------------------- 1780 1781 NS_IMETHODIMP 1782 HttpChannelParent::StartRedirect(nsIChannel* newChannel, uint32_t redirectFlags, 1783 nsIAsyncVerifyRedirectCallback* callback) { 1784 nsresult rv; 1785 1786 LOG(("HttpChannelParent::StartRedirect [this=%p, newChannel=%p callback=%p]", 1787 this, newChannel, callback)); 1788 1789 // Register the new channel and obtain id for it 1790 nsCOMPtr<nsIRedirectChannelRegistrar> registrar = 1791 RedirectChannelRegistrar::GetOrCreate(); 1792 MOZ_ASSERT(registrar); 1793 1794 mRedirectChannelId = nsContentUtils::GenerateLoadIdentifier(); 1795 rv = registrar->RegisterChannel(newChannel, mRedirectChannelId); 1796 NS_ENSURE_SUCCESS(rv, rv); 1797 1798 LOG(("Registered %p channel under id=%" PRIx64, newChannel, 1799 mRedirectChannelId)); 1800 1801 if (mIPCClosed) { 1802 return NS_BINDING_ABORTED; 1803 } 1804 1805 // If this is an internal redirect for service worker interception or 1806 // internal redirect due to auth retries, then hide it from the child 1807 // process. The original e10s interception code was not designed with this 1808 // in mind and its not necessary to replace the HttpChannelChild/Parent 1809 // objects in this case. 1810 if (redirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) { 1811 nsCOMPtr<nsIInterceptedChannel> oldIntercepted = 1812 do_QueryInterface(static_cast<nsIChannel*>(mChannel.get())); 1813 nsCOMPtr<nsIInterceptedChannel> newIntercepted = 1814 do_QueryInterface(newChannel); 1815 1816 // 1. We only want to hide the special internal redirects from 1817 // nsHttpChannel to InterceptedHttpChannel. 1818 // 2. We want to allow through internal redirects 1819 // initiated from the InterceptedHttpChannel even if they are to another 1820 // InterceptedHttpChannel, except the interception reset, since 1821 // corresponding HttpChannelChild/Parent objects can be reused for reset 1822 // case. 1823 // 3. If this is an internal redirect due to auth retry then we will 1824 // hide it from the child process 1825 1826 if ((!oldIntercepted && newIntercepted) || 1827 (oldIntercepted && !newIntercepted && oldIntercepted->IsReset()) || 1828 (IsRedirectDueToAuthRetry(redirectFlags))) { 1829 // We need to move across the reserved and initial client information 1830 // to the new channel. Normally this would be handled by the child 1831 // ClientChannelHelper, but that is not notified of this redirect since 1832 // we're not propagating it back to the child process. 1833 nsCOMPtr<nsILoadInfo> oldLoadInfo = mChannel->LoadInfo(); 1834 1835 nsCOMPtr<nsILoadInfo> newLoadInfo = newChannel->LoadInfo(); 1836 1837 Maybe<ClientInfo> reservedClientInfo( 1838 oldLoadInfo->GetReservedClientInfo()); 1839 if (reservedClientInfo.isSome()) { 1840 newLoadInfo->SetReservedClientInfo(reservedClientInfo.ref()); 1841 } 1842 1843 Maybe<ClientInfo> initialClientInfo(oldLoadInfo->GetInitialClientInfo()); 1844 if (initialClientInfo.isSome()) { 1845 newLoadInfo->SetInitialClientInfo(initialClientInfo.ref()); 1846 } 1847 1848 // If this is ServiceWorker fallback redirect, info HttpChannelChild to 1849 // detach StreamFilters. Otherwise StreamFilters will be attached twice 1850 // on the same HttpChannelChild when opening the new nsHttpChannel. 1851 if (oldIntercepted) { 1852 (void)DetachStreamFilters(); 1853 } 1854 1855 // Re-link the HttpChannelParent to the new channel. 1856 nsCOMPtr<nsIChannel> linkedChannel; 1857 rv = NS_LinkRedirectChannels(mRedirectChannelId, this, 1858 getter_AddRefs(linkedChannel)); 1859 NS_ENSURE_SUCCESS(rv, rv); 1860 MOZ_ASSERT(linkedChannel == newChannel); 1861 1862 // We immediately store the channel as our nested mChannel. 1863 // None of the redirect IPC messaging takes place. 1864 mChannel = do_QueryObject(newChannel); 1865 1866 callback->OnRedirectVerifyCallback(NS_OK); 1867 return NS_OK; 1868 } 1869 } 1870 1871 // Sending down the original URI, because that is the URI we have 1872 // to construct the channel from - this is the URI we've been actually 1873 // redirected to. URI of the channel may be an inner channel URI. 1874 // URI of the channel will be reconstructed by the protocol handler 1875 // on the child process, no need to send it then. 1876 nsCOMPtr<nsIURI> newOriginalURI; 1877 newChannel->GetOriginalURI(getter_AddRefs(newOriginalURI)); 1878 1879 uint32_t newLoadFlags = nsIRequest::LOAD_NORMAL; 1880 MOZ_ALWAYS_SUCCEEDS(newChannel->GetLoadFlags(&newLoadFlags)); 1881 1882 nsCOMPtr<nsITransportSecurityInfo> securityInfo(SecurityInfo()); 1883 1884 // If the channel is a HTTP channel, we also want to inform the child 1885 // about the parent's channelId attribute, so that both parent and child 1886 // share the same ID. Useful for monitoring channel activity in devtools. 1887 uint64_t channelId = 0; 1888 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(newChannel); 1889 if (httpChannel) { 1890 rv = httpChannel->GetChannelId(&channelId); 1891 NS_ENSURE_SUCCESS(rv, NS_BINDING_ABORTED); 1892 } 1893 1894 nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo(); 1895 1896 ParentLoadInfoForwarderArgs loadInfoForwarderArg; 1897 mozilla::ipc::LoadInfoToParentLoadInfoForwarder(loadInfo, 1898 &loadInfoForwarderArg); 1899 1900 nsHttpResponseHead* responseHead = mChannel->GetResponseHead(); 1901 1902 nsHttpResponseHead cleanedUpResponseHead; 1903 if (responseHead && responseHead->HasHeader(nsHttp::Set_Cookie)) { 1904 cleanedUpResponseHead = *responseHead; 1905 cleanedUpResponseHead.ClearHeader(nsHttp::Set_Cookie); 1906 responseHead = &cleanedUpResponseHead; 1907 } 1908 1909 if (!responseHead) { 1910 responseHead = &cleanedUpResponseHead; 1911 } 1912 1913 if (!mIPCClosed) { 1914 cleanedUpResponseHead = *responseHead; 1915 if (!SendRedirect1Begin(mRedirectChannelId, newOriginalURI, newLoadFlags, 1916 redirectFlags, loadInfoForwarderArg, 1917 std::move(cleanedUpResponseHead), securityInfo, 1918 channelId, mChannel->GetPeerAddr(), 1919 GetTimingAttributes(mChannel))) { 1920 return NS_BINDING_ABORTED; 1921 } 1922 } 1923 1924 // Result is handled in RecvRedirect2Verify above 1925 1926 mRedirectChannel = newChannel; 1927 mRedirectCallback = callback; 1928 return NS_OK; 1929 } 1930 1931 NS_IMETHODIMP 1932 HttpChannelParent::CompleteRedirect(nsresult status) { 1933 LOG(("HttpChannelParent::CompleteRedirect [this=%p status=0x%X]\n", this, 1934 static_cast<uint32_t>(status))); 1935 1936 // If this was an internal redirect for a service worker interception then 1937 // we will not have a redirecting channel here. Hide this redirect from 1938 // the child. 1939 if (!mRedirectChannel) { 1940 return NS_OK; 1941 } 1942 1943 if (!mIPCClosed) { 1944 // TODO: check return value: assume child dead if failed 1945 if (NS_SUCCEEDED(status)) { 1946 (void)SendRedirect3Complete(); 1947 } else { 1948 (void)SendRedirectFailed(status); 1949 } 1950 } 1951 1952 mRedirectChannel = nullptr; 1953 return NS_OK; 1954 } 1955 1956 NS_IMPL_ADDREF(CacheEntryWriteHandleParent) 1957 NS_IMPL_RELEASE(CacheEntryWriteHandleParent) 1958 NS_INTERFACE_MAP_BEGIN(CacheEntryWriteHandleParent) 1959 NS_INTERFACE_MAP_ENTRY(nsISupports) 1960 NS_INTERFACE_MAP_ENTRY(nsICacheEntryWriteHandle) 1961 NS_INTERFACE_MAP_END 1962 1963 CacheEntryWriteHandleParent::CacheEntryWriteHandleParent( 1964 nsICacheEntry* aCacheEntry) 1965 : mCacheEntry(aCacheEntry) {} 1966 1967 NS_IMETHODIMP 1968 CacheEntryWriteHandleParent::OpenAlternativeOutputStream( 1969 const nsACString& type, int64_t predictedSize, 1970 nsIAsyncOutputStream** _retval) { 1971 if (!mCacheEntry) { 1972 return NS_ERROR_NOT_AVAILABLE; 1973 } 1974 1975 nsresult rv = 1976 mCacheEntry->OpenAlternativeOutputStream(type, predictedSize, _retval); 1977 if (NS_SUCCEEDED(rv)) { 1978 mCacheEntry->SetMetaDataElement("alt-data-from-child", "1"); 1979 } 1980 return rv; 1981 } 1982 1983 CacheEntryWriteHandleParent* HttpChannelParent::AllocCacheEntryWriteHandle() { 1984 return new CacheEntryWriteHandleParent(mCacheEntry); 1985 } 1986 1987 nsresult HttpChannelParent::OpenAlternativeOutputStream( 1988 const nsACString& type, int64_t predictedSize, 1989 nsIAsyncOutputStream** _retval) { 1990 // We need to make sure the child does not call SendDocumentChannelCleanup() 1991 // before opening the altOutputStream, because that clears mCacheEntry. 1992 if (!mCacheEntry) { 1993 return NS_ERROR_NOT_AVAILABLE; 1994 } 1995 nsresult rv = 1996 mCacheEntry->OpenAlternativeOutputStream(type, predictedSize, _retval); 1997 if (NS_SUCCEEDED(rv)) { 1998 mCacheEntry->SetMetaDataElement("alt-data-from-child", "1"); 1999 } 2000 return rv; 2001 } 2002 2003 already_AddRefed<nsITransportSecurityInfo> HttpChannelParent::SecurityInfo() { 2004 if (!mChannel) { 2005 return nullptr; 2006 } 2007 nsCOMPtr<nsITransportSecurityInfo> securityInfo; 2008 mChannel->GetSecurityInfo(getter_AddRefs(securityInfo)); 2009 return securityInfo.forget(); 2010 } 2011 2012 bool HttpChannelParent::DoSendDeleteSelf() { 2013 mIPCClosed = true; 2014 bool rv = SendDeleteSelf(); 2015 2016 CleanupBackgroundChannel(); 2017 2018 return rv; 2019 } 2020 2021 mozilla::ipc::IPCResult HttpChannelParent::RecvDeletingChannel() { 2022 // We need to ensure that the parent channel will not be sending any more IPC 2023 // messages after this, as the child is going away. DoSendDeleteSelf will 2024 // set mIPCClosed = true; 2025 if (!DoSendDeleteSelf()) { 2026 return IPC_FAIL_NO_REASON(this); 2027 } 2028 return IPC_OK(); 2029 } 2030 2031 //----------------------------------------------------------------------------- 2032 // HttpChannelSecurityWarningReporter 2033 //----------------------------------------------------------------------------- 2034 2035 nsresult HttpChannelParent::ReportSecurityMessage( 2036 const nsAString& aMessageTag, const nsAString& aMessageCategory) { 2037 if (mIPCClosed || NS_WARN_IF(!SendReportSecurityMessage( 2038 nsString(aMessageTag), nsString(aMessageCategory)))) { 2039 return NS_ERROR_UNEXPECTED; 2040 } 2041 return NS_OK; 2042 } 2043 2044 //----------------------------------------------------------------------------- 2045 // nsIAsyncVerifyRedirectReadyCallback 2046 //----------------------------------------------------------------------------- 2047 2048 NS_IMETHODIMP 2049 HttpChannelParent::ReadyToVerify(nsresult aResult) { 2050 LOG(("HttpChannelParent::ReadyToVerify [this=%p result=%" PRIx32 "]\n", this, 2051 static_cast<uint32_t>(aResult))); 2052 MOZ_ASSERT(NS_IsMainThread()); 2053 2054 ContinueRedirect2Verify(aResult); 2055 2056 return NS_OK; 2057 } 2058 2059 void HttpChannelParent::DoSendSetPriority(int16_t aValue) { 2060 if (!mIPCClosed) { 2061 (void)SendSetPriority(aValue); 2062 } 2063 } 2064 2065 void HttpChannelParent::DoSendReportLNAToConsole( 2066 const NetAddr& aPeerAddr, const nsACString& aMessageType, 2067 const nsACString& aPromptAction, const nsACString& aTopLevelSite) { 2068 if (!mIPCClosed) { 2069 (void)SendReportLNAToConsole(aPeerAddr, nsCString(aMessageType), 2070 nsCString(aPromptAction), 2071 nsCString(aTopLevelSite)); 2072 } 2073 } 2074 2075 nsresult HttpChannelParent::LogBlockedCORSRequest(const nsAString& aMessage, 2076 const nsACString& aCategory, 2077 bool aIsWarning) { 2078 if (mIPCClosed || 2079 NS_WARN_IF(!SendLogBlockedCORSRequest( 2080 nsString(aMessage), nsCString(aCategory), aIsWarning))) { 2081 return NS_ERROR_UNEXPECTED; 2082 } 2083 return NS_OK; 2084 } 2085 2086 nsresult HttpChannelParent::LogMimeTypeMismatch(const nsACString& aMessageName, 2087 bool aWarning, 2088 const nsAString& aURL, 2089 const nsAString& aContentType) { 2090 if (mIPCClosed || NS_WARN_IF(!SendLogMimeTypeMismatch( 2091 nsCString(aMessageName), aWarning, nsString(aURL), 2092 nsString(aContentType)))) { 2093 return NS_ERROR_UNEXPECTED; 2094 } 2095 return NS_OK; 2096 } 2097 2098 //----------------------------------------------------------------------------- 2099 // nsIChannelEventSink 2100 //----------------------------------------------------------------------------- 2101 2102 NS_IMETHODIMP 2103 HttpChannelParent::AsyncOnChannelRedirect( 2104 nsIChannel* aOldChannel, nsIChannel* aNewChannel, uint32_t aRedirectFlags, 2105 nsIAsyncVerifyRedirectCallback* aCallback) { 2106 LOG( 2107 ("HttpChannelParent::AsyncOnChannelRedirect [this=%p, old=%p, " 2108 "new=%p, flags=%u]", 2109 this, aOldChannel, aNewChannel, aRedirectFlags)); 2110 2111 return StartRedirect(aNewChannel, aRedirectFlags, aCallback); 2112 } 2113 2114 //----------------------------------------------------------------------------- 2115 // nsIRedirectResultListener 2116 //----------------------------------------------------------------------------- 2117 2118 NS_IMETHODIMP 2119 HttpChannelParent::OnRedirectResult(nsresult status) { 2120 LOG(("HttpChannelParent::OnRedirectResult [this=%p, status=0x%X]", this, 2121 static_cast<uint32_t>(status))); 2122 2123 nsresult rv = NS_OK; 2124 2125 nsCOMPtr<nsIParentChannel> redirectChannel; 2126 if (mRedirectChannelId) { 2127 nsCOMPtr<nsIRedirectChannelRegistrar> registrar = 2128 RedirectChannelRegistrar::GetOrCreate(); 2129 MOZ_ASSERT(registrar); 2130 2131 rv = registrar->GetParentChannel(mRedirectChannelId, 2132 getter_AddRefs(redirectChannel)); 2133 if (NS_FAILED(rv) || !redirectChannel) { 2134 // Redirect might get canceled before we got AsyncOnChannelRedirect 2135 LOG(("Registered parent channel not found under id=%" PRIx64, 2136 mRedirectChannelId)); 2137 2138 nsCOMPtr<nsIChannel> newChannel; 2139 rv = registrar->GetRegisteredChannel(mRedirectChannelId, 2140 getter_AddRefs(newChannel)); 2141 MOZ_ASSERT(newChannel, "Already registered channel not found"); 2142 2143 if (NS_SUCCEEDED(rv)) { 2144 newChannel->Cancel(NS_BINDING_ABORTED); 2145 } 2146 } 2147 2148 // Release all previously registered channels, they are no longer need to be 2149 // kept in the registrar from this moment. 2150 registrar->DeregisterChannels(mRedirectChannelId); 2151 2152 mRedirectChannelId = 0; 2153 } 2154 2155 if (!redirectChannel) { 2156 if (NS_FAILED(rv)) { 2157 status = rv; 2158 } else { 2159 status = NS_ERROR_NULL_POINTER; 2160 } 2161 } 2162 2163 CompleteRedirect(status); 2164 2165 if (NS_SUCCEEDED(status)) { 2166 if (!SameCOMIdentity(redirectChannel, 2167 static_cast<nsIParentRedirectingChannel*>(this))) { 2168 Delete(); 2169 mParentListener->SetListenerAfterRedirect(redirectChannel); 2170 redirectChannel->SetParentListener(mParentListener); 2171 } 2172 } else if (redirectChannel) { 2173 // Delete the redirect target channel: continue using old channel 2174 redirectChannel->Delete(); 2175 } 2176 2177 return NS_OK; 2178 } 2179 2180 void HttpChannelParent::OverrideReferrerInfoDuringBeginConnect( 2181 nsIReferrerInfo* aReferrerInfo) { 2182 MOZ_ASSERT(aReferrerInfo); 2183 MOZ_ASSERT(!mAfterOnStartRequestBegun); 2184 2185 mOverrideReferrerInfo = aReferrerInfo; 2186 } 2187 2188 auto HttpChannelParent::AttachStreamFilter( 2189 Endpoint<extensions::PStreamFilterParent>&& aParentEndpoint, 2190 Endpoint<extensions::PStreamFilterChild>&& aChildEndpoint) 2191 -> RefPtr<ChildEndpointPromise> { 2192 LOG(("HttpChannelParent::AttachStreamFilter [this=%p]", this)); 2193 MOZ_ASSERT(!mAfterOnStartRequestBegun); 2194 2195 if (mIPCClosed) { 2196 return ChildEndpointPromise::CreateAndReject(false, __func__); 2197 } 2198 2199 // If IPC channel is open, background channel should be ready to send 2200 // SendAttachStreamFilter. 2201 MOZ_ASSERT(mBgParent); 2202 return InvokeAsync(mBgParent->GetBackgroundTarget(), mBgParent.get(), 2203 __func__, &HttpBackgroundChannelParent::AttachStreamFilter, 2204 std::move(aParentEndpoint), std::move(aChildEndpoint)); 2205 } 2206 2207 auto HttpChannelParent::DetachStreamFilters() -> RefPtr<GenericPromise> { 2208 LOG(("HttpChannelParent::DeattachStreamFilter [this=%p]", this)); 2209 MOZ_ASSERT(!mAfterOnStartRequestBegun); 2210 2211 if (NS_WARN_IF(mIPCClosed)) { 2212 return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); 2213 } 2214 2215 MOZ_ASSERT(mBgParent); 2216 return InvokeAsync(mBgParent->GetBackgroundTarget(), mBgParent.get(), 2217 __func__, 2218 &HttpBackgroundChannelParent::DetachStreamFilters); 2219 } 2220 2221 void HttpChannelParent::SetHttpChannelFromEarlyHintPreloader( 2222 HttpBaseChannel* aChannel) { 2223 MOZ_ASSERT(aChannel); 2224 if (mChannel) { 2225 MOZ_ASSERT(false, "SetHttpChannel called with mChannel aready set"); 2226 return; 2227 } 2228 2229 mChannel = aChannel; 2230 } 2231 2232 void HttpChannelParent::SetCookieChanges(nsTArray<CookieChange>&& aChanges) { 2233 LOG(("HttpChannelParent::SetCookie [this=%p]", this)); 2234 MOZ_ASSERT(!mAfterOnStartRequestBegun); 2235 MOZ_ASSERT(mCookieChanges.IsEmpty()); 2236 2237 // The loadGroup of the channel in the parent process could be null in the 2238 // XPCShell content process test, see test_cookiejars_wrap.js. In this case, 2239 // we cannot explicitly set the loadGroup for the parent channel because it's 2240 // created from the content process. To workaround this, we add a testing pref 2241 // to skip this check. 2242 if (!StaticPrefs:: 2243 network_cookie_skip_browsing_context_check_in_parent_for_testing() && 2244 mChannel->IsBrowsingContextDiscarded()) { 2245 return; 2246 } 2247 mCookieChanges.AppendElements(aChanges); 2248 } 2249 2250 } // namespace mozilla::net