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