1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Pierre Phaneuf <pp@ludusdesign.com>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include "IPCMessageUtils.h"
40 : #include "mozilla/net/NeckoMessageUtils.h"
41 :
42 : #include "nsAboutProtocolHandler.h"
43 : #include "nsIURI.h"
44 : #include "nsIIOService.h"
45 : #include "nsCRT.h"
46 : #include "nsIComponentManager.h"
47 : #include "nsIServiceManager.h"
48 : #include "nsIAboutModule.h"
49 : #include "nsString.h"
50 : #include "nsReadableUtils.h"
51 : #include "nsNetCID.h"
52 : #include "nsAboutProtocolUtils.h"
53 : #include "nsNetError.h"
54 : #include "nsNetUtil.h"
55 : #include "nsIObjectInputStream.h"
56 : #include "nsIObjectOutputStream.h"
57 : #include "nsAutoPtr.h"
58 : #include "nsIWritablePropertyBag2.h"
59 :
60 : static NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID);
61 : static NS_DEFINE_CID(kNestedAboutURICID, NS_NESTEDABOUTURI_CID);
62 :
63 : ////////////////////////////////////////////////////////////////////////////////
64 :
65 5840 : NS_IMPL_ISUPPORTS1(nsAboutProtocolHandler, nsIProtocolHandler)
66 :
67 : ////////////////////////////////////////////////////////////////////////////////
68 : // nsIProtocolHandler methods:
69 :
70 : NS_IMETHODIMP
71 0 : nsAboutProtocolHandler::GetScheme(nsACString &result)
72 : {
73 0 : result.AssignLiteral("about");
74 0 : return NS_OK;
75 : }
76 :
77 : NS_IMETHODIMP
78 0 : nsAboutProtocolHandler::GetDefaultPort(PRInt32 *result)
79 : {
80 0 : *result = -1; // no port for about: URLs
81 0 : return NS_OK;
82 : }
83 :
84 : NS_IMETHODIMP
85 15 : nsAboutProtocolHandler::GetProtocolFlags(PRUint32 *result)
86 : {
87 15 : *result = URI_NORELATIVE | URI_NOAUTH | URI_DANGEROUS_TO_LOAD;
88 15 : return NS_OK;
89 : }
90 :
91 : NS_IMETHODIMP
92 659 : nsAboutProtocolHandler::NewURI(const nsACString &aSpec,
93 : const char *aCharset, // ignore charset info
94 : nsIURI *aBaseURI,
95 : nsIURI **result)
96 : {
97 659 : *result = nsnull;
98 : nsresult rv;
99 :
100 : // Use a simple URI to parse out some stuff first
101 1318 : nsCOMPtr<nsIURI> url = do_CreateInstance(kSimpleURICID, &rv);
102 659 : if (NS_FAILED(rv)) return rv;
103 :
104 659 : rv = url->SetSpec(aSpec);
105 659 : if (NS_FAILED(rv)) {
106 0 : return rv;
107 : }
108 :
109 : // Unfortunately, people create random about: URIs that don't correspond to
110 : // about: modules... Since those URIs will never open a channel, might as
111 : // well consider them unsafe for better perf, and just in case.
112 659 : bool isSafe = false;
113 :
114 1318 : nsCOMPtr<nsIAboutModule> aboutMod;
115 659 : rv = NS_GetAboutModule(url, getter_AddRefs(aboutMod));
116 659 : if (NS_SUCCEEDED(rv)) {
117 : // The standard return case
118 : PRUint32 flags;
119 601 : rv = aboutMod->GetURIFlags(url, &flags);
120 601 : NS_ENSURE_SUCCESS(rv, rv);
121 :
122 : isSafe =
123 601 : ((flags & nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT) != 0);
124 : }
125 :
126 659 : if (isSafe) {
127 : // We need to indicate that this baby is safe. Use an inner URI that
128 : // no one but the security manager will see. Make sure to preserve our
129 : // path, in case someone decides to hardcode checks for particular
130 : // about: URIs somewhere.
131 1172 : nsCAutoString spec;
132 586 : rv = url->GetPath(spec);
133 586 : NS_ENSURE_SUCCESS(rv, rv);
134 :
135 586 : spec.Insert("moz-safe-about:", 0);
136 :
137 1172 : nsCOMPtr<nsIURI> inner;
138 586 : rv = NS_NewURI(getter_AddRefs(inner), spec);
139 586 : NS_ENSURE_SUCCESS(rv, rv);
140 :
141 1172 : nsSimpleNestedURI* outer = new nsNestedAboutURI(inner, aBaseURI);
142 586 : NS_ENSURE_TRUE(outer, NS_ERROR_OUT_OF_MEMORY);
143 :
144 : // Take a ref to it in the COMPtr we plan to return
145 586 : url = outer;
146 :
147 586 : rv = outer->SetSpec(aSpec);
148 586 : NS_ENSURE_SUCCESS(rv, rv);
149 : }
150 :
151 : // We don't want to allow mutation, since it would allow safe and
152 : // unsafe URIs to change into each other...
153 659 : NS_TryToSetImmutable(url);
154 659 : url.swap(*result);
155 659 : return NS_OK;
156 : }
157 :
158 : NS_IMETHODIMP
159 8 : nsAboutProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result)
160 : {
161 8 : NS_ENSURE_ARG_POINTER(uri);
162 :
163 : // about:what you ask?
164 16 : nsCOMPtr<nsIAboutModule> aboutMod;
165 8 : nsresult rv = NS_GetAboutModule(uri, getter_AddRefs(aboutMod));
166 8 : if (NS_SUCCEEDED(rv)) {
167 : // The standard return case:
168 8 : rv = aboutMod->NewChannel(uri, result);
169 8 : if (NS_SUCCEEDED(rv)) {
170 16 : nsRefPtr<nsNestedAboutURI> aboutURI;
171 : nsresult rv2 = uri->QueryInterface(kNestedAboutURICID,
172 8 : getter_AddRefs(aboutURI));
173 8 : if (NS_SUCCEEDED(rv2) && aboutURI->GetBaseURI()) {
174 : nsCOMPtr<nsIWritablePropertyBag2> writableBag =
175 2 : do_QueryInterface(*result);
176 1 : if (writableBag) {
177 1 : writableBag->
178 1 : SetPropertyAsInterface(NS_LITERAL_STRING("baseURI"),
179 1 : aboutURI->GetBaseURI());
180 : }
181 : }
182 : }
183 8 : return rv;
184 : }
185 :
186 : // mumble...
187 :
188 0 : if (rv == NS_ERROR_FACTORY_NOT_REGISTERED) {
189 : // This looks like an about: we don't know about. Convert
190 : // this to an invalid URI error.
191 0 : rv = NS_ERROR_MALFORMED_URI;
192 : }
193 :
194 0 : return rv;
195 : }
196 :
197 : NS_IMETHODIMP
198 0 : nsAboutProtocolHandler::AllowPort(PRInt32 port, const char *scheme, bool *_retval)
199 : {
200 : // don't override anything.
201 0 : *_retval = false;
202 0 : return NS_OK;
203 : }
204 :
205 : ////////////////////////////////////////////////////////////////////////////////
206 : // Safe about protocol handler impl
207 :
208 5316 : NS_IMPL_ISUPPORTS1(nsSafeAboutProtocolHandler, nsIProtocolHandler)
209 :
210 : // nsIProtocolHandler methods:
211 :
212 : NS_IMETHODIMP
213 0 : nsSafeAboutProtocolHandler::GetScheme(nsACString &result)
214 : {
215 0 : result.AssignLiteral("moz-safe-about");
216 0 : return NS_OK;
217 : }
218 :
219 : NS_IMETHODIMP
220 0 : nsSafeAboutProtocolHandler::GetDefaultPort(PRInt32 *result)
221 : {
222 0 : *result = -1; // no port for moz-safe-about: URLs
223 0 : return NS_OK;
224 : }
225 :
226 : NS_IMETHODIMP
227 14 : nsSafeAboutProtocolHandler::GetProtocolFlags(PRUint32 *result)
228 : {
229 14 : *result = URI_NORELATIVE | URI_NOAUTH | URI_LOADABLE_BY_ANYONE;
230 14 : return NS_OK;
231 : }
232 :
233 : NS_IMETHODIMP
234 588 : nsSafeAboutProtocolHandler::NewURI(const nsACString &aSpec,
235 : const char *aCharset, // ignore charset info
236 : nsIURI *aBaseURI,
237 : nsIURI **result)
238 : {
239 : nsresult rv;
240 :
241 1176 : nsCOMPtr<nsIURI> url = do_CreateInstance(kSimpleURICID, &rv);
242 588 : if (NS_FAILED(rv)) return rv;
243 :
244 588 : rv = url->SetSpec(aSpec);
245 588 : if (NS_FAILED(rv)) {
246 0 : return rv;
247 : }
248 :
249 588 : NS_TryToSetImmutable(url);
250 :
251 588 : *result = nsnull;
252 588 : url.swap(*result);
253 588 : return rv;
254 : }
255 :
256 : NS_IMETHODIMP
257 0 : nsSafeAboutProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result)
258 : {
259 0 : *result = nsnull;
260 0 : return NS_ERROR_NOT_AVAILABLE;
261 : }
262 :
263 : NS_IMETHODIMP
264 0 : nsSafeAboutProtocolHandler::AllowPort(PRInt32 port, const char *scheme, bool *_retval)
265 : {
266 : // don't override anything.
267 0 : *_retval = false;
268 0 : return NS_OK;
269 : }
270 :
271 : ////////////////////////////////////////////////////////////
272 : // nsNestedAboutURI implementation
273 4999 : NS_INTERFACE_MAP_BEGIN(nsNestedAboutURI)
274 4999 : if (aIID.Equals(kNestedAboutURICID))
275 2 : foundInterface = static_cast<nsIURI*>(this);
276 : else
277 4997 : NS_INTERFACE_MAP_END_INHERITING(nsSimpleNestedURI)
278 :
279 : // nsISerializable
280 : NS_IMETHODIMP
281 1 : nsNestedAboutURI::Read(nsIObjectInputStream* aStream)
282 : {
283 1 : nsresult rv = nsSimpleNestedURI::Read(aStream);
284 1 : if (NS_FAILED(rv)) return rv;
285 :
286 : bool haveBase;
287 1 : rv = aStream->ReadBoolean(&haveBase);
288 1 : if (NS_FAILED(rv)) return rv;
289 :
290 1 : if (haveBase) {
291 2 : nsCOMPtr<nsISupports> supports;
292 1 : rv = aStream->ReadObject(true, getter_AddRefs(supports));
293 1 : if (NS_FAILED(rv)) return rv;
294 :
295 1 : mBaseURI = do_QueryInterface(supports, &rv);
296 1 : if (NS_FAILED(rv)) return rv;
297 : }
298 :
299 1 : return NS_OK;
300 : }
301 :
302 : NS_IMETHODIMP
303 1 : nsNestedAboutURI::Write(nsIObjectOutputStream* aStream)
304 : {
305 1 : nsresult rv = nsSimpleNestedURI::Write(aStream);
306 1 : if (NS_FAILED(rv)) return rv;
307 :
308 1 : rv = aStream->WriteBoolean(mBaseURI != nsnull);
309 1 : if (NS_FAILED(rv)) return rv;
310 :
311 1 : if (mBaseURI) {
312 : // A previous iteration of this code wrote out mBaseURI as nsISupports
313 : // and then read it in as nsIURI, which is non-kosher when mBaseURI
314 : // implements more than just a single line of interfaces and the
315 : // canonical nsISupports* isn't the one a static_cast<> of mBaseURI
316 : // would produce. For backwards compatibility with existing
317 : // serializations we continue to write mBaseURI as nsISupports but
318 : // switch to reading it as nsISupports, with a post-read QI to get to
319 : // nsIURI.
320 : rv = aStream->WriteCompoundObject(mBaseURI, NS_GET_IID(nsISupports),
321 1 : true);
322 1 : if (NS_FAILED(rv)) return rv;
323 : }
324 :
325 1 : return NS_OK;
326 : }
327 :
328 : // nsIIPCSerializable
329 : bool
330 0 : nsNestedAboutURI::Read(const IPC::Message *aMsg, void **aIter)
331 : {
332 0 : if (!nsSimpleNestedURI::Read(aMsg, aIter))
333 0 : return false;
334 :
335 0 : IPC::URI uri;
336 0 : if (!ReadParam(aMsg, aIter, &uri))
337 0 : return false;
338 :
339 0 : mBaseURI = uri;
340 :
341 0 : return true;
342 : }
343 :
344 : void
345 0 : nsNestedAboutURI::Write(IPC::Message *aMsg)
346 : {
347 0 : nsSimpleNestedURI::Write(aMsg);
348 :
349 0 : IPC::URI uri(mBaseURI);
350 0 : WriteParam(aMsg, uri);
351 0 : }
352 :
353 : // nsSimpleURI
354 : /* virtual */ nsSimpleURI*
355 24 : nsNestedAboutURI::StartClone(nsSimpleURI::RefHandlingEnum aRefHandlingMode)
356 : {
357 : // Sadly, we can't make use of nsSimpleNestedURI::StartClone here.
358 : // However, this function is expected to exactly match that function,
359 : // aside from the "new ns***URI()" call.
360 24 : NS_ENSURE_TRUE(mInnerURI, nsnull);
361 :
362 48 : nsCOMPtr<nsIURI> innerClone;
363 : nsresult rv = aRefHandlingMode == eHonorRef ?
364 48 : mInnerURI->Clone(getter_AddRefs(innerClone)) :
365 48 : mInnerURI->CloneIgnoringRef(getter_AddRefs(innerClone));
366 :
367 24 : if (NS_FAILED(rv)) {
368 0 : return nsnull;
369 : }
370 :
371 48 : nsNestedAboutURI* url = new nsNestedAboutURI(innerClone, mBaseURI);
372 24 : url->SetMutable(false);
373 :
374 24 : return url;
375 : }
376 :
377 : // nsIClassInfo
378 : NS_IMETHODIMP
379 1 : nsNestedAboutURI::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
380 : {
381 1 : *aClassIDNoAlloc = kNestedAboutURICID;
382 1 : return NS_OK;
383 : }
|