Bug 829043 - Separate wyciwyg cache into app jars. r=michal.novotny
authorJosh Matthews <josh@joshmatthews.net>
Fri, 11 Jan 2013 15:40:25 +0100
changeset 118520 44dcffe8792b49ce4ef2e6471f61e1af5ff62b5e
parent 118519 63c4b0f66a0ced763bdca91f4ea714a24e962afc
child 118531 da63d4717b51ce586b0842e945ca4090737d5793
child 118590 3ba8ec844de6a092d65e498ba61e97b27eba666b
child 118688 b4c9fb778df9f79672a3fe6e30157a597f67cde5
push id24167
push userjosh@joshmatthews.net
push dateFri, 11 Jan 2013 14:40:35 +0000
treeherdermozilla-central@44dcffe8792b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmichal.novotny
bugs829043
milestone21.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 829043 - Separate wyciwyg cache into app jars. r=michal.novotny
netwerk/build/nsNetModule.cpp
netwerk/protocol/ftp/FTPChannelParent.cpp
netwerk/protocol/http/nsHttpChannel.cpp
netwerk/protocol/wyciwyg/PWyciwygChannel.ipdl
netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp
netwerk/protocol/wyciwyg/WyciwygChannelChild.h
netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp
netwerk/protocol/wyciwyg/WyciwygChannelParent.h
netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp
netwerk/protocol/wyciwyg/nsWyciwygChannel.h
netwerk/protocol/wyciwyg/nsWyciwygProtocolHandler.cpp
netwerk/protocol/wyciwyg/nsWyciwygProtocolHandler.h
--- a/netwerk/build/nsNetModule.cpp
+++ b/netwerk/build/nsNetModule.cpp
@@ -265,17 +265,17 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsViewSou
 #endif
 
 #ifdef NECKO_PROTOCOL_data
 #include "nsDataHandler.h"
 #endif
 
 #ifdef NECKO_PROTOCOL_wyciwyg
 #include "nsWyciwygProtocolHandler.h"
-NS_GENERIC_FACTORY_CONSTRUCTOR(nsWyciwygProtocolHandler)
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsWyciwygProtocolHandler, Init)
 #endif
 
 #ifdef NECKO_PROTOCOL_websocket
 #include "WebSocketChannel.h"
 #include "WebSocketChannelChild.h"
 namespace mozilla {
 namespace net {
 static BaseWebSocketChannel*
--- a/netwerk/protocol/ftp/FTPChannelParent.cpp
+++ b/netwerk/protocol/ftp/FTPChannelParent.cpp
@@ -88,16 +88,20 @@ FTPChannelParent::RecvAsyncOpen(const UR
     return SendFailedAsyncOpen(rv);
 
   mChannel = static_cast<nsFtpChannel*>(chan.get());
 
   if (mPBOverride != kPBOverride_Unset) {
     mChannel->SetPrivate(mPBOverride == kPBOverride_Private ? true : false);
   }
 
+  rv = mChannel->SetNotificationCallbacks(this);
+  if (NS_FAILED(rv))
+    return SendFailedAsyncOpen(rv);
+
   nsCOMPtr<nsIInputStream> upload = DeserializeInputStream(aUploadStream);
   if (upload) {
     // contentType and contentLength are ignored
     rv = mChannel->SetUploadStream(upload, EmptyCString(), 0);
     if (NS_FAILED(rv))
       return SendFailedAsyncOpen(rv);
   }
 
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -2463,39 +2463,26 @@ nsHttpChannel::OnOfflineCacheEntryAvaila
         }
     }
 
     bool usingSSL = false;
     (void) mURI->SchemeIs("https", &usingSSL);
     return OpenNormalCacheEntry(usingSSL);
 }
 
-static void
-GetAppInfo(nsIChannel* aChannel, uint32_t* aAppId, bool* aIsInBrowser)
-{
-    nsCOMPtr<nsILoadContext> loadContext;
-    NS_QueryNotificationCallbacks(aChannel, loadContext);
-    *aAppId = NECKO_NO_APP_ID;
-    *aIsInBrowser = false;
-    if (loadContext) {
-        loadContext->GetAppId(aAppId);
-        loadContext->GetIsInBrowserElement(aIsInBrowser);
-    }
-}
-
 nsresult
 nsHttpChannel::OpenNormalCacheEntry(bool usingSSL)
 {
     NS_ASSERTION(!mCacheEntry, "We have already mCacheEntry");
 
     nsresult rv;
 
-    uint32_t appId;
-    bool isInBrowser;
-    GetAppInfo(this, &appId, &isInBrowser);
+    uint32_t appId = NECKO_NO_APP_ID;
+    bool isInBrowser = false;
+    NS_GetAppInfo(this, &appId, &isInBrowser);
 
     nsCacheStoragePolicy storagePolicy = DetermineStoragePolicy();
     nsAutoCString clientID;
     nsHttpHandler::GetCacheSessionNameForStoragePolicy(storagePolicy, mPrivateBrowsing,
                                                        appId, isInBrowser, clientID);
 
     nsAutoCString cacheKey;
     GenerateCacheKey(mPostID, cacheKey);
@@ -5856,19 +5843,19 @@ void
 nsHttpChannel::DoInvalidateCacheEntry(const nsCString &key)
 {
     // NOTE:
     // Following comments 24,32 and 33 in bug #327765, we only care about
     // the cache in the protocol-handler, not the application cache.
     // The logic below deviates from the original logic in OpenCacheEntry on
     // one point by using only READ_ONLY access-policy. I think this is safe.
 
-    uint32_t appId;
-    bool isInBrowser;
-    GetAppInfo(this, &appId, &isInBrowser);
+    uint32_t appId = NECKO_NO_APP_ID;
+    bool isInBrowser = false;
+    NS_GetAppInfo(this, &appId, &isInBrowser);
 
     // First, find session holding the cache-entry - use current storage-policy
     nsCacheStoragePolicy storagePolicy = DetermineStoragePolicy();
     nsAutoCString clientID;
     nsHttpHandler::GetCacheSessionNameForStoragePolicy(storagePolicy, mPrivateBrowsing,
                                                        appId, isInBrowser, clientID);
 
     LOG(("DoInvalidateCacheEntry [channel=%p session=%s policy=%d key=%s]",
--- a/netwerk/protocol/wyciwyg/PWyciwygChannel.ipdl
+++ b/netwerk/protocol/wyciwyg/PWyciwygChannel.ipdl
@@ -21,16 +21,17 @@ protocol PWyciwygChannel
 parent:
   __delete__();
 
   Init(URIParams uri);
   AsyncOpen(URIParams             originalURI,
             uint32_t              loadFlags,
             SerializedLoadContext loadContext,
             PBrowser browser);
+  AppData(SerializedLoadContext loadContext, PBrowser browser);
 
   // methods corresponding to those of nsIWyciwygChannel
   WriteToCacheEntry(nsString data);
   CloseCacheEntry(nsresult reason);
   SetCharsetAndSource(int32_t source, nsCString charset);
   SetSecurityInfo(nsCString securityInfo);
   Cancel(nsresult status);
 
--- a/netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp
+++ b/netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp
@@ -33,16 +33,17 @@ WyciwygChannelChild::WyciwygChannelChild
   : mStatus(NS_OK)
   , mIsPending(false)
   , mCanceled(false)
   , mLoadFlags(LOAD_NORMAL)
   , mContentLength(-1)
   , mCharsetSource(kCharsetUninitialized)
   , mState(WCC_NEW)
   , mIPCOpen(false)
+  , mSentAppData(false)
   , mEventQ(NS_ISUPPORTS_CAST(nsIWyciwygChannel*, this))
 {
   LOG(("Creating WyciwygChannelChild @%x\n", this));
 }
 
 WyciwygChannelChild::~WyciwygChannelChild()
 {
   LOG(("Destroying WyciwygChannelChild @%x\n", this));
@@ -563,16 +564,24 @@ WyciwygChannelChild::SetContentLength(in
 
 /* nsIInputStream open (); */
 NS_IMETHODIMP
 WyciwygChannelChild::Open(nsIInputStream **_retval)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
+static mozilla::dom::TabChild*
+GetTabChild(nsIChannel* aChannel)
+{
+  nsCOMPtr<nsITabChild> iTabChild;
+  NS_QueryNotificationCallbacks(aChannel, iTabChild);
+  return iTabChild ? static_cast<mozilla::dom::TabChild*>(iTabChild.get()) : nullptr;
+}
+
 /* void asyncOpen (in nsIStreamListener aListener, in nsISupports aContext); */
 NS_IMETHODIMP
 WyciwygChannelChild::AsyncOpen(nsIStreamListener *aListener, nsISupports *aContext)
 {
   LOG(("WyciwygChannelChild::AsyncOpen [this=%x]\n", this));
 
   // The only places creating wyciwyg: channels should be
   // HTMLDocument::OpenCommon and session history.  Both should be setting an
@@ -588,44 +597,42 @@ WyciwygChannelChild::AsyncOpen(nsIStream
   mIsPending = true;
 
   if (mLoadGroup)
     mLoadGroup->AddRequest(this, nullptr);
 
   URIParams originalURI;
   SerializeURI(mOriginalURI, originalURI);
 
-  mozilla::dom::TabChild* tabChild = nullptr;
-  nsCOMPtr<nsITabChild> iTabChild;
-  NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
-                                NS_GET_IID(nsITabChild),
-                                getter_AddRefs(iTabChild));
-  if (iTabChild) {
-    tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get());
-  }
-
+  mozilla::dom::TabChild* tabChild = GetTabChild(this);
   SendAsyncOpen(originalURI, mLoadFlags, IPC::SerializedLoadContext(this), tabChild);
 
+  mSentAppData = true;
   mState = WCC_OPENED;
 
   return NS_OK;
 }
 
-
 //-----------------------------------------------------------------------------
 // nsIWyciwygChannel
 //-----------------------------------------------------------------------------
 
 /* void writeToCacheEntry (in AString aData); */
 NS_IMETHODIMP
 WyciwygChannelChild::WriteToCacheEntry(const nsAString & aData)
 {
   NS_ENSURE_TRUE((mState == WCC_INIT) ||
                  (mState == WCC_ONWRITE), NS_ERROR_UNEXPECTED);
 
+  if (!mSentAppData) {
+    mozilla::dom::TabChild* tabChild = GetTabChild(this);
+    SendAppData(IPC::SerializedLoadContext(this), tabChild);
+    mSentAppData = true;
+  }
+
   SendWriteToCacheEntry(PromiseFlatString(aData));
   mState = WCC_ONWRITE;
   return NS_OK;
 }
 
 /* void closeCacheEntry (in nsresult reason); */
 NS_IMETHODIMP
 WyciwygChannelChild::CloseCacheEntry(nsresult reason)
--- a/netwerk/protocol/wyciwyg/WyciwygChannelChild.h
+++ b/netwerk/protocol/wyciwyg/WyciwygChannelChild.h
@@ -93,16 +93,17 @@ private:
   nsCOMPtr<nsIStreamListener>       mListener;
   nsCOMPtr<nsISupports>             mListenerContext;
   nsCOMPtr<nsISupports>             mSecurityInfo;
 
   // FIXME: replace with IPDL states (bug 536319)
   enum WyciwygChannelChildState mState;
 
   bool mIPCOpen;
+  bool mSentAppData;
   ChannelEventQueue mEventQ;
 
   friend class WyciwygStartRequestEvent;
   friend class WyciwygDataAvailableEvent;
   friend class WyciwygStopRequestEvent;
   friend class WyciwygCancelEvent;
 };
 
--- a/netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp
+++ b/netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp
@@ -16,16 +16,17 @@
 
 using namespace mozilla::ipc;
 
 namespace mozilla {
 namespace net {
 
 WyciwygChannelParent::WyciwygChannelParent()
  : mIPCClosed(false)
+ , mReceivedAppData(false)
 {
 #if defined(PR_LOGGING)
   if (!gWyciwygLog)
     gWyciwygLog = PR_NewLogModule("nsWyciwygChannel");
 #endif
 }
 
 WyciwygChannelParent::~WyciwygChannelParent()
@@ -33,16 +34,19 @@ WyciwygChannelParent::~WyciwygChannelPar
 }
 
 void
 WyciwygChannelParent::ActorDestroy(ActorDestroyReason why)
 {
   // We may still have refcount>0 if the channel hasn't called OnStopRequest
   // yet, but we must not send any more msgs to child.
   mIPCClosed = true;
+
+  // We need to force the cycle to break here
+  mChannel->SetNotificationCallbacks(nullptr);
 }
 
 //-----------------------------------------------------------------------------
 // WyciwygChannelParent::nsISupports
 //-----------------------------------------------------------------------------
 
 NS_IMPL_ISUPPORTS3(WyciwygChannelParent,
                    nsIStreamListener,
@@ -79,16 +83,54 @@ WyciwygChannelParent::RecvInit(const URI
   mChannel = do_QueryInterface(chan, &rv);
   if (NS_FAILED(rv))
     return SendCancelEarly(rv);
 
   return true;
 }
 
 bool
+WyciwygChannelParent::RecvAppData(const IPC::SerializedLoadContext& loadContext,
+                                  PBrowserParent* parent)
+{
+  LOG(("WyciwygChannelParent RecvAppData [this=%x]\n", this));
+
+  if (!SetupAppData(loadContext, parent))
+    return false;
+
+  mChannel->SetNotificationCallbacks(this);
+  return true;
+}
+
+bool
+WyciwygChannelParent::SetupAppData(const IPC::SerializedLoadContext& loadContext,
+                                   PBrowserParent* aParent)
+{
+  if (!mChannel)
+    return true;
+
+  const char* error = NeckoParent::CreateChannelLoadContext(aParent, loadContext,
+                                                            mLoadContext);
+  if (error) {
+    printf_stderr(nsPrintfCString("WyciwygChannelParent::SetupAppData: FATAL ERROR: %s\n",
+                                  error).get());
+    return false;
+  }
+
+  if (!mLoadContext && loadContext.IsPrivateBitValid()) {
+    nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel = do_QueryInterface(mChannel);
+    if (pbChannel)
+      pbChannel->SetPrivate(loadContext.mUsePrivateBrowsing);
+  }
+
+  mReceivedAppData = true;
+  return true;
+}
+
+bool
 WyciwygChannelParent::RecvAsyncOpen(const URIParams& aOriginal,
                                     const uint32_t& aLoadFlags,
                                     const IPC::SerializedLoadContext& loadContext,
                                     PBrowserParent* aParent)
 {
   nsCOMPtr<nsIURI> original = DeserializeURI(aOriginal);
   if (!original)
     return false;
@@ -103,51 +145,51 @@ WyciwygChannelParent::RecvAsyncOpen(cons
   rv = mChannel->SetOriginalURI(original);
   if (NS_FAILED(rv))
     return SendCancelEarly(rv);
 
   rv = mChannel->SetLoadFlags(aLoadFlags);
   if (NS_FAILED(rv))
     return SendCancelEarly(rv);
 
-  const char* error = NeckoParent::CreateChannelLoadContext(aParent, loadContext,
-                                                            mLoadContext);
-  if (error) {
-    NS_WARNING(nsPrintfCString("WyciwygChannelParent::RecvAsyncOpen: error: %s\n",
-                               error).get());
+  if (!mReceivedAppData && !SetupAppData(loadContext, aParent)) {
     return false;
   }
 
-  if (!mLoadContext && loadContext.IsPrivateBitValid()) {
-    nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel = do_QueryInterface(mChannel);
-    if (pbChannel)
-      pbChannel->SetPrivate(loadContext.mUsePrivateBrowsing);
-  }
+  rv = mChannel->SetNotificationCallbacks(this);
+  if (NS_FAILED(rv))
+    return SendCancelEarly(rv);
 
   rv = mChannel->AsyncOpen(this, nullptr);
   if (NS_FAILED(rv))
     return SendCancelEarly(rv);
 
   return true;
 }
 
 bool
 WyciwygChannelParent::RecvWriteToCacheEntry(const nsString& data)
 {
+  if (!mReceivedAppData) {
+    printf_stderr("WyciwygChannelParent::RecvWriteToCacheEntry: FATAL ERROR: didn't receive app data\n");
+    return false;
+  }
+
   if (mChannel)
     mChannel->WriteToCacheEntry(data);
 
   return true;
 }
 
 bool
 WyciwygChannelParent::RecvCloseCacheEntry(const nsresult& reason)
 {
-  if (mChannel)
+  if (mChannel) {
     mChannel->CloseCacheEntry(reason);
+  }
 
   return true;
 }
 
 bool
 WyciwygChannelParent::RecvSetCharsetAndSource(const int32_t& aCharsetSource,
                                               const nsCString& aCharset)
 {
--- a/netwerk/protocol/wyciwyg/WyciwygChannelParent.h
+++ b/netwerk/protocol/wyciwyg/WyciwygChannelParent.h
@@ -40,20 +40,26 @@ protected:
                              const IPC::SerializedLoadContext& loadContext,
                              PBrowserParent* parent);
   virtual bool RecvWriteToCacheEntry(const nsString& data);
   virtual bool RecvCloseCacheEntry(const nsresult& reason);
   virtual bool RecvSetCharsetAndSource(const int32_t& source,
                                        const nsCString& charset);
   virtual bool RecvSetSecurityInfo(const nsCString& securityInfo);
   virtual bool RecvCancel(const nsresult& statusCode);
+  virtual bool RecvAppData(const IPC::SerializedLoadContext& loadContext,
+                           PBrowserParent* parent);
 
   virtual void ActorDestroy(ActorDestroyReason why);
 
+  bool SetupAppData(const IPC::SerializedLoadContext& loadContext,
+                    PBrowserParent* aParent);
+
   nsCOMPtr<nsIWyciwygChannel> mChannel;
   bool mIPCClosed;
+  bool mReceivedAppData;
   nsCOMPtr<nsILoadContext> mLoadContext;
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif // mozilla_net_WyciwygChannelParent_h
--- a/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp
+++ b/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp
@@ -80,17 +80,19 @@ private:
 // nsWyciwygChannel methods 
 nsWyciwygChannel::nsWyciwygChannel()
   : mStatus(NS_OK),
     mIsPending(false),
     mCharsetAndSourceSet(false),
     mNeedToWriteCharset(false),
     mCharsetSource(kCharsetUninitialized),
     mContentLength(-1),
-    mLoadFlags(LOAD_NORMAL)
+    mLoadFlags(LOAD_NORMAL),
+    mAppId(NECKO_NO_APP_ID),
+    mInBrowser(false)
 {
 }
 
 nsWyciwygChannel::~nsWyciwygChannel() 
 {
 }
 
 NS_IMPL_THREADSAFE_ISUPPORTS7(nsWyciwygChannel,
@@ -193,16 +195,17 @@ nsWyciwygChannel::SetLoadGroup(nsILoadGr
   }
 
   mLoadGroup = aLoadGroup;
   NS_QueryNotificationCallbacks(mCallbacks,
                                 mLoadGroup,
                                 NS_GET_IID(nsIProgressEventSink),
                                 getter_AddRefs(mProgressSink));
   mPrivateBrowsing = NS_UsePrivateBrowsing(this);
+  NS_GetAppInfo(this, &mAppId, &mInBrowser);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWyciwygChannel::SetLoadFlags(uint32_t aLoadFlags)
 {
   mLoadFlags = aLoadFlags;
   return NS_OK;
@@ -277,16 +280,17 @@ nsWyciwygChannel::SetNotificationCallbac
 
   mCallbacks = aNotificationCallbacks;
   NS_QueryNotificationCallbacks(mCallbacks,
                                 mLoadGroup,
                                 NS_GET_IID(nsIProgressEventSink),
                                 getter_AddRefs(mProgressSink));
 
   mPrivateBrowsing = NS_UsePrivateBrowsing(this);
+  NS_GetAppInfo(this, &mAppId, &mInBrowser);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP 
 nsWyciwygChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
 {
   NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo);
@@ -688,19 +692,23 @@ nsWyciwygChannel::OpenCacheEntry(const n
   // honor security settings
   nsCacheStoragePolicy storagePolicy;
   if (mPrivateBrowsing || mLoadFlags & INHIBIT_PERSISTENT_CACHING)
     storagePolicy = nsICache::STORE_IN_MEMORY;
   else
     storagePolicy = nsICache::STORE_ANYWHERE;
 
   nsCOMPtr<nsICacheSession> cacheSession;
+  nsAutoCString sessionName;
+  nsWyciwygProtocolHandler::GetCacheSessionName(mAppId, mInBrowser,
+                                                mPrivateBrowsing,
+                                                sessionName);
+
   // Open a stream based cache session.
-  const char* sessionName = mPrivateBrowsing ? "wyciwyg-private" : "wyciwyg";
-  rv = cacheService->CreateSession(sessionName, storagePolicy, true,
+  rv = cacheService->CreateSession(sessionName.get(), storagePolicy, true,
                                    getter_AddRefs(cacheSession));
   if (!cacheSession) 
     return NS_ERROR_FAILURE;
 
   cacheSession->SetIsPrivate(mPrivateBrowsing);
 
   if (aAccessMode == nsICache::ACCESS_WRITE)
     rv = cacheSession->OpenCacheEntry(aCacheKey, aAccessMode, false,
--- a/netwerk/protocol/wyciwyg/nsWyciwygChannel.h
+++ b/netwerk/protocol/wyciwyg/nsWyciwygChannel.h
@@ -75,16 +75,18 @@ protected:
     nsresult                            mStatus;
     bool                                mIsPending;
     bool                                mCharsetAndSourceSet;
     bool                                mNeedToWriteCharset;
     int32_t                             mCharsetSource;
     nsCString                           mCharset;
     int64_t                             mContentLength;
     uint32_t                            mLoadFlags;
+    uint32_t                            mAppId;
+    bool                                mInBrowser;
     nsCOMPtr<nsIURI>                    mURI;
     nsCOMPtr<nsIURI>                    mOriginalURI;
     nsCOMPtr<nsISupports>               mOwner;
     nsCOMPtr<nsIInterfaceRequestor>     mCallbacks;
     nsCOMPtr<nsIProgressEventSink>      mProgressSink;
     nsCOMPtr<nsILoadGroup>              mLoadGroup;
     nsCOMPtr<nsIStreamListener>         mListener;
     nsCOMPtr<nsISupports>               mListenerContext;
--- a/netwerk/protocol/wyciwyg/nsWyciwygProtocolHandler.cpp
+++ b/netwerk/protocol/wyciwyg/nsWyciwygProtocolHandler.cpp
@@ -8,16 +8,20 @@
 #include "nsWyciwygChannel.h"
 #include "nsWyciwygProtocolHandler.h"
 #include "nsIURL.h"
 #include "nsIComponentManager.h"
 #include "nsNetCID.h"
 #include "nsServiceManagerUtils.h"
 #include "plstr.h"
 #include "nsNetUtil.h"
+#include "nsIObserverService.h"
+#include "mozIApplicationClearPrivateDataParams.h"
+#include "nsICacheService.h"
+#include "nsICacheSession.h"
 
 #include "mozilla/net/NeckoChild.h"
 
 using namespace mozilla::net;
 #include "mozilla/net/WyciwygChannelChild.h"
 
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -31,17 +35,104 @@ nsWyciwygProtocolHandler::nsWyciwygProto
   LOG(("Creating nsWyciwygProtocolHandler [this=%x].\n", this));
 }
 
 nsWyciwygProtocolHandler::~nsWyciwygProtocolHandler() 
 {
   LOG(("Deleting nsWyciwygProtocolHandler [this=%x]\n", this));
 }
 
-NS_IMPL_ISUPPORTS1(nsWyciwygProtocolHandler, nsIProtocolHandler)
+nsresult
+nsWyciwygProtocolHandler::Init()
+{
+  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  if (obs) {
+    obs->AddObserver(this, "webapps-clear-data", true);
+  }
+  return NS_OK;
+}
+
+static void
+EvictCacheSession(uint32_t aAppId,
+                  bool aInBrowser,
+                  bool aPrivateBrowsing)
+{
+  nsAutoCString clientId;
+  nsWyciwygProtocolHandler::GetCacheSessionName(aAppId, aInBrowser,
+                                                aPrivateBrowsing,
+                                                clientId);
+  nsCOMPtr<nsICacheService> serv =
+      do_GetService(NS_CACHESERVICE_CONTRACTID);
+  nsCOMPtr<nsICacheSession> session;
+  nsresult rv = serv->CreateSession(clientId.get(),
+                                    nsICache::STORE_ANYWHERE,
+                                    nsICache::STREAM_BASED,
+                                    getter_AddRefs(session));
+  if (NS_SUCCEEDED(rv) && session) {
+    session->EvictEntries();
+  }
+}
+
+void
+nsWyciwygProtocolHandler::GetCacheSessionName(uint32_t aAppId,
+                                              bool aInBrowser,
+                                              bool aPrivateBrowsing,
+                                              nsACString& aSessionName)
+{
+  if (aPrivateBrowsing) {
+    aSessionName.AssignLiteral("wyciwyg-private");
+  } else {
+    aSessionName.AssignLiteral("wyciwyg");
+  }
+  if (aAppId == NECKO_NO_APP_ID && !aInBrowser) {
+    return;
+  }
+
+  aSessionName.Append('~');
+  aSessionName.AppendInt(aAppId);
+  aSessionName.Append('~');
+  aSessionName.AppendInt(aInBrowser);
+}
+
+NS_IMETHODIMP
+nsWyciwygProtocolHandler::Observe(nsISupports *subject,
+                                  const char *topic,
+                                  const PRUnichar *data)
+{
+  if (strcmp(topic, "webapps-clear-data") == 0) {
+    nsCOMPtr<mozIApplicationClearPrivateDataParams> params =
+        do_QueryInterface(subject);
+    if (!params) {
+      NS_ERROR("'webapps-clear-data' notification's subject should be a mozIApplicationClearPrivateDataParams");
+      return NS_ERROR_UNEXPECTED;
+    }
+
+    uint32_t appId;
+    bool browserOnly;
+    nsresult rv = params->GetAppId(&appId);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = params->GetBrowserOnly(&browserOnly);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    MOZ_ASSERT(appId != NECKO_UNKNOWN_APP_ID);
+
+    EvictCacheSession(appId, browserOnly, false);
+    EvictCacheSession(appId, browserOnly, true);
+    if (!browserOnly) {
+      EvictCacheSession(appId, true, false);
+      EvictCacheSession(appId, true, true);
+    }
+  }
+  return NS_OK;
+}
+
+NS_IMPL_ISUPPORTS3(nsWyciwygProtocolHandler,
+                   nsIProtocolHandler,
+                   nsIObserver,
+                   nsISupportsWeakReference)
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsIProtocolHandler methods:
 ////////////////////////////////////////////////////////////////////////////////
 
 NS_IMETHODIMP
 nsWyciwygProtocolHandler::GetScheme(nsACString &result)
 {
--- a/netwerk/protocol/wyciwyg/nsWyciwygProtocolHandler.h
+++ b/netwerk/protocol/wyciwyg/nsWyciwygProtocolHandler.h
@@ -3,21 +3,32 @@
  * 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 nsWyciwygProtocolHandler_h___
 #define nsWyciwygProtocolHandler_h___
 
 #include "nsIProtocolHandler.h"
-
+#include "nsIObserver.h"
+#include "nsWeakReference.h"
             
 class nsWyciwygProtocolHandler : public nsIProtocolHandler
+                               , public nsIObserver
+                               , public nsSupportsWeakReference
 {
 public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIPROTOCOLHANDLER
+    NS_DECL_NSIOBSERVER
 
     nsWyciwygProtocolHandler();
     virtual ~nsWyciwygProtocolHandler();
+
+    nsresult Init();
+
+    static void GetCacheSessionName(uint32_t aAppId,
+                                    bool aInBrowser,
+                                    bool aPrivateBrowsing,
+                                    nsACString& aSessionName);
 };
 
 #endif /* nsWyciwygProtocolHandler_h___ */