Bug 786419 - Part 8 - Several improvements to per-app-offline behaviour r=jduell
authorValentin Gosu <valentin.gosu@gmail.com>
Fri, 22 Aug 2014 20:15:00 +0300
changeset 209175 c748712cd1ee62af9ea485449b278af08288b29a
parent 209174 9653d9285cca794827cd6fa55b8ac8dbe1a3354b
child 209176 6898b53b3c11d04f422af9d90a5b9bca378d5ad4
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersjduell
bugs786419
milestone35.0a1
Bug 786419 - Part 8 - Several improvements to per-app-offline behaviour r=jduell Make GetAppId() pure-virtual and add implementation for TCPSocketParent, UDPSocketParent, and one for Necko parent that returns UNKNOWN_APP_ID Change nsIOService to use IsNeckoChild instead of XRE_ method. Include nsThreadUtils.h (for nsRunnable and dispatchToMainThread) and NeckoCommon for IsNeckoChild. Make HttpChannelParent set LOAD_ONLY_FROM_CACHE, LOAD_FROM_CACHE and LOAD_NO_NETWORK_IO when offline.
dom/network/TCPSocketParent.cpp
dom/network/TCPSocketParent.h
dom/network/UDPSocketParent.cpp
dom/network/UDPSocketParent.h
netwerk/base/src/OfflineObserver.cpp
netwerk/base/src/OfflineObserver.h
netwerk/base/src/nsIOService.cpp
netwerk/ipc/NeckoParent.h
netwerk/protocol/http/HttpChannelParent.cpp
--- a/dom/network/TCPSocketParent.cpp
+++ b/dom/network/TCPSocketParent.cpp
@@ -75,36 +75,42 @@ TCPSocketParentBase::TCPSocketParentBase
 TCPSocketParentBase::~TCPSocketParentBase()
 {
   if (mObserver) {
     mObserver->RemoveObserver();
   }
   mozilla::DropJSObjects(this);
 }
 
+uint32_t
+TCPSocketParent::GetAppId()
+{
+  uint32_t appId = nsIScriptSecurityManager::UNKNOWN_APP_ID;
+  const PContentParent *content = Manager()->Manager();
+  const InfallibleTArray<PBrowserParent*>& browsers = content->ManagedPBrowserParent();
+  if (browsers.Length() > 0) {
+    TabParent *tab = static_cast<TabParent*>(browsers[0]);
+    appId = tab->OwnAppId();
+  }
+  return appId;
+};
+
 nsresult
 TCPSocketParent::OfflineNotification(nsISupports *aSubject)
 {
   nsCOMPtr<nsIAppOfflineInfo> info(do_QueryInterface(aSubject));
   if (!info) {
     return NS_OK;
   }
 
   uint32_t targetAppId = nsIScriptSecurityManager::UNKNOWN_APP_ID;
   info->GetAppId(&targetAppId);
 
   // Obtain App ID
-  uint32_t appId = nsIScriptSecurityManager::UNKNOWN_APP_ID;
-  const PContentParent *content = Manager()->Manager();
-  const InfallibleTArray<PBrowserParent*>& browsers = content->ManagedPBrowserParent();
-  if (browsers.Length() > 0) {
-    TabParent *tab = static_cast<TabParent*>(browsers[0]);
-    appId = tab->OwnAppId();
-  }
-
+  uint32_t appId = GetAppId();
   if (appId != targetAppId) {
     return NS_OK;
   }
 
   // If the app is offline, close the socket
   if (mSocket && NS_IsAppOffline(appId)) {
     mSocket->Close();
     mSocket = nullptr;
@@ -150,23 +156,17 @@ TCPSocketParent::RecvOpen(const nsString
   // tests without this loophole.
   if (net::UsingNeckoIPCSecurity() &&
       !AssertAppProcessPermission(Manager()->Manager(), "tcp-socket")) {
     FireInteralError(this, __LINE__);
     return true;
   }
 
   // Obtain App ID
-  uint32_t appId = nsIScriptSecurityManager::UNKNOWN_APP_ID;
-  const PContentParent *content = Manager()->Manager();
-  const InfallibleTArray<PBrowserParent*>& browsers = content->ManagedPBrowserParent();
-  if (browsers.Length() > 0) {
-    TabParent *tab = static_cast<TabParent*>(browsers[0]);
-    appId = tab->OwnAppId();
-  }
+  uint32_t appId = GetAppId();
 
   if (NS_IsAppOffline(appId)) {
     NS_ERROR("Can't open socket because app is offline");
     FireInteralError(this, __LINE__);
     return true;
   }
 
   nsresult rv;
--- a/dom/network/TCPSocketParent.h
+++ b/dom/network/TCPSocketParent.h
@@ -57,16 +57,17 @@ public:
   virtual bool RecvStartTLS() MOZ_OVERRIDE;
   virtual bool RecvSuspend() MOZ_OVERRIDE;
   virtual bool RecvResume() MOZ_OVERRIDE;
   virtual bool RecvClose() MOZ_OVERRIDE;
   virtual bool RecvData(const SendableData& aData,
                         const uint32_t& aTrackingNumber) MOZ_OVERRIDE;
   virtual bool RecvRequestDelete() MOZ_OVERRIDE;
   virtual nsresult OfflineNotification(nsISupports *) MOZ_OVERRIDE;
+  virtual uint32_t GetAppId() MOZ_OVERRIDE;
 
 private:
   virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/network/UDPSocketParent.cpp
+++ b/dom/network/UDPSocketParent.cpp
@@ -44,36 +44,42 @@ UDPSocketParent::OfflineNotification(nsI
   if (!info) {
     return NS_OK;
   }
 
   uint32_t targetAppId = nsIScriptSecurityManager::UNKNOWN_APP_ID;
   info->GetAppId(&targetAppId);
 
   // Obtain App ID
-  uint32_t appId = nsIScriptSecurityManager::UNKNOWN_APP_ID;
-  const PContentParent *content = Manager()->Manager();
-  const InfallibleTArray<PBrowserParent*>& browsers = content->ManagedPBrowserParent();
-  if (browsers.Length() > 0) {
-    TabParent *tab = static_cast<TabParent*>(browsers[0]);
-    appId = tab->OwnAppId();
-  }
-
+  uint32_t appId = GetAppId();
   if (appId != targetAppId) {
     return NS_OK;
   }
 
   // If the app is offline, close the socket
   if (mSocket && NS_IsAppOffline(appId)) {
     mSocket->Close();
   }
 
   return NS_OK;
 }
 
+uint32_t
+UDPSocketParent::GetAppId()
+{
+  uint32_t appId = nsIScriptSecurityManager::UNKNOWN_APP_ID;
+  const PContentParent *content = Manager()->Manager();
+  const InfallibleTArray<PBrowserParent*>& browsers = content->ManagedPBrowserParent();
+  if (browsers.Length() > 0) {
+    TabParent *tab = static_cast<TabParent*>(browsers[0]);
+    appId = tab->OwnAppId();
+  }
+  return appId;
+}
+
 bool
 UDPSocketParent::Init(const nsACString& aFilter)
 {
   if (!aFilter.IsEmpty()) {
     nsAutoCString contractId(NS_NETWORK_UDP_SOCKET_FILTER_HANDLER_PREFIX);
     contractId.Append(aFilter);
     nsCOMPtr<nsIUDPSocketFilterHandler> filterHandler =
       do_GetService(contractId.get());
--- a/dom/network/UDPSocketParent.h
+++ b/dom/network/UDPSocketParent.h
@@ -36,16 +36,17 @@ public:
   virtual bool RecvClose() MOZ_OVERRIDE;
 
   virtual bool RecvRequestDelete() MOZ_OVERRIDE;
   virtual bool RecvJoinMulticast(const nsCString& aMulticastAddress,
                                  const nsCString& aInterface) MOZ_OVERRIDE;
   virtual bool RecvLeaveMulticast(const nsCString& aMulticastAddress,
                                   const nsCString& aInterface) MOZ_OVERRIDE;
   virtual nsresult OfflineNotification(nsISupports *) MOZ_OVERRIDE;
+  virtual uint32_t GetAppId() MOZ_OVERRIDE;
 
 private:
   virtual ~UDPSocketParent();
 
   virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
   void Send(const InfallibleTArray<uint8_t>& aData, const UDPSocketAddr& aAddr);
   void Send(const InputStreamParams& aStream, const UDPSocketAddr& aAddr);
   nsresult BindInternal(const nsCString& aHost, const uint16_t& aPort,
--- a/netwerk/base/src/OfflineObserver.cpp
+++ b/netwerk/base/src/OfflineObserver.cpp
@@ -84,22 +84,16 @@ OfflineObserver::Observe(nsISupports *aS
 {
   if (mParent &&
       !strcmp(aTopic, NS_IOSERVICE_APP_OFFLINE_STATUS_TOPIC)) {
     mParent->OfflineNotification(aSubject);
   }
   return NS_OK;
 }
 
-uint32_t
-DisconnectableParent::GetAppId()
-{
-  return NECKO_UNKNOWN_APP_ID;
-}
-
 nsresult
 DisconnectableParent::OfflineNotification(nsISupports *aSubject)
 {
   nsCOMPtr<nsIAppOfflineInfo> info(do_QueryInterface(aSubject));
   if (!info) {
     return NS_ERROR_NOT_INITIALIZED;
   }
 
--- a/netwerk/base/src/OfflineObserver.h
+++ b/netwerk/base/src/OfflineObserver.h
@@ -24,17 +24,17 @@ namespace net {
 class DisconnectableParent
 {
 public:
   // This is called on the main thread, by the OfflineObserver.
   // aSubject is of type nsAppOfflineInfo and contains appId and offline mode.
   virtual nsresult OfflineNotification(nsISupports *aSubject);
 
   // GetAppId returns the appId for the app associated with the parent
-  virtual uint32_t GetAppId();
+  virtual uint32_t GetAppId() = 0;
 
   // OfflineDisconnect cancels all existing connections in the parent when
   // the app becomes offline.
   virtual void     OfflineDisconnect() { }
 };
 
 /**
  * This class observes the "network:app-offline-status-changed" topic and calls
--- a/netwerk/base/src/nsIOService.cpp
+++ b/netwerk/base/src/nsIOService.cpp
@@ -34,26 +34,29 @@
 #include "nsINetworkLinkService.h"
 #include "nsPISocketTransportService.h"
 #include "nsAsyncRedirectVerifyHelper.h"
 #include "nsURLHelper.h"
 #include "nsPIDNSService.h"
 #include "nsIProtocolProxyService2.h"
 #include "MainThreadUtils.h"
 #include "nsIWidget.h"
+#include "nsThreadUtils.h"
+#include "mozilla/net/NeckoCommon.h"
 
 #ifdef MOZ_WIDGET_GONK
 #include "nsINetworkManager.h"
 #endif
 
 #if defined(XP_WIN)
 #include "nsNativeConnectionHelper.h"
 #endif
 
 using namespace mozilla;
+using mozilla::net::IsNeckoChild;
 
 #define PORT_PREF_PREFIX           "network.security.ports."
 #define PORT_PREF(x)               PORT_PREF_PREFIX x
 #define AUTODIAL_PREF              "network.autodial-helper.enabled"
 #define MANAGE_OFFLINE_STATUS_PREF "network.manage-offline-status"
 
 // Nb: these have been misnomers since bug 715770 removed the buffer cache.
 // "network.segment.count" and "network.segment.size" would be better names,
@@ -920,21 +923,22 @@ nsIOService::ParsePortList(nsIPrefBranch
 void
 nsIOService::GetPrefBranch(nsIPrefBranch **result)
 {
     *result = nullptr;
     CallGetService(NS_PREFSERVICE_CONTRACTID, result);
 }
 
 // This returns true if wifi-only apps should have connectivity.
+// Always returns false in the child process (should not depend on this method)
 static bool
 IsWifiActive()
 {
     // We don't need to do this check inside the child process
-    if (XRE_GetProcessType() != GeckoProcessType_Default) {
+    if (IsNeckoChild()) {
         return false;
     }
 #ifdef MOZ_WIDGET_GONK
     // On B2G we query the network manager for the active interface
     nsCOMPtr<nsINetworkManager> networkManager =
         do_GetService("@mozilla.org/network/manager;1");
     if (!networkManager) {
         return false;
@@ -1424,17 +1428,17 @@ private:
     int32_t mState;
 };
 
 }
 
 NS_IMETHODIMP
 nsIOService::SetAppOffline(uint32_t aAppId, int32_t aState)
 {
-    NS_ENSURE_TRUE(XRE_GetProcessType() == GeckoProcessType_Default,
+    NS_ENSURE_TRUE(!IsNeckoChild(),
                    NS_ERROR_FAILURE);
     NS_ENSURE_TRUE(aAppId != nsIScriptSecurityManager::NO_APP_ID,
                    NS_ERROR_INVALID_ARG);
     NS_ENSURE_TRUE(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID,
                    NS_ERROR_INVALID_ARG);
 
     if (!NS_IsMainThread()) {
         NS_DispatchToMainThread(new SetAppOfflineMainThread(aAppId, aState));
@@ -1465,16 +1469,17 @@ nsIOService::SetAppOfflineInternal(uint3
     switch (aState) {
     case nsIAppOfflineInfo::OFFLINE:
         mAppsOfflineStatus.Put(aAppId, nsIAppOfflineInfo::OFFLINE);
         if (!offline) {
             NotifyAppOfflineStatus(aAppId, nsIAppOfflineInfo::OFFLINE);
         }
         break;
     case nsIAppOfflineInfo::WIFI_ONLY:
+        MOZ_RELEASE_ASSERT(!IsNeckoChild());
         mAppsOfflineStatus.Put(aAppId, nsIAppOfflineInfo::WIFI_ONLY);
         if (offline && wifiActive) {
             NotifyAppOfflineStatus(aAppId, nsIAppOfflineInfo::ONLINE);
         } else if (!offline && !wifiActive) {
             NotifyAppOfflineStatus(aAppId, nsIAppOfflineInfo::OFFLINE);
         }
         break;
     case nsIAppOfflineInfo::ONLINE:
@@ -1507,16 +1512,17 @@ nsIOService::IsAppOffline(uint32_t aAppI
 
     int32_t state;
     if (mAppsOfflineStatus.Get(aAppId, &state)) {
         switch (state) {
         case nsIAppOfflineInfo::OFFLINE:
             *aResult = true;
             break;
         case nsIAppOfflineInfo::WIFI_ONLY:
+            MOZ_RELEASE_ASSERT(!IsNeckoChild());
             *aResult = !IsWifiActive();
             break;
         default:
             // The app is online by default
             break;
         }
     }
 
--- a/netwerk/ipc/NeckoParent.h
+++ b/netwerk/ipc/NeckoParent.h
@@ -49,16 +49,17 @@ public:
   static const char*
   CreateChannelLoadContext(const PBrowserOrId& aBrowser,
                            PContentParent* aContent,
                            const SerializedLoadContext& aSerialized,
                            nsCOMPtr<nsILoadContext> &aResult);
 
   virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
   virtual nsresult OfflineNotification(nsISupports *) MOZ_OVERRIDE;
+  virtual uint32_t GetAppId() MOZ_OVERRIDE { return NECKO_UNKNOWN_APP_ID; }
   virtual void
   CloneManagees(ProtocolBase* aSource,
               mozilla::ipc::ProtocolCloneContext* aCtx) MOZ_OVERRIDE;
   virtual PCookieServiceParent* AllocPCookieServiceParent() MOZ_OVERRIDE;
   virtual bool
   RecvPCookieServiceConstructor(PCookieServiceParent* aActor) MOZ_OVERRIDE
   {
     return PNeckoParent::RecvPCookieServiceConstructor(aActor);
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -226,16 +226,18 @@ HttpChannelParent::DoAsyncOpen(  const U
   if (appId != NECKO_UNKNOWN_APP_ID &&
       appId != NECKO_NO_APP_ID) {
     gIOService->IsAppOffline(appId, &appOffline);
   }
 
   uint32_t loadFlags = aLoadFlags;
   if (appOffline) {
     loadFlags |= nsICachingChannel::LOAD_ONLY_FROM_CACHE;
+    loadFlags |= nsIRequest::LOAD_FROM_CACHE;
+    loadFlags |= nsICachingChannel::LOAD_NO_NETWORK_IO;
   }
 
   nsCOMPtr<nsIChannel> channel;
   rv = NS_NewChannel(getter_AddRefs(channel),
                      uri,
                      requestingPrincipal,
                      aSecurityFlags,
                      aContentPolicyType,
@@ -378,18 +380,22 @@ HttpChannelParent::ConnectChannel(const 
   bool appOffline = false;
   uint32_t appId = GetAppId();
   if (appId != NECKO_UNKNOWN_APP_ID &&
       appId != NECKO_NO_APP_ID) {
     gIOService->IsAppOffline(appId, &appOffline);
   }
 
   if (appOffline) {
-    mChannel->Cancel(NS_ERROR_OFFLINE);
-    mStatus = NS_ERROR_OFFLINE;
+    uint32_t loadFlags;
+    mChannel->GetLoadFlags(&loadFlags);
+    loadFlags |= nsICachingChannel::LOAD_ONLY_FROM_CACHE;
+    loadFlags |= nsIRequest::LOAD_FROM_CACHE;
+    loadFlags |= nsICachingChannel::LOAD_NO_NETWORK_IO;
+    mChannel->SetLoadFlags(loadFlags);
   }
 
   return true;
 }
 
 bool
 HttpChannelParent::RecvSetPriority(const uint16_t& priority)
 {