Bug 499733 - Open Web Location dialog leaks URL/search entered in private browsing mode; r=mconnor
authorEhsan Akhgari <ehsan.akhgari@gmail.com>
Sun, 30 Aug 2009 11:01:46 +0430
changeset 32083 31ab7a791467af6cafa763a93127c0674d0492a1
parent 32082 860134e65933f25e1b8c6da1d34041c99bfe09c8
child 32084 2b834d3174574039b30e6116e9a55c1347d1a926
push id8837
push userehsan.akhgari@gmail.com
push dateSun, 30 Aug 2009 06:32:19 +0000
treeherdermozilla-central@31ab7a791467 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmconnor
bugs499733
milestone1.9.3a1pre
Bug 499733 - Open Web Location dialog leaks URL/search entered in private browsing mode; r=mconnor
browser/base/Makefile.in
browser/base/content/openLocation.js
browser/base/content/openLocationLastURL.jsm
browser/components/privatebrowsing/test/browser/Makefile.in
browser/components/privatebrowsing/test/browser/browser_privatebrowsing_openlocation.js
browser/components/privatebrowsing/test/unit/test_openLocationLastURL.js
--- a/browser/base/Makefile.in
+++ b/browser/base/Makefile.in
@@ -48,16 +48,20 @@ include $(topsrcdir)/config/config.mk
 abs_srcdir = $(call core_abspath,$(srcdir))
 
 CHROME_DEPS += $(abs_srcdir)/content/overrides/app-license.html
 
 ifdef ENABLE_TESTS
 DIRS += content/test
 endif
 
+EXTRA_JS_MODULES = \
+	content/openLocationLastURL.jsm \
+	$(NULL)
+
 include $(topsrcdir)/config/rules.mk
 
 PRE_RELEASE_SUFFIX := $(shell $(PYTHON) $(topsrcdir)/config/printprereleasesuffix.py \
                         $(shell cat $(srcdir)/../config/version.txt))
 
 DEFINES += \
 	-DMOZ_APP_VERSION=$(MOZ_APP_VERSION) \
 	-DAPP_LICENSE_BLOCK=$(abs_srcdir)/content/overrides/app-license.html \
--- a/browser/base/content/openLocation.js
+++ b/browser/base/content/openLocation.js
@@ -44,16 +44,18 @@ var dialog = {};
 var pref = null;
 try {
   pref = Components.classes["@mozilla.org/preferences-service;1"]
                    .getService(Components.interfaces.nsIPrefBranch);
 } catch (ex) {
   // not critical, remain silent
 }
 
+Components.utils.import("resource://gre/modules/openLocationLastURL.jsm");
+
 function onLoad()
 {
   dialog.input         = document.getElementById("dialog.input");
   dialog.open          = document.documentElement.getButton("accept");
   dialog.openWhereList = document.getElementById("openWhereList");
   dialog.openTopWindow = document.getElementById("currentWindow");
   dialog.bundle        = document.getElementById("openLocationBundle");
 
@@ -69,18 +71,17 @@ function onLoad()
         dialog.input.setAttribute("completedefaultindex", "true");
     } catch (ex) {}
 
     try {
       var value = pref.getIntPref("general.open_location.last_window_choice");
       var element = dialog.openWhereList.getElementsByAttribute("value", value)[0];
       if (element)
         dialog.openWhereList.selectedItem = element;
-      dialog.input.value = pref.getComplexValue("general.open_location.last_url",
-                                                Components.interfaces.nsISupportsString).data;
+      dialog.input.value = gOpenLocationLastURL.value;
     }
     catch(ex) {
     }
     if (dialog.input.value)
       dialog.input.select(); // XXX should probably be done automatically
   }
 
   doEnabling();
@@ -115,21 +116,17 @@ function open()
         browser.delayedOpenTab(url, null, null, postData.value, true);
         break;
     }
   }
   catch(exception) {
   }
 
   if (pref) {
-    var str = Components.classes["@mozilla.org/supports-string;1"]
-                        .createInstance(Components.interfaces.nsISupportsString);
-    str.data = dialog.input.value;
-    pref.setComplexValue("general.open_location.last_url",
-                         Components.interfaces.nsISupportsString, str);
+    gOpenLocationLastURL.value = dialog.input.value;
     pref.setIntPref("general.open_location.last_window_choice", dialog.openWhereList.value);
   }
 
   // Delay closing slightly to avoid timing bug on Linux.
   window.close();
   return false;
 }
 
new file mode 100644
--- /dev/null
+++ b/browser/base/content/openLocationLastURL.jsm
@@ -0,0 +1,94 @@
+/* ***** 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 Open Location Dialog Utility Code.
+ *
+ * The Initial Developer of the Original Code is
+ * Ehsan Akhgari <ehsan.akhgari@gmail.com>.
+ * 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 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 LAST_URL_PREF = "general.open_location.last_url";
+const nsISupportsString = Components.interfaces.nsISupportsString;
+
+var EXPORTED_SYMBOLS = [ "gOpenLocationLastURL" ];
+
+let pbSvc = Components.classes["@mozilla.org/privatebrowsing;1"]
+                      .getService(Components.interfaces.nsIPrivateBrowsingService);
+let prefSvc = Components.classes["@mozilla.org/preferences-service;1"]
+                        .getService(Components.interfaces.nsIPrefBranch);
+
+let observer = {
+  QueryInterface: function (aIID) {
+    if (aIID.equals(Components.interfaces.nsIObserver) ||
+        aIID.equals(Components.interfaces.nsISupports) ||
+        aIID.equals(Components.interfaces.nsISupportsWeakReference))
+      return this;
+    throw Components.results.NS_NOINTERFACE;
+  },
+  observe: function (aSubject, aTopic, aData) {
+    gOpenLocationLastURLData = "";
+  }
+};
+
+Components.classes["@mozilla.org/observer-service;1"]
+          .getService(Components.interfaces.nsIObserverService)
+          .addObserver(observer, "private-browsing", true);
+
+let gOpenLocationLastURLData = "";
+let gOpenLocationLastURL = {
+  get value() {
+    if (pbSvc.privateBrowsingEnabled)
+      return gOpenLocationLastURLData;
+    else {
+      try {
+        return prefSvc.getComplexValue(LAST_URL_PREF, nsISupportsString).data;
+      }
+      catch (e) {
+        return "";
+      }
+    }
+  },
+  set value(val) {
+    if (typeof val != "string")
+      val = "";
+    if (pbSvc.privateBrowsingEnabled)
+      gOpenLocationLastURLData = val;
+    else {
+      let str = Components.classes["@mozilla.org/supports-string;1"]
+                          .createInstance(Components.interfaces.nsISupportsString);
+      str.data = val;
+      prefSvc.setComplexValue(LAST_URL_PREF, nsISupportsString, str);
+    }
+  },
+  reset: function() {
+    prefSvc.clearUserPref(LAST_URL_PREF);
+    gOpenLocationLastURLData = "";
+  }
+};
--- a/browser/components/privatebrowsing/test/browser/Makefile.in
+++ b/browser/components/privatebrowsing/test/browser/Makefile.in
@@ -50,16 +50,17 @@ include $(topsrcdir)/config/rules.mk
 		browser_privatebrowsing_crh.js \
 		browser_privatebrowsing_downloadmonitor.js \
 		browser_privatebrowsing_findbar.js \
 		browser_privatebrowsing_forgetthissite.js \
 		browser_privatebrowsing_geoprompt.js \
 		browser_privatebrowsing_geoprompt_page.html \
 		browser_privatebrowsing_import.js \
 		browser_privatebrowsing_opendir.js \
+		browser_privatebrowsing_openlocation.js \
 		browser_privatebrowsing_pageinfo.js \
 		browser_privatebrowsing_popupmode.js \
 		browser_privatebrowsing_searchbar.js \
 		browser_privatebrowsing_sslsite_transition.js \
 		browser_privatebrowsing_theming.js \
 		browser_privatebrowsing_transition.js \
 		browser_privatebrowsing_ui.js \
 		browser_privatebrowsing_urlbarfocus.js \
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_openlocation.js
@@ -0,0 +1,110 @@
+/* ***** 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 Private Browsing Tests.
+ *
+ * The Initial Developer of the Original Code is
+ * Ehsan Akhgari.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Ehsan Akhgari <ehsan.akhgari@gmail.com> (Original Author)
+ *
+ * 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 ***** */
+
+// This test makes sure that Open Location dialog is usable inside the private browsing
+// mode without leaving any trace of the URLs visited.
+
+function test() {
+  // initialization
+  let pb = Cc["@mozilla.org/privatebrowsing;1"].
+           getService(Ci.nsIPrivateBrowsingService);
+  let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
+           getService(Ci.nsIWindowWatcher);
+  waitForExplicitFinish();
+
+  function openLocation(url, autofilled, callback) {
+    let observer = {
+      observe: function(aSubject, aTopic, aData) {
+        switch (aTopic) {
+        case "domwindowopened":
+          let dialog = aSubject.QueryInterface(Ci.nsIDOMWindow);
+          dialog.addEventListener("load", function () {
+            dialog.removeEventListener("load", arguments.callee, false);
+
+            let browser = gBrowser.getBrowserForTab(gBrowser.selectedTab);
+            browser.addEventListener("load", function() {
+              browser.removeEventListener("load", arguments.callee, true);
+
+              is(browser.currentURI.spec, url,
+                 "The correct URL should be loaded via the open location dialog");
+              executeSoon(callback);
+            }, true);
+
+            executeSoon(function() {
+              let input = dialog.document.getElementById("dialog.input");
+              is(input.value, autofilled, "The input field should be correctly auto-filled");
+              input.focus();
+              for (let i = 0; i < url.length; ++i)
+                EventUtils.synthesizeKey(url[i], {}, dialog);
+              EventUtils.synthesizeKey("VK_RETURN", {}, dialog);
+            });
+          }, false);
+          break;
+
+        case "domwindowclosed":
+          ww.unregisterNotification(this);
+          break;
+        }
+      }
+    };
+
+    ww.registerNotification(observer);
+    gPrefService.setIntPref("general.open_location.last_window_choice", 0);
+    openDialog("chrome://browser/content/openLocation.xul", "_blank",
+               "chrome,titlebar", window);
+  }
+
+  gPrefService.clearUserPref("general.open_location.last_url");
+
+  openLocation("http://example.com/", "", function() {
+    openLocation("http://example.org/", "http://example.com/", function() {
+      // enter private browsing mode
+      pb.privateBrowsingEnabled = true;
+      openLocation("about:logo", "", function() {
+        openLocation("about:buildconfig", "about:logo", function() {
+          // exit private browsing mode
+          pb.privateBrowsingEnabled = false;
+          openLocation("about:blank", "http://example.org/", function() {
+            gPrefService.clearUserPref("general.open_location.last_url");
+            gPrefService.clearUserPref("general.open_location.last_window_choice");
+            finish();
+          });
+        });
+      });
+    });
+  });
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/unit/test_openLocationLastURL.js
@@ -0,0 +1,84 @@
+/* ***** 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 Private Browsing Test Code.
+ *
+ * The Initial Developer of the Original Code is
+ * Ehsan Akhgari <ehsan.akhgari@gmail.com>.
+ * 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 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 ***** */
+
+// Test the correct behavior of the openLocationLastURL.jsm JS module.
+
+function run_test_on_service()
+{
+  let Cc = Components.classes;
+  let Ci = Components.interfaces;
+  let Cu = Components.utils;
+  Cu.import("resource://gre/modules/openLocationLastURL.jsm");
+
+  let pb = Cc[PRIVATEBROWSING_CONTRACT_ID].
+           getService(Ci.nsIPrivateBrowsingService);
+  let pref = Cc["@mozilla.org/preferences-service;1"].
+             getService(Ci.nsIPrefBranch);
+  gOpenLocationLastURL.reset();
+
+  do_check_eq(typeof gOpenLocationLastURL, "object");
+  do_check_eq(gOpenLocationLastURL.value, "");
+
+  const url1 = "mozilla.org";
+  const url2 = "mozilla.com";
+
+  gOpenLocationLastURL.value = url1;
+  do_check_eq(gOpenLocationLastURL.value, url1);
+
+  gOpenLocationLastURL.value = "";
+  do_check_eq(gOpenLocationLastURL.value, "");
+
+  gOpenLocationLastURL.value = url2;
+  do_check_eq(gOpenLocationLastURL.value, url2);
+
+  pb.privateBrowsingEnabled = true;
+  do_check_eq(gOpenLocationLastURL.value, "");
+
+  pb.privateBrowsingEnabled = false;
+  do_check_eq(gOpenLocationLastURL.value, url2);
+  pb.privateBrowsingEnabled = true;
+
+  gOpenLocationLastURL.value = url1;
+  do_check_eq(gOpenLocationLastURL.value, url1);
+
+  pb.privateBrowsingEnabled = false;
+  do_check_eq(gOpenLocationLastURL.value, url2);
+}
+
+// Support running tests on both the service itself and its wrapper
+function run_test() {
+  run_test_on_all_services();
+}