Bug 1890277: part 4) Add CSPParser support for the `trusted-types` directive, guarded...
[gecko.git] / netwerk / base / nsIOService.cpp
blob998c389ace63e178d5deb8fb44b03ff6b7339320
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."
90 #define SIMPLE_URI_SCHEMES_PREF "network.url.simple_uri_schemes"
92 nsIOService* gIOService;
93 static bool gHasWarnedUploadChannel2;
94 static bool gCaptivePortalEnabled = false;
95 static LazyLogModule gIOServiceLog("nsIOService");
96 #undef LOG
97 #define LOG(args) MOZ_LOG(gIOServiceLog, LogLevel::Debug, args)
99 // A general port blacklist. Connections to these ports will not be allowed
100 // unless the protocol overrides.
102 // This list is to be kept in sync with "bad ports" as defined in the
103 // WHATWG Fetch standard at <https://fetch.spec.whatwg.org/#port-blocking>
105 int16_t gBadPortList[] = {
106 1, // tcpmux
107 7, // echo
108 9, // discard
109 11, // systat
110 13, // daytime
111 15, // netstat
112 17, // qotd
113 19, // chargen
114 20, // ftp-data
115 21, // ftp
116 22, // ssh
117 23, // telnet
118 25, // smtp
119 37, // time
120 42, // name
121 43, // nicname
122 53, // domain
123 69, // tftp
124 77, // priv-rjs
125 79, // finger
126 87, // ttylink
127 95, // supdup
128 101, // hostriame
129 102, // iso-tsap
130 103, // gppitnp
131 104, // acr-nema
132 109, // pop2
133 110, // pop3
134 111, // sunrpc
135 113, // auth
136 115, // sftp
137 117, // uucp-path
138 119, // nntp
139 123, // ntp
140 135, // loc-srv / epmap
141 137, // netbios
142 139, // netbios
143 143, // imap2
144 161, // snmp
145 179, // bgp
146 389, // ldap
147 427, // afp (alternate)
148 465, // smtp (alternate)
149 512, // print / exec
150 513, // login
151 514, // shell
152 515, // printer
153 526, // tempo
154 530, // courier
155 531, // chat
156 532, // netnews
157 540, // uucp
158 548, // afp
159 554, // rtsp
160 556, // remotefs
161 563, // nntp+ssl
162 587, // smtp (outgoing)
163 601, // syslog-conn
164 636, // ldap+ssl
165 989, // ftps-data
166 990, // ftps
167 993, // imap+ssl
168 995, // pop3+ssl
169 1719, // h323gatestat
170 1720, // h323hostcall
171 1723, // pptp
172 2049, // nfs
173 3659, // apple-sasl
174 4045, // lockd
175 4160, // sieve
176 5060, // sip
177 5061, // sips
178 6000, // x11
179 6566, // sane-port
180 6665, // irc (alternate)
181 6666, // irc (alternate)
182 6667, // irc (default)
183 6668, // irc (alternate)
184 6669, // irc (alternate)
185 6679, // osaut
186 6697, // irc+tls
187 10080, // amanda
188 0, // Sentinel value: This MUST be zero
191 static const char kProfileChangeNetTeardownTopic[] =
192 "profile-change-net-teardown";
193 static const char kProfileChangeNetRestoreTopic[] =
194 "profile-change-net-restore";
195 static const char kProfileDoChange[] = "profile-do-change";
197 // Necko buffer defaults
198 uint32_t nsIOService::gDefaultSegmentSize = 4096;
199 uint32_t nsIOService::gDefaultSegmentCount = 24;
201 uint32_t nsIOService::sSocketProcessCrashedCount = 0;
203 ////////////////////////////////////////////////////////////////////////////////
205 nsIOService::nsIOService()
206 : mLastOfflineStateChange(PR_IntervalNow()),
207 mLastConnectivityChange(PR_IntervalNow()),
208 mLastNetworkLinkChange(PR_IntervalNow()) {}
210 static const char* gCallbackPrefs[] = {
211 PORT_PREF_PREFIX,
212 MANAGE_OFFLINE_STATUS_PREF,
213 NECKO_BUFFER_CACHE_COUNT_PREF,
214 NECKO_BUFFER_CACHE_SIZE_PREF,
215 NETWORK_CAPTIVE_PORTAL_PREF,
216 FORCE_EXTERNAL_PREF_PREFIX,
217 SIMPLE_URI_SCHEMES_PREF,
218 nullptr,
221 static const char* gCallbackPrefsForSocketProcess[] = {
222 WEBRTC_PREF_PREFIX,
223 NETWORK_DNS_PREF,
224 "network.send_ODA_to_content_directly",
225 "network.trr.",
226 "doh-rollout.",
227 "network.dns.disableIPv6",
228 "network.offline-mirrors-connectivity",
229 "network.disable-localhost-when-offline",
230 "network.proxy.parse_pac_on_socket_process",
231 "network.proxy.allow_hijacking_localhost",
232 "network.connectivity-service.",
233 "network.captive-portal-service.testMode",
234 nullptr,
237 static const char* gCallbackSecurityPrefs[] = {
238 // Note the prefs listed below should be in sync with the code in
239 // HandleTLSPrefChange().
240 "security.tls.version.min",
241 "security.tls.version.max",
242 "security.tls.version.enable-deprecated",
243 "security.tls.hello_downgrade_check",
244 "security.ssl.require_safe_negotiation",
245 "security.ssl.enable_false_start",
246 "security.ssl.enable_alpn",
247 "security.tls.enable_0rtt_data",
248 "security.ssl.disable_session_identifiers",
249 "security.tls.enable_post_handshake_auth",
250 "security.tls.enable_delegated_credentials",
251 // Note the prefs listed below should be in sync with the code in
252 // SetValidationOptionsCommon().
253 "security.ssl.enable_ocsp_stapling",
254 "security.ssl.enable_ocsp_must_staple",
255 "security.pki.certificate_transparency.mode",
256 nullptr,
259 nsresult nsIOService::Init() {
260 SSLTokensCache::Init();
262 InitializeCaptivePortalService();
264 // setup our bad port list stuff
265 for (int i = 0; gBadPortList[i]; i++) {
266 // We can't be accessed by another thread yet
267 MOZ_PUSH_IGNORE_THREAD_SAFETY
268 mRestrictedPortList.AppendElement(gBadPortList[i]);
269 MOZ_POP_THREAD_SAFETY
272 // Further modifications to the port list come from prefs
273 Preferences::RegisterPrefixCallbacks(nsIOService::PrefsChanged,
274 gCallbackPrefs, this);
275 PrefsChanged();
277 mSocketProcessTopicBlockedList.Insert(
278 nsLiteralCString(NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID));
279 mSocketProcessTopicBlockedList.Insert(
280 nsLiteralCString(NS_XPCOM_SHUTDOWN_OBSERVER_ID));
281 mSocketProcessTopicBlockedList.Insert("xpcom-shutdown-threads"_ns);
282 mSocketProcessTopicBlockedList.Insert("profile-do-change"_ns);
283 mSocketProcessTopicBlockedList.Insert("network:socket-process-crashed"_ns);
285 // Register for profile change notifications
286 mObserverService = services::GetObserverService();
287 AddObserver(this, kProfileChangeNetTeardownTopic, true);
288 AddObserver(this, kProfileChangeNetRestoreTopic, true);
289 AddObserver(this, kProfileDoChange, true);
290 AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, true);
291 AddObserver(this, NS_NETWORK_LINK_TOPIC, true);
292 AddObserver(this, NS_NETWORK_ID_CHANGED_TOPIC, true);
293 AddObserver(this, NS_WIDGET_WAKE_OBSERVER_TOPIC, true);
295 // Register observers for sending notifications to nsSocketTransportService
296 if (XRE_IsParentProcess()) {
297 AddObserver(this, "profile-initial-state", true);
298 AddObserver(this, NS_WIDGET_SLEEP_OBSERVER_TOPIC, true);
301 if (IsSocketProcessChild()) {
302 Preferences::RegisterCallbacks(nsIOService::OnTLSPrefChange,
303 gCallbackSecurityPrefs, this);
306 gIOService = this;
308 InitializeNetworkLinkService();
309 InitializeProtocolProxyService();
311 SetOffline(false);
313 return NS_OK;
316 NS_IMETHODIMP
317 nsIOService::AddObserver(nsIObserver* aObserver, const char* aTopic,
318 bool aOwnsWeak) {
319 if (!mObserverService) {
320 return NS_ERROR_FAILURE;
323 // Register for the origional observer.
324 nsresult rv = mObserverService->AddObserver(aObserver, aTopic, aOwnsWeak);
325 if (NS_FAILED(rv)) {
326 return rv;
329 if (!XRE_IsParentProcess()) {
330 return NS_OK;
333 nsAutoCString topic(aTopic);
334 // This happens when AddObserver() is called by nsIOService::Init(). We don't
335 // want to add nsIOService again.
336 if (SameCOMIdentity(aObserver, static_cast<nsIObserver*>(this))) {
337 mIOServiceTopicList.Insert(topic);
338 return NS_OK;
341 if (!UseSocketProcess()) {
342 return NS_OK;
345 if (mSocketProcessTopicBlockedList.Contains(topic)) {
346 return NS_ERROR_FAILURE;
349 // Avoid registering duplicate topics.
350 if (mObserverTopicForSocketProcess.Contains(topic)) {
351 return NS_ERROR_FAILURE;
354 mObserverTopicForSocketProcess.Insert(topic);
356 // Avoid registering duplicate topics.
357 if (mIOServiceTopicList.Contains(topic)) {
358 return NS_ERROR_FAILURE;
361 return mObserverService->AddObserver(this, aTopic, true);
364 NS_IMETHODIMP
365 nsIOService::RemoveObserver(nsIObserver* aObserver, const char* aTopic) {
366 return NS_ERROR_NOT_IMPLEMENTED;
369 NS_IMETHODIMP
370 nsIOService::EnumerateObservers(const char* aTopic,
371 nsISimpleEnumerator** anEnumerator) {
372 return NS_ERROR_NOT_IMPLEMENTED;
375 NS_IMETHODIMP nsIOService::NotifyObservers(nsISupports* aSubject,
376 const char* aTopic,
377 const char16_t* aSomeData) {
378 return NS_ERROR_NOT_IMPLEMENTED;
381 nsIOService::~nsIOService() {
382 if (gIOService) {
383 MOZ_ASSERT(gIOService == this);
384 gIOService = nullptr;
388 // static
389 void nsIOService::OnTLSPrefChange(const char* aPref, void* aSelf) {
390 MOZ_ASSERT(IsSocketProcessChild());
392 if (!EnsureNSSInitializedChromeOrContent()) {
393 LOG(("NSS not initialized."));
394 return;
397 nsAutoCString pref(aPref);
398 // The preferences listed in gCallbackSecurityPrefs need to be in sync with
399 // the code in HandleTLSPrefChange() and SetValidationOptionsCommon().
400 if (HandleTLSPrefChange(pref)) {
401 LOG(("HandleTLSPrefChange done"));
402 } else if (pref.EqualsLiteral("security.ssl.enable_ocsp_stapling") ||
403 pref.EqualsLiteral("security.ssl.enable_ocsp_must_staple") ||
404 pref.EqualsLiteral("security.pki.certificate_transparency.mode")) {
405 SetValidationOptionsCommon();
409 nsresult nsIOService::InitializeCaptivePortalService() {
410 if (XRE_GetProcessType() != GeckoProcessType_Default) {
411 // We only initalize a captive portal service in the main process
412 return NS_OK;
415 mCaptivePortalService = do_GetService(NS_CAPTIVEPORTAL_CID);
416 if (mCaptivePortalService) {
417 return static_cast<CaptivePortalService*>(mCaptivePortalService.get())
418 ->Initialize();
421 // Instantiate and initialize the service
422 RefPtr<NetworkConnectivityService> ncs =
423 NetworkConnectivityService::GetSingleton();
425 return NS_OK;
428 nsresult nsIOService::InitializeSocketTransportService() {
429 nsresult rv = NS_OK;
431 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
432 LOG(
433 ("nsIOService aborting InitializeSocketTransportService because of app "
434 "shutdown"));
435 return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
438 if (!mSocketTransportService) {
439 mSocketTransportService =
440 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
441 if (NS_FAILED(rv)) {
442 NS_WARNING("failed to get socket transport service");
446 if (mSocketTransportService) {
447 rv = mSocketTransportService->Init();
448 NS_ASSERTION(NS_SUCCEEDED(rv), "socket transport service init failed");
449 mSocketTransportService->SetOffline(false);
452 return rv;
455 nsresult nsIOService::InitializeNetworkLinkService() {
456 nsresult rv = NS_OK;
458 if (mNetworkLinkServiceInitialized) return rv;
460 if (!NS_IsMainThread()) {
461 NS_WARNING("Network link service should be created on main thread");
462 return NS_ERROR_FAILURE;
465 // go into managed mode if we can, and chrome process
466 if (!XRE_IsParentProcess()) {
467 return NS_ERROR_NOT_AVAILABLE;
470 mNetworkLinkService = do_GetService(NS_NETWORK_LINK_SERVICE_CONTRACTID, &rv);
472 if (mNetworkLinkService) {
473 mNetworkLinkServiceInitialized = true;
476 // After initializing the networkLinkService, query the connectivity state
477 OnNetworkLinkEvent(NS_NETWORK_LINK_DATA_UNKNOWN);
479 return rv;
482 nsresult nsIOService::InitializeProtocolProxyService() {
483 nsresult rv = NS_OK;
485 if (XRE_IsParentProcess()) {
486 // for early-initialization
487 Unused << do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv);
490 return rv;
493 already_AddRefed<nsIOService> nsIOService::GetInstance() {
494 if (!gIOService) {
495 RefPtr<nsIOService> ios = new nsIOService();
496 if (NS_SUCCEEDED(ios->Init())) {
497 MOZ_ASSERT(gIOService == ios.get());
498 return ios.forget();
501 return do_AddRef(gIOService);
504 class SocketProcessListenerProxy : public SocketProcessHost::Listener {
505 public:
506 SocketProcessListenerProxy() = default;
507 void OnProcessLaunchComplete(SocketProcessHost* aHost, bool aSucceeded) {
508 if (!gIOService) {
509 return;
512 gIOService->OnProcessLaunchComplete(aHost, aSucceeded);
515 void OnProcessUnexpectedShutdown(SocketProcessHost* aHost) {
516 if (!gIOService) {
517 return;
520 gIOService->OnProcessUnexpectedShutdown(aHost);
524 // static
525 bool nsIOService::TooManySocketProcessCrash() {
526 return sSocketProcessCrashedCount >=
527 StaticPrefs::network_max_socket_process_failed_count();
530 // static
531 void nsIOService::IncreaseSocketProcessCrashCount() {
532 MOZ_ASSERT(IsNeckoChild());
533 sSocketProcessCrashedCount++;
536 nsresult nsIOService::LaunchSocketProcess() {
537 MOZ_ASSERT(NS_IsMainThread());
539 if (XRE_GetProcessType() != GeckoProcessType_Default) {
540 return NS_OK;
543 // We shouldn't launch socket prcess when shutdown begins.
544 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
545 return NS_OK;
548 if (mSocketProcess) {
549 return NS_OK;
552 if (PR_GetEnv("MOZ_DISABLE_SOCKET_PROCESS")) {
553 LOG(("nsIOService skipping LaunchSocketProcess because of the env"));
554 return NS_OK;
557 if (!StaticPrefs::network_process_enabled()) {
558 LOG(("nsIOService skipping LaunchSocketProcess because of the pref"));
559 return NS_OK;
562 Preferences::RegisterPrefixCallbacks(
563 nsIOService::NotifySocketProcessPrefsChanged,
564 gCallbackPrefsForSocketProcess, this);
566 // The subprocess is launched asynchronously, so we wait for a callback to
567 // acquire the IPDL actor.
568 mSocketProcess = new SocketProcessHost(new SocketProcessListenerProxy());
569 LOG(("nsIOService::LaunchSocketProcess"));
570 if (!mSocketProcess->Launch()) {
571 NS_WARNING("Failed to launch socket process!!");
572 DestroySocketProcess();
573 return NS_ERROR_FAILURE;
576 return NS_OK;
579 void nsIOService::DestroySocketProcess() {
580 LOG(("nsIOService::DestroySocketProcess"));
581 MOZ_ASSERT(NS_IsMainThread());
583 if (XRE_GetProcessType() != GeckoProcessType_Default || !mSocketProcess) {
584 return;
587 Preferences::UnregisterPrefixCallbacks(
588 nsIOService::NotifySocketProcessPrefsChanged,
589 gCallbackPrefsForSocketProcess, this);
591 mSocketProcess->Shutdown();
592 mSocketProcess = nullptr;
595 bool nsIOService::SocketProcessReady() {
596 return mSocketProcess && mSocketProcess->IsConnected();
599 static bool sUseSocketProcess = false;
600 static bool sUseSocketProcessChecked = false;
602 // static
603 bool nsIOService::UseSocketProcess(bool aCheckAgain) {
604 if (sUseSocketProcessChecked && !aCheckAgain) {
605 return sUseSocketProcess;
608 sUseSocketProcessChecked = true;
609 sUseSocketProcess = false;
611 if (PR_GetEnv("MOZ_DISABLE_SOCKET_PROCESS")) {
612 return sUseSocketProcess;
615 if (TooManySocketProcessCrash()) {
616 LOG(("TooManySocketProcessCrash"));
617 return sUseSocketProcess;
620 if (PR_GetEnv("MOZ_FORCE_USE_SOCKET_PROCESS")) {
621 sUseSocketProcess = true;
622 return sUseSocketProcess;
625 if (StaticPrefs::network_process_enabled()) {
626 sUseSocketProcess =
627 StaticPrefs::network_http_network_access_on_socket_process_enabled();
629 return sUseSocketProcess;
632 // static
633 void nsIOService::NotifySocketProcessPrefsChanged(const char* aName,
634 void* aSelf) {
635 static_cast<nsIOService*>(aSelf)->NotifySocketProcessPrefsChanged(aName);
638 void nsIOService::NotifySocketProcessPrefsChanged(const char* aName) {
639 MOZ_ASSERT(NS_IsMainThread());
641 if (!XRE_IsParentProcess()) {
642 return;
645 if (!StaticPrefs::network_process_enabled()) {
646 return;
649 dom::Pref pref(nsCString(aName), /* isLocked */ false,
650 /* isSanitized */ false, Nothing(), Nothing());
652 Preferences::GetPreference(&pref, GeckoProcessType_Socket,
653 /* remoteType */ ""_ns);
654 auto sendPrefUpdate = [pref]() {
655 Unused << gIOService->mSocketProcess->GetActor()->SendPreferenceUpdate(
656 pref);
658 CallOrWaitForSocketProcess(sendPrefUpdate);
661 void nsIOService::OnProcessLaunchComplete(SocketProcessHost* aHost,
662 bool aSucceeded) {
663 MOZ_ASSERT(NS_IsMainThread());
665 LOG(("nsIOService::OnProcessLaunchComplete aSucceeded=%d\n", aSucceeded));
667 mSocketProcessLaunchComplete = aSucceeded;
669 if (mShutdown || !SocketProcessReady() || !aSucceeded) {
670 mPendingEvents.Clear();
671 return;
674 if (!mPendingEvents.IsEmpty()) {
675 nsTArray<std::function<void()>> pendingEvents = std::move(mPendingEvents);
676 for (auto& func : pendingEvents) {
677 func();
682 void nsIOService::CallOrWaitForSocketProcess(
683 const std::function<void()>& aFunc) {
684 MOZ_ASSERT(NS_IsMainThread());
685 if (IsSocketProcessLaunchComplete() && SocketProcessReady()) {
686 aFunc();
687 } else {
688 mPendingEvents.AppendElement(aFunc); // infallible
689 LaunchSocketProcess();
693 int32_t nsIOService::SocketProcessPid() {
694 if (!mSocketProcess) {
695 return 0;
697 if (SocketProcessParent* actor = mSocketProcess->GetActor()) {
698 return (int32_t)actor->OtherPid();
700 return 0;
703 bool nsIOService::IsSocketProcessLaunchComplete() {
704 MOZ_ASSERT(NS_IsMainThread());
705 return mSocketProcessLaunchComplete;
708 void nsIOService::OnProcessUnexpectedShutdown(SocketProcessHost* aHost) {
709 MOZ_ASSERT(NS_IsMainThread());
711 LOG(("nsIOService::OnProcessUnexpectedShutdown\n"));
712 DestroySocketProcess();
713 mPendingEvents.Clear();
715 // Nothing to do if socket process was not used before.
716 if (!UseSocketProcess()) {
717 return;
720 sSocketProcessCrashedCount++;
721 if (TooManySocketProcessCrash()) {
722 sUseSocketProcessChecked = false;
723 DNSServiceWrapper::SwitchToBackupDNSService();
726 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
727 if (observerService) {
728 (void)observerService->NotifyObservers(
729 nullptr, "network:socket-process-crashed", nullptr);
732 // UseSocketProcess() could return false if we have too many crashes, so we
733 // should call it again.
734 if (UseSocketProcess()) {
735 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(
736 NewRunnableMethod("nsIOService::LaunchSocketProcess", this,
737 &nsIOService::LaunchSocketProcess)));
741 RefPtr<MemoryReportingProcess> nsIOService::GetSocketProcessMemoryReporter() {
742 // Check the prefs here again, since we don't want to create
743 // SocketProcessMemoryReporter for some tests.
744 if (!StaticPrefs::network_process_enabled() || !SocketProcessReady()) {
745 return nullptr;
748 return new SocketProcessMemoryReporter();
751 NS_IMETHODIMP
752 nsIOService::SocketProcessTelemetryPing() {
753 CallOrWaitForSocketProcess([]() {
754 Unused << gIOService->mSocketProcess->GetActor()
755 ->SendSocketProcessTelemetryPing();
757 return NS_OK;
760 NS_IMPL_ISUPPORTS(nsIOService, nsIIOService, nsINetUtil, nsISpeculativeConnect,
761 nsIObserver, nsIIOServiceInternal, nsISupportsWeakReference,
762 nsIObserverService)
764 ////////////////////////////////////////////////////////////////////////////////
766 nsresult nsIOService::RecheckCaptivePortal() {
767 MOZ_ASSERT(NS_IsMainThread(), "Must be called on the main thread");
768 if (!mCaptivePortalService) {
769 return NS_OK;
771 nsCOMPtr<nsIRunnable> task = NewRunnableMethod(
772 "nsIOService::RecheckCaptivePortal", mCaptivePortalService,
773 &nsICaptivePortalService::RecheckCaptivePortal);
774 return NS_DispatchToMainThread(task);
777 nsresult nsIOService::RecheckCaptivePortalIfLocalRedirect(nsIChannel* newChan) {
778 nsresult rv;
780 if (!mCaptivePortalService) {
781 return NS_OK;
784 nsCOMPtr<nsIURI> uri;
785 rv = newChan->GetURI(getter_AddRefs(uri));
786 if (NS_FAILED(rv)) {
787 return rv;
790 nsCString host;
791 rv = uri->GetHost(host);
792 if (NS_FAILED(rv)) {
793 return rv;
796 NetAddr addr;
797 // If the redirect wasn't to an IP literal, so there's probably no need
798 // to trigger the captive portal detection right now. It can wait.
799 if (NS_SUCCEEDED(addr.InitFromString(host)) && addr.IsIPAddrLocal()) {
800 RecheckCaptivePortal();
803 return NS_OK;
806 nsresult nsIOService::AsyncOnChannelRedirect(
807 nsIChannel* oldChan, nsIChannel* newChan, uint32_t flags,
808 nsAsyncRedirectVerifyHelper* helper) {
809 // If a redirect to a local network address occurs, then chances are we
810 // are in a captive portal, so we trigger a recheck.
811 RecheckCaptivePortalIfLocalRedirect(newChan);
813 // This is silly. I wish there was a simpler way to get at the global
814 // reference of the contentSecurityManager. But it lives in the XPCOM
815 // service registry.
816 nsCOMPtr<nsIChannelEventSink> sink =
817 do_GetService(NS_CONTENTSECURITYMANAGER_CONTRACTID);
818 if (sink) {
819 nsresult rv =
820 helper->DelegateOnChannelRedirect(sink, oldChan, newChan, flags);
821 if (NS_FAILED(rv)) return rv;
824 // Finally, our category
825 nsCOMArray<nsIChannelEventSink> entries;
826 mChannelEventSinks.GetEntries(entries);
827 int32_t len = entries.Count();
828 for (int32_t i = 0; i < len; ++i) {
829 nsresult rv =
830 helper->DelegateOnChannelRedirect(entries[i], oldChan, newChan, flags);
831 if (NS_FAILED(rv)) return rv;
834 nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(oldChan));
836 // Collect the redirection from HTTP(S) only.
837 if (httpChan) {
838 MOZ_ASSERT(NS_IsMainThread());
839 nsCOMPtr<nsIURI> newURI;
840 newChan->GetURI(getter_AddRefs(newURI));
841 MOZ_ASSERT(newURI);
843 nsAutoCString scheme;
844 newURI->GetScheme(scheme);
845 MOZ_ASSERT(!scheme.IsEmpty());
847 Telemetry::AccumulateCategoricalKeyed(
848 scheme,
849 oldChan->IsDocument()
850 ? Telemetry::LABELS_NETWORK_HTTP_REDIRECT_TO_SCHEME::topLevel
851 : Telemetry::LABELS_NETWORK_HTTP_REDIRECT_TO_SCHEME::subresource);
854 return NS_OK;
857 bool nsIOService::UsesExternalProtocolHandler(const nsACString& aScheme) {
858 if (aScheme == "file"_ns || aScheme == "chrome"_ns ||
859 aScheme == "resource"_ns) {
860 // Don't allow file:, chrome: or resource: URIs to be handled with
861 // nsExternalProtocolHandler, since internally we rely on being able to
862 // use and read from these URIs.
863 return false;
866 if (aScheme == "place"_ns || aScheme == "fake-favicon-uri"_ns ||
867 aScheme == "favicon"_ns || aScheme == "moz-nullprincipal"_ns) {
868 // Force place: fake-favicon-uri: favicon: and moz-nullprincipal: URIs to be
869 // handled with nsExternalProtocolHandler, and not with a dynamically
870 // registered handler.
871 return true;
874 // If prefs configure the URI to be handled externally, do so.
875 for (const auto& scheme : mForceExternalSchemes) {
876 if (aScheme == scheme) {
877 return true;
880 return false;
883 ProtocolHandlerInfo nsIOService::LookupProtocolHandler(
884 const nsACString& aScheme) {
885 // Look-ups are ASCII-case-insensitive, so lower-case the string before
886 // continuing.
887 nsAutoCString scheme(aScheme);
888 ToLowerCase(scheme);
890 // NOTE: If we could get rid of mForceExternalSchemes (or prevent them from
891 // disabling static protocols), we could avoid locking mLock until we need to
892 // check `mRuntimeProtocolHandlers.
893 AutoReadLock lock(mLock);
894 if (!UsesExternalProtocolHandler(scheme)) {
895 // Try the static protocol handler first - they cannot be overridden by
896 // dynamic protocols.
897 if (const xpcom::StaticProtocolHandler* handler =
898 xpcom::StaticProtocolHandler::Lookup(scheme)) {
899 return ProtocolHandlerInfo(*handler);
901 if (auto handler = mRuntimeProtocolHandlers.Lookup(scheme)) {
902 return ProtocolHandlerInfo(handler.Data());
905 return ProtocolHandlerInfo(xpcom::StaticProtocolHandler::Default());
908 NS_IMETHODIMP
909 nsIOService::GetProtocolHandler(const char* scheme,
910 nsIProtocolHandler** result) {
911 AssertIsOnMainThread();
912 NS_ENSURE_ARG_POINTER(scheme);
914 *result = LookupProtocolHandler(nsDependentCString(scheme)).Handler().take();
915 return *result ? NS_OK : NS_ERROR_UNKNOWN_PROTOCOL;
918 NS_IMETHODIMP
919 nsIOService::ExtractScheme(const nsACString& inURI, nsACString& scheme) {
920 return net_ExtractURLScheme(inURI, scheme);
923 NS_IMETHODIMP
924 nsIOService::HostnameIsLocalIPAddress(nsIURI* aURI, bool* aResult) {
925 NS_ENSURE_ARG_POINTER(aURI);
927 nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(aURI);
928 NS_ENSURE_ARG_POINTER(innerURI);
930 nsAutoCString host;
931 nsresult rv = innerURI->GetAsciiHost(host);
932 if (NS_FAILED(rv)) {
933 return rv;
936 *aResult = false;
938 NetAddr addr;
939 if (NS_SUCCEEDED(addr.InitFromString(host)) && addr.IsIPAddrLocal()) {
940 *aResult = true;
943 return NS_OK;
946 NS_IMETHODIMP
947 nsIOService::HostnameIsSharedIPAddress(nsIURI* aURI, bool* aResult) {
948 NS_ENSURE_ARG_POINTER(aURI);
950 nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(aURI);
951 NS_ENSURE_ARG_POINTER(innerURI);
953 nsAutoCString host;
954 nsresult rv = innerURI->GetAsciiHost(host);
955 if (NS_FAILED(rv)) {
956 return rv;
959 *aResult = false;
961 NetAddr addr;
962 if (NS_SUCCEEDED(addr.InitFromString(host)) && addr.IsIPAddrShared()) {
963 *aResult = true;
966 return NS_OK;
969 NS_IMETHODIMP
970 nsIOService::IsValidHostname(const nsACString& inHostname, bool* aResult) {
971 *aResult = net_IsValidHostName(inHostname);
973 return NS_OK;
976 NS_IMETHODIMP
977 nsIOService::GetProtocolFlags(const char* scheme, uint32_t* flags) {
978 NS_ENSURE_ARG_POINTER(scheme);
980 *flags =
981 LookupProtocolHandler(nsDependentCString(scheme)).StaticProtocolFlags();
982 return NS_OK;
985 NS_IMETHODIMP
986 nsIOService::GetDynamicProtocolFlags(nsIURI* uri, uint32_t* flags) {
987 AssertIsOnMainThread();
988 NS_ENSURE_ARG(uri);
990 nsAutoCString scheme;
991 nsresult rv = uri->GetScheme(scheme);
992 NS_ENSURE_SUCCESS(rv, rv);
994 return LookupProtocolHandler(scheme).DynamicProtocolFlags(uri, flags);
997 NS_IMETHODIMP
998 nsIOService::GetDefaultPort(const char* scheme, int32_t* defaultPort) {
999 NS_ENSURE_ARG_POINTER(scheme);
1001 *defaultPort =
1002 LookupProtocolHandler(nsDependentCString(scheme)).DefaultPort();
1003 return NS_OK;
1006 nsresult nsIOService::NewURI(const nsACString& aSpec, const char* aCharset,
1007 nsIURI* aBaseURI, nsIURI** result) {
1008 return NS_NewURI(result, aSpec, aCharset, aBaseURI);
1011 NS_IMETHODIMP
1012 nsIOService::NewFileURI(nsIFile* file, nsIURI** result) {
1013 nsresult rv;
1014 NS_ENSURE_ARG_POINTER(file);
1016 nsCOMPtr<nsIProtocolHandler> handler;
1018 rv = GetProtocolHandler("file", getter_AddRefs(handler));
1019 if (NS_FAILED(rv)) return rv;
1021 nsCOMPtr<nsIFileProtocolHandler> fileHandler(do_QueryInterface(handler, &rv));
1022 if (NS_FAILED(rv)) return rv;
1024 return fileHandler->NewFileURI(file, result);
1027 // static
1028 already_AddRefed<nsIURI> nsIOService::CreateExposableURI(nsIURI* aURI) {
1029 MOZ_ASSERT(aURI, "Must have a URI");
1030 nsCOMPtr<nsIURI> uri = aURI;
1031 bool hasUserPass;
1032 if (NS_SUCCEEDED(aURI->GetHasUserPass(&hasUserPass)) && hasUserPass) {
1033 DebugOnly<nsresult> rv = NS_MutateURI(uri).SetUserPass(""_ns).Finalize(uri);
1034 MOZ_ASSERT(NS_SUCCEEDED(rv) && uri, "Mutating URI should never fail");
1036 return uri.forget();
1039 NS_IMETHODIMP
1040 nsIOService::CreateExposableURI(nsIURI* aURI, nsIURI** _result) {
1041 NS_ENSURE_ARG_POINTER(aURI);
1042 NS_ENSURE_ARG_POINTER(_result);
1043 nsCOMPtr<nsIURI> exposableURI = CreateExposableURI(aURI);
1044 exposableURI.forget(_result);
1045 return NS_OK;
1048 NS_IMETHODIMP
1049 nsIOService::NewChannelFromURI(nsIURI* aURI, nsINode* aLoadingNode,
1050 nsIPrincipal* aLoadingPrincipal,
1051 nsIPrincipal* aTriggeringPrincipal,
1052 uint32_t aSecurityFlags,
1053 nsContentPolicyType aContentPolicyType,
1054 nsIChannel** result) {
1055 return NewChannelFromURIWithProxyFlags(aURI,
1056 nullptr, // aProxyURI
1057 0, // aProxyFlags
1058 aLoadingNode, aLoadingPrincipal,
1059 aTriggeringPrincipal, aSecurityFlags,
1060 aContentPolicyType, result);
1062 nsresult nsIOService::NewChannelFromURIWithClientAndController(
1063 nsIURI* aURI, nsINode* aLoadingNode, nsIPrincipal* aLoadingPrincipal,
1064 nsIPrincipal* aTriggeringPrincipal,
1065 const Maybe<ClientInfo>& aLoadingClientInfo,
1066 const Maybe<ServiceWorkerDescriptor>& aController, uint32_t aSecurityFlags,
1067 nsContentPolicyType aContentPolicyType, uint32_t aSandboxFlags,
1068 bool aSkipCheckForBrokenURLOrZeroSized, nsIChannel** aResult) {
1069 return NewChannelFromURIWithProxyFlagsInternal(
1070 aURI,
1071 nullptr, // aProxyURI
1072 0, // aProxyFlags
1073 aLoadingNode, aLoadingPrincipal, aTriggeringPrincipal, aLoadingClientInfo,
1074 aController, aSecurityFlags, aContentPolicyType, aSandboxFlags,
1075 aSkipCheckForBrokenURLOrZeroSized, aResult);
1078 NS_IMETHODIMP
1079 nsIOService::NewChannelFromURIWithLoadInfo(nsIURI* aURI, nsILoadInfo* aLoadInfo,
1080 nsIChannel** result) {
1081 return NewChannelFromURIWithProxyFlagsInternal(aURI,
1082 nullptr, // aProxyURI
1083 0, // aProxyFlags
1084 aLoadInfo, result);
1087 nsresult nsIOService::NewChannelFromURIWithProxyFlagsInternal(
1088 nsIURI* aURI, nsIURI* aProxyURI, uint32_t aProxyFlags,
1089 nsINode* aLoadingNode, nsIPrincipal* aLoadingPrincipal,
1090 nsIPrincipal* aTriggeringPrincipal,
1091 const Maybe<ClientInfo>& aLoadingClientInfo,
1092 const Maybe<ServiceWorkerDescriptor>& aController, uint32_t aSecurityFlags,
1093 nsContentPolicyType aContentPolicyType, uint32_t aSandboxFlags,
1094 bool aSkipCheckForBrokenURLOrZeroSized, nsIChannel** result) {
1095 nsCOMPtr<nsILoadInfo> loadInfo = new LoadInfo(
1096 aLoadingPrincipal, aTriggeringPrincipal, aLoadingNode, aSecurityFlags,
1097 aContentPolicyType, aLoadingClientInfo, aController, aSandboxFlags,
1098 aSkipCheckForBrokenURLOrZeroSized);
1099 return NewChannelFromURIWithProxyFlagsInternal(aURI, aProxyURI, aProxyFlags,
1100 loadInfo, result);
1103 nsresult nsIOService::NewChannelFromURIWithProxyFlagsInternal(
1104 nsIURI* aURI, nsIURI* aProxyURI, uint32_t aProxyFlags,
1105 nsILoadInfo* aLoadInfo, nsIChannel** result) {
1106 nsresult rv;
1107 NS_ENSURE_ARG_POINTER(aURI);
1108 // all channel creations must provide a valid loadinfo
1109 MOZ_ASSERT(aLoadInfo, "can not create channel without aLoadInfo");
1110 NS_ENSURE_ARG_POINTER(aLoadInfo);
1112 nsAutoCString scheme;
1113 rv = aURI->GetScheme(scheme);
1114 if (NS_FAILED(rv)) return rv;
1116 nsCOMPtr<nsIProtocolHandler> handler;
1117 rv = GetProtocolHandler(scheme.get(), getter_AddRefs(handler));
1118 if (NS_FAILED(rv)) return rv;
1120 nsCOMPtr<nsIChannel> channel;
1121 nsCOMPtr<nsIProxiedProtocolHandler> pph = do_QueryInterface(handler);
1122 if (pph) {
1123 rv = pph->NewProxiedChannel(aURI, nullptr, aProxyFlags, aProxyURI,
1124 aLoadInfo, getter_AddRefs(channel));
1125 } else {
1126 rv = handler->NewChannel(aURI, aLoadInfo, getter_AddRefs(channel));
1128 if (NS_FAILED(rv)) return rv;
1130 // Make sure that all the individual protocolhandlers attach a loadInfo.
1131 nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
1132 if (aLoadInfo != loadInfo) {
1133 MOZ_ASSERT(false, "newly created channel must have a loadinfo attached");
1134 return NS_ERROR_UNEXPECTED;
1137 // If we're sandboxed, make sure to clear any owner the channel
1138 // might already have.
1139 if (loadInfo->GetLoadingSandboxed()) {
1140 channel->SetOwner(nullptr);
1143 // Some extensions override the http protocol handler and provide their own
1144 // implementation. The channels returned from that implementation doesn't
1145 // seem to always implement the nsIUploadChannel2 interface, presumably
1146 // because it's a new interface.
1147 // Eventually we should remove this and simply require that http channels
1148 // implement the new interface.
1149 // See bug 529041
1150 if (!gHasWarnedUploadChannel2 && scheme.EqualsLiteral("http")) {
1151 nsCOMPtr<nsIUploadChannel2> uploadChannel2 = do_QueryInterface(channel);
1152 if (!uploadChannel2) {
1153 nsCOMPtr<nsIConsoleService> consoleService =
1154 do_GetService(NS_CONSOLESERVICE_CONTRACTID);
1155 if (consoleService) {
1156 consoleService->LogStringMessage(
1157 u"Http channel implementation "
1158 "doesn't support nsIUploadChannel2. An extension has "
1159 "supplied a non-functional http protocol handler. This will "
1160 "break behavior and in future releases not work at all.");
1162 gHasWarnedUploadChannel2 = true;
1166 channel.forget(result);
1167 return NS_OK;
1170 NS_IMETHODIMP
1171 nsIOService::NewChannelFromURIWithProxyFlags(
1172 nsIURI* aURI, nsIURI* aProxyURI, uint32_t aProxyFlags,
1173 nsINode* aLoadingNode, nsIPrincipal* aLoadingPrincipal,
1174 nsIPrincipal* aTriggeringPrincipal, uint32_t aSecurityFlags,
1175 nsContentPolicyType aContentPolicyType, nsIChannel** result) {
1176 return NewChannelFromURIWithProxyFlagsInternal(
1177 aURI, aProxyURI, aProxyFlags, aLoadingNode, aLoadingPrincipal,
1178 aTriggeringPrincipal, Maybe<ClientInfo>(),
1179 Maybe<ServiceWorkerDescriptor>(), aSecurityFlags, aContentPolicyType, 0,
1180 /* aSkipCheckForBrokenURLOrZeroSized = */ false, result);
1183 NS_IMETHODIMP
1184 nsIOService::NewChannel(const nsACString& aSpec, const char* aCharset,
1185 nsIURI* aBaseURI, nsINode* aLoadingNode,
1186 nsIPrincipal* aLoadingPrincipal,
1187 nsIPrincipal* aTriggeringPrincipal,
1188 uint32_t aSecurityFlags,
1189 nsContentPolicyType aContentPolicyType,
1190 nsIChannel** result) {
1191 nsresult rv;
1192 nsCOMPtr<nsIURI> uri;
1193 rv = NewURI(aSpec, aCharset, aBaseURI, getter_AddRefs(uri));
1194 if (NS_FAILED(rv)) return rv;
1196 return NewChannelFromURI(uri, aLoadingNode, aLoadingPrincipal,
1197 aTriggeringPrincipal, aSecurityFlags,
1198 aContentPolicyType, result);
1201 NS_IMETHODIMP
1202 nsIOService::NewWebTransport(nsIWebTransport** result) {
1203 if (!XRE_IsParentProcess()) {
1204 return NS_ERROR_NOT_AVAILABLE;
1207 nsCOMPtr<nsIWebTransport> webTransport = new WebTransportSessionProxy();
1209 webTransport.forget(result);
1210 return NS_OK;
1213 bool nsIOService::IsLinkUp() {
1214 InitializeNetworkLinkService();
1216 if (!mNetworkLinkService) {
1217 // We cannot decide, assume the link is up
1218 return true;
1221 bool isLinkUp;
1222 nsresult rv;
1223 rv = mNetworkLinkService->GetIsLinkUp(&isLinkUp);
1224 if (NS_FAILED(rv)) {
1225 return true;
1228 return isLinkUp;
1231 NS_IMETHODIMP
1232 nsIOService::GetOffline(bool* offline) {
1233 if (StaticPrefs::network_offline_mirrors_connectivity()) {
1234 *offline = mOffline || !mConnectivity;
1235 } else {
1236 *offline = mOffline;
1238 return NS_OK;
1241 NS_IMETHODIMP
1242 nsIOService::SetOffline(bool offline) { return SetOfflineInternal(offline); }
1244 nsresult nsIOService::SetOfflineInternal(bool offline,
1245 bool notifySocketProcess) {
1246 LOG(("nsIOService::SetOffline offline=%d\n", offline));
1247 // When someone wants to go online (!offline) after we got XPCOM shutdown
1248 // throw ERROR_NOT_AVAILABLE to prevent return to online state.
1249 if ((mShutdown || mOfflineForProfileChange) && !offline) {
1250 return NS_ERROR_NOT_AVAILABLE;
1253 // SetOffline() may re-enter while it's shutting down services.
1254 // If that happens, save the most recent value and it will be
1255 // processed when the first SetOffline() call is done bringing
1256 // down the service.
1257 mSetOfflineValue = offline;
1258 if (mSettingOffline) {
1259 return NS_OK;
1262 mSettingOffline = true;
1264 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
1266 NS_ASSERTION(observerService, "The observer service should not be null");
1268 if (XRE_IsParentProcess()) {
1269 if (observerService) {
1270 (void)observerService->NotifyObservers(nullptr,
1271 NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC,
1272 offline ? u"true" : u"false");
1274 if (SocketProcessReady() && notifySocketProcess) {
1275 Unused << mSocketProcess->GetActor()->SendSetOffline(offline);
1279 nsIIOService* subject = static_cast<nsIIOService*>(this);
1280 while (mSetOfflineValue != mOffline) {
1281 offline = mSetOfflineValue;
1283 if (offline && !mOffline) {
1284 mOffline = true; // indicate we're trying to shutdown
1286 // don't care if notifications fail
1287 if (observerService) {
1288 observerService->NotifyObservers(subject,
1289 NS_IOSERVICE_GOING_OFFLINE_TOPIC,
1290 u"" NS_IOSERVICE_OFFLINE);
1293 if (mSocketTransportService) mSocketTransportService->SetOffline(true);
1295 mLastOfflineStateChange = PR_IntervalNow();
1296 if (observerService) {
1297 observerService->NotifyObservers(subject,
1298 NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
1299 u"" NS_IOSERVICE_OFFLINE);
1301 } else if (!offline && mOffline) {
1302 // go online
1303 InitializeSocketTransportService();
1304 mOffline = false; // indicate success only AFTER we've
1305 // brought up the services
1307 mLastOfflineStateChange = PR_IntervalNow();
1308 // don't care if notification fails
1309 // Only send the ONLINE notification if there is connectivity
1310 if (observerService && mConnectivity) {
1311 observerService->NotifyObservers(subject,
1312 NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
1313 (u"" NS_IOSERVICE_ONLINE));
1318 // Don't notify here, as the above notifications (if used) suffice.
1319 if ((mShutdown || mOfflineForProfileChange) && mOffline) {
1320 if (mSocketTransportService) {
1321 DebugOnly<nsresult> rv = mSocketTransportService->Shutdown(mShutdown);
1322 NS_ASSERTION(NS_SUCCEEDED(rv),
1323 "socket transport service shutdown failed");
1327 mSettingOffline = false;
1329 return NS_OK;
1332 NS_IMETHODIMP
1333 nsIOService::GetConnectivity(bool* aConnectivity) {
1334 *aConnectivity = mConnectivity;
1335 return NS_OK;
1338 NS_IMETHODIMP
1339 nsIOService::SetConnectivity(bool aConnectivity) {
1340 LOG(("nsIOService::SetConnectivity aConnectivity=%d\n", aConnectivity));
1341 // This should only be called from ContentChild to pass the connectivity
1342 // value from the chrome process to the content process.
1343 if (XRE_IsParentProcess()) {
1344 return NS_ERROR_NOT_AVAILABLE;
1346 return SetConnectivityInternal(aConnectivity);
1349 nsresult nsIOService::SetConnectivityInternal(bool aConnectivity) {
1350 LOG(("nsIOService::SetConnectivityInternal aConnectivity=%d\n",
1351 aConnectivity));
1352 if (mConnectivity == aConnectivity) {
1353 // Nothing to do here.
1354 return NS_OK;
1356 mConnectivity = aConnectivity;
1358 // This is used for PR_Connect PR_Close telemetry so it is important that
1359 // we have statistic about network change event even if we are offline.
1360 mLastConnectivityChange = PR_IntervalNow();
1362 if (mCaptivePortalService) {
1363 if (aConnectivity && gCaptivePortalEnabled) {
1364 // This will also trigger a captive portal check for the new network
1365 static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Start();
1366 } else {
1367 static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Stop();
1371 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
1372 if (!observerService) {
1373 return NS_OK;
1375 // This notification sends the connectivity to the child processes
1376 if (XRE_IsParentProcess()) {
1377 observerService->NotifyObservers(nullptr,
1378 NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC,
1379 aConnectivity ? u"true" : u"false");
1380 if (SocketProcessReady()) {
1381 Unused << mSocketProcess->GetActor()->SendSetConnectivity(aConnectivity);
1385 if (mOffline) {
1386 // We don't need to send any notifications if we're offline
1387 return NS_OK;
1390 if (aConnectivity) {
1391 // If we were previously offline due to connectivity=false,
1392 // send the ONLINE notification
1393 observerService->NotifyObservers(static_cast<nsIIOService*>(this),
1394 NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
1395 (u"" NS_IOSERVICE_ONLINE));
1396 } else {
1397 // If we were previously online and lost connectivity
1398 // send the OFFLINE notification
1399 observerService->NotifyObservers(static_cast<nsIIOService*>(this),
1400 NS_IOSERVICE_GOING_OFFLINE_TOPIC,
1401 u"" NS_IOSERVICE_OFFLINE);
1402 observerService->NotifyObservers(static_cast<nsIIOService*>(this),
1403 NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
1404 u"" NS_IOSERVICE_OFFLINE);
1406 return NS_OK;
1409 NS_IMETHODIMP
1410 nsIOService::AllowPort(int32_t inPort, const char* scheme, bool* _retval) {
1411 int32_t port = inPort;
1412 if (port == -1) {
1413 *_retval = true;
1414 return NS_OK;
1417 if (port <= 0 || port > std::numeric_limits<uint16_t>::max()) {
1418 *_retval = false;
1419 return NS_OK;
1422 nsTArray<int32_t> restrictedPortList;
1424 AutoReadLock lock(mLock);
1425 restrictedPortList.Assign(mRestrictedPortList);
1427 // first check to see if the port is in our blacklist:
1428 int32_t badPortListCnt = restrictedPortList.Length();
1429 for (int i = 0; i < badPortListCnt; i++) {
1430 if (port == restrictedPortList[i]) {
1431 *_retval = false;
1433 // check to see if the protocol wants to override
1434 if (!scheme) return NS_OK;
1436 // We don't support get protocol handler off main thread.
1437 if (!NS_IsMainThread()) {
1438 return NS_OK;
1440 nsCOMPtr<nsIProtocolHandler> handler;
1441 nsresult rv = GetProtocolHandler(scheme, getter_AddRefs(handler));
1442 if (NS_FAILED(rv)) return rv;
1444 // let the protocol handler decide
1445 return handler->AllowPort(port, scheme, _retval);
1449 *_retval = true;
1450 return NS_OK;
1453 ////////////////////////////////////////////////////////////////////////////////
1455 // static
1456 void nsIOService::PrefsChanged(const char* pref, void* self) {
1457 static_cast<nsIOService*>(self)->PrefsChanged(pref);
1460 void nsIOService::PrefsChanged(const char* pref) {
1461 // Look for extra ports to block
1462 if (!pref || strcmp(pref, PORT_PREF("banned")) == 0) {
1463 ParsePortList(PORT_PREF("banned"), false);
1466 // ...as well as previous blocks to remove.
1467 if (!pref || strcmp(pref, PORT_PREF("banned.override")) == 0) {
1468 ParsePortList(PORT_PREF("banned.override"), true);
1471 if (!pref || strcmp(pref, MANAGE_OFFLINE_STATUS_PREF) == 0) {
1472 bool manage;
1473 if (mNetworkLinkServiceInitialized &&
1474 NS_SUCCEEDED(
1475 Preferences::GetBool(MANAGE_OFFLINE_STATUS_PREF, &manage))) {
1476 LOG(("nsIOService::PrefsChanged ManageOfflineStatus manage=%d\n",
1477 manage));
1478 SetManageOfflineStatus(manage);
1482 if (!pref || strcmp(pref, NECKO_BUFFER_CACHE_COUNT_PREF) == 0) {
1483 int32_t count;
1484 if (NS_SUCCEEDED(
1485 Preferences::GetInt(NECKO_BUFFER_CACHE_COUNT_PREF, &count))) {
1486 /* check for bogus values and default if we find such a value */
1487 if (count > 0) gDefaultSegmentCount = count;
1491 if (!pref || strcmp(pref, NECKO_BUFFER_CACHE_SIZE_PREF) == 0) {
1492 int32_t size;
1493 if (NS_SUCCEEDED(
1494 Preferences::GetInt(NECKO_BUFFER_CACHE_SIZE_PREF, &size))) {
1495 /* check for bogus values and default if we find such a value
1496 * the upper limit here is arbitrary. having a 1mb segment size
1497 * is pretty crazy. if you remove this, consider adding some
1498 * integer rollover test.
1500 if (size > 0 && size < 1024 * 1024) gDefaultSegmentSize = size;
1502 NS_WARNING_ASSERTION(!(size & (size - 1)),
1503 "network segment size is not a power of 2!");
1506 if (!pref || strcmp(pref, NETWORK_CAPTIVE_PORTAL_PREF) == 0) {
1507 nsresult rv = Preferences::GetBool(NETWORK_CAPTIVE_PORTAL_PREF,
1508 &gCaptivePortalEnabled);
1509 if (NS_SUCCEEDED(rv) && mCaptivePortalService) {
1510 if (gCaptivePortalEnabled) {
1511 static_cast<CaptivePortalService*>(mCaptivePortalService.get())
1512 ->Start();
1513 } else {
1514 static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Stop();
1519 if (!pref || strncmp(pref, FORCE_EXTERNAL_PREF_PREFIX,
1520 strlen(FORCE_EXTERNAL_PREF_PREFIX)) == 0) {
1521 nsTArray<nsCString> prefs;
1522 if (nsIPrefBranch* prefRootBranch = Preferences::GetRootBranch()) {
1523 prefRootBranch->GetChildList(FORCE_EXTERNAL_PREF_PREFIX, prefs);
1525 nsTArray<nsCString> forceExternalSchemes;
1526 for (const auto& pref : prefs) {
1527 if (Preferences::GetBool(pref.get(), false)) {
1528 forceExternalSchemes.AppendElement(
1529 Substring(pref, strlen(FORCE_EXTERNAL_PREF_PREFIX)));
1532 AutoWriteLock lock(mLock);
1533 mForceExternalSchemes = std::move(forceExternalSchemes);
1536 if (!pref || strncmp(pref, SIMPLE_URI_SCHEMES_PREF,
1537 strlen(SIMPLE_URI_SCHEMES_PREF)) == 0) {
1538 LOG((
1539 "simple_uri_schemes pref change observed, updating the scheme list\n"));
1540 nsAutoCString schemeList;
1541 Preferences::GetCString(SIMPLE_URI_SCHEMES_PREF, schemeList);
1542 mozilla::net::ParseSimpleURISchemes(schemeList);
1546 void nsIOService::ParsePortList(const char* pref, bool remove) {
1547 nsAutoCString portList;
1548 nsTArray<int32_t> restrictedPortList;
1550 AutoWriteLock lock(mLock);
1551 restrictedPortList.Assign(std::move(mRestrictedPortList));
1553 // Get a pref string and chop it up into a list of ports.
1554 Preferences::GetCString(pref, portList);
1555 if (!portList.IsVoid()) {
1556 nsTArray<nsCString> portListArray;
1557 ParseString(portList, ',', portListArray);
1558 uint32_t index;
1559 for (index = 0; index < portListArray.Length(); index++) {
1560 portListArray[index].StripWhitespace();
1561 int32_t portBegin, portEnd;
1563 if (PR_sscanf(portListArray[index].get(), "%d-%d", &portBegin,
1564 &portEnd) == 2) {
1565 if ((portBegin < 65536) && (portEnd < 65536)) {
1566 int32_t curPort;
1567 if (remove) {
1568 for (curPort = portBegin; curPort <= portEnd; curPort++) {
1569 restrictedPortList.RemoveElement(curPort);
1571 } else {
1572 for (curPort = portBegin; curPort <= portEnd; curPort++) {
1573 restrictedPortList.AppendElement(curPort);
1577 } else {
1578 nsresult aErrorCode;
1579 int32_t port = portListArray[index].ToInteger(&aErrorCode);
1580 if (NS_SUCCEEDED(aErrorCode) && port < 65536) {
1581 if (remove) {
1582 restrictedPortList.RemoveElement(port);
1583 } else {
1584 restrictedPortList.AppendElement(port);
1591 AutoWriteLock lock(mLock);
1592 mRestrictedPortList.Assign(std::move(restrictedPortList));
1595 class nsWakeupNotifier : public Runnable {
1596 public:
1597 explicit nsWakeupNotifier(nsIIOServiceInternal* ioService)
1598 : Runnable("net::nsWakeupNotifier"), mIOService(ioService) {}
1600 NS_IMETHOD Run() override { return mIOService->NotifyWakeup(); }
1602 private:
1603 virtual ~nsWakeupNotifier() = default;
1604 nsCOMPtr<nsIIOServiceInternal> mIOService;
1607 NS_IMETHODIMP
1608 nsIOService::NotifyWakeup() {
1609 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
1611 NS_ASSERTION(observerService, "The observer service should not be null");
1613 if (observerService && StaticPrefs::network_notify_changed()) {
1614 (void)observerService->NotifyObservers(nullptr, NS_NETWORK_LINK_TOPIC,
1615 (u"" NS_NETWORK_LINK_DATA_CHANGED));
1618 RecheckCaptivePortal();
1620 return NS_OK;
1623 void nsIOService::SetHttpHandlerAlreadyShutingDown() {
1624 if (!mShutdown && !mOfflineForProfileChange) {
1625 mNetTearingDownStarted = PR_IntervalNow();
1626 mHttpHandlerAlreadyShutingDown = true;
1630 // nsIObserver interface
1631 NS_IMETHODIMP
1632 nsIOService::Observe(nsISupports* subject, const char* topic,
1633 const char16_t* data) {
1634 if (UseSocketProcess() && SocketProcessReady() &&
1635 mObserverTopicForSocketProcess.Contains(nsDependentCString(topic))) {
1636 nsCString topicStr(topic);
1637 nsString dataStr(data);
1638 Unused << mSocketProcess->GetActor()->SendNotifyObserver(topicStr, dataStr);
1641 if (!strcmp(topic, kProfileChangeNetTeardownTopic)) {
1642 if (!mHttpHandlerAlreadyShutingDown) {
1643 mNetTearingDownStarted = PR_IntervalNow();
1645 mHttpHandlerAlreadyShutingDown = false;
1646 if (!mOffline) {
1647 mOfflineForProfileChange = true;
1648 SetOfflineInternal(true, false);
1650 } else if (!strcmp(topic, kProfileChangeNetRestoreTopic)) {
1651 if (mOfflineForProfileChange) {
1652 mOfflineForProfileChange = false;
1653 SetOfflineInternal(false, false);
1655 } else if (!strcmp(topic, kProfileDoChange)) {
1656 if (data && u"startup"_ns.Equals(data)) {
1657 // Lazy initialization of network link service (see bug 620472)
1658 InitializeNetworkLinkService();
1659 // Set up the initilization flag regardless the actuall result.
1660 // If we fail here, we will fail always on.
1661 mNetworkLinkServiceInitialized = true;
1663 // And now reflect the preference setting
1664 PrefsChanged(MANAGE_OFFLINE_STATUS_PREF);
1666 // Bug 870460 - Read cookie database at an early-as-possible time
1667 // off main thread. Hence, we have more chance to finish db query
1668 // before something calls into the cookie service.
1669 nsCOMPtr<nsISupports> cookieServ =
1670 do_GetService(NS_COOKIESERVICE_CONTRACTID);
1672 } else if (!strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
1673 // Remember we passed XPCOM shutdown notification to prevent any
1674 // changes of the offline status from now. We must not allow going
1675 // online after this point.
1676 mShutdown = true;
1678 if (!mHttpHandlerAlreadyShutingDown && !mOfflineForProfileChange) {
1679 mNetTearingDownStarted = PR_IntervalNow();
1681 mHttpHandlerAlreadyShutingDown = false;
1683 SetOfflineInternal(true, false);
1685 if (mCaptivePortalService) {
1686 static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Stop();
1687 mCaptivePortalService = nullptr;
1690 SSLTokensCache::Shutdown();
1692 DestroySocketProcess();
1694 if (IsSocketProcessChild()) {
1695 Preferences::UnregisterCallbacks(nsIOService::OnTLSPrefChange,
1696 gCallbackSecurityPrefs, this);
1697 PrepareForShutdownInSocketProcess();
1700 // We're in XPCOM shutdown now. Unregister any dynamic protocol handlers
1701 // after this point to avoid leaks.
1703 AutoWriteLock lock(mLock);
1704 mRuntimeProtocolHandlers.Clear();
1706 } else if (!strcmp(topic, NS_NETWORK_LINK_TOPIC)) {
1707 OnNetworkLinkEvent(NS_ConvertUTF16toUTF8(data).get());
1708 } else if (!strcmp(topic, NS_NETWORK_ID_CHANGED_TOPIC)) {
1709 LOG(("nsIOService::OnNetworkLinkEvent Network id changed"));
1710 } else if (!strcmp(topic, NS_WIDGET_WAKE_OBSERVER_TOPIC)) {
1711 // coming back alive from sleep
1712 // this indirection brought to you by:
1713 // https://bugzilla.mozilla.org/show_bug.cgi?id=1152048#c19
1714 nsCOMPtr<nsIRunnable> wakeupNotifier = new nsWakeupNotifier(this);
1715 NS_DispatchToMainThread(wakeupNotifier);
1718 return NS_OK;
1721 // nsINetUtil interface
1722 NS_IMETHODIMP
1723 nsIOService::ParseRequestContentType(const nsACString& aTypeHeader,
1724 nsACString& aCharset, bool* aHadCharset,
1725 nsACString& aContentType) {
1726 net_ParseRequestContentType(aTypeHeader, aContentType, aCharset, aHadCharset);
1727 return NS_OK;
1730 // nsINetUtil interface
1731 NS_IMETHODIMP
1732 nsIOService::ParseResponseContentType(const nsACString& aTypeHeader,
1733 nsACString& aCharset, bool* aHadCharset,
1734 nsACString& aContentType) {
1735 net_ParseContentType(aTypeHeader, aContentType, aCharset, aHadCharset);
1736 return NS_OK;
1739 NS_IMETHODIMP
1740 nsIOService::ProtocolHasFlags(nsIURI* uri, uint32_t flags, bool* result) {
1741 NS_ENSURE_ARG(uri);
1743 *result = false;
1744 nsAutoCString scheme;
1745 nsresult rv = uri->GetScheme(scheme);
1746 NS_ENSURE_SUCCESS(rv, rv);
1748 auto handler = LookupProtocolHandler(scheme);
1750 uint32_t protocolFlags;
1751 if (flags & nsIProtocolHandler::DYNAMIC_URI_FLAGS) {
1752 AssertIsOnMainThread();
1753 rv = handler.DynamicProtocolFlags(uri, &protocolFlags);
1754 NS_ENSURE_SUCCESS(rv, rv);
1755 } else {
1756 protocolFlags = handler.StaticProtocolFlags();
1759 *result = (protocolFlags & flags) == flags;
1760 return NS_OK;
1763 NS_IMETHODIMP
1764 nsIOService::URIChainHasFlags(nsIURI* uri, uint32_t flags, bool* result) {
1765 nsresult rv = ProtocolHasFlags(uri, flags, result);
1766 NS_ENSURE_SUCCESS(rv, rv);
1768 if (*result) {
1769 return rv;
1772 // Dig deeper into the chain. Note that this is not a do/while loop to
1773 // avoid the extra addref/release on |uri| in the common (non-nested) case.
1774 nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(uri);
1775 while (nestedURI) {
1776 nsCOMPtr<nsIURI> innerURI;
1777 rv = nestedURI->GetInnerURI(getter_AddRefs(innerURI));
1778 NS_ENSURE_SUCCESS(rv, rv);
1780 rv = ProtocolHasFlags(innerURI, flags, result);
1782 if (*result) {
1783 return rv;
1786 nestedURI = do_QueryInterface(innerURI);
1789 return rv;
1792 NS_IMETHODIMP
1793 nsIOService::SetManageOfflineStatus(bool aManage) {
1794 LOG(("nsIOService::SetManageOfflineStatus aManage=%d\n", aManage));
1795 mManageLinkStatus = aManage;
1797 // When detection is not activated, the default connectivity state is true.
1798 if (!mManageLinkStatus) {
1799 SetConnectivityInternal(true);
1800 return NS_OK;
1803 InitializeNetworkLinkService();
1804 // If the NetworkLinkService is already initialized, it does not call
1805 // OnNetworkLinkEvent. This is needed, when mManageLinkStatus goes from
1806 // false to true.
1807 OnNetworkLinkEvent(NS_NETWORK_LINK_DATA_UNKNOWN);
1808 return NS_OK;
1811 NS_IMETHODIMP
1812 nsIOService::GetManageOfflineStatus(bool* aManage) {
1813 *aManage = mManageLinkStatus;
1814 return NS_OK;
1817 // input argument 'data' is already UTF8'ed
1818 nsresult nsIOService::OnNetworkLinkEvent(const char* data) {
1819 if (IsNeckoChild() || IsSocketProcessChild()) {
1820 // There is nothing IO service could do on the child process
1821 // with this at the moment. Feel free to add functionality
1822 // here at will, though.
1823 return NS_OK;
1826 if (mShutdown) {
1827 return NS_ERROR_NOT_AVAILABLE;
1830 nsCString dataAsString(data);
1831 for (auto* cp : mozilla::dom::ContentParent::AllProcesses(
1832 mozilla::dom::ContentParent::eLive)) {
1833 PNeckoParent* neckoParent = SingleManagedOrNull(cp->ManagedPNeckoParent());
1834 if (!neckoParent) {
1835 continue;
1837 Unused << neckoParent->SendNetworkChangeNotification(dataAsString);
1840 LOG(("nsIOService::OnNetworkLinkEvent data:%s\n", data));
1841 if (!mNetworkLinkService) {
1842 return NS_ERROR_FAILURE;
1845 if (!mManageLinkStatus) {
1846 LOG(("nsIOService::OnNetworkLinkEvent mManageLinkStatus=false\n"));
1847 return NS_OK;
1850 bool isUp = true;
1851 if (!strcmp(data, NS_NETWORK_LINK_DATA_CHANGED)) {
1852 mLastNetworkLinkChange = PR_IntervalNow();
1853 // CHANGED means UP/DOWN didn't change
1854 // but the status of the captive portal may have changed.
1855 RecheckCaptivePortal();
1856 return NS_OK;
1858 if (!strcmp(data, NS_NETWORK_LINK_DATA_DOWN)) {
1859 isUp = false;
1860 } else if (!strcmp(data, NS_NETWORK_LINK_DATA_UP)) {
1861 isUp = true;
1862 } else if (!strcmp(data, NS_NETWORK_LINK_DATA_UNKNOWN)) {
1863 nsresult rv = mNetworkLinkService->GetIsLinkUp(&isUp);
1864 NS_ENSURE_SUCCESS(rv, rv);
1865 } else {
1866 NS_WARNING("Unhandled network event!");
1867 return NS_OK;
1870 return SetConnectivityInternal(isUp);
1873 NS_IMETHODIMP
1874 nsIOService::EscapeString(const nsACString& aString, uint32_t aEscapeType,
1875 nsACString& aResult) {
1876 NS_ENSURE_ARG_MAX(aEscapeType, 4);
1878 nsAutoCString stringCopy(aString);
1879 nsCString result;
1881 if (!NS_Escape(stringCopy, result, (nsEscapeMask)aEscapeType)) {
1882 return NS_ERROR_OUT_OF_MEMORY;
1885 aResult.Assign(result);
1887 return NS_OK;
1890 NS_IMETHODIMP
1891 nsIOService::EscapeURL(const nsACString& aStr, uint32_t aFlags,
1892 nsACString& aResult) {
1893 aResult.Truncate();
1894 NS_EscapeURL(aStr.BeginReading(), aStr.Length(), aFlags | esc_AlwaysCopy,
1895 aResult);
1896 return NS_OK;
1899 NS_IMETHODIMP
1900 nsIOService::UnescapeString(const nsACString& aStr, uint32_t aFlags,
1901 nsACString& aResult) {
1902 aResult.Truncate();
1903 NS_UnescapeURL(aStr.BeginReading(), aStr.Length(), aFlags | esc_AlwaysCopy,
1904 aResult);
1905 return NS_OK;
1908 NS_IMETHODIMP
1909 nsIOService::ExtractCharsetFromContentType(const nsACString& aTypeHeader,
1910 nsACString& aCharset,
1911 int32_t* aCharsetStart,
1912 int32_t* aCharsetEnd,
1913 bool* aHadCharset) {
1914 nsAutoCString ignored;
1915 net_ParseContentType(aTypeHeader, ignored, aCharset, aHadCharset,
1916 aCharsetStart, aCharsetEnd);
1917 if (*aHadCharset && *aCharsetStart == *aCharsetEnd) {
1918 *aHadCharset = false;
1920 return NS_OK;
1923 // nsISpeculativeConnect
1924 class IOServiceProxyCallback final : public nsIProtocolProxyCallback {
1925 ~IOServiceProxyCallback() = default;
1927 public:
1928 NS_DECL_ISUPPORTS
1929 NS_DECL_NSIPROTOCOLPROXYCALLBACK
1931 IOServiceProxyCallback(nsIInterfaceRequestor* aCallbacks,
1932 nsIOService* aIOService,
1933 Maybe<OriginAttributes>&& aOriginAttributes)
1934 : mCallbacks(aCallbacks),
1935 mIOService(aIOService),
1936 mOriginAttributes(std::move(aOriginAttributes)) {}
1938 private:
1939 RefPtr<nsIInterfaceRequestor> mCallbacks;
1940 RefPtr<nsIOService> mIOService;
1941 Maybe<OriginAttributes> mOriginAttributes;
1944 NS_IMPL_ISUPPORTS(IOServiceProxyCallback, nsIProtocolProxyCallback)
1946 NS_IMETHODIMP
1947 IOServiceProxyCallback::OnProxyAvailable(nsICancelable* request,
1948 nsIChannel* channel, nsIProxyInfo* pi,
1949 nsresult status) {
1950 // Checking proxy status for speculative connect
1951 nsAutoCString type;
1952 if (NS_SUCCEEDED(status) && pi && NS_SUCCEEDED(pi->GetType(type)) &&
1953 !type.EqualsLiteral("direct")) {
1954 // proxies dont do speculative connect
1955 return NS_OK;
1958 nsCOMPtr<nsIURI> uri;
1959 nsresult rv = channel->GetURI(getter_AddRefs(uri));
1960 if (NS_FAILED(rv)) {
1961 return NS_OK;
1964 nsAutoCString scheme;
1965 rv = uri->GetScheme(scheme);
1966 if (NS_FAILED(rv)) return NS_OK;
1968 nsCOMPtr<nsIProtocolHandler> handler;
1969 rv = mIOService->GetProtocolHandler(scheme.get(), getter_AddRefs(handler));
1970 if (NS_FAILED(rv)) return NS_OK;
1972 nsCOMPtr<nsISpeculativeConnect> speculativeHandler =
1973 do_QueryInterface(handler);
1974 if (!speculativeHandler) return NS_OK;
1976 nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
1977 nsCOMPtr<nsIPrincipal> principal = loadInfo->GetLoadingPrincipal();
1979 nsLoadFlags loadFlags = 0;
1980 channel->GetLoadFlags(&loadFlags);
1981 bool anonymous = !!(loadFlags & nsIRequest::LOAD_ANONYMOUS);
1982 if (mOriginAttributes) {
1983 speculativeHandler->SpeculativeConnectWithOriginAttributesNative(
1984 uri, std::move(mOriginAttributes.ref()), mCallbacks, anonymous);
1985 } else {
1986 speculativeHandler->SpeculativeConnect(uri, principal, mCallbacks,
1987 anonymous);
1990 return NS_OK;
1993 nsresult nsIOService::SpeculativeConnectInternal(
1994 nsIURI* aURI, nsIPrincipal* aPrincipal,
1995 Maybe<OriginAttributes>&& aOriginAttributes,
1996 nsIInterfaceRequestor* aCallbacks, bool aAnonymous) {
1997 NS_ENSURE_ARG(aURI);
1999 if (!aURI->SchemeIs("http") && !aURI->SchemeIs("https")) {
2000 // We don't speculatively connect to non-HTTP[S] URIs.
2001 return NS_OK;
2004 if (IsNeckoChild()) {
2005 gNeckoChild->SendSpeculativeConnect(
2006 aURI, aPrincipal, std::move(aOriginAttributes), aAnonymous);
2007 return NS_OK;
2010 // Check for proxy information. If there is a proxy configured then a
2011 // speculative connect should not be performed because the potential
2012 // reward is slim with tcp peers closely located to the browser.
2013 nsresult rv;
2014 nsCOMPtr<nsIProtocolProxyService> pps =
2015 do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv);
2016 NS_ENSURE_SUCCESS(rv, rv);
2018 nsCOMPtr<nsIPrincipal> loadingPrincipal = aPrincipal;
2020 MOZ_ASSERT(aPrincipal || aOriginAttributes,
2021 "We expect passing a principal or OriginAttributes here.");
2023 if (!aPrincipal && !aOriginAttributes) {
2024 return NS_ERROR_INVALID_ARG;
2027 if (aOriginAttributes) {
2028 loadingPrincipal =
2029 BasePrincipal::CreateContentPrincipal(aURI, aOriginAttributes.ref());
2032 // XXX Bug 1724080: Avoid TCP connections on port 80 when https-only
2033 // or https-first is enabled. Let's create a dummy loadinfo which we
2034 // only use to determine whether we need ot upgrade the speculative
2035 // connection from http to https.
2036 nsCOMPtr<nsIURI> httpsURI;
2037 if (aURI->SchemeIs("http")) {
2038 nsCOMPtr<nsILoadInfo> httpsOnlyCheckLoadInfo =
2039 new LoadInfo(loadingPrincipal, loadingPrincipal, nullptr,
2040 nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK,
2041 nsIContentPolicy::TYPE_SPECULATIVE);
2043 // Check if https-only, or https-first would upgrade the request
2044 if (nsHTTPSOnlyUtils::ShouldUpgradeRequest(aURI, httpsOnlyCheckLoadInfo) ||
2045 nsHTTPSOnlyUtils::ShouldUpgradeHttpsFirstRequest(
2046 aURI, httpsOnlyCheckLoadInfo)) {
2047 rv = NS_GetSecureUpgradedURI(aURI, getter_AddRefs(httpsURI));
2048 NS_ENSURE_SUCCESS(rv, rv);
2049 aURI = httpsURI.get();
2053 // dummy channel used to create a TCP connection.
2054 // we perform security checks on the *real* channel, responsible
2055 // for any network loads. this real channel just checks the TCP
2056 // pool if there is an available connection created by the
2057 // channel we create underneath - hence it's safe to use
2058 // the systemPrincipal as the loadingPrincipal for this channel.
2059 nsCOMPtr<nsIChannel> channel;
2060 rv = NewChannelFromURI(
2061 aURI,
2062 nullptr, // aLoadingNode,
2063 loadingPrincipal,
2064 nullptr, // aTriggeringPrincipal,
2065 nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
2066 nsIContentPolicy::TYPE_SPECULATIVE, getter_AddRefs(channel));
2067 NS_ENSURE_SUCCESS(rv, rv);
2069 if (aAnonymous) {
2070 nsLoadFlags loadFlags = 0;
2071 channel->GetLoadFlags(&loadFlags);
2072 loadFlags |= nsIRequest::LOAD_ANONYMOUS;
2073 channel->SetLoadFlags(loadFlags);
2076 nsCOMPtr<nsICancelable> cancelable;
2077 RefPtr<IOServiceProxyCallback> callback = new IOServiceProxyCallback(
2078 aCallbacks, this, std::move(aOriginAttributes));
2079 nsCOMPtr<nsIProtocolProxyService2> pps2 = do_QueryInterface(pps);
2080 if (pps2) {
2081 return pps2->AsyncResolve2(channel, 0, callback, nullptr,
2082 getter_AddRefs(cancelable));
2084 return pps->AsyncResolve(channel, 0, callback, nullptr,
2085 getter_AddRefs(cancelable));
2088 NS_IMETHODIMP
2089 nsIOService::SpeculativeConnect(nsIURI* aURI, nsIPrincipal* aPrincipal,
2090 nsIInterfaceRequestor* aCallbacks,
2091 bool aAnonymous) {
2092 return SpeculativeConnectInternal(aURI, aPrincipal, Nothing(), aCallbacks,
2093 aAnonymous);
2096 NS_IMETHODIMP nsIOService::SpeculativeConnectWithOriginAttributes(
2097 nsIURI* aURI, JS::Handle<JS::Value> aOriginAttributes,
2098 nsIInterfaceRequestor* aCallbacks, bool aAnonymous, JSContext* aCx) {
2099 OriginAttributes attrs;
2100 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
2101 return NS_ERROR_INVALID_ARG;
2104 SpeculativeConnectWithOriginAttributesNative(aURI, std::move(attrs),
2105 aCallbacks, aAnonymous);
2106 return NS_OK;
2109 NS_IMETHODIMP_(void)
2110 nsIOService::SpeculativeConnectWithOriginAttributesNative(
2111 nsIURI* aURI, OriginAttributes&& aOriginAttributes,
2112 nsIInterfaceRequestor* aCallbacks, bool aAnonymous) {
2113 Maybe<OriginAttributes> originAttributes;
2114 originAttributes.emplace(aOriginAttributes);
2115 Unused << SpeculativeConnectInternal(
2116 aURI, nullptr, std::move(originAttributes), aCallbacks, aAnonymous);
2119 NS_IMETHODIMP
2120 nsIOService::NotImplemented() { return NS_ERROR_NOT_IMPLEMENTED; }
2122 NS_IMETHODIMP
2123 nsIOService::GetSocketProcessLaunched(bool* aResult) {
2124 NS_ENSURE_ARG_POINTER(aResult);
2126 *aResult = SocketProcessReady();
2127 return NS_OK;
2130 bool nsIOService::HasObservers(const char* aTopic) {
2131 MOZ_ASSERT(false, "Calling this method is unexpected");
2132 return false;
2135 NS_IMETHODIMP
2136 nsIOService::GetSocketProcessId(uint64_t* aPid) {
2137 NS_ENSURE_ARG_POINTER(aPid);
2139 *aPid = 0;
2140 if (!mSocketProcess) {
2141 return NS_OK;
2144 if (SocketProcessParent* actor = mSocketProcess->GetActor()) {
2145 *aPid = (uint64_t)actor->OtherPid();
2148 return NS_OK;
2151 NS_IMETHODIMP
2152 nsIOService::RegisterProtocolHandler(const nsACString& aScheme,
2153 nsIProtocolHandler* aHandler,
2154 uint32_t aProtocolFlags,
2155 int32_t aDefaultPort) {
2156 if (mShutdown) {
2157 return NS_ERROR_NOT_AVAILABLE;
2159 if (aScheme.IsEmpty()) {
2160 return NS_ERROR_INVALID_ARG;
2163 nsAutoCString scheme(aScheme);
2164 ToLowerCase(scheme);
2166 AutoWriteLock lock(mLock);
2167 return mRuntimeProtocolHandlers.WithEntryHandle(scheme, [&](auto&& entry) {
2168 if (entry) {
2169 NS_WARNING("Cannot override an existing dynamic protocol handler");
2170 return NS_ERROR_FACTORY_EXISTS;
2172 if (xpcom::StaticProtocolHandler::Lookup(scheme)) {
2173 NS_WARNING("Cannot override an existing static protocol handler");
2174 return NS_ERROR_FACTORY_EXISTS;
2176 nsMainThreadPtrHandle<nsIProtocolHandler> handler(
2177 new nsMainThreadPtrHolder<nsIProtocolHandler>("RuntimeProtocolHandler",
2178 aHandler));
2179 entry.Insert(RuntimeProtocolHandler{
2180 .mHandler = std::move(handler),
2181 .mProtocolFlags = aProtocolFlags,
2182 .mDefaultPort = aDefaultPort,
2184 return NS_OK;
2188 NS_IMETHODIMP
2189 nsIOService::UnregisterProtocolHandler(const nsACString& aScheme) {
2190 if (mShutdown) {
2191 return NS_OK;
2193 if (aScheme.IsEmpty()) {
2194 return NS_ERROR_INVALID_ARG;
2197 nsAutoCString scheme(aScheme);
2198 ToLowerCase(scheme);
2200 AutoWriteLock lock(mLock);
2201 return mRuntimeProtocolHandlers.Remove(scheme)
2202 ? NS_OK
2203 : NS_ERROR_FACTORY_NOT_REGISTERED;
2206 } // namespace net
2207 } // namespace mozilla