Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
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 "nsAboutRedirector.h"
8
#include "nsNetUtil.h"
9
#include "nsAboutProtocolUtils.h"
10
#include "nsBaseChannel.h"
11
#include "mozilla/ArrayUtils.h"
12
#include "nsIProtocolHandler.h"
13
#include "mozilla/Preferences.h"
14
15
#define ABOUT_CONFIG_ENABLED_PREF "general.aboutConfig.enable"
16
17
NS_IMPL_ISUPPORTS(nsAboutRedirector, nsIAboutModule)
18
19
struct RedirEntry {
20
const char* id;
21
const char* url;
22
uint32_t flags;
23
};
24
25
class CrashChannel final : public nsBaseChannel {
26
public:
27
explicit CrashChannel(nsIURI* aURI) { SetURI(aURI); }
28
29
nsresult OpenContentStream(bool async, nsIInputStream** stream,
30
nsIChannel** channel) override {
31
nsAutoCString spec;
32
mURI->GetSpec(spec);
33
34
if (spec.EqualsASCII("about:crashparent") && XRE_IsParentProcess()) {
35
MOZ_CRASH("Crash via about:crashparent");
36
}
37
38
if (spec.EqualsASCII("about:crashcontent") && XRE_IsContentProcess()) {
39
MOZ_CRASH("Crash via about:crashcontent");
40
}
41
42
NS_WARNING("Unhandled about:crash* URI or wrong process");
43
return NS_ERROR_NOT_IMPLEMENTED;
44
}
45
46
protected:
47
virtual ~CrashChannel() = default;
48
};
49
50
/*
51
Entries which do not have URI_SAFE_FOR_UNTRUSTED_CONTENT will run with chrome
52
privileges. This is potentially dangerous. Please use
53
URI_SAFE_FOR_UNTRUSTED_CONTENT in the third argument to each map item below
54
unless your about: page really needs chrome privileges. Security review is
55
required before adding new map entries without
56
URI_SAFE_FOR_UNTRUSTED_CONTENT.
57
58
URI_SAFE_FOR_UNTRUSTED_CONTENT is not enough to let web pages load that page,
59
for that you need MAKE_LINKABLE.
60
*/
61
static const RedirEntry kRedirMap[] = {
64
nsIAboutModule::ALLOW_SCRIPT},
66
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT},
68
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
69
nsIAboutModule::ALLOW_SCRIPT},
70
#ifndef MOZ_BUILD_APP_IS_BROWSER
72
#endif
73
#ifdef MOZ_CRASHREPORTER
74
{"crashes", "chrome://global/content/crashes.html", 0},
75
#endif
77
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT},
79
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT},
81
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
82
// Linkable for testing reasons.
83
nsIAboutModule::MAKE_LINKABLE},
85
nsIAboutModule::ALLOW_SCRIPT},
87
nsIAboutModule::ALLOW_SCRIPT |
88
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
89
nsIAboutModule::URI_MUST_LOAD_IN_CHILD |
90
nsIAboutModule::URI_CAN_LOAD_IN_PRIVILEGEDABOUT_PROCESS},
92
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT},
94
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
95
nsIAboutModule::URI_CAN_LOAD_IN_CHILD | nsIAboutModule::ALLOW_SCRIPT |
96
nsIAboutModule::HIDE_FROM_ABOUTABOUT},
98
nsIAboutModule::ALLOW_SCRIPT},
100
nsIAboutModule::ALLOW_SCRIPT},
102
nsIAboutModule::URI_MUST_LOAD_IN_CHILD},
103
// about:serviceworkers always wants to load in the parent process because
104
// when dom.serviceWorkers.parent_intercept is set to true (the new default)
105
// then the only place nsIServiceWorkerManager has any data is in the
106
// parent process.
107
//
108
// There is overlap without about:debugging, but about:debugging is not
109
// available on mobile at this time, and it's useful to be able to know if
110
// a ServiceWorker is registered directly from the mobile browser without
111
// having to connect the device to a desktop machine and all that entails.
113
nsIAboutModule::ALLOW_SCRIPT},
114
#ifndef ANDROID
116
nsIAboutModule::ALLOW_SCRIPT},
117
#endif
118
// about:srcdoc is unresolvable by specification. It is included here
119
// because the security manager would disallow srcdoc iframes otherwise.
120
{"srcdoc", "about:blank",
121
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
122
nsIAboutModule::HIDE_FROM_ABOUTABOUT |
123
// Needs to be linkable so content can touch its own srcdoc frames
124
nsIAboutModule::MAKE_LINKABLE | nsIAboutModule::URI_CAN_LOAD_IN_CHILD},
126
nsIAboutModule::ALLOW_SCRIPT},
128
nsIAboutModule::ALLOW_SCRIPT},
130
nsIAboutModule::ALLOW_SCRIPT},
132
nsIAboutModule::ALLOW_SCRIPT},
133
{"printpreview", "about:blank",
134
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
135
nsIAboutModule::HIDE_FROM_ABOUTABOUT |
136
nsIAboutModule::URI_CAN_LOAD_IN_CHILD},
137
{"crashparent", "about:blank", nsIAboutModule::HIDE_FROM_ABOUTABOUT},
138
{"crashcontent", "about:blank",
139
nsIAboutModule::HIDE_FROM_ABOUTABOUT |
140
nsIAboutModule::URI_CAN_LOAD_IN_CHILD |
141
nsIAboutModule::URI_MUST_LOAD_IN_CHILD}};
142
static const int kRedirTotal = mozilla::ArrayLength(kRedirMap);
143
144
NS_IMETHODIMP
145
nsAboutRedirector::NewChannel(nsIURI* aURI, nsILoadInfo* aLoadInfo,
146
nsIChannel** aResult) {
147
NS_ENSURE_ARG_POINTER(aURI);
148
NS_ENSURE_ARG_POINTER(aLoadInfo);
149
NS_ASSERTION(aResult, "must not be null");
150
151
nsAutoCString path;
152
nsresult rv = NS_GetAboutModuleName(aURI, path);
153
NS_ENSURE_SUCCESS(rv, rv);
154
155
nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
156
NS_ENSURE_SUCCESS(rv, rv);
157
158
if (path.EqualsASCII("crashparent") || path.EqualsASCII("crashcontent")) {
159
bool isExternal;
160
aLoadInfo->GetLoadTriggeredFromExternal(&isExternal);
161
if (isExternal) {
162
return NS_ERROR_NOT_AVAILABLE;
163
}
164
165
nsCOMPtr<nsIChannel> channel = new CrashChannel(aURI);
166
channel->SetLoadInfo(aLoadInfo);
167
channel.forget(aResult);
168
return NS_OK;
169
}
170
171
if (path.EqualsASCII("config") &&
172
!mozilla::Preferences::GetBool(ABOUT_CONFIG_ENABLED_PREF, true)) {
173
return NS_ERROR_NOT_AVAILABLE;
174
}
175
176
for (int i = 0; i < kRedirTotal; i++) {
177
if (!strcmp(path.get(), kRedirMap[i].id)) {
178
nsCOMPtr<nsIChannel> tempChannel;
179
nsCOMPtr<nsIURI> tempURI;
180
rv = NS_NewURI(getter_AddRefs(tempURI), kRedirMap[i].url);
181
NS_ENSURE_SUCCESS(rv, rv);
182
183
rv = NS_NewChannelInternal(getter_AddRefs(tempChannel), tempURI,
184
aLoadInfo);
185
NS_ENSURE_SUCCESS(rv, rv);
186
187
// If tempURI links to an external URI (i.e. something other than
188
// chrome:// or resource://) then set result principal URI on the
189
// load info which forces the channel principal to reflect the displayed
190
// URL rather then being the systemPrincipal.
191
bool isUIResource = false;
192
rv = NS_URIChainHasFlags(tempURI, nsIProtocolHandler::URI_IS_UI_RESOURCE,
193
&isUIResource);
194
NS_ENSURE_SUCCESS(rv, rv);
195
196
bool isAboutBlank = NS_IsAboutBlank(tempURI);
197
198
if (!isUIResource && !isAboutBlank) {
199
aLoadInfo->SetResultPrincipalURI(tempURI);
200
}
201
202
tempChannel->SetOriginalURI(aURI);
203
204
tempChannel.forget(aResult);
205
return rv;
206
}
207
}
208
209
NS_ERROR("nsAboutRedirector called for unknown case");
210
return NS_ERROR_ILLEGAL_VALUE;
211
}
212
213
NS_IMETHODIMP
214
nsAboutRedirector::GetURIFlags(nsIURI* aURI, uint32_t* aResult) {
215
NS_ENSURE_ARG_POINTER(aURI);
216
217
nsAutoCString name;
218
nsresult rv = NS_GetAboutModuleName(aURI, name);
219
NS_ENSURE_SUCCESS(rv, rv);
220
221
for (int i = 0; i < kRedirTotal; i++) {
222
if (name.EqualsASCII(kRedirMap[i].id)) {
223
*aResult = kRedirMap[i].flags;
224
return NS_OK;
225
}
226
}
227
228
NS_ERROR("nsAboutRedirector called for unknown case");
229
return NS_ERROR_ILLEGAL_VALUE;
230
}
231
232
nsresult nsAboutRedirector::Create(nsISupports* aOuter, REFNSIID aIID,
233
void** aResult) {
234
RefPtr<nsAboutRedirector> about = new nsAboutRedirector();
235
return about->QueryInterface(aIID, aResult);
236
}