Bug 1861709 replace AudioCallbackDriver::ThreadRunning() assertions that mean to...
[gecko.git] / docshell / base / nsDSURIContentListener.cpp
blob3d2d32006ea7681ba478becba17443c199340acb
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsDocShell.h"
8 #include "nsDSURIContentListener.h"
9 #include "nsIChannel.h"
10 #include "nsServiceManagerUtils.h"
11 #include "nsDocShellCID.h"
12 #include "nsIWebNavigationInfo.h"
13 #include "mozilla/dom/CanonicalBrowsingContext.h"
14 #include "mozilla/dom/Document.h"
15 #include "mozilla/dom/WindowGlobalParent.h"
16 #include "mozilla/Unused.h"
17 #include "nsError.h"
18 #include "nsContentSecurityManager.h"
19 #include "nsDocShellLoadTypes.h"
20 #include "nsIInterfaceRequestor.h"
21 #include "nsIMultiPartChannel.h"
22 #include "nsWebNavigationInfo.h"
24 using namespace mozilla;
25 using namespace mozilla::dom;
27 NS_IMPL_ADDREF(MaybeCloseWindowHelper)
28 NS_IMPL_RELEASE(MaybeCloseWindowHelper)
30 NS_INTERFACE_MAP_BEGIN(MaybeCloseWindowHelper)
31 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsITimerCallback)
32 NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
33 NS_INTERFACE_MAP_ENTRY(nsINamed)
34 NS_INTERFACE_MAP_END
36 MaybeCloseWindowHelper::MaybeCloseWindowHelper(BrowsingContext* aContentContext)
37 : mBrowsingContext(aContentContext),
38 mTimer(nullptr),
39 mShouldCloseWindow(false) {}
41 MaybeCloseWindowHelper::~MaybeCloseWindowHelper() {}
43 void MaybeCloseWindowHelper::SetShouldCloseWindow(bool aShouldCloseWindow) {
44 mShouldCloseWindow = aShouldCloseWindow;
47 BrowsingContext* MaybeCloseWindowHelper::MaybeCloseWindow() {
48 if (!mShouldCloseWindow) {
49 return mBrowsingContext;
52 // This method should not be called more than once, but it's better to avoid
53 // closing the current window again.
54 mShouldCloseWindow = false;
56 // Reset the window context to the opener window so that the dependent
57 // dialogs have a parent
58 RefPtr<BrowsingContext> newBC = ChooseNewBrowsingContext(mBrowsingContext);
60 if (newBC != mBrowsingContext && newBC && !newBC->IsDiscarded()) {
61 mBCToClose = mBrowsingContext;
62 mBrowsingContext = newBC;
64 // Now close the old window. Do it on a timer so that we don't run
65 // into issues trying to close the window before it has fully opened.
66 NS_ASSERTION(!mTimer, "mTimer was already initialized once!");
67 NS_NewTimerWithCallback(getter_AddRefs(mTimer), this, 0,
68 nsITimer::TYPE_ONE_SHOT);
71 return mBrowsingContext;
74 already_AddRefed<BrowsingContext>
75 MaybeCloseWindowHelper::ChooseNewBrowsingContext(BrowsingContext* aBC) {
76 RefPtr<BrowsingContext> opener = aBC->GetOpener();
77 if (opener && !opener->IsDiscarded()) {
78 return opener.forget();
81 if (!XRE_IsParentProcess()) {
82 return nullptr;
85 opener = BrowsingContext::Get(aBC->Canonical()->GetCrossGroupOpenerId());
86 if (!opener || opener->IsDiscarded()) {
87 return nullptr;
89 return opener.forget();
92 NS_IMETHODIMP
93 MaybeCloseWindowHelper::Notify(nsITimer* timer) {
94 NS_ASSERTION(mBCToClose, "No window to close after timer fired");
96 mBCToClose->Close(CallerType::System, IgnoreErrors());
97 mBCToClose = nullptr;
98 mTimer = nullptr;
100 return NS_OK;
103 NS_IMETHODIMP
104 MaybeCloseWindowHelper::GetName(nsACString& aName) {
105 aName.AssignLiteral("MaybeCloseWindowHelper");
106 return NS_OK;
109 nsDSURIContentListener::nsDSURIContentListener(nsDocShell* aDocShell)
110 : mDocShell(aDocShell),
111 mExistingJPEGRequest(nullptr),
112 mParentContentListener(nullptr) {}
114 nsDSURIContentListener::~nsDSURIContentListener() {}
116 NS_IMPL_ADDREF(nsDSURIContentListener)
117 NS_IMPL_RELEASE(nsDSURIContentListener)
119 NS_INTERFACE_MAP_BEGIN(nsDSURIContentListener)
120 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIURIContentListener)
121 NS_INTERFACE_MAP_ENTRY(nsIURIContentListener)
122 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
123 NS_INTERFACE_MAP_END
125 NS_IMETHODIMP
126 nsDSURIContentListener::DoContent(const nsACString& aContentType,
127 bool aIsContentPreferred,
128 nsIRequest* aRequest,
129 nsIStreamListener** aContentHandler,
130 bool* aAbortProcess) {
131 nsresult rv;
132 NS_ENSURE_ARG_POINTER(aContentHandler);
133 NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
134 RefPtr<nsDocShell> docShell = mDocShell;
136 *aAbortProcess = false;
138 // determine if the channel has just been retargeted to us...
139 nsLoadFlags loadFlags = 0;
140 if (nsCOMPtr<nsIChannel> openedChannel = do_QueryInterface(aRequest)) {
141 openedChannel->GetLoadFlags(&loadFlags);
144 if (loadFlags & nsIChannel::LOAD_RETARGETED_DOCUMENT_URI) {
145 // XXX: Why does this not stop the content too?
146 docShell->Stop(nsIWebNavigation::STOP_NETWORK);
147 NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
148 docShell->SetLoadType(aIsContentPreferred ? LOAD_LINK : LOAD_NORMAL);
151 // In case of multipart jpeg request (mjpeg) we don't really want to
152 // create new viewer since the one we already have is capable of
153 // rendering multipart jpeg correctly (see bug 625012)
154 nsCOMPtr<nsIChannel> baseChannel;
155 if (nsCOMPtr<nsIMultiPartChannel> mpchan = do_QueryInterface(aRequest)) {
156 mpchan->GetBaseChannel(getter_AddRefs(baseChannel));
159 bool reuseCV = baseChannel && baseChannel == mExistingJPEGRequest &&
160 aContentType.EqualsLiteral("image/jpeg");
162 if (mExistingJPEGStreamListener && reuseCV) {
163 RefPtr<nsIStreamListener> copy(mExistingJPEGStreamListener);
164 copy.forget(aContentHandler);
165 rv = NS_OK;
166 } else {
167 rv = docShell->CreateContentViewer(aContentType, aRequest, aContentHandler);
168 if (NS_SUCCEEDED(rv) && reuseCV) {
169 mExistingJPEGStreamListener = *aContentHandler;
170 } else {
171 mExistingJPEGStreamListener = nullptr;
173 mExistingJPEGRequest = baseChannel;
176 if (rv == NS_ERROR_DOCSHELL_DYING) {
177 aRequest->Cancel(rv);
178 *aAbortProcess = true;
179 return NS_OK;
182 if (NS_FAILED(rv)) {
183 // we don't know how to handle the content
184 nsCOMPtr<nsIStreamListener> forget = dont_AddRef(*aContentHandler);
185 *aContentHandler = nullptr;
186 return rv;
189 if (loadFlags & nsIChannel::LOAD_RETARGETED_DOCUMENT_URI) {
190 nsCOMPtr<nsPIDOMWindowOuter> domWindow =
191 mDocShell ? mDocShell->GetWindow() : nullptr;
192 NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE);
193 domWindow->Focus(mozilla::dom::CallerType::System);
196 return NS_OK;
199 NS_IMETHODIMP
200 nsDSURIContentListener::IsPreferred(const char* aContentType,
201 char** aDesiredContentType,
202 bool* aCanHandle) {
203 NS_ENSURE_ARG_POINTER(aCanHandle);
204 NS_ENSURE_ARG_POINTER(aDesiredContentType);
206 // the docshell has no idea if it is the preferred content provider or not.
207 // It needs to ask its parent if it is the preferred content handler or not...
209 nsCOMPtr<nsIURIContentListener> parentListener;
210 GetParentContentListener(getter_AddRefs(parentListener));
211 if (parentListener) {
212 return parentListener->IsPreferred(aContentType, aDesiredContentType,
213 aCanHandle);
215 // we used to return false here if we didn't have a parent properly registered
216 // at the top of the docshell hierarchy to dictate what content types this
217 // docshell should be a preferred handler for. But this really makes it hard
218 // for developers using iframe or browser tags because then they need to make
219 // sure they implement nsIURIContentListener otherwise all link clicks would
220 // get sent to another window because we said we weren't the preferred handler
221 // type. I'm going to change the default now... if we can handle the content,
222 // and someone didn't EXPLICITLY set a nsIURIContentListener at the top of our
223 // docshell chain, then we'll now always attempt to process the content
224 // ourselves...
225 return CanHandleContent(aContentType, true, aDesiredContentType, aCanHandle);
228 NS_IMETHODIMP
229 nsDSURIContentListener::CanHandleContent(const char* aContentType,
230 bool aIsContentPreferred,
231 char** aDesiredContentType,
232 bool* aCanHandleContent) {
233 MOZ_ASSERT(aCanHandleContent, "Null out param?");
234 NS_ENSURE_ARG_POINTER(aDesiredContentType);
236 *aCanHandleContent = false;
237 *aDesiredContentType = nullptr;
239 if (aContentType) {
240 uint32_t canHandle =
241 nsWebNavigationInfo::IsTypeSupported(nsDependentCString(aContentType));
242 *aCanHandleContent = (canHandle != nsIWebNavigationInfo::UNSUPPORTED);
245 return NS_OK;
248 NS_IMETHODIMP
249 nsDSURIContentListener::GetLoadCookie(nsISupports** aLoadCookie) {
250 NS_IF_ADDREF(*aLoadCookie = nsDocShell::GetAsSupports(mDocShell));
251 return NS_OK;
254 NS_IMETHODIMP
255 nsDSURIContentListener::SetLoadCookie(nsISupports* aLoadCookie) {
256 #ifdef DEBUG
257 RefPtr<nsDocLoader> cookieAsDocLoader =
258 nsDocLoader::GetAsDocLoader(aLoadCookie);
259 NS_ASSERTION(cookieAsDocLoader && cookieAsDocLoader == mDocShell,
260 "Invalid load cookie being set!");
261 #endif
262 return NS_OK;
265 NS_IMETHODIMP
266 nsDSURIContentListener::GetParentContentListener(
267 nsIURIContentListener** aParentListener) {
268 if (mWeakParentContentListener) {
269 nsCOMPtr<nsIURIContentListener> tempListener =
270 do_QueryReferent(mWeakParentContentListener);
271 *aParentListener = tempListener;
272 NS_IF_ADDREF(*aParentListener);
273 } else {
274 *aParentListener = mParentContentListener;
275 NS_IF_ADDREF(*aParentListener);
277 return NS_OK;
280 NS_IMETHODIMP
281 nsDSURIContentListener::SetParentContentListener(
282 nsIURIContentListener* aParentListener) {
283 if (aParentListener) {
284 // Store the parent listener as a weak ref. Parents not supporting
285 // nsISupportsWeakReference assert but may still be used.
286 mParentContentListener = nullptr;
287 mWeakParentContentListener = do_GetWeakReference(aParentListener);
288 if (!mWeakParentContentListener) {
289 mParentContentListener = aParentListener;
291 } else {
292 mWeakParentContentListener = nullptr;
293 mParentContentListener = nullptr;
295 return NS_OK;