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
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7
8 #include "DocumentChannelParent.h"
9
10 #include "mozilla/dom/BrowserParent.h"
11 #include "mozilla/dom/CanonicalBrowsingContext.h"
12 #include "mozilla/dom/ClientInfo.h"
13 #include "mozilla/dom/ContentParent.h"
14 #include "nsDocShellLoadState.h"
15
16 extern mozilla::LazyLogModule gDocumentChannelLog;
17 #define LOG(fmt) MOZ_LOG(gDocumentChannelLog, mozilla::LogLevel::Verbose, fmt)
18
19 using namespace mozilla::dom;
20
21 namespace mozilla {
22 namespace net {
23
DocumentChannelParent()24 DocumentChannelParent::DocumentChannelParent() {
25 LOG(("DocumentChannelParent ctor [this=%p]", this));
26 }
27
~DocumentChannelParent()28 DocumentChannelParent::~DocumentChannelParent() {
29 LOG(("DocumentChannelParent dtor [this=%p]", this));
30 }
31
Init(dom::CanonicalBrowsingContext * aContext,const DocumentChannelCreationArgs & aArgs)32 bool DocumentChannelParent::Init(dom::CanonicalBrowsingContext* aContext,
33 const DocumentChannelCreationArgs& aArgs) {
34 RefPtr<nsDocShellLoadState> loadState =
35 new nsDocShellLoadState(aArgs.loadState());
36 LOG(("DocumentChannelParent Init [this=%p, uri=%s]", this,
37 loadState->URI()->GetSpecOrDefault().get()));
38 if (aArgs.parentInitiatedNavigationEpoch() <
39 aContext->GetParentInitiatedNavigationEpoch()) {
40 nsresult rv = NS_BINDING_ABORTED;
41 return SendFailedAsyncOpen(rv);
42 }
43
44 ContentParent* contentParent =
45 static_cast<ContentParent*>(Manager()->Manager());
46
47 RefPtr<DocumentLoadListener::OpenPromise> promise;
48 if (loadState->GetChannelInitialized()) {
49 promise = DocumentLoadListener::ClaimParentLoad(
50 getter_AddRefs(mDocumentLoadListener), loadState->GetLoadIdentifier(),
51 Some(aArgs.channelId()));
52 }
53 if (!promise) {
54 bool isDocumentLoad =
55 aArgs.elementCreationArgs().type() ==
56 DocumentChannelElementCreationArgs::TDocumentCreationArgs;
57 mDocumentLoadListener = new DocumentLoadListener(aContext, isDocumentLoad);
58
59 Maybe<ClientInfo> clientInfo;
60 if (aArgs.initialClientInfo().isSome()) {
61 clientInfo.emplace(ClientInfo(aArgs.initialClientInfo().ref()));
62 }
63
64 nsresult rv = NS_ERROR_UNEXPECTED;
65
66 if (isDocumentLoad) {
67 const DocumentCreationArgs& docArgs = aArgs.elementCreationArgs();
68
69 promise = mDocumentLoadListener->OpenDocument(
70 loadState, aArgs.cacheKey(), Some(aArgs.channelId()),
71 aArgs.asyncOpenTime(), aArgs.timing().refOr(nullptr),
72 std::move(clientInfo), Some(docArgs.uriModified()),
73 Some(docArgs.isXFOError()), contentParent, &rv);
74 } else {
75 const ObjectCreationArgs& objectArgs = aArgs.elementCreationArgs();
76
77 promise = mDocumentLoadListener->OpenObject(
78 loadState, aArgs.cacheKey(), Some(aArgs.channelId()),
79 aArgs.asyncOpenTime(), aArgs.timing().refOr(nullptr),
80 std::move(clientInfo), objectArgs.embedderInnerWindowId(),
81 objectArgs.loadFlags(), objectArgs.contentPolicyType(),
82 objectArgs.isUrgentStart(), contentParent,
83 this /* ObjectUpgradeHandler */, &rv);
84 }
85
86 if (NS_FAILED(rv)) {
87 MOZ_ASSERT(!promise);
88 return SendFailedAsyncOpen(rv);
89 }
90 }
91
92 RefPtr<DocumentChannelParent> self = this;
93 promise->Then(
94 GetCurrentSerialEventTarget(), __func__,
95 [self](DocumentLoadListener::OpenPromiseSucceededType&& aResolveValue) {
96 // The DLL is waiting for us to resolve the
97 // PDocumentChannel::RedirectToRealChannelPromise given as parameter.
98 auto promise = self->RedirectToRealChannel(
99 std::move(aResolveValue.mStreamFilterEndpoints),
100 aResolveValue.mRedirectFlags, aResolveValue.mLoadFlags);
101 // We chain the promise the DLL is waiting on to the one returned by
102 // RedirectToRealChannel. As soon as the promise returned is resolved
103 // or rejected, so will the DLL's promise.
104 promise->ChainTo(aResolveValue.mPromise.forget(), __func__);
105 self->mDocumentLoadListener = nullptr;
106 },
107 [self](DocumentLoadListener::OpenPromiseFailedType&& aRejectValue) {
108 if (self->CanSend()) {
109 Unused << self->SendDisconnectChildListeners(
110 aRejectValue.mStatus, aRejectValue.mLoadGroupStatus,
111 aRejectValue.mSwitchedProcess);
112 }
113 self->mDocumentLoadListener = nullptr;
114 });
115
116 return true;
117 }
118
UpgradeObjectLoad()119 auto DocumentChannelParent::UpgradeObjectLoad()
120 -> RefPtr<ObjectUpgradePromise> {
121 return SendUpgradeObjectLoad()->Then(
122 GetCurrentSerialEventTarget(), __func__,
123 [](const UpgradeObjectLoadPromise::ResolveOrRejectValue& aValue) {
124 if (!aValue.IsResolve() || aValue.ResolveValue().IsNullOrDiscarded()) {
125 LOG(("DocumentChannelParent object load upgrade failed"));
126 return ObjectUpgradePromise::CreateAndReject(NS_ERROR_FAILURE,
127 __func__);
128 }
129
130 return ObjectUpgradePromise::CreateAndResolve(
131 aValue.ResolveValue().get_canonical(), __func__);
132 });
133 }
134
135 RefPtr<PDocumentChannelParent::RedirectToRealChannelPromise>
RedirectToRealChannel(nsTArray<ipc::Endpoint<extensions::PStreamFilterParent>> && aStreamFilterEndpoints,uint32_t aRedirectFlags,uint32_t aLoadFlags)136 DocumentChannelParent::RedirectToRealChannel(
137 nsTArray<ipc::Endpoint<extensions::PStreamFilterParent>>&&
138 aStreamFilterEndpoints,
139 uint32_t aRedirectFlags, uint32_t aLoadFlags) {
140 if (!CanSend()) {
141 return PDocumentChannelParent::RedirectToRealChannelPromise::
142 CreateAndReject(ResponseRejectReason::ChannelClosed, __func__);
143 }
144 RedirectToRealChannelArgs args;
145 mDocumentLoadListener->SerializeRedirectData(
146 args, false, aRedirectFlags, aLoadFlags,
147 static_cast<ContentParent*>(Manager()->Manager()));
148 return SendRedirectToRealChannel(args, std::move(aStreamFilterEndpoints));
149 }
150
151 } // namespace net
152 } // namespace mozilla
153
154 #undef LOG
155