tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsIOService.cpp (81118B)


      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 "netCore.h"
     16 #include "nsIObserverService.h"
     17 #include "nsXPCOM.h"
     18 #include "nsIProxiedProtocolHandler.h"
     19 #include "nsIProxyInfo.h"
     20 #include "nsDNSService2.h"
     21 #include "nsEscape.h"
     22 #include "nsNetUtil.h"
     23 #include "nsNetCID.h"
     24 #include "nsCRT.h"
     25 #include "nsSimpleNestedURI.h"
     26 #include "nsSocketTransport2.h"
     27 #include "nsTArray.h"
     28 #include "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 "nsIWebTransport.h"
     39 #include "nsIWidget.h"
     40 #include "nsThreadUtils.h"
     41 #include "WebTransportSessionProxy.h"
     42 #include "mozilla/AppShutdown.h"
     43 #include "mozilla/Components.h"
     44 #include "mozilla/LoadInfo.h"
     45 #include "mozilla/net/NeckoCommon.h"
     46 #include "mozilla/Services.h"
     47 #include "mozilla/net/DNS.h"
     48 #include "mozilla/ipc/URIUtils.h"
     49 #include "mozilla/net/CacheControlParser.h"
     50 #include "mozilla/net/NeckoChild.h"
     51 #include "mozilla/net/NeckoParent.h"
     52 #include "mozilla/dom/ChromeUtilsBinding.h"
     53 #include "mozilla/dom/ClientInfo.h"
     54 #include "mozilla/dom/ContentParent.h"
     55 #include "mozilla/dom/nsHTTPSOnlyUtils.h"
     56 #include "mozilla/dom/ServiceWorkerDescriptor.h"
     57 #include "mozilla/net/CaptivePortalService.h"
     58 #include "mozilla/net/NetworkConnectivityService.h"
     59 #include "mozilla/net/SocketProcessHost.h"
     60 #include "mozilla/net/SocketProcessParent.h"
     61 #include "mozilla/net/SSLTokensCache.h"
     62 #include "mozilla/StoragePrincipalHelper.h"
     63 #include "nsContentSecurityManager.h"
     64 #include "nsContentUtils.h"
     65 #include "mozilla/StaticPrefs_network.h"
     66 #include "mozilla/StaticPrefs_security.h"
     67 #include "mozilla/glean/NetwerkMetrics.h"
     68 #include "nsNSSComponent.h"
     69 #include "IPv4Parser.h"
     70 #include "ssl.h"
     71 #include "StaticComponents.h"
     72 #include "SuspendableChannelWrapper.h"
     73 
     74 #ifdef MOZ_WIDGET_ANDROID
     75 #  include <regex>
     76 #  include "AndroidBridge.h"
     77 #  include "mozilla/java/GeckoAppShellWrappers.h"
     78 #  include "mozilla/jni/Utils.h"
     79 #endif
     80 
     81 namespace mozilla {
     82 namespace net {
     83 
     84 using mozilla::Maybe;
     85 using mozilla::dom::ClientInfo;
     86 using mozilla::dom::ServiceWorkerDescriptor;
     87 
     88 #define PORT_PREF_PREFIX "network.security.ports."
     89 #define PORT_PREF(x) PORT_PREF_PREFIX x
     90 #define MANAGE_OFFLINE_STATUS_PREF "network.manage-offline-status"
     91 
     92 // Nb: these have been misnomers since bug 715770 removed the buffer cache.
     93 // "network.segment.count" and "network.segment.size" would be better names,
     94 // but the old names are still used to preserve backward compatibility.
     95 #define NECKO_BUFFER_CACHE_COUNT_PREF "network.buffer.cache.count"
     96 #define NECKO_BUFFER_CACHE_SIZE_PREF "network.buffer.cache.size"
     97 #define NETWORK_CAPTIVE_PORTAL_PREF "network.captive-portal-service.enabled"
     98 #define WEBRTC_PREF_PREFIX "media.peerconnection."
     99 #define NETWORK_DNS_PREF "network.dns."
    100 #define FORCE_EXTERNAL_PREF_PREFIX "network.protocol-handler.external."
    101 // prefs for overriding IPAddress->IpAddressSpace mapping
    102 #define PREF_LNA_IP_ADDR_SPACE_PUBLIC \
    103  "network.lna.address_space.public.override"
    104 #define PREF_LNA_IP_ADDR_SPACE_PRIVATE \
    105  "network.lna.address_space.private.override"
    106 #define PREF_LNA_IP_ADDR_SPACE_LOCAL "network.lna.address_space.local.override"
    107 #define PREF_LNA_SKIP_DOMAINS "network.lna.skip-domains"
    108 
    109 nsIOService* gIOService;
    110 static bool gCaptivePortalEnabled = false;
    111 static LazyLogModule gIOServiceLog("nsIOService");
    112 #undef LOG
    113 #define LOG(args) MOZ_LOG(gIOServiceLog, LogLevel::Debug, args)
    114 
    115 // A general port blacklist.  Connections to these ports will not be allowed
    116 // unless the protocol overrides.
    117 //
    118 // This list is to be kept in sync with "bad ports" as defined in the
    119 // WHATWG Fetch standard at <https://fetch.spec.whatwg.org/#port-blocking>
    120 
    121 int16_t gBadPortList[] = {
    122    1,      // tcpmux
    123    7,      // echo
    124    9,      // discard
    125    11,     // systat
    126    13,     // daytime
    127    15,     // netstat
    128    17,     // qotd
    129    19,     // chargen
    130    20,     // ftp-data
    131    21,     // ftp
    132    22,     // ssh
    133    23,     // telnet
    134    25,     // smtp
    135    37,     // time
    136    42,     // name
    137    43,     // nicname
    138    53,     // domain
    139    69,     // tftp
    140    77,     // priv-rjs
    141    79,     // finger
    142    87,     // ttylink
    143    95,     // supdup
    144    101,    // hostriame
    145    102,    // iso-tsap
    146    103,    // gppitnp
    147    104,    // acr-nema
    148    109,    // pop2
    149    110,    // pop3
    150    111,    // sunrpc
    151    113,    // auth
    152    115,    // sftp
    153    117,    // uucp-path
    154    119,    // nntp
    155    123,    // ntp
    156    135,    // loc-srv / epmap
    157    137,    // netbios
    158    139,    // netbios
    159    143,    // imap2
    160    161,    // snmp
    161    179,    // bgp
    162    389,    // ldap
    163    427,    // afp (alternate)
    164    465,    // smtp (alternate)
    165    512,    // print / exec
    166    513,    // login
    167    514,    // shell
    168    515,    // printer
    169    526,    // tempo
    170    530,    // courier
    171    531,    // chat
    172    532,    // netnews
    173    540,    // uucp
    174    548,    // afp
    175    554,    // rtsp
    176    556,    // remotefs
    177    563,    // nntp+ssl
    178    587,    // smtp (outgoing)
    179    601,    // syslog-conn
    180    636,    // ldap+ssl
    181    989,    // ftps-data
    182    990,    // ftps
    183    993,    // imap+ssl
    184    995,    // pop3+ssl
    185    1719,   // h323gatestat
    186    1720,   // h323hostcall
    187    1723,   // pptp
    188    2049,   // nfs
    189    3659,   // apple-sasl
    190    4045,   // lockd
    191    4190,   // sieve
    192    5060,   // sip
    193    5061,   // sips
    194    6000,   // x11
    195    6566,   // sane-port
    196    6665,   // irc (alternate)
    197    6666,   // irc (alternate)
    198    6667,   // irc (default)
    199    6668,   // irc (alternate)
    200    6669,   // irc (alternate)
    201    6679,   // osaut
    202    6697,   // irc+tls
    203    10080,  // amanda
    204    0,      // Sentinel value: This MUST be zero
    205 };
    206 
    207 static const char kProfileChangeNetTeardownTopic[] =
    208    "profile-change-net-teardown";
    209 static const char kProfileChangeNetRestoreTopic[] =
    210    "profile-change-net-restore";
    211 static const char kProfileDoChange[] = "profile-do-change";
    212 
    213 // Necko buffer defaults
    214 uint32_t nsIOService::gDefaultSegmentSize = 4096;
    215 uint32_t nsIOService::gDefaultSegmentCount = 24;
    216 
    217 uint32_t nsIOService::sSocketProcessCrashedCount = 0;
    218 
    219 ////////////////////////////////////////////////////////////////////////////////
    220 
    221 nsIOService::nsIOService()
    222    : mLastOfflineStateChange(PR_IntervalNow()),
    223      mLastConnectivityChange(PR_IntervalNow()),
    224      mLastNetworkLinkChange(PR_IntervalNow()) {}
    225 
    226 static const char* gCallbackPrefs[] = {
    227    PORT_PREF_PREFIX,
    228    MANAGE_OFFLINE_STATUS_PREF,
    229    NECKO_BUFFER_CACHE_COUNT_PREF,
    230    NECKO_BUFFER_CACHE_SIZE_PREF,
    231    NETWORK_CAPTIVE_PORTAL_PREF,
    232    FORCE_EXTERNAL_PREF_PREFIX,
    233    SIMPLE_URI_SCHEMES_PREF,
    234    PREF_LNA_IP_ADDR_SPACE_PUBLIC,
    235    PREF_LNA_IP_ADDR_SPACE_PRIVATE,
    236    PREF_LNA_IP_ADDR_SPACE_LOCAL,
    237    PREF_LNA_SKIP_DOMAINS,
    238    nullptr,
    239 };
    240 
    241 static const char* gCallbackPrefsForSocketProcess[] = {
    242    WEBRTC_PREF_PREFIX,
    243    NETWORK_DNS_PREF,
    244    "media.webrtc.enable_pq_hybrid_kex",
    245    "media.webrtc.send_mlkem_keyshare",
    246    "network.send_ODA_to_content_directly",
    247    "network.trr.",
    248    "doh-rollout.",
    249    "network.dns.disableIPv6",
    250    "network.offline-mirrors-connectivity",
    251    "network.disable-localhost-when-offline",
    252    "network.proxy.parse_pac_on_socket_process",
    253    "network.proxy.allow_hijacking_localhost",
    254    "network.proxy.testing_localhost_is_secure_when_hijacked",
    255    "network.connectivity-service.",
    256    "network.captive-portal-service.testMode",
    257    "network.socket.ip_addr_any.disabled",
    258    "network.socket.attach_mock_network_layer",
    259    "network.lna.enabled",
    260    "network.lna.blocking",
    261    "network.lna.address_space.private.override",
    262    "network.lna.address_space.public.override",
    263    "network.lna.websocket.enabled",
    264    "network.lna.local-network-to-localhost.skip-checks",
    265    "network.socket.forcePort",
    266    nullptr,
    267 };
    268 
    269 static const char* gCallbackSecurityPrefs[] = {
    270    // Note the prefs listed below should be in sync with the code in
    271    // HandleTLSPrefChange().
    272    "security.tls.version.min",
    273    "security.tls.version.max",
    274    "security.tls.version.enable-deprecated",
    275    "security.tls.hello_downgrade_check",
    276    "security.ssl.require_safe_negotiation",
    277    "security.ssl.enable_false_start",
    278    "security.ssl.enable_alpn",
    279    "security.tls.enable_0rtt_data",
    280    "security.ssl.disable_session_identifiers",
    281    "security.tls.enable_post_handshake_auth",
    282    "security.tls.enable_delegated_credentials",
    283    nullptr,
    284 };
    285 
    286 nsresult nsIOService::Init() {
    287  SSLTokensCache::Init();
    288 
    289  InitializeCaptivePortalService();
    290 
    291  // setup our bad port list stuff
    292  for (int i = 0; gBadPortList[i]; i++) {
    293    // We can't be accessed by another thread yet
    294    MOZ_PUSH_IGNORE_THREAD_SAFETY
    295    mRestrictedPortList.AppendElement(gBadPortList[i]);
    296    MOZ_POP_THREAD_SAFETY
    297  }
    298 
    299  // Further modifications to the port list come from prefs
    300  Preferences::RegisterPrefixCallbacks(nsIOService::PrefsChanged,
    301                                       gCallbackPrefs, this);
    302  PrefsChanged();
    303 
    304  mSocketProcessTopicBlockedList.Insert(
    305      nsLiteralCString(NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID));
    306  mSocketProcessTopicBlockedList.Insert(
    307      nsLiteralCString(NS_XPCOM_SHUTDOWN_OBSERVER_ID));
    308  mSocketProcessTopicBlockedList.Insert("xpcom-shutdown-threads"_ns);
    309  mSocketProcessTopicBlockedList.Insert("profile-do-change"_ns);
    310  mSocketProcessTopicBlockedList.Insert("network:socket-process-crashed"_ns);
    311 
    312  // Register for profile change notifications
    313  mObserverService = services::GetObserverService();
    314  MOZ_ALWAYS_SUCCEEDS(AddObserver(this, kProfileChangeNetTeardownTopic, true));
    315  MOZ_ALWAYS_SUCCEEDS(AddObserver(this, kProfileChangeNetRestoreTopic, true));
    316  MOZ_ALWAYS_SUCCEEDS(AddObserver(this, kProfileDoChange, true));
    317  MOZ_ALWAYS_SUCCEEDS(AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, true));
    318  MOZ_ALWAYS_SUCCEEDS(AddObserver(this, NS_NETWORK_LINK_TOPIC, true));
    319  MOZ_ALWAYS_SUCCEEDS(AddObserver(this, NS_NETWORK_ID_CHANGED_TOPIC, true));
    320  MOZ_ALWAYS_SUCCEEDS(AddObserver(this, NS_WIDGET_WAKE_OBSERVER_TOPIC, true));
    321 
    322  // Register observers for sending notifications to nsSocketTransportService
    323  if (XRE_IsParentProcess()) {
    324    AddObserver(this, "profile-initial-state", true);
    325    AddObserver(this, NS_WIDGET_SLEEP_OBSERVER_TOPIC, true);
    326  }
    327 
    328  if (IsSocketProcessChild()) {
    329    Preferences::RegisterCallbacks(nsIOService::OnTLSPrefChange,
    330                                   gCallbackSecurityPrefs, this);
    331  }
    332 
    333  gIOService = this;
    334 
    335  InitializeNetworkLinkService();
    336  InitializeProtocolProxyService();
    337  SetOffline(false);
    338 
    339  // This is just to start the DNS service to make it fast to get later.
    340  // Don't invoke directly since we're already in GetService.  RefPtr needed
    341  // because already_AddRefed<> doesn't like to be dropped
    342  NS_DispatchToCurrentThread(NS_NewRunnableFunction(
    343      __func__, []() { RefPtr<nsIDNSService> dns = GetOrInitDNSService(); }));
    344 
    345  return NS_OK;
    346 }
    347 
    348 NS_IMETHODIMP
    349 nsIOService::AddObserver(nsIObserver* aObserver, const char* aTopic,
    350                         bool aOwnsWeak) {
    351  if (!mObserverService) {
    352    return NS_ERROR_FAILURE;
    353  }
    354 
    355  // Register for the origional observer.
    356  nsresult rv = mObserverService->AddObserver(aObserver, aTopic, aOwnsWeak);
    357  if (NS_FAILED(rv)) {
    358    return rv;
    359  }
    360 
    361  if (!XRE_IsParentProcess()) {
    362    return NS_OK;
    363  }
    364 
    365  nsAutoCString topic(aTopic);
    366  // This happens when AddObserver() is called by nsIOService::Init(). We don't
    367  // want to add nsIOService again.
    368  if (SameCOMIdentity(aObserver, static_cast<nsIObserver*>(this))) {
    369    mIOServiceTopicList.Insert(topic);
    370    return NS_OK;
    371  }
    372 
    373  if (!UseSocketProcess()) {
    374    return NS_OK;
    375  }
    376 
    377  if (mSocketProcessTopicBlockedList.Contains(topic)) {
    378    return NS_ERROR_FAILURE;
    379  }
    380 
    381  // Avoid registering  duplicate topics.
    382  if (mObserverTopicForSocketProcess.Contains(topic)) {
    383    return NS_ERROR_FAILURE;
    384  }
    385 
    386  mObserverTopicForSocketProcess.Insert(topic);
    387 
    388  // Avoid registering duplicate topics.
    389  if (mIOServiceTopicList.Contains(topic)) {
    390    return NS_ERROR_FAILURE;
    391  }
    392 
    393  return mObserverService->AddObserver(this, aTopic, true);
    394 }
    395 
    396 NS_IMETHODIMP
    397 nsIOService::RemoveObserver(nsIObserver* aObserver, const char* aTopic) {
    398  return NS_ERROR_NOT_IMPLEMENTED;
    399 }
    400 
    401 NS_IMETHODIMP
    402 nsIOService::EnumerateObservers(const char* aTopic,
    403                                nsISimpleEnumerator** anEnumerator) {
    404  return NS_ERROR_NOT_IMPLEMENTED;
    405 }
    406 
    407 NS_IMETHODIMP nsIOService::NotifyObservers(nsISupports* aSubject,
    408                                           const char* aTopic,
    409                                           const char16_t* aSomeData) {
    410  return NS_ERROR_NOT_IMPLEMENTED;
    411 }
    412 
    413 nsIOService::~nsIOService() {
    414  if (gIOService) {
    415    MOZ_ASSERT(gIOService == this);
    416    gIOService = nullptr;
    417  }
    418 }
    419 
    420 #ifdef MOZ_WIDGET_ANDROID
    421 bool nsIOService::ShouldAddAdditionalSearchHeaders(nsIURI* aURI,
    422                                                   bool* aHeaderVal) {
    423  if (!(mozilla::AndroidBridge::Bridge())) {
    424    return false;
    425  }
    426 
    427  if (!aURI->SchemeIs("https")) {
    428    return false;
    429  }
    430 
    431  // We need to improve below logic for matching google domains
    432  // See Bug 1894642
    433  // Is URI same as google ^https://www\\.google\\..+
    434  nsAutoCString host;
    435  aURI->GetHost(host);
    436  LOG(("nsIOService::ShouldAddAdditionalSearchHeaders() checking host %s\n",
    437       PromiseFlatCString(host).get()));
    438 
    439  std::regex pattern("^www\\.google\\..+");
    440  if (std::regex_match(host.get(), pattern)) {
    441    LOG(("Google domain detected for host %s\n",
    442         PromiseFlatCString(host).get()));
    443    static bool ramAboveThreshold =
    444        java::GeckoAppShell::IsDeviceRamThresholdOkay();
    445    *aHeaderVal = ramAboveThreshold;
    446    return true;
    447  }
    448 
    449  return false;
    450 }
    451 #endif
    452 
    453 // static
    454 void nsIOService::OnTLSPrefChange(const char* aPref, void* aSelf) {
    455  MOZ_ASSERT(IsSocketProcessChild());
    456 
    457  if (!EnsureNSSInitializedChromeOrContent()) {
    458    LOG(("NSS not initialized."));
    459    return;
    460  }
    461 
    462  nsAutoCString pref(aPref);
    463  // The preferences listed in gCallbackSecurityPrefs need to be in sync with
    464  // the code in HandleTLSPrefChange().
    465  if (HandleTLSPrefChange(pref)) {
    466    LOG(("HandleTLSPrefChange done"));
    467  }
    468 }
    469 
    470 nsresult nsIOService::InitializeCaptivePortalService() {
    471  if (XRE_GetProcessType() != GeckoProcessType_Default) {
    472    // We only initalize a captive portal service in the main process
    473    return NS_OK;
    474  }
    475 
    476  mCaptivePortalService = mozilla::components::CaptivePortal::Service();
    477  if (mCaptivePortalService) {
    478    static_cast<CaptivePortalService*>(mCaptivePortalService.get())
    479        ->Initialize();
    480  }
    481 
    482  // Instantiate and initialize the service
    483  RefPtr<NetworkConnectivityService> ncs =
    484      NetworkConnectivityService::GetSingleton();
    485 
    486  return NS_OK;
    487 }
    488 
    489 nsresult nsIOService::InitializeSocketTransportService() {
    490  nsresult rv = NS_OK;
    491 
    492  if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
    493    LOG(
    494        ("nsIOService aborting InitializeSocketTransportService because of app "
    495         "shutdown"));
    496    return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
    497  }
    498 
    499  if (!mSocketTransportService) {
    500    mSocketTransportService =
    501        mozilla::components::SocketTransport::Service(&rv);
    502    if (NS_FAILED(rv)) {
    503      NS_WARNING("failed to get socket transport service");
    504    }
    505  }
    506 
    507  if (mSocketTransportService) {
    508    rv = mSocketTransportService->Init();
    509    NS_ASSERTION(NS_SUCCEEDED(rv), "socket transport service init failed");
    510    mSocketTransportService->SetOffline(false);
    511  }
    512 
    513  return rv;
    514 }
    515 
    516 nsresult nsIOService::InitializeNetworkLinkService() {
    517  nsresult rv = NS_OK;
    518 
    519  if (mNetworkLinkServiceInitialized) return rv;
    520 
    521  if (!NS_IsMainThread()) {
    522    NS_WARNING("Network link service should be created on main thread");
    523    return NS_ERROR_FAILURE;
    524  }
    525 
    526  // go into managed mode if we can, and chrome process
    527  if (!XRE_IsParentProcess()) {
    528    return NS_ERROR_NOT_AVAILABLE;
    529  }
    530 
    531  mNetworkLinkService = do_GetService(NS_NETWORK_LINK_SERVICE_CONTRACTID, &rv);
    532 
    533  if (mNetworkLinkService) {
    534    mNetworkLinkServiceInitialized = true;
    535  }
    536 
    537  // After initializing the networkLinkService, query the connectivity state
    538  OnNetworkLinkEvent(NS_NETWORK_LINK_DATA_UNKNOWN);
    539 
    540  return rv;
    541 }
    542 
    543 nsresult nsIOService::InitializeProtocolProxyService() {
    544  nsresult rv = NS_OK;
    545 
    546  if (XRE_IsParentProcess()) {
    547    // for early-initialization
    548    (void)mozilla::components::ProtocolProxy::Service(&rv);
    549  }
    550 
    551  return rv;
    552 }
    553 
    554 already_AddRefed<nsIOService> nsIOService::GetInstance() {
    555  if (!gIOService) {
    556    RefPtr<nsIOService> ios = new nsIOService();
    557    if (NS_SUCCEEDED(ios->Init())) {
    558      MOZ_ASSERT(gIOService == ios.get());
    559      return ios.forget();
    560    }
    561  }
    562  return do_AddRef(gIOService);
    563 }
    564 
    565 class SocketProcessListenerProxy : public SocketProcessHost::Listener {
    566 public:
    567  SocketProcessListenerProxy() = default;
    568  void OnProcessLaunchComplete(SocketProcessHost* aHost, bool aSucceeded) {
    569    if (!gIOService) {
    570      return;
    571    }
    572 
    573    gIOService->OnProcessLaunchComplete(aHost, aSucceeded);
    574  }
    575 
    576  void OnProcessUnexpectedShutdown(SocketProcessHost* aHost) {
    577    if (!gIOService) {
    578      return;
    579    }
    580 
    581    gIOService->OnProcessUnexpectedShutdown(aHost);
    582  }
    583 };
    584 
    585 // static
    586 bool nsIOService::TooManySocketProcessCrash() {
    587  return sSocketProcessCrashedCount >=
    588         StaticPrefs::network_max_socket_process_failed_count();
    589 }
    590 
    591 // static
    592 void nsIOService::IncreaseSocketProcessCrashCount() {
    593  MOZ_ASSERT(IsNeckoChild());
    594  sSocketProcessCrashedCount++;
    595 }
    596 
    597 nsresult nsIOService::LaunchSocketProcess() {
    598  MOZ_ASSERT(NS_IsMainThread());
    599 
    600  if (XRE_GetProcessType() != GeckoProcessType_Default) {
    601    return NS_OK;
    602  }
    603 
    604  // We shouldn't launch socket prcess when shutdown begins.
    605  if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
    606    return NS_OK;
    607  }
    608 
    609  if (mSocketProcess) {
    610    return NS_OK;
    611  }
    612 
    613  if (PR_GetEnv("MOZ_DISABLE_SOCKET_PROCESS")) {
    614    LOG(("nsIOService skipping LaunchSocketProcess because of the env"));
    615    return NS_OK;
    616  }
    617 
    618  if (!StaticPrefs::network_process_enabled()) {
    619    LOG(("nsIOService skipping LaunchSocketProcess because of the pref"));
    620    return NS_OK;
    621  }
    622 
    623  Preferences::RegisterPrefixCallbacks(
    624      nsIOService::NotifySocketProcessPrefsChanged,
    625      gCallbackPrefsForSocketProcess, this);
    626 
    627  // The subprocess is launched asynchronously, so we wait for a callback to
    628  // acquire the IPDL actor.
    629  mSocketProcess = new SocketProcessHost(new SocketProcessListenerProxy());
    630  LOG(("nsIOService::LaunchSocketProcess"));
    631  if (!mSocketProcess->Launch()) {
    632    NS_WARNING("Failed to launch socket process!!");
    633    DestroySocketProcess();
    634    return NS_ERROR_FAILURE;
    635  }
    636 
    637  return NS_OK;
    638 }
    639 
    640 void nsIOService::DestroySocketProcess() {
    641  LOG(("nsIOService::DestroySocketProcess"));
    642  MOZ_ASSERT(NS_IsMainThread());
    643 
    644  if (XRE_GetProcessType() != GeckoProcessType_Default || !mSocketProcess) {
    645    return;
    646  }
    647 
    648  Preferences::UnregisterPrefixCallbacks(
    649      nsIOService::NotifySocketProcessPrefsChanged,
    650      gCallbackPrefsForSocketProcess, this);
    651 
    652  mSocketProcess->Shutdown();
    653  mSocketProcess = nullptr;
    654 }
    655 
    656 bool nsIOService::SocketProcessReady() {
    657  return mSocketProcess && mSocketProcess->IsConnected();
    658 }
    659 
    660 static bool sUseSocketProcess = false;
    661 static bool sUseSocketProcessChecked = false;
    662 
    663 // static
    664 bool nsIOService::UseSocketProcess(bool aCheckAgain) {
    665  if (sUseSocketProcessChecked && !aCheckAgain) {
    666    return sUseSocketProcess;
    667  }
    668 
    669  sUseSocketProcessChecked = true;
    670  sUseSocketProcess = false;
    671 
    672  if (PR_GetEnv("MOZ_DISABLE_SOCKET_PROCESS")) {
    673    return sUseSocketProcess;
    674  }
    675 
    676  if (TooManySocketProcessCrash()) {
    677    LOG(("TooManySocketProcessCrash"));
    678    return sUseSocketProcess;
    679  }
    680 
    681  if (PR_GetEnv("MOZ_FORCE_USE_SOCKET_PROCESS")) {
    682    sUseSocketProcess = true;
    683    return sUseSocketProcess;
    684  }
    685 
    686  if (StaticPrefs::network_process_enabled()) {
    687    sUseSocketProcess =
    688        StaticPrefs::network_http_network_access_on_socket_process_enabled();
    689  }
    690  return sUseSocketProcess;
    691 }
    692 
    693 // static
    694 void nsIOService::NotifySocketProcessPrefsChanged(const char* aName,
    695                                                  void* aSelf) {
    696  static_cast<nsIOService*>(aSelf)->NotifySocketProcessPrefsChanged(aName);
    697 }
    698 
    699 void nsIOService::NotifySocketProcessPrefsChanged(const char* aName) {
    700  MOZ_ASSERT(NS_IsMainThread());
    701 
    702  if (!XRE_IsParentProcess()) {
    703    return;
    704  }
    705 
    706  if (!StaticPrefs::network_process_enabled()) {
    707    return;
    708  }
    709 
    710  dom::Pref pref(nsCString(aName), /* isLocked */ false,
    711                 /* isSanitized */ false, Nothing(), Nothing());
    712 
    713  Preferences::GetPreference(&pref, GeckoProcessType_Socket,
    714                             /* remoteType */ ""_ns);
    715  auto sendPrefUpdate = [pref]() {
    716    (void)gIOService->mSocketProcess->GetActor()->SendPreferenceUpdate(pref);
    717  };
    718  CallOrWaitForSocketProcess(sendPrefUpdate);
    719 }
    720 
    721 void nsIOService::OnProcessLaunchComplete(SocketProcessHost* aHost,
    722                                          bool aSucceeded) {
    723  MOZ_ASSERT(NS_IsMainThread());
    724 
    725  LOG(("nsIOService::OnProcessLaunchComplete aSucceeded=%d\n", aSucceeded));
    726 
    727  mSocketProcessLaunchComplete = aSucceeded;
    728 
    729  if (mShutdown || !SocketProcessReady() || !aSucceeded) {
    730    mPendingEvents.Clear();
    731    return;
    732  }
    733 
    734  if (!mPendingEvents.IsEmpty()) {
    735    nsTArray<std::function<void()>> pendingEvents = std::move(mPendingEvents);
    736    for (auto& func : pendingEvents) {
    737      func();
    738    }
    739  }
    740 }
    741 
    742 void nsIOService::CallOrWaitForSocketProcess(
    743    const std::function<void()>& aFunc) {
    744  MOZ_ASSERT(NS_IsMainThread());
    745  if (IsSocketProcessLaunchComplete() && SocketProcessReady()) {
    746    aFunc();
    747  } else {
    748    mPendingEvents.AppendElement(aFunc);  // infallible
    749    LaunchSocketProcess();
    750  }
    751 }
    752 
    753 int32_t nsIOService::SocketProcessPid() {
    754  if (!mSocketProcess) {
    755    return 0;
    756  }
    757  if (SocketProcessParent* actor = mSocketProcess->GetActor()) {
    758    return (int32_t)actor->OtherPid();
    759  }
    760  return 0;
    761 }
    762 
    763 bool nsIOService::IsSocketProcessLaunchComplete() {
    764  MOZ_ASSERT(NS_IsMainThread());
    765  return mSocketProcessLaunchComplete;
    766 }
    767 
    768 void nsIOService::OnProcessUnexpectedShutdown(SocketProcessHost* aHost) {
    769  MOZ_ASSERT(NS_IsMainThread());
    770 
    771  LOG(("nsIOService::OnProcessUnexpectedShutdown\n"));
    772  DestroySocketProcess();
    773  mPendingEvents.Clear();
    774 
    775  // Nothing to do if socket process was not used before.
    776  if (!UseSocketProcess()) {
    777    return;
    778  }
    779 
    780  sSocketProcessCrashedCount++;
    781  if (TooManySocketProcessCrash()) {
    782    sUseSocketProcessChecked = false;
    783    DNSServiceWrapper::SwitchToBackupDNSService();
    784  }
    785 
    786  nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
    787  if (observerService) {
    788    (void)observerService->NotifyObservers(
    789        nullptr, "network:socket-process-crashed", nullptr);
    790  }
    791 
    792  // UseSocketProcess() could return false if we have too many crashes, so we
    793  // should call it again.
    794  if (UseSocketProcess()) {
    795    MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(
    796        NewRunnableMethod("nsIOService::LaunchSocketProcess", this,
    797                          &nsIOService::LaunchSocketProcess)));
    798  }
    799 }
    800 
    801 RefPtr<MemoryReportingProcess> nsIOService::GetSocketProcessMemoryReporter() {
    802  // Check the prefs here again, since we don't want to create
    803  // SocketProcessMemoryReporter for some tests.
    804  if (!StaticPrefs::network_process_enabled() || !SocketProcessReady()) {
    805    return nullptr;
    806  }
    807 
    808  return new SocketProcessMemoryReporter();
    809 }
    810 
    811 NS_IMETHODIMP
    812 nsIOService::SocketProcessTelemetryPing() {
    813  CallOrWaitForSocketProcess([]() {
    814    (void)gIOService->mSocketProcess->GetActor()
    815        ->SendSocketProcessTelemetryPing();
    816  });
    817  return NS_OK;
    818 }
    819 
    820 NS_IMPL_ISUPPORTS(nsIOService, nsIIOService, nsINetUtil, nsISpeculativeConnect,
    821                  nsIObserver, nsIIOServiceInternal, nsISupportsWeakReference,
    822                  nsIObserverService)
    823 
    824 ////////////////////////////////////////////////////////////////////////////////
    825 
    826 nsresult nsIOService::RecheckCaptivePortal() {
    827  MOZ_ASSERT(NS_IsMainThread(), "Must be called on the main thread");
    828  if (!mCaptivePortalService) {
    829    return NS_OK;
    830  }
    831  nsCOMPtr<nsIRunnable> task = NewRunnableMethod(
    832      "nsIOService::RecheckCaptivePortal", mCaptivePortalService,
    833      &nsICaptivePortalService::RecheckCaptivePortal);
    834  return NS_DispatchToMainThread(task);
    835 }
    836 
    837 nsresult nsIOService::RecheckCaptivePortalIfLocalRedirect(nsIChannel* newChan) {
    838  nsresult rv;
    839 
    840  if (!mCaptivePortalService) {
    841    return NS_OK;
    842  }
    843 
    844  nsCOMPtr<nsIURI> uri;
    845  rv = newChan->GetURI(getter_AddRefs(uri));
    846  if (NS_FAILED(rv)) {
    847    return rv;
    848  }
    849 
    850  nsCString host;
    851  rv = uri->GetHost(host);
    852  if (NS_FAILED(rv)) {
    853    return rv;
    854  }
    855 
    856  NetAddr addr;
    857  // If the redirect wasn't to an IP literal, so there's probably no need
    858  // to trigger the captive portal detection right now. It can wait.
    859  if (NS_SUCCEEDED(addr.InitFromString(host)) && addr.IsIPAddrLocal()) {
    860    RecheckCaptivePortal();
    861  }
    862 
    863  return NS_OK;
    864 }
    865 
    866 nsresult nsIOService::AsyncOnChannelRedirect(
    867    nsIChannel* oldChan, nsIChannel* newChan, uint32_t flags,
    868    nsAsyncRedirectVerifyHelper* helper) {
    869  // If a redirect to a local network address occurs, then chances are we
    870  // are in a captive portal, so we trigger a recheck.
    871  RecheckCaptivePortalIfLocalRedirect(newChan);
    872 
    873  // This is silly. I wish there was a simpler way to get at the global
    874  // reference of the contentSecurityManager. But it lives in the XPCOM
    875  // service registry.
    876  nsCOMPtr<nsIChannelEventSink> sink;
    877  sink = mozilla::components::ContentSecurityManager::Service();
    878  if (sink) {
    879    nsresult rv =
    880        helper->DelegateOnChannelRedirect(sink, oldChan, newChan, flags);
    881    if (NS_FAILED(rv)) return rv;
    882  }
    883 
    884  // Finally, our category
    885  nsCOMArray<nsIChannelEventSink> entries;
    886  mChannelEventSinks.GetEntries(entries);
    887  int32_t len = entries.Count();
    888  for (int32_t i = 0; i < len; ++i) {
    889    nsresult rv =
    890        helper->DelegateOnChannelRedirect(entries[i], oldChan, newChan, flags);
    891    if (NS_FAILED(rv)) return rv;
    892  }
    893 
    894  nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(oldChan));
    895 
    896  // Collect the redirection from HTTP(S) only.
    897  if (httpChan) {
    898    MOZ_ASSERT(NS_IsMainThread());
    899    nsCOMPtr<nsIURI> newURI;
    900    newChan->GetURI(getter_AddRefs(newURI));
    901    MOZ_ASSERT(newURI);
    902 
    903    nsAutoCString scheme;
    904    newURI->GetScheme(scheme);
    905    MOZ_ASSERT(!scheme.IsEmpty());
    906 
    907    if (oldChan->IsDocument()) {
    908      mozilla::glean::networking::http_redirect_to_scheme_top_level.Get(scheme)
    909          .Add(1);
    910    } else {
    911      mozilla::glean::networking::http_redirect_to_scheme_subresource
    912          .Get(scheme)
    913          .Add(1);
    914    }
    915  }
    916  return NS_OK;
    917 }
    918 
    919 bool nsIOService::UsesExternalProtocolHandler(const nsACString& aScheme) {
    920  if (aScheme == "file"_ns || aScheme == "chrome"_ns ||
    921      aScheme == "resource"_ns || aScheme == "moz-src"_ns) {
    922    // Don't allow file:, chrome: or resource: URIs to be handled with
    923    // nsExternalProtocolHandler, since internally we rely on being able to
    924    // use and read from these URIs.
    925    return false;
    926  }
    927 
    928  if (aScheme == "place"_ns || aScheme == "fake-favicon-uri"_ns ||
    929      aScheme == "favicon"_ns || aScheme == "moz-nullprincipal"_ns) {
    930    // Force place: fake-favicon-uri: favicon: and moz-nullprincipal: URIs to be
    931    // handled with nsExternalProtocolHandler, and not with a dynamically
    932    // registered handler.
    933    return true;
    934  }
    935 
    936  // If prefs configure the URI to be handled externally, do so.
    937  for (const auto& scheme : mForceExternalSchemes) {
    938    if (aScheme == scheme) {
    939      return true;
    940    }
    941  }
    942  return false;
    943 }
    944 
    945 ProtocolHandlerInfo nsIOService::LookupProtocolHandler(
    946    const nsACString& aScheme) {
    947  // Look-ups are ASCII-case-insensitive, so lower-case the string before
    948  // continuing.
    949  nsAutoCString scheme(aScheme);
    950  ToLowerCase(scheme);
    951 
    952  // NOTE: If we could get rid of mForceExternalSchemes (or prevent them from
    953  // disabling static protocols), we could avoid locking mLock until we need to
    954  // check `mRuntimeProtocolHandlers.
    955  AutoReadLock lock(mLock);
    956  if (!UsesExternalProtocolHandler(scheme)) {
    957    // Try the static protocol handler first - they cannot be overridden by
    958    // dynamic protocols.
    959    if (const xpcom::StaticProtocolHandler* handler =
    960            xpcom::StaticProtocolHandler::Lookup(scheme)) {
    961      return ProtocolHandlerInfo(*handler);
    962    }
    963    if (auto handler = mRuntimeProtocolHandlers.Lookup(scheme)) {
    964      return ProtocolHandlerInfo(handler.Data());
    965    }
    966  }
    967  return ProtocolHandlerInfo(xpcom::StaticProtocolHandler::Default());
    968 }
    969 
    970 NS_IMETHODIMP
    971 nsIOService::GetProtocolHandler(const char* scheme,
    972                                nsIProtocolHandler** result) {
    973  AssertIsOnMainThread();
    974  NS_ENSURE_ARG_POINTER(scheme);
    975 
    976  *result = LookupProtocolHandler(nsDependentCString(scheme)).Handler().take();
    977  return *result ? NS_OK : NS_ERROR_UNKNOWN_PROTOCOL;
    978 }
    979 
    980 NS_IMETHODIMP
    981 nsIOService::ExtractScheme(const nsACString& inURI, nsACString& scheme) {
    982  return net_ExtractURLScheme(inURI, scheme);
    983 }
    984 
    985 NS_IMETHODIMP
    986 nsIOService::HostnameIsLocalIPAddress(nsIURI* aURI, bool* aResult) {
    987  NS_ENSURE_ARG_POINTER(aURI);
    988 
    989  nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(aURI);
    990  NS_ENSURE_ARG_POINTER(innerURI);
    991 
    992  nsAutoCString host;
    993  nsresult rv = innerURI->GetAsciiHost(host);
    994  if (NS_FAILED(rv)) {
    995    return rv;
    996  }
    997 
    998  *aResult = false;
    999 
   1000  NetAddr addr;
   1001  if (NS_SUCCEEDED(addr.InitFromString(host)) && addr.IsIPAddrLocal()) {
   1002    *aResult = true;
   1003  }
   1004 
   1005  return NS_OK;
   1006 }
   1007 
   1008 NS_IMETHODIMP
   1009 nsIOService::HostnameIsIPAddressAny(nsIURI* aURI, bool* aResult) {
   1010  NS_ENSURE_ARG_POINTER(aURI);
   1011 
   1012  nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(aURI);
   1013  NS_ENSURE_ARG_POINTER(innerURI);
   1014 
   1015  nsAutoCString host;
   1016  nsresult rv = innerURI->GetAsciiHost(host);
   1017  if (NS_FAILED(rv)) {
   1018    return rv;
   1019  }
   1020 
   1021  *aResult = false;
   1022 
   1023  NetAddr addr;
   1024  if (NS_SUCCEEDED(addr.InitFromString(host)) && addr.IsIPAddrAny()) {
   1025    *aResult = true;
   1026  }
   1027 
   1028  return NS_OK;
   1029 }
   1030 
   1031 NS_IMETHODIMP
   1032 nsIOService::HostnameIsSharedIPAddress(nsIURI* aURI, bool* aResult) {
   1033  NS_ENSURE_ARG_POINTER(aURI);
   1034 
   1035  nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(aURI);
   1036  NS_ENSURE_ARG_POINTER(innerURI);
   1037 
   1038  nsAutoCString host;
   1039  nsresult rv = innerURI->GetAsciiHost(host);
   1040  if (NS_FAILED(rv)) {
   1041    return rv;
   1042  }
   1043 
   1044  *aResult = false;
   1045 
   1046  NetAddr addr;
   1047  if (NS_SUCCEEDED(addr.InitFromString(host)) && addr.IsIPAddrShared()) {
   1048    *aResult = true;
   1049  }
   1050 
   1051  return NS_OK;
   1052 }
   1053 
   1054 NS_IMETHODIMP
   1055 nsIOService::IsValidHostname(const nsACString& inHostname, bool* aResult) {
   1056  if (!net_IsValidDNSHost(inHostname)) {
   1057    *aResult = false;
   1058    return NS_OK;
   1059  }
   1060 
   1061  // hostname ending with a "." delimited octet that is a number
   1062  // must be IPv4 or IPv6 dual address
   1063  nsAutoCString host(inHostname);
   1064  if (IPv4Parser::EndsInANumber(host)) {
   1065    // ipv6 dual address; for example "::1.2.3.4"
   1066    if (net_IsValidIPv6Addr(host)) {
   1067      *aResult = true;
   1068      return NS_OK;
   1069    }
   1070 
   1071    nsAutoCString normalized;
   1072    nsresult rv = IPv4Parser::NormalizeIPv4(host, normalized);
   1073    if (NS_FAILED(rv)) {
   1074      *aResult = false;
   1075      return NS_OK;
   1076    }
   1077  }
   1078  *aResult = true;
   1079  return NS_OK;
   1080 }
   1081 
   1082 NS_IMETHODIMP
   1083 nsIOService::GetProtocolFlags(const char* scheme, uint32_t* flags) {
   1084  NS_ENSURE_ARG_POINTER(scheme);
   1085 
   1086  *flags =
   1087      LookupProtocolHandler(nsDependentCString(scheme)).StaticProtocolFlags();
   1088  return NS_OK;
   1089 }
   1090 
   1091 NS_IMETHODIMP
   1092 nsIOService::GetDynamicProtocolFlags(nsIURI* uri, uint32_t* flags) {
   1093  AssertIsOnMainThread();
   1094  NS_ENSURE_ARG(uri);
   1095 
   1096  nsAutoCString scheme;
   1097  nsresult rv = uri->GetScheme(scheme);
   1098  NS_ENSURE_SUCCESS(rv, rv);
   1099 
   1100  return LookupProtocolHandler(scheme).DynamicProtocolFlags(uri, flags);
   1101 }
   1102 
   1103 NS_IMETHODIMP
   1104 nsIOService::GetDefaultPort(const char* scheme, int32_t* defaultPort) {
   1105  NS_ENSURE_ARG_POINTER(scheme);
   1106 
   1107  *defaultPort =
   1108      LookupProtocolHandler(nsDependentCString(scheme)).DefaultPort();
   1109  return NS_OK;
   1110 }
   1111 
   1112 nsresult nsIOService::NewURI(const nsACString& aSpec, const char* aCharset,
   1113                             nsIURI* aBaseURI, nsIURI** result) {
   1114  return NS_NewURI(result, aSpec, aCharset, aBaseURI);
   1115 }
   1116 
   1117 NS_IMETHODIMP
   1118 nsIOService::NewFileURI(nsIFile* file, nsIURI** result) {
   1119  nsresult rv;
   1120  NS_ENSURE_ARG_POINTER(file);
   1121 
   1122  nsCOMPtr<nsIProtocolHandler> handler;
   1123 
   1124  rv = GetProtocolHandler("file", getter_AddRefs(handler));
   1125  if (NS_FAILED(rv)) return rv;
   1126 
   1127  nsCOMPtr<nsIFileProtocolHandler> fileHandler(do_QueryInterface(handler, &rv));
   1128  if (NS_FAILED(rv)) return rv;
   1129 
   1130  return fileHandler->NewFileURI(file, result);
   1131 }
   1132 
   1133 // static
   1134 already_AddRefed<nsIURI> nsIOService::CreateExposableURI(nsIURI* aURI) {
   1135  MOZ_ASSERT(aURI, "Must have a URI");
   1136  nsCOMPtr<nsIURI> uri = aURI;
   1137  bool hasUserPass;
   1138  if (NS_SUCCEEDED(aURI->GetHasUserPass(&hasUserPass)) && hasUserPass) {
   1139    DebugOnly<nsresult> rv = NS_MutateURI(uri).SetUserPass(""_ns).Finalize(uri);
   1140    MOZ_ASSERT(NS_SUCCEEDED(rv) && uri, "Mutating URI should never fail");
   1141  }
   1142  return uri.forget();
   1143 }
   1144 
   1145 NS_IMETHODIMP
   1146 nsIOService::CreateExposableURI(nsIURI* aURI, nsIURI** _result) {
   1147  NS_ENSURE_ARG_POINTER(aURI);
   1148  NS_ENSURE_ARG_POINTER(_result);
   1149  nsCOMPtr<nsIURI> exposableURI = CreateExposableURI(aURI);
   1150  exposableURI.forget(_result);
   1151  return NS_OK;
   1152 }
   1153 
   1154 NS_IMETHODIMP
   1155 nsIOService::NewChannelFromURI(nsIURI* aURI, nsINode* aLoadingNode,
   1156                               nsIPrincipal* aLoadingPrincipal,
   1157                               nsIPrincipal* aTriggeringPrincipal,
   1158                               uint32_t aSecurityFlags,
   1159                               nsContentPolicyType aContentPolicyType,
   1160                               nsIChannel** result) {
   1161  return NewChannelFromURIWithProxyFlags(aURI,
   1162                                         nullptr,  // aProxyURI
   1163                                         0,        // aProxyFlags
   1164                                         aLoadingNode, aLoadingPrincipal,
   1165                                         aTriggeringPrincipal, aSecurityFlags,
   1166                                         aContentPolicyType, result);
   1167 }
   1168 nsresult nsIOService::NewChannelFromURIWithClientAndController(
   1169    nsIURI* aURI, nsINode* aLoadingNode, nsIPrincipal* aLoadingPrincipal,
   1170    nsIPrincipal* aTriggeringPrincipal,
   1171    const Maybe<ClientInfo>& aLoadingClientInfo,
   1172    const Maybe<ServiceWorkerDescriptor>& aController, uint32_t aSecurityFlags,
   1173    nsContentPolicyType aContentPolicyType, uint32_t aSandboxFlags,
   1174    nsIChannel** aResult) {
   1175  return NewChannelFromURIWithProxyFlagsInternal(
   1176      aURI,
   1177      nullptr,  // aProxyURI
   1178      0,        // aProxyFlags
   1179      aLoadingNode, aLoadingPrincipal, aTriggeringPrincipal, aLoadingClientInfo,
   1180      aController, aSecurityFlags, aContentPolicyType, aSandboxFlags, aResult);
   1181 }
   1182 
   1183 NS_IMETHODIMP
   1184 nsIOService::NewChannelFromURIWithLoadInfo(nsIURI* aURI, nsILoadInfo* aLoadInfo,
   1185                                           nsIChannel** result) {
   1186  return NewChannelFromURIWithProxyFlagsInternal(aURI,
   1187                                                 nullptr,  // aProxyURI
   1188                                                 0,        // aProxyFlags
   1189                                                 aLoadInfo, result);
   1190 }
   1191 
   1192 nsresult nsIOService::NewChannelFromURIWithProxyFlagsInternal(
   1193    nsIURI* aURI, nsIURI* aProxyURI, uint32_t aProxyFlags,
   1194    nsINode* aLoadingNode, nsIPrincipal* aLoadingPrincipal,
   1195    nsIPrincipal* aTriggeringPrincipal,
   1196    const Maybe<ClientInfo>& aLoadingClientInfo,
   1197    const Maybe<ServiceWorkerDescriptor>& aController, uint32_t aSecurityFlags,
   1198    nsContentPolicyType aContentPolicyType, uint32_t aSandboxFlags,
   1199    nsIChannel** result) {
   1200  nsCOMPtr<nsILoadInfo> loadInfo = MOZ_TRY(LoadInfo::Create(
   1201      aLoadingPrincipal, aTriggeringPrincipal, aLoadingNode, aSecurityFlags,
   1202      aContentPolicyType, aLoadingClientInfo, aController, aSandboxFlags));
   1203  return NewChannelFromURIWithProxyFlagsInternal(aURI, aProxyURI, aProxyFlags,
   1204                                                 loadInfo, result);
   1205 }
   1206 
   1207 nsresult nsIOService::NewChannelFromURIWithProxyFlagsInternal(
   1208    nsIURI* aURI, nsIURI* aProxyURI, uint32_t aProxyFlags,
   1209    nsILoadInfo* aLoadInfo, nsIChannel** result) {
   1210  nsresult rv;
   1211  NS_ENSURE_ARG_POINTER(aURI);
   1212  // all channel creations must provide a valid loadinfo
   1213  MOZ_ASSERT(aLoadInfo, "can not create channel without aLoadInfo");
   1214  NS_ENSURE_ARG_POINTER(aLoadInfo);
   1215 
   1216  nsAutoCString scheme;
   1217  rv = aURI->GetScheme(scheme);
   1218  if (NS_FAILED(rv)) return rv;
   1219 
   1220  nsCOMPtr<nsIProtocolHandler> handler;
   1221  rv = GetProtocolHandler(scheme.get(), getter_AddRefs(handler));
   1222  if (NS_FAILED(rv)) return rv;
   1223 
   1224  nsCOMPtr<nsIChannel> channel;
   1225  nsCOMPtr<nsIProxiedProtocolHandler> pph = do_QueryInterface(handler);
   1226  if (pph) {
   1227    rv = pph->NewProxiedChannel(aURI, nullptr, aProxyFlags, aProxyURI,
   1228                                aLoadInfo, getter_AddRefs(channel));
   1229  } else {
   1230    rv = handler->NewChannel(aURI, aLoadInfo, getter_AddRefs(channel));
   1231  }
   1232  if (NS_FAILED(rv)) return rv;
   1233 
   1234  // Make sure that all the individual protocolhandlers attach a loadInfo.
   1235  nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
   1236  if (aLoadInfo != loadInfo) {
   1237    MOZ_ASSERT(false, "newly created channel must have a loadinfo attached");
   1238    return NS_ERROR_UNEXPECTED;
   1239  }
   1240 
   1241  // If we're sandboxed, make sure to clear any owner the channel
   1242  // might already have.
   1243  if (loadInfo->GetLoadingSandboxed()) {
   1244    channel->SetOwner(nullptr);
   1245  }
   1246  channel.forget(result);
   1247  return NS_OK;
   1248 }
   1249 
   1250 NS_IMETHODIMP
   1251 nsIOService::NewChannelFromURIWithProxyFlags(
   1252    nsIURI* aURI, nsIURI* aProxyURI, uint32_t aProxyFlags,
   1253    nsINode* aLoadingNode, nsIPrincipal* aLoadingPrincipal,
   1254    nsIPrincipal* aTriggeringPrincipal, uint32_t aSecurityFlags,
   1255    nsContentPolicyType aContentPolicyType, nsIChannel** result) {
   1256  return NewChannelFromURIWithProxyFlagsInternal(
   1257      aURI, aProxyURI, aProxyFlags, aLoadingNode, aLoadingPrincipal,
   1258      aTriggeringPrincipal, Maybe<ClientInfo>(),
   1259      Maybe<ServiceWorkerDescriptor>(), aSecurityFlags, aContentPolicyType, 0,
   1260      result);
   1261 }
   1262 
   1263 NS_IMETHODIMP
   1264 nsIOService::NewChannel(const nsACString& aSpec, const char* aCharset,
   1265                        nsIURI* aBaseURI, nsINode* aLoadingNode,
   1266                        nsIPrincipal* aLoadingPrincipal,
   1267                        nsIPrincipal* aTriggeringPrincipal,
   1268                        uint32_t aSecurityFlags,
   1269                        nsContentPolicyType aContentPolicyType,
   1270                        nsIChannel** result) {
   1271  nsresult rv;
   1272  nsCOMPtr<nsIURI> uri;
   1273  rv = NewURI(aSpec, aCharset, aBaseURI, getter_AddRefs(uri));
   1274  if (NS_FAILED(rv)) return rv;
   1275 
   1276  return NewChannelFromURI(uri, aLoadingNode, aLoadingPrincipal,
   1277                           aTriggeringPrincipal, aSecurityFlags,
   1278                           aContentPolicyType, result);
   1279 }
   1280 
   1281 NS_IMETHODIMP
   1282 nsIOService::NewSuspendableChannelWrapper(
   1283    nsIChannel* aInnerChannel, nsISuspendableChannelWrapper** result) {
   1284  NS_ENSURE_ARG_POINTER(aInnerChannel);
   1285 
   1286  nsCOMPtr<nsISuspendableChannelWrapper> wrapper =
   1287      new SuspendableChannelWrapper(aInnerChannel);
   1288  wrapper.forget(result);
   1289  return NS_OK;
   1290 }
   1291 
   1292 NS_IMETHODIMP
   1293 nsIOService::NewWebTransport(nsIWebTransport** result) {
   1294  if (!XRE_IsParentProcess()) {
   1295    return NS_ERROR_NOT_AVAILABLE;
   1296  }
   1297 
   1298  nsCOMPtr<nsIWebTransport> webTransport = new WebTransportSessionProxy();
   1299 
   1300  webTransport.forget(result);
   1301  return NS_OK;
   1302 }
   1303 
   1304 NS_IMETHODIMP
   1305 nsIOService::OriginAttributesForNetworkState(
   1306    nsIChannel* aChannel, JSContext* cx, JS::MutableHandle<JS::Value> _retval) {
   1307  OriginAttributes attrs;
   1308  if (!StoragePrincipalHelper::GetOriginAttributesForNetworkState(aChannel,
   1309                                                                  attrs)) {
   1310    return NS_ERROR_FAILURE;
   1311  }
   1312 
   1313  if (NS_WARN_IF(!mozilla::dom::ToJSValue(cx, attrs, _retval))) {
   1314    return NS_ERROR_FAILURE;
   1315  }
   1316 
   1317  return NS_OK;
   1318 }
   1319 
   1320 bool nsIOService::IsLinkUp() {
   1321  InitializeNetworkLinkService();
   1322 
   1323  if (!mNetworkLinkService) {
   1324    // We cannot decide, assume the link is up
   1325    return true;
   1326  }
   1327 
   1328  bool isLinkUp;
   1329  nsresult rv;
   1330  rv = mNetworkLinkService->GetIsLinkUp(&isLinkUp);
   1331  if (NS_FAILED(rv)) {
   1332    return true;
   1333  }
   1334 
   1335  return isLinkUp;
   1336 }
   1337 
   1338 NS_IMETHODIMP
   1339 nsIOService::GetOffline(bool* offline) {
   1340  if (StaticPrefs::network_offline_mirrors_connectivity()) {
   1341    *offline = mOffline || !mConnectivity;
   1342  } else {
   1343    *offline = mOffline;
   1344  }
   1345  return NS_OK;
   1346 }
   1347 
   1348 NS_IMETHODIMP
   1349 nsIOService::SetOffline(bool offline) { return SetOfflineInternal(offline); }
   1350 
   1351 nsresult nsIOService::SetOfflineInternal(bool offline,
   1352                                         bool notifySocketProcess) {
   1353  LOG(("nsIOService::SetOffline offline=%d\n", offline));
   1354  // When someone wants to go online (!offline) after we got XPCOM shutdown
   1355  // throw ERROR_NOT_AVAILABLE to prevent return to online state.
   1356  if ((mShutdown || mOfflineForProfileChange) && !offline) {
   1357    return NS_ERROR_NOT_AVAILABLE;
   1358  }
   1359 
   1360  // SetOffline() may re-enter while it's shutting down services.
   1361  // If that happens, save the most recent value and it will be
   1362  // processed when the first SetOffline() call is done bringing
   1363  // down the service.
   1364  mSetOfflineValue = offline;
   1365  if (mSettingOffline) {
   1366    return NS_OK;
   1367  }
   1368 
   1369  mSettingOffline = true;
   1370 
   1371  nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
   1372 
   1373  NS_ASSERTION(observerService, "The observer service should not be null");
   1374 
   1375  if (XRE_IsParentProcess()) {
   1376    if (observerService) {
   1377      (void)observerService->NotifyObservers(nullptr,
   1378                                             NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC,
   1379                                             offline ? u"true" : u"false");
   1380    }
   1381    if (SocketProcessReady() && notifySocketProcess) {
   1382      (void)mSocketProcess->GetActor()->SendSetOffline(offline);
   1383    }
   1384  }
   1385 
   1386  nsIIOService* subject = static_cast<nsIIOService*>(this);
   1387  while (mSetOfflineValue != mOffline) {
   1388    offline = mSetOfflineValue;
   1389 
   1390    if (offline && !mOffline) {
   1391      mOffline = true;  // indicate we're trying to shutdown
   1392 
   1393      // don't care if notifications fail
   1394      if (observerService) {
   1395        observerService->NotifyObservers(subject,
   1396                                         NS_IOSERVICE_GOING_OFFLINE_TOPIC,
   1397                                         u"" NS_IOSERVICE_OFFLINE);
   1398      }
   1399 
   1400      if (mSocketTransportService) mSocketTransportService->SetOffline(true);
   1401 
   1402      mLastOfflineStateChange = PR_IntervalNow();
   1403      if (observerService) {
   1404        observerService->NotifyObservers(subject,
   1405                                         NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
   1406                                         u"" NS_IOSERVICE_OFFLINE);
   1407      }
   1408    } else if (!offline && mOffline) {
   1409      // go online
   1410      InitializeSocketTransportService();
   1411      mOffline = false;  // indicate success only AFTER we've
   1412                         // brought up the services
   1413 
   1414      mLastOfflineStateChange = PR_IntervalNow();
   1415      // don't care if notification fails
   1416      // Only send the ONLINE notification if there is connectivity
   1417      if (observerService && mConnectivity) {
   1418        observerService->NotifyObservers(subject,
   1419                                         NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
   1420                                         (u"" NS_IOSERVICE_ONLINE));
   1421      }
   1422    }
   1423  }
   1424 
   1425  // Don't notify here, as the above notifications (if used) suffice.
   1426  if ((mShutdown || mOfflineForProfileChange) && mOffline) {
   1427    if (mSocketTransportService) {
   1428      DebugOnly<nsresult> rv = mSocketTransportService->Shutdown(mShutdown);
   1429      NS_ASSERTION(NS_SUCCEEDED(rv),
   1430                   "socket transport service shutdown failed");
   1431    }
   1432  }
   1433 
   1434  mSettingOffline = false;
   1435 
   1436  return NS_OK;
   1437 }
   1438 
   1439 NS_IMETHODIMP
   1440 nsIOService::GetConnectivity(bool* aConnectivity) {
   1441  *aConnectivity = mConnectivity;
   1442  return NS_OK;
   1443 }
   1444 
   1445 NS_IMETHODIMP
   1446 nsIOService::SetConnectivity(bool aConnectivity) {
   1447  LOG(("nsIOService::SetConnectivity aConnectivity=%d\n", aConnectivity));
   1448  // This should only be called from ContentChild to pass the connectivity
   1449  // value from the chrome process to the content process.
   1450  if (XRE_IsParentProcess()) {
   1451    return NS_ERROR_NOT_AVAILABLE;
   1452  }
   1453  return SetConnectivityInternal(aConnectivity);
   1454 }
   1455 
   1456 NS_IMETHODIMP
   1457 nsIOService::SetConnectivityForTesting(bool aConnectivity) {
   1458  return SetConnectivityInternal(aConnectivity);
   1459 }
   1460 
   1461 nsresult nsIOService::SetConnectivityInternal(bool aConnectivity) {
   1462  LOG(("nsIOService::SetConnectivityInternal aConnectivity=%d\n",
   1463       aConnectivity));
   1464  if (mConnectivity == aConnectivity) {
   1465    // Nothing to do here.
   1466    return NS_OK;
   1467  }
   1468  mConnectivity = aConnectivity;
   1469 
   1470  // This is used for PR_Connect PR_Close telemetry so it is important that
   1471  // we have statistic about network change event even if we are offline.
   1472  mLastConnectivityChange = PR_IntervalNow();
   1473 
   1474  if (mCaptivePortalService) {
   1475    if (aConnectivity && gCaptivePortalEnabled) {
   1476      // This will also trigger a captive portal check for the new network
   1477      static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Start();
   1478    } else {
   1479      static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Stop();
   1480    }
   1481  }
   1482 
   1483  nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
   1484  if (!observerService) {
   1485    return NS_OK;
   1486  }
   1487  // This notification sends the connectivity to the child processes
   1488  if (XRE_IsParentProcess()) {
   1489    observerService->NotifyObservers(nullptr,
   1490                                     NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC,
   1491                                     aConnectivity ? u"true" : u"false");
   1492    if (SocketProcessReady()) {
   1493      (void)mSocketProcess->GetActor()->SendSetConnectivity(aConnectivity);
   1494    }
   1495  }
   1496 
   1497  if (mOffline) {
   1498    // We don't need to send any notifications if we're offline
   1499    return NS_OK;
   1500  }
   1501 
   1502  if (aConnectivity) {
   1503    // If we were previously offline due to connectivity=false,
   1504    // send the ONLINE notification
   1505    observerService->NotifyObservers(static_cast<nsIIOService*>(this),
   1506                                     NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
   1507                                     (u"" NS_IOSERVICE_ONLINE));
   1508  } else {
   1509    // If we were previously online and lost connectivity
   1510    // send the OFFLINE notification
   1511    observerService->NotifyObservers(static_cast<nsIIOService*>(this),
   1512                                     NS_IOSERVICE_GOING_OFFLINE_TOPIC,
   1513                                     u"" NS_IOSERVICE_OFFLINE);
   1514    observerService->NotifyObservers(static_cast<nsIIOService*>(this),
   1515                                     NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
   1516                                     u"" NS_IOSERVICE_OFFLINE);
   1517  }
   1518  return NS_OK;
   1519 }
   1520 
   1521 NS_IMETHODIMP
   1522 nsIOService::AllowPort(int32_t inPort, const char* scheme, bool* _retval) {
   1523  int32_t port = inPort;
   1524  if (port == -1) {
   1525    *_retval = true;
   1526    return NS_OK;
   1527  }
   1528 
   1529  if (port <= 0 || port > std::numeric_limits<uint16_t>::max()) {
   1530    *_retval = false;
   1531    return NS_OK;
   1532  }
   1533 
   1534  nsTArray<int32_t> restrictedPortList;
   1535  {
   1536    AutoReadLock lock(mLock);
   1537    restrictedPortList.Assign(mRestrictedPortList);
   1538  }
   1539  // first check to see if the port is in our blacklist:
   1540  int32_t badPortListCnt = restrictedPortList.Length();
   1541  for (int i = 0; i < badPortListCnt; i++) {
   1542    if (port == restrictedPortList[i]) {
   1543      *_retval = false;
   1544 
   1545      // check to see if the protocol wants to override
   1546      if (!scheme) return NS_OK;
   1547 
   1548      // We don't support get protocol handler off main thread.
   1549      if (!NS_IsMainThread()) {
   1550        return NS_OK;
   1551      }
   1552      nsCOMPtr<nsIProtocolHandler> handler;
   1553      nsresult rv = GetProtocolHandler(scheme, getter_AddRefs(handler));
   1554      if (NS_FAILED(rv)) return rv;
   1555 
   1556      // let the protocol handler decide
   1557      return handler->AllowPort(port, scheme, _retval);
   1558    }
   1559  }
   1560 
   1561  *_retval = true;
   1562  return NS_OK;
   1563 }
   1564 
   1565 ////////////////////////////////////////////////////////////////////////////////
   1566 
   1567 // static
   1568 void nsIOService::PrefsChanged(const char* pref, void* self) {
   1569  static_cast<nsIOService*>(self)->PrefsChanged(pref);
   1570 }
   1571 
   1572 void nsIOService::PrefsChanged(const char* pref) {
   1573  // Look for extra ports to block
   1574  if (!pref || strcmp(pref, PORT_PREF("banned")) == 0) {
   1575    ParsePortList(PORT_PREF("banned"), false);
   1576  }
   1577 
   1578  // ...as well as previous blocks to remove.
   1579  if (!pref || strcmp(pref, PORT_PREF("banned.override")) == 0) {
   1580    ParsePortList(PORT_PREF("banned.override"), true);
   1581  }
   1582 
   1583  if (!pref || strcmp(pref, MANAGE_OFFLINE_STATUS_PREF) == 0) {
   1584    bool manage;
   1585    if (mNetworkLinkServiceInitialized &&
   1586        NS_SUCCEEDED(
   1587            Preferences::GetBool(MANAGE_OFFLINE_STATUS_PREF, &manage))) {
   1588      LOG(("nsIOService::PrefsChanged ManageOfflineStatus manage=%d\n",
   1589           manage));
   1590      SetManageOfflineStatus(manage);
   1591    }
   1592  }
   1593 
   1594  if (!pref || strcmp(pref, NECKO_BUFFER_CACHE_COUNT_PREF) == 0) {
   1595    int32_t count;
   1596    if (NS_SUCCEEDED(
   1597            Preferences::GetInt(NECKO_BUFFER_CACHE_COUNT_PREF, &count))) {
   1598      /* check for bogus values and default if we find such a value */
   1599      if (count > 0) gDefaultSegmentCount = count;
   1600    }
   1601  }
   1602 
   1603  if (!pref || strcmp(pref, NECKO_BUFFER_CACHE_SIZE_PREF) == 0) {
   1604    int32_t size;
   1605    if (NS_SUCCEEDED(
   1606            Preferences::GetInt(NECKO_BUFFER_CACHE_SIZE_PREF, &size))) {
   1607      /* check for bogus values and default if we find such a value
   1608       * the upper limit here is arbitrary. having a 1mb segment size
   1609       * is pretty crazy.  if you remove this, consider adding some
   1610       * integer rollover test.
   1611       */
   1612      if (size > 0 && size < 1024 * 1024) gDefaultSegmentSize = size;
   1613    }
   1614    NS_WARNING_ASSERTION(!(size & (size - 1)),
   1615                         "network segment size is not a power of 2!");
   1616  }
   1617 
   1618  if (!pref || strcmp(pref, NETWORK_CAPTIVE_PORTAL_PREF) == 0) {
   1619    nsresult rv = Preferences::GetBool(NETWORK_CAPTIVE_PORTAL_PREF,
   1620                                       &gCaptivePortalEnabled);
   1621    if (NS_SUCCEEDED(rv) && mCaptivePortalService) {
   1622      if (gCaptivePortalEnabled) {
   1623        static_cast<CaptivePortalService*>(mCaptivePortalService.get())
   1624            ->Start();
   1625      } else {
   1626        static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Stop();
   1627      }
   1628    }
   1629  }
   1630 
   1631  if (!pref || strncmp(pref, FORCE_EXTERNAL_PREF_PREFIX,
   1632                       strlen(FORCE_EXTERNAL_PREF_PREFIX)) == 0) {
   1633    nsTArray<nsCString> prefs;
   1634    if (nsIPrefBranch* prefRootBranch = Preferences::GetRootBranch()) {
   1635      prefRootBranch->GetChildList(FORCE_EXTERNAL_PREF_PREFIX, prefs);
   1636    }
   1637    nsTArray<nsCString> forceExternalSchemes;
   1638    for (const auto& pref : prefs) {
   1639      if (Preferences::GetBool(pref.get(), false)) {
   1640        forceExternalSchemes.AppendElement(
   1641            Substring(pref, strlen(FORCE_EXTERNAL_PREF_PREFIX)));
   1642      }
   1643    }
   1644    AutoWriteLock lock(mLock);
   1645    mForceExternalSchemes = std::move(forceExternalSchemes);
   1646  }
   1647 
   1648  if (!pref || strncmp(pref, SIMPLE_URI_SCHEMES_PREF,
   1649                       strlen(SIMPLE_URI_SCHEMES_PREF)) == 0) {
   1650    LOG(("simple_uri_unknown_schemes pref changed, updating the scheme list"));
   1651    mSimpleURIUnknownSchemes.ParseAndMergePrefSchemes();
   1652    // runs on parent and child, no need to broadcast
   1653  }
   1654 
   1655  if (!pref || strncmp(pref, PREF_LNA_IP_ADDR_SPACE_PUBLIC,
   1656                       strlen(PREF_LNA_IP_ADDR_SPACE_PUBLIC)) == 0) {
   1657    AutoWriteLock lock(mLock);
   1658    UpdateAddressSpaceOverrideList(PREF_LNA_IP_ADDR_SPACE_PUBLIC,
   1659                                   mPublicAddressSpaceOverridesList);
   1660  }
   1661 
   1662  if (!pref || strncmp(pref, PREF_LNA_IP_ADDR_SPACE_PRIVATE,
   1663                       strlen(PREF_LNA_IP_ADDR_SPACE_PRIVATE)) == 0) {
   1664    AutoWriteLock lock(mLock);
   1665    UpdateAddressSpaceOverrideList(PREF_LNA_IP_ADDR_SPACE_PRIVATE,
   1666                                   mPrivateAddressSpaceOverridesList);
   1667  }
   1668  if (!pref || strncmp(pref, PREF_LNA_IP_ADDR_SPACE_LOCAL,
   1669                       strlen(PREF_LNA_IP_ADDR_SPACE_LOCAL)) == 0) {
   1670    AutoWriteLock lock(mLock);
   1671    UpdateAddressSpaceOverrideList(PREF_LNA_IP_ADDR_SPACE_LOCAL,
   1672                                   mLocalAddressSpaceOverrideList);
   1673  }
   1674  if (!pref || strncmp(pref, PREF_LNA_SKIP_DOMAINS,
   1675                       strlen(PREF_LNA_SKIP_DOMAINS)) == 0) {
   1676    UpdateSkipDomainsList();
   1677  }
   1678 }
   1679 
   1680 void nsIOService::UpdateAddressSpaceOverrideList(
   1681    const char* aPrefName, nsTArray<nsCString>& aTargetList) {
   1682  nsAutoCString aAddressSpaceOverrides;
   1683  Preferences::GetCString(aPrefName, aAddressSpaceOverrides);
   1684 
   1685  nsTArray<nsCString> addressSpaceOverridesArray;
   1686  nsCCharSeparatedTokenizer tokenizer(aAddressSpaceOverrides, ',');
   1687  while (tokenizer.hasMoreTokens()) {
   1688    nsAutoCString token(tokenizer.nextToken());
   1689    token.StripWhitespace();
   1690    addressSpaceOverridesArray.AppendElement(token);
   1691  }
   1692 
   1693  aTargetList = std::move(addressSpaceOverridesArray);
   1694 }
   1695 
   1696 void nsIOService::UpdateSkipDomainsList() {
   1697  nsAutoCString skipDomains;
   1698  Preferences::GetCString(PREF_LNA_SKIP_DOMAINS, skipDomains);
   1699 
   1700  nsTArray<nsCString> skipDomainsArray;
   1701  nsCCharSeparatedTokenizer tokenizer(skipDomains, ',');
   1702  while (tokenizer.hasMoreTokens()) {
   1703    nsAutoCString token(tokenizer.nextToken());
   1704    token.StripWhitespace();
   1705    if (!token.IsEmpty()) {
   1706      skipDomainsArray.AppendElement(token);
   1707    }
   1708  }
   1709 
   1710  AutoWriteLock lock(mLock);
   1711  mLNASkipDomainsList = std::move(skipDomainsArray);
   1712 }
   1713 
   1714 bool nsIOService::ShouldSkipDomainForLNA(const nsACString& aDomain) {
   1715  AutoReadLock lock(mLock);
   1716 
   1717  // Check each domain pattern
   1718  for (const auto& pattern : mLNASkipDomainsList) {
   1719    // Special case: plain "*" matches all domains
   1720    if (pattern.Equals("*"_ns)) {
   1721      return true;
   1722    }
   1723 
   1724    // Suffix wildcard pattern (starts with *.)
   1725    if (StringBeginsWith(pattern, "*."_ns)) {
   1726      nsDependentCSubstring suffix(Substring(pattern, 2));
   1727      nsDependentCSubstring suffixWithDot(Substring(pattern, 1));
   1728      if (aDomain == suffix || StringEndsWith(aDomain, suffixWithDot)) {
   1729        return true;
   1730      }
   1731    }
   1732 
   1733    // Exact match
   1734    if (pattern == aDomain) {
   1735      return true;
   1736    }
   1737  }
   1738 
   1739  return false;
   1740 }
   1741 
   1742 void nsIOService::ParsePortList(const char* pref, bool remove) {
   1743  nsAutoCString portList;
   1744  nsTArray<int32_t> restrictedPortList;
   1745  {
   1746    AutoWriteLock lock(mLock);
   1747    restrictedPortList.Assign(std::move(mRestrictedPortList));
   1748  }
   1749  // Get a pref string and chop it up into a list of ports.
   1750  Preferences::GetCString(pref, portList);
   1751  if (!portList.IsVoid()) {
   1752    nsTArray<nsCString> portListArray;
   1753    ParseString(portList, ',', portListArray);
   1754    uint32_t index;
   1755    for (index = 0; index < portListArray.Length(); index++) {
   1756      portListArray[index].StripWhitespace();
   1757      int32_t portBegin, portEnd;
   1758 
   1759      if (PR_sscanf(portListArray[index].get(), "%d-%d", &portBegin,
   1760                    &portEnd) == 2) {
   1761        if ((portBegin < 65536) && (portEnd < 65536)) {
   1762          int32_t curPort;
   1763          if (remove) {
   1764            for (curPort = portBegin; curPort <= portEnd; curPort++) {
   1765              restrictedPortList.RemoveElement(curPort);
   1766            }
   1767          } else {
   1768            for (curPort = portBegin; curPort <= portEnd; curPort++) {
   1769              restrictedPortList.AppendElement(curPort);
   1770            }
   1771          }
   1772        }
   1773      } else {
   1774        nsresult aErrorCode;
   1775        int32_t port = portListArray[index].ToInteger(&aErrorCode);
   1776        if (NS_SUCCEEDED(aErrorCode) && port < 65536) {
   1777          if (remove) {
   1778            restrictedPortList.RemoveElement(port);
   1779          } else {
   1780            restrictedPortList.AppendElement(port);
   1781          }
   1782        }
   1783      }
   1784    }
   1785  }
   1786 
   1787  AutoWriteLock lock(mLock);
   1788  mRestrictedPortList.Assign(std::move(restrictedPortList));
   1789 }
   1790 
   1791 class nsWakeupNotifier : public Runnable {
   1792 public:
   1793  explicit nsWakeupNotifier(nsIIOServiceInternal* ioService)
   1794      : Runnable("net::nsWakeupNotifier"), mIOService(ioService) {}
   1795 
   1796  NS_IMETHOD Run() override { return mIOService->NotifyWakeup(); }
   1797 
   1798 private:
   1799  virtual ~nsWakeupNotifier() = default;
   1800  nsCOMPtr<nsIIOServiceInternal> mIOService;
   1801 };
   1802 
   1803 NS_IMETHODIMP
   1804 nsIOService::NotifyWakeup() {
   1805  nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
   1806 
   1807  NS_ASSERTION(observerService, "The observer service should not be null");
   1808 
   1809  if (observerService && StaticPrefs::network_notify_changed()) {
   1810    (void)observerService->NotifyObservers(nullptr, NS_NETWORK_LINK_TOPIC,
   1811                                           (u"" NS_NETWORK_LINK_DATA_CHANGED));
   1812  }
   1813 
   1814  RecheckCaptivePortal();
   1815 
   1816  return NS_OK;
   1817 }
   1818 
   1819 void nsIOService::SetHttpHandlerAlreadyShutingDown() {
   1820  if (!mShutdown && !mOfflineForProfileChange) {
   1821    mNetTearingDownStarted = PR_IntervalNow();
   1822    mHttpHandlerAlreadyShutingDown = true;
   1823  }
   1824 }
   1825 
   1826 // nsIObserver interface
   1827 NS_IMETHODIMP
   1828 nsIOService::Observe(nsISupports* subject, const char* topic,
   1829                     const char16_t* data) {
   1830  if (UseSocketProcess() && SocketProcessReady() &&
   1831      mObserverTopicForSocketProcess.Contains(nsDependentCString(topic))) {
   1832    nsCString topicStr(topic);
   1833    nsString dataStr(data);
   1834    (void)mSocketProcess->GetActor()->SendNotifyObserver(topicStr, dataStr);
   1835  }
   1836 
   1837  if (!strcmp(topic, kProfileChangeNetTeardownTopic)) {
   1838    if (!mHttpHandlerAlreadyShutingDown) {
   1839      mNetTearingDownStarted = PR_IntervalNow();
   1840    }
   1841    mHttpHandlerAlreadyShutingDown = false;
   1842    if (!mOffline) {
   1843      mOfflineForProfileChange = true;
   1844      SetOfflineInternal(true, false);
   1845    }
   1846  } else if (!strcmp(topic, kProfileChangeNetRestoreTopic)) {
   1847    if (mOfflineForProfileChange) {
   1848      mOfflineForProfileChange = false;
   1849      SetOfflineInternal(false, false);
   1850    }
   1851  } else if (!strcmp(topic, kProfileDoChange)) {
   1852    if (data && u"startup"_ns.Equals(data)) {
   1853      // Lazy initialization of network link service (see bug 620472)
   1854      InitializeNetworkLinkService();
   1855      // Set up the initilization flag regardless the actuall result.
   1856      // If we fail here, we will fail always on.
   1857      mNetworkLinkServiceInitialized = true;
   1858 
   1859      // And now reflect the preference setting
   1860      PrefsChanged(MANAGE_OFFLINE_STATUS_PREF);
   1861 
   1862      // Bug 870460 - Read cookie database at an early-as-possible time
   1863      // off main thread. Hence, we have more chance to finish db query
   1864      // before something calls into the cookie service.
   1865      nsCOMPtr<nsISupports> cookieServ =
   1866          do_GetService(NS_COOKIESERVICE_CONTRACTID);
   1867    }
   1868  } else if (!strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
   1869    // Remember we passed XPCOM shutdown notification to prevent any
   1870    // changes of the offline status from now. We must not allow going
   1871    // online after this point.
   1872    mShutdown = true;
   1873 
   1874    if (!mHttpHandlerAlreadyShutingDown && !mOfflineForProfileChange) {
   1875      mNetTearingDownStarted = PR_IntervalNow();
   1876    }
   1877    mHttpHandlerAlreadyShutingDown = false;
   1878 
   1879    SetOfflineInternal(true, false);
   1880 
   1881    if (mCaptivePortalService) {
   1882      static_cast<CaptivePortalService*>(mCaptivePortalService.get())->Stop();
   1883      mCaptivePortalService = nullptr;
   1884    }
   1885 
   1886    SSLTokensCache::Shutdown();
   1887 
   1888    DestroySocketProcess();
   1889 
   1890    if (IsSocketProcessChild()) {
   1891      Preferences::UnregisterCallbacks(nsIOService::OnTLSPrefChange,
   1892                                       gCallbackSecurityPrefs, this);
   1893      PrepareForShutdownInSocketProcess();
   1894    }
   1895 
   1896    // We're in XPCOM shutdown now. Unregister any dynamic protocol handlers
   1897    // after this point to avoid leaks.
   1898    {
   1899      AutoWriteLock lock(mLock);
   1900      mRuntimeProtocolHandlers.Clear();
   1901    }
   1902  } else if (!strcmp(topic, NS_NETWORK_LINK_TOPIC)) {
   1903    OnNetworkLinkEvent(NS_ConvertUTF16toUTF8(data).get());
   1904  } else if (!strcmp(topic, NS_NETWORK_ID_CHANGED_TOPIC)) {
   1905    LOG(("nsIOService::OnNetworkLinkEvent Network id changed"));
   1906  } else if (!strcmp(topic, NS_WIDGET_WAKE_OBSERVER_TOPIC)) {
   1907    // coming back alive from sleep
   1908    // this indirection brought to you by:
   1909    // https://bugzilla.mozilla.org/show_bug.cgi?id=1152048#c19
   1910    nsCOMPtr<nsIRunnable> wakeupNotifier = new nsWakeupNotifier(this);
   1911    NS_DispatchToMainThread(wakeupNotifier);
   1912    mInSleepMode = false;
   1913  } else if (!strcmp(topic, NS_WIDGET_SLEEP_OBSERVER_TOPIC)) {
   1914    mInSleepMode = true;
   1915  }
   1916 
   1917  return NS_OK;
   1918 }
   1919 
   1920 // nsINetUtil interface
   1921 NS_IMETHODIMP
   1922 nsIOService::ParseRequestContentType(const nsACString& aTypeHeader,
   1923                                     nsACString& aCharset, bool* aHadCharset,
   1924                                     nsACString& aContentType) {
   1925  net_ParseRequestContentType(aTypeHeader, aContentType, aCharset, aHadCharset);
   1926  return NS_OK;
   1927 }
   1928 
   1929 // nsINetUtil interface
   1930 NS_IMETHODIMP
   1931 nsIOService::ParseResponseContentType(const nsACString& aTypeHeader,
   1932                                      nsACString& aCharset, bool* aHadCharset,
   1933                                      nsACString& aContentType) {
   1934  net_ParseContentType(aTypeHeader, aContentType, aCharset, aHadCharset);
   1935  return NS_OK;
   1936 }
   1937 
   1938 NS_IMETHODIMP
   1939 nsIOService::ProtocolHasFlags(nsIURI* uri, uint32_t flags, bool* result) {
   1940  NS_ENSURE_ARG(uri);
   1941 
   1942  *result = false;
   1943  nsAutoCString scheme;
   1944  nsresult rv = uri->GetScheme(scheme);
   1945  NS_ENSURE_SUCCESS(rv, rv);
   1946 
   1947  auto handler = LookupProtocolHandler(scheme);
   1948 
   1949  uint32_t protocolFlags;
   1950  if (flags & nsIProtocolHandler::DYNAMIC_URI_FLAGS) {
   1951    AssertIsOnMainThread();
   1952    rv = handler.DynamicProtocolFlags(uri, &protocolFlags);
   1953    NS_ENSURE_SUCCESS(rv, rv);
   1954  } else {
   1955    protocolFlags = handler.StaticProtocolFlags();
   1956  }
   1957 
   1958  *result = (protocolFlags & flags) == flags;
   1959  return NS_OK;
   1960 }
   1961 
   1962 NS_IMETHODIMP
   1963 nsIOService::URIChainHasFlags(nsIURI* uri, uint32_t flags, bool* result) {
   1964  nsresult rv = ProtocolHasFlags(uri, flags, result);
   1965  NS_ENSURE_SUCCESS(rv, rv);
   1966 
   1967  if (*result) {
   1968    return rv;
   1969  }
   1970 
   1971  // Dig deeper into the chain.  Note that this is not a do/while loop to
   1972  // avoid the extra addref/release on |uri| in the common (non-nested) case.
   1973  nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(uri);
   1974  while (nestedURI) {
   1975    nsCOMPtr<nsIURI> innerURI;
   1976    rv = nestedURI->GetInnerURI(getter_AddRefs(innerURI));
   1977    NS_ENSURE_SUCCESS(rv, rv);
   1978 
   1979    rv = ProtocolHasFlags(innerURI, flags, result);
   1980 
   1981    if (*result) {
   1982      return rv;
   1983    }
   1984 
   1985    nestedURI = do_QueryInterface(innerURI);
   1986  }
   1987 
   1988  return rv;
   1989 }
   1990 
   1991 NS_IMETHODIMP
   1992 nsIOService::SetManageOfflineStatus(bool aManage) {
   1993  LOG(("nsIOService::SetManageOfflineStatus aManage=%d\n", aManage));
   1994  mManageLinkStatus = aManage;
   1995 
   1996  // When detection is not activated, the default connectivity state is true.
   1997  if (!mManageLinkStatus) {
   1998    SetConnectivityInternal(true);
   1999    return NS_OK;
   2000  }
   2001 
   2002  InitializeNetworkLinkService();
   2003  // If the NetworkLinkService is already initialized, it does not call
   2004  // OnNetworkLinkEvent. This is needed, when mManageLinkStatus goes from
   2005  // false to true.
   2006  OnNetworkLinkEvent(NS_NETWORK_LINK_DATA_UNKNOWN);
   2007  return NS_OK;
   2008 }
   2009 
   2010 NS_IMETHODIMP
   2011 nsIOService::GetManageOfflineStatus(bool* aManage) {
   2012  *aManage = mManageLinkStatus;
   2013  return NS_OK;
   2014 }
   2015 
   2016 // input argument 'data' is already UTF8'ed
   2017 nsresult nsIOService::OnNetworkLinkEvent(const char* data) {
   2018  if (IsNeckoChild() || IsSocketProcessChild()) {
   2019    // There is nothing IO service could do on the child process
   2020    // with this at the moment.  Feel free to add functionality
   2021    // here at will, though.
   2022    return NS_OK;
   2023  }
   2024 
   2025  if (mShutdown) {
   2026    return NS_ERROR_NOT_AVAILABLE;
   2027  }
   2028 
   2029  nsCString dataAsString(data);
   2030  for (auto* cp : mozilla::dom::ContentParent::AllProcesses(
   2031           mozilla::dom::ContentParent::eLive)) {
   2032    PNeckoParent* neckoParent = SingleManagedOrNull(cp->ManagedPNeckoParent());
   2033    if (!neckoParent) {
   2034      continue;
   2035    }
   2036    (void)neckoParent->SendNetworkChangeNotification(dataAsString);
   2037  }
   2038 
   2039  LOG(("nsIOService::OnNetworkLinkEvent data:%s\n", data));
   2040  if (!mNetworkLinkService) {
   2041    return NS_ERROR_FAILURE;
   2042  }
   2043 
   2044  if (!mManageLinkStatus) {
   2045    LOG(("nsIOService::OnNetworkLinkEvent mManageLinkStatus=false\n"));
   2046    return NS_OK;
   2047  }
   2048 
   2049  bool isUp = true;
   2050  if (!strcmp(data, NS_NETWORK_LINK_DATA_CHANGED)) {
   2051    mLastNetworkLinkChange = PR_IntervalNow();
   2052    // CHANGED means UP/DOWN didn't change
   2053    // but the status of the captive portal may have changed.
   2054    RecheckCaptivePortal();
   2055    return NS_OK;
   2056  }
   2057  if (!strcmp(data, NS_NETWORK_LINK_DATA_DOWN)) {
   2058    isUp = false;
   2059  } else if (!strcmp(data, NS_NETWORK_LINK_DATA_UP)) {
   2060    isUp = true;
   2061  } else if (!strcmp(data, NS_NETWORK_LINK_DATA_UNKNOWN)) {
   2062    nsresult rv = mNetworkLinkService->GetIsLinkUp(&isUp);
   2063    NS_ENSURE_SUCCESS(rv, rv);
   2064  } else {
   2065    NS_WARNING("Unhandled network event!");
   2066    return NS_OK;
   2067  }
   2068 
   2069  return SetConnectivityInternal(isUp);
   2070 }
   2071 
   2072 NS_IMETHODIMP
   2073 nsIOService::EscapeString(const nsACString& aString, uint32_t aEscapeType,
   2074                          nsACString& aResult) {
   2075  NS_ENSURE_ARG_MAX(aEscapeType, 4);
   2076 
   2077  nsAutoCString stringCopy(aString);
   2078  nsCString result;
   2079 
   2080  if (!NS_Escape(stringCopy, result, (nsEscapeMask)aEscapeType)) {
   2081    return NS_ERROR_OUT_OF_MEMORY;
   2082  }
   2083 
   2084  aResult.Assign(result);
   2085 
   2086  return NS_OK;
   2087 }
   2088 
   2089 NS_IMETHODIMP
   2090 nsIOService::EscapeURL(const nsACString& aStr, uint32_t aFlags,
   2091                       nsACString& aResult) {
   2092  aResult.Truncate();
   2093  NS_EscapeURL(aStr.BeginReading(), aStr.Length(), aFlags | esc_AlwaysCopy,
   2094               aResult);
   2095  return NS_OK;
   2096 }
   2097 
   2098 NS_IMETHODIMP
   2099 nsIOService::UnescapeString(const nsACString& aStr, uint32_t aFlags,
   2100                            nsACString& aResult) {
   2101  aResult.Truncate();
   2102  NS_UnescapeURL(aStr.BeginReading(), aStr.Length(), aFlags | esc_AlwaysCopy,
   2103                 aResult);
   2104  return NS_OK;
   2105 }
   2106 
   2107 NS_IMETHODIMP
   2108 nsIOService::ExtractCharsetFromContentType(const nsACString& aTypeHeader,
   2109                                           nsACString& aCharset,
   2110                                           int32_t* aCharsetStart,
   2111                                           int32_t* aCharsetEnd,
   2112                                           bool* aHadCharset) {
   2113  nsAutoCString ignored;
   2114  net_ParseContentType(aTypeHeader, ignored, aCharset, aHadCharset,
   2115                       aCharsetStart, aCharsetEnd);
   2116  if (*aHadCharset && *aCharsetStart == *aCharsetEnd) {
   2117    *aHadCharset = false;
   2118  }
   2119  return NS_OK;
   2120 }
   2121 
   2122 // nsISpeculativeConnect
   2123 class IOServiceProxyCallback final : public nsIProtocolProxyCallback {
   2124  ~IOServiceProxyCallback() = default;
   2125 
   2126 public:
   2127  NS_DECL_ISUPPORTS
   2128  NS_DECL_NSIPROTOCOLPROXYCALLBACK
   2129 
   2130  IOServiceProxyCallback(nsIInterfaceRequestor* aCallbacks,
   2131                         nsIOService* aIOService,
   2132                         Maybe<OriginAttributes>&& aOriginAttributes)
   2133      : mCallbacks(aCallbacks),
   2134        mIOService(aIOService),
   2135        mOriginAttributes(std::move(aOriginAttributes)) {}
   2136 
   2137 private:
   2138  RefPtr<nsIInterfaceRequestor> mCallbacks;
   2139  RefPtr<nsIOService> mIOService;
   2140  Maybe<OriginAttributes> mOriginAttributes;
   2141 };
   2142 
   2143 NS_IMPL_ISUPPORTS(IOServiceProxyCallback, nsIProtocolProxyCallback)
   2144 
   2145 NS_IMETHODIMP
   2146 IOServiceProxyCallback::OnProxyAvailable(nsICancelable* request,
   2147                                         nsIChannel* channel, nsIProxyInfo* pi,
   2148                                         nsresult status) {
   2149  // Checking proxy status for speculative connect
   2150  nsAutoCString type;
   2151  if (NS_SUCCEEDED(status) && pi && NS_SUCCEEDED(pi->GetType(type)) &&
   2152      !type.EqualsLiteral("direct")) {
   2153    // proxies dont do speculative connect
   2154    return NS_OK;
   2155  }
   2156 
   2157  nsCOMPtr<nsIURI> uri;
   2158  nsresult rv = channel->GetURI(getter_AddRefs(uri));
   2159  if (NS_FAILED(rv)) {
   2160    return NS_OK;
   2161  }
   2162 
   2163  nsAutoCString scheme;
   2164  rv = uri->GetScheme(scheme);
   2165  if (NS_FAILED(rv)) return NS_OK;
   2166 
   2167  nsCOMPtr<nsIProtocolHandler> handler;
   2168  rv = mIOService->GetProtocolHandler(scheme.get(), getter_AddRefs(handler));
   2169  if (NS_FAILED(rv)) return NS_OK;
   2170 
   2171  nsCOMPtr<nsISpeculativeConnect> speculativeHandler =
   2172      do_QueryInterface(handler);
   2173  if (!speculativeHandler) return NS_OK;
   2174 
   2175  nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
   2176  nsCOMPtr<nsIPrincipal> principal = loadInfo->GetLoadingPrincipal();
   2177 
   2178  nsLoadFlags loadFlags = 0;
   2179  channel->GetLoadFlags(&loadFlags);
   2180  bool anonymous = !!(loadFlags & nsIRequest::LOAD_ANONYMOUS);
   2181  if (mOriginAttributes) {
   2182    speculativeHandler->SpeculativeConnectWithOriginAttributesNative(
   2183        uri, std::move(mOriginAttributes.ref()), mCallbacks, anonymous);
   2184  } else {
   2185    speculativeHandler->SpeculativeConnect(uri, principal, mCallbacks,
   2186                                           anonymous);
   2187  }
   2188 
   2189  return NS_OK;
   2190 }
   2191 
   2192 nsresult nsIOService::SpeculativeConnectInternal(
   2193    nsIURI* aURI, nsIPrincipal* aPrincipal,
   2194    Maybe<OriginAttributes>&& aOriginAttributes,
   2195    nsIInterfaceRequestor* aCallbacks, bool aAnonymous) {
   2196  NS_ENSURE_ARG(aURI);
   2197 
   2198  if (!SchemeIsHttpOrHttps(aURI)) {
   2199    // We don't speculatively connect to non-HTTP[S] URIs.
   2200    return NS_OK;
   2201  }
   2202 
   2203  if (IsNeckoChild()) {
   2204    gNeckoChild->SendSpeculativeConnect(
   2205        aURI, aPrincipal, std::move(aOriginAttributes), aAnonymous);
   2206    return NS_OK;
   2207  }
   2208 
   2209  // Check for proxy information. If there is a proxy configured then a
   2210  // speculative connect should not be performed because the potential
   2211  // reward is slim with tcp peers closely located to the browser.
   2212  nsresult rv;
   2213  nsCOMPtr<nsIProtocolProxyService> pps;
   2214  pps = mozilla::components::ProtocolProxy::Service(&rv);
   2215  NS_ENSURE_SUCCESS(rv, rv);
   2216 
   2217  nsCOMPtr<nsIPrincipal> loadingPrincipal = aPrincipal;
   2218 
   2219  MOZ_ASSERT(aPrincipal || aOriginAttributes,
   2220             "We expect passing a principal or OriginAttributes here.");
   2221 
   2222  if (!aPrincipal && !aOriginAttributes) {
   2223    return NS_ERROR_INVALID_ARG;
   2224  }
   2225 
   2226  if (aOriginAttributes) {
   2227    loadingPrincipal =
   2228        BasePrincipal::CreateContentPrincipal(aURI, aOriginAttributes.ref());
   2229  }
   2230 
   2231  // XXX Bug 1724080: Avoid TCP connections on port 80 when https-only
   2232  // or https-first is enabled. Let's create a dummy loadinfo which we
   2233  // only use to determine whether we need ot upgrade the speculative
   2234  // connection from http to https.
   2235  nsCOMPtr<nsIURI> httpsURI;
   2236  if (aURI->SchemeIs("http")) {
   2237    nsCOMPtr<nsILoadInfo> httpsOnlyCheckLoadInfo = MOZ_TRY(
   2238        LoadInfo::Create(loadingPrincipal, loadingPrincipal, nullptr,
   2239                         nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK,
   2240                         nsIContentPolicy::TYPE_SPECULATIVE));
   2241 
   2242    // Check if https-only, or https-first would upgrade the request
   2243    if (nsHTTPSOnlyUtils::ShouldUpgradeRequest(aURI, httpsOnlyCheckLoadInfo) ||
   2244        nsHTTPSOnlyUtils::ShouldUpgradeHttpsFirstRequest(
   2245            aURI, httpsOnlyCheckLoadInfo)) {
   2246      rv = NS_GetSecureUpgradedURI(aURI, getter_AddRefs(httpsURI));
   2247      NS_ENSURE_SUCCESS(rv, rv);
   2248      aURI = httpsURI.get();
   2249    }
   2250  }
   2251 
   2252  // dummy channel used to create a TCP connection.
   2253  // we perform security checks on the *real* channel, responsible
   2254  // for any network loads. this real channel just checks the TCP
   2255  // pool if there is an available connection created by the
   2256  // channel we create underneath - hence it's safe to use
   2257  // the systemPrincipal as the loadingPrincipal for this channel.
   2258  nsCOMPtr<nsIChannel> channel;
   2259  rv = NewChannelFromURI(
   2260      aURI,
   2261      nullptr,  // aLoadingNode,
   2262      loadingPrincipal,
   2263      nullptr,  // aTriggeringPrincipal,
   2264      nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
   2265      nsIContentPolicy::TYPE_SPECULATIVE, getter_AddRefs(channel));
   2266  NS_ENSURE_SUCCESS(rv, rv);
   2267 
   2268  if (aAnonymous) {
   2269    nsLoadFlags loadFlags = 0;
   2270    channel->GetLoadFlags(&loadFlags);
   2271    loadFlags |= nsIRequest::LOAD_ANONYMOUS;
   2272    channel->SetLoadFlags(loadFlags);
   2273  }
   2274 
   2275  if (!aCallbacks) {
   2276    // Proxy filters are registered, but no callbacks were provided.
   2277    // When proxyDNS is true, this speculative connection would likely leak a
   2278    // DNS lookup, so we should return early to avoid that.
   2279    bool hasProxyFilterRegistered = false;
   2280    (void)pps->GetHasProxyFilterRegistered(&hasProxyFilterRegistered);
   2281    if (hasProxyFilterRegistered) {
   2282      return NS_ERROR_FAILURE;
   2283    }
   2284  } else {
   2285    rv = channel->SetNotificationCallbacks(aCallbacks);
   2286    NS_ENSURE_SUCCESS(rv, rv);
   2287  }
   2288 
   2289  nsCOMPtr<nsICancelable> cancelable;
   2290  RefPtr<IOServiceProxyCallback> callback = new IOServiceProxyCallback(
   2291      aCallbacks, this, std::move(aOriginAttributes));
   2292  nsCOMPtr<nsIProtocolProxyService2> pps2 = do_QueryInterface(pps);
   2293  if (pps2) {
   2294    return pps2->AsyncResolve2(channel, 0, callback, nullptr,
   2295                               getter_AddRefs(cancelable));
   2296  }
   2297  return pps->AsyncResolve(channel, 0, callback, nullptr,
   2298                           getter_AddRefs(cancelable));
   2299 }
   2300 
   2301 NS_IMETHODIMP
   2302 nsIOService::SpeculativeConnect(nsIURI* aURI, nsIPrincipal* aPrincipal,
   2303                                nsIInterfaceRequestor* aCallbacks,
   2304                                bool aAnonymous) {
   2305  return SpeculativeConnectInternal(aURI, aPrincipal, Nothing(), aCallbacks,
   2306                                    aAnonymous);
   2307 }
   2308 
   2309 NS_IMETHODIMP nsIOService::SpeculativeConnectWithOriginAttributes(
   2310    nsIURI* aURI, JS::Handle<JS::Value> aOriginAttributes,
   2311    nsIInterfaceRequestor* aCallbacks, bool aAnonymous, JSContext* aCx) {
   2312  OriginAttributes attrs;
   2313  if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
   2314    return NS_ERROR_INVALID_ARG;
   2315  }
   2316 
   2317  SpeculativeConnectWithOriginAttributesNative(aURI, std::move(attrs),
   2318                                               aCallbacks, aAnonymous);
   2319  return NS_OK;
   2320 }
   2321 
   2322 NS_IMETHODIMP_(void)
   2323 nsIOService::SpeculativeConnectWithOriginAttributesNative(
   2324    nsIURI* aURI, OriginAttributes&& aOriginAttributes,
   2325    nsIInterfaceRequestor* aCallbacks, bool aAnonymous) {
   2326  Maybe<OriginAttributes> originAttributes;
   2327  originAttributes.emplace(aOriginAttributes);
   2328  (void)SpeculativeConnectInternal(aURI, nullptr, std::move(originAttributes),
   2329                                   aCallbacks, aAnonymous);
   2330 }
   2331 
   2332 NS_IMETHODIMP
   2333 nsIOService::NotImplemented() { return NS_ERROR_NOT_IMPLEMENTED; }
   2334 
   2335 NS_IMETHODIMP
   2336 nsIOService::GetSocketProcessLaunched(bool* aResult) {
   2337  NS_ENSURE_ARG_POINTER(aResult);
   2338 
   2339  *aResult = SocketProcessReady();
   2340  return NS_OK;
   2341 }
   2342 
   2343 bool nsIOService::HasObservers(const char* aTopic) {
   2344  MOZ_ASSERT(false, "Calling this method is unexpected");
   2345  return false;
   2346 }
   2347 
   2348 NS_IMETHODIMP
   2349 nsIOService::GetSocketProcessId(uint64_t* aPid) {
   2350  NS_ENSURE_ARG_POINTER(aPid);
   2351 
   2352  *aPid = 0;
   2353  if (!mSocketProcess) {
   2354    return NS_OK;
   2355  }
   2356 
   2357  if (SocketProcessParent* actor = mSocketProcess->GetActor()) {
   2358    *aPid = (uint64_t)actor->OtherPid();
   2359  }
   2360 
   2361  return NS_OK;
   2362 }
   2363 
   2364 NS_IMETHODIMP
   2365 nsIOService::RegisterProtocolHandler(const nsACString& aScheme,
   2366                                     nsIProtocolHandler* aHandler,
   2367                                     uint32_t aProtocolFlags,
   2368                                     int32_t aDefaultPort) {
   2369  if (mShutdown) {
   2370    return NS_ERROR_NOT_AVAILABLE;
   2371  }
   2372  if (aScheme.IsEmpty()) {
   2373    return NS_ERROR_INVALID_ARG;
   2374  }
   2375 
   2376  nsAutoCString scheme(aScheme);
   2377  ToLowerCase(scheme);
   2378 
   2379  AutoWriteLock lock(mLock);
   2380  return mRuntimeProtocolHandlers.WithEntryHandle(scheme, [&](auto&& entry) {
   2381    if (entry) {
   2382      NS_WARNING("Cannot override an existing dynamic protocol handler");
   2383      return NS_ERROR_FACTORY_EXISTS;
   2384    }
   2385    if (xpcom::StaticProtocolHandler::Lookup(scheme)) {
   2386      NS_WARNING("Cannot override an existing static protocol handler");
   2387      return NS_ERROR_FACTORY_EXISTS;
   2388    }
   2389    nsMainThreadPtrHandle<nsIProtocolHandler> handler(
   2390        new nsMainThreadPtrHolder<nsIProtocolHandler>("RuntimeProtocolHandler",
   2391                                                      aHandler));
   2392    entry.Insert(RuntimeProtocolHandler{
   2393        .mHandler = std::move(handler),
   2394        .mProtocolFlags = aProtocolFlags,
   2395        .mDefaultPort = aDefaultPort,
   2396    });
   2397    return NS_OK;
   2398  });
   2399 }
   2400 
   2401 NS_IMETHODIMP
   2402 nsIOService::UnregisterProtocolHandler(const nsACString& aScheme) {
   2403  if (mShutdown) {
   2404    return NS_OK;
   2405  }
   2406  if (aScheme.IsEmpty()) {
   2407    return NS_ERROR_INVALID_ARG;
   2408  }
   2409 
   2410  nsAutoCString scheme(aScheme);
   2411  ToLowerCase(scheme);
   2412 
   2413  AutoWriteLock lock(mLock);
   2414  return mRuntimeProtocolHandlers.Remove(scheme)
   2415             ? NS_OK
   2416             : NS_ERROR_FACTORY_NOT_REGISTERED;
   2417 }
   2418 
   2419 NS_IMETHODIMP
   2420 nsIOService::SetSimpleURIUnknownRemoteSchemes(
   2421    const nsTArray<nsCString>& aRemoteSchemes) {
   2422  LOG(("nsIOService::SetSimpleUriUnknownRemoteSchemes"));
   2423  mSimpleURIUnknownSchemes.SetAndMergeRemoteSchemes(aRemoteSchemes);
   2424 
   2425  if (XRE_IsParentProcess()) {
   2426    // since we only expect socket, parent and content processes to create URLs
   2427    // that need to check the bypass list
   2428    // we only broadcast the list to content processes
   2429    // (and leave socket process broadcast as todo if necessary)
   2430    //
   2431    // sending only the remote-settings schemes to the content,
   2432    // which already has the pref list
   2433    for (auto* cp : mozilla::dom::ContentParent::AllProcesses(
   2434             mozilla::dom::ContentParent::eLive)) {
   2435      (void)cp->SendSimpleURIUnknownRemoteSchemes(aRemoteSchemes);
   2436    }
   2437  }
   2438  return NS_OK;
   2439 }
   2440 
   2441 // Check for any address space overrides for Local Network Access Checks
   2442 // The override prefs should be set only for tests (controlled by
   2443 // network_lna_blocking pref).
   2444 NS_IMETHODIMP
   2445 nsIOService::GetOverridenIpAddressSpace(
   2446    nsILoadInfo::IPAddressSpace* aIpAddressSpace, const NetAddr& aAddr) {
   2447  nsAutoCString addrPortString;
   2448 
   2449  if (!StaticPrefs::network_lna_enabled()) {
   2450    return NS_ERROR_FAILURE;
   2451  }
   2452 
   2453  {
   2454    AutoReadLock lock(mLock);
   2455    if (mPublicAddressSpaceOverridesList.IsEmpty() &&
   2456        mPrivateAddressSpaceOverridesList.IsEmpty() &&
   2457        mLocalAddressSpaceOverrideList.IsEmpty()) {
   2458      return NS_ERROR_FAILURE;
   2459    }
   2460  }
   2461 
   2462  aAddr.ToAddrPortString(addrPortString);
   2463  addrPortString.StripWhitespace();
   2464  AutoReadLock lock(mLock);
   2465 
   2466  for (const auto& ipAddr : mPublicAddressSpaceOverridesList) {
   2467    if (addrPortString.Equals(ipAddr)) {
   2468      *aIpAddressSpace = nsILoadInfo::IPAddressSpace::Public;
   2469      return NS_OK;
   2470    }
   2471  }
   2472 
   2473  for (const auto& ipAddr : mPrivateAddressSpaceOverridesList) {
   2474    if (addrPortString.Equals(ipAddr)) {
   2475      *aIpAddressSpace = nsILoadInfo::IPAddressSpace::Private;
   2476      return NS_OK;
   2477    }
   2478  }
   2479 
   2480  for (const auto& ipAddr : mLocalAddressSpaceOverrideList) {
   2481    if (addrPortString.Equals(ipAddr)) {
   2482      *aIpAddressSpace = nsILoadInfo::IPAddressSpace::Local;
   2483      return NS_OK;
   2484    }
   2485  }
   2486 
   2487  *aIpAddressSpace = nsILoadInfo::IPAddressSpace::Unknown;
   2488  return NS_ERROR_FAILURE;
   2489 }
   2490 
   2491 NS_IMETHODIMP
   2492 nsIOService::IsSimpleURIUnknownScheme(const nsACString& aScheme,
   2493                                      bool* _retval) {
   2494  *_retval = mSimpleURIUnknownSchemes.IsSimpleURIUnknownScheme(aScheme);
   2495  return NS_OK;
   2496 }
   2497 
   2498 NS_IMETHODIMP
   2499 nsIOService::GetSimpleURIUnknownRemoteSchemes(nsTArray<nsCString>& _retval) {
   2500  mSimpleURIUnknownSchemes.GetRemoteSchemes(_retval);
   2501  return NS_OK;
   2502 }
   2503 
   2504 NS_IMETHODIMP
   2505 nsIOService::AddEssentialDomainMapping(const nsACString& aFrom,
   2506                                       const nsACString& aTo) {
   2507  MOZ_ASSERT(NS_IsMainThread());
   2508  mEssentialDomainMapping.InsertOrUpdate(aFrom, aTo);
   2509  return NS_OK;
   2510 }
   2511 
   2512 NS_IMETHODIMP
   2513 nsIOService::ClearEssentialDomainMapping() {
   2514  MOZ_ASSERT(NS_IsMainThread());
   2515  mEssentialDomainMapping.Clear();
   2516  return NS_OK;
   2517 }
   2518 
   2519 bool nsIOService::GetFallbackDomain(const nsACString& aDomain,
   2520                                    nsACString& aFallbackDomain) {
   2521  MOZ_ASSERT(NS_IsMainThread());
   2522  if (auto entry = mEssentialDomainMapping.Lookup(aDomain)) {
   2523    aFallbackDomain = entry.Data();
   2524    return true;
   2525  }
   2526  return false;
   2527 }
   2528 
   2529 NS_IMETHODIMP
   2530 nsIOService::ParseCacheControlHeader(const nsACString& aCacheControlHeader,
   2531                                     JSContext* cx,
   2532                                     JS::MutableHandle<JS::Value> _retval) {
   2533  MOZ_ASSERT(NS_IsMainThread());
   2534 
   2535  mozilla::dom::HTTPCacheControlParseResult result;
   2536  CacheControlParser parser(aCacheControlHeader);
   2537 
   2538  bool didParseValue = false;
   2539 
   2540  uint32_t maxAge = 0;
   2541  didParseValue = parser.MaxAge(&maxAge);
   2542  if (didParseValue) {
   2543    result.mMaxAge = maxAge;
   2544  }
   2545 
   2546  uint32_t maxStale = 0;
   2547  didParseValue = parser.MaxStale(&maxStale);
   2548  if (didParseValue) {
   2549    result.mMaxStale = maxStale;
   2550  }
   2551 
   2552  uint32_t minFresh = 0;
   2553  didParseValue = parser.MaxStale(&minFresh);
   2554  if (didParseValue) {
   2555    result.mMinFresh = minFresh;
   2556  }
   2557 
   2558  uint32_t staleWhileRevalidate = 0;
   2559  didParseValue = parser.StaleWhileRevalidate(&staleWhileRevalidate);
   2560  if (didParseValue) {
   2561    result.mStaleWhileRevalidate = staleWhileRevalidate;
   2562  }
   2563 
   2564  result.mNoCache = parser.NoCache();
   2565  result.mNoStore = parser.NoStore();
   2566  result.mPublic = parser.Public();
   2567  result.mPrivate = parser.Private();
   2568  result.mImmutable = parser.Immutable();
   2569 
   2570  if (!ToJSValue(cx, result, _retval)) {
   2571    return NS_ERROR_FAILURE;
   2572  }
   2573  return NS_OK;
   2574 }
   2575 
   2576 }  // namespace net
   2577 }  // namespace mozilla