netwerk/base/nsIOService.h
author Mozilla Releng Treescript <release+treescript@mozilla.org>
Fri, 20 May 2022 19:04:40 +0000
changeset 618368 3b0030f76f1ee69138d29f114d5221f21c55e7e5
parent 611372 3032024389a93dd78d007ffe70cb217cd51d3f16
permissions -rw-r--r--
no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD de -> 1d458b9f128b124a25679e755f61139726a77caf dsb -> d3afb988e0d6b558a8a590658da39eb15b2f0b18 et -> 77d8cd6a89d77a9356bc597e476cd2cc764cd607 hsb -> a67aba9c3b33f8bc097d742bd70ea98ca80a1335 hu -> ccf9d887f4eb7e4bac53afde57598686a1e255b9 hye -> ed3709ec02d90cca3ebf3237ea6d6411353e2559 it -> d544065a45d9b684beb7f60bbeaf30fd1a696e69 ja -> 17e2f87f08c519add504e8f4265e0f7b6524a34a ja-JP-mac -> 0e30fddf50953f46b80dbc99825270568b1a0d65 oc -> e114f06272b1c9377d19ca013aa6a51509cb719a pt-PT -> f7bf8255666f78337b22b3206516736daf222d40 zh-CN -> ff1ee767ed480c30d6aaefa00c65c8f62477cc18

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef nsIOService_h__
#define nsIOService_h__

#include "nsStringFwd.h"
#include "nsIIOService.h"
#include "nsTArray.h"
#include "nsCOMPtr.h"
#include "nsIObserver.h"
#include "nsIWeakReferenceUtils.h"
#include "nsINetUtil.h"
#include "nsIChannelEventSink.h"
#include "nsCategoryCache.h"
#include "nsISpeculativeConnect.h"
#include "nsWeakReference.h"
#include "mozilla/Atomics.h"
#include "mozilla/Attributes.h"
#include "mozilla/Mutex.h"
#include "prtime.h"
#include "nsICaptivePortalService.h"
#include "nsIObserverService.h"
#include "nsTHashSet.h"
#include "nsWeakReference.h"
#include "nsNetCID.h"

#define NS_N(x) (sizeof(x) / sizeof(*(x)))

// We don't want to expose this observer topic.
// Intended internal use only for remoting offline/inline events.
// See Bug 552829
#define NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC "ipc:network:set-offline"
#define NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC "ipc:network:set-connectivity"

static const char gScheme[][sizeof("moz-safe-about")] = {
    "chrome",   "file",          "http",      "https",
    "jar",      "data",          "about",     "moz-safe-about",
    "resource", "moz-extension", "page-icon", "blob"};

static const char gForcedExternalSchemes[][sizeof("moz-nullprincipal")] = {
    "place", "fake-favicon-uri", "favicon", "moz-nullprincipal"};

class nsINetworkLinkService;
class nsIPrefBranch;
class nsIProtocolProxyService2;
class nsIProxyInfo;
class nsPISocketTransportService;

namespace mozilla {
class MemoryReportingProcess;
namespace net {
class NeckoChild;
class nsAsyncRedirectVerifyHelper;
class SocketProcessHost;
class SocketProcessMemoryReporter;

class nsIOService final : public nsIIOService,
                          public nsIObserver,
                          public nsINetUtil,
                          public nsISpeculativeConnect,
                          public nsSupportsWeakReference,
                          public nsIIOServiceInternal,
                          public nsIObserverService {
 public:
  NS_DECL_THREADSAFE_ISUPPORTS
  NS_DECL_NSIIOSERVICE
  NS_DECL_NSIOBSERVER
  NS_DECL_NSINETUTIL
  NS_DECL_NSISPECULATIVECONNECT
  NS_DECL_NSIIOSERVICEINTERNAL
  NS_DECL_NSIOBSERVERSERVICE

  // Gets the singleton instance of the IO Service, creating it as needed
  // Returns nullptr on out of memory or failure to initialize.
  static already_AddRefed<nsIOService> GetInstance();

  nsresult Init();
  nsresult NewURI(const char* aSpec, nsIURI* aBaseURI, nsIURI** result,
                  nsIProtocolHandler** hdlrResult);

  // Called by channels before a redirect happens. This notifies the global
  // redirect observers.
  nsresult AsyncOnChannelRedirect(nsIChannel* oldChan, nsIChannel* newChan,
                                  uint32_t flags,
                                  nsAsyncRedirectVerifyHelper* helper);

  bool IsOffline() { return mOffline; }
  PRIntervalTime LastOfflineStateChange() { return mLastOfflineStateChange; }
  PRIntervalTime LastConnectivityChange() { return mLastConnectivityChange; }
  PRIntervalTime LastNetworkLinkChange() { return mLastNetworkLinkChange; }
  bool IsNetTearingDown() {
    return mShutdown || mOfflineForProfileChange ||
           mHttpHandlerAlreadyShutingDown;
  }
  PRIntervalTime NetTearingDownStarted() { return mNetTearingDownStarted; }

  // nsHttpHandler is going to call this function to inform nsIOService that
  // network is in process of tearing down. Moving nsHttpConnectionMgr::Shutdown
  // to nsIOService caused problems (bug 1242755) so we doing it in this way. As
  // soon as nsIOService gets notification that it is shutdown it is going to
  // reset mHttpHandlerAlreadyShutingDown.
  void SetHttpHandlerAlreadyShutingDown();

  bool IsLinkUp();

  // Converts an internal URI (e.g. one that has a username and password in
  // it) into one which we can expose to the user, for example on the URL bar.
  static already_AddRefed<nsIURI> CreateExposableURI(nsIURI*);

  // Used to count the total number of HTTP requests made
  void IncrementRequestNumber() { mTotalRequests++; }
  uint32_t GetTotalRequestNumber() { return mTotalRequests; }
  // Used to keep "race cache with network" stats
  void IncrementCacheWonRequestNumber() { mCacheWon++; }
  uint32_t GetCacheWonRequestNumber() { return mCacheWon; }
  void IncrementNetWonRequestNumber() { mNetWon++; }
  uint32_t GetNetWonRequestNumber() { return mNetWon; }

  // Used to trigger a recheck of the captive portal status
  nsresult RecheckCaptivePortal();

  void OnProcessLaunchComplete(SocketProcessHost* aHost, bool aSucceeded);
  void OnProcessUnexpectedShutdown(SocketProcessHost* aHost);
  bool SocketProcessReady();
  static void NotifySocketProcessPrefsChanged(const char* aName, void* aSelf);
  void NotifySocketProcessPrefsChanged(const char* aName);
  static bool UseSocketProcess(bool aCheckAgain = false);

  bool IsSocketProcessLaunchComplete();

  // Call func immediately if socket process is launched completely. Otherwise,
  // |func| will be queued and then executed in the *main thread* once socket
  // process is launced.
  void CallOrWaitForSocketProcess(const std::function<void()>& aFunc);

  int32_t SocketProcessPid();
  SocketProcessHost* SocketProcess() { return mSocketProcess; }

  friend SocketProcessMemoryReporter;
  RefPtr<MemoryReportingProcess> GetSocketProcessMemoryReporter();

  static void OnTLSPrefChange(const char* aPref, void* aSelf);

  nsresult LaunchSocketProcess();

  static bool TooManySocketProcessCrash();
  static void IncreaseSocketProcessCrashCount();

 private:
  // These shouldn't be called directly:
  // - construct using GetInstance
  // - destroy using Release
  nsIOService();
  ~nsIOService();
  nsresult SetConnectivityInternal(bool aConnectivity);

  nsresult OnNetworkLinkEvent(const char* data);

  nsresult GetCachedProtocolHandler(const char* scheme,
                                    nsIProtocolHandler** hdlrResult,
                                    uint32_t start = 0, uint32_t end = 0);
  nsresult CacheProtocolHandler(const char* scheme,
                                nsIProtocolHandler* handler);

  nsresult InitializeCaptivePortalService();
  nsresult RecheckCaptivePortalIfLocalRedirect(nsIChannel* newChan);

  // Prefs wrangling
  static void PrefsChanged(const char* pref, void* self);
  void PrefsChanged(const char* pref = nullptr);
  void ParsePortList(const char* pref, bool remove);

  nsresult InitializeSocketTransportService();
  nsresult InitializeNetworkLinkService();
  nsresult InitializeProtocolProxyService();

  // consolidated helper function
  void LookupProxyInfo(nsIURI* aURI, nsIURI* aProxyURI, uint32_t aProxyFlags,
                       nsCString* aScheme, nsIProxyInfo** outPI);

  nsresult NewChannelFromURIWithProxyFlagsInternal(
      nsIURI* aURI, nsIURI* aProxyURI, uint32_t aProxyFlags,
      nsINode* aLoadingNode, nsIPrincipal* aLoadingPrincipal,
      nsIPrincipal* aTriggeringPrincipal,
      const mozilla::Maybe<mozilla::dom::ClientInfo>& aLoadingClientInfo,
      const mozilla::Maybe<mozilla::dom::ServiceWorkerDescriptor>& aController,
      uint32_t aSecurityFlags, nsContentPolicyType aContentPolicyType,
      uint32_t aSandboxFlags, nsIChannel** result);

  nsresult NewChannelFromURIWithProxyFlagsInternal(nsIURI* aURI,
                                                   nsIURI* aProxyURI,
                                                   uint32_t aProxyFlags,
                                                   nsILoadInfo* aLoadInfo,
                                                   nsIChannel** result);

  nsresult SpeculativeConnectInternal(nsIURI* aURI, nsIPrincipal* aPrincipal,
                                      nsIInterfaceRequestor* aCallbacks,
                                      bool aAnonymous);

  void DestroySocketProcess();

  nsresult SetOfflineInternal(bool offline, bool notifySocketProcess = true);

 private:
  mozilla::Atomic<bool, mozilla::Relaxed> mOffline{true};
  mozilla::Atomic<bool, mozilla::Relaxed> mOfflineForProfileChange{false};
  bool mManageLinkStatus{false};
  mozilla::Atomic<bool, mozilla::Relaxed> mConnectivity{true};

  // Used to handle SetOffline() reentrancy.  See the comment in
  // SetOffline() for more details.
  bool mSettingOffline{false};
  bool mSetOfflineValue{false};

  bool mSocketProcessLaunchComplete{false};

  mozilla::Atomic<bool, mozilla::Relaxed> mShutdown{false};
  mozilla::Atomic<bool, mozilla::Relaxed> mHttpHandlerAlreadyShutingDown{false};

  nsCOMPtr<nsPISocketTransportService> mSocketTransportService;
  nsCOMPtr<nsICaptivePortalService> mCaptivePortalService;
  nsCOMPtr<nsINetworkLinkService> mNetworkLinkService;
  bool mNetworkLinkServiceInitialized{false};

  // Cached protocol handlers, only accessed on the main thread
  nsWeakPtr mWeakHandler[NS_N(gScheme)];

  // cached categories
  nsCategoryCache<nsIChannelEventSink> mChannelEventSinks{
      NS_CHANNEL_EVENT_SINK_CATEGORY};

  Mutex mMutex{"nsIOService::mMutex"};
  nsTArray<int32_t> mRestrictedPortList GUARDED_BY(mMutex);

  uint32_t mTotalRequests{0};
  uint32_t mCacheWon{0};
  uint32_t mNetWon{0};
  static uint32_t sSocketProcessCrashedCount;

  // These timestamps are needed for collecting telemetry on PR_Connect,
  // PR_ConnectContinue and PR_Close blocking time.  If we spend very long
  // time in any of these functions we want to know if and what network
  // change has happened shortly before.
  mozilla::Atomic<PRIntervalTime> mLastOfflineStateChange;
  mozilla::Atomic<PRIntervalTime> mLastConnectivityChange;
  mozilla::Atomic<PRIntervalTime> mLastNetworkLinkChange;

  // Time a network tearing down started.
  mozilla::Atomic<PRIntervalTime> mNetTearingDownStarted{0};

  SocketProcessHost* mSocketProcess{nullptr};

  // Events should be executed after the socket process is launched. Will
  // dispatch these events while socket process fires OnProcessLaunchComplete.
  // Note: this array is accessed only on the main thread.
  nsTArray<std::function<void()>> mPendingEvents;

  // The observer notifications need to be forwarded to socket process.
  nsTHashSet<nsCString> mObserverTopicForSocketProcess;
  // Some noticications (e.g., NS_XPCOM_SHUTDOWN_OBSERVER_ID) are triggered in
  // socket process, so we should not send the notifications again.
  nsTHashSet<nsCString> mSocketProcessTopicBlockedList;
  // Used to store the topics that are already observed by IOService.
  nsTHashSet<nsCString> mIOServiceTopicList;

  nsCOMPtr<nsIObserverService> mObserverService;

 public:
  // Used for all default buffer sizes that necko allocates.
  static uint32_t gDefaultSegmentSize;
  static uint32_t gDefaultSegmentCount;
};

/**
 * Reference to the IO service singleton. May be null.
 */
extern nsIOService* gIOService;

}  // namespace net
}  // namespace mozilla

#endif  // nsIOService_h__