diff options
Diffstat (limited to '')
-rw-r--r-- | netwerk/ipc/DocumentChannelParent.cpp | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/netwerk/ipc/DocumentChannelParent.cpp b/netwerk/ipc/DocumentChannelParent.cpp new file mode 100644 index 0000000000..a360f76bcb --- /dev/null +++ b/netwerk/ipc/DocumentChannelParent.cpp @@ -0,0 +1,160 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et tw=80 : */ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "DocumentChannelParent.h" + +#include "mozilla/dom/BrowserParent.h" +#include "mozilla/dom/CanonicalBrowsingContext.h" +#include "mozilla/dom/ClientInfo.h" +#include "mozilla/dom/ContentParent.h" +#include "mozilla/net/NeckoChannelParams.h" +#include "nsDocShellLoadState.h" + +extern mozilla::LazyLogModule gDocumentChannelLog; +#define LOG(fmt) MOZ_LOG(gDocumentChannelLog, mozilla::LogLevel::Verbose, fmt) + +using namespace mozilla::dom; + +namespace mozilla { +namespace net { + +DocumentChannelParent::DocumentChannelParent() { + LOG(("DocumentChannelParent ctor [this=%p]", this)); +} + +DocumentChannelParent::~DocumentChannelParent() { + LOG(("DocumentChannelParent dtor [this=%p]", this)); +} + +bool DocumentChannelParent::Init(dom::CanonicalBrowsingContext* aContext, + const DocumentChannelCreationArgs& aArgs) { + RefPtr<nsDocShellLoadState> loadState = aArgs.loadState(); + LOG(("DocumentChannelParent Init [this=%p, uri=%s]", this, + loadState->URI()->GetSpecOrDefault().get())); + if (aArgs.parentInitiatedNavigationEpoch() < + aContext->GetParentInitiatedNavigationEpoch()) { + nsresult rv = NS_BINDING_ABORTED; + return SendFailedAsyncOpen(rv); + } + + ContentParent* contentParent = + static_cast<ContentParent*>(Manager()->Manager()); + + RefPtr<DocumentLoadListener::OpenPromise> promise; + if (loadState->GetChannelInitialized()) { + promise = DocumentLoadListener::ClaimParentLoad( + getter_AddRefs(mDocumentLoadListener), loadState->GetLoadIdentifier(), + Some(aArgs.channelId())); + } + if (!promise) { + bool isDocumentLoad = + aArgs.elementCreationArgs().type() == + DocumentChannelElementCreationArgs::TDocumentCreationArgs; + mDocumentLoadListener = new DocumentLoadListener(aContext, isDocumentLoad); + + Maybe<ClientInfo> clientInfo; + if (aArgs.initialClientInfo().isSome()) { + clientInfo.emplace(ClientInfo(aArgs.initialClientInfo().ref())); + } + + nsresult rv = NS_ERROR_UNEXPECTED; + + if (isDocumentLoad) { + const DocumentCreationArgs& docArgs = aArgs.elementCreationArgs(); + + promise = mDocumentLoadListener->OpenDocument( + loadState, aArgs.cacheKey(), Some(aArgs.channelId()), + aArgs.asyncOpenTime(), aArgs.timing(), std::move(clientInfo), + Some(docArgs.uriModified()), Some(docArgs.isEmbeddingBlockedError()), + contentParent, &rv); + } else { + const ObjectCreationArgs& objectArgs = aArgs.elementCreationArgs(); + + promise = mDocumentLoadListener->OpenObject( + loadState, aArgs.cacheKey(), Some(aArgs.channelId()), + aArgs.asyncOpenTime(), aArgs.timing(), std::move(clientInfo), + objectArgs.embedderInnerWindowId(), objectArgs.loadFlags(), + objectArgs.contentPolicyType(), objectArgs.isUrgentStart(), + contentParent, this /* ObjectUpgradeHandler */, &rv); + } + + if (NS_FAILED(rv)) { + MOZ_ASSERT(!promise); + return SendFailedAsyncOpen(rv); + } + } + + RefPtr<DocumentChannelParent> self = this; + promise->Then( + GetCurrentSerialEventTarget(), __func__, + [self](DocumentLoadListener::OpenPromiseSucceededType&& aResolveValue) { + // The DLL is waiting for us to resolve the + // PDocumentChannel::RedirectToRealChannelPromise given as parameter. + auto promise = self->RedirectToRealChannel( + std::move(aResolveValue.mStreamFilterEndpoints), + aResolveValue.mRedirectFlags, aResolveValue.mLoadFlags, + aResolveValue.mEarlyHintLinkType); + // We chain the promise the DLL is waiting on to the one returned by + // RedirectToRealChannel. As soon as the promise returned is resolved + // or rejected, so will the DLL's promise. + promise->ChainTo(aResolveValue.mPromise.forget(), __func__); + self->mDocumentLoadListener = nullptr; + }, + [self](DocumentLoadListener::OpenPromiseFailedType&& aRejectValue) { + if (self->CanSend()) { + Unused << self->SendDisconnectChildListeners( + aRejectValue.mStatus, aRejectValue.mLoadGroupStatus, + aRejectValue.mContinueNavigating); + } + self->mDocumentLoadListener = nullptr; + }); + + return true; +} + +auto DocumentChannelParent::UpgradeObjectLoad() + -> RefPtr<ObjectUpgradePromise> { + return SendUpgradeObjectLoad()->Then( + GetCurrentSerialEventTarget(), __func__, + [](const UpgradeObjectLoadPromise::ResolveOrRejectValue& aValue) { + if (!aValue.IsResolve() || aValue.ResolveValue().IsNullOrDiscarded()) { + LOG(("DocumentChannelParent object load upgrade failed")); + return ObjectUpgradePromise::CreateAndReject(NS_ERROR_FAILURE, + __func__); + } + + return ObjectUpgradePromise::CreateAndResolve( + aValue.ResolveValue().get_canonical(), __func__); + }); +} + +RefPtr<PDocumentChannelParent::RedirectToRealChannelPromise> +DocumentChannelParent::RedirectToRealChannel( + nsTArray<ipc::Endpoint<extensions::PStreamFilterParent>>&& + aStreamFilterEndpoints, + uint32_t aRedirectFlags, uint32_t aLoadFlags, uint32_t aEarlyHintLinkType) { + if (!CanSend()) { + return PDocumentChannelParent::RedirectToRealChannelPromise:: + CreateAndReject(ResponseRejectReason::ChannelClosed, __func__); + } + + ContentParent* cp = static_cast<ContentParent*>(Manager()->Manager()); + nsTArray<EarlyHintConnectArgs> earlyHints; + mDocumentLoadListener->RegisterEarlyHintLinksAndGetConnectArgs(cp->ChildID(), + earlyHints); + + RedirectToRealChannelArgs args; + mDocumentLoadListener->SerializeRedirectData( + args, false, aRedirectFlags, aLoadFlags, std::move(earlyHints), + aEarlyHintLinkType); + return SendRedirectToRealChannel(args, std::move(aStreamFilterEndpoints)); +} + +} // namespace net +} // namespace mozilla + +#undef LOG |