1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=8 et tw=80 : */
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/. */
8 #include "mozilla/net/DocumentChannel.h"
12 #include "mozIDOMWindow.h"
13 #include "mozilla/AlreadyAddRefed.h"
14 #include "mozilla/Assertions.h"
15 #include "mozilla/LoadInfo.h"
16 #include "mozilla/Logging.h"
17 #include "mozilla/RefPtr.h"
18 #include "mozilla/TimeStamp.h"
19 #include "mozilla/Unused.h"
20 #include "mozilla/dom/Document.h"
21 #include "mozilla/net/DocumentChannelChild.h"
22 #include "mozilla/net/ParentProcessDocumentChannel.h"
25 #include "nsDocShell.h"
26 #include "nsDocShellLoadState.h"
27 #include "nsHttpHandler.h"
28 #include "nsIContentPolicy.h"
29 #include "nsIInterfaceRequestor.h"
30 #include "nsILoadContext.h"
31 #include "nsILoadGroup.h"
32 #include "nsILoadInfo.h"
33 #include "nsIStreamListener.h"
35 #include "nsMimeTypes.h"
36 #include "nsNetUtil.h"
37 #include "nsPIDOMWindow.h"
38 #include "nsPIDOMWindowInlines.h"
39 #include "nsStringFwd.h"
40 #include "nsThreadUtils.h"
41 #include "nsXULAppAPI.h"
44 using namespace mozilla::dom
;
45 using namespace mozilla::ipc
;
47 extern mozilla::LazyLogModule gDocumentChannelLog
;
48 #define LOG(fmt) MOZ_LOG(gDocumentChannelLog, mozilla::LogLevel::Verbose, fmt)
53 //-----------------------------------------------------------------------------
54 // DocumentChannel::nsISupports
56 NS_IMPL_ADDREF(DocumentChannel
)
57 NS_IMPL_RELEASE(DocumentChannel
)
59 NS_INTERFACE_MAP_BEGIN(DocumentChannel
)
60 NS_INTERFACE_MAP_ENTRY(nsIRequest
)
61 NS_INTERFACE_MAP_ENTRY(nsIChannel
)
62 NS_INTERFACE_MAP_ENTRY(nsIIdentChannel
)
63 NS_INTERFACE_MAP_ENTRY_CONCRETE(DocumentChannel
)
64 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIRequest
)
67 DocumentChannel::DocumentChannel(nsDocShellLoadState
* aLoadState
,
68 net::LoadInfo
* aLoadInfo
,
69 nsLoadFlags aLoadFlags
, uint32_t aCacheKey
,
71 bool aIsEmbeddingBlockedError
)
72 : mLoadState(aLoadState
),
74 mLoadFlags(aLoadFlags
),
75 mURI(aLoadState
->URI()),
77 mUriModified(aUriModified
),
78 mIsEmbeddingBlockedError(aIsEmbeddingBlockedError
) {
79 LOG(("DocumentChannel ctor [this=%p, uri=%s]", this,
80 aLoadState
->URI()->GetSpecOrDefault().get()));
81 RefPtr
<nsHttpHandler
> handler
= nsHttpHandler::GetInstance();
83 Unused
<< handler
->NewChannelId(channelId
);
84 mChannelId
= channelId
;
88 DocumentChannel::AsyncOpen(nsIStreamListener
* aListener
) {
89 MOZ_CRASH("If we get here, something is broken");
90 return NS_ERROR_NOT_IMPLEMENTED
;
93 void DocumentChannel::ShutdownListeners(nsresult aStatusCode
) {
94 LOG(("DocumentChannel ShutdownListeners [this=%p, status=%" PRIx32
"]", this,
95 static_cast<uint32_t>(aStatusCode
)));
96 mStatus
= aStatusCode
;
98 nsCOMPtr
<nsIStreamListener
> listener
= mListener
;
100 listener
->OnStartRequest(this);
105 listener
= mListener
; // it might have changed!
106 nsCOMPtr
<nsILoadGroup
> loadGroup
= mLoadGroup
;
109 mLoadGroup
= nullptr;
110 mCallbacks
= nullptr;
112 NS_DispatchToMainThread(NS_NewRunnableFunction(
113 "DocumentChannel::ShutdownListeners", [=, self
= RefPtr
{this}] {
115 listener
->OnStopRequest(self
, aStatusCode
);
119 loadGroup
->RemoveRequest(self
, nullptr, aStatusCode
);
126 void DocumentChannel::DisconnectChildListeners(
127 const nsresult
& aStatus
, const nsresult
& aLoadGroupStatus
) {
128 MOZ_ASSERT(NS_FAILED(aStatus
));
129 mStatus
= aLoadGroupStatus
;
130 // Make sure we remove from the load group before
131 // setting mStatus, as existing tests expect the
132 // status to be successful when we disconnect.
134 mLoadGroup
->RemoveRequest(this, nullptr, aStatus
);
135 mLoadGroup
= nullptr;
138 ShutdownListeners(aStatus
);
141 nsDocShell
* DocumentChannel::GetDocShell() {
142 nsCOMPtr
<nsILoadContext
> loadContext
;
143 NS_QueryNotificationCallbacks(this, loadContext
);
147 nsCOMPtr
<mozIDOMWindowProxy
> domWindow
;
148 loadContext
->GetAssociatedWindow(getter_AddRefs(domWindow
));
152 auto* pDomWindow
= nsPIDOMWindowOuter::From(domWindow
);
153 nsIDocShell
* docshell
= pDomWindow
->GetDocShell();
154 return nsDocShell::Cast(docshell
);
157 static bool URIUsesDocChannel(nsIURI
* aURI
) {
158 if (SchemeIsJavascript(aURI
)) {
162 nsCString spec
= aURI
->GetSpecOrDefault();
163 return !spec
.EqualsLiteral("about:crashcontent");
166 bool DocumentChannel::CanUseDocumentChannel(nsIURI
* aURI
) {
167 // We want to use DocumentChannel if we're using a supported scheme.
168 return URIUsesDocChannel(aURI
);
172 already_AddRefed
<DocumentChannel
> DocumentChannel::CreateForDocument(
173 nsDocShellLoadState
* aLoadState
, class LoadInfo
* aLoadInfo
,
174 nsLoadFlags aLoadFlags
, nsIInterfaceRequestor
* aNotificationCallbacks
,
175 uint32_t aCacheKey
, bool aUriModified
, bool aIsEmbeddingBlockedError
) {
176 RefPtr
<DocumentChannel
> channel
;
177 if (XRE_IsContentProcess()) {
179 new DocumentChannelChild(aLoadState
, aLoadInfo
, aLoadFlags
, aCacheKey
,
180 aUriModified
, aIsEmbeddingBlockedError
);
182 channel
= new ParentProcessDocumentChannel(
183 aLoadState
, aLoadInfo
, aLoadFlags
, aCacheKey
, aUriModified
,
184 aIsEmbeddingBlockedError
);
186 channel
->SetNotificationCallbacks(aNotificationCallbacks
);
187 return channel
.forget();
191 already_AddRefed
<DocumentChannel
> DocumentChannel::CreateForObject(
192 nsDocShellLoadState
* aLoadState
, class LoadInfo
* aLoadInfo
,
193 nsLoadFlags aLoadFlags
, nsIInterfaceRequestor
* aNotificationCallbacks
) {
194 return CreateForDocument(aLoadState
, aLoadInfo
, aLoadFlags
,
195 aNotificationCallbacks
, 0, false, false);
198 NS_IMETHODIMP
DocumentChannel::SetCanceledReason(const nsACString
& aReason
) {
199 return SetCanceledReasonImpl(aReason
);
202 NS_IMETHODIMP
DocumentChannel::GetCanceledReason(nsACString
& aReason
) {
203 return GetCanceledReasonImpl(aReason
);
206 NS_IMETHODIMP
DocumentChannel::CancelWithReason(nsresult aStatus
,
207 const nsACString
& aReason
) {
208 return CancelWithReasonImpl(aStatus
, aReason
);
212 DocumentChannel::Cancel(nsresult aStatusCode
) {
213 MOZ_CRASH("If we get here, something is broken");
214 return NS_ERROR_NOT_IMPLEMENTED
;
218 DocumentChannel::Suspend() {
219 MOZ_CRASH("If we get here, something is broken");
220 return NS_ERROR_NOT_IMPLEMENTED
;
224 DocumentChannel::Resume() {
225 MOZ_CRASH("If we get here, something is broken");
226 return NS_ERROR_NOT_IMPLEMENTED
;
229 //-----------------------------------------------------------------------------
230 // Remainder of nsIRequest/nsIChannel.
231 //-----------------------------------------------------------------------------
233 NS_IMETHODIMP
DocumentChannel::GetNotificationCallbacks(
234 nsIInterfaceRequestor
** aCallbacks
) {
235 nsCOMPtr
<nsIInterfaceRequestor
> callbacks(mCallbacks
);
236 callbacks
.forget(aCallbacks
);
240 NS_IMETHODIMP
DocumentChannel::SetNotificationCallbacks(
241 nsIInterfaceRequestor
* aNotificationCallbacks
) {
242 mCallbacks
= aNotificationCallbacks
;
246 NS_IMETHODIMP
DocumentChannel::GetLoadGroup(nsILoadGroup
** aLoadGroup
) {
247 nsCOMPtr
<nsILoadGroup
> loadGroup(mLoadGroup
);
248 loadGroup
.forget(aLoadGroup
);
252 NS_IMETHODIMP
DocumentChannel::SetLoadGroup(nsILoadGroup
* aLoadGroup
) {
253 mLoadGroup
= aLoadGroup
;
257 NS_IMETHODIMP
DocumentChannel::GetStatus(nsresult
* aStatus
) {
262 NS_IMETHODIMP
DocumentChannel::GetName(nsACString
& aResult
) {
268 nsresult rv
= mURI
->GetSpec(spec
);
269 NS_ENSURE_SUCCESS(rv
, rv
);
271 aResult
.AssignLiteral("documentchannel:");
272 aResult
.Append(spec
);
276 NS_IMETHODIMP
DocumentChannel::IsPending(bool* aResult
) {
277 *aResult
= mIsPending
;
281 NS_IMETHODIMP
DocumentChannel::GetLoadFlags(nsLoadFlags
* aLoadFlags
) {
282 *aLoadFlags
= mLoadFlags
;
287 DocumentChannel::GetTRRMode(nsIRequest::TRRMode
* aTRRMode
) {
288 return GetTRRModeImpl(aTRRMode
);
292 DocumentChannel::SetTRRMode(nsIRequest::TRRMode aTRRMode
) {
293 return SetTRRModeImpl(aTRRMode
);
296 NS_IMETHODIMP
DocumentChannel::SetLoadFlags(nsLoadFlags aLoadFlags
) {
297 // Setting load flags for TYPE_OBJECT is OK, so long as the channel to parent
298 // isn't opened yet, or we're only setting the `LOAD_DOCUMENT_URI` flag.
299 auto contentPolicy
= mLoadInfo
->GetExternalContentPolicyType();
300 if (contentPolicy
== ExtContentPolicy::TYPE_OBJECT
) {
302 MOZ_DIAGNOSTIC_ASSERT(
303 aLoadFlags
== (mLoadFlags
| nsIChannel::LOAD_DOCUMENT_URI
),
304 "After the channel has been opened, can only set the "
305 "`LOAD_DOCUMENT_URI` flag.");
307 mLoadFlags
= aLoadFlags
;
311 MOZ_CRASH_UNSAFE_PRINTF(
312 "DocumentChannel::SetLoadFlags: Don't set flags after creation "
313 "(differing flags %x != %x)",
314 (mLoadFlags
^ aLoadFlags
) & mLoadFlags
,
315 (mLoadFlags
^ aLoadFlags
) & aLoadFlags
);
318 NS_IMETHODIMP
DocumentChannel::GetOriginalURI(nsIURI
** aOriginalURI
) {
319 nsCOMPtr
<nsIURI
> originalURI
=
320 mLoadState
->OriginalURI() ? mLoadState
->OriginalURI() : mLoadState
->URI();
321 originalURI
.forget(aOriginalURI
);
325 NS_IMETHODIMP
DocumentChannel::SetOriginalURI(nsIURI
* aOriginalURI
) {
326 MOZ_CRASH("If we get here, something is broken");
327 return NS_ERROR_NOT_IMPLEMENTED
;
330 NS_IMETHODIMP
DocumentChannel::GetURI(nsIURI
** aURI
) {
331 nsCOMPtr
<nsIURI
> uri(mURI
);
336 NS_IMETHODIMP
DocumentChannel::GetOwner(nsISupports
** aOwner
) {
337 nsCOMPtr
<nsISupports
> owner(mOwner
);
338 owner
.forget(aOwner
);
342 NS_IMETHODIMP
DocumentChannel::SetOwner(nsISupports
* aOwner
) {
347 NS_IMETHODIMP
DocumentChannel::GetSecurityInfo(
348 nsITransportSecurityInfo
** aSecurityInfo
) {
349 *aSecurityInfo
= nullptr;
353 NS_IMETHODIMP
DocumentChannel::GetContentType(nsACString
& aContentType
) {
354 // We may be trying to load HTML object data, and have determined that we're
355 // going to be performing a document load. In that case, fake the "text/html"
356 // content type for nsObjectLoadingContent.
357 if ((mLoadFlags
& nsIRequest::LOAD_HTML_OBJECT_DATA
) &&
358 (mLoadFlags
& nsIChannel::LOAD_DOCUMENT_URI
)) {
359 aContentType
= TEXT_HTML
;
363 NS_ERROR("If we get here, something is broken");
364 return NS_ERROR_NOT_IMPLEMENTED
;
367 NS_IMETHODIMP
DocumentChannel::SetContentType(const nsACString
& aContentType
) {
368 MOZ_CRASH("If we get here, something is broken");
369 return NS_ERROR_NOT_IMPLEMENTED
;
372 NS_IMETHODIMP
DocumentChannel::GetContentCharset(nsACString
& aContentCharset
) {
373 MOZ_CRASH("If we get here, something is broken");
374 return NS_ERROR_NOT_IMPLEMENTED
;
377 NS_IMETHODIMP
DocumentChannel::SetContentCharset(
378 const nsACString
& aContentCharset
) {
379 MOZ_CRASH("If we get here, something is broken");
380 return NS_ERROR_NOT_IMPLEMENTED
;
383 NS_IMETHODIMP
DocumentChannel::GetContentLength(int64_t* aContentLength
) {
384 MOZ_CRASH("If we get here, something is broken");
385 return NS_ERROR_NOT_IMPLEMENTED
;
388 NS_IMETHODIMP
DocumentChannel::SetContentLength(int64_t aContentLength
) {
389 MOZ_CRASH("If we get here, something is broken");
390 return NS_ERROR_NOT_IMPLEMENTED
;
393 NS_IMETHODIMP
DocumentChannel::Open(nsIInputStream
** aStream
) {
394 MOZ_CRASH("If we get here, something is broken");
395 return NS_ERROR_NOT_IMPLEMENTED
;
398 NS_IMETHODIMP
DocumentChannel::GetContentDisposition(
399 uint32_t* aContentDisposition
) {
400 MOZ_CRASH("If we get here, something is broken");
401 return NS_ERROR_NOT_IMPLEMENTED
;
404 NS_IMETHODIMP
DocumentChannel::SetContentDisposition(
405 uint32_t aContentDisposition
) {
406 MOZ_CRASH("If we get here, something is broken");
407 return NS_ERROR_NOT_IMPLEMENTED
;
410 NS_IMETHODIMP
DocumentChannel::GetContentDispositionFilename(
411 nsAString
& aContentDispositionFilename
) {
412 MOZ_CRASH("If we get here, something will be broken");
413 return NS_ERROR_NOT_IMPLEMENTED
;
416 NS_IMETHODIMP
DocumentChannel::SetContentDispositionFilename(
417 const nsAString
& aContentDispositionFilename
) {
418 MOZ_CRASH("If we get here, something will be broken");
419 return NS_ERROR_NOT_IMPLEMENTED
;
422 NS_IMETHODIMP
DocumentChannel::GetContentDispositionHeader(
423 nsACString
& aContentDispositionHeader
) {
424 MOZ_CRASH("If we get here, something is broken");
425 return NS_ERROR_NOT_IMPLEMENTED
;
428 NS_IMETHODIMP
DocumentChannel::GetLoadInfo(nsILoadInfo
** aLoadInfo
) {
429 nsCOMPtr
<nsILoadInfo
> loadInfo(mLoadInfo
);
430 loadInfo
.forget(aLoadInfo
);
434 NS_IMETHODIMP
DocumentChannel::SetLoadInfo(nsILoadInfo
* aLoadInfo
) {
435 MOZ_CRASH("If we get here, something is broken");
436 return NS_ERROR_NOT_IMPLEMENTED
;
439 NS_IMETHODIMP
DocumentChannel::GetIsDocument(bool* aIsDocument
) {
440 return NS_GetIsDocumentChannel(this, aIsDocument
);
443 NS_IMETHODIMP
DocumentChannel::GetCanceled(bool* aCanceled
) {
444 *aCanceled
= mCanceled
;
448 //-----------------------------------------------------------------------------
450 //-----------------------------------------------------------------------------
453 DocumentChannel::GetChannelId(uint64_t* aChannelId
) {
454 *aChannelId
= mChannelId
;
459 DocumentChannel::SetChannelId(uint64_t aChannelId
) {
460 mChannelId
= aChannelId
;
464 //-----------------------------------------------------------------------------
466 //-----------------------------------------------------------------------------
468 uint64_t InnerWindowIDForExtantDoc(nsDocShell
* docShell
) {
473 Document
* doc
= docShell
->GetExtantDocument();
478 return doc
->InnerWindowID();
482 } // namespace mozilla