Bug 1845134 - Part 4: Update existing ui-icons to use the latest source from acorn...
[gecko.git] / netwerk / base / nsIOService.cpp
blob8450a59b4afee7f55600063aa5a3138cda48c506
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/. */
7 #include "mozilla/DebugOnly.h"
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 "netCore.h"
16 #include "nsIObserverService.h"
17 #include "nsXPCOM.h"
18 #include "nsIProxiedProtocolHandler.h"
19 #include "nsIProxyInfo.h"
20 #include "nsDNSService2.h"
21 #include "nsEscape.h"
22 #include "nsNetUtil.h"
23 #include "nsNetCID.h"
24 #include "nsCRT.h"
25 #include "nsSimpleNestedURI.h"
26 #include "nsSocketTransport2.h"
27 #include "nsTArray.h"
28 #include "nsIConsoleService.h"
29 #include "nsIUploadChannel2.h"
30 #include "nsXULAppAPI.h"
31 #include "nsIProtocolProxyCallback.h"
32 #include "nsICancelable.h"
33 #include "nsINetworkLinkService.h"
34 #include "nsAsyncRedirectVerifyHelper.h"
35 #include "nsURLHelper.h"
36 #include "nsIProtocolProxyService2.h"
37 #include "MainThreadUtils.h"
38 #include "nsINode.h"
39 #include "nsIWebTransport.h"
40 #include "nsIWidget.h"
41 #include "nsThreadUtils.h"
42 #include "WebTransportSessionProxy.h"
43 #include "mozilla/AppShutdown.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/nsHTTPSOnlyUtils.h"
55 #include "mozilla/dom/ServiceWorkerDescriptor.h"
56 #include "mozilla/net/CaptivePortalService.h"
57 #include "mozilla/net/NetworkConnectivityService.h"
58 #include "mozilla/net/SocketProcessHost.h"
59 #include "mozilla/net/SocketProcessParent.h"
60 #include "mozilla/net/SSLTokensCache.h"
61 #include "mozilla/Unused.h"
62 #include "nsContentSecurityManager.h"
63 #include "nsContentUtils.h"
64 #include "mozilla/StaticPrefs_network.h"
65 #include "mozilla/StaticPrefs_security.h"
66 #include "nsNSSComponent.h"
67 #include "ssl.h"
68 #include "StaticComponents.h"
70 namespace mozilla {
71 namespace net {
73 using mozilla::Maybe;
74 using mozilla::dom::ClientInfo;
75 using mozilla::dom::ServiceWorkerDescriptor;
77 #define PORT_PREF_PREFIX "network.security.ports."
78 #define PORT_PREF(x) PORT_PREF_PREFIX x
79 #define MANAGE_OFFLINE_STATUS_PREF "network.manage-offline-status"
81 // Nb: these have been misnomers since bug 715770 removed the buffer cache.
82 // "network.segment.count" and "network.segment.size" would be better names,
83 // but the old names are still used to preserve backward compatibility.
84 #define NECKO_BUFFER_CACHE_COUNT_PREF "network.buffer.cache.count"
85 #define NECKO_BUFFER_CACHE_SIZE_PREF "network.buffer.cache.size"
86 #define NETWORK_CAPTIVE_PORTAL_PREF "network.captive-portal-service.enabled"
87 #define WEBRTC_PREF_PREFIX "media.peerconnection."
88 #define NETWORK_DNS_PREF "network.dns."
89 #define FORCE_EXTERNAL_PREF_PREFIX "network.protocol-handler.external."
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)
98 // A general port blacklist. Connections to these ports will not be allowed
99 // unless the protocol overrides.
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>
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
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";
194 // Necko buffer defaults
195 uint32_t nsIOService::gDefaultSegmentSize = 4096;
196 uint32_t nsIOService::gDefaultSegmentCount = 24;
198 uint32_t nsIOService::sSocketProcessCrashedCount = 0;
200 ////////////////////////////////////////////////////////////////////////////////
202 nsIOService::nsIOService()
203 : mLastOfflineStateChange(PR_IntervalNow()),
204 mLastConnectivityChange(PR_IntervalNow()),
205 mLastNetworkLinkChange(PR_IntervalNow()) {}
207 static const char* gCallbackPrefs[] = {
208 PORT_PREF_PREFIX,
209 MANAGE_OFFLINE_STATUS_PREF,
210 NECKO_BUFFER_CACHE_COUNT_PREF,
211 NECKO_BUFFER_CACHE_SIZE_PREF,
212 NETWORK_CAPTIVE_PORTAL_PREF,
213 FORCE_EXTERNAL_PREF_PREFIX,
214 nullptr,
217 static const char* gCallbackPrefsForSocketProcess[] = {
218 WEBRTC_PREF_PREFIX,
219 NETWORK_DNS_PREF,
220 "network.send_ODA_to_content_directly",
221 "network.trr.",
222 "doh-rollout.",
223 "network.dns.disableIPv6",
224 "network.offline-mirrors-connectivity",
225 "network.disable-localhost-when-offline",
226 "network.proxy.parse_pac_on_socket_process",
227 "network.proxy.allow_hijacking_localhost",
228 "network.connectivity-service.",
229 "network.captive-portal-service.testMode",
230 nullptr,
233 static const char* gCallbackSecurityPrefs[] = {
234 // Note the prefs listed below should be in sync with the code in
235 // HandleTLSPrefChange().
236 "security.tls.version.min",
237 "security.tls.version.max",
238 "security.tls.version.enable-deprecated",
239 "security.tls.hello_downgrade_check",
240 "security.ssl.require_safe_negotiation",
241 "security.ssl.enable_false_start",
242 "security.ssl.enable_alpn",
243 "security.tls.enable_0rtt_data",
244 "security.ssl.disable_session_identifiers",
245 "security.tls.enable_post_handshake_auth",
246 "security.tls.enable_delegated_credentials",
247 // Note the prefs listed below should be in sync with the code in
248 // SetValidationOptionsCommon().
249 "security.ssl.enable_ocsp_stapling",
250 "security.ssl.enable_ocsp_must_staple",
251 "security.pki.certificate_transparency.mode",
252 nullptr,
255 nsresult nsIOService::Init() {
256 SSLTokensCache::Init();
258 InitializeCaptivePortalService();
260 // setup our bad port list stuff
261 for (int i = 0; gBadPortList[i]; i++) {
262 // We can't be accessed by another thread yet
263 MOZ_PUSH_IGNORE_THREAD_SAFETY
264 mRestrictedPortList.AppendElement(gBadPortList[i]);
265 MOZ_POP_THREAD_SAFETY
268 // Further modifications to the port list come from prefs
269 Preferences::RegisterPrefixCallbacks(nsIOService::PrefsChanged,
270 gCallbackPrefs, this);
271 PrefsChanged();
273 mSocketProcessTopicBlockedList.Insert(
274 nsLiteralCString(NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID));
275 mSocketProcessTopicBlockedList.Insert(
276 nsLiteralCString(NS_XPCOM_SHUTDOWN_OBSERVER_ID));
277 mSocketProcessTopicBlockedList.Insert("xpcom-shutdown-threads"_ns);
278 mSocketProcessTopicBlockedList.Insert("profile-do-change"_ns);
279 mSocketProcessTopicBlockedList.Insert("network:socket-process-crashed"_ns);
281 // Register for profile change notifications
282 mObserverService = services::GetObserverService();
283 AddObserver(this, kProfileChangeNetTeardownTopic, true);
284 AddObserver(this, kProfileChangeNetRestoreTopic, true);
285 AddObserver(this, kProfileDoChange, true);
286 AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, true);
287 AddObserver(this, NS_NETWORK_LINK_TOPIC, true);
288 AddObserver(this, NS_NETWORK_ID_CHANGED_TOPIC, true);
289 AddObserver(this, NS_WIDGET_WAKE_OBSERVER_TOPIC, true);
291 // Register observers for sending notifications to nsSocketTransportService
292 if (XRE_IsParentProcess()) {
293 AddObserver(this, "profile-initial-state", true);
294 AddObserver(this, NS_WIDGET_SLEEP_OBSERVER_TOPIC, true);
297 if (IsSocketProcessChild()) {
298 Preferences::RegisterCallbacks(nsIOService::OnTLSPrefChange,
299 gCallbackSecurityPrefs, this);
302 gIOService = this;
304 InitializeNetworkLinkService();
305 InitializeProtocolProxyService();
307 SetOffline(false);
309 return NS_OK;
312 NS_IMETHODIMP
313 nsIOService::AddObserver(nsIObserver* aObserver, const char* aTopic,
314 bool aOwnsWeak) {
315 if (!mObserverService) {
316 return NS_ERROR_FAILURE;
319 // Register for the origional observer.
320 nsresult rv = mObserverService->AddObserver(aObserver, aTopic, aOwnsWeak);
321 if (NS_FAILED(rv)) {
322 return rv;
325 if (!XRE_IsParentProcess()) {
326 return NS_OK;
329 nsAutoCString topic(aTopic);
330 // This happens when AddObserver() is called by nsIOService::Init(). We don't
331 // want to add nsIOService again.
332 if (SameCOMIdentity(aObserver, static_cast<nsIObserver*>(this))) {
333 mIOServiceTopicList.Insert(topic);
334 return NS_OK;
337 if (!UseSocketProcess()) {
338 return NS_OK;
341 if (mSocketProcessTopicBlockedList.Contains(topic)) {
342 return NS_ERROR_FAILURE;
345 // Avoid registering duplicate topics.
346 if (mObserverTopicForSocketProcess.Contains(topic)) {
347 return NS_ERROR_FAILURE;
350 mObserverTopicForSocketProcess.Insert(topic);
352 // Avoid registering duplicate topics.
353 if (mIOServiceTopicList.Contains(topic)) {
354 return NS_ERROR_FAILURE;
357 return mObserverService->AddObserver(this, aTopic, true);
360 NS_IMETHODIMP
361 nsIOService::RemoveObserver(nsIObserver* aObserver, const char* aTopic) {
362 return NS_ERROR_NOT_IMPLEMENTED;
365 NS_IMETHODIMP
366 nsIOService::EnumerateObservers(const char* aTopic,
367 nsISimpleEnumerator** anEnumerator) {
368 return NS_ERROR_NOT_IMPLEMENTED;
371 NS_IMETHODIMP nsIOService::NotifyObservers(nsISupports* aSubject,
372 const char* aTopic,
373 const char16_t* aSomeData) {
374 return NS_ERROR_NOT_IMPLEMENTED;
377 nsIOService::~nsIOService() {
378 if (gIOService) {
379 MOZ_ASSERT(gIOService == this);
380 gIOService = nullptr;
384 // static
385 void nsIOService::OnTLSPrefChange(const char* aPref, void* aSelf) {
386 MOZ_ASSERT(IsSocketProcessChild());
388 if (!EnsureNSSInitializedChromeOrContent()) {
389 LOG(("NSS not initialized."));
390 return;
393 nsAutoCString pref(aPref);
394 // The preferences listed in gCallbackSecurityPrefs need to be in sync with
395 // the code in HandleTLSPrefChange() and SetValidationOptionsCommon().
396 if (HandleTLSPrefChange(pref)) {
397 LOG(("HandleTLSPrefChange done"));
398 } else if (pref.EqualsLiteral("security.ssl.enable_ocsp_stapling") ||
399 pref.EqualsLiteral("security.ssl.enable_ocsp_must_staple") ||
400 pref.EqualsLiteral("security.pki.certificate_transparency.mode")) {
401 SetValidationOptionsCommon();
405 nsresult nsIOService::InitializeCaptivePortalService() {
406 if (XRE_GetProcessType() != GeckoProcessType_Default) {
407 // We only initalize a captive portal service in the main process
408 return NS_OK;
411 mCaptivePortalService = do_GetService(NS_CAPTIVEPORTAL_CID);
412 if (mCaptivePortalService) {
413 return static_cast<CaptivePortalService*>(mCaptivePortalService.get())
414 ->Initialize();
417 // Instantiate and initialize the service
418 RefPtr<NetworkConnectivityService> ncs =
419 NetworkConnectivityService::GetSingleton();
421 return NS_OK;
424 nsresult nsIOService::InitializeSocketTransportService() {
425 nsresult rv = NS_OK;
427 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
428 LOG(
429 ("nsIOService aborting InitializeSocketTransportService because of app "
430 "shutdown"));
431 return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
434 if (!mSocketTransportService) {
435 mSocketTransportService =
436 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
437 if (NS_FAILED(rv)) {
438 NS_WARNING("failed to get socket transport service");
442 if (mSocketTransportService) {
443 rv = mSocketTransportService->Init();
444 NS_ASSERTION(NS_SUCCEEDED(rv), "socket transport service init failed");
445 mSocketTransportService->SetOffline(false);
448 return rv;
451 nsresult nsIOService::InitializeNetworkLinkService() {
452 nsresult rv = NS_OK;
454 if (mNetworkLinkServiceInitialized) return rv;
456 if (!NS_IsMainThread()) {
457 NS_WARNING("Network link service should be created on main thread");
458 return NS_ERROR_FAILURE;
461 // go into managed mode if we can, and chrome process
462 if (!XRE_IsParentProcess()) {
463 return NS_ERROR_NOT_AVAILABLE;
466 mNetworkLinkService = do_GetService(NS_NETWORK_LINK_SERVICE_CONTRACTID, &rv);
468 if (mNetworkLinkService) {
469 mNetworkLinkServiceInitialized = true;
472 // After initializing the networkLinkService, query the connectivity state
473 OnNetworkLinkEvent(NS_NETWORK_LINK_DATA_UNKNOWN);
475 return rv;
478 nsresult nsIOService::InitializeProtocolProxyService() {
479 nsresult rv = NS_OK;
481 if (XRE_IsParentProcess()) {
482 // for early-initialization
483 Unused << do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv);
486 return rv;
489 already_AddRefed<nsIOService> nsIOService::GetInstance() {
490 if (!gIOService) {
491 RefPtr<nsIOService> ios = new nsIOService();
492 if (NS_SUCCEEDED(ios->Init())) {
493 MOZ_ASSERT(gIOService == ios.get());
494 return ios.forget();
497 return do_AddRef(gIOService);
500 class SocketProcessListenerProxy : public SocketProcessHost::Listener {
501 public:
502 SocketProcessListenerProxy() = default;
503 void OnProcessLaunchComplete(SocketProcessHost* aHost, bool aSucceeded) {
504 if (!gIOService) {
505 return;
508 gIOService->OnProcessLaunchComplete(aHost, aSucceeded);
511 void OnProcessUnexpectedShutdown(SocketProcessHost* aHost) {
512 if (!gIOService) {
513 return;
516 gIOService->OnProcessUnexpectedShutdown(aHost);
520 // static
521 bool nsIOService::TooManySocketProcessCrash() {
522 return sSocketProcessCrashedCount >=
523 StaticPrefs::network_max_socket_process_failed_count();
526 // static
527 void nsIOService::IncreaseSocketProcessCrashCount() {
528 MOZ_ASSERT(IsNeckoChild());
529 sSocketProcessCrashedCount++;
532 nsresult nsIOService::LaunchSocketProcess() {
533 MOZ_ASSERT(NS_IsMainThread());
535 if (XRE_GetProcessType() != GeckoProcessType_Default) {
536 return NS_OK;
539 // We shouldn't launch socket prcess when shutdown begins.
540 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
541 return NS_OK;
544 if (mSocketProcess) {
545 return NS_OK;
548 if (PR_GetEnv("MOZ_DISABLE_SOCKET_PROCESS")) {
549 LOG(("nsIOService skipping LaunchSocketProcess because of the env"));
550 return NS_OK;
553 if (!StaticPrefs::network_process_enabled()) {
554 LOG(("nsIOService skipping LaunchSocketProcess because of the pref"));
555 return NS_OK;
558 Preferences::RegisterPrefixCallbacks(
559 nsIOService::NotifySocketProcessPrefsChanged,
560 gCallbackPrefsForSocketProcess, this);
562 // The subprocess is launched asynchronously, so we wait for a callback to
563 // acquire the IPDL actor.
564 mSocketProcess = new SocketProcessHost(new SocketProcessListenerProxy());
565 LOG(("nsIOService::LaunchSocketProcess"));
566 if (!mSocketProcess->Launch()) {
567 NS_WARNING("Failed to launch socket process!!");
568 DestroySocketProcess();
569 return NS_ERROR_FAILURE;
572 return NS_OK;
575 void nsIOService::DestroySocketProcess() {
576 LOG(("nsIOService::DestroySocketProcess"));
577 MOZ_ASSERT(NS_IsMainThread());
579 if (XRE_GetProcessType() != GeckoProcessType_Default || !mSocketProcess) {
580 return;
583 Preferences::UnregisterPrefixCallbacks(
584 nsIOService::NotifySocketProcessPrefsChanged,
585 gCallbackPrefsForSocketProcess, this);
587 mSocketProcess->Shutdown();
588 mSocketProcess = nullptr;
591 bool nsIOService::SocketProcessReady() {
592 return mSocketProcess && mSocketProcess->IsConnected();
595 static bool sUseSocketProcess = false;
596 static bool sUseSocketProcessChecked = false;
598 // static
599 bool nsIOService::UseSocketProcess(bool aCheckAgain) {
600 if (sUseSocketProcessChecked && !aCheckAgain) {
601 return sUseSocketProcess;
604 sUseSocketProcessChecked = true;
605 sUseSocketProcess = false;
607 if (PR_GetEnv("MOZ_DISABLE_SOCKET_PROCESS")) {
608 return sUseSocketProcess;
611 if (TooManySocketProcessCrash()) {
612 LOG(("TooManySocketProcessCrash"));
613 return sUseSocketProcess;
616 if (PR_GetEnv("MOZ_FORCE_USE_SOCKET_PROCESS")) {
617 sUseSocketProcess = true;
618 return sUseSocketProcess;
621 if (StaticPrefs::network_process_enabled()) {
622 sUseSocketProcess =
623 StaticPrefs::network_http_network_access_on_socket_process_enabled();
625 return sUseSocketProcess;
628 // static
629 void nsIOService::NotifySocketProcessPrefsChanged(const char* aName,
630 void* aSelf) {
631 static_cast<nsIOService*>(aSelf)->NotifySocketProcessPrefsChanged(aName);
634 void nsIOService::NotifySocketProcessPrefsChanged(const char* aName) {
635 MOZ_ASSERT(NS_IsMainThread());
637 if (!XRE_IsParentProcess()) {
638 return;
641 if (!StaticPrefs::network_process_enabled()) {
642 return;
645 dom::Pref pref(nsCString(aName), /* isLocked */ false,
646 /* isSanitized */ false, Nothing(), Nothing());
648 Preferences::GetPreference(&pref, GeckoProcessType_Socket,
649 /* remoteType */ ""_ns);
650 auto sendPrefUpdate = [pref]() {
651 Unused << gIOService->mSocketProcess->GetActor()->SendPreferenceUpdate(
652 pref);
654 CallOrWaitForSocketProcess(sendPrefUpdate);
657 void nsIOService::OnProcessLaunchComplete(SocketProcessHost* aHost,
658 bool aSucceeded) {
659 MOZ_ASSERT(NS_IsMainThread());
661 LOG(("nsIOService::OnProcessLaunchComplete aSucceeded=%d\n", aSucceeded));
663 mSocketProcessLaunchComplete = aSucceeded;
665 if (mShutdown || !SocketProcessReady() || !aSucceeded) {
666 mPendingEvents.Clear();
667 return;
670 if (!mPendingEvents.IsEmpty()) {
671 nsTArray<std::function<void()>> pendingEvents = std::move(mPendingEvents);
672 for (auto& func : pendingEvents) {
673 func();
678 void nsIOService::CallOrWaitForSocketProcess(
679 const std::function<void()>& aFunc) {
680 MOZ_ASSERT(NS_IsMainThread());
681 if (IsSocketProcessLaunchComplete() && SocketProcessReady()) {
682 aFunc();
683 } else {
684 mPendingEvents.AppendElement(aFunc); // infallible
685 LaunchSocketProcess();
689 int32_t nsIOService::SocketProcessPid() {
690 if (!mSocketProcess) {
691 return 0;
693 if (SocketProcessParent* actor = mSocketProcess->GetActor()) {
694 return (int32_t)actor->OtherPid();
696 return 0;
699 bool nsIOService::IsSocketProcessLaunchComplete() {
700 MOZ_ASSERT(NS_IsMainThread());
701 return mSocketProcessLaunchComplete;
704 void nsIOService::OnProcessUnexpectedShutdown(SocketProcessHost* aHost) {
705 MOZ_ASSERT(NS_IsMainThread());
707 LOG(("nsIOService::OnProcessUnexpectedShutdown\n"));
708 DestroySocketProcess();
709 mPendingEvents.Clear();
711 // Nothing to do if socket process was not used before.
712 if (!UseSocketProcess()) {
713 return;
716 sSocketProcessCrashedCount++;
717 if (TooManySocketProcessCrash()) {
718 sUseSocketProcessChecked = false;
719 DNSServiceWrapper::SwitchToBackupDNSService();
722 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
723 if (observerService) {
724 (void)observerService->NotifyObservers(
725 nullptr, "network:socket-process-crashed", nullptr);
728 // UseSocketProcess() could return false if we have too many crashes, so we
729 // should call it again.
730 if (UseSocketProcess()) {
731 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(
732 NewRunnableMethod("nsIOService::LaunchSocketProcess", this,
733 &nsIOService::LaunchSocketProcess)));
737 RefPtr<MemoryReportingProcess> nsIOService::GetSocketProcessMemoryReporter() {
738 // Check the prefs here again, since we don't want to create
739 // SocketProcessMemoryReporter for some tests.
740 if (!StaticPrefs::network_process_enabled() || !SocketProcessReady()) {
741 return nullptr;
744 return new SocketProcessMemoryReporter();
747 NS_IMETHODIMP
748 nsIOService::SocketProcessTelemetryPing() {
749 CallOrWaitForSocketProcess([]() {
750 Unused << gIOService->mSocketProcess->GetActor()
751 ->SendSocketProcessTelemetryPing();
753 return NS_OK;
756 NS_IMPL_ISUPPORTS(nsIOService, nsIIOService, nsINetUtil, nsISpeculativeConnect,
757 nsIObserver, nsIIOServiceInternal, nsISupportsWeakReference,
758 nsIObserverService)
760 ////////////////////////////////////////////////////////////////////////////////
762 nsresult nsIOService::RecheckCaptivePortal() {
763 MOZ_ASSERT(NS_IsMainThread(), "Must be called on the main thread");
764 if (!mCaptivePortalService) {
765 return NS_OK;
767 nsCOMPtr<nsIRunnable> task = NewRunnableMethod(
768 "nsIOService::RecheckCaptivePortal", mCaptivePortalService,
769 &nsICaptivePortalService::RecheckCaptivePortal);
770 return NS_DispatchToMainThread(task);
773 nsresult nsIOService::RecheckCaptivePortalIfLocalRedirect(nsIChannel* newChan) {
774 nsresult rv;
776 if (!mCaptivePortalService) {
777 return NS_OK;
780 nsCOMPtr<nsIURI> uri;
781 rv = newChan->GetURI(getter_AddRefs(uri));
782 if (NS_FAILED(rv)) {
783 return rv;
786 nsCString host;
787 rv = uri->GetHost(host);
788 if (NS_FAILED(rv)) {
789 return rv;
792 NetAddr addr;
793 // If the redirect wasn't to an IP literal, so there's probably no need
794 // to trigger the captive portal detection right now. It can wait.
795 if (NS_SUCCEEDED(addr.InitFromString(host)) && addr.IsIPAddrLocal()) {
796 RecheckCaptivePortal();
799 return NS_OK;
802 nsresult nsIOService::AsyncOnChannelRedirect(
803 nsIChannel* oldChan, nsIChannel* newChan, uint32_t flags,
804 nsAsyncRedirectVerifyHelper* helper) {
805 // If a redirect to a local network address occurs, then chances are we
806 // are in a captive portal, so we trigger a recheck.
807 RecheckCaptivePortalIfLocalRedirect(newChan);
809 // This is silly. I wish there was a simpler way to get at the global
810 // reference of the contentSecurityManager. But it lives in the XPCOM
811 // service registry.
812 nsCOMPtr<nsIChannelEventSink> sink =
813 do_GetService(NS_CONTENTSECURITYMANAGER_CONTRACTID);
814 if (sink) {
815 nsresult rv =
816 helper->DelegateOnChannelRedirect(sink, oldChan, newChan, flags);
817 if (NS_FAILED(rv)) return rv;
820 // Finally, our category
821 nsCOMArray<nsIChannelEventSink> entries;
822 mChannelEventSinks.GetEntries(entries);
823 int32_t len = entries.Count();
824 for (int32_t i = 0; i < len; ++i) {
825 nsresult rv =
826 helper->DelegateOnChannelRedirect(entries[i], oldChan, newChan, flags);
827 if (NS_FAILED(rv)) return rv;
830 nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(oldChan));
832 // Collect the redirection from HTTP(S) only.
833 if (httpChan) {
834 MOZ_ASSERT(NS_IsMainThread());
835 nsCOMPtr<nsIURI> newURI;
836 newChan->GetURI(getter_AddRefs(newURI));
837 MOZ_ASSERT(newURI);
839 nsAutoCString scheme;
840 newURI->GetScheme(scheme);
841 MOZ_ASSERT(!scheme.IsEmpty());
843 Telemetry::AccumulateCategoricalKeyed(
844 scheme,
845 oldChan->IsDocument()
846 ? Telemetry::LABELS_NETWORK_HTTP_REDIRECT_TO_SCHEME::topLevel
847 : Telemetry::LABELS_NETWORK_HTTP_REDIRECT_TO_SCHEME::subresource);
850 return NS_OK;
853 bool nsIOService::UsesExternalProtocolHandler(const nsACString& aScheme) {
854 if (aScheme == "file"_ns || aScheme == "chrome"_ns ||
855 aScheme == "resource"_ns) {
856 // Don't allow file:, chrome: or resource: URIs to be handled with
857 // nsExternalProtocolHandler, since internally we rely on being able to
858 // use and read from these URIs.
859 return false;
862 if (aScheme == "place"_ns || aScheme == "fake-favicon-uri"_ns ||
863 aScheme == "favicon"_ns || aScheme == "moz-nullprincipal"_ns) {
864 // Force place: fake-favicon-uri: favicon: and moz-nullprincipal: URIs to be
865 // handled with nsExternalProtocolHandler, and not with a dynamically
866 // registered handler.
867 return true;
870 // If prefs configure the URI to be handled externally, do so.
871 for (const auto& scheme : mForceExternalSchemes) {
872 if (aScheme == scheme) {
873 return true;
876 return false;
879 ProtocolHandlerInfo nsIOService::LookupProtocolHandler(
880 const nsACString& aScheme) {
881 // Look-ups are ASCII-case-insensitive, so lower-case the string before
882 // continuing.
883 nsAutoCString scheme(aScheme);
884 ToLowerCase(scheme);
886 // NOTE: If we could get rid of mForceExternalSchemes (or prevent them from
887 // disabling static protocols), we could avoid locking mLock until we need to
888 // check `mRuntimeProtocolHandlers.
889 AutoReadLock lock(mLock);
890 if (!UsesExternalProtocolHandler(scheme)) {
891 // Try the static protocol handler first - they cannot be overridden by
892 // dynamic protocols.
893 if (const xpcom::StaticProtocolHandler* handler =
894 xpcom::StaticProtocolHandler::Lookup(scheme)) {
895 return ProtocolHandlerInfo(*handler);
897 if (auto handler = mRuntimeProtocolHandlers.Lookup(scheme)) {
898 return ProtocolHandlerInfo(handler.Data());
901 return ProtocolHandlerInfo(xpcom::StaticProtocolHandler::Default());
904 NS_IMETHODIMP
905 nsIOService::GetProtocolHandler(const char* scheme,
906 nsIProtocolHandler** result) {
907 AssertIsOnMainThread();
908 NS_ENSURE_ARG_POINTER(scheme);
910 *result = LookupProtocolHandler(nsDependentCString(scheme)).Handler().take();
911 return *result ? NS_OK : NS_ERROR_UNKNOWN_PROTOCOL;
914 NS_IMETHODIMP
915 nsIOService::ExtractScheme(const nsACString& inURI, nsACString& scheme) {
916 return net_ExtractURLScheme(inURI, scheme);
919 NS_IMETHODIMP
920 nsIOService::HostnameIsLocalIPAddress(nsIURI* aURI, bool* aResult) {
921 NS_ENSURE_ARG_POINTER(aURI);
923 nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(aURI);
924 NS_ENSURE_ARG_POINTER(innerURI);
926 nsAutoCString host;
927 nsresult rv = innerURI->GetAsciiHost(host);
928 if (NS_FAILED(rv)) {
929 return rv;
932 *aResult = false;
934 NetAddr addr;
935 if (NS_SUCCEEDED(addr.InitFromString(host)) && addr.IsIPAddrLocal()) {
936 *aResult = true;
939 return NS_OK;
942 NS_IMETHODIMP
943 nsIOService::HostnameIsSharedIPAddress(nsIURI* aURI, bool* aResult) {
944 NS_ENSURE_ARG_POINTER(aURI);
946 nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(aURI);
947 NS_ENSURE_ARG_POINTER(innerURI);
949 nsAutoCString host;
950 nsresult rv = innerURI->GetAsciiHost(host);
951 if (NS_FAILED(rv)) {
952 return rv;
955 *aResult = false;
957 NetAddr addr;
958 if (NS_SUCCEEDED(addr.InitFromString(host)) && addr.IsIPAddrShared()) {
959 *aResult = true;
962 return NS_OK;
965 NS_IMETHODIMP
966 nsIOService::IsValidHostname(const nsACString& inHostname, bool* aResult) {
967 *aResult = net_IsValidHostName(inHostname);
969 return NS_OK;
972 NS_IMETHODIMP
973 nsIOService::GetProtocolFlags(const char* scheme, uint32_t* flags) {
974 NS_ENSURE_ARG_POINTER(scheme);
976 *flags =
977 LookupProtocolHandler(nsDependentCString(scheme)).StaticProtocolFlags();
978 return NS_OK;
981 NS_IMETHODIMP
982 nsIOService::GetDynamicProtocolFlags(nsIURI* uri, uint32_t* flags) {
983 AssertIsOnMainThread();
984 NS_ENSURE_ARG(uri);
986 nsAutoCString scheme;
987 nsresult rv = uri->GetScheme(scheme);
988 NS_ENSURE_SUCCESS(rv, rv);
990 return LookupProtocolHandler(scheme).DynamicProtocolFlags(uri, flags);
993 NS_IMETHODIMP
994 nsIOService::GetDefaultPort(const char* scheme, int32_t* defaultPort) {
995 NS_ENSURE_ARG_POINTER(scheme);
997 *defaultPort =
998 LookupProtocolHandler(nsDependentCString(scheme)).DefaultPort();
999 return NS_OK;
1002 nsresult nsIOService::NewURI(const nsACString& aSpec, const char* aCharset,
1003 nsIURI* aBaseURI, nsIURI** result) {
1004 return NS_NewURI(result, aSpec, aCharset, aBaseURI);
1007 NS_IMETHODIMP
1008 nsIOService::NewFileURI(nsIFile* file, nsIURI** result) {
1009 nsresult rv;
1010 NS_ENSURE_ARG_POINTER(file);
1012 nsCOMPtr<nsIProtocolHandler> handler;
1014 rv = GetProtocolHandler("file", getter_AddRefs(handler));
1015 if (NS_FAILED(rv)) return rv;
1017 nsCOMPtr<nsIFileProtocolHandler> fileHandler(do_QueryInterface(handler, &rv));
1018 if (NS_FAILED(rv)) return rv;
1020 return fileHandler->NewFileURI(file, result);
1023 // static
1024 already_AddRefed<nsIURI> nsIOService::CreateExposableURI(nsIURI* aURI) {
1025 MOZ_ASSERT(aURI, "Must have a URI");
1026 nsCOMPtr<nsIURI> uri = aURI;
1027 bool hasUserPass;
1028 if (NS_SUCCEEDED(aURI->GetHasUserPass(&hasUserPass)) && hasUserPass) {
1029 DebugOnly<nsresult> rv = NS_MutateURI(uri).SetUserPass(""_ns).Finalize(uri);
1030 MOZ_ASSERT(NS_SUCCEEDED(rv) && uri, "Mutating URI should never fail");
1032 return uri.forget();
1035 NS_IMETHODIMP
1036 nsIOService::CreateExposableURI(nsIURI* aURI, nsIURI** _result) {
1037 NS_ENSURE_ARG_POINTER(aURI);
1038 NS_ENSURE_ARG_POINTER(_result);
1039 nsCOMPtr<nsIURI> exposableURI = CreateExposableURI(aURI);
1040 exposableURI.forget(_result);
1041 return NS_OK;
1044 NS_IMETHODIMP
1045 nsIOService::NewChannelFromURI(nsIURI* aURI, nsINode* aLoadingNode,
1046 nsIPrincipal* aLoadingPrincipal,
1047 nsIPrincipal* aTriggeringPrincipal,
1048 uint32_t aSecurityFlags,
1049 nsContentPolicyType aContentPolicyType,
1050 nsIChannel** result) {
1051 return NewChannelFromURIWithProxyFlags(aURI,
1052 nullptr, // aProxyURI
1053 0, // aProxyFlags
1054 aLoadingNode, aLoadingPrincipal,
1055 aTriggeringPrincipal, aSecurityFlags,
1056 aContentPolicyType, result);
1058 nsresult nsIOService::NewChannelFromURIWithClientAndController(
1059 nsIURI* aURI, nsINode* aLoadingNode, nsIPrincipal* aLoadingPrincipal,
1060 nsIPrincipal* aTriggeringPrincipal,
1061 const Maybe<ClientInfo>& aLoadingClientInfo,
1062 const Maybe<ServiceWorkerDescriptor>& aController, uint32_t aSecurityFlags,
1063 nsContentPolicyType aContentPolicyType, uint32_t aSandboxFlags,
1064 bool aSkipCheckForBrokenURLOrZeroSized, nsIChannel** aResult) {
1065 return NewChannelFromURIWithProxyFlagsInternal(
1066 aURI,
1067 nullptr, // aProxyURI
1068 0, // aProxyFlags
1069 aLoadingNode, aLoadingPrincipal, aTriggeringPrincipal, aLoadingClientInfo,
1070 aController, aSecurityFlags, aContentPolicyType, aSandboxFlags,
1071 aSkipCheckForBrokenURLOrZeroSized, aResult);
1074 NS_IMETHODIMP
1075 nsIOService::NewChannelFromURIWithLoadInfo(nsIURI* aURI, nsILoadInfo* aLoadInfo,
1076 nsIChannel** result) {
1077 return NewChannelFromURIWithProxyFlagsInternal(aURI,
1078 nullptr, // aProxyURI
1079 0, // aProxyFlags
1080 aLoadInfo, result);
1083 nsresult nsIOService::NewChannelFromURIWithProxyFlagsInternal(
1084 nsIURI* aURI, nsIURI* aProxyURI, uint32_t aProxyFlags,
1085 nsINode* aLoadingNode, nsIPrincipal* aLoadingPrincipal,
1086 nsIPrincipal* aTriggeringPrincipal,
1087 const Maybe<ClientInfo>& aLoadingClientInfo,
1088 const Maybe<ServiceWorkerDescriptor>& aController, uint32_t aSecurityFlags,
1089 nsContentPolicyType aContentPolicyType, uint32_t aSandboxFlags,
1090 bool aSkipCheckForBrokenURLOrZeroSized, nsIChannel** result) {
1091 nsCOMPtr<nsILoadInfo> loadInfo = new LoadInfo(
1092 aLoadingPrincipal, aTriggeringPrincipal, aLoadingNode, aSecurityFlags,
1093 aContentPolicyType, aLoadingClientInfo, aController, aSandboxFlags,
1094 aSkipCheckForBrokenURLOrZeroSized);
1095 return NewChannelFromURIWithProxyFlagsInternal(aURI, aProxyURI, aProxyFlags,
1096 loadInfo, result);
1099 nsresult nsIOService::NewChannelFromURIWithProxyFlagsInternal(
1100 nsIURI* aURI, nsIURI* aProxyURI, uint32_t aProxyFlags,
1101 nsILoadInfo* aLoadInfo, nsIChannel** result) {
1102 nsresult rv;
1103 NS_ENSURE_ARG_POINTER(aURI);
1104 // all channel creations must provide a valid loadinfo
1105 MOZ_ASSERT(aLoadInfo, "can not create channel without aLoadInfo");
1106 NS_ENSURE_ARG_POINTER(aLoadInfo);
1108 nsAutoCString scheme;
1109 rv = aURI->GetScheme(scheme);
1110 if (NS_FAILED(rv)) return rv;
1112 nsCOMPtr<nsIProtocolHandler> handler;
1113 rv = GetProtocolHandler(scheme.get(), getter_AddRefs(handler));
1114 if (NS_FAILED(rv)) return rv;
1116 nsCOMPtr<nsIChannel> channel;
1117 nsCOMPtr<nsIProxiedProtocolHandler> pph = do_QueryInterface(handler);
1118 if (pph) {
1119 rv = pph->NewProxiedChannel(aURI, nullptr, aProxyFlags, aProxyURI,
1120 aLoadInfo, getter_AddRefs(channel));
1121 } else {
1122 rv = handler->NewChannel(aURI, aLoadInfo, getter_AddRefs(channel));
1124 if (NS_FAILED(rv)) return rv;
1126 // Make sure that all the individual protocolhandlers attach a loadInfo.
1127 nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
1128 if (aLoadInfo != loadInfo) {
1129 MOZ_ASSERT(false, "newly created channel must have a loadinfo attached");
1130 return NS_ERROR_UNEXPECTED;
1133 // If we're sandboxed, make sure to clear any owner the channel
1134 // might already have.
1135 if (loadInfo->GetLoadingSandboxed()) {
1136 channel->SetOwner(nullptr);
1139 // Some extensions override the http protocol handler and provide their own
1140 // implementation. The channels returned from that implementation doesn't
1141 // seem to always implement the nsIUploadChannel2 interface, presumably
1142 // because it's a new interface.
1143 // Eventually we should remove this and simply require that http channels
1144 // implement the new interface.
1145 // See bug 529041
1146 if (!gHasWarnedUploadChannel2 && scheme.EqualsLiteral("http")) {
1147 nsCOMPtr<nsIUploadChannel2> uploadChannel2 = do_QueryInterface(channel);
1148 if (!uploadChannel2) {
1149 nsCOMPtr<nsIConsoleService> consoleService =
1150 do_GetService(NS_CONSOLESERVICE_CONTRACTID);
1151 if (consoleService) {
1152 consoleService->LogStringMessage(
1153 u"Http channel implementation "
1154 "doesn't support nsIUploadChannel2. An extension has "
1155 "supplied a non-functional http protocol handler. This will "
1156 "break behavior and in future releases not work at all.");
1158 gHasWarnedUploadChannel2 = true;
1162 channel.forget(result);
1163 return NS_OK;
1166 NS_IMETHODIMP
1167 nsIOService::NewChannelFromURIWithProxyFlags(
1168 nsIURI* aURI, nsIURI* aProxyURI, uint32_t aProxyFlags,
1169 nsINode* aLoadingNode, nsIPrincipal* aLoadingPrincipal,
1170 nsIPrincipal* aTriggeringPrincipal, uint32_t aSecurityFlags,
1171 nsContentPolicyType aContentPolicyType, nsIChannel** result) {
1172 return NewChannelFromURIWithProxyFlagsInternal(
1173 aURI, aProxyURI, aProxyFlags, aLoadingNode, aLoadingPrincipal,
1174 aTriggeringPrincipal, Maybe<ClientInfo>(),
1175 Maybe<ServiceWorkerDescriptor>(), aSecurityFlags, aContentPolicyType, 0,
1176 /* aSkipCheckForBrokenURLOrZeroSized = */ false, result);
1179 NS_IMETHODIMP
1180 nsIOService::NewChannel(const nsACString& aSpec, const char* aCharset,
1181 nsIURI* aBaseURI, nsINode* aLoadingNode,
1182 nsIPrincipal* aLoadingPrincipal,
1183 nsIPrincipal* aTriggeringPrincipal,
1184 uint32_t aSecurityFlags,
1185 nsContentPolicyType aContentPolicyType,
1186 nsIChannel** result) {
1187 nsresult rv;
1188 nsCOMPtr<nsIURI> uri;
1189 rv = NewURI(aSpec, aCharset, aBaseURI, getter_AddRefs(uri));
1190 if (NS_FAILED(rv)) return rv;
1192 return NewChannelFromURI(uri, aLoadingNode, aLoadingPrincipal,
1193 aTriggeringPrincipal, aSecurityFlags,
1194 aContentPolicyType, result);
1197 NS_IMETHODIMP
1198 nsIOService::NewWebTransport(nsIWebTransport** result) {
1199 if (!XRE_IsParentProcess()) {
1200 return NS_ERROR_NOT_AVAILABLE;
1203 nsCOMPtr<nsIWebTransport> webTransport = new WebTransportSessionProxy();
1205 webTransport.forget(result);
1206 return NS_OK;
1209 bool nsIOService::IsLinkUp() {
1210 InitializeNetworkLinkService();
1212 if (!mNetworkLinkService) {
1213 // We cannot decide, assume the link is up
1214 return true;
1217 bool isLinkUp;
1218 nsresult rv;
1219 rv = mNetworkLinkService->GetIsLinkUp(&isLinkUp);
1220 if (NS_FAILED(rv)) {
1221 return true;
1224 return isLinkUp;
1227 NS_IMETHODIMP
1228 nsIOService::GetOffline(bool* offline) {
1229 if (StaticPrefs::network_offline_mirrors_connectivity()) {
1230 *offline = mOffline || !mConnectivity;
1231 } else {
1232 *offline = mOffline;
1234 return NS_OK;
1237 NS_IMETHODIMP
1238 nsIOService::SetOffline(bool offline) { return SetOfflineInternal(offline); }
1240 nsresult nsIOService::SetOfflineInternal(bool offline,
1241 bool notifySocketProcess) {
1242 LOG(("nsIOService::SetOffline offline=%d\n", offline));
1243 // When someone wants to go online (!offline) after we got XPCOM shutdown
1244 // throw ERROR_NOT_AVAILABLE to prevent return to online state.
1245 if ((mShutdown || mOfflineForProfileChange) && !offline) {
1246 return NS_ERROR_NOT_AVAILABLE;
1249 // SetOffline() may re-enter while it's shutting down services.
1250 // If that happens, save the most recent value and it will be
1251 // processed when the first SetOffline() call is done bringing
1252 // down the service.
1253 mSetOfflineValue = offline;
1254 if (mSettingOffline) {
1255 return NS_OK;
1258 mSettingOffline = true;
1260 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
1262 NS_ASSERTION(observerService, "The observer service should not be null");
1264 if (XRE_IsParentProcess()) {
1265 if (observerService) {
1266 (void)observerService->NotifyObservers(nullptr,
1267 NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC,
1268 offline ? u"true" : u"false");
1270 if (SocketProcessReady() && notifySocketProcess) {
1271 Unused << mSocketProcess->GetActor()->SendSetOffline(offline);
1275 nsIIOService* subject = static_cast<nsIIOService*>(this);
1276 while (mSetOfflineValue != mOffline) {
1277 offline = mSetOfflineValue;
1279 if (offline && !mOffline) {
1280 mOffline = true; // indicate we're trying to shutdown
1282 // don't care if notifications fail
1283 if (observerService) {
1284 observerService->NotifyObservers(subject,
1285 NS_IOSERVICE_GOING_OFFLINE_TOPIC,
1286 u"" NS_IOSERVICE_OFFLINE);
1289 if (mSocketTransportService) mSocketTransportService->SetOffline(true);
1291 mLastOfflineStateChange = PR_IntervalNow();
1292 if (observerService) {
1293 observerService->NotifyObservers(subject,
1294 NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
1295 u"" NS_IOSERVICE_OFFLINE);
1297 } else if (!offline && mOffline) {
1298 // go online
1299 InitializeSocketTransportService();
1300 mOffline = false; // indicate success only AFTER we've
1301 // brought up the services
1303 mLastOfflineStateChange = PR_IntervalNow();
1304 // don't care if notification fails
1305 // Only send the ONLINE notification if there is connectivity
1306 if (observerService && mConnectivity) {
1307 observerService->NotifyObservers(subject,
1308 NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
1309 (u"" NS_IOSERVICE_ONLINE));
1314 // Don't notify here, as the above notifications (if used) suffice.
1315 if ((mShutdown || mOfflineForProfileChange) && mOffline) {
1316 if (mSocketTransportService) {
1317 DebugOnly<nsresult> rv = mSocketTransportService->Shutdown(mShutdown);
1318 NS_ASSERTION(NS_SUCCEEDED(rv),
1319 "socket transport service shutdown failed");
1323 mSettingOffline = false;
1325 return NS_OK;
1328 NS_IMETHODIMP
1329 nsIOService::GetConnectivity(bool* aConnectivity) {
1330 *aConnectivity = mConnectivity;
1331 return NS_OK;
1334 NS_IMETHODIMP
1335 nsIOService::SetConnectivity(bool aConnectivity) {
1336 LOG(("nsIOService::SetConnectivity aConnectivity=%d\n", aConnectivity));
1337 // This should only be called from ContentChild to pass the connectivity
1338 // value from the chrome process to the content process.
1339 if (XRE_IsParentProcess()) {
1340 return NS_ERROR_NOT_AVAILABLE;
1342 return SetConnectivityInternal(aConnectivity);
1345 nsresult nsIOService::SetConnectivityInternal(bool aConnectivity) {
1346 LOG(("nsIOService::SetConnectivityInternal aConnectivity=%d\n",
1347 aConnectivity));
1348 if (mConnectivity == aConnectivity) {
1349 // Nothing to do here.
1350 return NS_OK;
1352 mConnectivity = aConnectivity;
1354 // This is used for PR_Connect PR_Close telemetry so it is important that
1355 // we have statistic about network change event even if we are offline.
1356 mLastConnectivityChange = PR_IntervalNow();
1358 if (mCaptivePortalService) {
1359 if (aConnectivity && gCaptivePortalEnabled) {
1360 // This will also trigger a captive portal check for the new network
1361 static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Start();
1362 } else {
1363 static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Stop();
1367 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
1368 if (!observerService) {
1369 return NS_OK;
1371 // This notification sends the connectivity to the child processes
1372 if (XRE_IsParentProcess()) {
1373 observerService->NotifyObservers(nullptr,
1374 NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC,
1375 aConnectivity ? u"true" : u"false");
1376 if (SocketProcessReady()) {
1377 Unused << mSocketProcess->GetActor()->SendSetConnectivity(aConnectivity);
1381 if (mOffline) {
1382 // We don't need to send any notifications if we're offline
1383 return NS_OK;
1386 if (aConnectivity) {
1387 // If we were previously offline due to connectivity=false,
1388 // send the ONLINE notification
1389 observerService->NotifyObservers(static_cast<nsIIOService*>(this),
1390 NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
1391 (u"" NS_IOSERVICE_ONLINE));
1392 } else {
1393 // If we were previously online and lost connectivity
1394 // send the OFFLINE notification
1395 observerService->NotifyObservers(static_cast<nsIIOService*>(this),
1396 NS_IOSERVICE_GOING_OFFLINE_TOPIC,
1397 u"" NS_IOSERVICE_OFFLINE);
1398 observerService->NotifyObservers(static_cast<nsIIOService*>(this),
1399 NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
1400 u"" NS_IOSERVICE_OFFLINE);
1402 return NS_OK;
1405 NS_IMETHODIMP
1406 nsIOService::AllowPort(int32_t inPort, const char* scheme, bool* _retval) {
1407 int32_t port = inPort;
1408 if (port == -1) {
1409 *_retval = true;
1410 return NS_OK;
1413 if (port <= 0 || port > std::numeric_limits<uint16_t>::max()) {
1414 *_retval = false;
1415 return NS_OK;
1418 nsTArray<int32_t> restrictedPortList;
1420 AutoReadLock lock(mLock);
1421 restrictedPortList.Assign(mRestrictedPortList);
1423 // first check to see if the port is in our blacklist:
1424 int32_t badPortListCnt = restrictedPortList.Length();
1425 for (int i = 0; i < badPortListCnt; i++) {
1426 if (port == restrictedPortList[i]) {
1427 *_retval = false;
1429 // check to see if the protocol wants to override
1430 if (!scheme) return NS_OK;
1432 // We don't support get protocol handler off main thread.
1433 if (!NS_IsMainThread()) {
1434 return NS_OK;
1436 nsCOMPtr<nsIProtocolHandler> handler;
1437 nsresult rv = GetProtocolHandler(scheme, getter_AddRefs(handler));
1438 if (NS_FAILED(rv)) return rv;
1440 // let the protocol handler decide
1441 return handler->AllowPort(port, scheme, _retval);
1445 *_retval = true;
1446 return NS_OK;
1449 ////////////////////////////////////////////////////////////////////////////////
1451 // static
1452 void nsIOService::PrefsChanged(const char* pref, void* self) {
1453 static_cast<nsIOService*>(self)->PrefsChanged(pref);
1456 void nsIOService::PrefsChanged(const char* pref) {
1457 // Look for extra ports to block
1458 if (!pref || strcmp(pref, PORT_PREF("banned")) == 0) {
1459 ParsePortList(PORT_PREF("banned"), false);
1462 // ...as well as previous blocks to remove.
1463 if (!pref || strcmp(pref, PORT_PREF("banned.override")) == 0) {
1464 ParsePortList(PORT_PREF("banned.override"), true);
1467 if (!pref || strcmp(pref, MANAGE_OFFLINE_STATUS_PREF) == 0) {
1468 bool manage;
1469 if (mNetworkLinkServiceInitialized &&
1470 NS_SUCCEEDED(
1471 Preferences::GetBool(MANAGE_OFFLINE_STATUS_PREF, &manage))) {
1472 LOG(("nsIOService::PrefsChanged ManageOfflineStatus manage=%d\n",
1473 manage));
1474 SetManageOfflineStatus(manage);
1478 if (!pref || strcmp(pref, NECKO_BUFFER_CACHE_COUNT_PREF) == 0) {
1479 int32_t count;
1480 if (NS_SUCCEEDED(
1481 Preferences::GetInt(NECKO_BUFFER_CACHE_COUNT_PREF, &count))) {
1482 /* check for bogus values and default if we find such a value */
1483 if (count > 0) gDefaultSegmentCount = count;
1487 if (!pref || strcmp(pref, NECKO_BUFFER_CACHE_SIZE_PREF) == 0) {
1488 int32_t size;
1489 if (NS_SUCCEEDED(
1490 Preferences::GetInt(NECKO_BUFFER_CACHE_SIZE_PREF, &size))) {
1491 /* check for bogus values and default if we find such a value
1492 * the upper limit here is arbitrary. having a 1mb segment size
1493 * is pretty crazy. if you remove this, consider adding some
1494 * integer rollover test.
1496 if (size > 0 && size < 1024 * 1024) gDefaultSegmentSize = size;
1498 NS_WARNING_ASSERTION(!(size & (size - 1)),
1499 "network segment size is not a power of 2!");
1502 if (!pref || strcmp(pref, NETWORK_CAPTIVE_PORTAL_PREF) == 0) {
1503 nsresult rv = Preferences::GetBool(NETWORK_CAPTIVE_PORTAL_PREF,
1504 &gCaptivePortalEnabled);
1505 if (NS_SUCCEEDED(rv) && mCaptivePortalService) {
1506 if (gCaptivePortalEnabled) {
1507 static_cast<CaptivePortalService*>(mCaptivePortalService.get())
1508 ->Start();
1509 } else {
1510 static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Stop();
1515 if (!pref || strncmp(pref, FORCE_EXTERNAL_PREF_PREFIX,
1516 strlen(FORCE_EXTERNAL_PREF_PREFIX)) == 0) {
1517 nsTArray<nsCString> prefs;
1518 if (nsIPrefBranch* prefRootBranch = Preferences::GetRootBranch()) {
1519 prefRootBranch->GetChildList(FORCE_EXTERNAL_PREF_PREFIX, prefs);
1521 nsTArray<nsCString> forceExternalSchemes;
1522 for (const auto& pref : prefs) {
1523 if (Preferences::GetBool(pref.get(), false)) {
1524 forceExternalSchemes.AppendElement(
1525 Substring(pref, strlen(FORCE_EXTERNAL_PREF_PREFIX)));
1528 AutoWriteLock lock(mLock);
1529 mForceExternalSchemes = std::move(forceExternalSchemes);
1533 void nsIOService::ParsePortList(const char* pref, bool remove) {
1534 nsAutoCString portList;
1535 nsTArray<int32_t> restrictedPortList;
1537 AutoWriteLock lock(mLock);
1538 restrictedPortList.Assign(std::move(mRestrictedPortList));
1540 // Get a pref string and chop it up into a list of ports.
1541 Preferences::GetCString(pref, portList);
1542 if (!portList.IsVoid()) {
1543 nsTArray<nsCString> portListArray;
1544 ParseString(portList, ',', portListArray);
1545 uint32_t index;
1546 for (index = 0; index < portListArray.Length(); index++) {
1547 portListArray[index].StripWhitespace();
1548 int32_t portBegin, portEnd;
1550 if (PR_sscanf(portListArray[index].get(), "%d-%d", &portBegin,
1551 &portEnd) == 2) {
1552 if ((portBegin < 65536) && (portEnd < 65536)) {
1553 int32_t curPort;
1554 if (remove) {
1555 for (curPort = portBegin; curPort <= portEnd; curPort++) {
1556 restrictedPortList.RemoveElement(curPort);
1558 } else {
1559 for (curPort = portBegin; curPort <= portEnd; curPort++) {
1560 restrictedPortList.AppendElement(curPort);
1564 } else {
1565 nsresult aErrorCode;
1566 int32_t port = portListArray[index].ToInteger(&aErrorCode);
1567 if (NS_SUCCEEDED(aErrorCode) && port < 65536) {
1568 if (remove) {
1569 restrictedPortList.RemoveElement(port);
1570 } else {
1571 restrictedPortList.AppendElement(port);
1578 AutoWriteLock lock(mLock);
1579 mRestrictedPortList.Assign(std::move(restrictedPortList));
1582 class nsWakeupNotifier : public Runnable {
1583 public:
1584 explicit nsWakeupNotifier(nsIIOServiceInternal* ioService)
1585 : Runnable("net::nsWakeupNotifier"), mIOService(ioService) {}
1587 NS_IMETHOD Run() override { return mIOService->NotifyWakeup(); }
1589 private:
1590 virtual ~nsWakeupNotifier() = default;
1591 nsCOMPtr<nsIIOServiceInternal> mIOService;
1594 NS_IMETHODIMP
1595 nsIOService::NotifyWakeup() {
1596 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
1598 NS_ASSERTION(observerService, "The observer service should not be null");
1600 if (observerService && StaticPrefs::network_notify_changed()) {
1601 (void)observerService->NotifyObservers(nullptr, NS_NETWORK_LINK_TOPIC,
1602 (u"" NS_NETWORK_LINK_DATA_CHANGED));
1605 RecheckCaptivePortal();
1607 return NS_OK;
1610 void nsIOService::SetHttpHandlerAlreadyShutingDown() {
1611 if (!mShutdown && !mOfflineForProfileChange) {
1612 mNetTearingDownStarted = PR_IntervalNow();
1613 mHttpHandlerAlreadyShutingDown = true;
1617 // nsIObserver interface
1618 NS_IMETHODIMP
1619 nsIOService::Observe(nsISupports* subject, const char* topic,
1620 const char16_t* data) {
1621 if (UseSocketProcess() && SocketProcessReady() &&
1622 mObserverTopicForSocketProcess.Contains(nsDependentCString(topic))) {
1623 nsCString topicStr(topic);
1624 nsString dataStr(data);
1625 Unused << mSocketProcess->GetActor()->SendNotifyObserver(topicStr, dataStr);
1628 if (!strcmp(topic, kProfileChangeNetTeardownTopic)) {
1629 if (!mHttpHandlerAlreadyShutingDown) {
1630 mNetTearingDownStarted = PR_IntervalNow();
1632 mHttpHandlerAlreadyShutingDown = false;
1633 if (!mOffline) {
1634 mOfflineForProfileChange = true;
1635 SetOfflineInternal(true, false);
1637 } else if (!strcmp(topic, kProfileChangeNetRestoreTopic)) {
1638 if (mOfflineForProfileChange) {
1639 mOfflineForProfileChange = false;
1640 SetOfflineInternal(false, false);
1642 } else if (!strcmp(topic, kProfileDoChange)) {
1643 if (data && u"startup"_ns.Equals(data)) {
1644 // Lazy initialization of network link service (see bug 620472)
1645 InitializeNetworkLinkService();
1646 // Set up the initilization flag regardless the actuall result.
1647 // If we fail here, we will fail always on.
1648 mNetworkLinkServiceInitialized = true;
1650 // And now reflect the preference setting
1651 PrefsChanged(MANAGE_OFFLINE_STATUS_PREF);
1653 // Bug 870460 - Read cookie database at an early-as-possible time
1654 // off main thread. Hence, we have more chance to finish db query
1655 // before something calls into the cookie service.
1656 nsCOMPtr<nsISupports> cookieServ =
1657 do_GetService(NS_COOKIESERVICE_CONTRACTID);
1659 } else if (!strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
1660 // Remember we passed XPCOM shutdown notification to prevent any
1661 // changes of the offline status from now. We must not allow going
1662 // online after this point.
1663 mShutdown = true;
1665 if (!mHttpHandlerAlreadyShutingDown && !mOfflineForProfileChange) {
1666 mNetTearingDownStarted = PR_IntervalNow();
1668 mHttpHandlerAlreadyShutingDown = false;
1670 SetOfflineInternal(true, false);
1672 if (mCaptivePortalService) {
1673 static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Stop();
1674 mCaptivePortalService = nullptr;
1677 SSLTokensCache::Shutdown();
1679 DestroySocketProcess();
1681 if (IsSocketProcessChild()) {
1682 Preferences::UnregisterCallbacks(nsIOService::OnTLSPrefChange,
1683 gCallbackSecurityPrefs, this);
1684 PrepareForShutdownInSocketProcess();
1687 // We're in XPCOM shutdown now. Unregister any dynamic protocol handlers
1688 // after this point to avoid leaks.
1690 AutoWriteLock lock(mLock);
1691 mRuntimeProtocolHandlers.Clear();
1693 } else if (!strcmp(topic, NS_NETWORK_LINK_TOPIC)) {
1694 OnNetworkLinkEvent(NS_ConvertUTF16toUTF8(data).get());
1695 } else if (!strcmp(topic, NS_NETWORK_ID_CHANGED_TOPIC)) {
1696 LOG(("nsIOService::OnNetworkLinkEvent Network id changed"));
1697 } else if (!strcmp(topic, NS_WIDGET_WAKE_OBSERVER_TOPIC)) {
1698 // coming back alive from sleep
1699 // this indirection brought to you by:
1700 // https://bugzilla.mozilla.org/show_bug.cgi?id=1152048#c19
1701 nsCOMPtr<nsIRunnable> wakeupNotifier = new nsWakeupNotifier(this);
1702 NS_DispatchToMainThread(wakeupNotifier);
1705 return NS_OK;
1708 // nsINetUtil interface
1709 NS_IMETHODIMP
1710 nsIOService::ParseRequestContentType(const nsACString& aTypeHeader,
1711 nsACString& aCharset, bool* aHadCharset,
1712 nsACString& aContentType) {
1713 net_ParseRequestContentType(aTypeHeader, aContentType, aCharset, aHadCharset);
1714 return NS_OK;
1717 // nsINetUtil interface
1718 NS_IMETHODIMP
1719 nsIOService::ParseResponseContentType(const nsACString& aTypeHeader,
1720 nsACString& aCharset, bool* aHadCharset,
1721 nsACString& aContentType) {
1722 net_ParseContentType(aTypeHeader, aContentType, aCharset, aHadCharset);
1723 return NS_OK;
1726 NS_IMETHODIMP
1727 nsIOService::ProtocolHasFlags(nsIURI* uri, uint32_t flags, bool* result) {
1728 NS_ENSURE_ARG(uri);
1730 *result = false;
1731 nsAutoCString scheme;
1732 nsresult rv = uri->GetScheme(scheme);
1733 NS_ENSURE_SUCCESS(rv, rv);
1735 auto handler = LookupProtocolHandler(scheme);
1737 uint32_t protocolFlags;
1738 if (flags & nsIProtocolHandler::DYNAMIC_URI_FLAGS) {
1739 AssertIsOnMainThread();
1740 rv = handler.DynamicProtocolFlags(uri, &protocolFlags);
1741 NS_ENSURE_SUCCESS(rv, rv);
1742 } else {
1743 protocolFlags = handler.StaticProtocolFlags();
1746 *result = (protocolFlags & flags) == flags;
1747 return NS_OK;
1750 NS_IMETHODIMP
1751 nsIOService::URIChainHasFlags(nsIURI* uri, uint32_t flags, bool* result) {
1752 nsresult rv = ProtocolHasFlags(uri, flags, result);
1753 NS_ENSURE_SUCCESS(rv, rv);
1755 if (*result) {
1756 return rv;
1759 // Dig deeper into the chain. Note that this is not a do/while loop to
1760 // avoid the extra addref/release on |uri| in the common (non-nested) case.
1761 nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(uri);
1762 while (nestedURI) {
1763 nsCOMPtr<nsIURI> innerURI;
1764 rv = nestedURI->GetInnerURI(getter_AddRefs(innerURI));
1765 NS_ENSURE_SUCCESS(rv, rv);
1767 rv = ProtocolHasFlags(innerURI, flags, result);
1769 if (*result) {
1770 return rv;
1773 nestedURI = do_QueryInterface(innerURI);
1776 return rv;
1779 NS_IMETHODIMP
1780 nsIOService::SetManageOfflineStatus(bool aManage) {
1781 LOG(("nsIOService::SetManageOfflineStatus aManage=%d\n", aManage));
1782 mManageLinkStatus = aManage;
1784 // When detection is not activated, the default connectivity state is true.
1785 if (!mManageLinkStatus) {
1786 SetConnectivityInternal(true);
1787 return NS_OK;
1790 InitializeNetworkLinkService();
1791 // If the NetworkLinkService is already initialized, it does not call
1792 // OnNetworkLinkEvent. This is needed, when mManageLinkStatus goes from
1793 // false to true.
1794 OnNetworkLinkEvent(NS_NETWORK_LINK_DATA_UNKNOWN);
1795 return NS_OK;
1798 NS_IMETHODIMP
1799 nsIOService::GetManageOfflineStatus(bool* aManage) {
1800 *aManage = mManageLinkStatus;
1801 return NS_OK;
1804 // input argument 'data' is already UTF8'ed
1805 nsresult nsIOService::OnNetworkLinkEvent(const char* data) {
1806 if (IsNeckoChild() || IsSocketProcessChild()) {
1807 // There is nothing IO service could do on the child process
1808 // with this at the moment. Feel free to add functionality
1809 // here at will, though.
1810 return NS_OK;
1813 if (mShutdown) {
1814 return NS_ERROR_NOT_AVAILABLE;
1817 nsCString dataAsString(data);
1818 for (auto* cp : mozilla::dom::ContentParent::AllProcesses(
1819 mozilla::dom::ContentParent::eLive)) {
1820 PNeckoParent* neckoParent = SingleManagedOrNull(cp->ManagedPNeckoParent());
1821 if (!neckoParent) {
1822 continue;
1824 Unused << neckoParent->SendNetworkChangeNotification(dataAsString);
1827 LOG(("nsIOService::OnNetworkLinkEvent data:%s\n", data));
1828 if (!mNetworkLinkService) {
1829 return NS_ERROR_FAILURE;
1832 if (!mManageLinkStatus) {
1833 LOG(("nsIOService::OnNetworkLinkEvent mManageLinkStatus=false\n"));
1834 return NS_OK;
1837 bool isUp = true;
1838 if (!strcmp(data, NS_NETWORK_LINK_DATA_CHANGED)) {
1839 mLastNetworkLinkChange = PR_IntervalNow();
1840 // CHANGED means UP/DOWN didn't change
1841 // but the status of the captive portal may have changed.
1842 RecheckCaptivePortal();
1843 return NS_OK;
1845 if (!strcmp(data, NS_NETWORK_LINK_DATA_DOWN)) {
1846 isUp = false;
1847 } else if (!strcmp(data, NS_NETWORK_LINK_DATA_UP)) {
1848 isUp = true;
1849 } else if (!strcmp(data, NS_NETWORK_LINK_DATA_UNKNOWN)) {
1850 nsresult rv = mNetworkLinkService->GetIsLinkUp(&isUp);
1851 NS_ENSURE_SUCCESS(rv, rv);
1852 } else {
1853 NS_WARNING("Unhandled network event!");
1854 return NS_OK;
1857 return SetConnectivityInternal(isUp);
1860 NS_IMETHODIMP
1861 nsIOService::EscapeString(const nsACString& aString, uint32_t aEscapeType,
1862 nsACString& aResult) {
1863 NS_ENSURE_ARG_MAX(aEscapeType, 4);
1865 nsAutoCString stringCopy(aString);
1866 nsCString result;
1868 if (!NS_Escape(stringCopy, result, (nsEscapeMask)aEscapeType)) {
1869 return NS_ERROR_OUT_OF_MEMORY;
1872 aResult.Assign(result);
1874 return NS_OK;
1877 NS_IMETHODIMP
1878 nsIOService::EscapeURL(const nsACString& aStr, uint32_t aFlags,
1879 nsACString& aResult) {
1880 aResult.Truncate();
1881 NS_EscapeURL(aStr.BeginReading(), aStr.Length(), aFlags | esc_AlwaysCopy,
1882 aResult);
1883 return NS_OK;
1886 NS_IMETHODIMP
1887 nsIOService::UnescapeString(const nsACString& aStr, uint32_t aFlags,
1888 nsACString& aResult) {
1889 aResult.Truncate();
1890 NS_UnescapeURL(aStr.BeginReading(), aStr.Length(), aFlags | esc_AlwaysCopy,
1891 aResult);
1892 return NS_OK;
1895 NS_IMETHODIMP
1896 nsIOService::ExtractCharsetFromContentType(const nsACString& aTypeHeader,
1897 nsACString& aCharset,
1898 int32_t* aCharsetStart,
1899 int32_t* aCharsetEnd,
1900 bool* aHadCharset) {
1901 nsAutoCString ignored;
1902 net_ParseContentType(aTypeHeader, ignored, aCharset, aHadCharset,
1903 aCharsetStart, aCharsetEnd);
1904 if (*aHadCharset && *aCharsetStart == *aCharsetEnd) {
1905 *aHadCharset = false;
1907 return NS_OK;
1910 // nsISpeculativeConnect
1911 class IOServiceProxyCallback final : public nsIProtocolProxyCallback {
1912 ~IOServiceProxyCallback() = default;
1914 public:
1915 NS_DECL_ISUPPORTS
1916 NS_DECL_NSIPROTOCOLPROXYCALLBACK
1918 IOServiceProxyCallback(nsIInterfaceRequestor* aCallbacks,
1919 nsIOService* aIOService,
1920 Maybe<OriginAttributes>&& aOriginAttributes)
1921 : mCallbacks(aCallbacks),
1922 mIOService(aIOService),
1923 mOriginAttributes(std::move(aOriginAttributes)) {}
1925 private:
1926 RefPtr<nsIInterfaceRequestor> mCallbacks;
1927 RefPtr<nsIOService> mIOService;
1928 Maybe<OriginAttributes> mOriginAttributes;
1931 NS_IMPL_ISUPPORTS(IOServiceProxyCallback, nsIProtocolProxyCallback)
1933 NS_IMETHODIMP
1934 IOServiceProxyCallback::OnProxyAvailable(nsICancelable* request,
1935 nsIChannel* channel, nsIProxyInfo* pi,
1936 nsresult status) {
1937 // Checking proxy status for speculative connect
1938 nsAutoCString type;
1939 if (NS_SUCCEEDED(status) && pi && NS_SUCCEEDED(pi->GetType(type)) &&
1940 !type.EqualsLiteral("direct")) {
1941 // proxies dont do speculative connect
1942 return NS_OK;
1945 nsCOMPtr<nsIURI> uri;
1946 nsresult rv = channel->GetURI(getter_AddRefs(uri));
1947 if (NS_FAILED(rv)) {
1948 return NS_OK;
1951 nsAutoCString scheme;
1952 rv = uri->GetScheme(scheme);
1953 if (NS_FAILED(rv)) return NS_OK;
1955 nsCOMPtr<nsIProtocolHandler> handler;
1956 rv = mIOService->GetProtocolHandler(scheme.get(), getter_AddRefs(handler));
1957 if (NS_FAILED(rv)) return NS_OK;
1959 nsCOMPtr<nsISpeculativeConnect> speculativeHandler =
1960 do_QueryInterface(handler);
1961 if (!speculativeHandler) return NS_OK;
1963 nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
1964 nsCOMPtr<nsIPrincipal> principal = loadInfo->GetLoadingPrincipal();
1966 nsLoadFlags loadFlags = 0;
1967 channel->GetLoadFlags(&loadFlags);
1968 bool anonymous = !!(loadFlags & nsIRequest::LOAD_ANONYMOUS);
1969 if (mOriginAttributes) {
1970 speculativeHandler->SpeculativeConnectWithOriginAttributesNative(
1971 uri, std::move(mOriginAttributes.ref()), mCallbacks, anonymous);
1972 } else {
1973 speculativeHandler->SpeculativeConnect(uri, principal, mCallbacks,
1974 anonymous);
1977 return NS_OK;
1980 nsresult nsIOService::SpeculativeConnectInternal(
1981 nsIURI* aURI, nsIPrincipal* aPrincipal,
1982 Maybe<OriginAttributes>&& aOriginAttributes,
1983 nsIInterfaceRequestor* aCallbacks, bool aAnonymous) {
1984 NS_ENSURE_ARG(aURI);
1986 if (!aURI->SchemeIs("http") && !aURI->SchemeIs("https")) {
1987 // We don't speculatively connect to non-HTTP[S] URIs.
1988 return NS_OK;
1991 if (IsNeckoChild()) {
1992 gNeckoChild->SendSpeculativeConnect(
1993 aURI, aPrincipal, std::move(aOriginAttributes), aAnonymous);
1994 return NS_OK;
1997 // Check for proxy information. If there is a proxy configured then a
1998 // speculative connect should not be performed because the potential
1999 // reward is slim with tcp peers closely located to the browser.
2000 nsresult rv;
2001 nsCOMPtr<nsIProtocolProxyService> pps =
2002 do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv);
2003 NS_ENSURE_SUCCESS(rv, rv);
2005 nsCOMPtr<nsIPrincipal> loadingPrincipal = aPrincipal;
2007 MOZ_ASSERT(aPrincipal || aOriginAttributes,
2008 "We expect passing a principal or OriginAttributes here.");
2010 if (!aPrincipal && !aOriginAttributes) {
2011 return NS_ERROR_INVALID_ARG;
2014 if (aOriginAttributes) {
2015 loadingPrincipal =
2016 BasePrincipal::CreateContentPrincipal(aURI, aOriginAttributes.ref());
2019 // XXX Bug 1724080: Avoid TCP connections on port 80 when https-only
2020 // or https-first is enabled. Let's create a dummy loadinfo which we
2021 // only use to determine whether we need ot upgrade the speculative
2022 // connection from http to https.
2023 nsCOMPtr<nsIURI> httpsURI;
2024 if (aURI->SchemeIs("http")) {
2025 nsCOMPtr<nsILoadInfo> httpsOnlyCheckLoadInfo =
2026 new LoadInfo(loadingPrincipal, loadingPrincipal, nullptr,
2027 nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK,
2028 nsIContentPolicy::TYPE_SPECULATIVE);
2030 // Check if https-only, or https-first would upgrade the request
2031 if (nsHTTPSOnlyUtils::ShouldUpgradeRequest(aURI, httpsOnlyCheckLoadInfo) ||
2032 nsHTTPSOnlyUtils::ShouldUpgradeHttpsFirstRequest(
2033 aURI, httpsOnlyCheckLoadInfo)) {
2034 rv = NS_GetSecureUpgradedURI(aURI, getter_AddRefs(httpsURI));
2035 NS_ENSURE_SUCCESS(rv, rv);
2036 aURI = httpsURI.get();
2040 // dummy channel used to create a TCP connection.
2041 // we perform security checks on the *real* channel, responsible
2042 // for any network loads. this real channel just checks the TCP
2043 // pool if there is an available connection created by the
2044 // channel we create underneath - hence it's safe to use
2045 // the systemPrincipal as the loadingPrincipal for this channel.
2046 nsCOMPtr<nsIChannel> channel;
2047 rv = NewChannelFromURI(
2048 aURI,
2049 nullptr, // aLoadingNode,
2050 loadingPrincipal,
2051 nullptr, // aTriggeringPrincipal,
2052 nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
2053 nsIContentPolicy::TYPE_SPECULATIVE, getter_AddRefs(channel));
2054 NS_ENSURE_SUCCESS(rv, rv);
2056 if (aAnonymous) {
2057 nsLoadFlags loadFlags = 0;
2058 channel->GetLoadFlags(&loadFlags);
2059 loadFlags |= nsIRequest::LOAD_ANONYMOUS;
2060 channel->SetLoadFlags(loadFlags);
2063 nsCOMPtr<nsICancelable> cancelable;
2064 RefPtr<IOServiceProxyCallback> callback = new IOServiceProxyCallback(
2065 aCallbacks, this, std::move(aOriginAttributes));
2066 nsCOMPtr<nsIProtocolProxyService2> pps2 = do_QueryInterface(pps);
2067 if (pps2) {
2068 return pps2->AsyncResolve2(channel, 0, callback, nullptr,
2069 getter_AddRefs(cancelable));
2071 return pps->AsyncResolve(channel, 0, callback, nullptr,
2072 getter_AddRefs(cancelable));
2075 NS_IMETHODIMP
2076 nsIOService::SpeculativeConnect(nsIURI* aURI, nsIPrincipal* aPrincipal,
2077 nsIInterfaceRequestor* aCallbacks,
2078 bool aAnonymous) {
2079 return SpeculativeConnectInternal(aURI, aPrincipal, Nothing(), aCallbacks,
2080 aAnonymous);
2083 NS_IMETHODIMP nsIOService::SpeculativeConnectWithOriginAttributes(
2084 nsIURI* aURI, JS::Handle<JS::Value> aOriginAttributes,
2085 nsIInterfaceRequestor* aCallbacks, bool aAnonymous, JSContext* aCx) {
2086 OriginAttributes attrs;
2087 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
2088 return NS_ERROR_INVALID_ARG;
2091 SpeculativeConnectWithOriginAttributesNative(aURI, std::move(attrs),
2092 aCallbacks, aAnonymous);
2093 return NS_OK;
2096 NS_IMETHODIMP_(void)
2097 nsIOService::SpeculativeConnectWithOriginAttributesNative(
2098 nsIURI* aURI, OriginAttributes&& aOriginAttributes,
2099 nsIInterfaceRequestor* aCallbacks, bool aAnonymous) {
2100 Maybe<OriginAttributes> originAttributes;
2101 originAttributes.emplace(aOriginAttributes);
2102 Unused << SpeculativeConnectInternal(
2103 aURI, nullptr, std::move(originAttributes), aCallbacks, aAnonymous);
2106 NS_IMETHODIMP
2107 nsIOService::NotImplemented() { return NS_ERROR_NOT_IMPLEMENTED; }
2109 NS_IMETHODIMP
2110 nsIOService::GetSocketProcessLaunched(bool* aResult) {
2111 NS_ENSURE_ARG_POINTER(aResult);
2113 *aResult = SocketProcessReady();
2114 return NS_OK;
2117 bool nsIOService::HasObservers(const char* aTopic) {
2118 MOZ_ASSERT(false, "Calling this method is unexpected");
2119 return false;
2122 NS_IMETHODIMP
2123 nsIOService::GetSocketProcessId(uint64_t* aPid) {
2124 NS_ENSURE_ARG_POINTER(aPid);
2126 *aPid = 0;
2127 if (!mSocketProcess) {
2128 return NS_OK;
2131 if (SocketProcessParent* actor = mSocketProcess->GetActor()) {
2132 *aPid = (uint64_t)actor->OtherPid();
2135 return NS_OK;
2138 NS_IMETHODIMP
2139 nsIOService::RegisterProtocolHandler(const nsACString& aScheme,
2140 nsIProtocolHandler* aHandler,
2141 uint32_t aProtocolFlags,
2142 int32_t aDefaultPort) {
2143 if (mShutdown) {
2144 return NS_ERROR_NOT_AVAILABLE;
2146 if (aScheme.IsEmpty()) {
2147 return NS_ERROR_INVALID_ARG;
2150 nsAutoCString scheme(aScheme);
2151 ToLowerCase(scheme);
2153 AutoWriteLock lock(mLock);
2154 return mRuntimeProtocolHandlers.WithEntryHandle(scheme, [&](auto&& entry) {
2155 if (entry) {
2156 NS_WARNING("Cannot override an existing dynamic protocol handler");
2157 return NS_ERROR_FACTORY_EXISTS;
2159 if (xpcom::StaticProtocolHandler::Lookup(scheme)) {
2160 NS_WARNING("Cannot override an existing static protocol handler");
2161 return NS_ERROR_FACTORY_EXISTS;
2163 nsMainThreadPtrHandle<nsIProtocolHandler> handler(
2164 new nsMainThreadPtrHolder<nsIProtocolHandler>("RuntimeProtocolHandler",
2165 aHandler));
2166 entry.Insert(RuntimeProtocolHandler{
2167 .mHandler = std::move(handler),
2168 .mProtocolFlags = aProtocolFlags,
2169 .mDefaultPort = aDefaultPort,
2171 return NS_OK;
2175 NS_IMETHODIMP
2176 nsIOService::UnregisterProtocolHandler(const nsACString& aScheme) {
2177 if (mShutdown) {
2178 return NS_OK;
2180 if (aScheme.IsEmpty()) {
2181 return NS_ERROR_INVALID_ARG;
2184 nsAutoCString scheme(aScheme);
2185 ToLowerCase(scheme);
2187 AutoWriteLock lock(mLock);
2188 return mRuntimeProtocolHandlers.Remove(scheme)
2189 ? NS_OK
2190 : NS_ERROR_FACTORY_NOT_REGISTERED;
2193 } // namespace net
2194 } // namespace mozilla