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 : mAsyncOpenTime(TimeStamp::Now()),
72 mLoadState(aLoadState
),
74 mLoadFlags(aLoadFlags
),
75 mURI(aLoadState
->URI()),
77 mUriModified(aUriModified
),
78 mIsXFOError(aIsXFOError
) {
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 // Changes here should also be made in
158 // E10SUtils.documentChannelPermittedForURI().
159 static bool URIUsesDocChannel(nsIURI
* aURI
) {
160 if (SchemeIsJavascript(aURI
)) {
164 nsCString spec
= aURI
->GetSpecOrDefault();
165 return !spec
.EqualsLiteral("about:printpreview") &&
166 !spec
.EqualsLiteral("about:crashcontent");
169 bool DocumentChannel::CanUseDocumentChannel(nsIURI
* aURI
) {
170 // We want to use DocumentChannel if we're using a supported scheme.
171 return URIUsesDocChannel(aURI
);
175 already_AddRefed
<DocumentChannel
> DocumentChannel::CreateForDocument(
176 nsDocShellLoadState
* aLoadState
, class LoadInfo
* aLoadInfo
,
177 nsLoadFlags aLoadFlags
, nsIInterfaceRequestor
* aNotificationCallbacks
,
178 uint32_t aCacheKey
, bool aUriModified
, bool aIsXFOError
) {
179 RefPtr
<DocumentChannel
> channel
;
180 if (XRE_IsContentProcess()) {
181 channel
= new DocumentChannelChild(aLoadState
, aLoadInfo
, aLoadFlags
,
182 aCacheKey
, aUriModified
, aIsXFOError
);
185 new ParentProcessDocumentChannel(aLoadState
, aLoadInfo
, aLoadFlags
,
186 aCacheKey
, aUriModified
, aIsXFOError
);
188 channel
->SetNotificationCallbacks(aNotificationCallbacks
);
189 return channel
.forget();
193 already_AddRefed
<DocumentChannel
> DocumentChannel::CreateForObject(
194 nsDocShellLoadState
* aLoadState
, class LoadInfo
* aLoadInfo
,
195 nsLoadFlags aLoadFlags
, nsIInterfaceRequestor
* aNotificationCallbacks
) {
196 return CreateForDocument(aLoadState
, aLoadInfo
, aLoadFlags
,
197 aNotificationCallbacks
, 0, false, false);
201 DocumentChannel::Cancel(nsresult aStatusCode
) {
202 MOZ_CRASH("If we get here, something is broken");
203 return NS_ERROR_NOT_IMPLEMENTED
;
207 DocumentChannel::Suspend() {
208 MOZ_CRASH("If we get here, something is broken");
209 return NS_ERROR_NOT_IMPLEMENTED
;
213 DocumentChannel::Resume() {
214 MOZ_CRASH("If we get here, something is broken");
215 return NS_ERROR_NOT_IMPLEMENTED
;
218 //-----------------------------------------------------------------------------
219 // Remainder of nsIRequest/nsIChannel.
220 //-----------------------------------------------------------------------------
222 NS_IMETHODIMP
DocumentChannel::GetNotificationCallbacks(
223 nsIInterfaceRequestor
** aCallbacks
) {
224 nsCOMPtr
<nsIInterfaceRequestor
> callbacks(mCallbacks
);
225 callbacks
.forget(aCallbacks
);
229 NS_IMETHODIMP
DocumentChannel::SetNotificationCallbacks(
230 nsIInterfaceRequestor
* aNotificationCallbacks
) {
231 mCallbacks
= aNotificationCallbacks
;
235 NS_IMETHODIMP
DocumentChannel::GetLoadGroup(nsILoadGroup
** aLoadGroup
) {
236 nsCOMPtr
<nsILoadGroup
> loadGroup(mLoadGroup
);
237 loadGroup
.forget(aLoadGroup
);
241 NS_IMETHODIMP
DocumentChannel::SetLoadGroup(nsILoadGroup
* aLoadGroup
) {
242 mLoadGroup
= aLoadGroup
;
246 NS_IMETHODIMP
DocumentChannel::GetStatus(nsresult
* aStatus
) {
251 NS_IMETHODIMP
DocumentChannel::GetName(nsACString
& aResult
) {
257 nsresult rv
= mURI
->GetSpec(spec
);
258 NS_ENSURE_SUCCESS(rv
, rv
);
260 aResult
.AssignLiteral("documentchannel:");
261 aResult
.Append(spec
);
265 NS_IMETHODIMP
DocumentChannel::IsPending(bool* aResult
) {
266 *aResult
= mIsPending
;
270 NS_IMETHODIMP
DocumentChannel::GetLoadFlags(nsLoadFlags
* aLoadFlags
) {
271 *aLoadFlags
= mLoadFlags
;
276 DocumentChannel::GetTRRMode(nsIRequest::TRRMode
* aTRRMode
) {
277 return GetTRRModeImpl(aTRRMode
);
281 DocumentChannel::SetTRRMode(nsIRequest::TRRMode aTRRMode
) {
282 return SetTRRModeImpl(aTRRMode
);
285 NS_IMETHODIMP
DocumentChannel::SetLoadFlags(nsLoadFlags aLoadFlags
) {
286 // Setting load flags for TYPE_OBJECT is OK, so long as the channel to parent
287 // isn't opened yet, or we're only setting the `LOAD_DOCUMENT_URI` flag.
288 auto contentPolicy
= mLoadInfo
->GetExternalContentPolicyType();
289 if (contentPolicy
== ExtContentPolicy::TYPE_OBJECT
) {
291 MOZ_DIAGNOSTIC_ASSERT(
292 aLoadFlags
== (mLoadFlags
| nsIChannel::LOAD_DOCUMENT_URI
),
293 "After the channel has been opened, can only set the "
294 "`LOAD_DOCUMENT_URI` flag.");
296 mLoadFlags
= aLoadFlags
;
300 MOZ_CRASH("DocumentChannel::SetLoadFlags: Don't set flags after creation");
303 NS_IMETHODIMP
DocumentChannel::GetOriginalURI(nsIURI
** aOriginalURI
) {
304 nsCOMPtr
<nsIURI
> originalURI
=
305 mLoadState
->OriginalURI() ? mLoadState
->OriginalURI() : mLoadState
->URI();
306 originalURI
.forget(aOriginalURI
);
310 NS_IMETHODIMP
DocumentChannel::SetOriginalURI(nsIURI
* aOriginalURI
) {
311 MOZ_CRASH("If we get here, something is broken");
312 return NS_ERROR_NOT_IMPLEMENTED
;
315 NS_IMETHODIMP
DocumentChannel::GetURI(nsIURI
** aURI
) {
316 nsCOMPtr
<nsIURI
> uri(mURI
);
321 NS_IMETHODIMP
DocumentChannel::GetOwner(nsISupports
** aOwner
) {
322 nsCOMPtr
<nsISupports
> owner(mOwner
);
323 owner
.forget(aOwner
);
327 NS_IMETHODIMP
DocumentChannel::SetOwner(nsISupports
* aOwner
) {
332 NS_IMETHODIMP
DocumentChannel::GetSecurityInfo(nsISupports
** aSecurityInfo
) {
333 *aSecurityInfo
= nullptr;
337 NS_IMETHODIMP
DocumentChannel::GetContentType(nsACString
& aContentType
) {
338 // We may be trying to load HTML object data, and have determined that we're
339 // going to be performing a document load. In that case, fake the "text/html"
340 // content type for nsObjectLoadingContent.
341 if ((mLoadFlags
& nsIRequest::LOAD_HTML_OBJECT_DATA
) &&
342 (mLoadFlags
& nsIChannel::LOAD_DOCUMENT_URI
)) {
343 aContentType
= TEXT_HTML
;
347 NS_ERROR("If we get here, something is broken");
348 return NS_ERROR_NOT_IMPLEMENTED
;
351 NS_IMETHODIMP
DocumentChannel::SetContentType(const nsACString
& aContentType
) {
352 MOZ_CRASH("If we get here, something is broken");
353 return NS_ERROR_NOT_IMPLEMENTED
;
356 NS_IMETHODIMP
DocumentChannel::GetContentCharset(nsACString
& aContentCharset
) {
357 MOZ_CRASH("If we get here, something is broken");
358 return NS_ERROR_NOT_IMPLEMENTED
;
361 NS_IMETHODIMP
DocumentChannel::SetContentCharset(
362 const nsACString
& aContentCharset
) {
363 MOZ_CRASH("If we get here, something is broken");
364 return NS_ERROR_NOT_IMPLEMENTED
;
367 NS_IMETHODIMP
DocumentChannel::GetContentLength(int64_t* aContentLength
) {
368 MOZ_CRASH("If we get here, something is broken");
369 return NS_ERROR_NOT_IMPLEMENTED
;
372 NS_IMETHODIMP
DocumentChannel::SetContentLength(int64_t aContentLength
) {
373 MOZ_CRASH("If we get here, something is broken");
374 return NS_ERROR_NOT_IMPLEMENTED
;
377 NS_IMETHODIMP
DocumentChannel::Open(nsIInputStream
** aStream
) {
378 MOZ_CRASH("If we get here, something is broken");
379 return NS_ERROR_NOT_IMPLEMENTED
;
382 NS_IMETHODIMP
DocumentChannel::GetContentDisposition(
383 uint32_t* aContentDisposition
) {
384 MOZ_CRASH("If we get here, something is broken");
385 return NS_ERROR_NOT_IMPLEMENTED
;
388 NS_IMETHODIMP
DocumentChannel::SetContentDisposition(
389 uint32_t aContentDisposition
) {
390 MOZ_CRASH("If we get here, something is broken");
391 return NS_ERROR_NOT_IMPLEMENTED
;
394 NS_IMETHODIMP
DocumentChannel::GetContentDispositionFilename(
395 nsAString
& aContentDispositionFilename
) {
396 MOZ_CRASH("If we get here, something will be broken");
397 return NS_ERROR_NOT_IMPLEMENTED
;
400 NS_IMETHODIMP
DocumentChannel::SetContentDispositionFilename(
401 const nsAString
& aContentDispositionFilename
) {
402 MOZ_CRASH("If we get here, something will be broken");
403 return NS_ERROR_NOT_IMPLEMENTED
;
406 NS_IMETHODIMP
DocumentChannel::GetContentDispositionHeader(
407 nsACString
& aContentDispositionHeader
) {
408 MOZ_CRASH("If we get here, something is broken");
409 return NS_ERROR_NOT_IMPLEMENTED
;
412 NS_IMETHODIMP
DocumentChannel::GetLoadInfo(nsILoadInfo
** aLoadInfo
) {
413 nsCOMPtr
<nsILoadInfo
> loadInfo(mLoadInfo
);
414 loadInfo
.forget(aLoadInfo
);
418 NS_IMETHODIMP
DocumentChannel::SetLoadInfo(nsILoadInfo
* aLoadInfo
) {
419 MOZ_CRASH("If we get here, something is broken");
420 return NS_ERROR_NOT_IMPLEMENTED
;
423 NS_IMETHODIMP
DocumentChannel::GetIsDocument(bool* aIsDocument
) {
424 return NS_GetIsDocumentChannel(this, aIsDocument
);
427 NS_IMETHODIMP
DocumentChannel::GetCanceled(bool* aCanceled
) {
428 *aCanceled
= mCanceled
;
432 //-----------------------------------------------------------------------------
434 //-----------------------------------------------------------------------------
437 DocumentChannel::GetChannelId(uint64_t* aChannelId
) {
438 *aChannelId
= mChannelId
;
443 DocumentChannel::SetChannelId(uint64_t aChannelId
) {
444 mChannelId
= aChannelId
;
448 //-----------------------------------------------------------------------------
450 //-----------------------------------------------------------------------------
452 uint64_t InnerWindowIDForExtantDoc(nsDocShell
* docShell
) {
457 Document
* doc
= docShell
->GetExtantDocument();
462 return doc
->InnerWindowID();
466 } // namespace mozilla