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
,
70 bool aUriModified
, bool aIsXFOError
)
71 : mLoadState(aLoadState
),
73 mLoadFlags(aLoadFlags
),
74 mURI(aLoadState
->URI()),
76 mUriModified(aUriModified
),
77 mIsXFOError(aIsXFOError
) {
78 LOG(("DocumentChannel ctor [this=%p, uri=%s]", this,
79 aLoadState
->URI()->GetSpecOrDefault().get()));
80 RefPtr
<nsHttpHandler
> handler
= nsHttpHandler::GetInstance();
82 Unused
<< handler
->NewChannelId(channelId
);
83 mChannelId
= channelId
;
87 DocumentChannel::AsyncOpen(nsIStreamListener
* aListener
) {
88 MOZ_CRASH("If we get here, something is broken");
89 return NS_ERROR_NOT_IMPLEMENTED
;
92 void DocumentChannel::ShutdownListeners(nsresult aStatusCode
) {
93 LOG(("DocumentChannel ShutdownListeners [this=%p, status=%" PRIx32
"]", this,
94 static_cast<uint32_t>(aStatusCode
)));
95 mStatus
= aStatusCode
;
97 nsCOMPtr
<nsIStreamListener
> listener
= mListener
;
99 listener
->OnStartRequest(this);
104 listener
= mListener
; // it might have changed!
105 nsCOMPtr
<nsILoadGroup
> loadGroup
= mLoadGroup
;
108 mLoadGroup
= nullptr;
109 mCallbacks
= nullptr;
111 NS_DispatchToMainThread(NS_NewRunnableFunction(
112 "DocumentChannel::ShutdownListeners", [=, self
= RefPtr
{this}] {
114 listener
->OnStopRequest(self
, aStatusCode
);
118 loadGroup
->RemoveRequest(self
, nullptr, aStatusCode
);
125 void DocumentChannel::DisconnectChildListeners(
126 const nsresult
& aStatus
, const nsresult
& aLoadGroupStatus
) {
127 MOZ_ASSERT(NS_FAILED(aStatus
));
128 mStatus
= aLoadGroupStatus
;
129 // Make sure we remove from the load group before
130 // setting mStatus, as existing tests expect the
131 // status to be successful when we disconnect.
133 mLoadGroup
->RemoveRequest(this, nullptr, aStatus
);
134 mLoadGroup
= nullptr;
137 ShutdownListeners(aStatus
);
140 nsDocShell
* DocumentChannel::GetDocShell() {
141 nsCOMPtr
<nsILoadContext
> loadContext
;
142 NS_QueryNotificationCallbacks(this, loadContext
);
146 nsCOMPtr
<mozIDOMWindowProxy
> domWindow
;
147 loadContext
->GetAssociatedWindow(getter_AddRefs(domWindow
));
151 auto* pDomWindow
= nsPIDOMWindowOuter::From(domWindow
);
152 nsIDocShell
* docshell
= pDomWindow
->GetDocShell();
153 return nsDocShell::Cast(docshell
);
156 static bool URIUsesDocChannel(nsIURI
* aURI
) {
157 if (SchemeIsJavascript(aURI
)) {
161 nsCString spec
= aURI
->GetSpecOrDefault();
162 return !spec
.EqualsLiteral("about:crashcontent");
165 bool DocumentChannel::CanUseDocumentChannel(nsIURI
* aURI
) {
166 // We want to use DocumentChannel if we're using a supported scheme.
167 return URIUsesDocChannel(aURI
);
171 already_AddRefed
<DocumentChannel
> DocumentChannel::CreateForDocument(
172 nsDocShellLoadState
* aLoadState
, class LoadInfo
* aLoadInfo
,
173 nsLoadFlags aLoadFlags
, nsIInterfaceRequestor
* aNotificationCallbacks
,
174 uint32_t aCacheKey
, bool aUriModified
, bool aIsXFOError
) {
175 RefPtr
<DocumentChannel
> channel
;
176 if (XRE_IsContentProcess()) {
177 channel
= new DocumentChannelChild(aLoadState
, aLoadInfo
, aLoadFlags
,
178 aCacheKey
, aUriModified
, aIsXFOError
);
181 new ParentProcessDocumentChannel(aLoadState
, aLoadInfo
, aLoadFlags
,
182 aCacheKey
, aUriModified
, aIsXFOError
);
184 channel
->SetNotificationCallbacks(aNotificationCallbacks
);
185 return channel
.forget();
189 already_AddRefed
<DocumentChannel
> DocumentChannel::CreateForObject(
190 nsDocShellLoadState
* aLoadState
, class LoadInfo
* aLoadInfo
,
191 nsLoadFlags aLoadFlags
, nsIInterfaceRequestor
* aNotificationCallbacks
) {
192 return CreateForDocument(aLoadState
, aLoadInfo
, aLoadFlags
,
193 aNotificationCallbacks
, 0, false, false);
196 NS_IMETHODIMP
DocumentChannel::SetCanceledReason(const nsACString
& aReason
) {
197 return SetCanceledReasonImpl(aReason
);
200 NS_IMETHODIMP
DocumentChannel::GetCanceledReason(nsACString
& aReason
) {
201 return GetCanceledReasonImpl(aReason
);
204 NS_IMETHODIMP
DocumentChannel::CancelWithReason(nsresult aStatus
,
205 const nsACString
& aReason
) {
206 return CancelWithReasonImpl(aStatus
, aReason
);
210 DocumentChannel::Cancel(nsresult aStatusCode
) {
211 MOZ_CRASH("If we get here, something is broken");
212 return NS_ERROR_NOT_IMPLEMENTED
;
216 DocumentChannel::Suspend() {
217 MOZ_CRASH("If we get here, something is broken");
218 return NS_ERROR_NOT_IMPLEMENTED
;
222 DocumentChannel::Resume() {
223 MOZ_CRASH("If we get here, something is broken");
224 return NS_ERROR_NOT_IMPLEMENTED
;
227 //-----------------------------------------------------------------------------
228 // Remainder of nsIRequest/nsIChannel.
229 //-----------------------------------------------------------------------------
231 NS_IMETHODIMP
DocumentChannel::GetNotificationCallbacks(
232 nsIInterfaceRequestor
** aCallbacks
) {
233 nsCOMPtr
<nsIInterfaceRequestor
> callbacks(mCallbacks
);
234 callbacks
.forget(aCallbacks
);
238 NS_IMETHODIMP
DocumentChannel::SetNotificationCallbacks(
239 nsIInterfaceRequestor
* aNotificationCallbacks
) {
240 mCallbacks
= aNotificationCallbacks
;
244 NS_IMETHODIMP
DocumentChannel::GetLoadGroup(nsILoadGroup
** aLoadGroup
) {
245 nsCOMPtr
<nsILoadGroup
> loadGroup(mLoadGroup
);
246 loadGroup
.forget(aLoadGroup
);
250 NS_IMETHODIMP
DocumentChannel::SetLoadGroup(nsILoadGroup
* aLoadGroup
) {
251 mLoadGroup
= aLoadGroup
;
255 NS_IMETHODIMP
DocumentChannel::GetStatus(nsresult
* aStatus
) {
260 NS_IMETHODIMP
DocumentChannel::GetName(nsACString
& aResult
) {
266 nsresult rv
= mURI
->GetSpec(spec
);
267 NS_ENSURE_SUCCESS(rv
, rv
);
269 aResult
.AssignLiteral("documentchannel:");
270 aResult
.Append(spec
);
274 NS_IMETHODIMP
DocumentChannel::IsPending(bool* aResult
) {
275 *aResult
= mIsPending
;
279 NS_IMETHODIMP
DocumentChannel::GetLoadFlags(nsLoadFlags
* aLoadFlags
) {
280 *aLoadFlags
= mLoadFlags
;
285 DocumentChannel::GetTRRMode(nsIRequest::TRRMode
* aTRRMode
) {
286 return GetTRRModeImpl(aTRRMode
);
290 DocumentChannel::SetTRRMode(nsIRequest::TRRMode aTRRMode
) {
291 return SetTRRModeImpl(aTRRMode
);
294 NS_IMETHODIMP
DocumentChannel::SetLoadFlags(nsLoadFlags aLoadFlags
) {
295 // Setting load flags for TYPE_OBJECT is OK, so long as the channel to parent
296 // isn't opened yet, or we're only setting the `LOAD_DOCUMENT_URI` flag.
297 auto contentPolicy
= mLoadInfo
->GetExternalContentPolicyType();
298 if (contentPolicy
== ExtContentPolicy::TYPE_OBJECT
) {
300 MOZ_DIAGNOSTIC_ASSERT(
301 aLoadFlags
== (mLoadFlags
| nsIChannel::LOAD_DOCUMENT_URI
),
302 "After the channel has been opened, can only set the "
303 "`LOAD_DOCUMENT_URI` flag.");
305 mLoadFlags
= aLoadFlags
;
309 MOZ_CRASH_UNSAFE_PRINTF(
310 "DocumentChannel::SetLoadFlags: Don't set flags after creation "
311 "(differing flags %x != %x)",
312 (mLoadFlags
^ aLoadFlags
) & mLoadFlags
,
313 (mLoadFlags
^ aLoadFlags
) & aLoadFlags
);
316 NS_IMETHODIMP
DocumentChannel::GetOriginalURI(nsIURI
** aOriginalURI
) {
317 nsCOMPtr
<nsIURI
> originalURI
=
318 mLoadState
->OriginalURI() ? mLoadState
->OriginalURI() : mLoadState
->URI();
319 originalURI
.forget(aOriginalURI
);
323 NS_IMETHODIMP
DocumentChannel::SetOriginalURI(nsIURI
* aOriginalURI
) {
324 MOZ_CRASH("If we get here, something is broken");
325 return NS_ERROR_NOT_IMPLEMENTED
;
328 NS_IMETHODIMP
DocumentChannel::GetURI(nsIURI
** aURI
) {
329 nsCOMPtr
<nsIURI
> uri(mURI
);
334 NS_IMETHODIMP
DocumentChannel::GetOwner(nsISupports
** aOwner
) {
335 nsCOMPtr
<nsISupports
> owner(mOwner
);
336 owner
.forget(aOwner
);
340 NS_IMETHODIMP
DocumentChannel::SetOwner(nsISupports
* aOwner
) {
345 NS_IMETHODIMP
DocumentChannel::GetSecurityInfo(
346 nsITransportSecurityInfo
** aSecurityInfo
) {
347 *aSecurityInfo
= nullptr;
351 NS_IMETHODIMP
DocumentChannel::GetContentType(nsACString
& aContentType
) {
352 // We may be trying to load HTML object data, and have determined that we're
353 // going to be performing a document load. In that case, fake the "text/html"
354 // content type for nsObjectLoadingContent.
355 if ((mLoadFlags
& nsIRequest::LOAD_HTML_OBJECT_DATA
) &&
356 (mLoadFlags
& nsIChannel::LOAD_DOCUMENT_URI
)) {
357 aContentType
= TEXT_HTML
;
361 NS_ERROR("If we get here, something is broken");
362 return NS_ERROR_NOT_IMPLEMENTED
;
365 NS_IMETHODIMP
DocumentChannel::SetContentType(const nsACString
& aContentType
) {
366 MOZ_CRASH("If we get here, something is broken");
367 return NS_ERROR_NOT_IMPLEMENTED
;
370 NS_IMETHODIMP
DocumentChannel::GetContentCharset(nsACString
& aContentCharset
) {
371 MOZ_CRASH("If we get here, something is broken");
372 return NS_ERROR_NOT_IMPLEMENTED
;
375 NS_IMETHODIMP
DocumentChannel::SetContentCharset(
376 const nsACString
& aContentCharset
) {
377 MOZ_CRASH("If we get here, something is broken");
378 return NS_ERROR_NOT_IMPLEMENTED
;
381 NS_IMETHODIMP
DocumentChannel::GetContentLength(int64_t* aContentLength
) {
382 MOZ_CRASH("If we get here, something is broken");
383 return NS_ERROR_NOT_IMPLEMENTED
;
386 NS_IMETHODIMP
DocumentChannel::SetContentLength(int64_t aContentLength
) {
387 MOZ_CRASH("If we get here, something is broken");
388 return NS_ERROR_NOT_IMPLEMENTED
;
391 NS_IMETHODIMP
DocumentChannel::Open(nsIInputStream
** aStream
) {
392 MOZ_CRASH("If we get here, something is broken");
393 return NS_ERROR_NOT_IMPLEMENTED
;
396 NS_IMETHODIMP
DocumentChannel::GetContentDisposition(
397 uint32_t* aContentDisposition
) {
398 MOZ_CRASH("If we get here, something is broken");
399 return NS_ERROR_NOT_IMPLEMENTED
;
402 NS_IMETHODIMP
DocumentChannel::SetContentDisposition(
403 uint32_t aContentDisposition
) {
404 MOZ_CRASH("If we get here, something is broken");
405 return NS_ERROR_NOT_IMPLEMENTED
;
408 NS_IMETHODIMP
DocumentChannel::GetContentDispositionFilename(
409 nsAString
& aContentDispositionFilename
) {
410 MOZ_CRASH("If we get here, something will be broken");
411 return NS_ERROR_NOT_IMPLEMENTED
;
414 NS_IMETHODIMP
DocumentChannel::SetContentDispositionFilename(
415 const nsAString
& aContentDispositionFilename
) {
416 MOZ_CRASH("If we get here, something will be broken");
417 return NS_ERROR_NOT_IMPLEMENTED
;
420 NS_IMETHODIMP
DocumentChannel::GetContentDispositionHeader(
421 nsACString
& aContentDispositionHeader
) {
422 MOZ_CRASH("If we get here, something is broken");
423 return NS_ERROR_NOT_IMPLEMENTED
;
426 NS_IMETHODIMP
DocumentChannel::GetLoadInfo(nsILoadInfo
** aLoadInfo
) {
427 nsCOMPtr
<nsILoadInfo
> loadInfo(mLoadInfo
);
428 loadInfo
.forget(aLoadInfo
);
432 NS_IMETHODIMP
DocumentChannel::SetLoadInfo(nsILoadInfo
* aLoadInfo
) {
433 MOZ_CRASH("If we get here, something is broken");
434 return NS_ERROR_NOT_IMPLEMENTED
;
437 NS_IMETHODIMP
DocumentChannel::GetIsDocument(bool* aIsDocument
) {
438 return NS_GetIsDocumentChannel(this, aIsDocument
);
441 NS_IMETHODIMP
DocumentChannel::GetCanceled(bool* aCanceled
) {
442 *aCanceled
= mCanceled
;
446 //-----------------------------------------------------------------------------
448 //-----------------------------------------------------------------------------
451 DocumentChannel::GetChannelId(uint64_t* aChannelId
) {
452 *aChannelId
= mChannelId
;
457 DocumentChannel::SetChannelId(uint64_t aChannelId
) {
458 mChannelId
= aChannelId
;
462 //-----------------------------------------------------------------------------
464 //-----------------------------------------------------------------------------
466 uint64_t InnerWindowIDForExtantDoc(nsDocShell
* docShell
) {
471 Document
* doc
= docShell
->GetExtantDocument();
476 return doc
->InnerWindowID();
480 } // namespace mozilla