Bug 455213: Plugins get enabled when updating to Firefox 3.1. r=jst, r=josh
authorDave Townsend <dtownsend@oxymoronical.com>
Thu, 09 Oct 2008 10:35:20 +0100
changeset 20197 62274f98ccf834fef92e40f9b6afc9e235ab3596
parent 20196 b55e95f2997345fc0eba8c7a05130f0190ebf0c5
child 20198 335b63a03aba0b7e0a329eea658dd94410e71402
child 20203 2ab95180da6d0920307d06f1061486a504757aff
push idunknown
push userunknown
push dateunknown
reviewersjst, josh
bugs455213
milestone1.9.1b2pre
Bug 455213: Plugins get enabled when updating to Firefox 3.1. r=jst, r=josh
modules/plugin/base/src/nsPluginHostImpl.cpp
modules/plugin/test/Makefile.in
modules/plugin/test/unit/test_bug455213.js
--- a/modules/plugin/base/src/nsPluginHostImpl.cpp
+++ b/modules/plugin/base/src/nsPluginHostImpl.cpp
@@ -87,16 +87,17 @@
 #include "nsHashtable.h"
 #include "nsIProxyInfo.h"
 #include "nsObsoleteModuleLoading.h"
 #include "nsIComponentRegistrar.h"
 #include "nsPluginLogging.h"
 #include "nsIPrefBranch2.h"
 #include "nsIScriptChannel.h"
 #include "nsPrintfCString.h"
+#include "nsVersionComparator.h"
 
 // Friggin' X11 has to "#define None". Lame!
 #ifdef None
 #undef None
 #endif
 
 #ifdef CursorShape
 #undef CursorShape /*X.h defines it as 0,
@@ -198,17 +199,20 @@
 // 0.03 changed name, description and mime desc from string to bytes, bug 108246
 // 0.04 added new mime entry point on Mac, bug 113464
 // 0.05 added new entry point check for the default plugin, bug 132430
 // 0.06 strip off suffixes in mime description strings, bug 53895
 // 0.07 changed nsIRegistry to flat file support for caching plugins info
 // 0.08 mime entry point on MachO, bug 137535
 // 0.09 the file encoding is changed to UTF-8, bug 420285
 // 0.10 added plugin versions on appropriate platforms, bug 427743
+// The current plugin registry version (and the maximum version we know how to read)
 static const char *kPluginRegistryVersion = "0.10";
+// The minimum registry version we know how to read
+static const char *kMinimumRegistryVersion = "0.9";
 ////////////////////////////////////////////////////////////////////////
 // CID's && IID's
 static NS_DEFINE_IID(kIPluginInstanceIID, NS_IPLUGININSTANCE_IID);
 static NS_DEFINE_CID(kPluginCID, NS_PLUGIN_CID);
 static NS_DEFINE_IID(kIPluginTagInfo2IID, NS_IPLUGINTAGINFO2_IID);
 static const char kDirectoryServiceContractID[] = "@mozilla.org/file/directory_service;1";
 // for the dialog
 static NS_DEFINE_CID(kCPluginManagerCID, NS_PLUGINMANAGER_CID); // needed for NS_TRY_SAFE_CALL
@@ -5769,42 +5773,55 @@ nsPluginHostImpl::ReadPluginInfo()
   }
 
   // VersionLiteral
   if (PL_strcmp(values[0], "Version")) {
     return rv;
   }
 
   // kPluginRegistryVersion
-  if (PL_strcmp(values[1], kPluginRegistryVersion)) {
+  PRInt32 vdiff = NS_CompareVersions(values[1], kPluginRegistryVersion);
+  // If this is a registry from some future version then don't attempt to read it
+  if (vdiff > 0) {
+    return rv;
+  }
+  // If this is a registry from before the minimum then don't attempt to read it
+  if (NS_CompareVersions(values[1], kMinimumRegistryVersion) < 0) {
     return rv;
   }
 
   if (!ReadSectionHeader(reader, "PLUGINS")) {
     return rv;
   }
 
   while (reader.NextLine()) {
     char *filename = reader.LinePtr();
     if (!reader.NextLine())
       return rv;
 
     char *fullpath = reader.LinePtr();
     if (!reader.NextLine())
       return rv;
 
-    char *version = reader.LinePtr();
-    if (!reader.NextLine())
-      return rv;
+    char *version;
+    if (NS_CompareVersions(values[1], "0.10") >= 0) {
+      version = reader.LinePtr();
+      if (!reader.NextLine())
+        return rv;
+    }
+    else {
+      version = "0";
+    }
 
     // lastModifiedTimeStamp|canUnload|tag.mFlag
     if (3 != reader.ParseLine(values, 3))
       return rv;
 
-    PRInt64 lastmod = nsCRT::atoll(values[0]);
+    // If this is an old plugin registry mark this plugin tag to be refreshed
+    PRInt64 lastmod = vdiff == 0 ? nsCRT::atoll(values[0]) : -1;
     PRBool canunload = atoi(values[1]);
     PRUint32 tagflag = atoi(values[2]);
     if (!reader.NextLine())
       return rv;
 
     char *description = reader.LinePtr();
     if (!reader.NextLine())
       return rv;
--- a/modules/plugin/test/Makefile.in
+++ b/modules/plugin/test/Makefile.in
@@ -37,13 +37,17 @@
 
 DEPTH		= ../../..
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
-MODULE = plugin
+MODULE = test_plugin
 
 DIRS = testplugin
 
+XPCSHELL_TESTS = \
+  unit \
+  $(NULL)
+
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/modules/plugin/test/unit/test_bug455213.js
@@ -0,0 +1,160 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ *      Dave Townsend <dtownsend@oxymoronical.com>.
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK *****
+ */
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+const NS_APP_USER_PROFILE_50_DIR      = "ProfD";
+const NS_APP_PROFILE_DIR_STARTUP      = "ProfDS";
+
+var gProfD;
+var gDirSvc = Cc["@mozilla.org/file/directory_service;1"].
+             getService(Ci.nsIProperties);
+
+// Creates a fake profile folder that the pluginhost will read our crafted
+// pluginreg.dat from
+function createProfileFolder() {
+  gProfD = gDirSvc.get("CurProcD", Ci.nsILocalFile);
+  gProfD = gProfD.parent.parent;
+  gProfD.append("_tests");
+  gProfD.append("xpcshell-simple");
+  gProfD.append("test_plugin");
+  gProfD.append("profile");
+  
+  if (gProfD.exists())
+    gProfD.remove(true);
+  gProfD.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0755);
+  
+  var dirProvider = {
+    getFile: function(prop, persistent) {
+      persistent.value = true;
+      if (prop == NS_APP_USER_PROFILE_50_DIR ||
+          prop == NS_APP_PROFILE_DIR_STARTUP)
+        return gProfD.clone();
+      return null;
+    },
+    QueryInterface: function(iid) {
+      if (iid.equals(Ci.nsIDirectoryServiceProvider) ||
+          iid.equals(Ci.nsISupports)) {
+        return this;
+      }
+      throw Components.results.NS_ERROR_NO_INTERFACE;
+    }
+  };
+  gDirSvc.QueryInterface(Ci.nsIDirectoryService)
+         .registerProvider(dirProvider);
+}
+
+// Writes out some plugin registry to the profile
+function write_registry(version, info) {
+  var header = "Generated File. Do not edit.\n\n";
+  header += "[HEADER]\n";
+  header += "Version:" + version + ":$\n\n";
+  header += "[PLUGINS]\n";
+
+  var registry = gProfD.clone();
+  registry.append("pluginreg.dat");
+  var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
+                           .createInstance(Components.interfaces.nsIFileOutputStream);
+  // write, create, truncate
+  foStream.init(registry, 0x02 | 0x08 | 0x20, 0666, 0); 
+
+  var charset = "UTF-8"; // Can be any character encoding name that Mozilla supports
+  var os = Cc["@mozilla.org/intl/converter-output-stream;1"].
+           createInstance(Ci.nsIConverterOutputStream);
+  os.init(foStream, charset, 0, 0x0000);
+  
+  os.writeString(header);
+  os.writeString(info);
+  os.close();
+}
+
+// Finds the test plugin library
+function get_test_plugin() {
+  var plugins = gDirSvc.get("CurProcD", Ci.nsILocalFile);
+  plugins.append("plugins");
+  do_check_true(plugins.exists());
+  var plugin = plugins.clone();
+  plugin.append("Test.plugin");
+  if (plugin.exists()) {
+    plugin.normalize();
+    return plugin;
+  }
+  return null;
+}
+
+// Finds the test nsIPluginTag
+function get_test_plugintag() {
+  var host = Cc["@mozilla.org/plugin/host;1"].
+             getService(Ci.nsIPluginHost);
+  var tags = host.getPluginTags({});
+  for (var i = 0; i < tags.length; i++) {
+    if (tags[i].name == "Test Plug-in")
+      return tags[i];
+  }
+  return null;
+}
+
+function run_test() {
+  createProfileFolder();
+  var file = get_test_plugin();
+  if (!file)
+    do_throw("Plugin library not found");
+
+  // Write out a 0.9 version registry that marks the test plugin as disabled
+  var registry = "";
+  registry += file.leafName + ":$\n";
+  registry += file.path + ":$\n";
+  registry += file.lastModifiedTime + ":0:0" + ":$\n";
+  registry += "Plug-in for testing purposes." + ":$\n";
+  registry += "Test Plug-in" + ":$\n";
+  registry += "1\n";
+  registry += "0:application/x-test:Test mimetype:tst" + ":$\n";
+  write_registry("0.9", registry);
+
+  var plugin = get_test_plugintag();
+  if (!plugin)
+    do_throw("Plugin tag not found");
+
+  // If the plugin was not rescanned then this version will not be correct
+  do_check_eq(plugin.version, "1.0.0.0");
+  do_check_eq(plugin.description, "Plug-in for testing purposes.");
+  // If the plugin registry was not read then the plugin will not be disabled
+  do_check_true(plugin.disabled);
+  do_check_false(plugin.blocklisted);
+}