1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "base/basictypes.h"
7 #include "mozilla/ArrayUtils.h"
9 #include "nsAboutProtocolHandler.h"
11 #include "nsIAboutModule.h"
12 #include "nsContentUtils.h"
15 #include "nsAboutProtocolUtils.h"
17 #include "nsNetUtil.h"
18 #include "nsIObjectInputStream.h"
19 #include "nsIObjectOutputStream.h"
20 #include "nsIWritablePropertyBag2.h"
21 #include "nsIChannel.h"
22 #include "nsIScriptError.h"
23 #include "nsIClassInfoImpl.h"
24 #include "DefaultURI.h"
26 #include "mozilla/ipc/URIUtils.h"
31 static NS_DEFINE_CID(kNestedAboutURICID
, NS_NESTEDABOUTURI_CID
);
33 static bool IsSafeToLinkForUntrustedContent(nsIURI
* aURI
) {
35 aURI
->GetPathQueryRef(path
);
37 int32_t f
= path
.FindChar('#');
42 f
= path
.FindChar('?');
49 // The about modules for these URL types have the
50 // URI_SAFE_FOR_UNTRUSTED_CONTENT and MAKE_LINKABLE flags set.
51 return path
.EqualsLiteral("blank") || path
.EqualsLiteral("logo") ||
52 path
.EqualsLiteral("srcdoc");
55 ////////////////////////////////////////////////////////////////////////////////
57 NS_IMPL_ISUPPORTS(nsAboutProtocolHandler
, nsIProtocolHandler
,
58 nsIProtocolHandlerWithDynamicFlags
, nsISupportsWeakReference
)
60 ////////////////////////////////////////////////////////////////////////////////
61 // nsIProtocolHandler methods:
64 nsAboutProtocolHandler::GetScheme(nsACString
& result
) {
65 result
.AssignLiteral("about");
70 nsAboutProtocolHandler::GetFlagsForURI(nsIURI
* aURI
, uint32_t* aFlags
) {
71 // First use the default (which is "unsafe for content"):
72 *aFlags
= URI_NORELATIVE
| URI_NOAUTH
| URI_DANGEROUS_TO_LOAD
|
73 URI_SCHEME_NOT_SELF_LINKABLE
;
75 // Now try to see if this URI overrides the default:
76 nsCOMPtr
<nsIAboutModule
> aboutMod
;
77 nsresult rv
= NS_GetAboutModule(aURI
, getter_AddRefs(aboutMod
));
79 // Swallow this and just tell the consumer the default:
82 uint32_t aboutModuleFlags
= 0;
83 rv
= aboutMod
->GetURIFlags(aURI
, &aboutModuleFlags
);
84 // This should never happen, so pass back the error:
85 NS_ENSURE_SUCCESS(rv
, rv
);
87 // Secure (https) pages can load safe about pages without becoming
89 if (aboutModuleFlags
& nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT
) {
90 *aFlags
|= URI_IS_POTENTIALLY_TRUSTWORTHY
;
91 // about: pages can only be loaded by unprivileged principals
92 // if they are marked as LINKABLE
93 if (aboutModuleFlags
& nsIAboutModule::MAKE_LINKABLE
) {
94 // Replace URI_DANGEROUS_TO_LOAD with URI_LOADABLE_BY_ANYONE.
95 *aFlags
&= ~URI_DANGEROUS_TO_LOAD
;
96 *aFlags
|= URI_LOADABLE_BY_ANYONE
;
103 nsresult
nsAboutProtocolHandler::CreateNewURI(const nsACString
& aSpec
,
104 const char* aCharset
,
110 // Use a simple URI to parse out some stuff first
111 nsCOMPtr
<nsIURI
> url
;
112 rv
= NS_MutateURI(new nsSimpleURI::Mutator()).SetSpec(aSpec
).Finalize(url
);
118 if (IsSafeToLinkForUntrustedContent(url
)) {
119 // We need to indicate that this baby is safe. Use an inner URI that
120 // no one but the security manager will see. Make sure to preserve our
121 // path, in case someone decides to hardcode checks for particular
122 // about: URIs somewhere.
124 rv
= url
->GetPathQueryRef(spec
);
125 NS_ENSURE_SUCCESS(rv
, rv
);
127 spec
.InsertLiteral("moz-safe-about:", 0);
129 nsCOMPtr
<nsIURI
> inner
;
130 rv
= NS_NewURI(getter_AddRefs(inner
), spec
);
131 NS_ENSURE_SUCCESS(rv
, rv
);
133 rv
= NS_MutateURI(new nsNestedAboutURI::Mutator())
134 .Apply(&nsINestedAboutURIMutator::InitWithBase
, inner
, aBaseURI
)
137 NS_ENSURE_SUCCESS(rv
, rv
);
140 // use DefaultURI to check for validity when we have possible hostnames
141 // since nsSimpleURI doesn't know about hostnames
142 auto pos
= aSpec
.Find("about:/");
143 if (pos
!= kNotFound
) {
144 rv
= NS_MutateURI(new mozilla::net::DefaultURI::Mutator())
147 NS_ENSURE_SUCCESS(rv
, rv
);
155 nsAboutProtocolHandler::NewChannel(nsIURI
* uri
, nsILoadInfo
* aLoadInfo
,
156 nsIChannel
** result
) {
157 NS_ENSURE_ARG_POINTER(uri
);
159 // about:what you ask?
160 nsCOMPtr
<nsIAboutModule
> aboutMod
;
161 nsresult rv
= NS_GetAboutModule(uri
, getter_AddRefs(aboutMod
));
164 if (NS_SUCCEEDED(NS_GetAboutModuleName(uri
, path
)) &&
165 path
.EqualsLiteral("srcdoc")) {
166 // about:srcdoc is meant to be unresolvable, yet is included in the
167 // about lookup tables so that it can pass security checks when used in
168 // a srcdoc iframe. To ensure that it stays unresolvable, we pretend
169 // that it doesn't exist.
170 return NS_ERROR_MALFORMED_URI
;
174 if (rv
== NS_ERROR_FACTORY_NOT_REGISTERED
) {
175 // This looks like an about: we don't know about. Convert
176 // this to an invalid URI error.
177 return NS_ERROR_MALFORMED_URI
;
184 if (NS_FAILED(aboutMod
->GetURIFlags(uri
, &flags
))) {
185 return NS_ERROR_FAILURE
;
188 bool safeForUntrustedContent
=
189 (flags
& nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT
) != 0;
191 MOZ_DIAGNOSTIC_ASSERT(
192 safeForUntrustedContent
||
193 (flags
& (nsIAboutModule::URI_CAN_LOAD_IN_CHILD
|
194 nsIAboutModule::URI_MUST_LOAD_IN_CHILD
)) == 0,
195 "Only unprivileged content should be loaded in child processes. (Did "
196 "you forget to add URI_SAFE_FOR_UNTRUSTED_CONTENT to your about: "
199 // The standard return case:
200 rv
= aboutMod
->NewChannel(uri
, aLoadInfo
, result
);
202 if (rv
== NS_ERROR_FACTORY_NOT_REGISTERED
) {
203 // This looks like an about: we don't know about. Convert
204 // this to an invalid URI error.
205 return NS_ERROR_MALFORMED_URI
;
211 // Not all implementations of nsIAboutModule::NewChannel()
212 // set the LoadInfo on the newly created channel yet, as
213 // an interim solution we set the LoadInfo here if not
214 // available on the channel. Bug 1087720
215 nsCOMPtr
<nsILoadInfo
> loadInfo
= (*result
)->LoadInfo();
216 if (aLoadInfo
!= loadInfo
) {
218 "nsIAboutModule->newChannel(aURI, aLoadInfo) needs to "
220 AutoTArray
<nsString
, 2> params
= {
221 u
"nsIAboutModule->newChannel(aURI)"_ns
,
222 u
"nsIAboutModule->newChannel(aURI, aLoadInfo)"_ns
};
223 nsContentUtils::ReportToConsole(
224 nsIScriptError::warningFlag
, "Security by Default"_ns
,
225 nullptr, // aDocument
226 nsContentUtils::eNECKO_PROPERTIES
, "APIDeprecationWarning", params
);
227 (*result
)->SetLoadInfo(aLoadInfo
);
230 // If this URI is safe for untrusted content, enforce that its
231 // principal be based on the channel's originalURI by setting the
233 // Note: this relies on aboutMod's newChannel implementation
234 // having set the proper originalURI, which probably isn't ideal.
235 if (safeForUntrustedContent
) {
236 (*result
)->SetOwner(nullptr);
239 RefPtr
<nsNestedAboutURI
> aboutURI
;
241 uri
->QueryInterface(kNestedAboutURICID
, getter_AddRefs(aboutURI
))) &&
242 aboutURI
->GetBaseURI()) {
243 nsCOMPtr
<nsIWritablePropertyBag2
> writableBag
= do_QueryInterface(*result
);
245 writableBag
->SetPropertyAsInterface(u
"baseURI"_ns
,
246 aboutURI
->GetBaseURI());
254 nsAboutProtocolHandler::AllowPort(int32_t port
, const char* scheme
,
256 // don't override anything.
261 ////////////////////////////////////////////////////////////////////////////////
262 // Safe about protocol handler impl
264 NS_IMPL_ISUPPORTS(nsSafeAboutProtocolHandler
, nsIProtocolHandler
,
265 nsISupportsWeakReference
)
267 // nsIProtocolHandler methods:
270 nsSafeAboutProtocolHandler::GetScheme(nsACString
& result
) {
271 result
.AssignLiteral("moz-safe-about");
276 nsSafeAboutProtocolHandler::NewChannel(nsIURI
* uri
, nsILoadInfo
* aLoadInfo
,
277 nsIChannel
** result
) {
279 return NS_ERROR_NOT_AVAILABLE
;
283 nsSafeAboutProtocolHandler::AllowPort(int32_t port
, const char* scheme
,
285 // don't override anything.
290 ////////////////////////////////////////////////////////////
291 // nsNestedAboutURI implementation
293 NS_IMPL_CLASSINFO(nsNestedAboutURI
, nullptr, nsIClassInfo::THREADSAFE
,
294 NS_NESTEDABOUTURI_CID
);
295 // Empty CI getter. We only need nsIClassInfo for Serialization
296 NS_IMPL_CI_INTERFACE_GETTER0(nsNestedAboutURI
)
298 NS_INTERFACE_MAP_BEGIN(nsNestedAboutURI
)
299 if (aIID
.Equals(kNestedAboutURICID
)) {
300 foundInterface
= static_cast<nsIURI
*>(this);
302 NS_IMPL_QUERY_CLASSINFO(nsNestedAboutURI
)
303 NS_INTERFACE_MAP_END_INHERITING(nsSimpleNestedURI
)
308 nsNestedAboutURI::Read(nsIObjectInputStream
* aStream
) {
309 MOZ_ASSERT_UNREACHABLE("Use nsIURIMutator.read() instead");
310 return NS_ERROR_NOT_IMPLEMENTED
;
313 nsresult
nsNestedAboutURI::ReadPrivate(nsIObjectInputStream
* aStream
) {
314 nsresult rv
= nsSimpleNestedURI::ReadPrivate(aStream
);
315 if (NS_FAILED(rv
)) return rv
;
318 rv
= aStream
->ReadBoolean(&haveBase
);
319 if (NS_FAILED(rv
)) return rv
;
322 nsCOMPtr
<nsISupports
> supports
;
323 rv
= aStream
->ReadObject(true, getter_AddRefs(supports
));
324 if (NS_FAILED(rv
)) return rv
;
326 mBaseURI
= do_QueryInterface(supports
, &rv
);
327 if (NS_FAILED(rv
)) return rv
;
334 nsNestedAboutURI::Write(nsIObjectOutputStream
* aStream
) {
335 nsresult rv
= nsSimpleNestedURI::Write(aStream
);
336 if (NS_FAILED(rv
)) return rv
;
338 rv
= aStream
->WriteBoolean(mBaseURI
!= nullptr);
339 if (NS_FAILED(rv
)) return rv
;
342 // A previous iteration of this code wrote out mBaseURI as nsISupports
343 // and then read it in as nsIURI, which is non-kosher when mBaseURI
344 // implements more than just a single line of interfaces and the
345 // canonical nsISupports* isn't the one a static_cast<> of mBaseURI
346 // would produce. For backwards compatibility with existing
347 // serializations we continue to write mBaseURI as nsISupports but
348 // switch to reading it as nsISupports, with a post-read QI to get to
350 rv
= aStream
->WriteCompoundObject(mBaseURI
, NS_GET_IID(nsISupports
), true);
351 if (NS_FAILED(rv
)) return rv
;
358 nsNestedAboutURI::Serialize(mozilla::ipc::URIParams
& aParams
) {
359 using namespace mozilla::ipc
;
361 NestedAboutURIParams params
;
362 URIParams nestedParams
;
364 nsSimpleNestedURI::Serialize(nestedParams
);
365 params
.nestedParams() = nestedParams
;
368 SerializeURI(mBaseURI
, params
.baseURI());
374 bool nsNestedAboutURI::Deserialize(const mozilla::ipc::URIParams
& aParams
) {
375 using namespace mozilla::ipc
;
377 if (aParams
.type() != URIParams::TNestedAboutURIParams
) {
378 NS_ERROR("Received unknown parameters from the other process!");
382 const NestedAboutURIParams
& params
= aParams
.get_NestedAboutURIParams();
383 if (!nsSimpleNestedURI::Deserialize(params
.nestedParams())) {
388 if (params
.baseURI()) {
389 mBaseURI
= DeserializeURI(*params
.baseURI());
395 /* virtual */ nsSimpleURI
* nsNestedAboutURI::StartClone(
396 nsSimpleURI::RefHandlingEnum aRefHandlingMode
, const nsACString
& aNewRef
) {
397 // Sadly, we can't make use of nsSimpleNestedURI::StartClone here.
398 // However, this function is expected to exactly match that function,
399 // aside from the "new ns***URI()" call.
400 NS_ENSURE_TRUE(mInnerURI
, nullptr);
402 nsCOMPtr
<nsIURI
> innerClone
;
404 if (aRefHandlingMode
== eHonorRef
) {
405 innerClone
= mInnerURI
;
406 } else if (aRefHandlingMode
== eReplaceRef
) {
407 rv
= NS_GetURIWithNewRef(mInnerURI
, aNewRef
, getter_AddRefs(innerClone
));
409 rv
= NS_GetURIWithoutRef(mInnerURI
, getter_AddRefs(innerClone
));
416 nsNestedAboutURI
* url
= new nsNestedAboutURI(innerClone
, mBaseURI
);
417 SetRefOnClone(url
, aRefHandlingMode
, aNewRef
);
422 // Queries this list of interfaces. If none match, it queries mURI.
423 NS_IMPL_NSIURIMUTATOR_ISUPPORTS(nsNestedAboutURI::Mutator
, nsIURISetters
,
424 nsIURIMutator
, nsISerializable
,
425 nsINestedAboutURIMutator
)
428 nsNestedAboutURI::Mutate(nsIURIMutator
** aMutator
) {
429 RefPtr
<nsNestedAboutURI::Mutator
> mutator
= new nsNestedAboutURI::Mutator();
430 nsresult rv
= mutator
->InitFromURI(this);
434 mutator
.forget(aMutator
);
439 } // namespace mozilla