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"
16 #include "nsIObserverService.h"
18 #include "nsIProxiedProtocolHandler.h"
19 #include "nsIProxyInfo.h"
20 #include "nsDNSService2.h"
22 #include "nsNetUtil.h"
25 #include "nsSimpleNestedURI.h"
26 #include "nsSocketTransport2.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"
39 #include "nsIWebTransport.h"
40 #include "nsIWidget.h"
41 #include "nsThreadUtils.h"
42 #include "WebTransportSessionProxy.h"
43 #include "mozilla/AppShutdown.h"
44 #include "mozilla/Components.h"
45 #include "mozilla/LoadInfo.h"
46 #include "mozilla/net/NeckoCommon.h"
47 #include "mozilla/Services.h"
48 #include "mozilla/Telemetry.h"
49 #include "mozilla/net/DNS.h"
50 #include "mozilla/ipc/URIUtils.h"
51 #include "mozilla/net/NeckoChild.h"
52 #include "mozilla/net/NeckoParent.h"
53 #include "mozilla/dom/ClientInfo.h"
54 #include "mozilla/dom/ContentParent.h"
55 #include "mozilla/dom/nsHTTPSOnlyUtils.h"
56 #include "mozilla/dom/ServiceWorkerDescriptor.h"
57 #include "mozilla/net/CaptivePortalService.h"
58 #include "mozilla/net/NetworkConnectivityService.h"
59 #include "mozilla/net/SocketProcessHost.h"
60 #include "mozilla/net/SocketProcessParent.h"
61 #include "mozilla/net/SSLTokensCache.h"
62 #include "mozilla/StoragePrincipalHelper.h"
63 #include "mozilla/Unused.h"
64 #include "nsContentSecurityManager.h"
65 #include "nsContentUtils.h"
66 #include "mozilla/StaticPrefs_network.h"
67 #include "mozilla/StaticPrefs_security.h"
68 #include "mozilla/glean/NetwerkMetrics.h"
69 #include "nsNSSComponent.h"
70 #include "IPv4Parser.h"
72 #include "StaticComponents.h"
74 #ifdef MOZ_WIDGET_ANDROID
76 # include "AndroidBridge.h"
77 # include "mozilla/java/GeckoAppShellWrappers.h"
78 # include "mozilla/jni/Utils.h"
85 using mozilla::dom::ClientInfo
;
86 using mozilla::dom::ServiceWorkerDescriptor
;
88 #define PORT_PREF_PREFIX "network.security.ports."
89 #define PORT_PREF(x) PORT_PREF_PREFIX x
90 #define MANAGE_OFFLINE_STATUS_PREF "network.manage-offline-status"
92 // Nb: these have been misnomers since bug 715770 removed the buffer cache.
93 // "network.segment.count" and "network.segment.size" would be better names,
94 // but the old names are still used to preserve backward compatibility.
95 #define NECKO_BUFFER_CACHE_COUNT_PREF "network.buffer.cache.count"
96 #define NECKO_BUFFER_CACHE_SIZE_PREF "network.buffer.cache.size"
97 #define NETWORK_CAPTIVE_PORTAL_PREF "network.captive-portal-service.enabled"
98 #define WEBRTC_PREF_PREFIX "media.peerconnection."
99 #define NETWORK_DNS_PREF "network.dns."
100 #define FORCE_EXTERNAL_PREF_PREFIX "network.protocol-handler.external."
102 nsIOService
* gIOService
;
103 static bool gHasWarnedUploadChannel2
;
104 static bool gCaptivePortalEnabled
= false;
105 static LazyLogModule
gIOServiceLog("nsIOService");
107 #define LOG(args) MOZ_LOG(gIOServiceLog, LogLevel::Debug, args)
109 // A general port blacklist. Connections to these ports will not be allowed
110 // unless the protocol overrides.
112 // This list is to be kept in sync with "bad ports" as defined in the
113 // WHATWG Fetch standard at <https://fetch.spec.whatwg.org/#port-blocking>
115 int16_t gBadPortList
[] = {
150 135, // loc-srv / epmap
157 427, // afp (alternate)
158 465, // smtp (alternate)
172 587, // smtp (outgoing)
179 1719, // h323gatestat
180 1720, // h323hostcall
190 6665, // irc (alternate)
191 6666, // irc (alternate)
192 6667, // irc (default)
193 6668, // irc (alternate)
194 6669, // irc (alternate)
198 0, // Sentinel value: This MUST be zero
201 static const char kProfileChangeNetTeardownTopic
[] =
202 "profile-change-net-teardown";
203 static const char kProfileChangeNetRestoreTopic
[] =
204 "profile-change-net-restore";
205 static const char kProfileDoChange
[] = "profile-do-change";
207 // Necko buffer defaults
208 uint32_t nsIOService::gDefaultSegmentSize
= 4096;
209 uint32_t nsIOService::gDefaultSegmentCount
= 24;
211 uint32_t nsIOService::sSocketProcessCrashedCount
= 0;
213 ////////////////////////////////////////////////////////////////////////////////
215 nsIOService::nsIOService()
216 : mLastOfflineStateChange(PR_IntervalNow()),
217 mLastConnectivityChange(PR_IntervalNow()),
218 mLastNetworkLinkChange(PR_IntervalNow()) {}
220 static const char* gCallbackPrefs
[] = {
222 MANAGE_OFFLINE_STATUS_PREF
,
223 NECKO_BUFFER_CACHE_COUNT_PREF
,
224 NECKO_BUFFER_CACHE_SIZE_PREF
,
225 NETWORK_CAPTIVE_PORTAL_PREF
,
226 FORCE_EXTERNAL_PREF_PREFIX
,
227 SIMPLE_URI_SCHEMES_PREF
,
231 static const char* gCallbackPrefsForSocketProcess
[] = {
234 "network.send_ODA_to_content_directly",
237 "network.dns.disableIPv6",
238 "network.offline-mirrors-connectivity",
239 "network.disable-localhost-when-offline",
240 "network.proxy.parse_pac_on_socket_process",
241 "network.proxy.allow_hijacking_localhost",
242 "network.connectivity-service.",
243 "network.captive-portal-service.testMode",
244 "network.socket.ip_addr_any.disabled",
245 "network.socket.attach_mock_network_layer",
249 static const char* gCallbackSecurityPrefs
[] = {
250 // Note the prefs listed below should be in sync with the code in
251 // HandleTLSPrefChange().
252 "security.tls.version.min",
253 "security.tls.version.max",
254 "security.tls.version.enable-deprecated",
255 "security.tls.hello_downgrade_check",
256 "security.ssl.require_safe_negotiation",
257 "security.ssl.enable_false_start",
258 "security.ssl.enable_alpn",
259 "security.tls.enable_0rtt_data",
260 "security.ssl.disable_session_identifiers",
261 "security.tls.enable_post_handshake_auth",
262 "security.tls.enable_delegated_credentials",
266 nsresult
nsIOService::Init() {
267 SSLTokensCache::Init();
269 InitializeCaptivePortalService();
271 // setup our bad port list stuff
272 for (int i
= 0; gBadPortList
[i
]; i
++) {
273 // We can't be accessed by another thread yet
274 MOZ_PUSH_IGNORE_THREAD_SAFETY
275 mRestrictedPortList
.AppendElement(gBadPortList
[i
]);
276 MOZ_POP_THREAD_SAFETY
279 // Further modifications to the port list come from prefs
280 Preferences::RegisterPrefixCallbacks(nsIOService::PrefsChanged
,
281 gCallbackPrefs
, this);
284 mSocketProcessTopicBlockedList
.Insert(
285 nsLiteralCString(NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID
));
286 mSocketProcessTopicBlockedList
.Insert(
287 nsLiteralCString(NS_XPCOM_SHUTDOWN_OBSERVER_ID
));
288 mSocketProcessTopicBlockedList
.Insert("xpcom-shutdown-threads"_ns
);
289 mSocketProcessTopicBlockedList
.Insert("profile-do-change"_ns
);
290 mSocketProcessTopicBlockedList
.Insert("network:socket-process-crashed"_ns
);
292 // Register for profile change notifications
293 mObserverService
= services::GetObserverService();
294 AddObserver(this, kProfileChangeNetTeardownTopic
, true);
295 AddObserver(this, kProfileChangeNetRestoreTopic
, true);
296 AddObserver(this, kProfileDoChange
, true);
297 AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID
, true);
298 AddObserver(this, NS_NETWORK_LINK_TOPIC
, true);
299 AddObserver(this, NS_NETWORK_ID_CHANGED_TOPIC
, true);
300 AddObserver(this, NS_WIDGET_WAKE_OBSERVER_TOPIC
, true);
302 // Register observers for sending notifications to nsSocketTransportService
303 if (XRE_IsParentProcess()) {
304 AddObserver(this, "profile-initial-state", true);
305 AddObserver(this, NS_WIDGET_SLEEP_OBSERVER_TOPIC
, true);
308 if (IsSocketProcessChild()) {
309 Preferences::RegisterCallbacks(nsIOService::OnTLSPrefChange
,
310 gCallbackSecurityPrefs
, this);
315 InitializeNetworkLinkService();
316 InitializeProtocolProxyService();
324 nsIOService::AddObserver(nsIObserver
* aObserver
, const char* aTopic
,
326 if (!mObserverService
) {
327 return NS_ERROR_FAILURE
;
330 // Register for the origional observer.
331 nsresult rv
= mObserverService
->AddObserver(aObserver
, aTopic
, aOwnsWeak
);
336 if (!XRE_IsParentProcess()) {
340 nsAutoCString
topic(aTopic
);
341 // This happens when AddObserver() is called by nsIOService::Init(). We don't
342 // want to add nsIOService again.
343 if (SameCOMIdentity(aObserver
, static_cast<nsIObserver
*>(this))) {
344 mIOServiceTopicList
.Insert(topic
);
348 if (!UseSocketProcess()) {
352 if (mSocketProcessTopicBlockedList
.Contains(topic
)) {
353 return NS_ERROR_FAILURE
;
356 // Avoid registering duplicate topics.
357 if (mObserverTopicForSocketProcess
.Contains(topic
)) {
358 return NS_ERROR_FAILURE
;
361 mObserverTopicForSocketProcess
.Insert(topic
);
363 // Avoid registering duplicate topics.
364 if (mIOServiceTopicList
.Contains(topic
)) {
365 return NS_ERROR_FAILURE
;
368 return mObserverService
->AddObserver(this, aTopic
, true);
372 nsIOService::RemoveObserver(nsIObserver
* aObserver
, const char* aTopic
) {
373 return NS_ERROR_NOT_IMPLEMENTED
;
377 nsIOService::EnumerateObservers(const char* aTopic
,
378 nsISimpleEnumerator
** anEnumerator
) {
379 return NS_ERROR_NOT_IMPLEMENTED
;
382 NS_IMETHODIMP
nsIOService::NotifyObservers(nsISupports
* aSubject
,
384 const char16_t
* aSomeData
) {
385 return NS_ERROR_NOT_IMPLEMENTED
;
388 nsIOService::~nsIOService() {
390 MOZ_ASSERT(gIOService
== this);
391 gIOService
= nullptr;
395 #ifdef MOZ_WIDGET_ANDROID
396 bool nsIOService::ShouldAddAdditionalSearchHeaders(nsIURI
* aURI
,
398 if (!(mozilla::AndroidBridge::Bridge())) {
402 if (!aURI
->SchemeIs("https")) {
406 // We need to improve below logic for matching google domains
408 // Is URI same as google ^https://www\\.google\\..+
411 LOG(("nsIOService::ShouldAddAdditionalSearchHeaders() checking host %s\n",
412 PromiseFlatCString(host
).get()));
414 std::regex
pattern("^www\\.google\\..+");
415 if (std::regex_match(host
.get(), pattern
)) {
416 LOG(("Google domain detected for host %s\n",
417 PromiseFlatCString(host
).get()));
418 static bool ramAboveThreshold
=
419 java::GeckoAppShell::IsDeviceRamThresholdOkay();
420 *aHeaderVal
= ramAboveThreshold
;
429 void nsIOService::OnTLSPrefChange(const char* aPref
, void* aSelf
) {
430 MOZ_ASSERT(IsSocketProcessChild());
432 if (!EnsureNSSInitializedChromeOrContent()) {
433 LOG(("NSS not initialized."));
437 nsAutoCString
pref(aPref
);
438 // The preferences listed in gCallbackSecurityPrefs need to be in sync with
439 // the code in HandleTLSPrefChange().
440 if (HandleTLSPrefChange(pref
)) {
441 LOG(("HandleTLSPrefChange done"));
445 nsresult
nsIOService::InitializeCaptivePortalService() {
446 if (XRE_GetProcessType() != GeckoProcessType_Default
) {
447 // We only initalize a captive portal service in the main process
451 mCaptivePortalService
= mozilla::components::CaptivePortal::Service();
452 if (mCaptivePortalService
) {
453 static_cast<CaptivePortalService
*>(mCaptivePortalService
.get())
457 // Instantiate and initialize the service
458 RefPtr
<NetworkConnectivityService
> ncs
=
459 NetworkConnectivityService::GetSingleton();
464 nsresult
nsIOService::InitializeSocketTransportService() {
467 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
469 ("nsIOService aborting InitializeSocketTransportService because of app "
471 return NS_ERROR_ILLEGAL_DURING_SHUTDOWN
;
474 if (!mSocketTransportService
) {
475 mSocketTransportService
=
476 mozilla::components::SocketTransport::Service(&rv
);
478 NS_WARNING("failed to get socket transport service");
482 if (mSocketTransportService
) {
483 rv
= mSocketTransportService
->Init();
484 NS_ASSERTION(NS_SUCCEEDED(rv
), "socket transport service init failed");
485 mSocketTransportService
->SetOffline(false);
491 nsresult
nsIOService::InitializeNetworkLinkService() {
494 if (mNetworkLinkServiceInitialized
) return rv
;
496 if (!NS_IsMainThread()) {
497 NS_WARNING("Network link service should be created on main thread");
498 return NS_ERROR_FAILURE
;
501 // go into managed mode if we can, and chrome process
502 if (!XRE_IsParentProcess()) {
503 return NS_ERROR_NOT_AVAILABLE
;
506 mNetworkLinkService
= do_GetService(NS_NETWORK_LINK_SERVICE_CONTRACTID
, &rv
);
508 if (mNetworkLinkService
) {
509 mNetworkLinkServiceInitialized
= true;
512 // After initializing the networkLinkService, query the connectivity state
513 OnNetworkLinkEvent(NS_NETWORK_LINK_DATA_UNKNOWN
);
518 nsresult
nsIOService::InitializeProtocolProxyService() {
521 if (XRE_IsParentProcess()) {
522 // for early-initialization
523 Unused
<< mozilla::components::ProtocolProxy::Service(&rv
);
529 already_AddRefed
<nsIOService
> nsIOService::GetInstance() {
531 RefPtr
<nsIOService
> ios
= new nsIOService();
532 if (NS_SUCCEEDED(ios
->Init())) {
533 MOZ_ASSERT(gIOService
== ios
.get());
537 return do_AddRef(gIOService
);
540 class SocketProcessListenerProxy
: public SocketProcessHost::Listener
{
542 SocketProcessListenerProxy() = default;
543 void OnProcessLaunchComplete(SocketProcessHost
* aHost
, bool aSucceeded
) {
548 gIOService
->OnProcessLaunchComplete(aHost
, aSucceeded
);
551 void OnProcessUnexpectedShutdown(SocketProcessHost
* aHost
) {
556 gIOService
->OnProcessUnexpectedShutdown(aHost
);
561 bool nsIOService::TooManySocketProcessCrash() {
562 return sSocketProcessCrashedCount
>=
563 StaticPrefs::network_max_socket_process_failed_count();
567 void nsIOService::IncreaseSocketProcessCrashCount() {
568 MOZ_ASSERT(IsNeckoChild());
569 sSocketProcessCrashedCount
++;
572 nsresult
nsIOService::LaunchSocketProcess() {
573 MOZ_ASSERT(NS_IsMainThread());
575 if (XRE_GetProcessType() != GeckoProcessType_Default
) {
579 // We shouldn't launch socket prcess when shutdown begins.
580 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
584 if (mSocketProcess
) {
588 if (PR_GetEnv("MOZ_DISABLE_SOCKET_PROCESS")) {
589 LOG(("nsIOService skipping LaunchSocketProcess because of the env"));
593 if (!StaticPrefs::network_process_enabled()) {
594 LOG(("nsIOService skipping LaunchSocketProcess because of the pref"));
598 Preferences::RegisterPrefixCallbacks(
599 nsIOService::NotifySocketProcessPrefsChanged
,
600 gCallbackPrefsForSocketProcess
, this);
602 // The subprocess is launched asynchronously, so we wait for a callback to
603 // acquire the IPDL actor.
604 mSocketProcess
= new SocketProcessHost(new SocketProcessListenerProxy());
605 LOG(("nsIOService::LaunchSocketProcess"));
606 if (!mSocketProcess
->Launch()) {
607 NS_WARNING("Failed to launch socket process!!");
608 DestroySocketProcess();
609 return NS_ERROR_FAILURE
;
615 void nsIOService::DestroySocketProcess() {
616 LOG(("nsIOService::DestroySocketProcess"));
617 MOZ_ASSERT(NS_IsMainThread());
619 if (XRE_GetProcessType() != GeckoProcessType_Default
|| !mSocketProcess
) {
623 Preferences::UnregisterPrefixCallbacks(
624 nsIOService::NotifySocketProcessPrefsChanged
,
625 gCallbackPrefsForSocketProcess
, this);
627 mSocketProcess
->Shutdown();
628 mSocketProcess
= nullptr;
631 bool nsIOService::SocketProcessReady() {
632 return mSocketProcess
&& mSocketProcess
->IsConnected();
635 static bool sUseSocketProcess
= false;
636 static bool sUseSocketProcessChecked
= false;
639 bool nsIOService::UseSocketProcess(bool aCheckAgain
) {
640 if (sUseSocketProcessChecked
&& !aCheckAgain
) {
641 return sUseSocketProcess
;
644 sUseSocketProcessChecked
= true;
645 sUseSocketProcess
= false;
647 if (PR_GetEnv("MOZ_DISABLE_SOCKET_PROCESS")) {
648 return sUseSocketProcess
;
651 if (TooManySocketProcessCrash()) {
652 LOG(("TooManySocketProcessCrash"));
653 return sUseSocketProcess
;
656 if (PR_GetEnv("MOZ_FORCE_USE_SOCKET_PROCESS")) {
657 sUseSocketProcess
= true;
658 return sUseSocketProcess
;
661 if (StaticPrefs::network_process_enabled()) {
663 StaticPrefs::network_http_network_access_on_socket_process_enabled();
665 return sUseSocketProcess
;
669 void nsIOService::NotifySocketProcessPrefsChanged(const char* aName
,
671 static_cast<nsIOService
*>(aSelf
)->NotifySocketProcessPrefsChanged(aName
);
674 void nsIOService::NotifySocketProcessPrefsChanged(const char* aName
) {
675 MOZ_ASSERT(NS_IsMainThread());
677 if (!XRE_IsParentProcess()) {
681 if (!StaticPrefs::network_process_enabled()) {
685 dom::Pref
pref(nsCString(aName
), /* isLocked */ false,
686 /* isSanitized */ false, Nothing(), Nothing());
688 Preferences::GetPreference(&pref
, GeckoProcessType_Socket
,
689 /* remoteType */ ""_ns
);
690 auto sendPrefUpdate
= [pref
]() {
691 Unused
<< gIOService
->mSocketProcess
->GetActor()->SendPreferenceUpdate(
694 CallOrWaitForSocketProcess(sendPrefUpdate
);
697 void nsIOService::OnProcessLaunchComplete(SocketProcessHost
* aHost
,
699 MOZ_ASSERT(NS_IsMainThread());
701 LOG(("nsIOService::OnProcessLaunchComplete aSucceeded=%d\n", aSucceeded
));
703 mSocketProcessLaunchComplete
= aSucceeded
;
705 if (mShutdown
|| !SocketProcessReady() || !aSucceeded
) {
706 mPendingEvents
.Clear();
710 if (!mPendingEvents
.IsEmpty()) {
711 nsTArray
<std::function
<void()>> pendingEvents
= std::move(mPendingEvents
);
712 for (auto& func
: pendingEvents
) {
718 void nsIOService::CallOrWaitForSocketProcess(
719 const std::function
<void()>& aFunc
) {
720 MOZ_ASSERT(NS_IsMainThread());
721 if (IsSocketProcessLaunchComplete() && SocketProcessReady()) {
724 mPendingEvents
.AppendElement(aFunc
); // infallible
725 LaunchSocketProcess();
729 int32_t nsIOService::SocketProcessPid() {
730 if (!mSocketProcess
) {
733 if (SocketProcessParent
* actor
= mSocketProcess
->GetActor()) {
734 return (int32_t)actor
->OtherPid();
739 bool nsIOService::IsSocketProcessLaunchComplete() {
740 MOZ_ASSERT(NS_IsMainThread());
741 return mSocketProcessLaunchComplete
;
744 void nsIOService::OnProcessUnexpectedShutdown(SocketProcessHost
* aHost
) {
745 MOZ_ASSERT(NS_IsMainThread());
747 LOG(("nsIOService::OnProcessUnexpectedShutdown\n"));
748 DestroySocketProcess();
749 mPendingEvents
.Clear();
751 // Nothing to do if socket process was not used before.
752 if (!UseSocketProcess()) {
756 sSocketProcessCrashedCount
++;
757 if (TooManySocketProcessCrash()) {
758 sUseSocketProcessChecked
= false;
759 DNSServiceWrapper::SwitchToBackupDNSService();
762 nsCOMPtr
<nsIObserverService
> observerService
= services::GetObserverService();
763 if (observerService
) {
764 (void)observerService
->NotifyObservers(
765 nullptr, "network:socket-process-crashed", nullptr);
768 // UseSocketProcess() could return false if we have too many crashes, so we
769 // should call it again.
770 if (UseSocketProcess()) {
771 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(
772 NewRunnableMethod("nsIOService::LaunchSocketProcess", this,
773 &nsIOService::LaunchSocketProcess
)));
777 RefPtr
<MemoryReportingProcess
> nsIOService::GetSocketProcessMemoryReporter() {
778 // Check the prefs here again, since we don't want to create
779 // SocketProcessMemoryReporter for some tests.
780 if (!StaticPrefs::network_process_enabled() || !SocketProcessReady()) {
784 return new SocketProcessMemoryReporter();
788 nsIOService::SocketProcessTelemetryPing() {
789 CallOrWaitForSocketProcess([]() {
790 Unused
<< gIOService
->mSocketProcess
->GetActor()
791 ->SendSocketProcessTelemetryPing();
796 NS_IMPL_ISUPPORTS(nsIOService
, nsIIOService
, nsINetUtil
, nsISpeculativeConnect
,
797 nsIObserver
, nsIIOServiceInternal
, nsISupportsWeakReference
,
800 ////////////////////////////////////////////////////////////////////////////////
802 nsresult
nsIOService::RecheckCaptivePortal() {
803 MOZ_ASSERT(NS_IsMainThread(), "Must be called on the main thread");
804 if (!mCaptivePortalService
) {
807 nsCOMPtr
<nsIRunnable
> task
= NewRunnableMethod(
808 "nsIOService::RecheckCaptivePortal", mCaptivePortalService
,
809 &nsICaptivePortalService::RecheckCaptivePortal
);
810 return NS_DispatchToMainThread(task
);
813 nsresult
nsIOService::RecheckCaptivePortalIfLocalRedirect(nsIChannel
* newChan
) {
816 if (!mCaptivePortalService
) {
820 nsCOMPtr
<nsIURI
> uri
;
821 rv
= newChan
->GetURI(getter_AddRefs(uri
));
827 rv
= uri
->GetHost(host
);
833 // If the redirect wasn't to an IP literal, so there's probably no need
834 // to trigger the captive portal detection right now. It can wait.
835 if (NS_SUCCEEDED(addr
.InitFromString(host
)) && addr
.IsIPAddrLocal()) {
836 RecheckCaptivePortal();
842 nsresult
nsIOService::AsyncOnChannelRedirect(
843 nsIChannel
* oldChan
, nsIChannel
* newChan
, uint32_t flags
,
844 nsAsyncRedirectVerifyHelper
* helper
) {
845 // If a redirect to a local network address occurs, then chances are we
846 // are in a captive portal, so we trigger a recheck.
847 RecheckCaptivePortalIfLocalRedirect(newChan
);
849 // This is silly. I wish there was a simpler way to get at the global
850 // reference of the contentSecurityManager. But it lives in the XPCOM
852 nsCOMPtr
<nsIChannelEventSink
> sink
;
853 sink
= mozilla::components::ContentSecurityManager::Service();
856 helper
->DelegateOnChannelRedirect(sink
, oldChan
, newChan
, flags
);
857 if (NS_FAILED(rv
)) return rv
;
860 // Finally, our category
861 nsCOMArray
<nsIChannelEventSink
> entries
;
862 mChannelEventSinks
.GetEntries(entries
);
863 int32_t len
= entries
.Count();
864 for (int32_t i
= 0; i
< len
; ++i
) {
866 helper
->DelegateOnChannelRedirect(entries
[i
], oldChan
, newChan
, flags
);
867 if (NS_FAILED(rv
)) return rv
;
870 nsCOMPtr
<nsIHttpChannel
> httpChan(do_QueryInterface(oldChan
));
872 // Collect the redirection from HTTP(S) only.
874 MOZ_ASSERT(NS_IsMainThread());
875 nsCOMPtr
<nsIURI
> newURI
;
876 newChan
->GetURI(getter_AddRefs(newURI
));
879 nsAutoCString scheme
;
880 newURI
->GetScheme(scheme
);
881 MOZ_ASSERT(!scheme
.IsEmpty());
883 if (oldChan
->IsDocument()) {
884 Telemetry::AccumulateCategoricalKeyed(
885 scheme
, Telemetry::LABELS_NETWORK_HTTP_REDIRECT_TO_SCHEME::topLevel
);
887 mozilla::glean::networking::http_redirect_to_scheme_top_level
.Get(scheme
)
891 Telemetry::AccumulateCategoricalKeyed(
893 Telemetry::LABELS_NETWORK_HTTP_REDIRECT_TO_SCHEME::subresource
);
895 mozilla::glean::networking::http_redirect_to_scheme_subresource
904 bool nsIOService::UsesExternalProtocolHandler(const nsACString
& aScheme
) {
905 if (aScheme
== "file"_ns
|| aScheme
== "chrome"_ns
||
906 aScheme
== "resource"_ns
) {
907 // Don't allow file:, chrome: or resource: URIs to be handled with
908 // nsExternalProtocolHandler, since internally we rely on being able to
909 // use and read from these URIs.
913 if (aScheme
== "place"_ns
|| aScheme
== "fake-favicon-uri"_ns
||
914 aScheme
== "favicon"_ns
|| aScheme
== "moz-nullprincipal"_ns
) {
915 // Force place: fake-favicon-uri: favicon: and moz-nullprincipal: URIs to be
916 // handled with nsExternalProtocolHandler, and not with a dynamically
917 // registered handler.
921 // If prefs configure the URI to be handled externally, do so.
922 for (const auto& scheme
: mForceExternalSchemes
) {
923 if (aScheme
== scheme
) {
930 ProtocolHandlerInfo
nsIOService::LookupProtocolHandler(
931 const nsACString
& aScheme
) {
932 // Look-ups are ASCII-case-insensitive, so lower-case the string before
934 nsAutoCString
scheme(aScheme
);
937 // NOTE: If we could get rid of mForceExternalSchemes (or prevent them from
938 // disabling static protocols), we could avoid locking mLock until we need to
939 // check `mRuntimeProtocolHandlers.
940 AutoReadLock
lock(mLock
);
941 if (!UsesExternalProtocolHandler(scheme
)) {
942 // Try the static protocol handler first - they cannot be overridden by
943 // dynamic protocols.
944 if (const xpcom::StaticProtocolHandler
* handler
=
945 xpcom::StaticProtocolHandler::Lookup(scheme
)) {
946 return ProtocolHandlerInfo(*handler
);
948 if (auto handler
= mRuntimeProtocolHandlers
.Lookup(scheme
)) {
949 return ProtocolHandlerInfo(handler
.Data());
952 return ProtocolHandlerInfo(xpcom::StaticProtocolHandler::Default());
956 nsIOService::GetProtocolHandler(const char* scheme
,
957 nsIProtocolHandler
** result
) {
958 AssertIsOnMainThread();
959 NS_ENSURE_ARG_POINTER(scheme
);
961 *result
= LookupProtocolHandler(nsDependentCString(scheme
)).Handler().take();
962 return *result
? NS_OK
: NS_ERROR_UNKNOWN_PROTOCOL
;
966 nsIOService::ExtractScheme(const nsACString
& inURI
, nsACString
& scheme
) {
967 return net_ExtractURLScheme(inURI
, scheme
);
971 nsIOService::HostnameIsLocalIPAddress(nsIURI
* aURI
, bool* aResult
) {
972 NS_ENSURE_ARG_POINTER(aURI
);
974 nsCOMPtr
<nsIURI
> innerURI
= NS_GetInnermostURI(aURI
);
975 NS_ENSURE_ARG_POINTER(innerURI
);
978 nsresult rv
= innerURI
->GetAsciiHost(host
);
986 if (NS_SUCCEEDED(addr
.InitFromString(host
)) && addr
.IsIPAddrLocal()) {
994 nsIOService::HostnameIsIPAddressAny(nsIURI
* aURI
, bool* aResult
) {
995 NS_ENSURE_ARG_POINTER(aURI
);
997 nsCOMPtr
<nsIURI
> innerURI
= NS_GetInnermostURI(aURI
);
998 NS_ENSURE_ARG_POINTER(innerURI
);
1001 nsresult rv
= innerURI
->GetAsciiHost(host
);
1002 if (NS_FAILED(rv
)) {
1009 if (NS_SUCCEEDED(addr
.InitFromString(host
)) && addr
.IsIPAddrAny()) {
1017 nsIOService::HostnameIsSharedIPAddress(nsIURI
* aURI
, bool* aResult
) {
1018 NS_ENSURE_ARG_POINTER(aURI
);
1020 nsCOMPtr
<nsIURI
> innerURI
= NS_GetInnermostURI(aURI
);
1021 NS_ENSURE_ARG_POINTER(innerURI
);
1024 nsresult rv
= innerURI
->GetAsciiHost(host
);
1025 if (NS_FAILED(rv
)) {
1032 if (NS_SUCCEEDED(addr
.InitFromString(host
)) && addr
.IsIPAddrShared()) {
1040 nsIOService::IsValidHostname(const nsACString
& inHostname
, bool* aResult
) {
1041 if (!net_IsValidDNSHost(inHostname
)) {
1046 // hostname ending with a "." delimited octet that is a number
1047 // must be IPv4 or IPv6 dual address
1048 nsAutoCString
host(inHostname
);
1049 if (IPv4Parser::EndsInANumber(host
)) {
1050 // ipv6 dual address; for example "::1.2.3.4"
1051 if (net_IsValidIPv6Addr(host
)) {
1056 nsAutoCString normalized
;
1057 nsresult rv
= IPv4Parser::NormalizeIPv4(host
, normalized
);
1058 if (NS_FAILED(rv
)) {
1068 nsIOService::GetProtocolFlags(const char* scheme
, uint32_t* flags
) {
1069 NS_ENSURE_ARG_POINTER(scheme
);
1072 LookupProtocolHandler(nsDependentCString(scheme
)).StaticProtocolFlags();
1077 nsIOService::GetDynamicProtocolFlags(nsIURI
* uri
, uint32_t* flags
) {
1078 AssertIsOnMainThread();
1081 nsAutoCString scheme
;
1082 nsresult rv
= uri
->GetScheme(scheme
);
1083 NS_ENSURE_SUCCESS(rv
, rv
);
1085 return LookupProtocolHandler(scheme
).DynamicProtocolFlags(uri
, flags
);
1089 nsIOService::GetDefaultPort(const char* scheme
, int32_t* defaultPort
) {
1090 NS_ENSURE_ARG_POINTER(scheme
);
1093 LookupProtocolHandler(nsDependentCString(scheme
)).DefaultPort();
1097 nsresult
nsIOService::NewURI(const nsACString
& aSpec
, const char* aCharset
,
1098 nsIURI
* aBaseURI
, nsIURI
** result
) {
1099 return NS_NewURI(result
, aSpec
, aCharset
, aBaseURI
);
1103 nsIOService::NewFileURI(nsIFile
* file
, nsIURI
** result
) {
1105 NS_ENSURE_ARG_POINTER(file
);
1107 nsCOMPtr
<nsIProtocolHandler
> handler
;
1109 rv
= GetProtocolHandler("file", getter_AddRefs(handler
));
1110 if (NS_FAILED(rv
)) return rv
;
1112 nsCOMPtr
<nsIFileProtocolHandler
> fileHandler(do_QueryInterface(handler
, &rv
));
1113 if (NS_FAILED(rv
)) return rv
;
1115 return fileHandler
->NewFileURI(file
, result
);
1119 already_AddRefed
<nsIURI
> nsIOService::CreateExposableURI(nsIURI
* aURI
) {
1120 MOZ_ASSERT(aURI
, "Must have a URI");
1121 nsCOMPtr
<nsIURI
> uri
= aURI
;
1123 if (NS_SUCCEEDED(aURI
->GetHasUserPass(&hasUserPass
)) && hasUserPass
) {
1124 DebugOnly
<nsresult
> rv
= NS_MutateURI(uri
).SetUserPass(""_ns
).Finalize(uri
);
1125 MOZ_ASSERT(NS_SUCCEEDED(rv
) && uri
, "Mutating URI should never fail");
1127 return uri
.forget();
1131 nsIOService::CreateExposableURI(nsIURI
* aURI
, nsIURI
** _result
) {
1132 NS_ENSURE_ARG_POINTER(aURI
);
1133 NS_ENSURE_ARG_POINTER(_result
);
1134 nsCOMPtr
<nsIURI
> exposableURI
= CreateExposableURI(aURI
);
1135 exposableURI
.forget(_result
);
1140 nsIOService::NewChannelFromURI(nsIURI
* aURI
, nsINode
* aLoadingNode
,
1141 nsIPrincipal
* aLoadingPrincipal
,
1142 nsIPrincipal
* aTriggeringPrincipal
,
1143 uint32_t aSecurityFlags
,
1144 nsContentPolicyType aContentPolicyType
,
1145 nsIChannel
** result
) {
1146 return NewChannelFromURIWithProxyFlags(aURI
,
1147 nullptr, // aProxyURI
1149 aLoadingNode
, aLoadingPrincipal
,
1150 aTriggeringPrincipal
, aSecurityFlags
,
1151 aContentPolicyType
, result
);
1153 nsresult
nsIOService::NewChannelFromURIWithClientAndController(
1154 nsIURI
* aURI
, nsINode
* aLoadingNode
, nsIPrincipal
* aLoadingPrincipal
,
1155 nsIPrincipal
* aTriggeringPrincipal
,
1156 const Maybe
<ClientInfo
>& aLoadingClientInfo
,
1157 const Maybe
<ServiceWorkerDescriptor
>& aController
, uint32_t aSecurityFlags
,
1158 nsContentPolicyType aContentPolicyType
, uint32_t aSandboxFlags
,
1159 nsIChannel
** aResult
) {
1160 return NewChannelFromURIWithProxyFlagsInternal(
1162 nullptr, // aProxyURI
1164 aLoadingNode
, aLoadingPrincipal
, aTriggeringPrincipal
, aLoadingClientInfo
,
1165 aController
, aSecurityFlags
, aContentPolicyType
, aSandboxFlags
, aResult
);
1169 nsIOService::NewChannelFromURIWithLoadInfo(nsIURI
* aURI
, nsILoadInfo
* aLoadInfo
,
1170 nsIChannel
** result
) {
1171 return NewChannelFromURIWithProxyFlagsInternal(aURI
,
1172 nullptr, // aProxyURI
1177 nsresult
nsIOService::NewChannelFromURIWithProxyFlagsInternal(
1178 nsIURI
* aURI
, nsIURI
* aProxyURI
, uint32_t aProxyFlags
,
1179 nsINode
* aLoadingNode
, nsIPrincipal
* aLoadingPrincipal
,
1180 nsIPrincipal
* aTriggeringPrincipal
,
1181 const Maybe
<ClientInfo
>& aLoadingClientInfo
,
1182 const Maybe
<ServiceWorkerDescriptor
>& aController
, uint32_t aSecurityFlags
,
1183 nsContentPolicyType aContentPolicyType
, uint32_t aSandboxFlags
,
1184 nsIChannel
** result
) {
1185 nsCOMPtr
<nsILoadInfo
> loadInfo
= new LoadInfo(
1186 aLoadingPrincipal
, aTriggeringPrincipal
, aLoadingNode
, aSecurityFlags
,
1187 aContentPolicyType
, aLoadingClientInfo
, aController
, aSandboxFlags
);
1188 return NewChannelFromURIWithProxyFlagsInternal(aURI
, aProxyURI
, aProxyFlags
,
1192 nsresult
nsIOService::NewChannelFromURIWithProxyFlagsInternal(
1193 nsIURI
* aURI
, nsIURI
* aProxyURI
, uint32_t aProxyFlags
,
1194 nsILoadInfo
* aLoadInfo
, nsIChannel
** result
) {
1196 NS_ENSURE_ARG_POINTER(aURI
);
1197 // all channel creations must provide a valid loadinfo
1198 MOZ_ASSERT(aLoadInfo
, "can not create channel without aLoadInfo");
1199 NS_ENSURE_ARG_POINTER(aLoadInfo
);
1201 nsAutoCString scheme
;
1202 rv
= aURI
->GetScheme(scheme
);
1203 if (NS_FAILED(rv
)) return rv
;
1205 nsCOMPtr
<nsIProtocolHandler
> handler
;
1206 rv
= GetProtocolHandler(scheme
.get(), getter_AddRefs(handler
));
1207 if (NS_FAILED(rv
)) return rv
;
1209 nsCOMPtr
<nsIChannel
> channel
;
1210 nsCOMPtr
<nsIProxiedProtocolHandler
> pph
= do_QueryInterface(handler
);
1212 rv
= pph
->NewProxiedChannel(aURI
, nullptr, aProxyFlags
, aProxyURI
,
1213 aLoadInfo
, getter_AddRefs(channel
));
1215 rv
= handler
->NewChannel(aURI
, aLoadInfo
, getter_AddRefs(channel
));
1217 if (NS_FAILED(rv
)) return rv
;
1219 // Make sure that all the individual protocolhandlers attach a loadInfo.
1220 nsCOMPtr
<nsILoadInfo
> loadInfo
= channel
->LoadInfo();
1221 if (aLoadInfo
!= loadInfo
) {
1222 MOZ_ASSERT(false, "newly created channel must have a loadinfo attached");
1223 return NS_ERROR_UNEXPECTED
;
1226 // If we're sandboxed, make sure to clear any owner the channel
1227 // might already have.
1228 if (loadInfo
->GetLoadingSandboxed()) {
1229 channel
->SetOwner(nullptr);
1232 // Some extensions override the http protocol handler and provide their own
1233 // implementation. The channels returned from that implementation doesn't
1234 // seem to always implement the nsIUploadChannel2 interface, presumably
1235 // because it's a new interface.
1236 // Eventually we should remove this and simply require that http channels
1237 // implement the new interface.
1239 if (!gHasWarnedUploadChannel2
&& scheme
.EqualsLiteral("http")) {
1240 nsCOMPtr
<nsIUploadChannel2
> uploadChannel2
= do_QueryInterface(channel
);
1241 if (!uploadChannel2
) {
1242 nsCOMPtr
<nsIConsoleService
> consoleService
;
1243 consoleService
= mozilla::components::Console::Service();
1244 if (consoleService
) {
1245 consoleService
->LogStringMessage(
1246 u
"Http channel implementation "
1247 "doesn't support nsIUploadChannel2. An extension has "
1248 "supplied a non-functional http protocol handler. This will "
1249 "break behavior and in future releases not work at all.");
1251 gHasWarnedUploadChannel2
= true;
1255 channel
.forget(result
);
1260 nsIOService::NewChannelFromURIWithProxyFlags(
1261 nsIURI
* aURI
, nsIURI
* aProxyURI
, uint32_t aProxyFlags
,
1262 nsINode
* aLoadingNode
, nsIPrincipal
* aLoadingPrincipal
,
1263 nsIPrincipal
* aTriggeringPrincipal
, uint32_t aSecurityFlags
,
1264 nsContentPolicyType aContentPolicyType
, nsIChannel
** result
) {
1265 return NewChannelFromURIWithProxyFlagsInternal(
1266 aURI
, aProxyURI
, aProxyFlags
, aLoadingNode
, aLoadingPrincipal
,
1267 aTriggeringPrincipal
, Maybe
<ClientInfo
>(),
1268 Maybe
<ServiceWorkerDescriptor
>(), aSecurityFlags
, aContentPolicyType
, 0,
1273 nsIOService::NewChannel(const nsACString
& aSpec
, const char* aCharset
,
1274 nsIURI
* aBaseURI
, nsINode
* aLoadingNode
,
1275 nsIPrincipal
* aLoadingPrincipal
,
1276 nsIPrincipal
* aTriggeringPrincipal
,
1277 uint32_t aSecurityFlags
,
1278 nsContentPolicyType aContentPolicyType
,
1279 nsIChannel
** result
) {
1281 nsCOMPtr
<nsIURI
> uri
;
1282 rv
= NewURI(aSpec
, aCharset
, aBaseURI
, getter_AddRefs(uri
));
1283 if (NS_FAILED(rv
)) return rv
;
1285 return NewChannelFromURI(uri
, aLoadingNode
, aLoadingPrincipal
,
1286 aTriggeringPrincipal
, aSecurityFlags
,
1287 aContentPolicyType
, result
);
1291 nsIOService::NewWebTransport(nsIWebTransport
** result
) {
1292 if (!XRE_IsParentProcess()) {
1293 return NS_ERROR_NOT_AVAILABLE
;
1296 nsCOMPtr
<nsIWebTransport
> webTransport
= new WebTransportSessionProxy();
1298 webTransport
.forget(result
);
1303 nsIOService::OriginAttributesForNetworkState(
1304 nsIChannel
* aChannel
, JSContext
* cx
, JS::MutableHandle
<JS::Value
> _retval
) {
1305 OriginAttributes attrs
;
1306 if (!StoragePrincipalHelper::GetOriginAttributesForNetworkState(aChannel
,
1308 return NS_ERROR_FAILURE
;
1311 if (NS_WARN_IF(!mozilla::dom::ToJSValue(cx
, attrs
, _retval
))) {
1312 return NS_ERROR_FAILURE
;
1318 bool nsIOService::IsLinkUp() {
1319 InitializeNetworkLinkService();
1321 if (!mNetworkLinkService
) {
1322 // We cannot decide, assume the link is up
1328 rv
= mNetworkLinkService
->GetIsLinkUp(&isLinkUp
);
1329 if (NS_FAILED(rv
)) {
1337 nsIOService::GetOffline(bool* offline
) {
1338 if (StaticPrefs::network_offline_mirrors_connectivity()) {
1339 *offline
= mOffline
|| !mConnectivity
;
1341 *offline
= mOffline
;
1347 nsIOService::SetOffline(bool offline
) { return SetOfflineInternal(offline
); }
1349 nsresult
nsIOService::SetOfflineInternal(bool offline
,
1350 bool notifySocketProcess
) {
1351 LOG(("nsIOService::SetOffline offline=%d\n", offline
));
1352 // When someone wants to go online (!offline) after we got XPCOM shutdown
1353 // throw ERROR_NOT_AVAILABLE to prevent return to online state.
1354 if ((mShutdown
|| mOfflineForProfileChange
) && !offline
) {
1355 return NS_ERROR_NOT_AVAILABLE
;
1358 // SetOffline() may re-enter while it's shutting down services.
1359 // If that happens, save the most recent value and it will be
1360 // processed when the first SetOffline() call is done bringing
1361 // down the service.
1362 mSetOfflineValue
= offline
;
1363 if (mSettingOffline
) {
1367 mSettingOffline
= true;
1369 nsCOMPtr
<nsIObserverService
> observerService
= services::GetObserverService();
1371 NS_ASSERTION(observerService
, "The observer service should not be null");
1373 if (XRE_IsParentProcess()) {
1374 if (observerService
) {
1375 (void)observerService
->NotifyObservers(nullptr,
1376 NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC
,
1377 offline
? u
"true" : u
"false");
1379 if (SocketProcessReady() && notifySocketProcess
) {
1380 Unused
<< mSocketProcess
->GetActor()->SendSetOffline(offline
);
1384 nsIIOService
* subject
= static_cast<nsIIOService
*>(this);
1385 while (mSetOfflineValue
!= mOffline
) {
1386 offline
= mSetOfflineValue
;
1388 if (offline
&& !mOffline
) {
1389 mOffline
= true; // indicate we're trying to shutdown
1391 // don't care if notifications fail
1392 if (observerService
) {
1393 observerService
->NotifyObservers(subject
,
1394 NS_IOSERVICE_GOING_OFFLINE_TOPIC
,
1395 u
"" NS_IOSERVICE_OFFLINE
);
1398 if (mSocketTransportService
) mSocketTransportService
->SetOffline(true);
1400 mLastOfflineStateChange
= PR_IntervalNow();
1401 if (observerService
) {
1402 observerService
->NotifyObservers(subject
,
1403 NS_IOSERVICE_OFFLINE_STATUS_TOPIC
,
1404 u
"" NS_IOSERVICE_OFFLINE
);
1406 } else if (!offline
&& mOffline
) {
1408 InitializeSocketTransportService();
1409 mOffline
= false; // indicate success only AFTER we've
1410 // brought up the services
1412 mLastOfflineStateChange
= PR_IntervalNow();
1413 // don't care if notification fails
1414 // Only send the ONLINE notification if there is connectivity
1415 if (observerService
&& mConnectivity
) {
1416 observerService
->NotifyObservers(subject
,
1417 NS_IOSERVICE_OFFLINE_STATUS_TOPIC
,
1418 (u
"" NS_IOSERVICE_ONLINE
));
1423 // Don't notify here, as the above notifications (if used) suffice.
1424 if ((mShutdown
|| mOfflineForProfileChange
) && mOffline
) {
1425 if (mSocketTransportService
) {
1426 DebugOnly
<nsresult
> rv
= mSocketTransportService
->Shutdown(mShutdown
);
1427 NS_ASSERTION(NS_SUCCEEDED(rv
),
1428 "socket transport service shutdown failed");
1432 mSettingOffline
= false;
1438 nsIOService::GetConnectivity(bool* aConnectivity
) {
1439 *aConnectivity
= mConnectivity
;
1444 nsIOService::SetConnectivity(bool aConnectivity
) {
1445 LOG(("nsIOService::SetConnectivity aConnectivity=%d\n", aConnectivity
));
1446 // This should only be called from ContentChild to pass the connectivity
1447 // value from the chrome process to the content process.
1448 if (XRE_IsParentProcess()) {
1449 return NS_ERROR_NOT_AVAILABLE
;
1451 return SetConnectivityInternal(aConnectivity
);
1454 nsresult
nsIOService::SetConnectivityInternal(bool aConnectivity
) {
1455 LOG(("nsIOService::SetConnectivityInternal aConnectivity=%d\n",
1457 if (mConnectivity
== aConnectivity
) {
1458 // Nothing to do here.
1461 mConnectivity
= aConnectivity
;
1463 // This is used for PR_Connect PR_Close telemetry so it is important that
1464 // we have statistic about network change event even if we are offline.
1465 mLastConnectivityChange
= PR_IntervalNow();
1467 if (mCaptivePortalService
) {
1468 if (aConnectivity
&& gCaptivePortalEnabled
) {
1469 // This will also trigger a captive portal check for the new network
1470 static_cast<CaptivePortalService
*>(mCaptivePortalService
.get())->Start();
1472 static_cast<CaptivePortalService
*>(mCaptivePortalService
.get())->Stop();
1476 nsCOMPtr
<nsIObserverService
> observerService
= services::GetObserverService();
1477 if (!observerService
) {
1480 // This notification sends the connectivity to the child processes
1481 if (XRE_IsParentProcess()) {
1482 observerService
->NotifyObservers(nullptr,
1483 NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC
,
1484 aConnectivity
? u
"true" : u
"false");
1485 if (SocketProcessReady()) {
1486 Unused
<< mSocketProcess
->GetActor()->SendSetConnectivity(aConnectivity
);
1491 // We don't need to send any notifications if we're offline
1495 if (aConnectivity
) {
1496 // If we were previously offline due to connectivity=false,
1497 // send the ONLINE notification
1498 observerService
->NotifyObservers(static_cast<nsIIOService
*>(this),
1499 NS_IOSERVICE_OFFLINE_STATUS_TOPIC
,
1500 (u
"" NS_IOSERVICE_ONLINE
));
1502 // If we were previously online and lost connectivity
1503 // send the OFFLINE notification
1504 observerService
->NotifyObservers(static_cast<nsIIOService
*>(this),
1505 NS_IOSERVICE_GOING_OFFLINE_TOPIC
,
1506 u
"" NS_IOSERVICE_OFFLINE
);
1507 observerService
->NotifyObservers(static_cast<nsIIOService
*>(this),
1508 NS_IOSERVICE_OFFLINE_STATUS_TOPIC
,
1509 u
"" NS_IOSERVICE_OFFLINE
);
1515 nsIOService::AllowPort(int32_t inPort
, const char* scheme
, bool* _retval
) {
1516 int32_t port
= inPort
;
1522 if (port
<= 0 || port
> std::numeric_limits
<uint16_t>::max()) {
1527 nsTArray
<int32_t> restrictedPortList
;
1529 AutoReadLock
lock(mLock
);
1530 restrictedPortList
.Assign(mRestrictedPortList
);
1532 // first check to see if the port is in our blacklist:
1533 int32_t badPortListCnt
= restrictedPortList
.Length();
1534 for (int i
= 0; i
< badPortListCnt
; i
++) {
1535 if (port
== restrictedPortList
[i
]) {
1538 // check to see if the protocol wants to override
1539 if (!scheme
) return NS_OK
;
1541 // We don't support get protocol handler off main thread.
1542 if (!NS_IsMainThread()) {
1545 nsCOMPtr
<nsIProtocolHandler
> handler
;
1546 nsresult rv
= GetProtocolHandler(scheme
, getter_AddRefs(handler
));
1547 if (NS_FAILED(rv
)) return rv
;
1549 // let the protocol handler decide
1550 return handler
->AllowPort(port
, scheme
, _retval
);
1558 ////////////////////////////////////////////////////////////////////////////////
1561 void nsIOService::PrefsChanged(const char* pref
, void* self
) {
1562 static_cast<nsIOService
*>(self
)->PrefsChanged(pref
);
1565 void nsIOService::PrefsChanged(const char* pref
) {
1566 // Look for extra ports to block
1567 if (!pref
|| strcmp(pref
, PORT_PREF("banned")) == 0) {
1568 ParsePortList(PORT_PREF("banned"), false);
1571 // ...as well as previous blocks to remove.
1572 if (!pref
|| strcmp(pref
, PORT_PREF("banned.override")) == 0) {
1573 ParsePortList(PORT_PREF("banned.override"), true);
1576 if (!pref
|| strcmp(pref
, MANAGE_OFFLINE_STATUS_PREF
) == 0) {
1578 if (mNetworkLinkServiceInitialized
&&
1580 Preferences::GetBool(MANAGE_OFFLINE_STATUS_PREF
, &manage
))) {
1581 LOG(("nsIOService::PrefsChanged ManageOfflineStatus manage=%d\n",
1583 SetManageOfflineStatus(manage
);
1587 if (!pref
|| strcmp(pref
, NECKO_BUFFER_CACHE_COUNT_PREF
) == 0) {
1590 Preferences::GetInt(NECKO_BUFFER_CACHE_COUNT_PREF
, &count
))) {
1591 /* check for bogus values and default if we find such a value */
1592 if (count
> 0) gDefaultSegmentCount
= count
;
1596 if (!pref
|| strcmp(pref
, NECKO_BUFFER_CACHE_SIZE_PREF
) == 0) {
1599 Preferences::GetInt(NECKO_BUFFER_CACHE_SIZE_PREF
, &size
))) {
1600 /* check for bogus values and default if we find such a value
1601 * the upper limit here is arbitrary. having a 1mb segment size
1602 * is pretty crazy. if you remove this, consider adding some
1603 * integer rollover test.
1605 if (size
> 0 && size
< 1024 * 1024) gDefaultSegmentSize
= size
;
1607 NS_WARNING_ASSERTION(!(size
& (size
- 1)),
1608 "network segment size is not a power of 2!");
1611 if (!pref
|| strcmp(pref
, NETWORK_CAPTIVE_PORTAL_PREF
) == 0) {
1612 nsresult rv
= Preferences::GetBool(NETWORK_CAPTIVE_PORTAL_PREF
,
1613 &gCaptivePortalEnabled
);
1614 if (NS_SUCCEEDED(rv
) && mCaptivePortalService
) {
1615 if (gCaptivePortalEnabled
) {
1616 static_cast<CaptivePortalService
*>(mCaptivePortalService
.get())
1619 static_cast<CaptivePortalService
*>(mCaptivePortalService
.get())->Stop();
1624 if (!pref
|| strncmp(pref
, FORCE_EXTERNAL_PREF_PREFIX
,
1625 strlen(FORCE_EXTERNAL_PREF_PREFIX
)) == 0) {
1626 nsTArray
<nsCString
> prefs
;
1627 if (nsIPrefBranch
* prefRootBranch
= Preferences::GetRootBranch()) {
1628 prefRootBranch
->GetChildList(FORCE_EXTERNAL_PREF_PREFIX
, prefs
);
1630 nsTArray
<nsCString
> forceExternalSchemes
;
1631 for (const auto& pref
: prefs
) {
1632 if (Preferences::GetBool(pref
.get(), false)) {
1633 forceExternalSchemes
.AppendElement(
1634 Substring(pref
, strlen(FORCE_EXTERNAL_PREF_PREFIX
)));
1637 AutoWriteLock
lock(mLock
);
1638 mForceExternalSchemes
= std::move(forceExternalSchemes
);
1641 if (!pref
|| strncmp(pref
, SIMPLE_URI_SCHEMES_PREF
,
1642 strlen(SIMPLE_URI_SCHEMES_PREF
)) == 0) {
1643 LOG(("simple_uri_unknown_schemes pref changed, updating the scheme list"));
1644 mSimpleURIUnknownSchemes
.ParseAndMergePrefSchemes();
1645 // runs on parent and child, no need to broadcast
1649 void nsIOService::ParsePortList(const char* pref
, bool remove
) {
1650 nsAutoCString portList
;
1651 nsTArray
<int32_t> restrictedPortList
;
1653 AutoWriteLock
lock(mLock
);
1654 restrictedPortList
.Assign(std::move(mRestrictedPortList
));
1656 // Get a pref string and chop it up into a list of ports.
1657 Preferences::GetCString(pref
, portList
);
1658 if (!portList
.IsVoid()) {
1659 nsTArray
<nsCString
> portListArray
;
1660 ParseString(portList
, ',', portListArray
);
1662 for (index
= 0; index
< portListArray
.Length(); index
++) {
1663 portListArray
[index
].StripWhitespace();
1664 int32_t portBegin
, portEnd
;
1666 if (PR_sscanf(portListArray
[index
].get(), "%d-%d", &portBegin
,
1668 if ((portBegin
< 65536) && (portEnd
< 65536)) {
1671 for (curPort
= portBegin
; curPort
<= portEnd
; curPort
++) {
1672 restrictedPortList
.RemoveElement(curPort
);
1675 for (curPort
= portBegin
; curPort
<= portEnd
; curPort
++) {
1676 restrictedPortList
.AppendElement(curPort
);
1681 nsresult aErrorCode
;
1682 int32_t port
= portListArray
[index
].ToInteger(&aErrorCode
);
1683 if (NS_SUCCEEDED(aErrorCode
) && port
< 65536) {
1685 restrictedPortList
.RemoveElement(port
);
1687 restrictedPortList
.AppendElement(port
);
1694 AutoWriteLock
lock(mLock
);
1695 mRestrictedPortList
.Assign(std::move(restrictedPortList
));
1698 class nsWakeupNotifier
: public Runnable
{
1700 explicit nsWakeupNotifier(nsIIOServiceInternal
* ioService
)
1701 : Runnable("net::nsWakeupNotifier"), mIOService(ioService
) {}
1703 NS_IMETHOD
Run() override
{ return mIOService
->NotifyWakeup(); }
1706 virtual ~nsWakeupNotifier() = default;
1707 nsCOMPtr
<nsIIOServiceInternal
> mIOService
;
1711 nsIOService::NotifyWakeup() {
1712 nsCOMPtr
<nsIObserverService
> observerService
= services::GetObserverService();
1714 NS_ASSERTION(observerService
, "The observer service should not be null");
1716 if (observerService
&& StaticPrefs::network_notify_changed()) {
1717 (void)observerService
->NotifyObservers(nullptr, NS_NETWORK_LINK_TOPIC
,
1718 (u
"" NS_NETWORK_LINK_DATA_CHANGED
));
1721 RecheckCaptivePortal();
1726 void nsIOService::SetHttpHandlerAlreadyShutingDown() {
1727 if (!mShutdown
&& !mOfflineForProfileChange
) {
1728 mNetTearingDownStarted
= PR_IntervalNow();
1729 mHttpHandlerAlreadyShutingDown
= true;
1733 // nsIObserver interface
1735 nsIOService::Observe(nsISupports
* subject
, const char* topic
,
1736 const char16_t
* data
) {
1737 if (UseSocketProcess() && SocketProcessReady() &&
1738 mObserverTopicForSocketProcess
.Contains(nsDependentCString(topic
))) {
1739 nsCString
topicStr(topic
);
1740 nsString
dataStr(data
);
1741 Unused
<< mSocketProcess
->GetActor()->SendNotifyObserver(topicStr
, dataStr
);
1744 if (!strcmp(topic
, kProfileChangeNetTeardownTopic
)) {
1745 if (!mHttpHandlerAlreadyShutingDown
) {
1746 mNetTearingDownStarted
= PR_IntervalNow();
1748 mHttpHandlerAlreadyShutingDown
= false;
1750 mOfflineForProfileChange
= true;
1751 SetOfflineInternal(true, false);
1753 } else if (!strcmp(topic
, kProfileChangeNetRestoreTopic
)) {
1754 if (mOfflineForProfileChange
) {
1755 mOfflineForProfileChange
= false;
1756 SetOfflineInternal(false, false);
1758 } else if (!strcmp(topic
, kProfileDoChange
)) {
1759 if (data
&& u
"startup"_ns
.Equals(data
)) {
1760 // Lazy initialization of network link service (see bug 620472)
1761 InitializeNetworkLinkService();
1762 // Set up the initilization flag regardless the actuall result.
1763 // If we fail here, we will fail always on.
1764 mNetworkLinkServiceInitialized
= true;
1766 // And now reflect the preference setting
1767 PrefsChanged(MANAGE_OFFLINE_STATUS_PREF
);
1769 // Bug 870460 - Read cookie database at an early-as-possible time
1770 // off main thread. Hence, we have more chance to finish db query
1771 // before something calls into the cookie service.
1772 nsCOMPtr
<nsISupports
> cookieServ
=
1773 do_GetService(NS_COOKIESERVICE_CONTRACTID
);
1775 } else if (!strcmp(topic
, NS_XPCOM_SHUTDOWN_OBSERVER_ID
)) {
1776 // Remember we passed XPCOM shutdown notification to prevent any
1777 // changes of the offline status from now. We must not allow going
1778 // online after this point.
1781 if (!mHttpHandlerAlreadyShutingDown
&& !mOfflineForProfileChange
) {
1782 mNetTearingDownStarted
= PR_IntervalNow();
1784 mHttpHandlerAlreadyShutingDown
= false;
1786 SetOfflineInternal(true, false);
1788 if (mCaptivePortalService
) {
1789 static_cast<CaptivePortalService
*>(mCaptivePortalService
.get())->Stop();
1790 mCaptivePortalService
= nullptr;
1793 SSLTokensCache::Shutdown();
1795 DestroySocketProcess();
1797 if (IsSocketProcessChild()) {
1798 Preferences::UnregisterCallbacks(nsIOService::OnTLSPrefChange
,
1799 gCallbackSecurityPrefs
, this);
1800 PrepareForShutdownInSocketProcess();
1803 // We're in XPCOM shutdown now. Unregister any dynamic protocol handlers
1804 // after this point to avoid leaks.
1806 AutoWriteLock
lock(mLock
);
1807 mRuntimeProtocolHandlers
.Clear();
1809 } else if (!strcmp(topic
, NS_NETWORK_LINK_TOPIC
)) {
1810 OnNetworkLinkEvent(NS_ConvertUTF16toUTF8(data
).get());
1811 } else if (!strcmp(topic
, NS_NETWORK_ID_CHANGED_TOPIC
)) {
1812 LOG(("nsIOService::OnNetworkLinkEvent Network id changed"));
1813 } else if (!strcmp(topic
, NS_WIDGET_WAKE_OBSERVER_TOPIC
)) {
1814 // coming back alive from sleep
1815 // this indirection brought to you by:
1816 // https://bugzilla.mozilla.org/show_bug.cgi?id=1152048#c19
1817 nsCOMPtr
<nsIRunnable
> wakeupNotifier
= new nsWakeupNotifier(this);
1818 NS_DispatchToMainThread(wakeupNotifier
);
1819 mInSleepMode
= false;
1820 } else if (!strcmp(topic
, NS_WIDGET_SLEEP_OBSERVER_TOPIC
)) {
1821 mInSleepMode
= true;
1827 // nsINetUtil interface
1829 nsIOService::ParseRequestContentType(const nsACString
& aTypeHeader
,
1830 nsACString
& aCharset
, bool* aHadCharset
,
1831 nsACString
& aContentType
) {
1832 net_ParseRequestContentType(aTypeHeader
, aContentType
, aCharset
, aHadCharset
);
1836 // nsINetUtil interface
1838 nsIOService::ParseResponseContentType(const nsACString
& aTypeHeader
,
1839 nsACString
& aCharset
, bool* aHadCharset
,
1840 nsACString
& aContentType
) {
1841 net_ParseContentType(aTypeHeader
, aContentType
, aCharset
, aHadCharset
);
1846 nsIOService::ProtocolHasFlags(nsIURI
* uri
, uint32_t flags
, bool* result
) {
1850 nsAutoCString scheme
;
1851 nsresult rv
= uri
->GetScheme(scheme
);
1852 NS_ENSURE_SUCCESS(rv
, rv
);
1854 auto handler
= LookupProtocolHandler(scheme
);
1856 uint32_t protocolFlags
;
1857 if (flags
& nsIProtocolHandler::DYNAMIC_URI_FLAGS
) {
1858 AssertIsOnMainThread();
1859 rv
= handler
.DynamicProtocolFlags(uri
, &protocolFlags
);
1860 NS_ENSURE_SUCCESS(rv
, rv
);
1862 protocolFlags
= handler
.StaticProtocolFlags();
1865 *result
= (protocolFlags
& flags
) == flags
;
1870 nsIOService::URIChainHasFlags(nsIURI
* uri
, uint32_t flags
, bool* result
) {
1871 nsresult rv
= ProtocolHasFlags(uri
, flags
, result
);
1872 NS_ENSURE_SUCCESS(rv
, rv
);
1878 // Dig deeper into the chain. Note that this is not a do/while loop to
1879 // avoid the extra addref/release on |uri| in the common (non-nested) case.
1880 nsCOMPtr
<nsINestedURI
> nestedURI
= do_QueryInterface(uri
);
1882 nsCOMPtr
<nsIURI
> innerURI
;
1883 rv
= nestedURI
->GetInnerURI(getter_AddRefs(innerURI
));
1884 NS_ENSURE_SUCCESS(rv
, rv
);
1886 rv
= ProtocolHasFlags(innerURI
, flags
, result
);
1892 nestedURI
= do_QueryInterface(innerURI
);
1899 nsIOService::SetManageOfflineStatus(bool aManage
) {
1900 LOG(("nsIOService::SetManageOfflineStatus aManage=%d\n", aManage
));
1901 mManageLinkStatus
= aManage
;
1903 // When detection is not activated, the default connectivity state is true.
1904 if (!mManageLinkStatus
) {
1905 SetConnectivityInternal(true);
1909 InitializeNetworkLinkService();
1910 // If the NetworkLinkService is already initialized, it does not call
1911 // OnNetworkLinkEvent. This is needed, when mManageLinkStatus goes from
1913 OnNetworkLinkEvent(NS_NETWORK_LINK_DATA_UNKNOWN
);
1918 nsIOService::GetManageOfflineStatus(bool* aManage
) {
1919 *aManage
= mManageLinkStatus
;
1923 // input argument 'data' is already UTF8'ed
1924 nsresult
nsIOService::OnNetworkLinkEvent(const char* data
) {
1925 if (IsNeckoChild() || IsSocketProcessChild()) {
1926 // There is nothing IO service could do on the child process
1927 // with this at the moment. Feel free to add functionality
1928 // here at will, though.
1933 return NS_ERROR_NOT_AVAILABLE
;
1936 nsCString
dataAsString(data
);
1937 for (auto* cp
: mozilla::dom::ContentParent::AllProcesses(
1938 mozilla::dom::ContentParent::eLive
)) {
1939 PNeckoParent
* neckoParent
= SingleManagedOrNull(cp
->ManagedPNeckoParent());
1943 Unused
<< neckoParent
->SendNetworkChangeNotification(dataAsString
);
1946 LOG(("nsIOService::OnNetworkLinkEvent data:%s\n", data
));
1947 if (!mNetworkLinkService
) {
1948 return NS_ERROR_FAILURE
;
1951 if (!mManageLinkStatus
) {
1952 LOG(("nsIOService::OnNetworkLinkEvent mManageLinkStatus=false\n"));
1957 if (!strcmp(data
, NS_NETWORK_LINK_DATA_CHANGED
)) {
1958 mLastNetworkLinkChange
= PR_IntervalNow();
1959 // CHANGED means UP/DOWN didn't change
1960 // but the status of the captive portal may have changed.
1961 RecheckCaptivePortal();
1964 if (!strcmp(data
, NS_NETWORK_LINK_DATA_DOWN
)) {
1966 } else if (!strcmp(data
, NS_NETWORK_LINK_DATA_UP
)) {
1968 } else if (!strcmp(data
, NS_NETWORK_LINK_DATA_UNKNOWN
)) {
1969 nsresult rv
= mNetworkLinkService
->GetIsLinkUp(&isUp
);
1970 NS_ENSURE_SUCCESS(rv
, rv
);
1972 NS_WARNING("Unhandled network event!");
1976 return SetConnectivityInternal(isUp
);
1980 nsIOService::EscapeString(const nsACString
& aString
, uint32_t aEscapeType
,
1981 nsACString
& aResult
) {
1982 NS_ENSURE_ARG_MAX(aEscapeType
, 4);
1984 nsAutoCString
stringCopy(aString
);
1987 if (!NS_Escape(stringCopy
, result
, (nsEscapeMask
)aEscapeType
)) {
1988 return NS_ERROR_OUT_OF_MEMORY
;
1991 aResult
.Assign(result
);
1997 nsIOService::EscapeURL(const nsACString
& aStr
, uint32_t aFlags
,
1998 nsACString
& aResult
) {
2000 NS_EscapeURL(aStr
.BeginReading(), aStr
.Length(), aFlags
| esc_AlwaysCopy
,
2006 nsIOService::UnescapeString(const nsACString
& aStr
, uint32_t aFlags
,
2007 nsACString
& aResult
) {
2009 NS_UnescapeURL(aStr
.BeginReading(), aStr
.Length(), aFlags
| esc_AlwaysCopy
,
2015 nsIOService::ExtractCharsetFromContentType(const nsACString
& aTypeHeader
,
2016 nsACString
& aCharset
,
2017 int32_t* aCharsetStart
,
2018 int32_t* aCharsetEnd
,
2019 bool* aHadCharset
) {
2020 nsAutoCString ignored
;
2021 net_ParseContentType(aTypeHeader
, ignored
, aCharset
, aHadCharset
,
2022 aCharsetStart
, aCharsetEnd
);
2023 if (*aHadCharset
&& *aCharsetStart
== *aCharsetEnd
) {
2024 *aHadCharset
= false;
2029 // nsISpeculativeConnect
2030 class IOServiceProxyCallback final
: public nsIProtocolProxyCallback
{
2031 ~IOServiceProxyCallback() = default;
2035 NS_DECL_NSIPROTOCOLPROXYCALLBACK
2037 IOServiceProxyCallback(nsIInterfaceRequestor
* aCallbacks
,
2038 nsIOService
* aIOService
,
2039 Maybe
<OriginAttributes
>&& aOriginAttributes
)
2040 : mCallbacks(aCallbacks
),
2041 mIOService(aIOService
),
2042 mOriginAttributes(std::move(aOriginAttributes
)) {}
2045 RefPtr
<nsIInterfaceRequestor
> mCallbacks
;
2046 RefPtr
<nsIOService
> mIOService
;
2047 Maybe
<OriginAttributes
> mOriginAttributes
;
2050 NS_IMPL_ISUPPORTS(IOServiceProxyCallback
, nsIProtocolProxyCallback
)
2053 IOServiceProxyCallback::OnProxyAvailable(nsICancelable
* request
,
2054 nsIChannel
* channel
, nsIProxyInfo
* pi
,
2056 // Checking proxy status for speculative connect
2058 if (NS_SUCCEEDED(status
) && pi
&& NS_SUCCEEDED(pi
->GetType(type
)) &&
2059 !type
.EqualsLiteral("direct")) {
2060 // proxies dont do speculative connect
2064 nsCOMPtr
<nsIURI
> uri
;
2065 nsresult rv
= channel
->GetURI(getter_AddRefs(uri
));
2066 if (NS_FAILED(rv
)) {
2070 nsAutoCString scheme
;
2071 rv
= uri
->GetScheme(scheme
);
2072 if (NS_FAILED(rv
)) return NS_OK
;
2074 nsCOMPtr
<nsIProtocolHandler
> handler
;
2075 rv
= mIOService
->GetProtocolHandler(scheme
.get(), getter_AddRefs(handler
));
2076 if (NS_FAILED(rv
)) return NS_OK
;
2078 nsCOMPtr
<nsISpeculativeConnect
> speculativeHandler
=
2079 do_QueryInterface(handler
);
2080 if (!speculativeHandler
) return NS_OK
;
2082 nsCOMPtr
<nsILoadInfo
> loadInfo
= channel
->LoadInfo();
2083 nsCOMPtr
<nsIPrincipal
> principal
= loadInfo
->GetLoadingPrincipal();
2085 nsLoadFlags loadFlags
= 0;
2086 channel
->GetLoadFlags(&loadFlags
);
2087 bool anonymous
= !!(loadFlags
& nsIRequest::LOAD_ANONYMOUS
);
2088 if (mOriginAttributes
) {
2089 speculativeHandler
->SpeculativeConnectWithOriginAttributesNative(
2090 uri
, std::move(mOriginAttributes
.ref()), mCallbacks
, anonymous
);
2092 speculativeHandler
->SpeculativeConnect(uri
, principal
, mCallbacks
,
2099 nsresult
nsIOService::SpeculativeConnectInternal(
2100 nsIURI
* aURI
, nsIPrincipal
* aPrincipal
,
2101 Maybe
<OriginAttributes
>&& aOriginAttributes
,
2102 nsIInterfaceRequestor
* aCallbacks
, bool aAnonymous
) {
2103 NS_ENSURE_ARG(aURI
);
2105 if (!aURI
->SchemeIs("http") && !aURI
->SchemeIs("https")) {
2106 // We don't speculatively connect to non-HTTP[S] URIs.
2110 if (IsNeckoChild()) {
2111 gNeckoChild
->SendSpeculativeConnect(
2112 aURI
, aPrincipal
, std::move(aOriginAttributes
), aAnonymous
);
2116 // Check for proxy information. If there is a proxy configured then a
2117 // speculative connect should not be performed because the potential
2118 // reward is slim with tcp peers closely located to the browser.
2120 nsCOMPtr
<nsIProtocolProxyService
> pps
;
2121 pps
= mozilla::components::ProtocolProxy::Service(&rv
);
2122 NS_ENSURE_SUCCESS(rv
, rv
);
2124 nsCOMPtr
<nsIPrincipal
> loadingPrincipal
= aPrincipal
;
2126 MOZ_ASSERT(aPrincipal
|| aOriginAttributes
,
2127 "We expect passing a principal or OriginAttributes here.");
2129 if (!aPrincipal
&& !aOriginAttributes
) {
2130 return NS_ERROR_INVALID_ARG
;
2133 if (aOriginAttributes
) {
2135 BasePrincipal::CreateContentPrincipal(aURI
, aOriginAttributes
.ref());
2138 // XXX Bug 1724080: Avoid TCP connections on port 80 when https-only
2139 // or https-first is enabled. Let's create a dummy loadinfo which we
2140 // only use to determine whether we need ot upgrade the speculative
2141 // connection from http to https.
2142 nsCOMPtr
<nsIURI
> httpsURI
;
2143 if (aURI
->SchemeIs("http")) {
2144 nsCOMPtr
<nsILoadInfo
> httpsOnlyCheckLoadInfo
=
2145 new LoadInfo(loadingPrincipal
, loadingPrincipal
, nullptr,
2146 nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK
,
2147 nsIContentPolicy::TYPE_SPECULATIVE
);
2149 // Check if https-only, or https-first would upgrade the request
2150 if (nsHTTPSOnlyUtils::ShouldUpgradeRequest(aURI
, httpsOnlyCheckLoadInfo
) ||
2151 nsHTTPSOnlyUtils::ShouldUpgradeHttpsFirstRequest(
2152 aURI
, httpsOnlyCheckLoadInfo
)) {
2153 rv
= NS_GetSecureUpgradedURI(aURI
, getter_AddRefs(httpsURI
));
2154 NS_ENSURE_SUCCESS(rv
, rv
);
2155 aURI
= httpsURI
.get();
2159 // dummy channel used to create a TCP connection.
2160 // we perform security checks on the *real* channel, responsible
2161 // for any network loads. this real channel just checks the TCP
2162 // pool if there is an available connection created by the
2163 // channel we create underneath - hence it's safe to use
2164 // the systemPrincipal as the loadingPrincipal for this channel.
2165 nsCOMPtr
<nsIChannel
> channel
;
2166 rv
= NewChannelFromURI(
2168 nullptr, // aLoadingNode,
2170 nullptr, // aTriggeringPrincipal,
2171 nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL
,
2172 nsIContentPolicy::TYPE_SPECULATIVE
, getter_AddRefs(channel
));
2173 NS_ENSURE_SUCCESS(rv
, rv
);
2176 nsLoadFlags loadFlags
= 0;
2177 channel
->GetLoadFlags(&loadFlags
);
2178 loadFlags
|= nsIRequest::LOAD_ANONYMOUS
;
2179 channel
->SetLoadFlags(loadFlags
);
2182 nsCOMPtr
<nsICancelable
> cancelable
;
2183 RefPtr
<IOServiceProxyCallback
> callback
= new IOServiceProxyCallback(
2184 aCallbacks
, this, std::move(aOriginAttributes
));
2185 nsCOMPtr
<nsIProtocolProxyService2
> pps2
= do_QueryInterface(pps
);
2187 return pps2
->AsyncResolve2(channel
, 0, callback
, nullptr,
2188 getter_AddRefs(cancelable
));
2190 return pps
->AsyncResolve(channel
, 0, callback
, nullptr,
2191 getter_AddRefs(cancelable
));
2195 nsIOService::SpeculativeConnect(nsIURI
* aURI
, nsIPrincipal
* aPrincipal
,
2196 nsIInterfaceRequestor
* aCallbacks
,
2198 return SpeculativeConnectInternal(aURI
, aPrincipal
, Nothing(), aCallbacks
,
2202 NS_IMETHODIMP
nsIOService::SpeculativeConnectWithOriginAttributes(
2203 nsIURI
* aURI
, JS::Handle
<JS::Value
> aOriginAttributes
,
2204 nsIInterfaceRequestor
* aCallbacks
, bool aAnonymous
, JSContext
* aCx
) {
2205 OriginAttributes attrs
;
2206 if (!aOriginAttributes
.isObject() || !attrs
.Init(aCx
, aOriginAttributes
)) {
2207 return NS_ERROR_INVALID_ARG
;
2210 SpeculativeConnectWithOriginAttributesNative(aURI
, std::move(attrs
),
2211 aCallbacks
, aAnonymous
);
2215 NS_IMETHODIMP_(void)
2216 nsIOService::SpeculativeConnectWithOriginAttributesNative(
2217 nsIURI
* aURI
, OriginAttributes
&& aOriginAttributes
,
2218 nsIInterfaceRequestor
* aCallbacks
, bool aAnonymous
) {
2219 Maybe
<OriginAttributes
> originAttributes
;
2220 originAttributes
.emplace(aOriginAttributes
);
2221 Unused
<< SpeculativeConnectInternal(
2222 aURI
, nullptr, std::move(originAttributes
), aCallbacks
, aAnonymous
);
2226 nsIOService::NotImplemented() { return NS_ERROR_NOT_IMPLEMENTED
; }
2229 nsIOService::GetSocketProcessLaunched(bool* aResult
) {
2230 NS_ENSURE_ARG_POINTER(aResult
);
2232 *aResult
= SocketProcessReady();
2236 bool nsIOService::HasObservers(const char* aTopic
) {
2237 MOZ_ASSERT(false, "Calling this method is unexpected");
2242 nsIOService::GetSocketProcessId(uint64_t* aPid
) {
2243 NS_ENSURE_ARG_POINTER(aPid
);
2246 if (!mSocketProcess
) {
2250 if (SocketProcessParent
* actor
= mSocketProcess
->GetActor()) {
2251 *aPid
= (uint64_t)actor
->OtherPid();
2258 nsIOService::RegisterProtocolHandler(const nsACString
& aScheme
,
2259 nsIProtocolHandler
* aHandler
,
2260 uint32_t aProtocolFlags
,
2261 int32_t aDefaultPort
) {
2263 return NS_ERROR_NOT_AVAILABLE
;
2265 if (aScheme
.IsEmpty()) {
2266 return NS_ERROR_INVALID_ARG
;
2269 nsAutoCString
scheme(aScheme
);
2270 ToLowerCase(scheme
);
2272 AutoWriteLock
lock(mLock
);
2273 return mRuntimeProtocolHandlers
.WithEntryHandle(scheme
, [&](auto&& entry
) {
2275 NS_WARNING("Cannot override an existing dynamic protocol handler");
2276 return NS_ERROR_FACTORY_EXISTS
;
2278 if (xpcom::StaticProtocolHandler::Lookup(scheme
)) {
2279 NS_WARNING("Cannot override an existing static protocol handler");
2280 return NS_ERROR_FACTORY_EXISTS
;
2282 nsMainThreadPtrHandle
<nsIProtocolHandler
> handler(
2283 new nsMainThreadPtrHolder
<nsIProtocolHandler
>("RuntimeProtocolHandler",
2285 entry
.Insert(RuntimeProtocolHandler
{
2286 .mHandler
= std::move(handler
),
2287 .mProtocolFlags
= aProtocolFlags
,
2288 .mDefaultPort
= aDefaultPort
,
2295 nsIOService::UnregisterProtocolHandler(const nsACString
& aScheme
) {
2299 if (aScheme
.IsEmpty()) {
2300 return NS_ERROR_INVALID_ARG
;
2303 nsAutoCString
scheme(aScheme
);
2304 ToLowerCase(scheme
);
2306 AutoWriteLock
lock(mLock
);
2307 return mRuntimeProtocolHandlers
.Remove(scheme
)
2309 : NS_ERROR_FACTORY_NOT_REGISTERED
;
2313 nsIOService::SetSimpleURIUnknownRemoteSchemes(
2314 const nsTArray
<nsCString
>& aRemoteSchemes
) {
2315 LOG(("nsIOService::SetSimpleUriUnknownRemoteSchemes"));
2316 mSimpleURIUnknownSchemes
.SetAndMergeRemoteSchemes(aRemoteSchemes
);
2318 if (XRE_IsParentProcess()) {
2319 // since we only expect socket, parent and content processes to create URLs
2320 // that need to check the bypass list
2321 // we only broadcast the list to content processes
2322 // (and leave socket process broadcast as todo if necessary)
2324 // sending only the remote-settings schemes to the content,
2325 // which already has the pref list
2326 for (auto* cp
: mozilla::dom::ContentParent::AllProcesses(
2327 mozilla::dom::ContentParent::eLive
)) {
2328 Unused
<< cp
->SendSimpleURIUnknownRemoteSchemes(aRemoteSchemes
);
2335 nsIOService::IsSimpleURIUnknownScheme(const nsACString
& aScheme
,
2337 *_retval
= mSimpleURIUnknownSchemes
.IsSimpleURIUnknownScheme(aScheme
);
2342 nsIOService::GetSimpleURIUnknownRemoteSchemes(nsTArray
<nsCString
>& _retval
) {
2343 mSimpleURIUnknownSchemes
.GetRemoteSchemes(_retval
);
2348 } // namespace mozilla