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