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