Bug 1268120 - Make plugin content blocking work on e10s. r=francois, a=gchang
authorTobias Schneider <schneider@jancona.com>
Fri, 17 Jun 2016 11:05:42 +0100
changeset 342109 db4d7a074f53507423cd2b2d64852c8085433b1b
parent 342108 fbf0cb3a765162fa77a125b4ec8e0ef67af72b47
child 342110 db9f8c2dcb833b7206f3cd6dfa8aa9677fa16fcd
push id1183
push userraliiev@mozilla.com
push dateMon, 05 Sep 2016 20:01:49 +0000
treeherdermozilla-release@3148731bed45 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfrancois, gchang
bugs1268120
milestone49.0a2
Bug 1268120 - Make plugin content blocking work on e10s. r=francois, a=gchang
dom/base/nsObjectLoadingContent.cpp
dom/base/nsObjectLoadingContent.h
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -127,16 +127,23 @@ GetObjectLog()
 static bool
 IsJavaMIME(const nsACString & aMIMEType)
 {
   return
     nsPluginHost::GetSpecialType(aMIMEType) == nsPluginHost::eSpecialType_Java;
 }
 
 static bool
+IsFlashMIME(const nsACString & aMIMEType)
+{
+  return
+    nsPluginHost::GetSpecialType(aMIMEType) == nsPluginHost::eSpecialType_Flash;
+}
+
+static bool
 InActiveDocument(nsIContent *aContent)
 {
   if (!aContent->IsInComposedDoc()) {
     return false;
   }
   nsIDocument *doc = aContent->OwnerDoc();
   return (doc && doc->IsActive());
 }
@@ -460,21 +467,20 @@ private:
   nsObjectLoadingContent* mContent;
 };
 
 ///
 /// Helper functions
 ///
 
 static bool
-IsSuccessfulRequest(nsIRequest* aRequest)
+IsSuccessfulRequest(nsIRequest* aRequest, nsresult* aStatus)
 {
-  nsresult status;
-  nsresult rv = aRequest->GetStatus(&status);
-  if (NS_FAILED(rv) || NS_FAILED(status)) {
+  nsresult rv = aRequest->GetStatus(aStatus);
+  if (NS_FAILED(rv) || NS_FAILED(*aStatus)) {
     return false;
   }
 
   // This may still be an error page or somesuch
   nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(aRequest));
   if (httpChan) {
     bool success;
     rv = httpChan->GetRequestSucceeded(&success);
@@ -714,16 +720,17 @@ nsObjectLoadingContent::nsObjectLoadingC
   : mType(eType_Loading)
   , mFallbackType(eFallbackAlternate)
   , mRunID(0)
   , mHasRunID(false)
   , mChannelLoaded(false)
   , mInstantiating(false)
   , mNetworkCreated(true)
   , mActivated(false)
+  , mContentBlockingDisabled(false)
   , mIsStopping(false)
   , mIsLoading(false)
   , mScriptRequested(false)
   , mRewrittenYoutubeEmbed(false) {}
 
 nsObjectLoadingContent::~nsObjectLoadingContent()
 {
   // Should have been unbound from the tree at this point, and
@@ -1118,23 +1125,41 @@ nsObjectLoadingContent::OnStartRequest(n
   NS_ASSERTION(!mChannelLoaded, "mChannelLoaded set already?");
   NS_ASSERTION(!mFinalListener, "mFinalListener exists already?");
 
   mChannelLoaded = true;
 
   nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
   NS_ASSERTION(chan, "Why is our request not a channel?");
 
-  nsCOMPtr<nsIURI> uri;
-
-  if (IsSuccessfulRequest(aRequest)) {
-    chan->GetURI(getter_AddRefs(uri));
+  nsresult status;
+  bool success = IsSuccessfulRequest(aRequest, &status);
+
+  if (status == NS_ERROR_BLOCKED_URI) {
+    nsCOMPtr<nsIConsoleService> console(
+      do_GetService("@mozilla.org/consoleservice;1"));
+    if (console) {
+      nsCOMPtr<nsIURI> uri;
+      chan->GetURI(getter_AddRefs(uri));
+      nsAutoCString spec;
+      uri->GetSpec(spec);
+      nsString message = NS_LITERAL_STRING("Blocking ") +
+        NS_ConvertASCIItoUTF16(spec.get()) +
+        NS_LITERAL_STRING(" since it was found on an internal Firefox blocklist.");
+      console->LogStringMessage(message.get());
+    }
+    Telemetry::Accumulate(Telemetry::PLUGIN_BLOCKED_FOR_STABILITY, 1);
+    return NS_ERROR_FAILURE;
+  } else if (status == NS_ERROR_TRACKING_URI) {
+    return NS_ERROR_FAILURE;
+  } else {
+    mContentBlockingDisabled = true;
   }
 
-  if (!uri) {
+  if (!success) {
     LOG(("OBJLC [%p]: OnStartRequest: Request failed\n", this));
     // If the request fails, we still call LoadObject() to handle fallback
     // content and notifying of failure. (mChannelLoaded && !mChannel) indicates
     // the bad state.
     mChannel = nullptr;
     LoadObject(true, false);
     return NS_ERROR_FAILURE;
   }
@@ -2272,42 +2297,16 @@ nsObjectLoadingContent::LoadObject(bool 
     }
     // If we're loading a type now, check ProcessPolicy. Note that we may check
     // both now in the case of plugins whose type is determined before opening a
     // channel.
     if (allowLoad && mType != eType_Loading) {
       allowLoad = CheckProcessPolicy(&contentPolicy);
     }
 
-    // This needs to be reverted once the plugin stability experiment is over (see bug #1268120).
-    if (allowLoad && Preferences::GetBool(kPrefBlockURIs)) {
-      RefPtr<nsChannelClassifier> channelClassifier = new nsChannelClassifier();
-      nsCOMPtr<nsIURIClassifier> classifier = do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID);
-      if (classifier) {
-        nsAutoCString tables;
-        Preferences::GetCString("urlclassifier.blockedTable", &tables);
-        nsAutoCString results;
-        rv = classifier->ClassifyLocalWithTables(mURI, tables, results);
-        if (NS_SUCCEEDED(rv) && !results.IsEmpty()) {
-          nsAutoCString uri;
-          mURI->GetSpec(uri);
-          nsCOMPtr<nsIConsoleService> console(
-            do_GetService("@mozilla.org/consoleservice;1"));
-          if (console) {
-            nsString message = NS_LITERAL_STRING("Blocking ") +
-              NS_ConvertASCIItoUTF16(uri) +
-              NS_LITERAL_STRING(" since it was found on an internal Firefox blocklist.");
-            console->LogStringMessage(message.get());
-          }
-          Telemetry::Accumulate(Telemetry::PLUGIN_BLOCKED_FOR_STABILITY, 1);
-          allowLoad = false;
-        }
-      }
-    }
-
     // Content policy implementations can mutate the DOM, check for re-entry
     if (!mIsLoading) {
       LOG(("OBJLC [%p]: We re-entered in content policy, leaving original load",
            this));
       return NS_OK;
     }
 
     // Load denied, switch to fallback and set disabled/suppressed if applicable
@@ -2345,16 +2344,23 @@ nsObjectLoadingContent::LoadObject(bool 
         break;
       }
 
       nestedURI->GetInnerURI(getter_AddRefs(tempURI));
       nestedURI = do_QueryInterface(tempURI);
     }
   }
 
+  // Items resolved as Image/Document are no candidates for content blocking,
+  // as well as invalid plugins (they will not have the mContentType set).
+  if ((mType == eType_Null || mType == eType_Plugin) && ShouldBlockContent()) {
+    LOG(("OBJLC [%p]: Enable content blocking", this));
+    mType = eType_Loading;
+  }
+
   // If we're a plugin but shouldn't start yet, load fallback with
   // reason click-to-play instead. Items resolved as Image/Document
   // will not be checked for previews, as well as invalid plugins
   // (they will not have the mContentType set).
   FallbackType clickToPlayReason;
   if (!mActivated && (mType == eType_Null || mType == eType_Plugin) &&
       !ShouldPlay(clickToPlayReason, false)) {
     LOG(("OBJLC [%p]: Marking plugin as click-to-play", this));
@@ -3354,16 +3360,30 @@ nsObjectLoadingContent::GetRunID(uint32_
   return NS_OK;
 }
 
 static bool sPrefsInitialized;
 static uint32_t sSessionTimeoutMinutes;
 static uint32_t sPersistentTimeoutDays;
 
 bool
+nsObjectLoadingContent::ShouldBlockContent()
+{
+  if (mContentBlockingDisabled)
+    return false;
+
+  if (!IsFlashMIME(mContentType) || !Preferences::GetBool(kPrefBlockURIs)) {
+    mContentBlockingDisabled = true;
+    return false;
+  }
+
+  return true;
+}
+
+bool
 nsObjectLoadingContent::ShouldPlay(FallbackType &aReason, bool aIgnoreCurrentType)
 {
   nsresult rv;
 
   if (!sPrefsInitialized) {
     Preferences::AddUintVarCache(&sSessionTimeoutMinutes,
                                  "plugin.sessionPermissionNow.intervalInMinutes", 60);
     Preferences::AddUintVarCache(&sPersistentTimeoutDays,
--- a/dom/base/nsObjectLoadingContent.h
+++ b/dom/base/nsObjectLoadingContent.h
@@ -441,16 +441,21 @@ class nsObjectLoadingContent : public ns
     nsresult OpenChannel();
 
     /**
      * Closes and releases references to mChannel and, if opened, mFinalListener
      */
     nsresult CloseChannel();
 
     /**
+     * If this object should be tested against blocking list.
+     */
+    bool ShouldBlockContent();
+
+    /**
      * If this object is allowed to play plugin content, or if it would display
      * click-to-play instead.
      * NOTE that this does not actually check if the object is a loadable plugin
      * NOTE This ignores the current activated state. The caller should check this if appropriate.
      */
     bool ShouldPlay(FallbackType &aReason, bool aIgnoreCurrentType);
 
     /*
@@ -645,16 +650,19 @@ class nsObjectLoadingContent : public ns
     // created using NS_FROM_PARSER_NETWORK flag. If the element is modified,
     // it may lose the flag.
     bool                        mNetworkCreated : 1;
 
     // Used to keep track of whether or not a plugin has been explicitly
     // activated by PlayPlugin(). (see ShouldPlay())
     bool                        mActivated : 1;
 
+    // Whether content blocking is enabled or not for this object.
+    bool                        mContentBlockingDisabled : 1;
+
     // Protects DoStopPlugin from reentry (bug 724781).
     bool                        mIsStopping : 1;
 
     // Protects LoadObject from re-entry
     bool                        mIsLoading : 1;
 
     // For plugin stand-in types (click-to-play) tracks
     // whether content js has tried to access the plugin script object.