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