From b38cf5820a966f798fe149d5988325b03dcd2277 Mon Sep 17 00:00:00 2001 From: Dave Townsend Date: Thu, 26 Mar 2009 11:12:55 +0000 Subject: [PATCH] Bug 435788: Plugin finder service can't install plugins using installerLocation, stage 1. r=robstrong --- browser/base/content/browser.js | 3 +- toolkit/mozapps/plugins/Makefile.in | 11 ++- .../plugins/content/pluginInstallerService.js | 12 ++- .../plugins/content/pluginInstallerWizard.js | 31 +++++-- toolkit/mozapps/plugins/tests/GoodPlugin.cpp | 4 + toolkit/mozapps/plugins/tests/Makefile.in | 72 +++++++++++++++ .../plugins/tests/browser_bug435788.js | 90 +++++++++++++++++++ .../mozapps/plugins/tests/pfs_bug435788_1.rdf | 30 +++++++ 8 files changed, 239 insertions(+), 14 deletions(-) create mode 100644 toolkit/mozapps/plugins/tests/GoodPlugin.cpp create mode 100644 toolkit/mozapps/plugins/tests/Makefile.in create mode 100644 toolkit/mozapps/plugins/tests/browser_bug435788.js create mode 100644 toolkit/mozapps/plugins/tests/pfs_bug435788_1.rdf diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 6dbf7e07c9b0..9351d2d99ed6 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -5935,7 +5935,8 @@ missingPluginInstaller.prototype.newDisabledPlugin = function(aEvent){ } missingPluginInstaller.prototype.refreshBrowser = function(aEvent) { - var browser = aEvent.target; + // browser elements are anonymous so we can't just use target. + var browser = aEvent.originalTarget; var notificationBox = gBrowser.getNotificationBox(browser); var notification = notificationBox.getNotificationWithValue("missing-plugins"); diff --git a/toolkit/mozapps/plugins/Makefile.in b/toolkit/mozapps/plugins/Makefile.in index 9d01d71af47e..fc574a0f8e79 100644 --- a/toolkit/mozapps/plugins/Makefile.in +++ b/toolkit/mozapps/plugins/Makefile.in @@ -44,5 +44,14 @@ include $(DEPTH)/config/autoconf.mk EXTRA_COMPONENTS = pluginGlue.js -include $(topsrcdir)/config/rules.mk +ifdef ENABLE_TESTS +# OSX will display a security warning when running the downloaded installer +ifneq (Darwin,$(OS_TARGET)) +# On Linux nsILocalFile.launch will only open documents, not run executables +ifneq (Linux,$(OS_TARGET)) +DIRS += tests +endif +endif +endif +include $(topsrcdir)/config/rules.mk diff --git a/toolkit/mozapps/plugins/content/pluginInstallerService.js b/toolkit/mozapps/plugins/content/pluginInstallerService.js index f6a1e165a163..4ffbcb4d06a9 100644 --- a/toolkit/mozapps/plugins/content/pluginInstallerService.js +++ b/toolkit/mozapps/plugins/content/pluginInstallerService.js @@ -85,9 +85,13 @@ InstallerObserver.prototype = { var uri = ios.newURI(this._plugin.InstallerLocation, null, null); uri.QueryInterface(Components.interfaces.nsIURL); + // Use a local filename appropriate for the OS var leafName = uri.fileName; - if (leafName.indexOf('.') == -1) - throw "Filename needs to contain a dot for platform-native launching to work correctly."; + var os = Components.classes["@mozilla.org/xre/app-info;1"] + .getService(Components.interfaces.nsIXULRuntime) + .OS; + if (os == "WINNT" && leafName.indexOf(".") < 0) + leafName += ".exe"; var dirs = Components.classes["@mozilla.org/file/directory_service;1"]. getService(Components.interfaces.nsIProperties); @@ -95,7 +99,7 @@ InstallerObserver.prototype = { var resultFile = dirs.get("TmpD", Components.interfaces.nsIFile); resultFile.append(leafName); resultFile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, - 0x770); + 0770); var channel = ios.newChannelFromURI(uri); this._downloader = @@ -174,6 +178,8 @@ InstallerObserver.prototype = { result.QueryInterface(Components.interfaces.nsILocalFile); try { + // Make sure the file is executable + result.permissions = 0770; result.launch(); this._fireNotification(nsIXPIProgressDialog.INSTALL_DONE, null); // It would be nice to remove the tempfile, but we don't have diff --git a/toolkit/mozapps/plugins/content/pluginInstallerWizard.js b/toolkit/mozapps/plugins/content/pluginInstallerWizard.js index 63046a9496d0..77e79b1e4fe1 100644 --- a/toolkit/mozapps/plugins/content/pluginInstallerWizard.js +++ b/toolkit/mozapps/plugins/content/pluginInstallerWizard.js @@ -481,7 +481,7 @@ nsPluginInstallerWizard.prototype.showPluginResults = function (){ notInstalledList += "&mimetype=" + pluginInfoItem; } else if (!myPluginItem.licenseAccepted) { statusMsg = this.getString("pluginInstallationSummary.licenseNotAccepted"); - } else if (!myPluginItem.XPILocation) { + } else if (!myPluginItem.XPILocation && !myPluginItem.InstallerLocation) { statusMsg = this.getString("pluginInstallationSummary.notAvailable"); notInstalledList += "&mimetype=" + pluginInfoItem; } else { @@ -495,7 +495,8 @@ nsPluginInstallerWizard.prototype.showPluginResults = function (){ // manual url - either returned from the webservice or the pluginspage attribute var manualUrl; - if ((myPluginItem.error || !myPluginItem.XPILocation) && (myPluginItem.manualInstallationURL || this.mPluginRequestArray[myPluginItem.requestedMimetype].pluginsPage)){ + if ((myPluginItem.error || (!myPluginItem.XPILocation && !myPluginItem.InstallerLocation)) && + (myPluginItem.manualInstallationURL || this.mPluginRequestArray[myPluginItem.requestedMimetype].pluginsPage)){ manualUrl = myPluginItem.manualInstallationURL ? myPluginItem.manualInstallationURL : this.mPluginRequestArray[myPluginItem.requestedMimetype].pluginsPage; } @@ -669,13 +670,25 @@ function wizardFinish(){ // don't refresh if no plugins were found or installed if ((gPluginInstaller.mSuccessfullPluginInstallation > 0) && - (gPluginInstaller.mPluginInfoArray.length != 0) && - gPluginInstaller.mBrowser) { - // notify listeners that a plugin is installed, - // so that they can reset the UI and update the browser. - var event = document.createEvent("Events"); - event.initEvent("NewPluginInstalled", true, true); - gPluginInstaller.mBrowser.dispatchEvent(event); + (gPluginInstaller.mPluginInfoArray.length != 0)) { + + // reload plugins so JS detection works immediately + try { + var pm = Components.classes["@mozilla.org/plugin/manager;1"] + .getService(Components.interfaces.nsIPluginManager); + pm.reloadPlugins(false); + } + catch (e) { + // reloadPlugins throws an exception if there were no plugins to load + } + + if (gPluginInstaller.mBrowser) { + // notify listeners that a plugin is installed, + // so that they can reset the UI and update the browser. + var event = document.createEvent("Events"); + event.initEvent("NewPluginInstalled", true, true); + gPluginInstaller.mBrowser.dispatchEvent(event); + } } return true; diff --git a/toolkit/mozapps/plugins/tests/GoodPlugin.cpp b/toolkit/mozapps/plugins/tests/GoodPlugin.cpp new file mode 100644 index 000000000000..e5a9ccbdf40e --- /dev/null +++ b/toolkit/mozapps/plugins/tests/GoodPlugin.cpp @@ -0,0 +1,4 @@ +int main(int argc, char** argv) +{ + return 0; +} diff --git a/toolkit/mozapps/plugins/tests/Makefile.in b/toolkit/mozapps/plugins/tests/Makefile.in new file mode 100644 index 000000000000..2e0443dc8516 --- /dev/null +++ b/toolkit/mozapps/plugins/tests/Makefile.in @@ -0,0 +1,72 @@ +# ***** 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 Plugin Finder Service. +# +# The Initial Developer of the Original Code is +# Mozilla Corporation. +# +# Portions created by the Initial Developer are Copyright (C) 2009 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = test_plugins +relativesrcdir = toolkit/mozapps/plugins/tests +TESTROOT = $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir) +USE_STATIC_LIBS = 1 + +_BROWSER_FILES = \ + browser_bug435788.js \ + pfs_bug435788_1.rdf \ + $(NULL) + +CPPSRCS = \ + GoodPlugin.cpp \ + $(NULL) + +SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX)) + +PROGRAMS = $(SIMPLE_PROGRAMS:%$(BIN_SUFFIX)=$(TESTROOT)/%) + +include $(topsrcdir)/config/rules.mk + +$(PROGRAMS): $(TESTROOT)/% : %$(BIN_SUFFIX) + $(NSINSTALL) -D $(TESTROOT) + cp $^ $@ + +libs:: $(_BROWSER_FILES) + $(INSTALL) $(foreach f,$^,"$f") $(TESTROOT) + +libs:: $(PROGRAMS) diff --git a/toolkit/mozapps/plugins/tests/browser_bug435788.js b/toolkit/mozapps/plugins/tests/browser_bug435788.js new file mode 100644 index 000000000000..ae2a27b85c77 --- /dev/null +++ b/toolkit/mozapps/plugins/tests/browser_bug435788.js @@ -0,0 +1,90 @@ +const Cc = Components.classes; +const Ci = Components.interfaces; + +const TEST_ROOT = "http://example.com/browser/toolkit/mozapps/plugins/tests/"; + +var gPrefs, gPFS, gDS; + +function test() { + waitForExplicitFinish(); + + gPrefs = Cc["@mozilla.org/preferences-service;1"]. + getService(Ci.nsIPrefBranch); + gDS = Cc["@mozilla.org/file/directory_service;1"]. + getService(Ci.nsIProperties); + prepare_test_1(); +} + +function finishTest(e) { + gPrefs.clearUserPref("pfs.datasource.url"); + finish(); +} + +function delete_installer() { + // Guess at the filename for the installer and delete it + try { + var filename = "setup"; + if (Components.classes["@mozilla.org/xre/app-info;1"] + .getService(Components.interfaces.nsIXULRuntime) + .OS == "WINNT") + filename += ".exe"; + var file = gDS.get("TmpD", Ci.nsIFile); + file.append(filename); + if (file.exists()) + file.remove(false); + } + catch (e) { } +} + +function prepare_test_1() { + gPrefs.setCharPref("pfs.datasource.url", TEST_ROOT + "pfs_bug435788_1.rdf"); + + var missingPluginsArray = { + "application/x-working-plugin": { + mimetype: "application/x-working-plugin", + pluginsPage: "" + } + }; + + gPFS = window.openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul", + "PFSWindow", "chrome,centerscreen,resizable=yes", + {plugins: missingPluginsArray}); + gPFS.addEventListener("load", test_1_start, false); +} + +function test_1_start() { + gPFS.addEventListener("unload", finishTest, false); + + gPFS.document.documentElement.wizardPages[1].addEventListener("pageshow", function() { + executeSoon(test_1_available); + }, false); +} + +function test_1_available() { + var list = gPFS.document.getElementById("pluginList"); + is(list.childNodes.length, 1, "Should have found 1 plugin to install"); + is(list.childNodes[0].label, "Test plugin 1 ", "Should have seen the right plugin name"); + + gPFS.document.documentElement.wizardPages[4].addEventListener("pageshow", function() { + executeSoon(test_1_complete); + }, false); + gPFS.document.documentElement.getButton("next").click(); +} + +function test_1_complete() { + var list = gPFS.document.getElementById("pluginResultList"); + is(list.childNodes.length, 1, "Should have attempted to install 1 plugin"); + var status = list.childNodes[0].childNodes[2]; + is(status.tagName, "label", "Should have a status"); + is(status.value, "Installed", "Should have been a successful install"); + + // This is necessary because PFS doesn't delete the installer it runs. Give it + // a second to finish then delete it ourselves + setTimeout(test_1_finish, 1000); +} + +function test_1_finish() { + delete_installer(); + + gPFS.document.documentElement.getButton("finish").click(); +} diff --git a/toolkit/mozapps/plugins/tests/pfs_bug435788_1.rdf b/toolkit/mozapps/plugins/tests/pfs_bug435788_1.rdf new file mode 100644 index 000000000000..61d58932bf3c --- /dev/null +++ b/toolkit/mozapps/plugins/tests/pfs_bug435788_1.rdf @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + Test plugin 1 + application/x-working-plugin + {8d3ab839-e03e-41a5-acd3-be1eabf94810} + + + http://example.com/browser/toolkit/mozapps/plugins/tests/GoodPlugin + + false + http://www.mozilla.com + + false + + +