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 "nsLoadGroup.h"
36 #include "nsMimeTypes.h"
37 #include "nsNetUtil.h"
38 #include "nsPIDOMWindow.h"
39 #include "nsPIDOMWindowInlines.h"
40 #include "nsStringFwd.h"
41 #include "nsThreadUtils.h"
42 #include "nsXULAppAPI.h"
45 using namespace mozilla::dom
;
46 using namespace mozilla::ipc
;
48 extern mozilla::LazyLogModule gDocumentChannelLog
;
49 #define LOG(fmt) MOZ_LOG(gDocumentChannelLog, mozilla::LogLevel::Verbose, fmt)
54 //-----------------------------------------------------------------------------
55 // DocumentChannel::nsISupports
57 NS_IMPL_ADDREF(DocumentChannel
)
58 NS_IMPL_RELEASE(DocumentChannel
)
60 NS_INTERFACE_MAP_BEGIN(DocumentChannel
)
61 NS_INTERFACE_MAP_ENTRY(nsIRequest
)
62 NS_INTERFACE_MAP_ENTRY(nsIChannel
)
63 NS_INTERFACE_MAP_ENTRY(nsIIdentChannel
)
64 NS_INTERFACE_MAP_ENTRY_CONCRETE(DocumentChannel
)
65 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIRequest
)
68 DocumentChannel::DocumentChannel(nsDocShellLoadState
* aLoadState
,
69 net::LoadInfo
* aLoadInfo
,
70 nsLoadFlags aLoadFlags
, uint32_t aCacheKey
,
72 bool aIsEmbeddingBlockedError
)
73 : mLoadState(aLoadState
),
75 mLoadFlags(aLoadFlags
),
76 mURI(aLoadState
->URI()),
78 mUriModified(aUriModified
),
79 mIsEmbeddingBlockedError(aIsEmbeddingBlockedError
) {
80 LOG(("DocumentChannel ctor [this=%p, uri=%s]", this,
81 aLoadState
->URI()->GetSpecOrDefault().get()));
82 RefPtr
<nsHttpHandler
> handler
= nsHttpHandler::GetInstance();
84 Unused
<< handler
->NewChannelId(channelId
);
85 mChannelId
= channelId
;
89 DocumentChannel::AsyncOpen(nsIStreamListener
* aListener
) {
90 MOZ_CRASH("If we get here, something is broken");
91 return NS_ERROR_NOT_IMPLEMENTED
;
94 void DocumentChannel::ShutdownListeners(nsresult aStatusCode
) {
95 LOG(("DocumentChannel ShutdownListeners [this=%p, status=%" PRIx32
"]", this,
96 static_cast<uint32_t>(aStatusCode
)));
97 mStatus
= aStatusCode
;
99 nsCOMPtr
<nsIStreamListener
> listener
= mListener
;
101 listener
->OnStartRequest(this);
106 listener
= mListener
; // it might have changed!
107 nsCOMPtr
<nsILoadGroup
> loadGroup
= mLoadGroup
;
110 mLoadGroup
= nullptr;
111 mCallbacks
= nullptr;
113 NS_DispatchToMainThread(NS_NewRunnableFunction(
114 "DocumentChannel::ShutdownListeners", [=, self
= RefPtr
{this}] {
116 listener
->OnStopRequest(self
, aStatusCode
);
120 loadGroup
->RemoveRequest(self
, nullptr, aStatusCode
);
127 void DocumentChannel::DisconnectChildListeners(
128 const nsresult
& aStatus
, const nsresult
& aLoadGroupStatus
) {
129 MOZ_ASSERT(NS_FAILED(aStatus
));
130 mStatus
= aLoadGroupStatus
;
131 // Make sure we remove from the load group before
132 // setting mStatus, as existing tests expect the
133 // status to be successful when we disconnect.
135 mLoadGroup
->RemoveRequest(this, nullptr, aStatus
);
136 mLoadGroup
= nullptr;
139 ShutdownListeners(aStatus
);
142 nsDocShell
* DocumentChannel::GetDocShell() {
143 nsCOMPtr
<nsILoadContext
> loadContext
;
144 NS_QueryNotificationCallbacks(this, loadContext
);
148 nsCOMPtr
<mozIDOMWindowProxy
> domWindow
;
149 loadContext
->GetAssociatedWindow(getter_AddRefs(domWindow
));
153 auto* pDomWindow
= nsPIDOMWindowOuter::From(domWindow
);
154 nsIDocShell
* docshell
= pDomWindow
->GetDocShell();
155 return nsDocShell::Cast(docshell
);
158 static bool URIUsesDocChannel(nsIURI
* aURI
) {
159 if (SchemeIsJavascript(aURI
)) {
163 nsCString spec
= aURI
->GetSpecOrDefault();
164 return !spec
.EqualsLiteral("about:crashcontent");
167 bool DocumentChannel::CanUseDocumentChannel(nsIURI
* aURI
) {
168 // We want to use DocumentChannel if we're using a supported scheme.
169 return URIUsesDocChannel(aURI
);
173 already_AddRefed
<DocumentChannel
> DocumentChannel::CreateForDocument(
174 nsDocShellLoadState
* aLoadState
, class LoadInfo
* aLoadInfo
,
175 nsLoadFlags aLoadFlags
, nsIInterfaceRequestor
* aNotificationCallbacks
,
176 uint32_t aCacheKey
, bool aUriModified
, bool aIsEmbeddingBlockedError
) {
177 RefPtr
<DocumentChannel
> channel
;
178 if (XRE_IsContentProcess()) {
180 new DocumentChannelChild(aLoadState
, aLoadInfo
, aLoadFlags
, aCacheKey
,
181 aUriModified
, aIsEmbeddingBlockedError
);
183 channel
= new ParentProcessDocumentChannel(
184 aLoadState
, aLoadInfo
, aLoadFlags
, aCacheKey
, aUriModified
,
185 aIsEmbeddingBlockedError
);
187 channel
->SetNotificationCallbacks(aNotificationCallbacks
);
188 return channel
.forget();
192 already_AddRefed
<DocumentChannel
> DocumentChannel::CreateForObject(
193 nsDocShellLoadState
* aLoadState
, class LoadInfo
* aLoadInfo
,
194 nsLoadFlags aLoadFlags
, nsIInterfaceRequestor
* aNotificationCallbacks
) {
195 return CreateForDocument(aLoadState
, aLoadInfo
, aLoadFlags
,
196 aNotificationCallbacks
, 0, false, false);
199 NS_IMETHODIMP
DocumentChannel::SetCanceledReason(const nsACString
& aReason
) {
200 return SetCanceledReasonImpl(aReason
);
203 NS_IMETHODIMP
DocumentChannel::GetCanceledReason(nsACString
& aReason
) {
204 return GetCanceledReasonImpl(aReason
);
207 NS_IMETHODIMP
DocumentChannel::CancelWithReason(nsresult aStatus
,
208 const nsACString
& aReason
) {
209 return CancelWithReasonImpl(aStatus
, aReason
);
213 DocumentChannel::Cancel(nsresult aStatusCode
) {
214 MOZ_CRASH("If we get here, something is broken");
215 return NS_ERROR_NOT_IMPLEMENTED
;
219 DocumentChannel::Suspend() {
220 MOZ_CRASH("If we get here, something is broken");
221 return NS_ERROR_NOT_IMPLEMENTED
;
225 DocumentChannel::Resume() {
226 MOZ_CRASH("If we get here, something is broken");
227 return NS_ERROR_NOT_IMPLEMENTED
;
230 //-----------------------------------------------------------------------------
231 // Remainder of nsIRequest/nsIChannel.
232 //-----------------------------------------------------------------------------
234 NS_IMETHODIMP
DocumentChannel::GetNotificationCallbacks(
235 nsIInterfaceRequestor
** aCallbacks
) {
236 nsCOMPtr
<nsIInterfaceRequestor
> callbacks(mCallbacks
);
237 callbacks
.forget(aCallbacks
);
241 NS_IMETHODIMP
DocumentChannel::SetNotificationCallbacks(
242 nsIInterfaceRequestor
* aNotificationCallbacks
) {
243 mCallbacks
= aNotificationCallbacks
;
247 NS_IMETHODIMP
DocumentChannel::GetLoadGroup(nsILoadGroup
** aLoadGroup
) {
248 nsCOMPtr
<nsILoadGroup
> loadGroup(mLoadGroup
);
249 loadGroup
.forget(aLoadGroup
);
253 NS_IMETHODIMP
DocumentChannel::SetLoadGroup(nsILoadGroup
* aLoadGroup
) {
254 mLoadGroup
= aLoadGroup
;
258 NS_IMETHODIMP
DocumentChannel::GetStatus(nsresult
* aStatus
) {
263 NS_IMETHODIMP
DocumentChannel::GetName(nsACString
& aResult
) {
269 nsresult rv
= mURI
->GetSpec(spec
);
270 NS_ENSURE_SUCCESS(rv
, rv
);
272 aResult
.AssignLiteral("documentchannel:");
273 aResult
.Append(spec
);
277 NS_IMETHODIMP
DocumentChannel::IsPending(bool* aResult
) {
278 *aResult
= mIsPending
;
282 NS_IMETHODIMP
DocumentChannel::GetLoadFlags(nsLoadFlags
* aLoadFlags
) {
283 *aLoadFlags
= mLoadFlags
;
288 DocumentChannel::GetTRRMode(nsIRequest::TRRMode
* aTRRMode
) {
289 return GetTRRModeImpl(aTRRMode
);
293 DocumentChannel::SetTRRMode(nsIRequest::TRRMode aTRRMode
) {
294 return SetTRRModeImpl(aTRRMode
);
297 NS_IMETHODIMP
DocumentChannel::SetLoadFlags(nsLoadFlags aLoadFlags
) {
298 nsLoadFlags mayChange
= 0;
299 if (mLoadInfo
->GetExternalContentPolicyType() ==
300 ExtContentPolicy::TYPE_OBJECT
) {
301 // Setting load flags for TYPE_OBJECT is OK, so long as the channel to
302 // parent isn't opened yet, or we're only setting the `LOAD_DOCUMENT_URI`
304 mayChange
= mWasOpened
? LOAD_DOCUMENT_URI
: ~0u;
305 } else if (!mWasOpened
) {
306 // If we haven't been opened yet, allow the LoadGroup to
307 // set cache control flags inherited from the default channel.
308 mayChange
= nsLoadGroup::kInheritedLoadFlags
;
311 // Check if we're allowed to adjust these flags.
312 if ((mLoadFlags
& ~mayChange
) == (aLoadFlags
& ~mayChange
)) {
313 mLoadFlags
= aLoadFlags
;
316 MOZ_CRASH_UNSAFE_PRINTF(
317 "DocumentChannel::SetLoadFlags: Don't set flags after creation "
318 "(differing flags %x != %x)",
319 (mLoadFlags
^ aLoadFlags
) & mLoadFlags
,
320 (mLoadFlags
^ aLoadFlags
) & aLoadFlags
);
324 NS_IMETHODIMP
DocumentChannel::GetOriginalURI(nsIURI
** aOriginalURI
) {
325 nsCOMPtr
<nsIURI
> originalURI
=
326 mLoadState
->OriginalURI() ? mLoadState
->OriginalURI() : mLoadState
->URI();
327 originalURI
.forget(aOriginalURI
);
331 NS_IMETHODIMP
DocumentChannel::SetOriginalURI(nsIURI
* aOriginalURI
) {
332 MOZ_CRASH("If we get here, something is broken");
333 return NS_ERROR_NOT_IMPLEMENTED
;
336 NS_IMETHODIMP
DocumentChannel::GetURI(nsIURI
** aURI
) {
337 nsCOMPtr
<nsIURI
> uri(mURI
);
342 NS_IMETHODIMP
DocumentChannel::GetOwner(nsISupports
** aOwner
) {
343 nsCOMPtr
<nsISupports
> owner(mOwner
);
344 owner
.forget(aOwner
);
348 NS_IMETHODIMP
DocumentChannel::SetOwner(nsISupports
* aOwner
) {
353 NS_IMETHODIMP
DocumentChannel::GetSecurityInfo(
354 nsITransportSecurityInfo
** aSecurityInfo
) {
355 *aSecurityInfo
= nullptr;
359 NS_IMETHODIMP
DocumentChannel::GetContentType(nsACString
& aContentType
) {
360 // We may be trying to load HTML object data, and have determined that we're
361 // going to be performing a document load. In that case, fake the "text/html"
362 // content type for nsObjectLoadingContent.
363 if ((mLoadFlags
& nsIRequest::LOAD_HTML_OBJECT_DATA
) &&
364 (mLoadFlags
& nsIChannel::LOAD_DOCUMENT_URI
)) {
365 aContentType
= TEXT_HTML
;
369 NS_ERROR("If we get here, something is broken");
370 return NS_ERROR_NOT_IMPLEMENTED
;
373 NS_IMETHODIMP
DocumentChannel::SetContentType(const nsACString
& aContentType
) {
374 MOZ_CRASH("If we get here, something is broken");
375 return NS_ERROR_NOT_IMPLEMENTED
;
378 NS_IMETHODIMP
DocumentChannel::GetContentCharset(nsACString
& aContentCharset
) {
379 MOZ_CRASH("If we get here, something is broken");
380 return NS_ERROR_NOT_IMPLEMENTED
;
383 NS_IMETHODIMP
DocumentChannel::SetContentCharset(
384 const nsACString
& aContentCharset
) {
385 MOZ_CRASH("If we get here, something is broken");
386 return NS_ERROR_NOT_IMPLEMENTED
;
389 NS_IMETHODIMP
DocumentChannel::GetContentLength(int64_t* aContentLength
) {
390 MOZ_CRASH("If we get here, something is broken");
391 return NS_ERROR_NOT_IMPLEMENTED
;
394 NS_IMETHODIMP
DocumentChannel::SetContentLength(int64_t aContentLength
) {
395 MOZ_CRASH("If we get here, something is broken");
396 return NS_ERROR_NOT_IMPLEMENTED
;
399 NS_IMETHODIMP
DocumentChannel::Open(nsIInputStream
** aStream
) {
400 MOZ_CRASH("If we get here, something is broken");
401 return NS_ERROR_NOT_IMPLEMENTED
;
404 NS_IMETHODIMP
DocumentChannel::GetContentDisposition(
405 uint32_t* aContentDisposition
) {
406 MOZ_CRASH("If we get here, something is broken");
407 return NS_ERROR_NOT_IMPLEMENTED
;
410 NS_IMETHODIMP
DocumentChannel::SetContentDisposition(
411 uint32_t aContentDisposition
) {
412 MOZ_CRASH("If we get here, something is broken");
413 return NS_ERROR_NOT_IMPLEMENTED
;
416 NS_IMETHODIMP
DocumentChannel::GetContentDispositionFilename(
417 nsAString
& aContentDispositionFilename
) {
418 MOZ_CRASH("If we get here, something will be broken");
419 return NS_ERROR_NOT_IMPLEMENTED
;
422 NS_IMETHODIMP
DocumentChannel::SetContentDispositionFilename(
423 const nsAString
& aContentDispositionFilename
) {
424 MOZ_CRASH("If we get here, something will be broken");
425 return NS_ERROR_NOT_IMPLEMENTED
;
428 NS_IMETHODIMP
DocumentChannel::GetContentDispositionHeader(
429 nsACString
& aContentDispositionHeader
) {
430 MOZ_CRASH("If we get here, something is broken");
431 return NS_ERROR_NOT_IMPLEMENTED
;
434 NS_IMETHODIMP
DocumentChannel::GetLoadInfo(nsILoadInfo
** aLoadInfo
) {
435 nsCOMPtr
<nsILoadInfo
> loadInfo(mLoadInfo
);
436 loadInfo
.forget(aLoadInfo
);
440 NS_IMETHODIMP
DocumentChannel::SetLoadInfo(nsILoadInfo
* aLoadInfo
) {
441 MOZ_CRASH("If we get here, something is broken");
442 return NS_ERROR_NOT_IMPLEMENTED
;
445 NS_IMETHODIMP
DocumentChannel::GetIsDocument(bool* aIsDocument
) {
446 return NS_GetIsDocumentChannel(this, aIsDocument
);
449 NS_IMETHODIMP
DocumentChannel::GetCanceled(bool* aCanceled
) {
450 *aCanceled
= mCanceled
;
454 //-----------------------------------------------------------------------------
456 //-----------------------------------------------------------------------------
459 DocumentChannel::GetChannelId(uint64_t* aChannelId
) {
460 *aChannelId
= mChannelId
;
465 DocumentChannel::SetChannelId(uint64_t aChannelId
) {
466 mChannelId
= aChannelId
;
470 //-----------------------------------------------------------------------------
472 //-----------------------------------------------------------------------------
474 uint64_t InnerWindowIDForExtantDoc(nsDocShell
* docShell
) {
479 Document
* doc
= docShell
->GetExtantDocument();
484 return doc
->InnerWindowID();
488 } // namespace mozilla