1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sw=2 et tw=78: */
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 "nsChromeRegistry.h"
8 #include "nsChromeRegistryChrome.h"
9 #include "nsChromeRegistryContent.h"
14 #include "nsNetUtil.h"
16 #include "nsQueryObject.h"
18 #include "mozilla/dom/URL.h"
19 #include "nsIConsoleService.h"
20 #include "mozilla/dom/Document.h"
21 #include "nsIObserverService.h"
22 #include "nsIScriptError.h"
23 #include "mozilla/Preferences.h"
24 #include "mozilla/PresShell.h"
25 #include "mozilla/Printf.h"
26 #include "mozilla/StyleSheet.h"
27 #include "mozilla/StyleSheetInlines.h"
28 #include "mozilla/dom/Location.h"
30 nsChromeRegistry
* nsChromeRegistry::gChromeRegistry
;
32 // DO NOT use namespace mozilla; it'll break due to a naming conflict between
33 // mozilla::TextRange and a TextRange in OSX headers.
34 using mozilla::PresShell
;
35 using mozilla::StyleSheet
;
36 using mozilla::dom::Document
;
37 using mozilla::dom::Location
;
39 ////////////////////////////////////////////////////////////////////////////////
41 void nsChromeRegistry::LogMessage(const char* aMsg
, ...) {
42 nsCOMPtr
<nsIConsoleService
> console(
43 do_GetService(NS_CONSOLESERVICE_CONTRACTID
));
48 mozilla::SmprintfPointer formatted
= mozilla::Vsmprintf(aMsg
, args
);
50 if (!formatted
) return;
52 console
->LogStringMessage(NS_ConvertUTF8toUTF16(formatted
.get()).get());
55 void nsChromeRegistry::LogMessageWithContext(nsIURI
* aURL
, uint32_t aLineNumber
,
56 uint32_t flags
, const char* aMsg
,
60 nsCOMPtr
<nsIConsoleService
> console(
61 do_GetService(NS_CONSOLESERVICE_CONTRACTID
));
63 nsCOMPtr
<nsIScriptError
> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID
));
64 if (!console
|| !error
) return;
68 mozilla::SmprintfPointer formatted
= mozilla::Vsmprintf(aMsg
, args
);
70 if (!formatted
) return;
73 if (aURL
) aURL
->GetSpec(spec
);
76 NS_ConvertUTF8toUTF16(formatted
.get()), NS_ConvertUTF8toUTF16(spec
),
77 EmptyString(), aLineNumber
, 0, flags
, "chrome registration",
78 false /* from private window */, true /* from chrome context */);
80 if (NS_FAILED(rv
)) return;
82 console
->LogMessage(error
);
85 nsChromeRegistry::~nsChromeRegistry() { gChromeRegistry
= nullptr; }
87 NS_INTERFACE_MAP_BEGIN(nsChromeRegistry
)
88 NS_INTERFACE_MAP_ENTRY(nsIChromeRegistry
)
89 NS_INTERFACE_MAP_ENTRY(nsIXULChromeRegistry
)
90 NS_INTERFACE_MAP_ENTRY(nsIToolkitChromeRegistry
)
91 NS_INTERFACE_MAP_ENTRY(nsIObserver
)
92 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
93 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIChromeRegistry
)
96 NS_IMPL_ADDREF(nsChromeRegistry
)
97 NS_IMPL_RELEASE(nsChromeRegistry
)
99 ////////////////////////////////////////////////////////////////////////////////
100 // nsIChromeRegistry methods:
102 already_AddRefed
<nsIChromeRegistry
> nsChromeRegistry::GetService() {
103 if (!gChromeRegistry
) {
104 // We don't actually want this ref, we just want the service to
105 // initialize if it hasn't already.
106 nsCOMPtr
<nsIChromeRegistry
> reg(
107 do_GetService(NS_CHROMEREGISTRY_CONTRACTID
));
108 if (!gChromeRegistry
) return nullptr;
110 nsCOMPtr
<nsIChromeRegistry
> registry
= gChromeRegistry
;
111 return registry
.forget();
114 nsresult
nsChromeRegistry::Init() {
115 // This initialization process is fairly complicated and may cause reentrant
116 // getservice calls to resolve chrome URIs (especially locale files). We
117 // don't want that, so we inform the protocol handler about our existence
118 // before we are actually fully initialized.
119 gChromeRegistry
= this;
126 nsresult
nsChromeRegistry::GetProviderAndPath(nsIURI
* aChromeURL
,
127 nsACString
& aProvider
,
131 NS_ASSERTION(aChromeURL
->SchemeIs("chrome"), "Non-chrome URI?");
134 rv
= aChromeURL
->GetPathQueryRef(path
);
135 NS_ENSURE_SUCCESS(rv
, rv
);
137 if (path
.Length() < 3) {
139 LogMessage("Invalid chrome URI (need path): %s",
140 aChromeURL
->GetSpecOrDefault().get());
142 return NS_ERROR_FAILURE
;
145 path
.SetLength(nsUnescapeCount(path
.BeginWriting()));
146 NS_ASSERTION(path
.First() == '/', "Path should always begin with a slash!");
148 int32_t slash
= path
.FindChar('/', 1);
151 LogMessage("Invalid chrome URI (path cannot start with another slash): %s",
152 aChromeURL
->GetSpecOrDefault().get());
154 return NS_ERROR_FAILURE
;
160 if (slash
== (int32_t)path
.Length() - 1)
163 aPath
.Assign(path
.get() + slash
+ 1, path
.Length() - slash
- 1);
168 aProvider
.Assign(path
.get() + 1, slash
);
172 nsresult
nsChromeRegistry::Canonify(nsCOMPtr
<nsIURI
>& aChromeURL
) {
173 constexpr auto kSlash
= "/"_ns
;
177 nsAutoCString provider
, path
;
178 rv
= GetProviderAndPath(aChromeURL
, provider
, path
);
179 NS_ENSURE_SUCCESS(rv
, rv
);
181 if (path
.IsEmpty()) {
182 nsAutoCString package
;
183 rv
= aChromeURL
->GetHost(package
);
184 NS_ENSURE_SUCCESS(rv
, rv
);
186 // we re-use the "path" local string to build a new URL path
187 path
.Assign(kSlash
+ provider
+ kSlash
+ package
);
188 if (provider
.EqualsLiteral("content")) {
189 path
.AppendLiteral(".xul");
190 } else if (provider
.EqualsLiteral("locale")) {
191 path
.AppendLiteral(".dtd");
192 } else if (provider
.EqualsLiteral("skin")) {
193 path
.AppendLiteral(".css");
195 return NS_ERROR_INVALID_ARG
;
197 return NS_MutateURI(aChromeURL
).SetPathQueryRef(path
).Finalize(aChromeURL
);
199 // prevent directory traversals ("..")
200 // path is already unescaped once, but uris can get unescaped twice
201 const char* pos
= path
.BeginReading();
202 const char* end
= path
.EndReading();
203 // Must start with [a-zA-Z0-9].
204 if (!('a' <= *pos
&& *pos
<= 'z') && !('A' <= *pos
&& *pos
<= 'Z') &&
205 !('0' <= *pos
&& *pos
<= '9')) {
206 return NS_ERROR_DOM_BAD_URI
;
211 return NS_ERROR_DOM_BAD_URI
;
213 if (pos
[1] == '.') return NS_ERROR_DOM_BAD_URI
;
216 // chrome: URIs with double-escapes are trying to trick us.
217 // watch for %2e, and %25 in case someone triple unescapes
219 (pos
[2] == 'e' || pos
[2] == 'E' || pos
[2] == '5'))
220 return NS_ERROR_DOM_BAD_URI
;
235 nsChromeRegistry::ConvertChromeURL(nsIURI
* aChromeURI
, nsIURI
** aResult
) {
237 if (NS_WARN_IF(!aChromeURI
)) {
238 return NS_ERROR_INVALID_ARG
;
241 if (mOverrideTable
.Get(aChromeURI
, aResult
)) return NS_OK
;
243 nsCOMPtr
<nsIURL
> chromeURL(do_QueryInterface(aChromeURI
));
244 NS_ENSURE_TRUE(chromeURL
, NS_NOINTERFACE
);
246 nsAutoCString package
, provider
, path
;
247 rv
= chromeURL
->GetHostPort(package
);
248 NS_ENSURE_SUCCESS(rv
, rv
);
250 rv
= GetProviderAndPath(chromeURL
, provider
, path
);
251 NS_ENSURE_SUCCESS(rv
, rv
);
253 nsIURI
* baseURI
= GetBaseURIFromPackage(package
, provider
, path
);
256 rv
= GetFlagsFromPackage(package
, &flags
);
257 if (NS_FAILED(rv
)) return rv
;
260 LogMessage("No chrome package registered for chrome://%s/%s/%s",
261 package
.get(), provider
.get(), path
.get());
262 return NS_ERROR_FILE_NOT_FOUND
;
265 return NS_NewURI(aResult
, path
, nullptr, baseURI
);
268 ////////////////////////////////////////////////////////////////////////
270 void nsChromeRegistry::FlushAllCaches() {
271 nsCOMPtr
<nsIObserverService
> obsSvc
= mozilla::services::GetObserverService();
272 NS_ASSERTION(obsSvc
, "Couldn't get observer service.");
274 obsSvc
->NotifyObservers((nsIChromeRegistry
*)this, NS_CHROME_FLUSH_TOPIC
,
279 nsChromeRegistry::AllowScriptsForPackage(nsIURI
* aChromeURI
, bool* aResult
) {
283 NS_ASSERTION(aChromeURI
->SchemeIs("chrome"),
284 "Non-chrome URI passed to AllowScriptsForPackage!");
286 nsCOMPtr
<nsIURL
> url(do_QueryInterface(aChromeURI
));
287 NS_ENSURE_TRUE(url
, NS_NOINTERFACE
);
289 nsAutoCString provider
, file
;
290 rv
= GetProviderAndPath(url
, provider
, file
);
291 NS_ENSURE_SUCCESS(rv
, rv
);
293 if (!provider
.EqualsLiteral("skin")) *aResult
= true;
299 nsChromeRegistry::AllowContentToAccess(nsIURI
* aURI
, bool* aResult
) {
304 NS_ASSERTION(aURI
->SchemeIs("chrome"),
305 "Non-chrome URI passed to AllowContentToAccess!");
307 nsCOMPtr
<nsIURL
> url
= do_QueryInterface(aURI
);
309 NS_ERROR("Chrome URL doesn't implement nsIURL.");
310 return NS_ERROR_UNEXPECTED
;
313 nsAutoCString package
;
314 rv
= url
->GetHostPort(package
);
315 NS_ENSURE_SUCCESS(rv
, rv
);
318 rv
= GetFlagsFromPackage(package
, &flags
);
320 if (NS_SUCCEEDED(rv
)) {
321 *aResult
= !!(flags
& CONTENT_ACCESSIBLE
);
327 nsChromeRegistry::CanLoadURLRemotely(nsIURI
* aURI
, bool* aResult
) {
332 NS_ASSERTION(aURI
->SchemeIs("chrome"),
333 "Non-chrome URI passed to CanLoadURLRemotely!");
335 nsCOMPtr
<nsIURL
> url
= do_QueryInterface(aURI
);
337 NS_ERROR("Chrome URL doesn't implement nsIURL.");
338 return NS_ERROR_UNEXPECTED
;
341 nsAutoCString package
;
342 rv
= url
->GetHostPort(package
);
343 NS_ENSURE_SUCCESS(rv
, rv
);
346 rv
= GetFlagsFromPackage(package
, &flags
);
348 if (NS_SUCCEEDED(rv
)) {
349 *aResult
= !!(flags
& REMOTE_ALLOWED
);
355 nsChromeRegistry::MustLoadURLRemotely(nsIURI
* aURI
, bool* aResult
) {
360 NS_ASSERTION(aURI
->SchemeIs("chrome"),
361 "Non-chrome URI passed to MustLoadURLRemotely!");
363 nsCOMPtr
<nsIURL
> url
= do_QueryInterface(aURI
);
365 NS_ERROR("Chrome URL doesn't implement nsIURL.");
366 return NS_ERROR_UNEXPECTED
;
369 nsAutoCString package
;
370 rv
= url
->GetHostPort(package
);
371 NS_ENSURE_SUCCESS(rv
, rv
);
374 rv
= GetFlagsFromPackage(package
, &flags
);
376 if (NS_SUCCEEDED(rv
)) {
377 *aResult
= !!(flags
& REMOTE_REQUIRED
);
382 already_AddRefed
<nsChromeRegistry
> nsChromeRegistry::GetSingleton() {
383 if (gChromeRegistry
) {
384 RefPtr
<nsChromeRegistry
> registry
= gChromeRegistry
;
385 return registry
.forget();
388 RefPtr
<nsChromeRegistry
> cr
;
389 if (GeckoProcessType_Content
== XRE_GetProcessType())
390 cr
= new nsChromeRegistryContent();
392 cr
= new nsChromeRegistryChrome();
394 if (NS_FAILED(cr
->Init())) return nullptr;