Source code

Revision control

Other Tools

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/. */
6
7
#include "nsChromeRegistry.h"
8
#include "nsChromeRegistryChrome.h"
9
#include "nsChromeRegistryContent.h"
10
11
#include "nsCOMPtr.h"
12
#include "nsError.h"
13
#include "nsEscape.h"
14
#include "nsNetUtil.h"
15
#include "nsString.h"
16
#include "nsQueryObject.h"
17
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"
29
30
nsChromeRegistry* nsChromeRegistry::gChromeRegistry;
31
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;
38
39
////////////////////////////////////////////////////////////////////////////////
40
41
void nsChromeRegistry::LogMessage(const char* aMsg, ...) {
42
nsCOMPtr<nsIConsoleService> console(
43
do_GetService(NS_CONSOLESERVICE_CONTRACTID));
44
if (!console) return;
45
46
va_list args;
47
va_start(args, aMsg);
48
mozilla::SmprintfPointer formatted = mozilla::Vsmprintf(aMsg, args);
49
va_end(args);
50
if (!formatted) return;
51
52
console->LogStringMessage(NS_ConvertUTF8toUTF16(formatted.get()).get());
53
}
54
55
void nsChromeRegistry::LogMessageWithContext(nsIURI* aURL, uint32_t aLineNumber,
56
uint32_t flags, const char* aMsg,
57
...) {
58
nsresult rv;
59
60
nsCOMPtr<nsIConsoleService> console(
61
do_GetService(NS_CONSOLESERVICE_CONTRACTID));
62
63
nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
64
if (!console || !error) return;
65
66
va_list args;
67
va_start(args, aMsg);
68
mozilla::SmprintfPointer formatted = mozilla::Vsmprintf(aMsg, args);
69
va_end(args);
70
if (!formatted) return;
71
72
nsCString spec;
73
if (aURL) aURL->GetSpec(spec);
74
75
rv = error->Init(
76
NS_ConvertUTF8toUTF16(formatted.get()), NS_ConvertUTF8toUTF16(spec),
77
EmptyString(), aLineNumber, 0, flags, "chrome registration",
78
false /* from private window */, true /* from chrome context */);
79
80
if (NS_FAILED(rv)) return;
81
82
console->LogMessage(error);
83
}
84
85
nsChromeRegistry::~nsChromeRegistry() { gChromeRegistry = nullptr; }
86
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)
94
NS_INTERFACE_MAP_END
95
96
NS_IMPL_ADDREF(nsChromeRegistry)
97
NS_IMPL_RELEASE(nsChromeRegistry)
98
99
////////////////////////////////////////////////////////////////////////////////
100
// nsIChromeRegistry methods:
101
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;
109
}
110
nsCOMPtr<nsIChromeRegistry> registry = gChromeRegistry;
111
return registry.forget();
112
}
113
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;
120
121
mInitialized = true;
122
123
return NS_OK;
124
}
125
126
nsresult nsChromeRegistry::GetProviderAndPath(nsIURI* aChromeURL,
127
nsACString& aProvider,
128
nsACString& aPath) {
129
nsresult rv;
130
131
NS_ASSERTION(aChromeURL->SchemeIs("chrome"), "Non-chrome URI?");
132
133
nsAutoCString path;
134
rv = aChromeURL->GetPathQueryRef(path);
135
NS_ENSURE_SUCCESS(rv, rv);
136
137
if (path.Length() < 3) {
138
LogMessage("Invalid chrome URI: %s", path.get());
139
return NS_ERROR_FAILURE;
140
}
141
142
path.SetLength(nsUnescapeCount(path.BeginWriting()));
143
NS_ASSERTION(path.First() == '/', "Path should always begin with a slash!");
144
145
int32_t slash = path.FindChar('/', 1);
146
if (slash == 1) {
147
LogMessage("Invalid chrome URI: %s", path.get());
148
return NS_ERROR_FAILURE;
149
}
150
151
if (slash == -1) {
152
aPath.Truncate();
153
} else {
154
if (slash == (int32_t)path.Length() - 1)
155
aPath.Truncate();
156
else
157
aPath.Assign(path.get() + slash + 1, path.Length() - slash - 1);
158
159
--slash;
160
}
161
162
aProvider.Assign(path.get() + 1, slash);
163
return NS_OK;
164
}
165
166
nsresult nsChromeRegistry::Canonify(nsCOMPtr<nsIURI>& aChromeURL) {
167
NS_NAMED_LITERAL_CSTRING(kSlash, "/");
168
169
nsresult rv;
170
171
nsAutoCString provider, path;
172
rv = GetProviderAndPath(aChromeURL, provider, path);
173
NS_ENSURE_SUCCESS(rv, rv);
174
175
if (path.IsEmpty()) {
176
nsAutoCString package;
177
rv = aChromeURL->GetHost(package);
178
NS_ENSURE_SUCCESS(rv, rv);
179
180
// we re-use the "path" local string to build a new URL path
181
path.Assign(kSlash + provider + kSlash + package);
182
if (provider.EqualsLiteral("content")) {
183
path.AppendLiteral(".xul");
184
} else if (provider.EqualsLiteral("locale")) {
185
path.AppendLiteral(".dtd");
186
} else if (provider.EqualsLiteral("skin")) {
187
path.AppendLiteral(".css");
188
} else {
189
return NS_ERROR_INVALID_ARG;
190
}
191
return NS_MutateURI(aChromeURL).SetPathQueryRef(path).Finalize(aChromeURL);
192
} else {
193
// prevent directory traversals ("..")
194
// path is already unescaped once, but uris can get unescaped twice
195
const char* pos = path.BeginReading();
196
const char* end = path.EndReading();
197
// Must start with [a-zA-Z0-9].
198
if (!('a' <= *pos && *pos <= 'z') && !('A' <= *pos && *pos <= 'Z') &&
199
!('0' <= *pos && *pos <= '9')) {
200
return NS_ERROR_DOM_BAD_URI;
201
}
202
while (pos < end) {
203
switch (*pos) {
204
case ':':
205
return NS_ERROR_DOM_BAD_URI;
206
case '.':
207
if (pos[1] == '.') return NS_ERROR_DOM_BAD_URI;
208
break;
209
case '%':
210
// chrome: URIs with double-escapes are trying to trick us.
211
// watch for %2e, and %25 in case someone triple unescapes
212
if (pos[1] == '2' &&
213
(pos[2] == 'e' || pos[2] == 'E' || pos[2] == '5'))
214
return NS_ERROR_DOM_BAD_URI;
215
break;
216
case '?':
217
case '#':
218
pos = end;
219
continue;
220
}
221
++pos;
222
}
223
}
224
225
return NS_OK;
226
}
227
228
NS_IMETHODIMP
229
nsChromeRegistry::ConvertChromeURL(nsIURI* aChromeURI, nsIURI** aResult) {
230
nsresult rv;
231
if (NS_WARN_IF(!aChromeURI)) {
232
return NS_ERROR_INVALID_ARG;
233
}
234
235
if (mOverrideTable.Get(aChromeURI, aResult)) return NS_OK;
236
237
nsCOMPtr<nsIURL> chromeURL(do_QueryInterface(aChromeURI));
238
NS_ENSURE_TRUE(chromeURL, NS_NOINTERFACE);
239
240
nsAutoCString package, provider, path;
241
rv = chromeURL->GetHostPort(package);
242
NS_ENSURE_SUCCESS(rv, rv);
243
244
rv = GetProviderAndPath(chromeURL, provider, path);
245
NS_ENSURE_SUCCESS(rv, rv);
246
247
nsIURI* baseURI = GetBaseURIFromPackage(package, provider, path);
248
249
uint32_t flags;
250
rv = GetFlagsFromPackage(package, &flags);
251
if (NS_FAILED(rv)) return rv;
252
253
if (!baseURI) {
254
LogMessage("No chrome package registered for chrome://%s/%s/%s",
255
package.get(), provider.get(), path.get());
256
return NS_ERROR_FILE_NOT_FOUND;
257
}
258
259
return NS_NewURI(aResult, path, nullptr, baseURI);
260
}
261
262
////////////////////////////////////////////////////////////////////////
263
264
void nsChromeRegistry::FlushAllCaches() {
265
nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
266
NS_ASSERTION(obsSvc, "Couldn't get observer service.");
267
268
obsSvc->NotifyObservers((nsIChromeRegistry*)this, NS_CHROME_FLUSH_TOPIC,
269
nullptr);
270
}
271
272
NS_IMETHODIMP
273
nsChromeRegistry::AllowScriptsForPackage(nsIURI* aChromeURI, bool* aResult) {
274
nsresult rv;
275
*aResult = false;
276
277
NS_ASSERTION(aChromeURI->SchemeIs("chrome"),
278
"Non-chrome URI passed to AllowScriptsForPackage!");
279
280
nsCOMPtr<nsIURL> url(do_QueryInterface(aChromeURI));
281
NS_ENSURE_TRUE(url, NS_NOINTERFACE);
282
283
nsAutoCString provider, file;
284
rv = GetProviderAndPath(url, provider, file);
285
NS_ENSURE_SUCCESS(rv, rv);
286
287
if (!provider.EqualsLiteral("skin")) *aResult = true;
288
289
return NS_OK;
290
}
291
292
NS_IMETHODIMP
293
nsChromeRegistry::AllowContentToAccess(nsIURI* aURI, bool* aResult) {
294
nsresult rv;
295
296
*aResult = false;
297
298
NS_ASSERTION(aURI->SchemeIs("chrome"),
299
"Non-chrome URI passed to AllowContentToAccess!");
300
301
nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
302
if (!url) {
303
NS_ERROR("Chrome URL doesn't implement nsIURL.");
304
return NS_ERROR_UNEXPECTED;
305
}
306
307
nsAutoCString package;
308
rv = url->GetHostPort(package);
309
NS_ENSURE_SUCCESS(rv, rv);
310
311
uint32_t flags;
312
rv = GetFlagsFromPackage(package, &flags);
313
314
if (NS_SUCCEEDED(rv)) {
315
*aResult = !!(flags & CONTENT_ACCESSIBLE);
316
}
317
return NS_OK;
318
}
319
320
NS_IMETHODIMP
321
nsChromeRegistry::CanLoadURLRemotely(nsIURI* aURI, bool* aResult) {
322
nsresult rv;
323
324
*aResult = false;
325
326
NS_ASSERTION(aURI->SchemeIs("chrome"),
327
"Non-chrome URI passed to CanLoadURLRemotely!");
328
329
nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
330
if (!url) {
331
NS_ERROR("Chrome URL doesn't implement nsIURL.");
332
return NS_ERROR_UNEXPECTED;
333
}
334
335
nsAutoCString package;
336
rv = url->GetHostPort(package);
337
NS_ENSURE_SUCCESS(rv, rv);
338
339
uint32_t flags;
340
rv = GetFlagsFromPackage(package, &flags);
341
342
if (NS_SUCCEEDED(rv)) {
343
*aResult = !!(flags & REMOTE_ALLOWED);
344
}
345
return NS_OK;
346
}
347
348
NS_IMETHODIMP
349
nsChromeRegistry::MustLoadURLRemotely(nsIURI* aURI, bool* aResult) {
350
nsresult rv;
351
352
*aResult = false;
353
354
NS_ASSERTION(aURI->SchemeIs("chrome"),
355
"Non-chrome URI passed to MustLoadURLRemotely!");
356
357
nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
358
if (!url) {
359
NS_ERROR("Chrome URL doesn't implement nsIURL.");
360
return NS_ERROR_UNEXPECTED;
361
}
362
363
nsAutoCString package;
364
rv = url->GetHostPort(package);
365
NS_ENSURE_SUCCESS(rv, rv);
366
367
uint32_t flags;
368
rv = GetFlagsFromPackage(package, &flags);
369
370
if (NS_SUCCEEDED(rv)) {
371
*aResult = !!(flags & REMOTE_REQUIRED);
372
}
373
return NS_OK;
374
}
375
376
already_AddRefed<nsChromeRegistry> nsChromeRegistry::GetSingleton() {
377
if (gChromeRegistry) {
378
RefPtr<nsChromeRegistry> registry = gChromeRegistry;
379
return registry.forget();
380
}
381
382
RefPtr<nsChromeRegistry> cr;
383
if (GeckoProcessType_Content == XRE_GetProcessType())
384
cr = new nsChromeRegistryContent();
385
else
386
cr = new nsChromeRegistryChrome();
387
388
if (NS_FAILED(cr->Init())) return nullptr;
389
390
return cr.forget();
391
}