mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
482d731e3a
By passing a weak reference back to the DocumentChannelParent into DocumentLoadListener for object loads, we are able to handle process switching loads by asking the content process to create a BrowsingContext, and delaying the real process switch until it becomes available. The load then completes as it would before, acting as a normal process-switching subframe load. Differential Revision: https://phabricator.services.mozilla.com/D86580
146 lines
5.5 KiB
C++
146 lines
5.5 KiB
C++
/* -*- 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 "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 =
|
|
new nsDocShellLoadState(aArgs.loadState());
|
|
LOG(("DocumentChannelParent Init [this=%p, uri=%s]", this,
|
|
loadState->URI()->GetSpecOrDefault().get()));
|
|
|
|
RefPtr<DocumentLoadListener::OpenPromise> promise;
|
|
if (loadState->GetChannelInitialized()) {
|
|
promise = DocumentLoadListener::ClaimParentLoad(
|
|
getter_AddRefs(mDocumentLoadListener), loadState->GetLoadIdentifier());
|
|
}
|
|
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().refOr(nullptr),
|
|
std::move(clientInfo), Some(docArgs.uriModified()),
|
|
Some(docArgs.isXFOError()), IProtocol::OtherPid(), &rv);
|
|
} else {
|
|
const ObjectCreationArgs& objectArgs = aArgs.elementCreationArgs();
|
|
|
|
promise = mDocumentLoadListener->OpenObject(
|
|
loadState, aArgs.cacheKey(), Some(aArgs.channelId()),
|
|
aArgs.asyncOpenTime(), aArgs.timing().refOr(nullptr),
|
|
std::move(clientInfo), objectArgs.embedderInnerWindowId(),
|
|
objectArgs.loadFlags(), objectArgs.contentPolicyType(),
|
|
objectArgs.isUrgentStart(), IProtocol::OtherPid(),
|
|
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);
|
|
// 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.mSwitchedProcess);
|
|
}
|
|
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) {
|
|
if (!CanSend()) {
|
|
return PDocumentChannelParent::RedirectToRealChannelPromise::
|
|
CreateAndReject(ResponseRejectReason::ChannelClosed, __func__);
|
|
}
|
|
RedirectToRealChannelArgs args;
|
|
mDocumentLoadListener->SerializeRedirectData(
|
|
args, false, aRedirectFlags, aLoadFlags,
|
|
static_cast<ContentParent*>(Manager()->Manager()));
|
|
return SendRedirectToRealChannel(args, std::move(aStreamFilterEndpoints));
|
|
}
|
|
|
|
} // namespace net
|
|
} // namespace mozilla
|
|
|
|
#undef LOG
|