Bug 462106 - Clear the data copied to clipboard inside the private browsing mode after leaving it; r,sr=roc a=blocking-firefox3.1+
--- a/widget/src/gtk2/nsClipboard.cpp
+++ b/widget/src/gtk2/nsClipboard.cpp
@@ -159,16 +159,19 @@ nsClipboard::SetData(nsITransferable *aT
aTransferable == mGlobalTransferable.get() &&
aOwner == mGlobalOwner.get()) ||
(aWhichClipboard == kSelectionClipboard &&
aTransferable == mSelectionTransferable.get() &&
aOwner == mSelectionOwner.get())) {
return NS_OK;
}
+ nsresult rv = mPrivacyHandler.PrepareDataForClipboard(aTransferable);
+ NS_ENSURE_SUCCESS(rv, rv);
+
// Clear out the clipboard in order to set the new data
EmptyClipboard(aWhichClipboard);
if (aWhichClipboard == kSelectionClipboard) {
mSelectionOwner = aOwner;
mSelectionTransferable = aTransferable;
}
else {
@@ -182,17 +185,16 @@ nsClipboard::SetData(nsITransferable *aT
// Make ourselves the owner. If we fail to, return.
if (!gtk_selection_owner_set(mWidget, selectionAtom, GDK_CURRENT_TIME))
return NS_ERROR_FAILURE;
// Clear the old selection target list.
gtk_selection_clear_targets(mWidget, selectionAtom);
// Get the types of supported flavors
- nsresult rv;
nsCOMPtr<nsISupportsArray> flavors;
rv = aTransferable->FlavorsTransferableCanExport(getter_AddRefs(flavors));
if (!flavors || NS_FAILED(rv))
return NS_ERROR_FAILURE;
// Add all the flavors to this widget's supported type.
PRUint32 count;
--- a/widget/src/gtk2/nsClipboard.h
+++ b/widget/src/gtk2/nsClipboard.h
@@ -35,16 +35,17 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __nsClipboard_h_
#define __nsClipboard_h_
#include "nsIClipboard.h"
+#include "nsClipboardPrivacyHandler.h"
#include <gtk/gtk.h>
class nsClipboard : public nsIClipboard
{
public:
nsClipboard();
virtual ~nsClipboard();
@@ -79,12 +80,13 @@ private:
// The hidden widget where we do all of our operations
GtkWidget *mWidget;
// Hang on to our owners and transferables so we can transfer data
// when asked.
nsCOMPtr<nsIClipboardOwner> mSelectionOwner;
nsCOMPtr<nsIClipboardOwner> mGlobalOwner;
nsCOMPtr<nsITransferable> mSelectionTransferable;
nsCOMPtr<nsITransferable> mGlobalTransferable;
+ nsClipboardPrivacyHandler mPrivacyHandler;
};
#endif /* __nsClipboard_h_ */
--- a/widget/src/photon/nsClipboard.cpp
+++ b/widget/src/photon/nsClipboard.cpp
@@ -125,16 +125,19 @@ NS_IMETHODIMP nsClipboard::SetData(nsITr
if ((aTransferable == mGlobalTransferable.get() && anOwner == mGlobalOwner.get() &&
aWhichClipboard == kGlobalClipboard ) || (aTransferable == mSelectionTransferable.get() &&
anOwner == mSelectionOwner.get() && aWhichClipboard == kSelectionClipboard))
{
return NS_OK;
}
+ nsresult rv = mPrivacyHandler.PrepareDataForClipboard(aTransferable);
+ NS_ENSURE_SUCCESS(rv, rv);
+
EmptyClipboard(aWhichClipboard);
switch (aWhichClipboard)
{
case kSelectionClipboard:
mSelectionOwner = anOwner;
mSelectionTransferable = aTransferable;
break;
--- a/widget/src/photon/nsClipboard.h
+++ b/widget/src/photon/nsClipboard.h
@@ -41,16 +41,17 @@
#ifndef nsClipboard_h__
#define nsClipboard_h__
#include <Pt.h>
#include "nsIClipboard.h"
#include "nsITransferable.h"
#include "nsIClipboardOwner.h"
+#include "nsClipboardPrivacyHandler.h"
#include <nsCOMPtr.h>
class nsITransferable;
class nsIClipboardOwner;
class nsIWidget;
/**
* Native Clipboard wrapper
@@ -86,16 +87,17 @@ nsresult GetFormat(const char* aMimeStr,
inline nsITransferable *GetTransferable(PRInt32 aWhichClipboard);
private:
unsigned long GetFlavourTimestamp( char *type );
nsCOMPtr<nsIClipboardOwner> mSelectionOwner;
nsCOMPtr<nsIClipboardOwner> mGlobalOwner;
nsCOMPtr<nsITransferable> mSelectionTransferable;
nsCOMPtr<nsITransferable> mGlobalTransferable;
+ nsClipboardPrivacyHandler mPrivacyHandler;
// Used for communicating pasted data
// from the asynchronous X routines back to a blocking paste:
PRBool mBlocking;
// Used for keeping track of the current input group
PRInt32 mInputGroup;
};
--- a/widget/src/qt/nsClipboard.cpp
+++ b/widget/src/qt/nsClipboard.cpp
@@ -303,16 +303,19 @@ nsClipboard::SetData(nsITransferable *aT
&& aTransferable == mSelectionTransferable.get()
&& aOwner == mSelectionOwner.get()
)
)
{
return NS_OK;
}
+ nsresult rv = mPrivacyHandler.PrepareDataForClipboard(aTransferable);
+ NS_ENSURE_SUCCESS(rv, rv);
+
EmptyClipboard(aWhichClipboard);
QClipboard::Mode mode;
if (kGlobalClipboard == aWhichClipboard)
{
mGlobalOwner = aOwner;
mGlobalTransferable = aTransferable;
--- a/widget/src/qt/nsClipboard.h
+++ b/widget/src/qt/nsClipboard.h
@@ -36,16 +36,17 @@
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsClipboard_h__
#define nsClipboard_h__
#include "nsIClipboard.h"
#include "nsITransferable.h"
#include "nsIClipboardOwner.h"
+#include "nsClipboardPrivacyHandler.h"
#include "nsCOMPtr.h"
#include <qclipboard.h>
/* Native Qt Clipboard wrapper */
class nsClipboard : public nsIClipboard
{
public:
@@ -63,11 +64,12 @@ protected:
QClipboard::Mode cbMode);
NS_IMETHOD GetNativeClipboardData(nsITransferable *aTransferable,
QClipboard::Mode cbMode);
nsCOMPtr<nsIClipboardOwner> mSelectionOwner;
nsCOMPtr<nsIClipboardOwner> mGlobalOwner;
nsCOMPtr<nsITransferable> mSelectionTransferable;
nsCOMPtr<nsITransferable> mGlobalTransferable;
+ nsClipboardPrivacyHandler mPrivacyHandler;
};
#endif // nsClipboard_h__
--- a/widget/src/xpwidgets/Makefile.in
+++ b/widget/src/xpwidgets/Makefile.in
@@ -76,16 +76,17 @@ CPPSRCS = \
nsPrimitiveHelpers.cpp \
nsXPLookAndFeel.cpp \
nsClipboardHelper.cpp \
nsPrintOptionsImpl.cpp \
nsPrintSettingsImpl.cpp \
nsPrintSession.cpp \
nsWidgetAtoms.cpp \
nsIdleService.cpp \
+ nsClipboardPrivacyHandler.cpp \
$(NULL)
ifneq (,$(filter beos os2 cocoa windows,$(MOZ_WIDGET_TOOLKIT)))
CPPSRCS += nsBaseClipboard.cpp
endif
ifneq (,$(filter beos qt gtk2 os2 cocoa photon windows,$(MOZ_WIDGET_TOOLKIT)))
CPPSRCS += nsBaseFilePicker.cpp
--- a/widget/src/xpwidgets/nsBaseClipboard.cpp
+++ b/widget/src/xpwidgets/nsBaseClipboard.cpp
@@ -81,16 +81,18 @@ NS_IMETHODIMP nsBaseClipboard::SetData(n
NS_ADDREF(mClipboardOwner);
mTransferable = aTransferable;
nsresult rv = NS_ERROR_FAILURE;
if ( mTransferable ) {
NS_ADDREF(mTransferable);
+ rv = mPrivacyHandler.PrepareDataForClipboard(mTransferable);
+ NS_ENSURE_SUCCESS(rv, rv);
rv = SetNativeClipboardData(aWhichClipboard);
}
return rv;
}
/**
* Gets the transferable object
--- a/widget/src/xpwidgets/nsBaseClipboard.h
+++ b/widget/src/xpwidgets/nsBaseClipboard.h
@@ -35,16 +35,17 @@
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsBaseClipboard_h__
#define nsBaseClipboard_h__
#include "nsIClipboard.h"
#include "nsITransferable.h"
+#include "nsClipboardPrivacyHandler.h"
class nsITransferable;
class nsDataObj;
class nsIClipboardOwner;
class nsIWidget;
/**
* Native Win32 BaseClipboard wrapper
@@ -66,13 +67,14 @@ public:
protected:
NS_IMETHOD SetNativeClipboardData ( PRInt32 aWhichClipboard ) = 0;
NS_IMETHOD GetNativeClipboardData ( nsITransferable * aTransferable, PRInt32 aWhichClipboard ) = 0;
PRBool mIgnoreEmptyNotification;
nsIClipboardOwner * mClipboardOwner;
nsITransferable * mTransferable;
+ nsClipboardPrivacyHandler mPrivacyHandler;
};
#endif // nsBaseClipboard_h__
new file mode 100644
--- /dev/null
+++ b/widget/src/xpwidgets/nsClipboardPrivacyHandler.cpp
@@ -0,0 +1,128 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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
+ * 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 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 ***** */
+
+#include "nsClipboardPrivacyHandler.h"
+#include "nsITransferable.h"
+#include "nsISupportsPrimitives.h"
+#include "nsIObserverService.h"
+#include "nsIClipboard.h"
+#include "nsComponentManagerUtils.h"
+#include "nsServiceManagerUtils.h"
+#include "nsLiteralString.h"
+#include "nsNetCID.h"
+#include "nsXPCOM.h"
+
+#define NS_MOZ_DATA_FROM_PRIVATEBROWSING "application/x-moz-private-browsing"
+
+NS_IMPL_ISUPPORTS2(nsClipboardPrivacyHandler, nsIObserver, nsISupportsWeakReference)
+
+nsClipboardPrivacyHandler::nsClipboardPrivacyHandler()
+{
+ NS_ADDREF(this);
+ nsCOMPtr<nsIObserverService> observerService =
+ do_GetService("@mozilla.org/observer-service;1");
+ if (observerService)
+ observerService->AddObserver(this, NS_PRIVATE_BROWSING_SWITCH_TOPIC, PR_TRUE);
+}
+
+/**
+ * Prepare the transferable object to be inserted into the clipboard
+ *
+ */
+nsresult
+nsClipboardPrivacyHandler::PrepareDataForClipboard(nsITransferable * aTransferable)
+{
+ NS_ASSERTION(aTransferable, "clipboard given a null transferable");
+
+ nsresult rv = NS_OK;
+ if (InPrivateBrowsing()) {
+ nsCOMPtr<nsISupportsPRBool> data = do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
+ if (data) {
+ rv = data->SetData(PR_TRUE);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = aTransferable->AddDataFlavor(NS_MOZ_DATA_FROM_PRIVATEBROWSING);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = aTransferable->SetTransferData(NS_MOZ_DATA_FROM_PRIVATEBROWSING, data, sizeof(PRBool));
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ }
+
+ return rv;
+}
+
+NS_IMETHODIMP
+nsClipboardPrivacyHandler::Observe(nsISupports *aSubject, char const *aTopic, PRUnichar const *aData)
+{
+ if (NS_LITERAL_STRING(NS_PRIVATE_BROWSING_LEAVE).Equals(aData)) {
+ nsresult rv;
+ nsCOMPtr<nsIClipboard> clipboard =
+ do_GetService("@mozilla.org/widget/clipboard;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ const char * flavors[] = { NS_MOZ_DATA_FROM_PRIVATEBROWSING };
+ PRBool haveFlavors;
+ rv = clipboard->HasDataMatchingFlavors(flavors,
+ NS_ARRAY_LENGTH(flavors),
+ nsIClipboard::kGlobalClipboard,
+ &haveFlavors);
+ if (NS_SUCCEEDED(rv) && haveFlavors) {
+ // Empty the native clipboard by copying an empty transferable
+ nsCOMPtr<nsITransferable> nullData =
+ do_CreateInstance("@mozilla.org/widget/transferable;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = clipboard->SetData(nullData, nsnull,
+ nsIClipboard::kGlobalClipboard);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ }
+
+ return NS_OK;
+}
+
+PRBool
+nsClipboardPrivacyHandler::InPrivateBrowsing()
+{
+ PRBool inPrivateBrowsingMode = PR_FALSE;
+ if (!mPBService)
+ mPBService = do_GetService(NS_PRIVATE_BROWSING_SERVICE_CONTRACTID);
+ if (mPBService)
+ mPBService->GetPrivateBrowsingEnabled(&inPrivateBrowsingMode);
+ return inPrivateBrowsingMode;
+}
new file mode 100644
--- /dev/null
+++ b/widget/src/xpwidgets/nsClipboardPrivacyHandler.h
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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
+ * 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 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 ***** */
+
+#ifndef nsClipboardPrivacyHandler_h__
+#define nsClipboardPrivacyHandler_h__
+
+#include "nsIObserver.h"
+#include "nsIPrivateBrowsingService.h"
+#include "nsWeakReference.h"
+#include "nsCOMPtr.h"
+
+class nsITransferable;
+
+// nsClipboardPrivacyHandler makes sure that clipboard data copied during
+// the private browsing mode does not leak after exiting this mode.
+// In order to ensure this, callers should store an object of this class
+// for their lifetime, and call PrepareDataForClipboard in their
+// nsIClipboard::SetData implementation before starting to use the
+// nsITransferable object in any way.
+
+class nsClipboardPrivacyHandler : public nsIObserver,
+ public nsSupportsWeakReference
+{
+
+public:
+ nsClipboardPrivacyHandler();
+
+ // nsISupports
+ NS_DECL_ISUPPORTS
+
+ // nsIObserver
+ NS_DECL_NSIOBSERVER
+
+ nsresult PrepareDataForClipboard(nsITransferable * aTransferable);
+
+private:
+
+ PRBool InPrivateBrowsing();
+
+ nsCOMPtr<nsIPrivateBrowsingService> mPBService;
+
+};
+
+#endif // nsClipboardPrivacyHandler_h__
+
--- a/widget/tests/Makefile.in
+++ b/widget/tests/Makefile.in
@@ -41,16 +41,17 @@ srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = widget/test
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TEST_FILES = test_bug343416.xul \
test_bug444800.xul \
+ test_bug462106.xul \
test_keycodes.xul \
$(NULL)
ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
_TEST_FILES += native_menus_window.xul \
test_native_menus.xul \
test_bug428405.xul \
test_bug466599.xul \
new file mode 100644
--- /dev/null
+++ b/widget/tests/test_bug462106.xul
@@ -0,0 +1,94 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=462106
+-->
+<window title="Mozilla Bug 462106"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="initAndRunTests()">
+ <script type="application/javascript"
+ src="chrome://mochikit/content/MochiKit/packed.js"/>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test"></pre>
+ </body>
+
+ <!-- test code goes here -->
+ <script class="testbody" type="application/javascript">
+ <![CDATA[
+
+ /** Test for Bug 462106 **/
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+function copy(str) {
+ Cc["@mozilla.org/widget/clipboardhelper;1"].
+ getService(Ci.nsIClipboardHelper).
+ copyString(str);
+}
+
+function paste() {
+ let trans = Cc["@mozilla.org/widget/transferable;1"].
+ createInstance(Ci.nsITransferable);
+ trans.addDataFlavor("text/unicode");
+ let clip = Cc["@mozilla.org/widget/clipboard;1"].
+ getService(Ci.nsIClipboard);
+ clip.getData(trans, Ci.nsIClipboard.kGlobalClipboard);
+ let str = {}, length = {};
+ try {
+ trans.getTransferData("text/unicode", str, length);
+ } catch (e) {
+ str = null;
+ }
+ if (str) {
+ str = str.value.QueryInterface(Ci.nsISupportsString);
+ if (str)
+ str = str.data.substring(0, length.value / 2);
+ }
+ return str;
+}
+
+function initAndRunTests() {
+ let pb;
+ try {
+ pb = Cc["@mozilla.org/privatebrowsing;1"].
+ getService(Ci.nsIPrivateBrowsingService);
+ } catch (e) {
+ return;
+ }
+
+ let prefBranch = Cc["@mozilla.org/preferences-service;1"].
+ getService(Ci.nsIPrefBranch);
+ prefBranch.setBoolPref("browser.privatebrowsing.keep_current_session", true);
+
+ const data = "random number: " + Math.random();
+ copy(data);
+ is(data, paste(), "Data successfully copied before entering the private browsing mode");
+ pb.privateBrowsingEnabled = true;
+ pb.privateBrowsingEnabled = false;
+ // the data should still be on the clipboard because it was copied before
+ // entering the private browsing mode
+ is(data, paste(), "Copied data persisted after leaving the private browsing mode");
+
+ const data2 = "another random number: " + Math.random();
+ pb.privateBrowsingEnabled = true;
+ copy(data2); // copy the data inside the private browsing mode
+ // the data should be on the clipboard inside the private browsing mode
+ is(data2, paste(), "Data successfully copied inside the private browsing mode");
+ pb.privateBrowsingEnabled = false;
+ // the data should no longer be on the clipboard at this stage
+ isnot(data2, paste(), "Data no longer available after leaving the private browsing mode");
+
+ prefBranch.clearUserPref("browser.privatebrowsing.keep_current_session");
+}
+
+ ]]>
+ </script>
+</window>