Bug 1317511 - [aurora] Share captive portal state with the content process r=bagder a=jcristau
authorValentin Gosu <valentin.gosu@gmail.com>
Wed, 16 Nov 2016 16:33:20 +0100
changeset 353366 11814a11cdbb6d3c0b0fdac54a0d750c1af94822
parent 353365 39ac6ce89edf573e28f0bd921b0944e3621f1d25
child 353367 5af63cf90f2874f840c132461bff7f6130483362
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-esr52@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbagder, jcristau
bugs1317511
milestone52.0a2
Bug 1317511 - [aurora] Share captive portal state with the content process r=bagder a=jcristau
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
netwerk/base/CaptivePortalService.cpp
netwerk/base/CaptivePortalService.h
netwerk/base/nsICaptivePortalService.idl
netwerk/base/nsIOService.cpp
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -49,16 +49,17 @@
 #include "mozilla/ipc/TestShellChild.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 #include "mozilla/layers/APZChild.h"
 #include "mozilla/layers/CompositorBridgeChild.h"
 #include "mozilla/layers/ContentProcessController.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "mozilla/layout/RenderFrameChild.h"
 #include "mozilla/net/NeckoChild.h"
+#include "mozilla/net/CaptivePortalService.h"
 #include "mozilla/plugins/PluginInstanceParent.h"
 #include "mozilla/plugins/PluginModuleParent.h"
 #include "mozilla/widget/WidgetMessageUtils.h"
 #include "nsBaseDragService.h"
 #include "mozilla/media/MediaChild.h"
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/WebBrowserPersistDocumentChild.h"
 #include "imgLoader.h"
@@ -925,23 +926,25 @@ ContentChild::InitXPCOM()
 
   bool isOffline, isLangRTL, haveBidiKeyboards;
   bool isConnected;
   ClipboardCapabilities clipboardCaps;
   DomainPolicyClone domainPolicy;
   StructuredCloneData initialData;
   OptionalURIParams userContentSheetURL;
 
-  SendGetXPCOMProcessAttributes(&isOffline, &isConnected,
+  int32_t captivePortalState;
+  SendGetXPCOMProcessAttributes(&isOffline, &isConnected, &captivePortalState,
                                 &isLangRTL, &haveBidiKeyboards,
                                 &mAvailableDictionaries,
                                 &clipboardCaps, &domainPolicy, &initialData,
                                 &userContentSheetURL);
   RecvSetOffline(isOffline);
   RecvSetConnectivity(isConnected);
+  RecvSetCaptivePortalState(captivePortalState);
   RecvBidiKeyboardNotify(isLangRTL, haveBidiKeyboards);
 
   // Create the CPOW manager as soon as possible.
   SendPJavaScriptConstructor();
 
   if (domainPolicy.active()) {
     nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
     MOZ_ASSERT(ssm);
@@ -2072,16 +2075,31 @@ ContentChild::RecvSetConnectivity(const 
   nsCOMPtr<nsIIOServiceInternal> ioInternal(do_QueryInterface(io));
   NS_ASSERTION(ioInternal, "IO Service can not be null");
 
   ioInternal->SetConnectivity(connectivity);
 
   return true;
 }
 
+bool
+ContentChild::RecvSetCaptivePortalState(const int32_t& aState)
+{
+  nsCOMPtr<nsICaptivePortalService> cps = do_GetService(NS_CAPTIVEPORTAL_CID);
+  if (!cps) {
+    return true;
+  }
+
+  mozilla::net::CaptivePortalService *portal =
+    static_cast<mozilla::net::CaptivePortalService*>(cps.get());
+  portal->SetStateInChild(aState);
+
+  return true;
+}
+
 void
 ContentChild::ActorDestroy(ActorDestroyReason why)
 {
   if (mForceKillTimer) {
     mForceKillTimer->Cancel();
     mForceKillTimer = nullptr;
   }
 
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -367,16 +367,17 @@ public:
 
   virtual PRemoteSpellcheckEngineChild* AllocPRemoteSpellcheckEngineChild() override;
 
   virtual bool DeallocPRemoteSpellcheckEngineChild(PRemoteSpellcheckEngineChild*) override;
 
   virtual bool RecvSetOffline(const bool& offline) override;
 
   virtual bool RecvSetConnectivity(const bool& connectivity) override;
+  virtual bool RecvSetCaptivePortalState(const int32_t& state) override;
 
   virtual bool RecvNotifyLayerAllocated(const dom::TabId& aTabId, const uint64_t& aLayersId) override;
 
   virtual bool RecvSpeakerManagerNotify() override;
 
   virtual bool RecvBidiKeyboardNotify(const bool& isLangRTL,
                                       const bool& haveBidiKeyboards) override;
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -177,16 +177,17 @@
 #include "mozilla/dom/ipc/StructuredCloneData.h"
 #include "mozilla/psm/PSMContentListener.h"
 #include "nsPluginHost.h"
 #include "nsPluginTags.h"
 #include "nsIBlocklistService.h"
 #include "mozilla/StyleSheet.h"
 #include "mozilla/StyleSheetInlines.h"
 #include "nsHostObjectProtocolHandler.h"
+#include "nsICaptivePortalService.h"
 
 #include "nsIBidiKeyboard.h"
 
 #include "nsLayoutStylesheetCache.h"
 
 #ifdef MOZ_WEBRTC
 #include "signaling/src/peerconnection/WebrtcGlobalParent.h"
 #endif
@@ -532,16 +533,17 @@ static uint64_t gContentChildID = 1;
 // Can't be a static constant.
 #define MAGIC_PREALLOCATED_APP_MANIFEST_URL NS_LITERAL_STRING("{{template}}")
 
 static const char* sObserverTopics[] = {
   "xpcom-shutdown",
   "profile-before-change",
   NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC,
   NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC,
+  NS_IPC_CAPTIVE_PORTAL_SET_STATE,
   "memory-pressure",
   "child-gc-request",
   "child-cc-request",
   "child-mmu-request",
   "last-pb-context-exited",
   "file-watcher-update",
 #ifdef MOZ_WIDGET_GONK
   NS_VOLUME_STATE_CHANGED,
@@ -2734,16 +2736,27 @@ ContentParent::Observe(nsISupports* aSub
     if (!SendSetOffline(!strcmp(offline, "true") ? true : false)) {
       return NS_ERROR_NOT_AVAILABLE;
     }
   }
   else if (!strcmp(aTopic, NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC)) {
     if (!SendSetConnectivity(NS_LITERAL_STRING("true").Equals(aData))) {
       return NS_ERROR_NOT_AVAILABLE;
     }
+  } else if (!strcmp(aTopic, NS_IPC_CAPTIVE_PORTAL_SET_STATE)) {
+    nsCOMPtr<nsICaptivePortalService> cps = do_QueryInterface(aSubject);
+    MOZ_ASSERT(cps, "Should QI to a captive portal service");
+    if (!cps) {
+      return NS_ERROR_FAILURE;
+    }
+    int32_t state;
+    cps->GetState(&state);
+    if (!SendSetCaptivePortalState(state)) {
+      return NS_ERROR_NOT_AVAILABLE;
+    }
   }
   // listening for alert notifications
   else if (!strcmp(aTopic, "alertfinished") ||
        !strcmp(aTopic, "alertclickcallback") ||
        !strcmp(aTopic, "alertshow") ||
        !strcmp(aTopic, "alertdisablecallback") ||
        !strcmp(aTopic, "alertsettingscallback")) {
     if (!SendNotifyAlertsObserver(nsDependentCString(aTopic),
@@ -2885,32 +2898,39 @@ ContentParent::RecvGetProcessAttributes(
   *aIsForBrowser = mIsForBrowser;
 
   return true;
 }
 
 bool
 ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline,
                                              bool* aIsConnected,
+                                             int32_t* aCaptivePortalState,
                                              bool* aIsLangRTL,
                                              bool* aHaveBidiKeyboards,
                                              InfallibleTArray<nsString>* dictionaries,
                                              ClipboardCapabilities* clipboardCaps,
                                              DomainPolicyClone* domainPolicy,
                                              StructuredCloneData* aInitialData,
                                              OptionalURIParams* aUserContentCSSURL)
 {
   nsCOMPtr<nsIIOService> io(do_GetIOService());
   MOZ_ASSERT(io, "No IO service?");
   DebugOnly<nsresult> rv = io->GetOffline(aIsOffline);
   MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting offline?");
 
   rv = io->GetConnectivity(aIsConnected);
   MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting connectivity?");
 
+  *aCaptivePortalState = nsICaptivePortalService::UNKNOWN;
+  nsCOMPtr<nsICaptivePortalService> cps = do_GetService(NS_CAPTIVEPORTAL_CONTRACTID);
+  if (cps) {
+    cps->GetState(aCaptivePortalState);
+  }
+
   nsIBidiKeyboard* bidi = nsContentUtils::GetBidiKeyboard();
 
   *aIsLangRTL = false;
   *aHaveBidiKeyboards = false;
   if (bidi) {
     bidi->IsLangRTL(aIsLangRTL);
     bidi->GetHaveBidiKeyboards(aHaveBidiKeyboards);
   }
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -702,16 +702,17 @@ private:
 
   virtual bool RecvGetProcessAttributes(ContentParentId* aCpId,
                                         bool* aIsForApp,
                                         bool* aIsForBrowser) override;
 
   virtual bool
   RecvGetXPCOMProcessAttributes(bool* aIsOffline,
                                 bool* aIsConnected,
+                                int32_t* aCaptivePortalState,
                                 bool* aIsLangRTL,
                                 bool* aHaveBidiKeyboards,
                                 InfallibleTArray<nsString>* dictionaries,
                                 ClipboardCapabilities* clipboardCaps,
                                 DomainPolicyClone* domainPolicy,
                                 StructuredCloneData* initialData,
                                 OptionalURIParams* aUserContentSheetURL) override;
 
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -479,16 +479,17 @@ child:
     async RegisterChrome(ChromePackage[] packages, SubstitutionMapping[] substitutions,
                          OverrideMapping[] overrides, nsCString locale, bool reset);
     async RegisterChromeItem(ChromeRegistryItem item);
 
     async ClearImageCache(bool privateLoader, bool chrome);
 
     async SetOffline(bool offline);
     async SetConnectivity(bool connectivity);
+    async SetCaptivePortalState(int32_t aState);
 
     async NotifyVisited(URIParams uri);
 
     async PreferenceUpdate(PrefSetting pref);
     async VarUpdate(GfxVarUpdate var);
 
     async DataStoragePut(nsString aFilename, DataStorageItem aItem);
     async DataStorageRemove(nsString aFilename, nsCString aKey, DataStorageType aType);
@@ -683,17 +684,18 @@ parent:
      * |isForBrowser|, we're loading <browser>.  When |!isForApp &&
      * !isForBrowser|, we're probably loading <xul:browser remote>.
      *
      * Keep the return values in sync with PBrowser()!
      */
     sync GetProcessAttributes()
         returns (ContentParentId cpId, bool isForApp, bool isForBrowser);
     sync GetXPCOMProcessAttributes()
-        returns (bool isOffline, bool isConnected, bool isLangRTL,
+        returns (bool isOffline, bool isConnected, int32_t captivePortalState,
+                 bool isLangRTL,
                  bool haveBidiKeyboards, nsString[] dictionaries,
                  ClipboardCapabilities clipboardCaps,
                  DomainPolicyClone domainPolicy,
                  StructuredCloneData initialData,
                  OptionalURIParams userContentSheetURL);
 
     sync CreateChildProcess(IPCTabContext context,
                             ProcessPriority priority,
--- a/netwerk/base/CaptivePortalService.cpp
+++ b/netwerk/base/CaptivePortalService.cpp
@@ -1,13 +1,13 @@
 /* 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/. */
 
-#include "CaptivePortalService.h"
+#include "mozilla/net/CaptivePortalService.h"
 #include "mozilla/Services.h"
 #include "mozilla/Preferences.h"
 #include "nsIObserverService.h"
 #include "nsServiceManagerUtils.h"
 #include "nsXULAppAPI.h"
 
 static const char16_t kInterfaceName[] = u"captive-portal-inteface";
 
@@ -51,17 +51,17 @@ nsresult
 CaptivePortalService::PerformCheck()
 {
   LOG(("CaptivePortalService::PerformCheck mRequestInProgress:%d mInitialized:%d mStarted:%d\n",
         mRequestInProgress, mInitialized, mStarted));
   // Don't issue another request if last one didn't complete
   if (mRequestInProgress || !mInitialized || !mStarted) {
     return NS_OK;
   }
-
+  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
   nsresult rv;
   if (!mCaptivePortalDetector) {
     mCaptivePortalDetector =
       do_GetService("@mozilla.org/toolkit/captive-detector;1", &rv);
     if (NS_FAILED(rv)) {
         LOG(("Unable to get a captive portal detector\n"));
         return rv;
     }
@@ -72,16 +72,17 @@ CaptivePortalService::PerformCheck()
   mCaptivePortalDetector->CheckCaptivePortal(kInterfaceName, this);
   return NS_OK;
 }
 
 nsresult
 CaptivePortalService::RearmTimer()
 {
   // Start a timer to recheck
+  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
   if (mTimer) {
     mTimer->Cancel();
   }
 
   if (!mTimer) {
     mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
   }
 
@@ -91,21 +92,27 @@ CaptivePortalService::RearmTimer()
   }
 
   return NS_OK;
 }
 
 nsresult
 CaptivePortalService::Initialize()
 {
-  if (mInitialized || XRE_GetProcessType() != GeckoProcessType_Default) {
+  if (mInitialized) {
     return NS_OK;
   }
   mInitialized = true;
 
+  // Only the main process service should actually do anything. The service in
+  // the content process only mirrors the CP state in the main process.
+  if (XRE_GetProcessType() != GeckoProcessType_Default) {
+    return NS_OK;
+  }
+
   nsCOMPtr<nsIObserverService> observerService =
     mozilla::services::GetObserverService();
   if (observerService) {
     observerService->AddObserver(this, kOpenCaptivePortalLoginEvent, true);
     observerService->AddObserver(this, kAbortCaptivePortalLoginEvent, true);
     observerService->AddObserver(this, kCaptivePortalLoginSuccessEvent, true);
   }
 
@@ -115,16 +122,21 @@ CaptivePortalService::Initialize()
 
 nsresult
 CaptivePortalService::Start()
 {
   if (!mInitialized) {
     return NS_ERROR_NOT_INITIALIZED;
   }
 
+  if (XRE_GetProcessType() != GeckoProcessType_Default) {
+    // Doesn't do anything if called in the content process.
+    return NS_OK;
+  }
+
   if (mStarted) {
     return NS_OK;
   }
 
   mStarted = true;
   mEverBeenCaptive = false;
 
   // Get the delay prefs
@@ -144,16 +156,21 @@ CaptivePortalService::Start()
   return NS_OK;
 }
 
 nsresult
 CaptivePortalService::Stop()
 {
   LOG(("CaptivePortalService::Stop\n"));
 
+  if (XRE_GetProcessType() != GeckoProcessType_Default) {
+    // Doesn't do anything when called in the content process.
+    return NS_OK;
+  }
+
   if (!mStarted) {
     return NS_OK;
   }
 
   if (mTimer) {
     mTimer->Cancel();
   }
   mTimer = nullptr;
@@ -161,16 +178,27 @@ CaptivePortalService::Stop()
   mStarted = false;
   if (mCaptivePortalDetector) {
     mCaptivePortalDetector->Abort(kInterfaceName);
   }
   mCaptivePortalDetector = nullptr;
   return NS_OK;
 }
 
+void
+CaptivePortalService::SetStateInChild(int32_t aState)
+{
+  // This should only be called in the content process, from ContentChild.cpp
+  // in order to mirror the captive portal state set in the chrome process.
+  MOZ_ASSERT(XRE_GetProcessType() != GeckoProcessType_Default);
+
+  mState = aState;
+  mLastChecked = TimeStamp::Now();
+}
+
 //-----------------------------------------------------------------------------
 // CaptivePortalService::nsICaptivePortalService
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 CaptivePortalService::GetState(int32_t *aState)
 {
   *aState = UNKNOWN;
@@ -182,16 +210,21 @@ CaptivePortalService::GetState(int32_t *
   return NS_OK;
 }
 
 NS_IMETHODIMP
 CaptivePortalService::RecheckCaptivePortal()
 {
   LOG(("CaptivePortalService::RecheckCaptivePortal\n"));
 
+  if (XRE_GetProcessType() != GeckoProcessType_Default) {
+    // Doesn't do anything if called in the content process.
+    return NS_OK;
+  }
+
   // This is called for user activity. We need to reset the slack count,
   // so the checks continue to be quite frequent.
   mSlackCount = 0;
   mDelay = mMinInterval;
 
   PerformCheck();
   RearmTimer();
   return NS_OK;
@@ -210,16 +243,17 @@ CaptivePortalService::GetLastChecked(uin
 // This callback gets called every mDelay miliseconds
 // It issues a checkCaptivePortal operation if one isn't already in progress
 //-----------------------------------------------------------------------------
 NS_IMETHODIMP
 CaptivePortalService::Notify(nsITimer *aTimer)
 {
   LOG(("CaptivePortalService::Notify\n"));
   MOZ_ASSERT(aTimer == mTimer);
+  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
 
   PerformCheck();
 
   // This is needed because we don't want to always make requests very often.
   // Every 10 checks, we the delay is increased mBackoffFactor times
   // to a maximum delay of mMaxInterval
   mSlackCount++;
   if (mSlackCount % 10 == 0) {
@@ -238,16 +272,21 @@ CaptivePortalService::Notify(nsITimer *a
 //-----------------------------------------------------------------------------
 // CaptivePortalService::nsIObserver
 //-----------------------------------------------------------------------------
 NS_IMETHODIMP
 CaptivePortalService::Observe(nsISupports *aSubject,
                               const char * aTopic,
                               const char16_t * aData)
 {
+  if (XRE_GetProcessType() != GeckoProcessType_Default) {
+    // Doesn't do anything if called in the content process.
+    return NS_OK;
+  }
+
   LOG(("CaptivePortalService::Observe() topic=%s\n", aTopic));
   if (!strcmp(aTopic, kOpenCaptivePortalLoginEvent)) {
     // A redirect or altered content has been detected.
     // The user needs to log in. We are in a captive portal.
     mState = LOCKED_PORTAL;
     mLastChecked = TimeStamp::Now();
     mEverBeenCaptive = true;
   } else if (!strcmp(aTopic, kCaptivePortalLoginSuccessEvent)) {
@@ -260,37 +299,48 @@ CaptivePortalService::Observe(nsISupport
     RearmTimer();
   } else if (!strcmp(aTopic, kAbortCaptivePortalLoginEvent)) {
     // The login has been aborted
     mRequestInProgress = false;
     mState = UNKNOWN;
     mLastChecked = TimeStamp::Now();
     mSlackCount = 0;
   }
+
+  // Send notification so that the captive portal state is mirrored in the
+  // content process.
+  nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
+  if (observerService) {
+    nsCOMPtr<nsICaptivePortalService> cps(this);
+    observerService->NotifyObservers(cps, NS_IPC_CAPTIVE_PORTAL_SET_STATE, nullptr);
+  }
+
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 // CaptivePortalService::nsICaptivePortalCallback
 //-----------------------------------------------------------------------------
 NS_IMETHODIMP
 CaptivePortalService::Prepare()
 {
   LOG(("CaptivePortalService::Prepare\n"));
+  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
   // XXX: Finish preparation shouldn't be called until dns and routing is available.
   if (mCaptivePortalDetector) {
     mCaptivePortalDetector->FinishPreparation(kInterfaceName);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 CaptivePortalService::Complete(bool success)
 {
   LOG(("CaptivePortalService::Complete(success=%d) mState=%d\n", success, mState));
+  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
   mLastChecked = TimeStamp::Now();
   if ((mState == UNKNOWN || mState == NOT_CAPTIVE) && success) {
     mState = NOT_CAPTIVE;
     // If this check succeeded and we have never been in a captive portal
     // since the service was started, there is no need to keep polling
     if (!mEverBeenCaptive) {
       mDelay = 0;
       if (mTimer) {
--- a/netwerk/base/CaptivePortalService.h
+++ b/netwerk/base/CaptivePortalService.h
@@ -29,16 +29,20 @@ public:
   NS_DECL_NSIOBSERVER
   NS_DECL_NSITIMERCALLBACK
   NS_DECL_NSICAPTIVEPORTALCALLBACK
 
   CaptivePortalService();
   nsresult Initialize();
   nsresult Start();
   nsresult Stop();
+
+  // This method is only called in the content process, in order to mirror
+  // the captive portal state in the parent process.
+  void SetStateInChild(int32_t aState);
 private:
   virtual ~CaptivePortalService();
   nsresult PerformCheck();
   nsresult RearmTimer();
 
   nsCOMPtr<nsICaptivePortalDetector>    mCaptivePortalDetector;
   int32_t                               mState;
 
--- a/netwerk/base/nsICaptivePortalService.idl
+++ b/netwerk/base/nsICaptivePortalService.idl
@@ -10,35 +10,50 @@ interface nsICaptivePortalServiceCallbac
   /**
    * Invoke callbacks after captive portal detection finished.
    */
   void complete(in bool success, in nsresult error);
 };
 
 /**
  * Service used for captive portal detection.
+ * The service is only active in the main process. It is also available in the
+ * content process, but only to mirror the captive portal state from the main
+ * process.
  */
 [scriptable, uuid(bdbe0555-fc3d-4f7b-9205-c309ceb2d641)]
 interface nsICaptivePortalService : nsISupports
 {
   const long UNKNOWN          = 0;
   const long NOT_CAPTIVE      = 1;
   const long UNLOCKED_PORTAL  = 2;
   const long LOCKED_PORTAL    = 3;
 
   /**
    * Called from XPCOM to trigger a captive portal recheck.
    * A network request will only be performed if no other checks are currently
    * ongoing.
+   * Will not do anything if called in the content process.
    */
   void recheckCaptivePortal();
 
   /**
    * Returns the state of the captive portal.
    */
   readonly attribute long state;
 
   /**
    * Returns the time difference between NOW and the last time a request was
    * completed in milliseconds.
    */
   readonly attribute unsigned long long lastChecked;
 };
+
+%{C++
+/**
+ * This observer notification will be emitted when the captive portal state
+ * changes. After receiving it, the ContentParent will send an IPC message
+ * to the ContentChild, which will set the state in the captive portal service
+ * in the child.
+ */
+#define NS_IPC_CAPTIVE_PORTAL_SET_STATE "ipc:network:captive-portal-set-state"
+
+%}
--- a/netwerk/base/nsIOService.cpp
+++ b/netwerk/base/nsIOService.cpp
@@ -48,17 +48,17 @@
 #include "mozilla/LoadInfo.h"
 #include "mozilla/net/NeckoCommon.h"
 #include "mozilla/Services.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/net/DNS.h"
 #include "mozilla/ipc/URIUtils.h"
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/dom/ContentParent.h"
-#include "CaptivePortalService.h"
+#include "mozilla/net/CaptivePortalService.h"
 #include "ReferrerPolicy.h"
 #include "nsContentSecurityManager.h"
 #include "nsContentUtils.h"
 #include "xpcpublic.h"
 
 #ifdef MOZ_WIDGET_GONK
 #include "nsINetworkManager.h"
 #include "nsINetworkInterface.h"