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"
12 #include "nsComponentManagerUtils.h"
15 #include "nsNetUtil.h"
17 #include "nsQueryObject.h"
19 #include "mozilla/dom/URL.h"
20 #include "nsIConsoleService.h"
21 #include "mozilla/dom/Document.h"
22 #include "nsIObserverService.h"
23 #include "nsIScriptError.h"
24 #include "mozilla/Preferences.h"
25 #include "mozilla/PresShell.h"
26 #include "mozilla/Printf.h"
27 #include "mozilla/StyleSheet.h"
28 #include "mozilla/StyleSheetInlines.h"
29 #include "mozilla/dom/Location.h"
31 nsChromeRegistry
* nsChromeRegistry::gChromeRegistry
;
33 // DO NOT use namespace mozilla; it'll break due to a naming conflict between
34 // mozilla::TextRange and a TextRange in OSX headers.
35 using mozilla::PresShell
;
36 using mozilla::StyleSheet
;
37 using mozilla::dom::Document
;
38 using mozilla::dom::Location
;
40 ////////////////////////////////////////////////////////////////////////////////
42 void nsChromeRegistry::LogMessage(const char* aMsg
, ...) {
43 nsCOMPtr
<nsIConsoleService
> console(
44 do_GetService(NS_CONSOLESERVICE_CONTRACTID
));
49 mozilla::SmprintfPointer formatted
= mozilla::Vsmprintf(aMsg
, args
);
51 if (!formatted
) return;
53 console
->LogStringMessage(NS_ConvertUTF8toUTF16(formatted
.get()).get());
56 void nsChromeRegistry::LogMessageWithContext(nsIURI
* aURL
, uint32_t aLineNumber
,
57 uint32_t flags
, const char* aMsg
,
61 nsCOMPtr
<nsIConsoleService
> console(
62 do_GetService(NS_CONSOLESERVICE_CONTRACTID
));
64 nsCOMPtr
<nsIScriptError
> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID
));
65 if (!console
|| !error
) return;
69 mozilla::SmprintfPointer formatted
= mozilla::Vsmprintf(aMsg
, args
);
71 if (!formatted
) return;
74 if (aURL
) aURL
->GetSpec(spec
);
76 rv
= error
->Init(NS_ConvertUTF8toUTF16(formatted
.get()),
77 NS_ConvertUTF8toUTF16(spec
), u
""_ns
, aLineNumber
, 0, flags
,
78 "chrome registration"_ns
, false /* from private window */,
79 true /* from chrome context */);
81 if (NS_FAILED(rv
)) return;
83 console
->LogMessage(error
);
86 nsChromeRegistry::~nsChromeRegistry() { gChromeRegistry
= nullptr; }
88 NS_INTERFACE_MAP_BEGIN(nsChromeRegistry
)
89 NS_INTERFACE_MAP_ENTRY(nsIChromeRegistry
)
90 NS_INTERFACE_MAP_ENTRY(nsIXULChromeRegistry
)
91 NS_INTERFACE_MAP_ENTRY(nsIToolkitChromeRegistry
)
92 NS_INTERFACE_MAP_ENTRY(nsIObserver
)
93 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
94 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIChromeRegistry
)
97 NS_IMPL_ADDREF(nsChromeRegistry
)
98 NS_IMPL_RELEASE(nsChromeRegistry
)
100 ////////////////////////////////////////////////////////////////////////////////
101 // nsIChromeRegistry methods:
103 already_AddRefed
<nsIChromeRegistry
> nsChromeRegistry::GetService() {
104 if (!gChromeRegistry
) {
105 // We don't actually want this ref, we just want the service to
106 // initialize if it hasn't already.
107 nsCOMPtr
<nsIChromeRegistry
> reg(
108 do_GetService(NS_CHROMEREGISTRY_CONTRACTID
));
109 if (!gChromeRegistry
) return nullptr;
111 nsCOMPtr
<nsIChromeRegistry
> registry
= gChromeRegistry
;
112 return registry
.forget();
115 nsresult
nsChromeRegistry::Init() {
116 // This initialization process is fairly complicated and may cause reentrant
117 // getservice calls to resolve chrome URIs (especially locale files). We
118 // don't want that, so we inform the protocol handler about our existence
119 // before we are actually fully initialized.
120 gChromeRegistry
= this;
127 nsresult
nsChromeRegistry::GetProviderAndPath(nsIURI
* aChromeURL
,
128 nsACString
& aProvider
,
132 NS_ASSERTION(aChromeURL
->SchemeIs("chrome"), "Non-chrome URI?");
135 rv
= aChromeURL
->GetPathQueryRef(path
);
136 NS_ENSURE_SUCCESS(rv
, rv
);
138 if (path
.Length() < 3) {
140 LogMessage("Invalid chrome URI (need path): %s",
141 aChromeURL
->GetSpecOrDefault().get());
143 return NS_ERROR_FAILURE
;
146 path
.SetLength(nsUnescapeCount(path
.BeginWriting()));
147 NS_ASSERTION(path
.First() == '/', "Path should always begin with a slash!");
149 int32_t slash
= path
.FindChar('/', 1);
152 LogMessage("Invalid chrome URI (path cannot start with another slash): %s",
153 aChromeURL
->GetSpecOrDefault().get());
155 return NS_ERROR_FAILURE
;
161 if (slash
== (int32_t)path
.Length() - 1)
164 aPath
.Assign(path
.get() + slash
+ 1, path
.Length() - slash
- 1);
169 aProvider
.Assign(path
.get() + 1, slash
);
173 nsresult
nsChromeRegistry::Canonify(nsCOMPtr
<nsIURI
>& aChromeURL
) {
174 constexpr auto kSlash
= "/"_ns
;
178 nsAutoCString provider
, path
;
179 rv
= GetProviderAndPath(aChromeURL
, provider
, path
);
180 NS_ENSURE_SUCCESS(rv
, rv
);
182 if (path
.IsEmpty()) {
183 nsAutoCString package
;
184 rv
= aChromeURL
->GetHost(package
);
185 NS_ENSURE_SUCCESS(rv
, rv
);
187 // we re-use the "path" local string to build a new URL path
188 path
.Assign(kSlash
+ provider
+ kSlash
+ package
);
189 if (provider
.EqualsLiteral("content")) {
190 path
.AppendLiteral(".xul");
191 } else if (provider
.EqualsLiteral("locale")) {
192 path
.AppendLiteral(".dtd");
193 } else if (provider
.EqualsLiteral("skin")) {
194 path
.AppendLiteral(".css");
196 return NS_ERROR_INVALID_ARG
;
198 return NS_MutateURI(aChromeURL
).SetPathQueryRef(path
).Finalize(aChromeURL
);
201 // prevent directory traversals ("..")
202 // path is already unescaped once, but uris can get unescaped twice
203 const char* pos
= path
.BeginReading();
204 const char* end
= path
.EndReading();
205 // Must start with [a-zA-Z0-9].
206 if (!('a' <= *pos
&& *pos
<= 'z') && !('A' <= *pos
&& *pos
<= 'Z') &&
207 !('0' <= *pos
&& *pos
<= '9')) {
208 return NS_ERROR_DOM_BAD_URI
;
213 return NS_ERROR_DOM_BAD_URI
;
216 return NS_ERROR_DOM_BAD_URI
;
220 // chrome: URIs with double-escapes are trying to trick us.
221 // watch for %2e, and %25 in case someone triple unescapes
223 (pos
[2] == 'e' || pos
[2] == 'E' || pos
[2] == '5')) {
224 return NS_ERROR_DOM_BAD_URI
;
239 nsChromeRegistry::ConvertChromeURL(nsIURI
* aChromeURI
, nsIURI
** aResult
) {
241 if (NS_WARN_IF(!aChromeURI
)) {
242 return NS_ERROR_INVALID_ARG
;
245 if (mOverrideTable
.Get(aChromeURI
, aResult
)) return NS_OK
;
247 nsCOMPtr
<nsIURL
> chromeURL(do_QueryInterface(aChromeURI
));
248 NS_ENSURE_TRUE(chromeURL
, NS_NOINTERFACE
);
250 nsAutoCString package
, provider
, path
;
251 rv
= chromeURL
->GetHostPort(package
);
252 NS_ENSURE_SUCCESS(rv
, rv
);
254 rv
= GetProviderAndPath(chromeURL
, provider
, path
);
255 NS_ENSURE_SUCCESS(rv
, rv
);
257 nsIURI
* baseURI
= GetBaseURIFromPackage(package
, provider
, path
);
260 rv
= GetFlagsFromPackage(package
, &flags
);
261 if (NS_FAILED(rv
)) return rv
;
264 LogMessage("No chrome package registered for chrome://%s/%s/%s",
265 package
.get(), provider
.get(), path
.get());
266 return NS_ERROR_FILE_NOT_FOUND
;
269 return NS_NewURI(aResult
, path
, nullptr, baseURI
);
272 ////////////////////////////////////////////////////////////////////////
274 void nsChromeRegistry::FlushAllCaches() {
275 nsCOMPtr
<nsIObserverService
> obsSvc
= mozilla::services::GetObserverService();
276 NS_ASSERTION(obsSvc
, "Couldn't get observer service.");
278 obsSvc
->NotifyObservers((nsIChromeRegistry
*)this, NS_CHROME_FLUSH_TOPIC
,
283 nsChromeRegistry::AllowScriptsForPackage(nsIURI
* aChromeURI
, bool* aResult
) {
287 NS_ASSERTION(aChromeURI
->SchemeIs("chrome"),
288 "Non-chrome URI passed to AllowScriptsForPackage!");
290 nsCOMPtr
<nsIURL
> url(do_QueryInterface(aChromeURI
));
291 NS_ENSURE_TRUE(url
, NS_NOINTERFACE
);
293 nsAutoCString provider
, file
;
294 rv
= GetProviderAndPath(url
, provider
, file
);
295 NS_ENSURE_SUCCESS(rv
, rv
);
297 if (!provider
.EqualsLiteral("skin")) *aResult
= true;
303 nsChromeRegistry::AllowContentToAccess(nsIURI
* aURI
, bool* aResult
) {
308 NS_ASSERTION(aURI
->SchemeIs("chrome"),
309 "Non-chrome URI passed to AllowContentToAccess!");
311 nsCOMPtr
<nsIURL
> url
= do_QueryInterface(aURI
);
313 NS_ERROR("Chrome URL doesn't implement nsIURL.");
314 return NS_ERROR_UNEXPECTED
;
317 nsAutoCString package
;
318 rv
= url
->GetHostPort(package
);
319 NS_ENSURE_SUCCESS(rv
, rv
);
322 rv
= GetFlagsFromPackage(package
, &flags
);
324 if (NS_SUCCEEDED(rv
)) {
325 *aResult
= !!(flags
& CONTENT_ACCESSIBLE
);
331 nsChromeRegistry::CanLoadURLRemotely(nsIURI
* aURI
, bool* aResult
) {
336 NS_ASSERTION(aURI
->SchemeIs("chrome"),
337 "Non-chrome URI passed to CanLoadURLRemotely!");
339 nsCOMPtr
<nsIURL
> url
= do_QueryInterface(aURI
);
341 NS_ERROR("Chrome URL doesn't implement nsIURL.");
342 return NS_ERROR_UNEXPECTED
;
345 nsAutoCString package
;
346 rv
= url
->GetHostPort(package
);
347 NS_ENSURE_SUCCESS(rv
, rv
);
350 rv
= GetFlagsFromPackage(package
, &flags
);
352 if (NS_SUCCEEDED(rv
)) {
353 *aResult
= !!(flags
& REMOTE_ALLOWED
);
359 nsChromeRegistry::MustLoadURLRemotely(nsIURI
* aURI
, bool* aResult
) {
364 NS_ASSERTION(aURI
->SchemeIs("chrome"),
365 "Non-chrome URI passed to MustLoadURLRemotely!");
367 nsCOMPtr
<nsIURL
> url
= do_QueryInterface(aURI
);
369 NS_ERROR("Chrome URL doesn't implement nsIURL.");
370 return NS_ERROR_UNEXPECTED
;
373 nsAutoCString package
;
374 rv
= url
->GetHostPort(package
);
375 NS_ENSURE_SUCCESS(rv
, rv
);
378 rv
= GetFlagsFromPackage(package
, &flags
);
380 if (NS_SUCCEEDED(rv
)) {
381 *aResult
= !!(flags
& REMOTE_REQUIRED
);
386 already_AddRefed
<nsChromeRegistry
> nsChromeRegistry::GetSingleton() {
387 if (gChromeRegistry
) {
388 RefPtr
<nsChromeRegistry
> registry
= gChromeRegistry
;
389 return registry
.forget();
392 RefPtr
<nsChromeRegistry
> cr
;
393 if (GeckoProcessType_Content
== XRE_GetProcessType())
394 cr
= new nsChromeRegistryContent();
396 cr
= new nsChromeRegistryChrome();
398 if (NS_FAILED(cr
->Init())) return nullptr;