tor-browser

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

NetworkConnectivityService.cpp (19254B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "DNSUtils.h"
      6 #include "NetworkConnectivityService.h"
      7 #include "mozilla/AppShutdown.h"
      8 #include "mozilla/ClearOnShutdown.h"
      9 #include "mozilla/net/SocketProcessParent.h"
     10 #include "mozilla/Preferences.h"
     11 #include "mozilla/Services.h"
     12 #include "nsCOMPtr.h"
     13 #include "nsIChannel.h"
     14 #include "nsIOService.h"
     15 #include "nsICancelable.h"
     16 #include "xpcpublic.h"
     17 #include "nsSocketTransport2.h"
     18 #include "nsIHttpChannelInternal.h"
     19 #include "nsINetworkLinkService.h"
     20 #include "mozilla/StaticPrefs_network.h"
     21 
     22 static mozilla::LazyLogModule gNCSLog("NetworkConnectivityService");
     23 #undef LOG
     24 #define LOG(args) MOZ_LOG(gNCSLog, mozilla::LogLevel::Debug, args)
     25 
     26 namespace mozilla {
     27 namespace net {
     28 
     29 NS_IMPL_ISUPPORTS(NetworkConnectivityService, nsIDNSListener, nsIObserver,
     30                  nsINetworkConnectivityService, nsIStreamListener)
     31 
     32 static StaticRefPtr<NetworkConnectivityService> gConnService;
     33 
     34 // static
     35 already_AddRefed<NetworkConnectivityService>
     36 NetworkConnectivityService::GetSingleton() {
     37  if (gConnService) {
     38    return do_AddRef(gConnService);
     39  }
     40 
     41  if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
     42    return nullptr;
     43  }
     44 
     45  RefPtr<NetworkConnectivityService> service = new NetworkConnectivityService();
     46  service->Init();
     47 
     48  gConnService = std::move(service);
     49  ClearOnShutdown(&gConnService);
     50  return do_AddRef(gConnService);
     51 }
     52 
     53 nsresult NetworkConnectivityService::Init() {
     54  nsCOMPtr<nsIObserverService> observerService =
     55      mozilla::services::GetObserverService();
     56  observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
     57  observerService->AddObserver(this, NS_NETWORK_LINK_TOPIC, false);
     58  observerService->AddObserver(this, "network:captive-portal-connectivity",
     59                               false);
     60  observerService->AddObserver(this, "browser-idle-startup-tasks-finished",
     61                               false);
     62 
     63  return NS_OK;
     64 }
     65 
     66 NS_IMETHODIMP
     67 NetworkConnectivityService::GetDNSv4(ConnectivityState* aState) {
     68  NS_ENSURE_ARG(aState);
     69  *aState = mDNSv4;
     70  return NS_OK;
     71 }
     72 
     73 NS_IMETHODIMP
     74 NetworkConnectivityService::SetDNSv4(
     75    nsINetworkConnectivityService::ConnectivityState aDNSv4) {
     76  mDNSv4 = aDNSv4;
     77  return NS_OK;
     78 }
     79 
     80 NS_IMETHODIMP
     81 NetworkConnectivityService::GetDNSv6(ConnectivityState* aState) {
     82  NS_ENSURE_ARG(aState);
     83  *aState = mDNSv6;
     84  return NS_OK;
     85 }
     86 
     87 NS_IMETHODIMP
     88 NetworkConnectivityService::SetDNSv6(
     89    nsINetworkConnectivityService::ConnectivityState aDNSv6) {
     90  mDNSv6 = aDNSv6;
     91  return NS_OK;
     92 }
     93 
     94 NS_IMETHODIMP
     95 NetworkConnectivityService::GetDNS_HTTPS(ConnectivityState* aState) {
     96  NS_ENSURE_ARG(aState);
     97  *aState = mDNS_HTTPS;
     98  return NS_OK;
     99 }
    100 
    101 NS_IMETHODIMP
    102 NetworkConnectivityService::SetDNS_HTTPS(
    103    nsINetworkConnectivityService::ConnectivityState aDNSHTTPS) {
    104  mDNS_HTTPS = aDNSHTTPS;
    105  return NS_OK;
    106 }
    107 
    108 NS_IMETHODIMP
    109 NetworkConnectivityService::GetIPv4(ConnectivityState* aState) {
    110  NS_ENSURE_ARG(aState);
    111  *aState = mIPv4;
    112  return NS_OK;
    113 }
    114 
    115 NS_IMETHODIMP
    116 NetworkConnectivityService::SetIPv4(
    117    nsINetworkConnectivityService::ConnectivityState aIPv4) {
    118  mIPv4 = aIPv4;
    119  return NS_OK;
    120 }
    121 
    122 NS_IMETHODIMP
    123 NetworkConnectivityService::GetIPv6(ConnectivityState* aState) {
    124  NS_ENSURE_ARG(aState);
    125  *aState = mIPv6;
    126  return NS_OK;
    127 }
    128 
    129 NS_IMETHODIMP
    130 NetworkConnectivityService::SetIPv6(
    131    nsINetworkConnectivityService::ConnectivityState aIPv6) {
    132  mIPv6 = aIPv6;
    133  return NS_OK;
    134 }
    135 
    136 NS_IMETHODIMP
    137 NetworkConnectivityService::GetNAT64(ConnectivityState* aState) {
    138  NS_ENSURE_ARG(aState);
    139  *aState = mNAT64;
    140  return NS_OK;
    141 }
    142 
    143 NS_IMETHODIMP
    144 NetworkConnectivityService::SetNAT64(
    145    nsINetworkConnectivityService::ConnectivityState aNAT64) {
    146  mNAT64 = aNAT64;
    147  return NS_OK;
    148 }
    149 
    150 already_AddRefed<AddrInfo> NetworkConnectivityService::MapNAT64IPs(
    151    AddrInfo* aNewRRSet) {
    152  // Add prefixes only if there are no IPv6 addresses.
    153  // Expect that if aNewRRSet has IPv6 addresses, they must come
    154  // before IPv4 addresses.
    155  if (aNewRRSet->Addresses().IsEmpty() ||
    156      aNewRRSet->Addresses()[0].raw.family == PR_AF_INET6) {
    157    return do_AddRef(aNewRRSet);
    158  }
    159 
    160  // Currently we only add prefixes to the first IP's clones.
    161  uint32_t ip = aNewRRSet->Addresses()[0].inet.ip;
    162  nsTArray<NetAddr> addresses = aNewRRSet->Addresses().Clone();
    163 
    164  {
    165    MutexAutoLock lock(mLock);
    166    for (const auto& prefix : mNAT64Prefixes) {
    167      NetAddr addr = NetAddr(prefix);
    168 
    169      // Copy the IPv4 address to the end
    170      addr.inet6.ip.u32[3] = ip;
    171 
    172      // If we have both IPv4 and NAT64, we be could insourcing NAT64
    173      // to avoid double NAT and improve performance. However, this
    174      // breaks WebRTC, so we push it to the back.
    175      addresses.AppendElement(addr);
    176    }
    177  }
    178 
    179  auto builder = aNewRRSet->Build();
    180  builder.SetAddresses(std::move(addresses));
    181  return builder.Finish();
    182 }
    183 
    184 // Returns true if a prefix was read and saved to the argument
    185 static inline bool NAT64PrefixFromPref(NetAddr* prefix) {
    186  nsAutoCString nat64PrefixPref;
    187 
    188  nsresult rv = Preferences::GetCString(
    189      "network.connectivity-service.nat64-prefix", nat64PrefixPref);
    190  return !(NS_FAILED(rv) || nat64PrefixPref.IsEmpty() ||
    191           NS_FAILED(prefix->InitFromString(nat64PrefixPref)) ||
    192           prefix->raw.family != PR_AF_INET6);
    193 }
    194 
    195 static inline bool NAT64PrefixCompare(const NetAddr& prefix1,
    196                                      const NetAddr& prefix2) {
    197  // Compare the first 96 bits as 64 + 32
    198  return prefix1.inet6.ip.u64[0] == prefix2.inet6.ip.u64[0] &&
    199         prefix1.inet6.ip.u32[2] == prefix2.inet6.ip.u32[2];
    200 }
    201 
    202 void NetworkConnectivityService::PerformChecks() {
    203  mDNSv4 = UNKNOWN;
    204  mDNSv6 = UNKNOWN;
    205  mDNS_HTTPS = UNKNOWN;
    206 
    207  mIPv4 = UNKNOWN;
    208  mIPv6 = UNKNOWN;
    209 
    210  mNAT64 = UNKNOWN;
    211 
    212  {
    213    MutexAutoLock lock(mLock);
    214    mNAT64Prefixes.Clear();
    215 
    216    // NAT64 checks might be disabled.
    217    // Since We can't guarantee a DNS response, we should set up
    218    // NAT64 manually now if needed.
    219 
    220    NetAddr priorityPrefix{};
    221    bool havePrefix = NAT64PrefixFromPref(&priorityPrefix);
    222    if (havePrefix) {
    223      mNAT64Prefixes.AppendElement(priorityPrefix);
    224      mNAT64 = OK;
    225    }
    226  }
    227 
    228  if (StaticPrefs::network_connectivity_service_wait_for_idle_startup() &&
    229      !mIdleStartupDone) {
    230    return;
    231  }
    232 
    233  RecheckDNS();
    234  RecheckIPConnectivity();
    235 }
    236 
    237 static inline void NotifyObservers(const char* aTopic) {
    238  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
    239  obs->NotifyObservers(nullptr, aTopic, nullptr);
    240 }
    241 
    242 void NetworkConnectivityService::SaveNAT64Prefixes(nsIDNSRecord* aRecord) {
    243  nsCOMPtr<nsIDNSAddrRecord> rec = do_QueryInterface(aRecord);
    244  MutexAutoLock lock(mLock);
    245  mNAT64Prefixes.Clear();
    246 
    247  NetAddr priorityPrefix{};
    248  bool havePrefix = NAT64PrefixFromPref(&priorityPrefix);
    249  if (havePrefix) {
    250    mNAT64 = OK;
    251    mNAT64Prefixes.AppendElement(priorityPrefix);
    252  }
    253 
    254  if (!rec) {
    255    if (!havePrefix) {
    256      mNAT64 = NOT_AVAILABLE;
    257    }
    258    return;
    259  }
    260 
    261  mNAT64 = UNKNOWN;
    262  NetAddr addr{};
    263 
    264  // use port 80 as dummy value for NetAddr
    265  while (NS_SUCCEEDED(rec->GetNextAddr(80, &addr))) {
    266    if (addr.raw.family != AF_INET6 || addr.IsIPAddrV4Mapped()) {
    267      // These are not the kind of addresses we are looking for.
    268      continue;
    269    }
    270 
    271    // RFC 7050 does not require the embedded IPv4 to be
    272    // at the end of IPv6. In practice, and as we assume,
    273    // it is always at the end.
    274    // The embedded IP must be 192.0.0.170 or 192.0.0.171
    275 
    276    // Clear the last bit to compare with the next one.
    277    addr.inet6.ip.u8[15] &= ~(uint32_t)1;
    278    if ((addr.inet6.ip.u8[12] != 192) || (addr.inet6.ip.u8[13] != 0) ||
    279        (addr.inet6.ip.u8[14] != 0) || (addr.inet6.ip.u8[15] != 170)) {
    280      continue;
    281    }
    282 
    283    mNAT64Prefixes.AppendElement(addr);
    284  }
    285 
    286  size_t length = mNAT64Prefixes.Length();
    287  if (length == 0) {
    288    mNAT64 = NOT_AVAILABLE;
    289    return;
    290  }
    291 
    292  // Remove duplicates. Typically a DNS64 resolver sends every
    293  // prefix twice with address with different last bits. We want
    294  // a list of unique prefixes while reordering is not allowed.
    295  // We must not handle the case with an element in-between
    296  // two identical ones, which is never the case for a properly
    297  // configured DNS64 resolver.
    298 
    299  NetAddr prev = mNAT64Prefixes[0];
    300 
    301  for (size_t i = 1; i < length; i++) {
    302    if (NAT64PrefixCompare(prev, mNAT64Prefixes[i])) {
    303      mNAT64Prefixes.RemoveElementAt(i);
    304      i--;
    305      length--;
    306    } else {
    307      prev = mNAT64Prefixes[i];
    308    }
    309  }
    310 
    311  // The prioritized address might also appear in the record we received.
    312 
    313  if (havePrefix) {
    314    for (size_t i = 1; i < length; i++) {
    315      if (NAT64PrefixCompare(priorityPrefix, mNAT64Prefixes[i])) {
    316        mNAT64Prefixes.RemoveElementAt(i);
    317        // It wouldn't appear more than once.
    318        break;
    319      }
    320    }
    321  }
    322 
    323  mNAT64 = OK;
    324 }
    325 
    326 NS_IMETHODIMP
    327 NetworkConnectivityService::OnLookupComplete(nsICancelable* aRequest,
    328                                             nsIDNSRecord* aRecord,
    329                                             nsresult aStatus) {
    330  ConnectivityState state = NS_SUCCEEDED(aStatus) ? OK : NOT_AVAILABLE;
    331 
    332  if (aRequest == mDNSv4Request) {
    333    mDNSv4 = state;
    334    mDNSv4Request = nullptr;
    335  } else if (aRequest == mDNSv6Request) {
    336    mDNSv6 = state;
    337    mDNSv6Request = nullptr;
    338  } else if (aRequest == mDNS_HTTPSRequest) {
    339    mDNS_HTTPS = state;
    340    mDNS_HTTPSRequest = nullptr;
    341  } else if (aRequest == mNAT64Request) {
    342    mNAT64Request = nullptr;
    343    SaveNAT64Prefixes(aRecord);
    344  }
    345 
    346  if (!mDNSv4Request && !mDNSv6Request && !mDNS_HTTPSRequest &&
    347      !mNAT64Request) {
    348    NotifyObservers("network:connectivity-service:dns-checks-complete");
    349  }
    350  return NS_OK;
    351 }
    352 
    353 NS_IMETHODIMP
    354 NetworkConnectivityService::RecheckDNS() {
    355  bool enabled =
    356      Preferences::GetBool("network.connectivity-service.enabled", false);
    357  if (!enabled) {
    358    return NS_OK;
    359  }
    360 
    361  if (nsIOService::UseSocketProcess()) {
    362    RefPtr<SocketProcessParent> parent = SocketProcessParent::GetSingleton();
    363    if (parent) {
    364      (void)parent->SendRecheckDNS();
    365    }
    366  }
    367 
    368  nsresult rv;
    369  nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID);
    370  OriginAttributes attrs;
    371  nsAutoCString host;
    372  Preferences::GetCString("network.connectivity-service.DNSv4.domain", host);
    373 
    374  rv = dns->AsyncResolveNative(host, nsIDNSService::RESOLVE_TYPE_DEFAULT,
    375                               nsIDNSService::RESOLVE_DISABLE_IPV6 |
    376                                   nsIDNSService::RESOLVE_TRR_DISABLED_MODE,
    377                               nullptr, this, NS_GetCurrentThread(), attrs,
    378                               getter_AddRefs(mDNSv4Request));
    379  NS_ENSURE_SUCCESS(rv, rv);
    380 
    381  Preferences::GetCString("network.connectivity-service.DNSv6.domain", host);
    382  rv = dns->AsyncResolveNative(host, nsIDNSService::RESOLVE_TYPE_DEFAULT,
    383                               nsIDNSService::RESOLVE_DISABLE_IPV4 |
    384                                   nsIDNSService::RESOLVE_TRR_DISABLED_MODE,
    385                               nullptr, this, NS_GetCurrentThread(), attrs,
    386                               getter_AddRefs(mDNSv6Request));
    387  NS_ENSURE_SUCCESS(rv, rv);
    388 
    389  Preferences::GetCString("network.connectivity-service.DNS_HTTPS.domain",
    390                          host);
    391  rv = dns->AsyncResolveNative(host, nsIDNSService::RESOLVE_TYPE_HTTPSSVC,
    392                               nsIDNSService::RESOLVE_TRR_DISABLED_MODE,
    393                               nullptr, this, NS_GetCurrentThread(), attrs,
    394                               getter_AddRefs(mDNS_HTTPSRequest));
    395  if (NS_FAILED(rv)) {
    396    mDNS_HTTPSRequest = nullptr;
    397  }
    398 
    399  if (StaticPrefs::network_connectivity_service_nat64_check()) {
    400    rv = dns->AsyncResolveNative("ipv4only.arpa"_ns,
    401                                 nsIDNSService::RESOLVE_TYPE_DEFAULT,
    402                                 nsIDNSService::RESOLVE_DISABLE_IPV4 |
    403                                     nsIDNSService::RESOLVE_TRR_DISABLED_MODE,
    404                                 nullptr, this, NS_GetCurrentThread(), attrs,
    405                                 getter_AddRefs(mNAT64Request));
    406    NS_ENSURE_SUCCESS(rv, rv);
    407  }
    408  return rv;
    409 }
    410 
    411 NS_IMETHODIMP
    412 NetworkConnectivityService::Observe(nsISupports* aSubject, const char* aTopic,
    413                                    const char16_t* aData) {
    414  if (!strcmp(aTopic, "network:captive-portal-connectivity")) {
    415    // Captive portal is cleared, so we redo the checks.
    416    PerformChecks();
    417  } else if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
    418    if (mDNSv4Request) {
    419      mDNSv4Request->Cancel(NS_ERROR_ABORT);
    420      mDNSv4Request = nullptr;
    421    }
    422    if (mDNSv6Request) {
    423      mDNSv6Request->Cancel(NS_ERROR_ABORT);
    424      mDNSv6Request = nullptr;
    425    }
    426    if (mDNS_HTTPSRequest) {
    427      mDNS_HTTPSRequest->Cancel(NS_ERROR_ABORT);
    428      mDNS_HTTPSRequest = nullptr;
    429    }
    430    if (mNAT64Request) {
    431      mNAT64Request->Cancel(NS_ERROR_ABORT);
    432      mNAT64Request = nullptr;
    433    }
    434 
    435    nsCOMPtr<nsIObserverService> observerService =
    436        mozilla::services::GetObserverService();
    437    observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
    438    observerService->RemoveObserver(this,
    439                                    "network:captive-portal-connectivity");
    440    observerService->RemoveObserver(this, NS_NETWORK_LINK_TOPIC);
    441  } else if (!strcmp(aTopic, NS_NETWORK_LINK_TOPIC) &&
    442             !NS_LITERAL_STRING_FROM_CSTRING(NS_NETWORK_LINK_DATA_UNKNOWN)
    443                  .Equals(aData)) {
    444    PerformChecks();
    445  } else if (!strcmp(aTopic, "browser-idle-startup-tasks-finished")) {
    446    mIdleStartupDone = true;
    447    PerformChecks();
    448  }
    449 
    450  return NS_OK;
    451 }
    452 
    453 already_AddRefed<nsIChannel> NetworkConnectivityService::SetupIPCheckChannel(
    454    bool ipv4) {
    455  nsresult rv;
    456  nsAutoCString url;
    457 
    458  if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
    459    return nullptr;
    460  }
    461 
    462  if (ipv4) {
    463    rv = Preferences::GetCString("network.connectivity-service.IPv4.url", url);
    464  } else {
    465    rv = Preferences::GetCString("network.connectivity-service.IPv6.url", url);
    466  }
    467  NS_ENSURE_SUCCESS(rv, nullptr);
    468 
    469  nsCOMPtr<nsIURI> uri;
    470  rv = NS_NewURI(getter_AddRefs(uri), url);
    471  NS_ENSURE_SUCCESS(rv, nullptr);
    472 
    473  nsCOMPtr<nsIChannel> channel;
    474  if (XRE_IsSocketProcess()) {
    475    rv = DNSUtils::CreateChannelHelper(uri, getter_AddRefs(channel));
    476    if (NS_FAILED(rv)) {
    477      return nullptr;
    478    }
    479    channel->SetLoadFlags(
    480        nsIRequest::LOAD_BYPASS_CACHE |  // don't read from the cache
    481        nsIRequest::INHIBIT_CACHING |    // don't write the response to cache
    482        nsIRequest::LOAD_ANONYMOUS);
    483  } else {
    484    rv = NS_NewChannel(
    485        getter_AddRefs(channel), uri, nsContentUtils::GetSystemPrincipal(),
    486        nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
    487        nsIContentPolicy::TYPE_OTHER,
    488        nullptr,  // nsICookieJarSettings
    489        nullptr,  // aPerformanceStorage
    490        nullptr,  // aLoadGroup
    491        nullptr,
    492        nsIRequest::LOAD_BYPASS_CACHE |    // don't read from the cache
    493            nsIRequest::INHIBIT_CACHING |  // don't write the response to cache
    494            nsIRequest::LOAD_ANONYMOUS);   // prevent privacy leaks
    495    NS_ENSURE_SUCCESS(rv, nullptr);
    496 
    497    {
    498      // Prevent HTTPS-Only Mode from upgrading the OCSP request.
    499      nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
    500      uint32_t httpsOnlyStatus = loadInfo->GetHttpsOnlyStatus();
    501      httpsOnlyStatus |= nsILoadInfo::HTTPS_ONLY_EXEMPT;
    502      loadInfo->SetHttpsOnlyStatus(httpsOnlyStatus);
    503 
    504      // allow deprecated HTTP request from SystemPrincipal
    505      loadInfo->SetAllowDeprecatedSystemRequests(true);
    506    }
    507  }
    508 
    509  rv = channel->SetTRRMode(nsIRequest::TRR_DISABLED_MODE);
    510  NS_ENSURE_SUCCESS(rv, nullptr);
    511 
    512  if (nsCOMPtr<nsIHttpChannelInternal> internalChan =
    513          do_QueryInterface(channel)) {
    514    if (ipv4) {
    515      internalChan->SetIPv6Disabled();
    516    } else {
    517      internalChan->SetIPv4Disabled();
    518    }
    519  }
    520 
    521  return channel.forget();
    522 }
    523 
    524 NS_IMETHODIMP
    525 NetworkConnectivityService::RecheckIPConnectivity() {
    526  bool enabled =
    527      Preferences::GetBool("network.connectivity-service.enabled", false);
    528  if (!enabled) {
    529    return NS_OK;
    530  }
    531 
    532  if (nsIOService::UseSocketProcess()) {
    533    RefPtr<SocketProcessParent> parent = SocketProcessParent::GetSingleton();
    534    if (parent) {
    535      (void)parent->SendRecheckIPConnectivity();
    536    }
    537  }
    538 
    539  if (xpc::AreNonLocalConnectionsDisabled() &&
    540      !Preferences::GetBool("network.captive-portal-service.testMode", false)) {
    541    return NS_OK;
    542  }
    543 
    544  if (mIPv4Channel) {
    545    mIPv4Channel->Cancel(NS_ERROR_ABORT);
    546    mIPv4Channel = nullptr;
    547  }
    548  if (mIPv6Channel) {
    549    mIPv6Channel->Cancel(NS_ERROR_ABORT);
    550    mIPv6Channel = nullptr;
    551  }
    552 
    553  nsresult rv;
    554  mHasNetworkId = false;
    555  mCheckedNetworkId = false;
    556  mIPv4Channel = SetupIPCheckChannel(/* ipv4 = */ true);
    557  if (mIPv4Channel) {
    558    rv = mIPv4Channel->AsyncOpen(this);
    559    NS_ENSURE_SUCCESS(rv, rv);
    560  }
    561 
    562  mIPv6Channel = SetupIPCheckChannel(/* ipv4 = */ false);
    563  if (mIPv6Channel) {
    564    rv = mIPv6Channel->AsyncOpen(this);
    565    NS_ENSURE_SUCCESS(rv, rv);
    566  }
    567 
    568  return NS_OK;
    569 }
    570 
    571 NS_IMETHODIMP
    572 NetworkConnectivityService::OnStartRequest(nsIRequest* aRequest) {
    573  return NS_OK;
    574 }
    575 
    576 NS_IMETHODIMP
    577 NetworkConnectivityService::OnStopRequest(nsIRequest* aRequest,
    578                                          nsresult aStatusCode) {
    579  if (aStatusCode == NS_ERROR_ABORT) {
    580    return NS_OK;
    581  }
    582 
    583  ConnectivityState status = NS_FAILED(aStatusCode) ? NOT_AVAILABLE : OK;
    584 
    585  if (aRequest == mIPv4Channel) {
    586    mIPv4 = status;
    587    mIPv4Channel = nullptr;
    588 
    589    if (mIPv4 == nsINetworkConnectivityService::OK) {
    590      glean::network::id_online
    591          .EnumGet(mHasNetworkId ? glean::network::IdOnlineLabel::ePresent
    592                                 : glean::network::IdOnlineLabel::eAbsent)
    593          .Add();
    594      LOG(("mHasNetworkId : %d\n", mHasNetworkId));
    595    }
    596  } else if (aRequest == mIPv6Channel) {
    597    mIPv6 = status;
    598    mIPv6Channel = nullptr;
    599  }
    600 
    601  if (!mIPv6Channel && !mIPv4Channel) {
    602    NotifyObservers("network:connectivity-service:ip-checks-complete");
    603  }
    604 
    605  return NS_OK;
    606 }
    607 
    608 NS_IMETHODIMP
    609 NetworkConnectivityService::OnDataAvailable(nsIRequest* aRequest,
    610                                            nsIInputStream* aInputStream,
    611                                            uint64_t aOffset, uint32_t aCount) {
    612  nsAutoCString data;
    613 
    614  // We perform this check here, instead of doing it in OnStopRequest in case
    615  // a network down event occurs after the data has arrived but before we fire
    616  // OnStopRequest. That would cause us to report a missing networkID, even
    617  // though it was not empty while receiving data.
    618  if (aRequest == mIPv4Channel && !mCheckedNetworkId) {
    619    nsCOMPtr<nsINetworkLinkService> nls =
    620        do_GetService(NS_NETWORK_LINK_SERVICE_CONTRACTID);
    621    nsAutoCString networkId;
    622    if (nls) {
    623      nls->GetNetworkID(networkId);
    624    }
    625    mHasNetworkId = !networkId.IsEmpty();
    626    mCheckedNetworkId = true;
    627  }
    628 
    629  (void)NS_ReadInputStreamToString(aInputStream, data, aCount);
    630  return NS_OK;
    631 }
    632 
    633 }  // namespace net
    634 }  // namespace mozilla