/src/mozilla-central/netwerk/base/nsIOService.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* vim:set ts=4 sw=4 cindent et: */ |
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 "mozilla/DebugOnly.h" |
8 | | |
9 | | #include "nsIOService.h" |
10 | | #include "nsIProtocolHandler.h" |
11 | | #include "nsIFileProtocolHandler.h" |
12 | | #include "nscore.h" |
13 | | #include "nsIURI.h" |
14 | | #include "prprf.h" |
15 | | #include "nsIErrorService.h" |
16 | | #include "netCore.h" |
17 | | #include "nsIObserverService.h" |
18 | | #include "nsIPrefService.h" |
19 | | #include "nsXPCOM.h" |
20 | | #include "nsIProxiedProtocolHandler.h" |
21 | | #include "nsIProxyInfo.h" |
22 | | #include "nsEscape.h" |
23 | | #include "nsNetUtil.h" |
24 | | #include "nsNetCID.h" |
25 | | #include "nsCRT.h" |
26 | | #include "nsSecCheckWrapChannel.h" |
27 | | #include "nsSimpleNestedURI.h" |
28 | | #include "nsTArray.h" |
29 | | #include "nsIConsoleService.h" |
30 | | #include "nsIUploadChannel2.h" |
31 | | #include "nsXULAppAPI.h" |
32 | | #include "nsIScriptSecurityManager.h" |
33 | | #include "nsIProtocolProxyCallback.h" |
34 | | #include "nsICancelable.h" |
35 | | #include "nsINetworkLinkService.h" |
36 | | #include "nsPISocketTransportService.h" |
37 | | #include "nsAsyncRedirectVerifyHelper.h" |
38 | | #include "nsURLHelper.h" |
39 | | #include "nsIProtocolProxyService2.h" |
40 | | #include "MainThreadUtils.h" |
41 | | #include "nsINode.h" |
42 | | #include "nsIWidget.h" |
43 | | #include "nsThreadUtils.h" |
44 | | #include "mozilla/LoadInfo.h" |
45 | | #include "mozilla/net/NeckoCommon.h" |
46 | | #include "mozilla/Services.h" |
47 | | #include "mozilla/Telemetry.h" |
48 | | #include "mozilla/net/DNS.h" |
49 | | #include "mozilla/ipc/URIUtils.h" |
50 | | #include "mozilla/net/NeckoChild.h" |
51 | | #include "mozilla/net/NeckoParent.h" |
52 | | #include "mozilla/dom/ClientInfo.h" |
53 | | #include "mozilla/dom/ContentParent.h" |
54 | | #include "mozilla/dom/ServiceWorkerDescriptor.h" |
55 | | #include "mozilla/net/CaptivePortalService.h" |
56 | | #include "mozilla/Unused.h" |
57 | | #include "ReferrerPolicy.h" |
58 | | #include "nsContentSecurityManager.h" |
59 | | #include "nsContentUtils.h" |
60 | | |
61 | | namespace mozilla { |
62 | | namespace net { |
63 | | |
64 | | using mozilla::Maybe; |
65 | | using mozilla::dom::ClientInfo; |
66 | | using mozilla::dom::ServiceWorkerDescriptor; |
67 | | |
68 | 6 | #define PORT_PREF_PREFIX "network.security.ports." |
69 | 6 | #define PORT_PREF(x) PORT_PREF_PREFIX x |
70 | 0 | #define MANAGE_OFFLINE_STATUS_PREF "network.manage-offline-status" |
71 | 3 | #define OFFLINE_MIRRORS_CONNECTIVITY "network.offline-mirrors-connectivity" |
72 | | |
73 | | // Nb: these have been misnomers since bug 715770 removed the buffer cache. |
74 | | // "network.segment.count" and "network.segment.size" would be better names, |
75 | | // but the old names are still used to preserve backward compatibility. |
76 | 0 | #define NECKO_BUFFER_CACHE_COUNT_PREF "network.buffer.cache.count" |
77 | 0 | #define NECKO_BUFFER_CACHE_SIZE_PREF "network.buffer.cache.size" |
78 | 3 | #define NETWORK_NOTIFY_CHANGED_PREF "network.notify.changed" |
79 | 3 | #define NETWORK_CAPTIVE_PORTAL_PREF "network.captive-portal-service.enabled" |
80 | | |
81 | 3.05M | #define MAX_RECURSION_COUNT 50 |
82 | | |
83 | | nsIOService* gIOService; |
84 | | static bool gHasWarnedUploadChannel2; |
85 | | static bool gCaptivePortalEnabled = false; |
86 | | static LazyLogModule gIOServiceLog("nsIOService"); |
87 | | #undef LOG |
88 | 9 | #define LOG(args) MOZ_LOG(gIOServiceLog, LogLevel::Debug, args) |
89 | | |
90 | | // A general port blacklist. Connections to these ports will not be allowed |
91 | | // unless the protocol overrides. |
92 | | // |
93 | | // TODO: I am sure that there are more ports to be added. |
94 | | // This cut is based on the classic mozilla codebase |
95 | | |
96 | | int16_t gBadPortList[] = { |
97 | | 1, // tcpmux |
98 | | 7, // echo |
99 | | 9, // discard |
100 | | 11, // systat |
101 | | 13, // daytime |
102 | | 15, // netstat |
103 | | 17, // qotd |
104 | | 19, // chargen |
105 | | 20, // ftp-data |
106 | | 21, // ftp |
107 | | 22, // ssh |
108 | | 23, // telnet |
109 | | 25, // smtp |
110 | | 37, // time |
111 | | 42, // name |
112 | | 43, // nicname |
113 | | 53, // domain |
114 | | 77, // priv-rjs |
115 | | 79, // finger |
116 | | 87, // ttylink |
117 | | 95, // supdup |
118 | | 101, // hostriame |
119 | | 102, // iso-tsap |
120 | | 103, // gppitnp |
121 | | 104, // acr-nema |
122 | | 109, // pop2 |
123 | | 110, // pop3 |
124 | | 111, // sunrpc |
125 | | 113, // auth |
126 | | 115, // sftp |
127 | | 117, // uucp-path |
128 | | 119, // nntp |
129 | | 123, // ntp |
130 | | 135, // loc-srv / epmap |
131 | | 139, // netbios |
132 | | 143, // imap2 |
133 | | 179, // bgp |
134 | | 389, // ldap |
135 | | 427, // afp (alternate) |
136 | | 465, // smtp (alternate) |
137 | | 512, // print / exec |
138 | | 513, // login |
139 | | 514, // shell |
140 | | 515, // printer |
141 | | 526, // tempo |
142 | | 530, // courier |
143 | | 531, // chat |
144 | | 532, // netnews |
145 | | 540, // uucp |
146 | | 548, // afp |
147 | | 556, // remotefs |
148 | | 563, // nntp+ssl |
149 | | 587, // smtp (outgoing) |
150 | | 601, // syslog-conn |
151 | | 636, // ldap+ssl |
152 | | 993, // imap+ssl |
153 | | 995, // pop3+ssl |
154 | | 2049, // nfs |
155 | | 3659, // apple-sasl |
156 | | 4045, // lockd |
157 | | 6000, // x11 |
158 | | 6665, // irc (alternate) |
159 | | 6666, // irc (alternate) |
160 | | 6667, // irc (default) |
161 | | 6668, // irc (alternate) |
162 | | 6669, // irc (alternate) |
163 | | 6697, // irc+tls |
164 | | 0, // Sentinel value: This MUST be zero |
165 | | }; |
166 | | |
167 | | static const char kProfileChangeNetTeardownTopic[] = "profile-change-net-teardown"; |
168 | | static const char kProfileChangeNetRestoreTopic[] = "profile-change-net-restore"; |
169 | | static const char kProfileDoChange[] = "profile-do-change"; |
170 | | |
171 | | // Necko buffer defaults |
172 | | uint32_t nsIOService::gDefaultSegmentSize = 4096; |
173 | | uint32_t nsIOService::gDefaultSegmentCount = 24; |
174 | | |
175 | | bool nsIOService::sIsDataURIUniqueOpaqueOrigin = false; |
176 | | bool nsIOService::sBlockToplevelDataUriNavigations = false; |
177 | | bool nsIOService::sBlockFTPSubresources = false; |
178 | | |
179 | | //////////////////////////////////////////////////////////////////////////////// |
180 | | |
181 | | nsIOService::nsIOService() |
182 | | : mOffline(true) |
183 | | , mOfflineForProfileChange(false) |
184 | | , mManageLinkStatus(false) |
185 | | , mConnectivity(true) |
186 | | , mOfflineMirrorsConnectivity(true) |
187 | | , mSettingOffline(false) |
188 | | , mSetOfflineValue(false) |
189 | | , mShutdown(false) |
190 | | , mHttpHandlerAlreadyShutingDown(false) |
191 | | , mNetworkLinkServiceInitialized(false) |
192 | | , mChannelEventSinks(NS_CHANNEL_EVENT_SINK_CATEGORY) |
193 | | , mNetworkNotifyChanged(true) |
194 | | , mTotalRequests(0) |
195 | | , mCacheWon(0) |
196 | | , mNetWon(0) |
197 | | , mLastOfflineStateChange(PR_IntervalNow()) |
198 | | , mLastConnectivityChange(PR_IntervalNow()) |
199 | | , mLastNetworkLinkChange(PR_IntervalNow()) |
200 | | , mNetTearingDownStarted(0) |
201 | 3 | { |
202 | 3 | } |
203 | | |
204 | | static const char* gCallbackPrefs[] = { |
205 | | PORT_PREF_PREFIX, |
206 | | MANAGE_OFFLINE_STATUS_PREF, |
207 | | NECKO_BUFFER_CACHE_COUNT_PREF, |
208 | | NECKO_BUFFER_CACHE_SIZE_PREF, |
209 | | NETWORK_NOTIFY_CHANGED_PREF, |
210 | | NETWORK_CAPTIVE_PORTAL_PREF, |
211 | | nullptr, |
212 | | }; |
213 | | |
214 | | nsresult |
215 | | nsIOService::Init() |
216 | 3 | { |
217 | 3 | // XXX hack until xpidl supports error info directly (bug 13423) |
218 | 3 | nsCOMPtr<nsIErrorService> errorService = do_GetService(NS_ERRORSERVICE_CONTRACTID); |
219 | 3 | if (errorService) { |
220 | 3 | errorService->RegisterErrorStringBundle(NS_ERROR_MODULE_NETWORK, NECKO_MSGS_URL); |
221 | 3 | } |
222 | 3 | else |
223 | 3 | NS_WARNING("failed to get error service"); |
224 | 3 | |
225 | 3 | InitializeCaptivePortalService(); |
226 | 3 | |
227 | 3 | // setup our bad port list stuff |
228 | 204 | for(int i=0; gBadPortList[i]; i++) |
229 | 201 | mRestrictedPortList.AppendElement(gBadPortList[i]); |
230 | 3 | |
231 | 3 | // Further modifications to the port list come from prefs |
232 | 3 | Preferences::RegisterPrefixCallbacks( |
233 | 3 | PREF_CHANGE_METHOD(nsIOService::PrefsChanged), |
234 | 3 | gCallbackPrefs, this); |
235 | 3 | PrefsChanged(); |
236 | 3 | |
237 | 3 | // Register for profile change notifications |
238 | 3 | nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); |
239 | 3 | if (observerService) { |
240 | 3 | observerService->AddObserver(this, kProfileChangeNetTeardownTopic, true); |
241 | 3 | observerService->AddObserver(this, kProfileChangeNetRestoreTopic, true); |
242 | 3 | observerService->AddObserver(this, kProfileDoChange, true); |
243 | 3 | observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, true); |
244 | 3 | observerService->AddObserver(this, NS_NETWORK_LINK_TOPIC, true); |
245 | 3 | observerService->AddObserver(this, NS_WIDGET_WAKE_OBSERVER_TOPIC, true); |
246 | 3 | } |
247 | 3 | else |
248 | 3 | NS_WARNING("failed to get observer service"); |
249 | 3 | |
250 | 3 | Preferences::AddBoolVarCache(&sIsDataURIUniqueOpaqueOrigin, |
251 | 3 | "security.data_uri.unique_opaque_origin", false); |
252 | 3 | Preferences::AddBoolVarCache(&sBlockToplevelDataUriNavigations, |
253 | 3 | "security.data_uri.block_toplevel_data_uri_navigations", false); |
254 | 3 | Preferences::AddBoolVarCache(&sBlockFTPSubresources, |
255 | 3 | "security.block_ftp_subresources", true); |
256 | 3 | Preferences::AddBoolVarCache(&mOfflineMirrorsConnectivity, OFFLINE_MIRRORS_CONNECTIVITY, true); |
257 | 3 | |
258 | 3 | gIOService = this; |
259 | 3 | |
260 | 3 | InitializeNetworkLinkService(); |
261 | 3 | InitializeProtocolProxyService(); |
262 | 3 | |
263 | 3 | SetOffline(false); |
264 | 3 | |
265 | 3 | return NS_OK; |
266 | 3 | } |
267 | | |
268 | | |
269 | | nsIOService::~nsIOService() |
270 | 0 | { |
271 | 0 | if (gIOService) { |
272 | 0 | MOZ_ASSERT(gIOService == this); |
273 | 0 | gIOService = nullptr; |
274 | 0 | } |
275 | 0 | } |
276 | | |
277 | | nsresult |
278 | | nsIOService::InitializeCaptivePortalService() |
279 | 3 | { |
280 | 3 | if (XRE_GetProcessType() != GeckoProcessType_Default) { |
281 | 0 | // We only initalize a captive portal service in the main process |
282 | 0 | return NS_OK; |
283 | 0 | } |
284 | 3 | |
285 | 3 | mCaptivePortalService = do_GetService(NS_CAPTIVEPORTAL_CID); |
286 | 3 | if (mCaptivePortalService) { |
287 | 3 | return static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Initialize(); |
288 | 3 | } |
289 | 0 | |
290 | 0 | return NS_OK; |
291 | 0 | } |
292 | | |
293 | | nsresult |
294 | | nsIOService::InitializeSocketTransportService() |
295 | 3 | { |
296 | 3 | nsresult rv = NS_OK; |
297 | 3 | |
298 | 3 | if (!mSocketTransportService) { |
299 | 3 | mSocketTransportService = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); |
300 | 3 | if (NS_FAILED(rv)) { |
301 | 0 | NS_WARNING("failed to get socket transport service"); |
302 | 0 | } |
303 | 3 | } |
304 | 3 | |
305 | 3 | if (mSocketTransportService) { |
306 | 3 | rv = mSocketTransportService->Init(); |
307 | 3 | NS_ASSERTION(NS_SUCCEEDED(rv), "socket transport service init failed"); |
308 | 3 | mSocketTransportService->SetOffline(false); |
309 | 3 | } |
310 | 3 | |
311 | 3 | return rv; |
312 | 3 | } |
313 | | |
314 | | nsresult |
315 | | nsIOService::InitializeNetworkLinkService() |
316 | 3 | { |
317 | 3 | nsresult rv = NS_OK; |
318 | 3 | |
319 | 3 | if (mNetworkLinkServiceInitialized) |
320 | 0 | return rv; |
321 | 3 | |
322 | 3 | if (!NS_IsMainThread()) { |
323 | 0 | NS_WARNING("Network link service should be created on main thread"); |
324 | 0 | return NS_ERROR_FAILURE; |
325 | 0 | } |
326 | 3 | |
327 | 3 | // go into managed mode if we can, and chrome process |
328 | 3 | if (XRE_IsParentProcess()) |
329 | 3 | { |
330 | 3 | mNetworkLinkService = do_GetService(NS_NETWORK_LINK_SERVICE_CONTRACTID, &rv); |
331 | 3 | } |
332 | 3 | |
333 | 3 | if (mNetworkLinkService) { |
334 | 3 | mNetworkLinkServiceInitialized = true; |
335 | 3 | } |
336 | 3 | |
337 | 3 | // After initializing the networkLinkService, query the connectivity state |
338 | 3 | OnNetworkLinkEvent(NS_NETWORK_LINK_DATA_UNKNOWN); |
339 | 3 | |
340 | 3 | return rv; |
341 | 3 | } |
342 | | |
343 | | nsresult |
344 | | nsIOService::InitializeProtocolProxyService() |
345 | 3 | { |
346 | 3 | nsresult rv = NS_OK; |
347 | 3 | |
348 | 3 | if (XRE_IsParentProcess()) { |
349 | 3 | // for early-initialization |
350 | 3 | Unused << do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv); |
351 | 3 | } |
352 | 3 | |
353 | 3 | return rv; |
354 | 3 | } |
355 | | |
356 | | already_AddRefed<nsIOService> |
357 | 3 | nsIOService::GetInstance() { |
358 | 3 | if (!gIOService) { |
359 | 3 | RefPtr<nsIOService> ios = new nsIOService(); |
360 | 3 | if (NS_SUCCEEDED(ios->Init())) { |
361 | 3 | MOZ_ASSERT(gIOService == ios.get()); |
362 | 3 | return ios.forget(); |
363 | 3 | } |
364 | 0 | } |
365 | 0 | return do_AddRef(gIOService); |
366 | 0 | } |
367 | | |
368 | | NS_IMPL_ISUPPORTS(nsIOService, |
369 | | nsIIOService, |
370 | | nsINetUtil, |
371 | | nsISpeculativeConnect, |
372 | | nsIObserver, |
373 | | nsIIOServiceInternal, |
374 | | nsISupportsWeakReference) |
375 | | |
376 | | //////////////////////////////////////////////////////////////////////////////// |
377 | | |
378 | | nsresult |
379 | | nsIOService::RecheckCaptivePortal() |
380 | 0 | { |
381 | 0 | MOZ_ASSERT(NS_IsMainThread(), "Must be called on the main thread"); |
382 | 0 | if (!mCaptivePortalService) { |
383 | 0 | return NS_OK; |
384 | 0 | } |
385 | 0 | nsCOMPtr<nsIRunnable> task = |
386 | 0 | NewRunnableMethod("nsIOService::RecheckCaptivePortal", |
387 | 0 | mCaptivePortalService, |
388 | 0 | &nsICaptivePortalService::RecheckCaptivePortal); |
389 | 0 | return NS_DispatchToMainThread(task); |
390 | 0 | } |
391 | | |
392 | | nsresult |
393 | | nsIOService::RecheckCaptivePortalIfLocalRedirect(nsIChannel* newChan) |
394 | 0 | { |
395 | 0 | nsresult rv; |
396 | 0 |
|
397 | 0 | if (!mCaptivePortalService) { |
398 | 0 | return NS_OK; |
399 | 0 | } |
400 | 0 | |
401 | 0 | nsCOMPtr<nsIURI> uri; |
402 | 0 | rv = newChan->GetURI(getter_AddRefs(uri)); |
403 | 0 | if (NS_FAILED(rv)) { |
404 | 0 | return rv; |
405 | 0 | } |
406 | 0 | |
407 | 0 | nsCString host; |
408 | 0 | rv = uri->GetHost(host); |
409 | 0 | if (NS_FAILED(rv)) { |
410 | 0 | return rv; |
411 | 0 | } |
412 | 0 | |
413 | 0 | PRNetAddr prAddr; |
414 | 0 | if (PR_StringToNetAddr(host.BeginReading(), &prAddr) != PR_SUCCESS) { |
415 | 0 | // The redirect wasn't to an IP literal, so there's probably no need |
416 | 0 | // to trigger the captive portal detection right now. It can wait. |
417 | 0 | return NS_OK; |
418 | 0 | } |
419 | 0 | |
420 | 0 | NetAddr netAddr; |
421 | 0 | PRNetAddrToNetAddr(&prAddr, &netAddr); |
422 | 0 | if (IsIPAddrLocal(&netAddr)) { |
423 | 0 | // Redirects to local IP addresses are probably captive portals |
424 | 0 | RecheckCaptivePortal(); |
425 | 0 | } |
426 | 0 |
|
427 | 0 | return NS_OK; |
428 | 0 | } |
429 | | |
430 | | nsresult |
431 | | nsIOService::AsyncOnChannelRedirect(nsIChannel* oldChan, nsIChannel* newChan, |
432 | | uint32_t flags, |
433 | | nsAsyncRedirectVerifyHelper *helper) |
434 | 0 | { |
435 | 0 | // If a redirect to a local network address occurs, then chances are we |
436 | 0 | // are in a captive portal, so we trigger a recheck. |
437 | 0 | RecheckCaptivePortalIfLocalRedirect(newChan); |
438 | 0 |
|
439 | 0 | // This is silly. I wish there was a simpler way to get at the global |
440 | 0 | // reference of the contentSecurityManager. But it lives in the XPCOM |
441 | 0 | // service registry. |
442 | 0 | nsCOMPtr<nsIChannelEventSink> sink = |
443 | 0 | do_GetService(NS_CONTENTSECURITYMANAGER_CONTRACTID); |
444 | 0 | if (sink) { |
445 | 0 | nsresult rv = helper->DelegateOnChannelRedirect(sink, oldChan, |
446 | 0 | newChan, flags); |
447 | 0 | if (NS_FAILED(rv)) |
448 | 0 | return rv; |
449 | 0 | } |
450 | 0 | |
451 | 0 | // Finally, our category |
452 | 0 | nsCOMArray<nsIChannelEventSink> entries; |
453 | 0 | mChannelEventSinks.GetEntries(entries); |
454 | 0 | int32_t len = entries.Count(); |
455 | 0 | for (int32_t i = 0; i < len; ++i) { |
456 | 0 | nsresult rv = helper->DelegateOnChannelRedirect(entries[i], oldChan, |
457 | 0 | newChan, flags); |
458 | 0 | if (NS_FAILED(rv)) |
459 | 0 | return rv; |
460 | 0 | } |
461 | 0 | return NS_OK; |
462 | 0 | } |
463 | | |
464 | | nsresult |
465 | | nsIOService::CacheProtocolHandler(const char *scheme, nsIProtocolHandler *handler) |
466 | 1.64M | { |
467 | 1.64M | MOZ_ASSERT(NS_IsMainThread()); |
468 | 1.64M | |
469 | 21.4M | for (unsigned int i=0; i<NS_N(gScheme); i++) |
470 | 19.7M | { |
471 | 19.7M | if (!nsCRT::strcasecmp(scheme, gScheme[i])) |
472 | 17 | { |
473 | 17 | nsresult rv; |
474 | 17 | NS_ASSERTION(!mWeakHandler[i], "Protocol handler already cached"); |
475 | 17 | // Make sure the handler supports weak references. |
476 | 17 | nsCOMPtr<nsISupportsWeakReference> factoryPtr = do_QueryInterface(handler, &rv); |
477 | 17 | if (!factoryPtr) |
478 | 0 | { |
479 | 0 | // Don't cache handlers that don't support weak reference as |
480 | 0 | // there is real danger of a circular reference. |
481 | | #ifdef DEBUG_dp |
482 | | printf("DEBUG: %s protcol handler doesn't support weak ref. Not cached.\n", scheme); |
483 | | #endif /* DEBUG_dp */ |
484 | | return NS_ERROR_FAILURE; |
485 | 0 | } |
486 | 17 | mWeakHandler[i] = do_GetWeakReference(handler); |
487 | 17 | return NS_OK; |
488 | 17 | } |
489 | 19.7M | } |
490 | 1.64M | return NS_ERROR_FAILURE; |
491 | 1.64M | } |
492 | | |
493 | | nsresult |
494 | | nsIOService::GetCachedProtocolHandler(const char *scheme, nsIProtocolHandler **result, uint32_t start, uint32_t end) |
495 | 3.06M | { |
496 | 3.06M | MOZ_ASSERT(NS_IsMainThread()); |
497 | 3.06M | |
498 | 3.06M | uint32_t len = end - start - 1; |
499 | 28.5M | for (unsigned int i=0; i<NS_N(gScheme); i++) |
500 | 26.6M | { |
501 | 26.6M | if (!mWeakHandler[i]) |
502 | 5.81M | continue; |
503 | 20.8M | |
504 | 20.8M | // handle unterminated strings |
505 | 20.8M | // start is inclusive, end is exclusive, len = end - start - 1 |
506 | 20.8M | if (end ? (!nsCRT::strncasecmp(scheme + start, gScheme[i], len) |
507 | 0 | && gScheme[i][len] == '\0') |
508 | 20.8M | : (!nsCRT::strcasecmp(scheme, gScheme[i]))) |
509 | 1.12M | { |
510 | 1.12M | return CallQueryReferent(mWeakHandler[i].get(), result); |
511 | 1.12M | } |
512 | 20.8M | } |
513 | 3.06M | return NS_ERROR_FAILURE; |
514 | 3.06M | } |
515 | | |
516 | | static bool |
517 | | UsesExternalProtocolHandler(const char* aScheme) |
518 | 1.93M | { |
519 | 1.93M | if (NS_LITERAL_CSTRING("file").Equals(aScheme) || |
520 | 1.93M | NS_LITERAL_CSTRING("chrome").Equals(aScheme) || |
521 | 1.93M | NS_LITERAL_CSTRING("resource").Equals(aScheme)) { |
522 | 9 | // Don't allow file:, chrome: or resource: URIs to be handled with |
523 | 9 | // nsExternalProtocolHandler, since internally we rely on being able to |
524 | 9 | // use and read from these URIs. |
525 | 9 | return false; |
526 | 9 | } |
527 | 1.93M | |
528 | 7.73M | for (const auto & forcedExternalScheme : gForcedExternalSchemes) { |
529 | 7.73M | if (!nsCRT::strcasecmp(forcedExternalScheme, aScheme)) { |
530 | 0 | return true; |
531 | 0 | } |
532 | 7.73M | } |
533 | 1.93M | |
534 | 1.93M | nsAutoCString pref("network.protocol-handler.external."); |
535 | 1.93M | pref += aScheme; |
536 | 1.93M | |
537 | 1.93M | return Preferences::GetBool(pref.get(), false); |
538 | 1.93M | } |
539 | | |
540 | | NS_IMETHODIMP |
541 | | nsIOService::GetProtocolHandler(const char* scheme, nsIProtocolHandler* *result) |
542 | 3.06M | { |
543 | 3.06M | nsresult rv; |
544 | 3.06M | |
545 | 3.06M | NS_ENSURE_ARG_POINTER(scheme); |
546 | 3.06M | // XXX we may want to speed this up by introducing our own protocol |
547 | 3.06M | // scheme -> protocol handler mapping, avoiding the string manipulation |
548 | 3.06M | // and service manager stuff |
549 | 3.06M | |
550 | 3.06M | rv = GetCachedProtocolHandler(scheme, result); |
551 | 3.06M | if (NS_SUCCEEDED(rv)) |
552 | 3.06M | return rv; |
553 | 1.93M | |
554 | 1.93M | if (scheme[0] != '\0' && !UsesExternalProtocolHandler(scheme)) { |
555 | 1.93M | nsAutoCString contractID(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX); |
556 | 1.93M | contractID += scheme; |
557 | 1.93M | ToLowerCase(contractID); |
558 | 1.93M | |
559 | 1.93M | rv = CallGetService(contractID.get(), result); |
560 | 1.93M | if (NS_SUCCEEDED(rv)) { |
561 | 1.64M | CacheProtocolHandler(scheme, *result); |
562 | 1.64M | return rv; |
563 | 1.64M | } |
564 | 285k | |
565 | 285k | #ifdef MOZ_WIDGET_GTK |
566 | 285k | // check to see whether GVFS can handle this URI scheme. if it can |
567 | 285k | // create a nsIURI for the "scheme:", then we assume it has support for |
568 | 285k | // the requested protocol. otherwise, we failover to using the default |
569 | 285k | // protocol handler. |
570 | 285k | |
571 | 285k | rv = CallGetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX"moz-gio", |
572 | 285k | result); |
573 | 285k | if (NS_SUCCEEDED(rv)) { |
574 | 285k | nsAutoCString spec(scheme); |
575 | 285k | spec.Append(':'); |
576 | 285k | |
577 | 285k | nsIURI *uri; |
578 | 285k | rv = (*result)->NewURI(spec, nullptr, nullptr, &uri); |
579 | 285k | if (NS_SUCCEEDED(rv)) { |
580 | 0 | NS_RELEASE(uri); |
581 | 0 | return rv; |
582 | 0 | } |
583 | 285k | |
584 | 285k | NS_RELEASE(*result); |
585 | 285k | } |
586 | 285k | #endif |
587 | 285k | } |
588 | 1.93M | |
589 | 1.93M | // Okay we don't have a protocol handler to handle this url type, so use |
590 | 1.93M | // the default protocol handler. This will cause urls to get dispatched |
591 | 1.93M | // out to the OS ('cause we can't do anything with them) when we try to |
592 | 1.93M | // read from a channel created by the default protocol handler. |
593 | 1.93M | |
594 | 1.93M | rv = CallGetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX"default", |
595 | 285k | result); |
596 | 285k | if (NS_FAILED(rv)) |
597 | 285k | return NS_ERROR_UNKNOWN_PROTOCOL; |
598 | 285k | |
599 | 285k | return rv; |
600 | 285k | } |
601 | | |
602 | | NS_IMETHODIMP |
603 | | nsIOService::ExtractScheme(const nsACString &inURI, nsACString &scheme) |
604 | 3.05M | { |
605 | 3.05M | return net_ExtractURLScheme(inURI, scheme); |
606 | 3.05M | } |
607 | | |
608 | | NS_IMETHODIMP |
609 | | nsIOService::HostnameIsLocalIPAddress(nsIURI *aURI, bool *aResult) |
610 | 0 | { |
611 | 0 | NS_ENSURE_ARG_POINTER(aURI); |
612 | 0 |
|
613 | 0 | nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(aURI); |
614 | 0 | NS_ENSURE_ARG_POINTER(innerURI); |
615 | 0 |
|
616 | 0 | nsAutoCString host; |
617 | 0 | nsresult rv = innerURI->GetAsciiHost(host); |
618 | 0 | if (NS_FAILED(rv)) { |
619 | 0 | return rv; |
620 | 0 | } |
621 | 0 | |
622 | 0 | *aResult = false; |
623 | 0 |
|
624 | 0 | PRNetAddr addr; |
625 | 0 | PRStatus result = PR_StringToNetAddr(host.get(), &addr); |
626 | 0 | if (result == PR_SUCCESS) { |
627 | 0 | NetAddr netAddr; |
628 | 0 | PRNetAddrToNetAddr(&addr, &netAddr); |
629 | 0 | if (IsIPAddrLocal(&netAddr)) { |
630 | 0 | *aResult = true; |
631 | 0 | } |
632 | 0 | } |
633 | 0 |
|
634 | 0 | return NS_OK; |
635 | 0 | } |
636 | | |
637 | | NS_IMETHODIMP |
638 | | nsIOService::GetProtocolFlags(const char* scheme, uint32_t *flags) |
639 | 0 | { |
640 | 0 | nsCOMPtr<nsIProtocolHandler> handler; |
641 | 0 | nsresult rv = GetProtocolHandler(scheme, getter_AddRefs(handler)); |
642 | 0 | if (NS_FAILED(rv)) return rv; |
643 | 0 | |
644 | 0 | // We can't call DoGetProtocolFlags here because we don't have a URI. This |
645 | 0 | // API is used by (and only used by) extensions, which is why it's still |
646 | 0 | // around. Calling this on a scheme with dynamic flags will throw. |
647 | 0 | rv = handler->GetProtocolFlags(flags); |
648 | 0 | #if !IS_ORIGIN_IS_FULL_SPEC_DEFINED |
649 | 0 | MOZ_RELEASE_ASSERT(!(*flags & nsIProtocolHandler::ORIGIN_IS_FULL_SPEC), |
650 | 0 | "ORIGIN_IS_FULL_SPEC is unsupported but used"); |
651 | 0 | #endif |
652 | 0 | return rv; |
653 | 0 | } |
654 | | |
655 | | class AutoIncrement |
656 | | { |
657 | | public: |
658 | | explicit AutoIncrement(uint32_t *var) : mVar(var) |
659 | 3.05M | { |
660 | 3.05M | ++*var; |
661 | 3.05M | } |
662 | | ~AutoIncrement() |
663 | 3.05M | { |
664 | 3.05M | --*mVar; |
665 | 3.05M | } |
666 | | private: |
667 | | uint32_t *mVar; |
668 | | }; |
669 | | |
670 | | nsresult |
671 | | nsIOService::NewURI(const nsACString &aSpec, const char *aCharset, nsIURI *aBaseURI, nsIURI **result) |
672 | 3.05M | { |
673 | 3.05M | NS_ASSERTION(NS_IsMainThread(), "wrong thread"); |
674 | 3.05M | |
675 | 3.05M | static uint32_t recursionCount = 0; |
676 | 3.05M | if (recursionCount >= MAX_RECURSION_COUNT) |
677 | 3.05M | return NS_ERROR_MALFORMED_URI; |
678 | 3.05M | AutoIncrement inc(&recursionCount); |
679 | 3.05M | |
680 | 3.05M | nsAutoCString scheme; |
681 | 3.05M | nsresult rv = ExtractScheme(aSpec, scheme); |
682 | 3.05M | if (NS_FAILED(rv)) { |
683 | 1.06M | // then aSpec is relative |
684 | 1.06M | if (!aBaseURI) |
685 | 0 | return NS_ERROR_MALFORMED_URI; |
686 | 1.06M | |
687 | 1.06M | if (!aSpec.IsEmpty() && aSpec[0] == '#') { |
688 | 2.32k | // Looks like a reference instead of a fully-specified URI. |
689 | 2.32k | // --> initialize |uri| as a clone of |aBaseURI|, with ref appended. |
690 | 2.32k | return NS_GetURIWithNewRef(aBaseURI, aSpec, result); |
691 | 2.32k | } |
692 | 1.05M | |
693 | 1.05M | rv = aBaseURI->GetScheme(scheme); |
694 | 1.05M | if (NS_FAILED(rv)) return rv; |
695 | 3.05M | } |
696 | 3.05M | |
697 | 3.05M | // now get the handler for this scheme |
698 | 3.05M | nsCOMPtr<nsIProtocolHandler> handler; |
699 | 3.05M | rv = GetProtocolHandler(scheme.get(), getter_AddRefs(handler)); |
700 | 3.05M | if (NS_FAILED(rv)) return rv; |
701 | 3.05M | |
702 | 3.05M | return handler->NewURI(aSpec, aCharset, aBaseURI, result); |
703 | 3.05M | } |
704 | | |
705 | | |
706 | | NS_IMETHODIMP |
707 | | nsIOService::NewFileURI(nsIFile *file, nsIURI **result) |
708 | 0 | { |
709 | 0 | nsresult rv; |
710 | 0 | NS_ENSURE_ARG_POINTER(file); |
711 | 0 |
|
712 | 0 | nsCOMPtr<nsIProtocolHandler> handler; |
713 | 0 |
|
714 | 0 | rv = GetProtocolHandler("file", getter_AddRefs(handler)); |
715 | 0 | if (NS_FAILED(rv)) return rv; |
716 | 0 | |
717 | 0 | nsCOMPtr<nsIFileProtocolHandler> fileHandler( do_QueryInterface(handler, &rv) ); |
718 | 0 | if (NS_FAILED(rv)) return rv; |
719 | 0 | |
720 | 0 | return fileHandler->NewFileURI(file, result); |
721 | 0 | } |
722 | | |
723 | | NS_IMETHODIMP |
724 | | nsIOService::NewChannelFromURI2(nsIURI* aURI, |
725 | | nsINode* aLoadingNode, |
726 | | nsIPrincipal* aLoadingPrincipal, |
727 | | nsIPrincipal* aTriggeringPrincipal, |
728 | | uint32_t aSecurityFlags, |
729 | | uint32_t aContentPolicyType, |
730 | | nsIChannel** result) |
731 | 0 | { |
732 | 0 | return NewChannelFromURIWithProxyFlags2(aURI, |
733 | 0 | nullptr, // aProxyURI |
734 | 0 | 0, // aProxyFlags |
735 | 0 | aLoadingNode, |
736 | 0 | aLoadingPrincipal, |
737 | 0 | aTriggeringPrincipal, |
738 | 0 | aSecurityFlags, |
739 | 0 | aContentPolicyType, |
740 | 0 | result); |
741 | 0 | } |
742 | | nsresult |
743 | | nsIOService::NewChannelFromURIWithClientAndController(nsIURI* aURI, |
744 | | nsINode* aLoadingNode, |
745 | | nsIPrincipal* aLoadingPrincipal, |
746 | | nsIPrincipal* aTriggeringPrincipal, |
747 | | const Maybe<ClientInfo>& aLoadingClientInfo, |
748 | | const Maybe<ServiceWorkerDescriptor>& aController, |
749 | | uint32_t aSecurityFlags, |
750 | | uint32_t aContentPolicyType, |
751 | | nsIChannel** aResult) |
752 | 5 | { |
753 | 5 | return NewChannelFromURIWithProxyFlagsInternal(aURI, |
754 | 5 | nullptr, // aProxyURI |
755 | 5 | 0, // aProxyFlags |
756 | 5 | aLoadingNode, |
757 | 5 | aLoadingPrincipal, |
758 | 5 | aTriggeringPrincipal, |
759 | 5 | aLoadingClientInfo, |
760 | 5 | aController, |
761 | 5 | aSecurityFlags, |
762 | 5 | aContentPolicyType, |
763 | 5 | aResult); |
764 | 5 | } |
765 | | |
766 | | NS_IMETHODIMP |
767 | | nsIOService::NewChannelFromURIWithLoadInfo(nsIURI* aURI, |
768 | | nsILoadInfo* aLoadInfo, |
769 | | nsIChannel** result) |
770 | 4 | { |
771 | 4 | return NewChannelFromURIWithProxyFlagsInternal(aURI, |
772 | 4 | nullptr, // aProxyURI |
773 | 4 | 0, // aProxyFlags |
774 | 4 | aLoadInfo, |
775 | 4 | result); |
776 | 4 | } |
777 | | |
778 | | |
779 | | nsresult |
780 | | nsIOService::NewChannelFromURIWithProxyFlagsInternal(nsIURI* aURI, |
781 | | nsIURI* aProxyURI, |
782 | | uint32_t aProxyFlags, |
783 | | nsINode* aLoadingNode, |
784 | | nsIPrincipal* aLoadingPrincipal, |
785 | | nsIPrincipal* aTriggeringPrincipal, |
786 | | const Maybe<ClientInfo>& aLoadingClientInfo, |
787 | | const Maybe<ServiceWorkerDescriptor>& aController, |
788 | | uint32_t aSecurityFlags, |
789 | | uint32_t aContentPolicyType, |
790 | | nsIChannel** result) |
791 | 5 | { |
792 | 5 | // Ideally all callers of NewChannelFromURIWithProxyFlagsInternal provide |
793 | 5 | // the necessary arguments to create a loadinfo. |
794 | 5 | // |
795 | 5 | // Note, historically this could be called with nullptr aLoadingNode, |
796 | 5 | // aLoadingPrincipal, and aTriggeringPrincipal from addons using |
797 | 5 | // newChannelFromURIWithProxyFlags(). This code tried to accomodate |
798 | 5 | // by not creating a LoadInfo in such cases. Now that both the legacy |
799 | 5 | // addons and that API are gone we could possibly require always creating a |
800 | 5 | // LoadInfo here. See bug 1432205. |
801 | 5 | nsCOMPtr<nsILoadInfo> loadInfo; |
802 | 5 | |
803 | 5 | // TYPE_DOCUMENT loads don't require a loadingNode or principal, but other |
804 | 5 | // types do. |
805 | 5 | if (aLoadingNode || aLoadingPrincipal || |
806 | 5 | aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT) { |
807 | 5 | loadInfo = new LoadInfo(aLoadingPrincipal, |
808 | 5 | aTriggeringPrincipal, |
809 | 5 | aLoadingNode, |
810 | 5 | aSecurityFlags, |
811 | 5 | aContentPolicyType, |
812 | 5 | aLoadingClientInfo, |
813 | 5 | aController); |
814 | 5 | } |
815 | 5 | NS_ASSERTION(loadInfo, "Please pass security info when creating a channel"); |
816 | 5 | return NewChannelFromURIWithProxyFlagsInternal(aURI, |
817 | 5 | aProxyURI, |
818 | 5 | aProxyFlags, |
819 | 5 | loadInfo, |
820 | 5 | result); |
821 | 5 | } |
822 | | |
823 | | nsresult |
824 | | nsIOService::NewChannelFromURIWithProxyFlagsInternal(nsIURI* aURI, |
825 | | nsIURI* aProxyURI, |
826 | | uint32_t aProxyFlags, |
827 | | nsILoadInfo* aLoadInfo, |
828 | | nsIChannel** result) |
829 | 9 | { |
830 | 9 | nsresult rv; |
831 | 9 | NS_ENSURE_ARG_POINTER(aURI); |
832 | 9 | |
833 | 9 | nsAutoCString scheme; |
834 | 9 | rv = aURI->GetScheme(scheme); |
835 | 9 | if (NS_FAILED(rv)) |
836 | 9 | return rv; |
837 | 9 | |
838 | 9 | nsCOMPtr<nsIProtocolHandler> handler; |
839 | 9 | rv = GetProtocolHandler(scheme.get(), getter_AddRefs(handler)); |
840 | 9 | if (NS_FAILED(rv)) |
841 | 9 | return rv; |
842 | 9 | |
843 | 9 | uint32_t protoFlags; |
844 | 9 | rv = handler->DoGetProtocolFlags(aURI, &protoFlags); |
845 | 9 | if (NS_FAILED(rv)) |
846 | 9 | return rv; |
847 | 9 | |
848 | 9 | // Ideally we are creating new channels by calling NewChannel2 (NewProxiedChannel2). |
849 | 9 | // Keep in mind that Addons can implement their own Protocolhandlers, hence |
850 | 9 | // NewChannel2() might *not* be implemented. |
851 | 9 | // We do not want to break those addons, therefore we first try to create a channel |
852 | 9 | // calling NewChannel2(); if that fails: |
853 | 9 | // * we fall back to creating a channel by calling NewChannel() |
854 | 9 | // * wrap the addon channel |
855 | 9 | // * and attach the loadInfo to the channel wrapper |
856 | 9 | nsCOMPtr<nsIChannel> channel; |
857 | 9 | nsCOMPtr<nsIProxiedProtocolHandler> pph = do_QueryInterface(handler); |
858 | 9 | if (pph) { |
859 | 0 | rv = pph->NewProxiedChannel2(aURI, nullptr, aProxyFlags, aProxyURI, |
860 | 0 | aLoadInfo, getter_AddRefs(channel)); |
861 | 0 | // if calling NewProxiedChannel2() fails we try to fall back to |
862 | 0 | // creating a new proxied channel by calling NewProxiedChannel(). |
863 | 0 | if (NS_FAILED(rv)) { |
864 | 0 | rv = pph->NewProxiedChannel(aURI, nullptr, aProxyFlags, aProxyURI, |
865 | 0 | getter_AddRefs(channel)); |
866 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
867 | 0 |
|
868 | 0 | // The protocol handler does not implement NewProxiedChannel2, so |
869 | 0 | // maybe we need to wrap the channel (see comment in MaybeWrap |
870 | 0 | // function). |
871 | 0 | channel = nsSecCheckWrapChannel::MaybeWrap(channel, aLoadInfo); |
872 | 0 | } |
873 | 0 | } |
874 | 9 | else { |
875 | 9 | rv = handler->NewChannel2(aURI, aLoadInfo, getter_AddRefs(channel)); |
876 | 9 | // if an implementation of NewChannel2() is missing we try to fall back to |
877 | 9 | // creating a new channel by calling NewChannel(). |
878 | 9 | if (rv == NS_ERROR_NOT_IMPLEMENTED || |
879 | 9 | rv == NS_ERROR_XPC_JSOBJECT_HAS_NO_FUNCTION_NAMED) { |
880 | 0 | LOG(("NewChannel2 not implemented rv=%" PRIx32 |
881 | 0 | ". Falling back to NewChannel\n", static_cast<uint32_t>(rv))); |
882 | 0 | rv = handler->NewChannel(aURI, getter_AddRefs(channel)); |
883 | 0 | if (NS_FAILED(rv)) { |
884 | 0 | return rv; |
885 | 0 | } |
886 | 0 | // The protocol handler does not implement NewChannel2, so |
887 | 0 | // maybe we need to wrap the channel (see comment in MaybeWrap |
888 | 0 | // function). |
889 | 0 | channel = nsSecCheckWrapChannel::MaybeWrap(channel, aLoadInfo); |
890 | 9 | } else if (NS_FAILED(rv)) { |
891 | 0 | return rv; |
892 | 0 | } |
893 | 9 | } |
894 | 9 | |
895 | 9 | // Make sure that all the individual protocolhandlers attach a loadInfo. |
896 | 9 | if (aLoadInfo) { |
897 | 9 | // make sure we have the same instance of loadInfo on the newly created channel |
898 | 9 | nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo(); |
899 | 9 | if (aLoadInfo != loadInfo) { |
900 | 0 | MOZ_ASSERT(false, "newly created channel must have a loadinfo attached"); |
901 | 0 | return NS_ERROR_UNEXPECTED; |
902 | 0 | } |
903 | 9 | |
904 | 9 | // If we're sandboxed, make sure to clear any owner the channel |
905 | 9 | // might already have. |
906 | 9 | if (loadInfo->GetLoadingSandboxed()) { |
907 | 0 | channel->SetOwner(nullptr); |
908 | 0 | } |
909 | 9 | } |
910 | 9 | |
911 | 9 | // Some extensions override the http protocol handler and provide their own |
912 | 9 | // implementation. The channels returned from that implementation doesn't |
913 | 9 | // seem to always implement the nsIUploadChannel2 interface, presumably |
914 | 9 | // because it's a new interface. |
915 | 9 | // Eventually we should remove this and simply require that http channels |
916 | 9 | // implement the new interface. |
917 | 9 | // See bug 529041 |
918 | 9 | if (!gHasWarnedUploadChannel2 && scheme.EqualsLiteral("http")) { |
919 | 0 | nsCOMPtr<nsIUploadChannel2> uploadChannel2 = do_QueryInterface(channel); |
920 | 0 | if (!uploadChannel2) { |
921 | 0 | nsCOMPtr<nsIConsoleService> consoleService = |
922 | 0 | do_GetService(NS_CONSOLESERVICE_CONTRACTID); |
923 | 0 | if (consoleService) { |
924 | 0 | consoleService->LogStringMessage(u"Http channel implementation " |
925 | 0 | "doesn't support nsIUploadChannel2. An extension has " |
926 | 0 | "supplied a non-functional http protocol handler. This will " |
927 | 0 | "break behavior and in future releases not work at all."); |
928 | 0 | } |
929 | 0 | gHasWarnedUploadChannel2 = true; |
930 | 0 | } |
931 | 0 | } |
932 | 9 | |
933 | 9 | channel.forget(result); |
934 | 9 | return NS_OK; |
935 | 9 | } |
936 | | |
937 | | NS_IMETHODIMP |
938 | | nsIOService::NewChannelFromURIWithProxyFlags2(nsIURI* aURI, |
939 | | nsIURI* aProxyURI, |
940 | | uint32_t aProxyFlags, |
941 | | nsINode* aLoadingNode, |
942 | | nsIPrincipal* aLoadingPrincipal, |
943 | | nsIPrincipal* aTriggeringPrincipal, |
944 | | uint32_t aSecurityFlags, |
945 | | uint32_t aContentPolicyType, |
946 | | nsIChannel** result) |
947 | 0 | { |
948 | 0 | return NewChannelFromURIWithProxyFlagsInternal(aURI, |
949 | 0 | aProxyURI, |
950 | 0 | aProxyFlags, |
951 | 0 | aLoadingNode, |
952 | 0 | aLoadingPrincipal, |
953 | 0 | aTriggeringPrincipal, |
954 | 0 | Maybe<ClientInfo>(), |
955 | 0 | Maybe<ServiceWorkerDescriptor>(), |
956 | 0 | aSecurityFlags, |
957 | 0 | aContentPolicyType, |
958 | 0 | result); |
959 | 0 | } |
960 | | |
961 | | NS_IMETHODIMP |
962 | | nsIOService::NewChannel2(const nsACString& aSpec, |
963 | | const char* aCharset, |
964 | | nsIURI* aBaseURI, |
965 | | nsINode* aLoadingNode, |
966 | | nsIPrincipal* aLoadingPrincipal, |
967 | | nsIPrincipal* aTriggeringPrincipal, |
968 | | uint32_t aSecurityFlags, |
969 | | uint32_t aContentPolicyType, |
970 | | nsIChannel** result) |
971 | 0 | { |
972 | 0 | nsresult rv; |
973 | 0 | nsCOMPtr<nsIURI> uri; |
974 | 0 | rv = NewURI(aSpec, aCharset, aBaseURI, getter_AddRefs(uri)); |
975 | 0 | if (NS_FAILED(rv)) return rv; |
976 | 0 | |
977 | 0 | return NewChannelFromURI2(uri, |
978 | 0 | aLoadingNode, |
979 | 0 | aLoadingPrincipal, |
980 | 0 | aTriggeringPrincipal, |
981 | 0 | aSecurityFlags, |
982 | 0 | aContentPolicyType, |
983 | 0 | result); |
984 | 0 | } |
985 | | |
986 | | bool |
987 | | nsIOService::IsLinkUp() |
988 | 0 | { |
989 | 0 | InitializeNetworkLinkService(); |
990 | 0 |
|
991 | 0 | if (!mNetworkLinkService) { |
992 | 0 | // We cannot decide, assume the link is up |
993 | 0 | return true; |
994 | 0 | } |
995 | 0 | |
996 | 0 | bool isLinkUp; |
997 | 0 | nsresult rv; |
998 | 0 | rv = mNetworkLinkService->GetIsLinkUp(&isLinkUp); |
999 | 0 | if (NS_FAILED(rv)) { |
1000 | 0 | return true; |
1001 | 0 | } |
1002 | 0 | |
1003 | 0 | return isLinkUp; |
1004 | 0 | } |
1005 | | |
1006 | | NS_IMETHODIMP |
1007 | | nsIOService::GetOffline(bool *offline) |
1008 | 0 | { |
1009 | 0 | if (mOfflineMirrorsConnectivity) { |
1010 | 0 | *offline = mOffline || !mConnectivity; |
1011 | 0 | } else { |
1012 | 0 | *offline = mOffline; |
1013 | 0 | } |
1014 | 0 | return NS_OK; |
1015 | 0 | } |
1016 | | |
1017 | | NS_IMETHODIMP |
1018 | | nsIOService::SetOffline(bool offline) |
1019 | 3 | { |
1020 | 3 | LOG(("nsIOService::SetOffline offline=%d\n", offline)); |
1021 | 3 | // When someone wants to go online (!offline) after we got XPCOM shutdown |
1022 | 3 | // throw ERROR_NOT_AVAILABLE to prevent return to online state. |
1023 | 3 | if ((mShutdown || mOfflineForProfileChange) && !offline) |
1024 | 0 | return NS_ERROR_NOT_AVAILABLE; |
1025 | 3 | |
1026 | 3 | // SetOffline() may re-enter while it's shutting down services. |
1027 | 3 | // If that happens, save the most recent value and it will be |
1028 | 3 | // processed when the first SetOffline() call is done bringing |
1029 | 3 | // down the service. |
1030 | 3 | mSetOfflineValue = offline; |
1031 | 3 | if (mSettingOffline) { |
1032 | 0 | return NS_OK; |
1033 | 0 | } |
1034 | 3 | |
1035 | 3 | mSettingOffline = true; |
1036 | 3 | |
1037 | 3 | nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); |
1038 | 3 | |
1039 | 3 | NS_ASSERTION(observerService, "The observer service should not be null"); |
1040 | 3 | |
1041 | 3 | if (XRE_IsParentProcess()) { |
1042 | 3 | if (observerService) { |
1043 | 3 | (void)observerService->NotifyObservers(nullptr, |
1044 | 3 | NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC, offline ? |
1045 | 0 | u"true" : |
1046 | 3 | u"false"); |
1047 | 3 | } |
1048 | 3 | } |
1049 | 3 | |
1050 | 3 | nsIIOService *subject = static_cast<nsIIOService *>(this); |
1051 | 6 | while (mSetOfflineValue != mOffline) { |
1052 | 3 | offline = mSetOfflineValue; |
1053 | 3 | |
1054 | 3 | if (offline && !mOffline) { |
1055 | 0 | mOffline = true; // indicate we're trying to shutdown |
1056 | 0 |
|
1057 | 0 | // don't care if notifications fail |
1058 | 0 | if (observerService) |
1059 | 0 | observerService->NotifyObservers(subject, |
1060 | 0 | NS_IOSERVICE_GOING_OFFLINE_TOPIC, |
1061 | 0 | u"" NS_IOSERVICE_OFFLINE); |
1062 | 0 |
|
1063 | 0 | if (mSocketTransportService) |
1064 | 0 | mSocketTransportService->SetOffline(true); |
1065 | 0 |
|
1066 | 0 | mLastOfflineStateChange = PR_IntervalNow(); |
1067 | 0 | if (observerService) |
1068 | 0 | observerService->NotifyObservers(subject, |
1069 | 0 | NS_IOSERVICE_OFFLINE_STATUS_TOPIC, |
1070 | 0 | u"" NS_IOSERVICE_OFFLINE); |
1071 | 0 | } |
1072 | 3 | else if (!offline && mOffline) { |
1073 | 3 | // go online |
1074 | 3 | InitializeSocketTransportService(); |
1075 | 3 | mOffline = false; // indicate success only AFTER we've |
1076 | 3 | // brought up the services |
1077 | 3 | |
1078 | 3 | mLastOfflineStateChange = PR_IntervalNow(); |
1079 | 3 | // don't care if notification fails |
1080 | 3 | // Only send the ONLINE notification if there is connectivity |
1081 | 3 | if (observerService && mConnectivity) { |
1082 | 3 | observerService->NotifyObservers(subject, |
1083 | 3 | NS_IOSERVICE_OFFLINE_STATUS_TOPIC, |
1084 | 3 | (u"" NS_IOSERVICE_ONLINE)); |
1085 | 3 | } |
1086 | 3 | } |
1087 | 3 | } |
1088 | 3 | |
1089 | 3 | // Don't notify here, as the above notifications (if used) suffice. |
1090 | 3 | if ((mShutdown || mOfflineForProfileChange) && mOffline) { |
1091 | 0 | if (mSocketTransportService) { |
1092 | 0 | DebugOnly<nsresult> rv = mSocketTransportService->Shutdown(mShutdown); |
1093 | 0 | NS_ASSERTION(NS_SUCCEEDED(rv), "socket transport service shutdown failed"); |
1094 | 0 | } |
1095 | 0 | } |
1096 | 3 | |
1097 | 3 | mSettingOffline = false; |
1098 | 3 | |
1099 | 3 | return NS_OK; |
1100 | 3 | } |
1101 | | |
1102 | | NS_IMETHODIMP |
1103 | | nsIOService::GetConnectivity(bool *aConnectivity) |
1104 | 0 | { |
1105 | 0 | *aConnectivity = mConnectivity; |
1106 | 0 | return NS_OK; |
1107 | 0 | } |
1108 | | |
1109 | | NS_IMETHODIMP |
1110 | | nsIOService::SetConnectivity(bool aConnectivity) |
1111 | 0 | { |
1112 | 0 | LOG(("nsIOService::SetConnectivity aConnectivity=%d\n", aConnectivity)); |
1113 | 0 | // This should only be called from ContentChild to pass the connectivity |
1114 | 0 | // value from the chrome process to the content process. |
1115 | 0 | if (XRE_IsParentProcess()) { |
1116 | 0 | return NS_ERROR_NOT_AVAILABLE; |
1117 | 0 | } |
1118 | 0 | return SetConnectivityInternal(aConnectivity); |
1119 | 0 | } |
1120 | | |
1121 | | nsresult |
1122 | | nsIOService::SetConnectivityInternal(bool aConnectivity) |
1123 | 0 | { |
1124 | 0 | LOG(("nsIOService::SetConnectivityInternal aConnectivity=%d\n", aConnectivity)); |
1125 | 0 | if (mConnectivity == aConnectivity) { |
1126 | 0 | // Nothing to do here. |
1127 | 0 | return NS_OK; |
1128 | 0 | } |
1129 | 0 | mConnectivity = aConnectivity; |
1130 | 0 |
|
1131 | 0 | // This is used for PR_Connect PR_Close telemetry so it is important that |
1132 | 0 | // we have statistic about network change event even if we are offline. |
1133 | 0 | mLastConnectivityChange = PR_IntervalNow(); |
1134 | 0 |
|
1135 | 0 | if (mCaptivePortalService) { |
1136 | 0 | if (aConnectivity && gCaptivePortalEnabled) { |
1137 | 0 | // This will also trigger a captive portal check for the new network |
1138 | 0 | static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Start(); |
1139 | 0 | } else { |
1140 | 0 | static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Stop(); |
1141 | 0 | } |
1142 | 0 | } |
1143 | 0 |
|
1144 | 0 | nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); |
1145 | 0 | if (!observerService) { |
1146 | 0 | return NS_OK; |
1147 | 0 | } |
1148 | 0 | // This notification sends the connectivity to the child processes |
1149 | 0 | if (XRE_IsParentProcess()) { |
1150 | 0 | observerService->NotifyObservers(nullptr, |
1151 | 0 | NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC, aConnectivity ? |
1152 | 0 | u"true" : |
1153 | 0 | u"false"); |
1154 | 0 | } |
1155 | 0 |
|
1156 | 0 | if (mOffline) { |
1157 | 0 | // We don't need to send any notifications if we're offline |
1158 | 0 | return NS_OK; |
1159 | 0 | } |
1160 | 0 | |
1161 | 0 | if (aConnectivity) { |
1162 | 0 | // If we were previously offline due to connectivity=false, |
1163 | 0 | // send the ONLINE notification |
1164 | 0 | observerService->NotifyObservers( |
1165 | 0 | static_cast<nsIIOService *>(this), |
1166 | 0 | NS_IOSERVICE_OFFLINE_STATUS_TOPIC, |
1167 | 0 | (u"" NS_IOSERVICE_ONLINE)); |
1168 | 0 | } else { |
1169 | 0 | // If we were previously online and lost connectivity |
1170 | 0 | // send the OFFLINE notification |
1171 | 0 | observerService->NotifyObservers(static_cast<nsIIOService *>(this), |
1172 | 0 | NS_IOSERVICE_GOING_OFFLINE_TOPIC, |
1173 | 0 | u"" NS_IOSERVICE_OFFLINE); |
1174 | 0 | observerService->NotifyObservers(static_cast<nsIIOService *>(this), |
1175 | 0 | NS_IOSERVICE_OFFLINE_STATUS_TOPIC, |
1176 | 0 | u"" NS_IOSERVICE_OFFLINE); |
1177 | 0 | } |
1178 | 0 | return NS_OK; |
1179 | 0 | } |
1180 | | |
1181 | | NS_IMETHODIMP |
1182 | | nsIOService::AllowPort(int32_t inPort, const char *scheme, bool *_retval) |
1183 | 0 | { |
1184 | 0 | int16_t port = inPort; |
1185 | 0 | if (port == -1) { |
1186 | 0 | *_retval = true; |
1187 | 0 | return NS_OK; |
1188 | 0 | } |
1189 | 0 | |
1190 | 0 | if (port == 0) { |
1191 | 0 | *_retval = false; |
1192 | 0 | return NS_OK; |
1193 | 0 | } |
1194 | 0 | |
1195 | 0 | // first check to see if the port is in our blacklist: |
1196 | 0 | int32_t badPortListCnt = mRestrictedPortList.Length(); |
1197 | 0 | for (int i=0; i<badPortListCnt; i++) |
1198 | 0 | { |
1199 | 0 | if (port == mRestrictedPortList[i]) |
1200 | 0 | { |
1201 | 0 | *_retval = false; |
1202 | 0 |
|
1203 | 0 | // check to see if the protocol wants to override |
1204 | 0 | if (!scheme) |
1205 | 0 | return NS_OK; |
1206 | 0 | |
1207 | 0 | nsCOMPtr<nsIProtocolHandler> handler; |
1208 | 0 | nsresult rv = GetProtocolHandler(scheme, getter_AddRefs(handler)); |
1209 | 0 | if (NS_FAILED(rv)) return rv; |
1210 | 0 | |
1211 | 0 | // let the protocol handler decide |
1212 | 0 | return handler->AllowPort(port, scheme, _retval); |
1213 | 0 | } |
1214 | 0 | } |
1215 | 0 |
|
1216 | 0 | *_retval = true; |
1217 | 0 | return NS_OK; |
1218 | 0 | } |
1219 | | |
1220 | | //////////////////////////////////////////////////////////////////////////////// |
1221 | | |
1222 | | void |
1223 | | nsIOService::PrefsChanged(const char *pref) |
1224 | 3 | { |
1225 | 3 | // Look for extra ports to block |
1226 | 3 | if (!pref || strcmp(pref, PORT_PREF("banned")) == 0) |
1227 | 3 | ParsePortList(PORT_PREF("banned"), false); |
1228 | 3 | |
1229 | 3 | // ...as well as previous blocks to remove. |
1230 | 3 | if (!pref || strcmp(pref, PORT_PREF("banned.override")) == 0) |
1231 | 3 | ParsePortList(PORT_PREF("banned.override"), true); |
1232 | 3 | |
1233 | 3 | if (!pref || strcmp(pref, MANAGE_OFFLINE_STATUS_PREF) == 0) { |
1234 | 3 | bool manage; |
1235 | 3 | if (mNetworkLinkServiceInitialized && |
1236 | 3 | NS_SUCCEEDED(Preferences::GetBool(MANAGE_OFFLINE_STATUS_PREF, |
1237 | 3 | &manage))) { |
1238 | 0 | LOG(("nsIOService::PrefsChanged ManageOfflineStatus manage=%d\n", manage)); |
1239 | 0 | SetManageOfflineStatus(manage); |
1240 | 0 | } |
1241 | 3 | } |
1242 | 3 | |
1243 | 3 | if (!pref || strcmp(pref, NECKO_BUFFER_CACHE_COUNT_PREF) == 0) { |
1244 | 3 | int32_t count; |
1245 | 3 | if (NS_SUCCEEDED(Preferences::GetInt(NECKO_BUFFER_CACHE_COUNT_PREF, |
1246 | 3 | &count))) |
1247 | 3 | /* check for bogus values and default if we find such a value */ |
1248 | 3 | if (count > 0) |
1249 | 3 | gDefaultSegmentCount = count; |
1250 | 3 | } |
1251 | 3 | |
1252 | 3 | if (!pref || strcmp(pref, NECKO_BUFFER_CACHE_SIZE_PREF) == 0) { |
1253 | 3 | int32_t size; |
1254 | 3 | if (NS_SUCCEEDED(Preferences::GetInt(NECKO_BUFFER_CACHE_SIZE_PREF, |
1255 | 3 | &size))) |
1256 | 3 | /* check for bogus values and default if we find such a value |
1257 | 3 | * the upper limit here is arbitrary. having a 1mb segment size |
1258 | 3 | * is pretty crazy. if you remove this, consider adding some |
1259 | 3 | * integer rollover test. |
1260 | 3 | */ |
1261 | 3 | if (size > 0 && size < 1024*1024) |
1262 | 3 | gDefaultSegmentSize = size; |
1263 | 3 | NS_WARNING_ASSERTION(!(size & (size - 1)), |
1264 | 3 | "network segment size is not a power of 2!"); |
1265 | 3 | } |
1266 | 3 | |
1267 | 3 | if (!pref || strcmp(pref, NETWORK_NOTIFY_CHANGED_PREF) == 0) { |
1268 | 3 | bool allow; |
1269 | 3 | nsresult rv = Preferences::GetBool(NETWORK_NOTIFY_CHANGED_PREF, &allow); |
1270 | 3 | if (NS_SUCCEEDED(rv)) { |
1271 | 3 | mNetworkNotifyChanged = allow; |
1272 | 3 | } |
1273 | 3 | } |
1274 | 3 | |
1275 | 3 | if (!pref || strcmp(pref, NETWORK_CAPTIVE_PORTAL_PREF) == 0) { |
1276 | 3 | nsresult rv = Preferences::GetBool(NETWORK_CAPTIVE_PORTAL_PREF, &gCaptivePortalEnabled); |
1277 | 3 | if (NS_SUCCEEDED(rv) && mCaptivePortalService) { |
1278 | 3 | if (gCaptivePortalEnabled) { |
1279 | 0 | static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Start(); |
1280 | 3 | } else { |
1281 | 3 | static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Stop(); |
1282 | 3 | } |
1283 | 3 | } |
1284 | 3 | } |
1285 | 3 | } |
1286 | | |
1287 | | void |
1288 | | nsIOService::ParsePortList(const char *pref, bool remove) |
1289 | 6 | { |
1290 | 6 | nsAutoCString portList; |
1291 | 6 | |
1292 | 6 | // Get a pref string and chop it up into a list of ports. |
1293 | 6 | Preferences::GetCString(pref, portList); |
1294 | 6 | if (!portList.IsVoid()) { |
1295 | 0 | nsTArray<nsCString> portListArray; |
1296 | 0 | ParseString(portList, ',', portListArray); |
1297 | 0 | uint32_t index; |
1298 | 0 | for (index=0; index < portListArray.Length(); index++) { |
1299 | 0 | portListArray[index].StripWhitespace(); |
1300 | 0 | int32_t portBegin, portEnd; |
1301 | 0 |
|
1302 | 0 | if (PR_sscanf(portListArray[index].get(), "%d-%d", &portBegin, &portEnd) == 2) { |
1303 | 0 | if ((portBegin < 65536) && (portEnd < 65536)) { |
1304 | 0 | int32_t curPort; |
1305 | 0 | if (remove) { |
1306 | 0 | for (curPort=portBegin; curPort <= portEnd; curPort++) |
1307 | 0 | mRestrictedPortList.RemoveElement(curPort); |
1308 | 0 | } else { |
1309 | 0 | for (curPort=portBegin; curPort <= portEnd; curPort++) |
1310 | 0 | mRestrictedPortList.AppendElement(curPort); |
1311 | 0 | } |
1312 | 0 | } |
1313 | 0 | } else { |
1314 | 0 | nsresult aErrorCode; |
1315 | 0 | int32_t port = portListArray[index].ToInteger(&aErrorCode); |
1316 | 0 | if (NS_SUCCEEDED(aErrorCode) && port < 65536) { |
1317 | 0 | if (remove) |
1318 | 0 | mRestrictedPortList.RemoveElement(port); |
1319 | 0 | else |
1320 | 0 | mRestrictedPortList.AppendElement(port); |
1321 | 0 | } |
1322 | 0 | } |
1323 | 0 |
|
1324 | 0 | } |
1325 | 0 | } |
1326 | 6 | } |
1327 | | |
1328 | | class nsWakeupNotifier : public Runnable |
1329 | | { |
1330 | | public: |
1331 | | explicit nsWakeupNotifier(nsIIOServiceInternal* ioService) |
1332 | | : Runnable("net::nsWakeupNotifier") |
1333 | | , mIOService(ioService) |
1334 | 0 | { |
1335 | 0 | } |
1336 | | |
1337 | 0 | NS_IMETHOD Run() override { return mIOService->NotifyWakeup(); } |
1338 | | |
1339 | | private: |
1340 | 0 | virtual ~nsWakeupNotifier() = default; |
1341 | | nsCOMPtr<nsIIOServiceInternal> mIOService; |
1342 | | }; |
1343 | | |
1344 | | NS_IMETHODIMP |
1345 | | nsIOService::NotifyWakeup() |
1346 | 0 | { |
1347 | 0 | nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); |
1348 | 0 |
|
1349 | 0 | NS_ASSERTION(observerService, "The observer service should not be null"); |
1350 | 0 |
|
1351 | 0 | if (observerService && mNetworkNotifyChanged) { |
1352 | 0 | (void)observerService-> |
1353 | 0 | NotifyObservers(nullptr, |
1354 | 0 | NS_NETWORK_LINK_TOPIC, |
1355 | 0 | (u"" NS_NETWORK_LINK_DATA_CHANGED)); |
1356 | 0 | } |
1357 | 0 |
|
1358 | 0 | RecheckCaptivePortal(); |
1359 | 0 |
|
1360 | 0 | return NS_OK; |
1361 | 0 | } |
1362 | | |
1363 | | void |
1364 | | nsIOService::SetHttpHandlerAlreadyShutingDown() |
1365 | 0 | { |
1366 | 0 | if (!mShutdown && !mOfflineForProfileChange) { |
1367 | 0 | mNetTearingDownStarted = PR_IntervalNow(); |
1368 | 0 | mHttpHandlerAlreadyShutingDown = true; |
1369 | 0 | } |
1370 | 0 | } |
1371 | | |
1372 | | // nsIObserver interface |
1373 | | NS_IMETHODIMP |
1374 | | nsIOService::Observe(nsISupports *subject, |
1375 | | const char *topic, |
1376 | | const char16_t *data) |
1377 | 0 | { |
1378 | 0 | if (!strcmp(topic, kProfileChangeNetTeardownTopic)) { |
1379 | 0 | if (!mHttpHandlerAlreadyShutingDown) { |
1380 | 0 | mNetTearingDownStarted = PR_IntervalNow(); |
1381 | 0 | } |
1382 | 0 | mHttpHandlerAlreadyShutingDown = false; |
1383 | 0 | if (!mOffline) { |
1384 | 0 | mOfflineForProfileChange = true; |
1385 | 0 | SetOffline(true); |
1386 | 0 | } |
1387 | 0 | } else if (!strcmp(topic, kProfileChangeNetRestoreTopic)) { |
1388 | 0 | if (mOfflineForProfileChange) { |
1389 | 0 | mOfflineForProfileChange = false; |
1390 | 0 | SetOffline(false); |
1391 | 0 | } |
1392 | 0 | } else if (!strcmp(topic, kProfileDoChange)) { |
1393 | 0 | if (data && NS_LITERAL_STRING("startup").Equals(data)) { |
1394 | 0 | // Lazy initialization of network link service (see bug 620472) |
1395 | 0 | InitializeNetworkLinkService(); |
1396 | 0 | // Set up the initilization flag regardless the actuall result. |
1397 | 0 | // If we fail here, we will fail always on. |
1398 | 0 | mNetworkLinkServiceInitialized = true; |
1399 | 0 |
|
1400 | 0 | // And now reflect the preference setting |
1401 | 0 | PrefsChanged(MANAGE_OFFLINE_STATUS_PREF); |
1402 | 0 |
|
1403 | 0 | // Bug 870460 - Read cookie database at an early-as-possible time |
1404 | 0 | // off main thread. Hence, we have more chance to finish db query |
1405 | 0 | // before something calls into the cookie service. |
1406 | 0 | nsCOMPtr<nsISupports> cookieServ = do_GetService(NS_COOKIESERVICE_CONTRACTID); |
1407 | 0 | } |
1408 | 0 | } else if (!strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) { |
1409 | 0 | // Remember we passed XPCOM shutdown notification to prevent any |
1410 | 0 | // changes of the offline status from now. We must not allow going |
1411 | 0 | // online after this point. |
1412 | 0 | mShutdown = true; |
1413 | 0 |
|
1414 | 0 | if (!mHttpHandlerAlreadyShutingDown && !mOfflineForProfileChange) { |
1415 | 0 | mNetTearingDownStarted = PR_IntervalNow(); |
1416 | 0 | } |
1417 | 0 | mHttpHandlerAlreadyShutingDown = false; |
1418 | 0 |
|
1419 | 0 | SetOffline(true); |
1420 | 0 |
|
1421 | 0 | if (mCaptivePortalService) { |
1422 | 0 | static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Stop(); |
1423 | 0 | mCaptivePortalService = nullptr; |
1424 | 0 | } |
1425 | 0 |
|
1426 | 0 | } else if (!strcmp(topic, NS_NETWORK_LINK_TOPIC)) { |
1427 | 0 | OnNetworkLinkEvent(NS_ConvertUTF16toUTF8(data).get()); |
1428 | 0 | } else if (!strcmp(topic, NS_WIDGET_WAKE_OBSERVER_TOPIC)) { |
1429 | 0 | // coming back alive from sleep |
1430 | 0 | // this indirection brought to you by: |
1431 | 0 | // https://bugzilla.mozilla.org/show_bug.cgi?id=1152048#c19 |
1432 | 0 | nsCOMPtr<nsIRunnable> wakeupNotifier = new nsWakeupNotifier(this); |
1433 | 0 | NS_DispatchToMainThread(wakeupNotifier); |
1434 | 0 | } |
1435 | 0 |
|
1436 | 0 | return NS_OK; |
1437 | 0 | } |
1438 | | |
1439 | | // nsINetUtil interface |
1440 | | NS_IMETHODIMP |
1441 | | nsIOService::ParseRequestContentType(const nsACString &aTypeHeader, |
1442 | | nsACString &aCharset, |
1443 | | bool *aHadCharset, |
1444 | | nsACString &aContentType) |
1445 | 0 | { |
1446 | 0 | net_ParseRequestContentType(aTypeHeader, aContentType, aCharset, aHadCharset); |
1447 | 0 | return NS_OK; |
1448 | 0 | } |
1449 | | |
1450 | | // nsINetUtil interface |
1451 | | NS_IMETHODIMP |
1452 | | nsIOService::ParseResponseContentType(const nsACString &aTypeHeader, |
1453 | | nsACString &aCharset, |
1454 | | bool *aHadCharset, |
1455 | | nsACString &aContentType) |
1456 | 0 | { |
1457 | 0 | net_ParseContentType(aTypeHeader, aContentType, aCharset, aHadCharset); |
1458 | 0 | return NS_OK; |
1459 | 0 | } |
1460 | | |
1461 | | NS_IMETHODIMP |
1462 | | nsIOService::ProtocolHasFlags(nsIURI *uri, |
1463 | | uint32_t flags, |
1464 | | bool *result) |
1465 | 11.7k | { |
1466 | 11.7k | NS_ENSURE_ARG(uri); |
1467 | 11.7k | |
1468 | 11.7k | *result = false; |
1469 | 11.7k | nsAutoCString scheme; |
1470 | 11.7k | nsresult rv = uri->GetScheme(scheme); |
1471 | 11.7k | NS_ENSURE_SUCCESS(rv, rv); |
1472 | 11.7k | |
1473 | 11.7k | // Grab the protocol flags from the URI. |
1474 | 11.7k | uint32_t protocolFlags; |
1475 | 11.7k | nsCOMPtr<nsIProtocolHandler> handler; |
1476 | 11.7k | rv = GetProtocolHandler(scheme.get(), getter_AddRefs(handler)); |
1477 | 11.7k | NS_ENSURE_SUCCESS(rv, rv); |
1478 | 11.7k | rv = handler->DoGetProtocolFlags(uri, &protocolFlags); |
1479 | 11.7k | NS_ENSURE_SUCCESS(rv, rv); |
1480 | 11.7k | |
1481 | 11.7k | *result = (protocolFlags & flags) == flags; |
1482 | 11.7k | return NS_OK; |
1483 | 11.7k | } |
1484 | | |
1485 | | NS_IMETHODIMP |
1486 | | nsIOService::URIChainHasFlags(nsIURI *uri, |
1487 | | uint32_t flags, |
1488 | | bool *result) |
1489 | 11.6k | { |
1490 | 11.6k | nsresult rv = ProtocolHasFlags(uri, flags, result); |
1491 | 11.6k | NS_ENSURE_SUCCESS(rv, rv); |
1492 | 11.6k | |
1493 | 11.6k | if (*result) { |
1494 | 39 | return rv; |
1495 | 39 | } |
1496 | 11.6k | |
1497 | 11.6k | // Dig deeper into the chain. Note that this is not a do/while loop to |
1498 | 11.6k | // avoid the extra addref/release on |uri| in the common (non-nested) case. |
1499 | 11.6k | nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(uri); |
1500 | 11.6k | while (nestedURI) { |
1501 | 90 | nsCOMPtr<nsIURI> innerURI; |
1502 | 90 | rv = nestedURI->GetInnerURI(getter_AddRefs(innerURI)); |
1503 | 90 | NS_ENSURE_SUCCESS(rv, rv); |
1504 | 90 | |
1505 | 90 | rv = ProtocolHasFlags(innerURI, flags, result); |
1506 | 90 | |
1507 | 90 | if (*result) { |
1508 | 90 | return rv; |
1509 | 90 | } |
1510 | 0 | |
1511 | 0 | nestedURI = do_QueryInterface(innerURI); |
1512 | 0 | } |
1513 | 11.6k | |
1514 | 11.6k | return rv; |
1515 | 11.6k | } |
1516 | | |
1517 | | NS_IMETHODIMP |
1518 | | nsIOService::SetManageOfflineStatus(bool aManage) |
1519 | 0 | { |
1520 | 0 | LOG(("nsIOService::SetManageOfflineStatus aManage=%d\n", aManage)); |
1521 | 0 | mManageLinkStatus = aManage; |
1522 | 0 |
|
1523 | 0 | // When detection is not activated, the default connectivity state is true. |
1524 | 0 | if (!mManageLinkStatus) { |
1525 | 0 | SetConnectivityInternal(true); |
1526 | 0 | return NS_OK; |
1527 | 0 | } |
1528 | 0 | |
1529 | 0 | InitializeNetworkLinkService(); |
1530 | 0 | // If the NetworkLinkService is already initialized, it does not call |
1531 | 0 | // OnNetworkLinkEvent. This is needed, when mManageLinkStatus goes from |
1532 | 0 | // false to true. |
1533 | 0 | OnNetworkLinkEvent(NS_NETWORK_LINK_DATA_UNKNOWN); |
1534 | 0 | return NS_OK; |
1535 | 0 | } |
1536 | | |
1537 | | NS_IMETHODIMP |
1538 | | nsIOService::GetManageOfflineStatus(bool* aManage) |
1539 | 0 | { |
1540 | 0 | *aManage = mManageLinkStatus; |
1541 | 0 | return NS_OK; |
1542 | 0 | } |
1543 | | |
1544 | | // input argument 'data' is already UTF8'ed |
1545 | | nsresult |
1546 | | nsIOService::OnNetworkLinkEvent(const char *data) |
1547 | 3 | { |
1548 | 3 | if (IsNeckoChild()) { |
1549 | 0 | // There is nothing IO service could do on the child process |
1550 | 0 | // with this at the moment. Feel free to add functionality |
1551 | 0 | // here at will, though. |
1552 | 0 | return NS_OK; |
1553 | 0 | } |
1554 | 3 | |
1555 | 3 | if (mShutdown) { |
1556 | 0 | return NS_ERROR_NOT_AVAILABLE; |
1557 | 0 | } |
1558 | 3 | |
1559 | 3 | nsCString dataAsString(data); |
1560 | 3 | for (auto* cp : mozilla::dom::ContentParent::AllProcesses(mozilla::dom::ContentParent::eLive)) { |
1561 | 0 | PNeckoParent* neckoParent = SingleManagedOrNull(cp->ManagedPNeckoParent()); |
1562 | 0 | if (!neckoParent) { |
1563 | 0 | continue; |
1564 | 0 | } |
1565 | 0 | Unused << neckoParent->SendNetworkChangeNotification(dataAsString); |
1566 | 0 | } |
1567 | 3 | |
1568 | 3 | LOG(("nsIOService::OnNetworkLinkEvent data:%s\n", data)); |
1569 | 3 | if (!mNetworkLinkService) { |
1570 | 0 | return NS_ERROR_FAILURE; |
1571 | 0 | } |
1572 | 3 | |
1573 | 3 | if (!mManageLinkStatus) { |
1574 | 3 | LOG(("nsIOService::OnNetworkLinkEvent mManageLinkStatus=false\n")); |
1575 | 3 | return NS_OK; |
1576 | 3 | } |
1577 | 0 | |
1578 | 0 | bool isUp = true; |
1579 | 0 | if (!strcmp(data, NS_NETWORK_LINK_DATA_CHANGED)) { |
1580 | 0 | mLastNetworkLinkChange = PR_IntervalNow(); |
1581 | 0 | // CHANGED means UP/DOWN didn't change |
1582 | 0 | // but the status of the captive portal may have changed. |
1583 | 0 | RecheckCaptivePortal(); |
1584 | 0 | return NS_OK; |
1585 | 0 | } |
1586 | 0 | if (!strcmp(data, NS_NETWORK_LINK_DATA_DOWN)) { |
1587 | 0 | isUp = false; |
1588 | 0 | } else if (!strcmp(data, NS_NETWORK_LINK_DATA_UP)) { |
1589 | 0 | isUp = true; |
1590 | 0 | } else if (!strcmp(data, NS_NETWORK_LINK_DATA_UNKNOWN)) { |
1591 | 0 | nsresult rv = mNetworkLinkService->GetIsLinkUp(&isUp); |
1592 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
1593 | 0 | } else { |
1594 | 0 | NS_WARNING("Unhandled network event!"); |
1595 | 0 | return NS_OK; |
1596 | 0 | } |
1597 | 0 |
|
1598 | 0 | return SetConnectivityInternal(isUp); |
1599 | 0 | } |
1600 | | |
1601 | | NS_IMETHODIMP |
1602 | | nsIOService::EscapeString(const nsACString& aString, |
1603 | | uint32_t aEscapeType, |
1604 | | nsACString& aResult) |
1605 | 0 | { |
1606 | 0 | NS_ENSURE_ARG_MAX(aEscapeType, 4); |
1607 | 0 |
|
1608 | 0 | nsAutoCString stringCopy(aString); |
1609 | 0 | nsCString result; |
1610 | 0 |
|
1611 | 0 | if (!NS_Escape(stringCopy, result, (nsEscapeMask) aEscapeType)) |
1612 | 0 | return NS_ERROR_OUT_OF_MEMORY; |
1613 | 0 | |
1614 | 0 | aResult.Assign(result); |
1615 | 0 |
|
1616 | 0 | return NS_OK; |
1617 | 0 | } |
1618 | | |
1619 | | NS_IMETHODIMP |
1620 | | nsIOService::EscapeURL(const nsACString &aStr, |
1621 | | uint32_t aFlags, nsACString &aResult) |
1622 | 0 | { |
1623 | 0 | aResult.Truncate(); |
1624 | 0 | NS_EscapeURL(aStr.BeginReading(), aStr.Length(), |
1625 | 0 | aFlags | esc_AlwaysCopy, aResult); |
1626 | 0 | return NS_OK; |
1627 | 0 | } |
1628 | | |
1629 | | NS_IMETHODIMP |
1630 | | nsIOService::UnescapeString(const nsACString &aStr, |
1631 | | uint32_t aFlags, nsACString &aResult) |
1632 | 0 | { |
1633 | 0 | aResult.Truncate(); |
1634 | 0 | NS_UnescapeURL(aStr.BeginReading(), aStr.Length(), |
1635 | 0 | aFlags | esc_AlwaysCopy, aResult); |
1636 | 0 | return NS_OK; |
1637 | 0 | } |
1638 | | |
1639 | | NS_IMETHODIMP |
1640 | | nsIOService::ExtractCharsetFromContentType(const nsACString &aTypeHeader, |
1641 | | nsACString &aCharset, |
1642 | | int32_t *aCharsetStart, |
1643 | | int32_t *aCharsetEnd, |
1644 | | bool *aHadCharset) |
1645 | 0 | { |
1646 | 0 | nsAutoCString ignored; |
1647 | 0 | net_ParseContentType(aTypeHeader, ignored, aCharset, aHadCharset, |
1648 | 0 | aCharsetStart, aCharsetEnd); |
1649 | 0 | if (*aHadCharset && *aCharsetStart == *aCharsetEnd) { |
1650 | 0 | *aHadCharset = false; |
1651 | 0 | } |
1652 | 0 | return NS_OK; |
1653 | 0 | } |
1654 | | |
1655 | | // parse policyString to policy enum value (see ReferrerPolicy.h) |
1656 | | NS_IMETHODIMP |
1657 | | nsIOService::ParseAttributePolicyString(const nsAString& policyString, |
1658 | | uint32_t *outPolicyEnum) |
1659 | 0 | { |
1660 | 0 | NS_ENSURE_ARG(outPolicyEnum); |
1661 | 0 | *outPolicyEnum = (uint32_t)AttributeReferrerPolicyFromString(policyString); |
1662 | 0 | return NS_OK; |
1663 | 0 | } |
1664 | | |
1665 | | // nsISpeculativeConnect |
1666 | | class IOServiceProxyCallback final : public nsIProtocolProxyCallback |
1667 | | { |
1668 | 0 | ~IOServiceProxyCallback() = default; |
1669 | | |
1670 | | public: |
1671 | | NS_DECL_ISUPPORTS |
1672 | | NS_DECL_NSIPROTOCOLPROXYCALLBACK |
1673 | | |
1674 | | IOServiceProxyCallback(nsIInterfaceRequestor *aCallbacks, |
1675 | | nsIOService *aIOService) |
1676 | | : mCallbacks(aCallbacks) |
1677 | | , mIOService(aIOService) |
1678 | 0 | { } |
1679 | | |
1680 | | private: |
1681 | | RefPtr<nsIInterfaceRequestor> mCallbacks; |
1682 | | RefPtr<nsIOService> mIOService; |
1683 | | }; |
1684 | | |
1685 | | NS_IMPL_ISUPPORTS(IOServiceProxyCallback, nsIProtocolProxyCallback) |
1686 | | |
1687 | | NS_IMETHODIMP |
1688 | | IOServiceProxyCallback::OnProxyAvailable(nsICancelable *request, nsIChannel *channel, |
1689 | | nsIProxyInfo *pi, nsresult status) |
1690 | 0 | { |
1691 | 0 | // Checking proxy status for speculative connect |
1692 | 0 | nsAutoCString type; |
1693 | 0 | if (NS_SUCCEEDED(status) && pi && |
1694 | 0 | NS_SUCCEEDED(pi->GetType(type)) && |
1695 | 0 | !type.EqualsLiteral("direct")) { |
1696 | 0 | // proxies dont do speculative connect |
1697 | 0 | return NS_OK; |
1698 | 0 | } |
1699 | 0 | |
1700 | 0 | nsCOMPtr<nsIURI> uri; |
1701 | 0 | nsresult rv = channel->GetURI(getter_AddRefs(uri)); |
1702 | 0 | if (NS_FAILED(rv)) { |
1703 | 0 | return NS_OK; |
1704 | 0 | } |
1705 | 0 | |
1706 | 0 | nsAutoCString scheme; |
1707 | 0 | rv = uri->GetScheme(scheme); |
1708 | 0 | if (NS_FAILED(rv)) |
1709 | 0 | return NS_OK; |
1710 | 0 | |
1711 | 0 | nsCOMPtr<nsIProtocolHandler> handler; |
1712 | 0 | rv = mIOService->GetProtocolHandler(scheme.get(), |
1713 | 0 | getter_AddRefs(handler)); |
1714 | 0 | if (NS_FAILED(rv)) |
1715 | 0 | return NS_OK; |
1716 | 0 | |
1717 | 0 | nsCOMPtr<nsISpeculativeConnect> speculativeHandler = |
1718 | 0 | do_QueryInterface(handler); |
1719 | 0 | if (!speculativeHandler) |
1720 | 0 | return NS_OK; |
1721 | 0 | |
1722 | 0 | nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo(); |
1723 | 0 | nsCOMPtr<nsIPrincipal> principal; |
1724 | 0 | if (loadInfo) { |
1725 | 0 | principal = loadInfo->LoadingPrincipal(); |
1726 | 0 | } |
1727 | 0 |
|
1728 | 0 | nsLoadFlags loadFlags = 0; |
1729 | 0 | channel->GetLoadFlags(&loadFlags); |
1730 | 0 | if (loadFlags & nsIRequest::LOAD_ANONYMOUS) { |
1731 | 0 | speculativeHandler->SpeculativeAnonymousConnect2(uri, principal, mCallbacks); |
1732 | 0 | } else { |
1733 | 0 | speculativeHandler->SpeculativeConnect2(uri, principal, mCallbacks); |
1734 | 0 | } |
1735 | 0 |
|
1736 | 0 | return NS_OK; |
1737 | 0 | } |
1738 | | |
1739 | | nsresult |
1740 | | nsIOService::SpeculativeConnectInternal(nsIURI *aURI, |
1741 | | nsIPrincipal *aPrincipal, |
1742 | | nsIInterfaceRequestor *aCallbacks, |
1743 | | bool aAnonymous) |
1744 | 0 | { |
1745 | 0 | NS_ENSURE_ARG(aURI); |
1746 | 0 |
|
1747 | 0 | bool isHTTP, isHTTPS; |
1748 | 0 | if (!(NS_SUCCEEDED(aURI->SchemeIs("http", &isHTTP)) && isHTTP) && |
1749 | 0 | !(NS_SUCCEEDED(aURI->SchemeIs("https", &isHTTPS)) && isHTTPS)) { |
1750 | 0 | // We don't speculatively connect to non-HTTP[S] URIs. |
1751 | 0 | return NS_OK; |
1752 | 0 | } |
1753 | 0 | |
1754 | 0 | if (IsNeckoChild()) { |
1755 | 0 | ipc::URIParams params; |
1756 | 0 | SerializeURI(aURI, params); |
1757 | 0 | gNeckoChild->SendSpeculativeConnect(params, |
1758 | 0 | IPC::Principal(aPrincipal), |
1759 | 0 | aAnonymous); |
1760 | 0 | return NS_OK; |
1761 | 0 | } |
1762 | 0 | |
1763 | 0 | // Check for proxy information. If there is a proxy configured then a |
1764 | 0 | // speculative connect should not be performed because the potential |
1765 | 0 | // reward is slim with tcp peers closely located to the browser. |
1766 | 0 | nsresult rv; |
1767 | 0 | nsCOMPtr<nsIProtocolProxyService> pps = |
1768 | 0 | do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv); |
1769 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
1770 | 0 |
|
1771 | 0 | nsCOMPtr<nsIPrincipal> loadingPrincipal = aPrincipal; |
1772 | 0 |
|
1773 | 0 | NS_ASSERTION(aPrincipal, "We expect passing a principal here."); |
1774 | 0 |
|
1775 | 0 | // If the principal is given, we use this principal directly. Otherwise, |
1776 | 0 | // we fallback to use the system principal. |
1777 | 0 | if (!aPrincipal) { |
1778 | 0 | loadingPrincipal = nsContentUtils::GetSystemPrincipal(); |
1779 | 0 | } |
1780 | 0 |
|
1781 | 0 | // dummy channel used to create a TCP connection. |
1782 | 0 | // we perform security checks on the *real* channel, responsible |
1783 | 0 | // for any network loads. this real channel just checks the TCP |
1784 | 0 | // pool if there is an available connection created by the |
1785 | 0 | // channel we create underneath - hence it's safe to use |
1786 | 0 | // the systemPrincipal as the loadingPrincipal for this channel. |
1787 | 0 | nsCOMPtr<nsIChannel> channel; |
1788 | 0 | rv = NewChannelFromURI2(aURI, |
1789 | 0 | nullptr, // aLoadingNode, |
1790 | 0 | loadingPrincipal, |
1791 | 0 | nullptr, //aTriggeringPrincipal, |
1792 | 0 | nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL, |
1793 | 0 | nsIContentPolicy::TYPE_SPECULATIVE, |
1794 | 0 | getter_AddRefs(channel)); |
1795 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
1796 | 0 |
|
1797 | 0 | if (aAnonymous) { |
1798 | 0 | nsLoadFlags loadFlags = 0; |
1799 | 0 | channel->GetLoadFlags(&loadFlags); |
1800 | 0 | loadFlags |= nsIRequest::LOAD_ANONYMOUS; |
1801 | 0 | channel->SetLoadFlags(loadFlags); |
1802 | 0 | } |
1803 | 0 |
|
1804 | 0 | nsCOMPtr<nsICancelable> cancelable; |
1805 | 0 | RefPtr<IOServiceProxyCallback> callback = |
1806 | 0 | new IOServiceProxyCallback(aCallbacks, this); |
1807 | 0 | nsCOMPtr<nsIProtocolProxyService2> pps2 = do_QueryInterface(pps); |
1808 | 0 | if (pps2) { |
1809 | 0 | return pps2->AsyncResolve2(channel, 0, callback, nullptr, |
1810 | 0 | getter_AddRefs(cancelable)); |
1811 | 0 | } |
1812 | 0 | return pps->AsyncResolve(channel, 0, callback, nullptr, |
1813 | 0 | getter_AddRefs(cancelable)); |
1814 | 0 | } |
1815 | | |
1816 | | NS_IMETHODIMP |
1817 | | nsIOService::SpeculativeConnect(nsIURI *aURI, |
1818 | | nsIInterfaceRequestor *aCallbacks) |
1819 | 0 | { |
1820 | 0 | return SpeculativeConnectInternal(aURI, nullptr, aCallbacks, false); |
1821 | 0 | } |
1822 | | |
1823 | | NS_IMETHODIMP |
1824 | | nsIOService::SpeculativeConnect2(nsIURI *aURI, |
1825 | | nsIPrincipal *aPrincipal, |
1826 | | nsIInterfaceRequestor *aCallbacks) |
1827 | 0 | { |
1828 | 0 | return SpeculativeConnectInternal(aURI, aPrincipal, aCallbacks, false); |
1829 | 0 | } |
1830 | | |
1831 | | NS_IMETHODIMP |
1832 | | nsIOService::SpeculativeAnonymousConnect(nsIURI *aURI, |
1833 | | nsIInterfaceRequestor *aCallbacks) |
1834 | 0 | { |
1835 | 0 | return SpeculativeConnectInternal(aURI, nullptr, aCallbacks, true); |
1836 | 0 | } |
1837 | | |
1838 | | NS_IMETHODIMP |
1839 | | nsIOService::SpeculativeAnonymousConnect2(nsIURI *aURI, |
1840 | | nsIPrincipal *aPrincipal, |
1841 | | nsIInterfaceRequestor *aCallbacks) |
1842 | 0 | { |
1843 | 0 | return SpeculativeConnectInternal(aURI, aPrincipal, aCallbacks, true); |
1844 | 0 | } |
1845 | | |
1846 | | /*static*/ bool |
1847 | | nsIOService::IsDataURIUniqueOpaqueOrigin() |
1848 | 0 | { |
1849 | 0 | return sIsDataURIUniqueOpaqueOrigin; |
1850 | 0 | } |
1851 | | |
1852 | | /*static*/ bool |
1853 | | nsIOService::BlockToplevelDataUriNavigations() |
1854 | 0 | { |
1855 | 0 | return sBlockToplevelDataUriNavigations; |
1856 | 0 | } |
1857 | | |
1858 | | /*static*/ bool |
1859 | | nsIOService::BlockFTPSubresources() |
1860 | 5 | { |
1861 | 5 | return sBlockFTPSubresources; |
1862 | 5 | } |
1863 | | |
1864 | | NS_IMETHODIMP |
1865 | | nsIOService::NotImplemented() |
1866 | 0 | { |
1867 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
1868 | 0 | } |
1869 | | |
1870 | | } // namespace net |
1871 | | } // namespace mozilla |