Line data Source code
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/. */
6 :
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 "nsIDocument.h"
14 : #include "nsIDOMWindow.h"
15 : #include "nsIHttpChannel.h"
16 : #include "nsError.h"
17 : #include "nsDocShellLoadTypes.h"
18 : #include "nsIMultiPartChannel.h"
19 :
20 : using namespace mozilla;
21 :
22 5 : nsDSURIContentListener::nsDSURIContentListener(nsDocShell* aDocShell)
23 : : mDocShell(aDocShell)
24 : , mExistingJPEGRequest(nullptr)
25 5 : , mParentContentListener(nullptr)
26 : {
27 5 : }
28 :
29 0 : nsDSURIContentListener::~nsDSURIContentListener()
30 : {
31 0 : }
32 :
33 : nsresult
34 5 : nsDSURIContentListener::Init()
35 : {
36 : nsresult rv;
37 5 : mNavInfo = do_GetService(NS_WEBNAVIGATION_INFO_CONTRACTID, &rv);
38 5 : NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to get webnav info");
39 5 : return rv;
40 : }
41 :
42 51 : NS_IMPL_ADDREF(nsDSURIContentListener)
43 46 : NS_IMPL_RELEASE(nsDSURIContentListener)
44 :
45 26 : NS_INTERFACE_MAP_BEGIN(nsDSURIContentListener)
46 26 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIURIContentListener)
47 26 : NS_INTERFACE_MAP_ENTRY(nsIURIContentListener)
48 2 : NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
49 0 : NS_INTERFACE_MAP_END
50 :
51 : NS_IMETHODIMP
52 8 : nsDSURIContentListener::OnStartURIOpen(nsIURI* aURI, bool* aAbortOpen)
53 : {
54 : // If mDocShell is null here, that means someone's starting a load in our
55 : // docshell after it's already been destroyed. Don't let that happen.
56 8 : if (!mDocShell) {
57 0 : *aAbortOpen = true;
58 0 : return NS_OK;
59 : }
60 :
61 16 : nsCOMPtr<nsIURIContentListener> parentListener;
62 8 : GetParentContentListener(getter_AddRefs(parentListener));
63 8 : if (parentListener) {
64 2 : return parentListener->OnStartURIOpen(aURI, aAbortOpen);
65 : }
66 :
67 6 : return NS_OK;
68 : }
69 :
70 : NS_IMETHODIMP
71 4 : nsDSURIContentListener::DoContent(const nsACString& aContentType,
72 : bool aIsContentPreferred,
73 : nsIRequest* aRequest,
74 : nsIStreamListener** aContentHandler,
75 : bool* aAbortProcess)
76 : {
77 : nsresult rv;
78 4 : NS_ENSURE_ARG_POINTER(aContentHandler);
79 4 : NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
80 :
81 4 : *aAbortProcess = false;
82 :
83 : // determine if the channel has just been retargeted to us...
84 4 : nsLoadFlags loadFlags = 0;
85 8 : nsCOMPtr<nsIChannel> aOpenedChannel = do_QueryInterface(aRequest);
86 :
87 4 : if (aOpenedChannel) {
88 4 : aOpenedChannel->GetLoadFlags(&loadFlags);
89 : }
90 :
91 4 : if (loadFlags & nsIChannel::LOAD_RETARGETED_DOCUMENT_URI) {
92 : // XXX: Why does this not stop the content too?
93 0 : mDocShell->Stop(nsIWebNavigation::STOP_NETWORK);
94 :
95 0 : mDocShell->SetLoadType(aIsContentPreferred ? LOAD_LINK : LOAD_NORMAL);
96 : }
97 :
98 : // In case of multipart jpeg request (mjpeg) we don't really want to
99 : // create new viewer since the one we already have is capable of
100 : // rendering multipart jpeg correctly (see bug 625012)
101 8 : nsCOMPtr<nsIChannel> baseChannel;
102 8 : if (nsCOMPtr<nsIMultiPartChannel> mpchan = do_QueryInterface(aRequest)) {
103 0 : mpchan->GetBaseChannel(getter_AddRefs(baseChannel));
104 : }
105 :
106 4 : bool reuseCV = baseChannel && baseChannel == mExistingJPEGRequest &&
107 4 : aContentType.EqualsLiteral("image/jpeg");
108 :
109 4 : if (mExistingJPEGStreamListener && reuseCV) {
110 0 : RefPtr<nsIStreamListener> copy(mExistingJPEGStreamListener);
111 0 : copy.forget(aContentHandler);
112 0 : rv = NS_OK;
113 : } else {
114 4 : rv = mDocShell->CreateContentViewer(aContentType, aRequest, aContentHandler);
115 4 : if (NS_SUCCEEDED(rv) && reuseCV) {
116 0 : mExistingJPEGStreamListener = *aContentHandler;
117 : } else {
118 4 : mExistingJPEGStreamListener = nullptr;
119 : }
120 4 : mExistingJPEGRequest = baseChannel;
121 : }
122 :
123 4 : if (rv == NS_ERROR_REMOTE_XUL || rv == NS_ERROR_DOCSHELL_DYING) {
124 0 : aRequest->Cancel(rv);
125 0 : *aAbortProcess = true;
126 0 : return NS_OK;
127 : }
128 :
129 4 : if (NS_FAILED(rv)) {
130 : // we don't know how to handle the content
131 0 : *aContentHandler = nullptr;
132 0 : return rv;
133 : }
134 :
135 4 : if (loadFlags & nsIChannel::LOAD_RETARGETED_DOCUMENT_URI) {
136 : nsCOMPtr<nsPIDOMWindowOuter> domWindow =
137 0 : mDocShell ? mDocShell->GetWindow() : nullptr;
138 0 : NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE);
139 0 : domWindow->Focus();
140 : }
141 :
142 4 : return NS_OK;
143 : }
144 :
145 : NS_IMETHODIMP
146 0 : nsDSURIContentListener::IsPreferred(const char* aContentType,
147 : char** aDesiredContentType,
148 : bool* aCanHandle)
149 : {
150 0 : NS_ENSURE_ARG_POINTER(aCanHandle);
151 0 : NS_ENSURE_ARG_POINTER(aDesiredContentType);
152 :
153 : // the docshell has no idea if it is the preferred content provider or not.
154 : // It needs to ask its parent if it is the preferred content handler or not...
155 :
156 0 : nsCOMPtr<nsIURIContentListener> parentListener;
157 0 : GetParentContentListener(getter_AddRefs(parentListener));
158 0 : if (parentListener) {
159 0 : return parentListener->IsPreferred(aContentType,
160 : aDesiredContentType,
161 0 : aCanHandle);
162 : }
163 : // we used to return false here if we didn't have a parent properly registered
164 : // at the top of the docshell hierarchy to dictate what content types this
165 : // docshell should be a preferred handler for. But this really makes it hard
166 : // for developers using iframe or browser tags because then they need to make
167 : // sure they implement nsIURIContentListener otherwise all link clicks would
168 : // get sent to another window because we said we weren't the preferred handler
169 : // type. I'm going to change the default now... if we can handle the content,
170 : // and someone didn't EXPLICITLY set a nsIURIContentListener at the top of our
171 : // docshell chain, then we'll now always attempt to process the content
172 : // ourselves...
173 0 : return CanHandleContent(aContentType, true, aDesiredContentType, aCanHandle);
174 : }
175 :
176 : NS_IMETHODIMP
177 4 : nsDSURIContentListener::CanHandleContent(const char* aContentType,
178 : bool aIsContentPreferred,
179 : char** aDesiredContentType,
180 : bool* aCanHandleContent)
181 : {
182 4 : NS_PRECONDITION(aCanHandleContent, "Null out param?");
183 4 : NS_ENSURE_ARG_POINTER(aDesiredContentType);
184 :
185 4 : *aCanHandleContent = false;
186 4 : *aDesiredContentType = nullptr;
187 :
188 4 : nsresult rv = NS_OK;
189 4 : if (aContentType) {
190 4 : uint32_t canHandle = nsIWebNavigationInfo::UNSUPPORTED;
191 16 : rv = mNavInfo->IsTypeSupported(nsDependentCString(aContentType),
192 8 : mDocShell,
193 8 : &canHandle);
194 4 : *aCanHandleContent = (canHandle != nsIWebNavigationInfo::UNSUPPORTED);
195 : }
196 :
197 4 : return rv;
198 : }
199 :
200 : NS_IMETHODIMP
201 0 : nsDSURIContentListener::GetLoadCookie(nsISupports** aLoadCookie)
202 : {
203 0 : NS_IF_ADDREF(*aLoadCookie = nsDocShell::GetAsSupports(mDocShell));
204 0 : return NS_OK;
205 : }
206 :
207 : NS_IMETHODIMP
208 0 : nsDSURIContentListener::SetLoadCookie(nsISupports* aLoadCookie)
209 : {
210 : #ifdef DEBUG
211 : RefPtr<nsDocLoader> cookieAsDocLoader =
212 0 : nsDocLoader::GetAsDocLoader(aLoadCookie);
213 0 : NS_ASSERTION(cookieAsDocLoader && cookieAsDocLoader == mDocShell,
214 : "Invalid load cookie being set!");
215 : #endif
216 0 : return NS_OK;
217 : }
218 :
219 : NS_IMETHODIMP
220 8 : nsDSURIContentListener::GetParentContentListener(
221 : nsIURIContentListener** aParentListener)
222 : {
223 8 : if (mWeakParentContentListener) {
224 : nsCOMPtr<nsIURIContentListener> tempListener =
225 4 : do_QueryReferent(mWeakParentContentListener);
226 2 : *aParentListener = tempListener;
227 2 : NS_IF_ADDREF(*aParentListener);
228 : } else {
229 6 : *aParentListener = mParentContentListener;
230 6 : NS_IF_ADDREF(*aParentListener);
231 : }
232 8 : return NS_OK;
233 : }
234 :
235 : NS_IMETHODIMP
236 3 : nsDSURIContentListener::SetParentContentListener(
237 : nsIURIContentListener* aParentListener)
238 : {
239 3 : if (aParentListener) {
240 : // Store the parent listener as a weak ref. Parents not supporting
241 : // nsISupportsWeakReference assert but may still be used.
242 2 : mParentContentListener = nullptr;
243 2 : mWeakParentContentListener = do_GetWeakReference(aParentListener);
244 2 : if (!mWeakParentContentListener) {
245 0 : mParentContentListener = aParentListener;
246 : }
247 : } else {
248 1 : mWeakParentContentListener = nullptr;
249 1 : mParentContentListener = nullptr;
250 : }
251 3 : return NS_OK;
252 : }
|