Merge autoland to mozilla-central. a=merge
[gecko.git] / netwerk / ipc / DocumentChannel.cpp
bloba0d6a0c1f9bde5accb39a197b0a1e25d6bb3cc33
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"
10 #include <inttypes.h>
11 #include <utility>
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"
23 #include "nsCOMPtr.h"
24 #include "nsDebug.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"
34 #include "nsIURI.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"
42 #include "nscore.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)
50 namespace mozilla {
51 namespace net {
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)
65 NS_INTERFACE_MAP_END
67 DocumentChannel::DocumentChannel(nsDocShellLoadState* aLoadState,
68 net::LoadInfo* aLoadInfo,
69 nsLoadFlags aLoadFlags, uint32_t aCacheKey,
70 bool aUriModified,
71 bool aIsEmbeddingBlockedError)
72 : mLoadState(aLoadState),
73 mCacheKey(aCacheKey),
74 mLoadFlags(aLoadFlags),
75 mURI(aLoadState->URI()),
76 mLoadInfo(aLoadInfo),
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();
82 uint64_t channelId;
83 Unused << handler->NewChannelId(channelId);
84 mChannelId = channelId;
87 NS_IMETHODIMP
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;
99 if (listener) {
100 listener->OnStartRequest(this);
103 mIsPending = false;
105 listener = mListener; // it might have changed!
106 nsCOMPtr<nsILoadGroup> loadGroup = mLoadGroup;
108 mListener = nullptr;
109 mLoadGroup = nullptr;
110 mCallbacks = nullptr;
112 NS_DispatchToMainThread(NS_NewRunnableFunction(
113 "DocumentChannel::ShutdownListeners", [=, self = RefPtr{this}] {
114 if (listener) {
115 listener->OnStopRequest(self, aStatusCode);
118 if (loadGroup) {
119 loadGroup->RemoveRequest(self, nullptr, aStatusCode);
121 }));
123 DeleteIPDL();
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.
133 if (mLoadGroup) {
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);
144 if (!loadContext) {
145 return nullptr;
147 nsCOMPtr<mozIDOMWindowProxy> domWindow;
148 loadContext->GetAssociatedWindow(getter_AddRefs(domWindow));
149 if (!domWindow) {
150 return nullptr;
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)) {
159 return false;
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);
171 /* static */
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()) {
178 channel =
179 new DocumentChannelChild(aLoadState, aLoadInfo, aLoadFlags, aCacheKey,
180 aUriModified, aIsEmbeddingBlockedError);
181 } else {
182 channel = new ParentProcessDocumentChannel(
183 aLoadState, aLoadInfo, aLoadFlags, aCacheKey, aUriModified,
184 aIsEmbeddingBlockedError);
186 channel->SetNotificationCallbacks(aNotificationCallbacks);
187 return channel.forget();
190 /* static */
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);
211 NS_IMETHODIMP
212 DocumentChannel::Cancel(nsresult aStatusCode) {
213 MOZ_CRASH("If we get here, something is broken");
214 return NS_ERROR_NOT_IMPLEMENTED;
217 NS_IMETHODIMP
218 DocumentChannel::Suspend() {
219 MOZ_CRASH("If we get here, something is broken");
220 return NS_ERROR_NOT_IMPLEMENTED;
223 NS_IMETHODIMP
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);
237 return NS_OK;
240 NS_IMETHODIMP DocumentChannel::SetNotificationCallbacks(
241 nsIInterfaceRequestor* aNotificationCallbacks) {
242 mCallbacks = aNotificationCallbacks;
243 return NS_OK;
246 NS_IMETHODIMP DocumentChannel::GetLoadGroup(nsILoadGroup** aLoadGroup) {
247 nsCOMPtr<nsILoadGroup> loadGroup(mLoadGroup);
248 loadGroup.forget(aLoadGroup);
249 return NS_OK;
252 NS_IMETHODIMP DocumentChannel::SetLoadGroup(nsILoadGroup* aLoadGroup) {
253 mLoadGroup = aLoadGroup;
254 return NS_OK;
257 NS_IMETHODIMP DocumentChannel::GetStatus(nsresult* aStatus) {
258 *aStatus = mStatus;
259 return NS_OK;
262 NS_IMETHODIMP DocumentChannel::GetName(nsACString& aResult) {
263 if (!mURI) {
264 aResult.Truncate();
265 return NS_OK;
267 nsCString spec;
268 nsresult rv = mURI->GetSpec(spec);
269 NS_ENSURE_SUCCESS(rv, rv);
271 aResult.AssignLiteral("documentchannel:");
272 aResult.Append(spec);
273 return NS_OK;
276 NS_IMETHODIMP DocumentChannel::IsPending(bool* aResult) {
277 *aResult = mIsPending;
278 return NS_OK;
281 NS_IMETHODIMP DocumentChannel::GetLoadFlags(nsLoadFlags* aLoadFlags) {
282 *aLoadFlags = mLoadFlags;
283 return NS_OK;
286 NS_IMETHODIMP
287 DocumentChannel::GetTRRMode(nsIRequest::TRRMode* aTRRMode) {
288 return GetTRRModeImpl(aTRRMode);
291 NS_IMETHODIMP
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) {
301 if (mWasOpened) {
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;
308 return NS_OK;
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);
322 return NS_OK;
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);
332 uri.forget(aURI);
333 return NS_OK;
336 NS_IMETHODIMP DocumentChannel::GetOwner(nsISupports** aOwner) {
337 nsCOMPtr<nsISupports> owner(mOwner);
338 owner.forget(aOwner);
339 return NS_OK;
342 NS_IMETHODIMP DocumentChannel::SetOwner(nsISupports* aOwner) {
343 mOwner = aOwner;
344 return NS_OK;
347 NS_IMETHODIMP DocumentChannel::GetSecurityInfo(
348 nsITransportSecurityInfo** aSecurityInfo) {
349 *aSecurityInfo = nullptr;
350 return NS_OK;
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;
360 return NS_OK;
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);
431 return NS_OK;
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;
445 return NS_OK;
448 //-----------------------------------------------------------------------------
449 // nsIIdentChannel
450 //-----------------------------------------------------------------------------
452 NS_IMETHODIMP
453 DocumentChannel::GetChannelId(uint64_t* aChannelId) {
454 *aChannelId = mChannelId;
455 return NS_OK;
458 NS_IMETHODIMP
459 DocumentChannel::SetChannelId(uint64_t aChannelId) {
460 mChannelId = aChannelId;
461 return NS_OK;
464 //-----------------------------------------------------------------------------
465 // Helpers
466 //-----------------------------------------------------------------------------
468 uint64_t InnerWindowIDForExtantDoc(nsDocShell* docShell) {
469 if (!docShell) {
470 return 0;
473 Document* doc = docShell->GetExtantDocument();
474 if (!doc) {
475 return 0;
478 return doc->InnerWindowID();
481 } // namespace net
482 } // namespace mozilla
484 #undef LOG