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/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"
68 #include "StaticComponents.h"
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");
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
[] = {
140 135, // loc-srv / epmap
147 427, // afp (alternate)
148 465, // smtp (alternate)
162 587, // smtp (outgoing)
169 1719, // h323gatestat
170 1720, // h323hostcall
180 6665, // irc (alternate)
181 6666, // irc (alternate)
182 6667, // irc (default)
183 6668, // irc (alternate)
184 6669, // irc (alternate)
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
[] = {
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
,
221 static const char* gCallbackPrefsForSocketProcess
[] = {
224 "network.send_ODA_to_content_directly",
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",
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",
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);
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);
308 InitializeNetworkLinkService();
309 InitializeProtocolProxyService();
317 nsIOService::AddObserver(nsIObserver
* aObserver
, const char* aTopic
,
319 if (!mObserverService
) {
320 return NS_ERROR_FAILURE
;
323 // Register for the origional observer.
324 nsresult rv
= mObserverService
->AddObserver(aObserver
, aTopic
, aOwnsWeak
);
329 if (!XRE_IsParentProcess()) {
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
);
341 if (!UseSocketProcess()) {
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);
365 nsIOService::RemoveObserver(nsIObserver
* aObserver
, const char* aTopic
) {
366 return NS_ERROR_NOT_IMPLEMENTED
;
370 nsIOService::EnumerateObservers(const char* aTopic
,
371 nsISimpleEnumerator
** anEnumerator
) {
372 return NS_ERROR_NOT_IMPLEMENTED
;
375 NS_IMETHODIMP
nsIOService::NotifyObservers(nsISupports
* aSubject
,
377 const char16_t
* aSomeData
) {
378 return NS_ERROR_NOT_IMPLEMENTED
;
381 nsIOService::~nsIOService() {
383 MOZ_ASSERT(gIOService
== this);
384 gIOService
= nullptr;
389 void nsIOService::OnTLSPrefChange(const char* aPref
, void* aSelf
) {
390 MOZ_ASSERT(IsSocketProcessChild());
392 if (!EnsureNSSInitializedChromeOrContent()) {
393 LOG(("NSS not initialized."));
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
415 mCaptivePortalService
= do_GetService(NS_CAPTIVEPORTAL_CID
);
416 if (mCaptivePortalService
) {
417 return static_cast<CaptivePortalService
*>(mCaptivePortalService
.get())
421 // Instantiate and initialize the service
422 RefPtr
<NetworkConnectivityService
> ncs
=
423 NetworkConnectivityService::GetSingleton();
428 nsresult
nsIOService::InitializeSocketTransportService() {
431 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
433 ("nsIOService aborting InitializeSocketTransportService because of app "
435 return NS_ERROR_ILLEGAL_DURING_SHUTDOWN
;
438 if (!mSocketTransportService
) {
439 mSocketTransportService
=
440 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID
, &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);
455 nsresult
nsIOService::InitializeNetworkLinkService() {
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
);
482 nsresult
nsIOService::InitializeProtocolProxyService() {
485 if (XRE_IsParentProcess()) {
486 // for early-initialization
487 Unused
<< do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID
, &rv
);
493 already_AddRefed
<nsIOService
> nsIOService::GetInstance() {
495 RefPtr
<nsIOService
> ios
= new nsIOService();
496 if (NS_SUCCEEDED(ios
->Init())) {
497 MOZ_ASSERT(gIOService
== ios
.get());
501 return do_AddRef(gIOService
);
504 class SocketProcessListenerProxy
: public SocketProcessHost::Listener
{
506 SocketProcessListenerProxy() = default;
507 void OnProcessLaunchComplete(SocketProcessHost
* aHost
, bool aSucceeded
) {
512 gIOService
->OnProcessLaunchComplete(aHost
, aSucceeded
);
515 void OnProcessUnexpectedShutdown(SocketProcessHost
* aHost
) {
520 gIOService
->OnProcessUnexpectedShutdown(aHost
);
525 bool nsIOService::TooManySocketProcessCrash() {
526 return sSocketProcessCrashedCount
>=
527 StaticPrefs::network_max_socket_process_failed_count();
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
) {
543 // We shouldn't launch socket prcess when shutdown begins.
544 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
548 if (mSocketProcess
) {
552 if (PR_GetEnv("MOZ_DISABLE_SOCKET_PROCESS")) {
553 LOG(("nsIOService skipping LaunchSocketProcess because of the env"));
557 if (!StaticPrefs::network_process_enabled()) {
558 LOG(("nsIOService skipping LaunchSocketProcess because of the pref"));
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
;
579 void nsIOService::DestroySocketProcess() {
580 LOG(("nsIOService::DestroySocketProcess"));
581 MOZ_ASSERT(NS_IsMainThread());
583 if (XRE_GetProcessType() != GeckoProcessType_Default
|| !mSocketProcess
) {
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;
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()) {
627 StaticPrefs::network_http_network_access_on_socket_process_enabled();
629 return sUseSocketProcess
;
633 void nsIOService::NotifySocketProcessPrefsChanged(const char* aName
,
635 static_cast<nsIOService
*>(aSelf
)->NotifySocketProcessPrefsChanged(aName
);
638 void nsIOService::NotifySocketProcessPrefsChanged(const char* aName
) {
639 MOZ_ASSERT(NS_IsMainThread());
641 if (!XRE_IsParentProcess()) {
645 if (!StaticPrefs::network_process_enabled()) {
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(
658 CallOrWaitForSocketProcess(sendPrefUpdate
);
661 void nsIOService::OnProcessLaunchComplete(SocketProcessHost
* aHost
,
663 MOZ_ASSERT(NS_IsMainThread());
665 LOG(("nsIOService::OnProcessLaunchComplete aSucceeded=%d\n", aSucceeded
));
667 mSocketProcessLaunchComplete
= aSucceeded
;
669 if (mShutdown
|| !SocketProcessReady() || !aSucceeded
) {
670 mPendingEvents
.Clear();
674 if (!mPendingEvents
.IsEmpty()) {
675 nsTArray
<std::function
<void()>> pendingEvents
= std::move(mPendingEvents
);
676 for (auto& func
: pendingEvents
) {
682 void nsIOService::CallOrWaitForSocketProcess(
683 const std::function
<void()>& aFunc
) {
684 MOZ_ASSERT(NS_IsMainThread());
685 if (IsSocketProcessLaunchComplete() && SocketProcessReady()) {
688 mPendingEvents
.AppendElement(aFunc
); // infallible
689 LaunchSocketProcess();
693 int32_t nsIOService::SocketProcessPid() {
694 if (!mSocketProcess
) {
697 if (SocketProcessParent
* actor
= mSocketProcess
->GetActor()) {
698 return (int32_t)actor
->OtherPid();
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()) {
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()) {
748 return new SocketProcessMemoryReporter();
752 nsIOService::SocketProcessTelemetryPing() {
753 CallOrWaitForSocketProcess([]() {
754 Unused
<< gIOService
->mSocketProcess
->GetActor()
755 ->SendSocketProcessTelemetryPing();
760 NS_IMPL_ISUPPORTS(nsIOService
, nsIIOService
, nsINetUtil
, nsISpeculativeConnect
,
761 nsIObserver
, nsIIOServiceInternal
, nsISupportsWeakReference
,
764 ////////////////////////////////////////////////////////////////////////////////
766 nsresult
nsIOService::RecheckCaptivePortal() {
767 MOZ_ASSERT(NS_IsMainThread(), "Must be called on the main thread");
768 if (!mCaptivePortalService
) {
771 nsCOMPtr
<nsIRunnable
> task
= NewRunnableMethod(
772 "nsIOService::RecheckCaptivePortal", mCaptivePortalService
,
773 &nsICaptivePortalService::RecheckCaptivePortal
);
774 return NS_DispatchToMainThread(task
);
777 nsresult
nsIOService::RecheckCaptivePortalIfLocalRedirect(nsIChannel
* newChan
) {
780 if (!mCaptivePortalService
) {
784 nsCOMPtr
<nsIURI
> uri
;
785 rv
= newChan
->GetURI(getter_AddRefs(uri
));
791 rv
= uri
->GetHost(host
);
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();
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
816 nsCOMPtr
<nsIChannelEventSink
> sink
=
817 do_GetService(NS_CONTENTSECURITYMANAGER_CONTRACTID
);
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
) {
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.
838 MOZ_ASSERT(NS_IsMainThread());
839 nsCOMPtr
<nsIURI
> newURI
;
840 newChan
->GetURI(getter_AddRefs(newURI
));
843 nsAutoCString scheme
;
844 newURI
->GetScheme(scheme
);
845 MOZ_ASSERT(!scheme
.IsEmpty());
847 Telemetry::AccumulateCategoricalKeyed(
849 oldChan
->IsDocument()
850 ? Telemetry::LABELS_NETWORK_HTTP_REDIRECT_TO_SCHEME::topLevel
851 : Telemetry::LABELS_NETWORK_HTTP_REDIRECT_TO_SCHEME::subresource
);
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.
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.
874 // If prefs configure the URI to be handled externally, do so.
875 for (const auto& scheme
: mForceExternalSchemes
) {
876 if (aScheme
== scheme
) {
883 ProtocolHandlerInfo
nsIOService::LookupProtocolHandler(
884 const nsACString
& aScheme
) {
885 // Look-ups are ASCII-case-insensitive, so lower-case the string before
887 nsAutoCString
scheme(aScheme
);
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());
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
;
919 nsIOService::ExtractScheme(const nsACString
& inURI
, nsACString
& scheme
) {
920 return net_ExtractURLScheme(inURI
, scheme
);
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
);
931 nsresult rv
= innerURI
->GetAsciiHost(host
);
939 if (NS_SUCCEEDED(addr
.InitFromString(host
)) && addr
.IsIPAddrLocal()) {
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
);
954 nsresult rv
= innerURI
->GetAsciiHost(host
);
962 if (NS_SUCCEEDED(addr
.InitFromString(host
)) && addr
.IsIPAddrShared()) {
970 nsIOService::IsValidHostname(const nsACString
& inHostname
, bool* aResult
) {
971 *aResult
= net_IsValidHostName(inHostname
);
977 nsIOService::GetProtocolFlags(const char* scheme
, uint32_t* flags
) {
978 NS_ENSURE_ARG_POINTER(scheme
);
981 LookupProtocolHandler(nsDependentCString(scheme
)).StaticProtocolFlags();
986 nsIOService::GetDynamicProtocolFlags(nsIURI
* uri
, uint32_t* flags
) {
987 AssertIsOnMainThread();
990 nsAutoCString scheme
;
991 nsresult rv
= uri
->GetScheme(scheme
);
992 NS_ENSURE_SUCCESS(rv
, rv
);
994 return LookupProtocolHandler(scheme
).DynamicProtocolFlags(uri
, flags
);
998 nsIOService::GetDefaultPort(const char* scheme
, int32_t* defaultPort
) {
999 NS_ENSURE_ARG_POINTER(scheme
);
1002 LookupProtocolHandler(nsDependentCString(scheme
)).DefaultPort();
1006 nsresult
nsIOService::NewURI(const nsACString
& aSpec
, const char* aCharset
,
1007 nsIURI
* aBaseURI
, nsIURI
** result
) {
1008 return NS_NewURI(result
, aSpec
, aCharset
, aBaseURI
);
1012 nsIOService::NewFileURI(nsIFile
* file
, nsIURI
** result
) {
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
);
1028 already_AddRefed
<nsIURI
> nsIOService::CreateExposableURI(nsIURI
* aURI
) {
1029 MOZ_ASSERT(aURI
, "Must have a URI");
1030 nsCOMPtr
<nsIURI
> uri
= aURI
;
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();
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
);
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
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(
1071 nullptr, // aProxyURI
1073 aLoadingNode
, aLoadingPrincipal
, aTriggeringPrincipal
, aLoadingClientInfo
,
1074 aController
, aSecurityFlags
, aContentPolicyType
, aSandboxFlags
,
1075 aSkipCheckForBrokenURLOrZeroSized
, aResult
);
1079 nsIOService::NewChannelFromURIWithLoadInfo(nsIURI
* aURI
, nsILoadInfo
* aLoadInfo
,
1080 nsIChannel
** result
) {
1081 return NewChannelFromURIWithProxyFlagsInternal(aURI
,
1082 nullptr, // aProxyURI
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
,
1103 nsresult
nsIOService::NewChannelFromURIWithProxyFlagsInternal(
1104 nsIURI
* aURI
, nsIURI
* aProxyURI
, uint32_t aProxyFlags
,
1105 nsILoadInfo
* aLoadInfo
, nsIChannel
** result
) {
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
);
1123 rv
= pph
->NewProxiedChannel(aURI
, nullptr, aProxyFlags
, aProxyURI
,
1124 aLoadInfo
, getter_AddRefs(channel
));
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.
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
);
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
);
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
) {
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
);
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
);
1213 bool nsIOService::IsLinkUp() {
1214 InitializeNetworkLinkService();
1216 if (!mNetworkLinkService
) {
1217 // We cannot decide, assume the link is up
1223 rv
= mNetworkLinkService
->GetIsLinkUp(&isLinkUp
);
1224 if (NS_FAILED(rv
)) {
1232 nsIOService::GetOffline(bool* offline
) {
1233 if (StaticPrefs::network_offline_mirrors_connectivity()) {
1234 *offline
= mOffline
|| !mConnectivity
;
1236 *offline
= mOffline
;
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
) {
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
) {
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;
1333 nsIOService::GetConnectivity(bool* aConnectivity
) {
1334 *aConnectivity
= mConnectivity
;
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",
1352 if (mConnectivity
== aConnectivity
) {
1353 // Nothing to do here.
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();
1367 static_cast<CaptivePortalService
*>(mCaptivePortalService
.get())->Stop();
1371 nsCOMPtr
<nsIObserverService
> observerService
= services::GetObserverService();
1372 if (!observerService
) {
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
);
1386 // We don't need to send any notifications if we're offline
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
));
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
);
1410 nsIOService::AllowPort(int32_t inPort
, const char* scheme
, bool* _retval
) {
1411 int32_t port
= inPort
;
1417 if (port
<= 0 || port
> std::numeric_limits
<uint16_t>::max()) {
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
]) {
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()) {
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
);
1453 ////////////////////////////////////////////////////////////////////////////////
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) {
1473 if (mNetworkLinkServiceInitialized
&&
1475 Preferences::GetBool(MANAGE_OFFLINE_STATUS_PREF
, &manage
))) {
1476 LOG(("nsIOService::PrefsChanged ManageOfflineStatus manage=%d\n",
1478 SetManageOfflineStatus(manage
);
1482 if (!pref
|| strcmp(pref
, NECKO_BUFFER_CACHE_COUNT_PREF
) == 0) {
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) {
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())
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) {
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
);
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
,
1565 if ((portBegin
< 65536) && (portEnd
< 65536)) {
1568 for (curPort
= portBegin
; curPort
<= portEnd
; curPort
++) {
1569 restrictedPortList
.RemoveElement(curPort
);
1572 for (curPort
= portBegin
; curPort
<= portEnd
; curPort
++) {
1573 restrictedPortList
.AppendElement(curPort
);
1578 nsresult aErrorCode
;
1579 int32_t port
= portListArray
[index
].ToInteger(&aErrorCode
);
1580 if (NS_SUCCEEDED(aErrorCode
) && port
< 65536) {
1582 restrictedPortList
.RemoveElement(port
);
1584 restrictedPortList
.AppendElement(port
);
1591 AutoWriteLock
lock(mLock
);
1592 mRestrictedPortList
.Assign(std::move(restrictedPortList
));
1595 class nsWakeupNotifier
: public Runnable
{
1597 explicit nsWakeupNotifier(nsIIOServiceInternal
* ioService
)
1598 : Runnable("net::nsWakeupNotifier"), mIOService(ioService
) {}
1600 NS_IMETHOD
Run() override
{ return mIOService
->NotifyWakeup(); }
1603 virtual ~nsWakeupNotifier() = default;
1604 nsCOMPtr
<nsIIOServiceInternal
> mIOService
;
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();
1623 void nsIOService::SetHttpHandlerAlreadyShutingDown() {
1624 if (!mShutdown
&& !mOfflineForProfileChange
) {
1625 mNetTearingDownStarted
= PR_IntervalNow();
1626 mHttpHandlerAlreadyShutingDown
= true;
1630 // nsIObserver interface
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;
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.
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
);
1721 // nsINetUtil interface
1723 nsIOService::ParseRequestContentType(const nsACString
& aTypeHeader
,
1724 nsACString
& aCharset
, bool* aHadCharset
,
1725 nsACString
& aContentType
) {
1726 net_ParseRequestContentType(aTypeHeader
, aContentType
, aCharset
, aHadCharset
);
1730 // nsINetUtil interface
1732 nsIOService::ParseResponseContentType(const nsACString
& aTypeHeader
,
1733 nsACString
& aCharset
, bool* aHadCharset
,
1734 nsACString
& aContentType
) {
1735 net_ParseContentType(aTypeHeader
, aContentType
, aCharset
, aHadCharset
);
1740 nsIOService::ProtocolHasFlags(nsIURI
* uri
, uint32_t flags
, bool* result
) {
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
);
1756 protocolFlags
= handler
.StaticProtocolFlags();
1759 *result
= (protocolFlags
& flags
) == flags
;
1764 nsIOService::URIChainHasFlags(nsIURI
* uri
, uint32_t flags
, bool* result
) {
1765 nsresult rv
= ProtocolHasFlags(uri
, flags
, result
);
1766 NS_ENSURE_SUCCESS(rv
, 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
);
1776 nsCOMPtr
<nsIURI
> innerURI
;
1777 rv
= nestedURI
->GetInnerURI(getter_AddRefs(innerURI
));
1778 NS_ENSURE_SUCCESS(rv
, rv
);
1780 rv
= ProtocolHasFlags(innerURI
, flags
, result
);
1786 nestedURI
= do_QueryInterface(innerURI
);
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);
1803 InitializeNetworkLinkService();
1804 // If the NetworkLinkService is already initialized, it does not call
1805 // OnNetworkLinkEvent. This is needed, when mManageLinkStatus goes from
1807 OnNetworkLinkEvent(NS_NETWORK_LINK_DATA_UNKNOWN
);
1812 nsIOService::GetManageOfflineStatus(bool* aManage
) {
1813 *aManage
= mManageLinkStatus
;
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.
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());
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"));
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();
1858 if (!strcmp(data
, NS_NETWORK_LINK_DATA_DOWN
)) {
1860 } else if (!strcmp(data
, NS_NETWORK_LINK_DATA_UP
)) {
1862 } else if (!strcmp(data
, NS_NETWORK_LINK_DATA_UNKNOWN
)) {
1863 nsresult rv
= mNetworkLinkService
->GetIsLinkUp(&isUp
);
1864 NS_ENSURE_SUCCESS(rv
, rv
);
1866 NS_WARNING("Unhandled network event!");
1870 return SetConnectivityInternal(isUp
);
1874 nsIOService::EscapeString(const nsACString
& aString
, uint32_t aEscapeType
,
1875 nsACString
& aResult
) {
1876 NS_ENSURE_ARG_MAX(aEscapeType
, 4);
1878 nsAutoCString
stringCopy(aString
);
1881 if (!NS_Escape(stringCopy
, result
, (nsEscapeMask
)aEscapeType
)) {
1882 return NS_ERROR_OUT_OF_MEMORY
;
1885 aResult
.Assign(result
);
1891 nsIOService::EscapeURL(const nsACString
& aStr
, uint32_t aFlags
,
1892 nsACString
& aResult
) {
1894 NS_EscapeURL(aStr
.BeginReading(), aStr
.Length(), aFlags
| esc_AlwaysCopy
,
1900 nsIOService::UnescapeString(const nsACString
& aStr
, uint32_t aFlags
,
1901 nsACString
& aResult
) {
1903 NS_UnescapeURL(aStr
.BeginReading(), aStr
.Length(), aFlags
| esc_AlwaysCopy
,
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;
1923 // nsISpeculativeConnect
1924 class IOServiceProxyCallback final
: public nsIProtocolProxyCallback
{
1925 ~IOServiceProxyCallback() = default;
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
)) {}
1939 RefPtr
<nsIInterfaceRequestor
> mCallbacks
;
1940 RefPtr
<nsIOService
> mIOService
;
1941 Maybe
<OriginAttributes
> mOriginAttributes
;
1944 NS_IMPL_ISUPPORTS(IOServiceProxyCallback
, nsIProtocolProxyCallback
)
1947 IOServiceProxyCallback::OnProxyAvailable(nsICancelable
* request
,
1948 nsIChannel
* channel
, nsIProxyInfo
* pi
,
1950 // Checking proxy status for speculative connect
1952 if (NS_SUCCEEDED(status
) && pi
&& NS_SUCCEEDED(pi
->GetType(type
)) &&
1953 !type
.EqualsLiteral("direct")) {
1954 // proxies dont do speculative connect
1958 nsCOMPtr
<nsIURI
> uri
;
1959 nsresult rv
= channel
->GetURI(getter_AddRefs(uri
));
1960 if (NS_FAILED(rv
)) {
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
);
1986 speculativeHandler
->SpeculativeConnect(uri
, principal
, mCallbacks
,
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.
2004 if (IsNeckoChild()) {
2005 gNeckoChild
->SendSpeculativeConnect(
2006 aURI
, aPrincipal
, std::move(aOriginAttributes
), aAnonymous
);
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.
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
) {
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(
2062 nullptr, // aLoadingNode,
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
);
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
);
2081 return pps2
->AsyncResolve2(channel
, 0, callback
, nullptr,
2082 getter_AddRefs(cancelable
));
2084 return pps
->AsyncResolve(channel
, 0, callback
, nullptr,
2085 getter_AddRefs(cancelable
));
2089 nsIOService::SpeculativeConnect(nsIURI
* aURI
, nsIPrincipal
* aPrincipal
,
2090 nsIInterfaceRequestor
* aCallbacks
,
2092 return SpeculativeConnectInternal(aURI
, aPrincipal
, Nothing(), aCallbacks
,
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
);
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
);
2120 nsIOService::NotImplemented() { return NS_ERROR_NOT_IMPLEMENTED
; }
2123 nsIOService::GetSocketProcessLaunched(bool* aResult
) {
2124 NS_ENSURE_ARG_POINTER(aResult
);
2126 *aResult
= SocketProcessReady();
2130 bool nsIOService::HasObservers(const char* aTopic
) {
2131 MOZ_ASSERT(false, "Calling this method is unexpected");
2136 nsIOService::GetSocketProcessId(uint64_t* aPid
) {
2137 NS_ENSURE_ARG_POINTER(aPid
);
2140 if (!mSocketProcess
) {
2144 if (SocketProcessParent
* actor
= mSocketProcess
->GetActor()) {
2145 *aPid
= (uint64_t)actor
->OtherPid();
2152 nsIOService::RegisterProtocolHandler(const nsACString
& aScheme
,
2153 nsIProtocolHandler
* aHandler
,
2154 uint32_t aProtocolFlags
,
2155 int32_t aDefaultPort
) {
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
) {
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",
2179 entry
.Insert(RuntimeProtocolHandler
{
2180 .mHandler
= std::move(handler
),
2181 .mProtocolFlags
= aProtocolFlags
,
2182 .mDefaultPort
= aDefaultPort
,
2189 nsIOService::UnregisterProtocolHandler(const nsACString
& aScheme
) {
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
)
2203 : NS_ERROR_FACTORY_NOT_REGISTERED
;
2207 } // namespace mozilla