From c4c18521be4adc019987f6a780bdb774a610bf38 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Tue, 4 Sep 2012 20:37:45 -0400 Subject: [PATCH] Bug 741059 - Part 1: Add APIs to nsIChannel to allow callers to override the private bit on the channel; r=jduell This is probably the worst patch that I have ever written! We add a setPrivate method to nsIPrivateBrowsingChannel which will be implemented by channels who care about private browsing. This allows the client to explicitly override the private bit on the channel. NS_UsePrivateBrowsing is also taught about this override bit using the internal nsIPrivateBrowsingChannel::IsPrivateModeOverriden API. This patch implements the new API for HTTP, FTP and wyciwyg channels. This also modifies the IPC implementations of these channels to correctly transfer that bit to the parent process if it has been set in the child process channel. --- docshell/base/SerializedLoadContext.cpp | 16 ++++ docshell/base/SerializedLoadContext.h | 10 ++- netwerk/base/public/Makefile.in | 1 + .../base/public/nsIPrivateBrowsingChannel.idl | 49 +++++++++++ netwerk/base/public/nsNetUtil.h | 9 ++ netwerk/base/src/PrivateBrowsingChannel.h | 83 +++++++++++++++++++ netwerk/protocol/ftp/FTPChannelChild.cpp | 25 +++++- netwerk/protocol/ftp/FTPChannelChild.h | 6 ++ netwerk/protocol/ftp/FTPChannelParent.cpp | 5 ++ netwerk/protocol/ftp/nsFTPChannel.cpp | 25 +++++- netwerk/protocol/ftp/nsFTPChannel.h | 11 ++- netwerk/protocol/http/HttpBaseChannel.cpp | 15 +++- netwerk/protocol/http/HttpBaseChannel.h | 5 +- netwerk/protocol/http/HttpChannelParent.cpp | 4 + .../websocket/WebSocketChannelParent.cpp | 5 ++ .../protocol/wyciwyg/WyciwygChannelChild.cpp | 13 ++- .../protocol/wyciwyg/WyciwygChannelChild.h | 4 + .../protocol/wyciwyg/WyciwygChannelParent.cpp | 5 ++ netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp | 18 ++-- netwerk/protocol/wyciwyg/nsWyciwygChannel.h | 7 +- netwerk/test/unit/head_cache.js | 22 +++++ netwerk/test/unit/test_bug248970_cache.js | 22 ----- netwerk/test/unit/test_private_channel.js | 50 +++++++++++ netwerk/test/unit/xpcshell.ini | 1 + 24 files changed, 368 insertions(+), 43 deletions(-) create mode 100644 netwerk/base/public/nsIPrivateBrowsingChannel.idl create mode 100644 netwerk/base/src/PrivateBrowsingChannel.h create mode 100644 netwerk/test/unit/test_private_channel.js diff --git a/docshell/base/SerializedLoadContext.cpp b/docshell/base/SerializedLoadContext.cpp index ec52b561935..b7f067c4c50 100644 --- a/docshell/base/SerializedLoadContext.cpp +++ b/docshell/base/SerializedLoadContext.cpp @@ -21,6 +21,20 @@ SerializedLoadContext::SerializedLoadContext(nsIChannel* aChannel) nsCOMPtr loadContext; NS_QueryNotificationCallbacks(aChannel, loadContext); Init(loadContext); + + if (!loadContext) { + // Attempt to retrieve the private bit from the channel if it has been + // overriden. + bool isPrivate = false; + bool isOverriden = false; + nsCOMPtr pbChannel = do_QueryInterface(aChannel); + if (pbChannel && + NS_SUCCEEDED(pbChannel->IsPrivateModeOverriden(&isPrivate, &isOverriden)) && + isOverriden) { + mUsePrivateBrowsing = isPrivate; + mIsPrivateBitValid = true; + } + } } SerializedLoadContext::SerializedLoadContext(nsIWebSocketChannel* aChannel) @@ -35,12 +49,14 @@ SerializedLoadContext::Init(nsILoadContext* aLoadContext) { if (aLoadContext) { mIsNotNull = true; + mIsPrivateBitValid = true; aLoadContext->GetIsContent(&mIsContent); aLoadContext->GetUsePrivateBrowsing(&mUsePrivateBrowsing); aLoadContext->GetAppId(&mAppId); aLoadContext->GetIsInBrowserElement(&mIsInBrowserElement); } else { mIsNotNull = false; + mIsPrivateBitValid = false; // none of below values really matter when mIsNotNull == false: // we won't be GetInterfaced to nsILoadContext mIsContent = true; diff --git a/docshell/base/SerializedLoadContext.h b/docshell/base/SerializedLoadContext.h index c2331ef244c..555d9eeccc8 100644 --- a/docshell/base/SerializedLoadContext.h +++ b/docshell/base/SerializedLoadContext.h @@ -36,13 +36,21 @@ public: void Init(nsILoadContext* aLoadContext); - bool IsNotNull() const + bool IsNotNull() const { return mIsNotNull; } + bool IsPrivateBitValid() const + { + return mIsPrivateBitValid; + } + // used to indicate if child-side LoadContext * was null. bool mIsNotNull; + // used to indicate if child-side mUsePrivateBrowsing flag is valid, even if + // mIsNotNull is false, i.e., child LoadContext was null. + bool mIsPrivateBitValid; bool mIsContent; bool mUsePrivateBrowsing; bool mIsInBrowserElement; diff --git a/netwerk/base/public/Makefile.in b/netwerk/base/public/Makefile.in index 93ce67c4759..013e8c942d9 100644 --- a/netwerk/base/public/Makefile.in +++ b/netwerk/base/public/Makefile.in @@ -58,6 +58,7 @@ XPIDLSRCS = \ nsINetworkLinkService.idl \ nsIPermission.idl \ nsIPermissionManager.idl \ + nsIPrivateBrowsingChannel.idl \ nsIPrivateBrowsingService.idl \ nsIProgressEventSink.idl \ nsIPrompt.idl \ diff --git a/netwerk/base/public/nsIPrivateBrowsingChannel.idl b/netwerk/base/public/nsIPrivateBrowsingChannel.idl new file mode 100644 index 00000000000..6d9afbd01af --- /dev/null +++ b/netwerk/base/public/nsIPrivateBrowsingChannel.idl @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +/** + * This interface is implemented by channels which support overriding the + * privacy state of the channel. + * + * This interface must be used only from the XPCOM main thread. + */ +[scriptable, uuid(424b7efc-5d56-4717-9a71-8db9dcaaa618)] +interface nsIPrivateBrowsingChannel : nsISupports +{ + /** + * Determine whether the channel is tied to a private browsing window. + * + * This value can be set only before the channel is opened. Setting it + * after that does not have any effect. This value overrides the privacy + * state of the channel, which means that if you call this method, then + * the loadGroup and load context will no longer be consulted when we + * need to know the private mode status for a channel. + * + * Note that this value is only meant to be used when the channel's privacy + * status cannot be obtained from the loadGroup or load context (for + * example, when the channel is not associated with any loadGroup or load + * context.) Setting this value directly should be avoided if possible. + * + * Implementations must enforce the ordering semantics of this function by + * raising errors if setPrivate is called on a channel which has a loadGroup + * and/or callbacks that implement nsILoadContext, or if the loadGroup + * or notificationCallbacks are set after setPrivate has been called. + * + * @param aPrivate whether the channel should be opened in private mode. + */ + void setPrivate(in boolean aPrivate); + + /* + * This function is used to determine whether the channel's private mode + * has been overridden by a call to setPrivate. It is intended to be used + * by NS_UsePrivateBrowsing(), and you should not call it directly. + * + * @param aValue the overridden value. This will only be set if the function + * returns true. + */ + [noscript] boolean isPrivateModeOverriden(out boolean aValue); +}; diff --git a/netwerk/base/public/nsNetUtil.h b/netwerk/base/public/nsNetUtil.h index bf665cb31a4..aad4280c71d 100644 --- a/netwerk/base/public/nsNetUtil.h +++ b/netwerk/base/public/nsNetUtil.h @@ -76,6 +76,7 @@ #include "nsIMIMEHeaderParam.h" #include "nsILoadContext.h" #include "mozilla/Services.h" +#include "nsIPrivateBrowsingChannel.h" #ifdef MOZILLA_INTERNAL_API @@ -1325,6 +1326,14 @@ NS_QueryNotificationCallbacks(nsIInterfaceRequestor *callbacks, inline bool NS_UsePrivateBrowsing(nsIChannel *channel) { + bool isPrivate = false; + bool isOverriden = false; + nsCOMPtr pbChannel = do_QueryInterface(channel); + if (pbChannel && + NS_SUCCEEDED(pbChannel->IsPrivateModeOverriden(&isPrivate, &isOverriden)) && + isOverriden) { + return isPrivate; + } nsCOMPtr loadContext; NS_QueryNotificationCallbacks(channel, loadContext); return loadContext && loadContext->UsePrivateBrowsing(); diff --git a/netwerk/base/src/PrivateBrowsingChannel.h b/netwerk/base/src/PrivateBrowsingChannel.h new file mode 100644 index 00000000000..451915c4cc1 --- /dev/null +++ b/netwerk/base/src/PrivateBrowsingChannel.h @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim:set ts=4 sts=4 sw=4 et cin: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_net_PrivateBrowsingChannel_h__ +#define mozilla_net_PrivateBrowsingChannel_h__ + +#include "nsIPrivateBrowsingChannel.h" +#include "nsCOMPtr.h" +#include "nsILoadGroup.h" +#include "nsILoadContext.h" + +namespace mozilla { +namespace net { + +template +class PrivateBrowsingChannel : public nsIPrivateBrowsingChannel +{ +public: + PrivateBrowsingChannel() : + mPrivateBrowsingOverriden(false), + mPrivateBrowsing(false) + { + } + + NS_IMETHOD SetPrivate(bool aPrivate) + { + // Make sure that we don't have a load group or a load context + // This is a fatal error in debug builds, and a runtime error in release + // builds. + nsILoadGroup* loadGroup = static_cast(this)->mLoadGroup; + nsCOMPtr loadContext; + if (!loadGroup) { + NS_QueryNotificationCallbacks(static_cast(this), loadContext); + } + MOZ_ASSERT(!loadGroup && !loadContext); + if (loadGroup || loadContext) { + return NS_ERROR_FAILURE; + } + + mPrivateBrowsingOverriden = true; + mPrivateBrowsing = aPrivate; + return NS_OK; + } + + NS_IMETHOD IsPrivateModeOverriden(bool* aValue, bool *aResult) + { + NS_ENSURE_ARG_POINTER(aValue); + NS_ENSURE_ARG_POINTER(aResult); + *aResult = mPrivateBrowsingOverriden; + if (mPrivateBrowsingOverriden) { + *aValue = mPrivateBrowsing; + } + return NS_OK; + } + + bool CanSetCallbacks() const + { + // Make sure that the private bit override flag is not set. + // This is a fatal error in debug builds, and a runtime error in release + // builds. + MOZ_ASSERT(!mPrivateBrowsingOverriden); + return !mPrivateBrowsingOverriden; + } + + bool CanSetLoadGroup() const + { + // We can set a load group whenever we can set a callback + return CanSetCallbacks(); + } + +protected: + bool mPrivateBrowsingOverriden; + bool mPrivateBrowsing; +}; + +} +} + +#endif + diff --git a/netwerk/protocol/ftp/FTPChannelChild.cpp b/netwerk/protocol/ftp/FTPChannelChild.cpp index d57bd9577e9..ae937356846 100644 --- a/netwerk/protocol/ftp/FTPChannelChild.cpp +++ b/netwerk/protocol/ftp/FTPChannelChild.cpp @@ -69,13 +69,14 @@ FTPChannelChild::ReleaseIPDLReference() // FTPChannelChild::nsISupports //----------------------------------------------------------------------------- -NS_IMPL_ISUPPORTS_INHERITED5(FTPChannelChild, +NS_IMPL_ISUPPORTS_INHERITED6(FTPChannelChild, nsBaseChannel, nsIFTPChannel, nsIUploadChannel, nsIResumableChannel, nsIProxiedChannel, - nsIChildChannel) + nsIChildChannel, + nsIPrivateBrowsingChannel) //----------------------------------------------------------------------------- @@ -546,6 +547,26 @@ FTPChannelChild::CompleteRedirectSetup(nsIStreamListener *listener, return NS_OK; } +NS_IMETHODIMP +FTPChannelChild::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks) +{ + if (!CanSetCallbacks()) { + return NS_ERROR_FAILURE; + } + + return nsBaseChannel::SetNotificationCallbacks(aCallbacks); +} + +NS_IMETHODIMP +FTPChannelChild::SetLoadGroup(nsILoadGroup * aLoadGroup) +{ + if (!CanSetLoadGroup()) { + return NS_ERROR_FAILURE; + } + + return nsBaseChannel::SetLoadGroup(aLoadGroup); +} + } // namespace net } // namespace mozilla diff --git a/netwerk/protocol/ftp/FTPChannelChild.h b/netwerk/protocol/ftp/FTPChannelChild.h index 65f01f4b88a..d02af96e6a2 100644 --- a/netwerk/protocol/ftp/FTPChannelChild.h +++ b/netwerk/protocol/ftp/FTPChannelChild.h @@ -18,6 +18,7 @@ #include "nsIChildChannel.h" #include "nsIStreamListener.h" +#include "PrivateBrowsingChannel.h" namespace mozilla { namespace net { @@ -34,6 +35,7 @@ class FTPChannelChild : public PFTPChannelChild , public nsIResumableChannel , public nsIProxiedChannel , public nsIChildChannel + , public mozilla::net::PrivateBrowsingChannel { public: typedef ::nsIStreamListener nsIStreamListener; @@ -92,11 +94,15 @@ protected: void DoFailedAsyncOpen(const nsresult& statusCode); void DoDeleteSelf(); + NS_IMETHOD SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks); + NS_IMETHOD SetLoadGroup(nsILoadGroup* aLoadGroup); + friend class FTPStartRequestEvent; friend class FTPDataAvailableEvent; friend class FTPStopRequestEvent; friend class FTPFailedAsyncOpenEvent; friend class FTPDeleteSelfEvent; + friend class mozilla::net::PrivateBrowsingChannel; private: // Called asynchronously from Resume: continues any pending calls into client. diff --git a/netwerk/protocol/ftp/FTPChannelParent.cpp b/netwerk/protocol/ftp/FTPChannelParent.cpp index 45cea07875c..c60bb75ab34 100644 --- a/netwerk/protocol/ftp/FTPChannelParent.cpp +++ b/netwerk/protocol/ftp/FTPChannelParent.cpp @@ -102,6 +102,11 @@ FTPChannelParent::RecvAsyncOpen(const URIParams& aURI, if (loadContext.IsNotNull()) mLoadContext = new LoadContext(loadContext); + else if (loadContext.IsPrivateBitValid()) { + nsCOMPtr pbChannel = do_QueryInterface(chan); + if (pbChannel) + pbChannel->SetPrivate(loadContext.mUsePrivateBrowsing); + } rv = mChannel->AsyncOpen(this, nullptr); if (NS_FAILED(rv)) diff --git a/netwerk/protocol/ftp/nsFTPChannel.cpp b/netwerk/protocol/ftp/nsFTPChannel.cpp index 82bf787fdaa..1496657bd1a 100644 --- a/netwerk/protocol/ftp/nsFTPChannel.cpp +++ b/netwerk/protocol/ftp/nsFTPChannel.cpp @@ -45,12 +45,13 @@ PRTimeToSeconds(PRTime t_usec) //----------------------------------------------------------------------------- -NS_IMPL_ISUPPORTS_INHERITED4(nsFtpChannel, +NS_IMPL_ISUPPORTS_INHERITED5(nsFtpChannel, nsBaseChannel, nsIUploadChannel, nsIResumableChannel, nsIFTPChannel, - nsIProxiedChannel) + nsIProxiedChannel, + nsIPrivateBrowsingChannel) //----------------------------------------------------------------------------- @@ -217,3 +218,23 @@ nsFtpChannel::GetFTPEventSink(nsCOMPtr &aResult) } aResult = mFTPEventSink; } + +NS_IMETHODIMP +nsFtpChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks) +{ + if (!CanSetCallbacks()) { + return NS_ERROR_FAILURE; + } + + return nsBaseChannel::SetNotificationCallbacks(aCallbacks); +} + +NS_IMETHODIMP +nsFtpChannel::SetLoadGroup(nsILoadGroup * aLoadGroup) +{ + if (!CanSetLoadGroup()) { + return NS_ERROR_FAILURE; + } + + return nsBaseChannel::SetLoadGroup(aLoadGroup); +} diff --git a/netwerk/protocol/ftp/nsFTPChannel.h b/netwerk/protocol/ftp/nsFTPChannel.h index aa512eb9797..bc93871388e 100644 --- a/netwerk/protocol/ftp/nsFTPChannel.h +++ b/netwerk/protocol/ftp/nsFTPChannel.h @@ -29,19 +29,21 @@ #include "nsHashPropertyBag.h" #include "nsFtpProtocolHandler.h" #include "nsNetUtil.h" +#include "PrivateBrowsingChannel.h" class nsFtpChannel : public nsBaseChannel, public nsIFTPChannel, public nsIUploadChannel, public nsIResumableChannel, - public nsIProxiedChannel + public nsIProxiedChannel, + public mozilla::net::PrivateBrowsingChannel { public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSIUPLOADCHANNEL NS_DECL_NSIRESUMABLECHANNEL NS_DECL_NSIPROXIEDCHANNEL - + nsFtpChannel(nsIURI *uri, nsIProxyInfo *pi) : mProxyInfo(pi) , mStartPos(0) @@ -94,6 +96,11 @@ protected: virtual bool GetStatusArg(nsresult status, nsString &statusArg); virtual void OnCallbacksChanged(); + NS_IMETHOD SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks); + NS_IMETHOD SetLoadGroup(nsILoadGroup* aLoadGroup); + + friend class mozilla::net::PrivateBrowsingChannel; + private: nsCOMPtr mProxyInfo; nsCOMPtr mFTPEventSink; diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp index c28ebc862e6..15622e5d306 100644 --- a/netwerk/protocol/http/HttpBaseChannel.cpp +++ b/netwerk/protocol/http/HttpBaseChannel.cpp @@ -48,7 +48,6 @@ HttpBaseChannel::HttpBaseChannel() , mTracingEnabled(true) , mTimingEnabled(false) , mAllowSpdy(true) - , mPrivateBrowsing(false) , mSuspendCount(0) { LOG(("Creating HttpBaseChannel @%x\n", this)); @@ -138,7 +137,7 @@ HttpBaseChannel::Init(nsIURI *aURI, // HttpBaseChannel::nsISupports //----------------------------------------------------------------------------- -NS_IMPL_ISUPPORTS_INHERITED9( HttpBaseChannel, +NS_IMPL_ISUPPORTS_INHERITED10(HttpBaseChannel, nsHashPropertyBag, nsIRequest, nsIChannel, @@ -148,7 +147,8 @@ NS_IMPL_ISUPPORTS_INHERITED9( HttpBaseChannel, nsIUploadChannel, nsIUploadChannel2, nsISupportsPriority, - nsITraceableChannel) + nsITraceableChannel, + nsIPrivateBrowsingChannel) //----------------------------------------------------------------------------- // HttpBaseChannel::nsIRequest @@ -189,6 +189,10 @@ HttpBaseChannel::GetLoadGroup(nsILoadGroup **aLoadGroup) NS_IMETHODIMP HttpBaseChannel::SetLoadGroup(nsILoadGroup *aLoadGroup) { + if (!CanSetLoadGroup()) { + return NS_ERROR_FAILURE; + } + mLoadGroup = aLoadGroup; mProgressSink = nullptr; mPrivateBrowsing = NS_UsePrivateBrowsing(this); @@ -269,10 +273,13 @@ HttpBaseChannel::GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks) NS_IMETHODIMP HttpBaseChannel::SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks) { + if (!CanSetCallbacks()) { + return NS_ERROR_FAILURE; + } + mCallbacks = aCallbacks; mProgressSink = nullptr; - // Will never change unless SetNotificationCallbacks called again, so cache mPrivateBrowsing = NS_UsePrivateBrowsing(this); return NS_OK; } diff --git a/netwerk/protocol/http/HttpBaseChannel.h b/netwerk/protocol/http/HttpBaseChannel.h index 971958c122e..a1fa503bad0 100644 --- a/netwerk/protocol/http/HttpBaseChannel.h +++ b/netwerk/protocol/http/HttpBaseChannel.h @@ -30,6 +30,7 @@ #include "nsILoadContext.h" #include "mozilla/net/NeckoCommon.h" #include "nsThreadUtils.h" +#include "PrivateBrowsingChannel.h" namespace mozilla { namespace net { @@ -50,6 +51,7 @@ class HttpBaseChannel : public nsHashPropertyBag , public nsISupportsPriority , public nsIResumableChannel , public nsITraceableChannel + , public PrivateBrowsingChannel { public: NS_DECL_ISUPPORTS_INHERITED @@ -208,6 +210,8 @@ protected: getter_AddRefs(aResult)); } + friend class PrivateBrowsingChannel; + nsCOMPtr mURI; nsCOMPtr mOriginalURI; nsCOMPtr mDocumentURI; @@ -263,7 +267,6 @@ protected: // True if timing collection is enabled uint32_t mTimingEnabled : 1; uint32_t mAllowSpdy : 1; - uint32_t mPrivateBrowsing : 1; // Current suspension depth for this channel object uint32_t mSuspendCount; diff --git a/netwerk/protocol/http/HttpChannelParent.cpp b/netwerk/protocol/http/HttpChannelParent.cpp index 211353074b8..3bbec203f53 100644 --- a/netwerk/protocol/http/HttpChannelParent.cpp +++ b/netwerk/protocol/http/HttpChannelParent.cpp @@ -152,6 +152,10 @@ HttpChannelParent::RecvAsyncOpen(const URIParams& aURI, mLoadContext = new LoadContext(loadContext, mTabParent->GetOwnerElement()); else mLoadContext = new LoadContext(loadContext); + } else if (loadContext.IsPrivateBitValid()) { + nsCOMPtr pbChannel = do_QueryInterface(mChannel); + if (pbChannel) + pbChannel->SetPrivate(loadContext.mUsePrivateBrowsing); } nsHttpChannel *httpChan = static_cast(mChannel.get()); diff --git a/netwerk/protocol/websocket/WebSocketChannelParent.cpp b/netwerk/protocol/websocket/WebSocketChannelParent.cpp index ce1e6c76ef6..8a659c7e5c3 100644 --- a/netwerk/protocol/websocket/WebSocketChannelParent.cpp +++ b/netwerk/protocol/websocket/WebSocketChannelParent.cpp @@ -67,6 +67,11 @@ WebSocketChannelParent::RecvAsyncOpen(const URIParams& aURI, if (loadContext.IsNotNull()) mLoadContext = new LoadContext(loadContext); +#ifdef DEBUG + else + // websocket channels cannot have a private bit override + MOZ_ASSERT(!loadContext.IsPrivateBitValid()); +#endif rv = mChannel->SetNotificationCallbacks(this); if (NS_FAILED(rv)) diff --git a/netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp b/netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp index ca8caf09eec..0a8da5ed31d 100644 --- a/netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp +++ b/netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp @@ -21,10 +21,11 @@ using namespace mozilla::ipc; namespace mozilla { namespace net { -NS_IMPL_ISUPPORTS3(WyciwygChannelChild, +NS_IMPL_ISUPPORTS4(WyciwygChannelChild, nsIRequest, nsIChannel, - nsIWyciwygChannel) + nsIWyciwygChannel, + nsIPrivateBrowsingChannel) WyciwygChannelChild::WyciwygChannelChild() @@ -384,6 +385,10 @@ WyciwygChannelChild::GetLoadGroup(nsILoadGroup * *aLoadGroup) NS_IMETHODIMP WyciwygChannelChild::SetLoadGroup(nsILoadGroup * aLoadGroup) { + if (!CanSetLoadGroup()) { + return NS_ERROR_FAILURE; + } + mLoadGroup = aLoadGroup; NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, @@ -466,6 +471,10 @@ WyciwygChannelChild::GetNotificationCallbacks(nsIInterfaceRequestor * *aCallback NS_IMETHODIMP WyciwygChannelChild::SetNotificationCallbacks(nsIInterfaceRequestor * aCallbacks) { + if (!CanSetCallbacks()) { + return NS_ERROR_FAILURE; + } + mCallbacks = aCallbacks; NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, diff --git a/netwerk/protocol/wyciwyg/WyciwygChannelChild.h b/netwerk/protocol/wyciwyg/WyciwygChannelChild.h index e5f3712fae9..e654edd6a58 100644 --- a/netwerk/protocol/wyciwyg/WyciwygChannelChild.h +++ b/netwerk/protocol/wyciwyg/WyciwygChannelChild.h @@ -10,6 +10,7 @@ #include "nsIWyciwygChannel.h" #include "nsIChannel.h" #include "nsIProgressEventSink.h" +#include "PrivateBrowsingChannel.h" namespace mozilla { namespace net { @@ -34,6 +35,7 @@ enum WyciwygChannelChildState { // Header file contents class WyciwygChannelChild : public PWyciwygChannelChild , public nsIWyciwygChannel + , public PrivateBrowsingChannel { public: NS_DECL_ISUPPORTS @@ -72,6 +74,8 @@ protected: void OnStopRequest(const nsresult& statusCode); void CancelEarly(const nsresult& statusCode); + friend class PrivateBrowsingChannel; + private: nsresult mStatus; bool mIsPending; diff --git a/netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp b/netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp index c8a4b0e2cb2..e0057a154ed 100644 --- a/netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp +++ b/netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp @@ -109,6 +109,11 @@ WyciwygChannelParent::RecvAsyncOpen(const URIParams& aOriginal, if (loadContext.IsNotNull()) mLoadContext = new LoadContext(loadContext); + else if (loadContext.IsPrivateBitValid()) { + nsCOMPtr pbChannel = do_QueryInterface(mChannel); + if (pbChannel) + pbChannel->SetPrivate(loadContext.mUsePrivateBrowsing); + } rv = mChannel->AsyncOpen(this, nullptr); if (NS_FAILED(rv)) diff --git a/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp b/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp index b6988297911..f687eaea748 100644 --- a/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp +++ b/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp @@ -83,7 +83,6 @@ nsWyciwygChannel::nsWyciwygChannel() mIsPending(false), mCharsetAndSourceSet(false), mNeedToWriteCharset(false), - mPrivateBrowsing(false), mCharsetSource(kCharsetUninitialized), mContentLength(-1), mLoadFlags(LOAD_NORMAL) @@ -94,13 +93,14 @@ nsWyciwygChannel::~nsWyciwygChannel() { } -NS_IMPL_THREADSAFE_ISUPPORTS6(nsWyciwygChannel, +NS_IMPL_THREADSAFE_ISUPPORTS7(nsWyciwygChannel, nsIChannel, nsIRequest, nsIStreamListener, nsIRequestObserver, - nsICacheListener, - nsIWyciwygChannel) + nsICacheListener, + nsIWyciwygChannel, + nsIPrivateBrowsingChannel) nsresult nsWyciwygChannel::Init(nsIURI* uri) @@ -188,11 +188,16 @@ nsWyciwygChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup) NS_IMETHODIMP nsWyciwygChannel::SetLoadGroup(nsILoadGroup* aLoadGroup) { + if (!CanSetLoadGroup()) { + return NS_ERROR_FAILURE; + } + mLoadGroup = aLoadGroup; NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, NS_GET_IID(nsIProgressEventSink), getter_AddRefs(mProgressSink)); + mPrivateBrowsing = NS_UsePrivateBrowsing(this); return NS_OK; } @@ -266,13 +271,16 @@ nsWyciwygChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aCallbacks) NS_IMETHODIMP nsWyciwygChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks) { + if (!CanSetCallbacks()) { + return NS_ERROR_FAILURE; + } + mCallbacks = aNotificationCallbacks; NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, NS_GET_IID(nsIProgressEventSink), getter_AddRefs(mProgressSink)); - // Will never change unless SetNotificationCallbacks called again, so cache mPrivateBrowsing = NS_UsePrivateBrowsing(this); return NS_OK; diff --git a/netwerk/protocol/wyciwyg/nsWyciwygChannel.h b/netwerk/protocol/wyciwyg/nsWyciwygChannel.h index b91458ab990..e5894ad41fb 100644 --- a/netwerk/protocol/wyciwyg/nsWyciwygChannel.h +++ b/netwerk/protocol/wyciwyg/nsWyciwygChannel.h @@ -26,6 +26,7 @@ #include "nsIEventTarget.h" #include "nsILoadContext.h" #include "nsNetUtil.h" +#include "PrivateBrowsingChannel.h" extern PRLogModuleInfo * gWyciwygLog; @@ -33,7 +34,8 @@ extern PRLogModuleInfo * gWyciwygLog; class nsWyciwygChannel: public nsIWyciwygChannel, public nsIStreamListener, - public nsICacheListener + public nsICacheListener, + public mozilla::net::PrivateBrowsingChannel { public: NS_DECL_ISUPPORTS @@ -68,11 +70,12 @@ protected: void NotifyListener(); bool IsOnCacheIOThread(); + friend class mozilla::net::PrivateBrowsingChannel; + nsresult mStatus; bool mIsPending; bool mCharsetAndSourceSet; bool mNeedToWriteCharset; - bool mPrivateBrowsing; int32_t mCharsetSource; nsCString mCharset; int32_t mContentLength; diff --git a/netwerk/test/unit/head_cache.js b/netwerk/test/unit/head_cache.js index 5bd964fe764..95ecb4402e0 100644 --- a/netwerk/test/unit/head_cache.js +++ b/netwerk/test/unit/head_cache.js @@ -55,3 +55,25 @@ function syncWithCacheIOThread(callback) callback(); }); } + +function get_device_entry_count(device) { + var cs = get_cache_service(); + var entry_count = -1; + + var visitor = { + visitDevice: function (deviceID, deviceInfo) { + if (device == deviceID) + entry_count = deviceInfo.entryCount; + return false; + }, + visitEntry: function (deviceID, entryInfo) { + do_throw("nsICacheVisitor.visitEntry should not be called " + + "when checking the availability of devices"); + } + }; + + // get the device entry count + cs.visitEntries(visitor); + + return entry_count; +} diff --git a/netwerk/test/unit/test_bug248970_cache.js b/netwerk/test/unit/test_bug248970_cache.js index 83aef245bdb..4d4bc20a315 100644 --- a/netwerk/test/unit/test_bug248970_cache.js +++ b/netwerk/test/unit/test_bug248970_cache.js @@ -52,28 +52,6 @@ function check_devices_available(devices) { } } -function get_device_entry_count(device) { - var cs = get_cache_service(); - var entry_count = -1; - - var visitor = { - visitDevice: function (deviceID, deviceInfo) { - if (device == deviceID) - entry_count = deviceInfo.entryCount; - return false; - }, - visitEntry: function (deviceID, entryInfo) { - do_throw("nsICacheVisitor.visitEntry should not be called " + - "when checking the availability of devices"); - } - }; - - // get the device entry count - cs.visitEntries(visitor); - - return entry_count; -} - function make_input_stream_scriptable(input) { var wrapper = Cc["@mozilla.org/scriptableinputstream;1"]. createInstance(Ci.nsIScriptableInputStream); diff --git a/netwerk/test/unit/test_private_channel.js b/netwerk/test/unit/test_private_channel.js new file mode 100644 index 00000000000..81a53050c58 --- /dev/null +++ b/netwerk/test/unit/test_private_channel.js @@ -0,0 +1,50 @@ +// +// Private channel test +// + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cr = Components.results; + +Cu.import("resource://testing-common/httpd.js"); + +var httpserver = new HttpServer(); +var testpath = "/simple"; + +function run_test() { + // Simulate a profile dir for xpcshell + do_get_profile(); + + // Start off with an empty cache + evict_cache_entries(); + + httpserver.registerPathHandler(testpath, serverHandler); + httpserver.start(4444); + + var channel = setupChannel(testpath); + + channel.QueryInterface(Ci.nsIPrivateBrowsingChannel); + channel.setPrivate(true); + + channel.asyncOpen(new ChannelListener(checkRequest, channel), null); + + do_test_pending(); +} + +function setupChannel(path) { + var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); + return chan = ios.newChannel("http://localhost:4444" + path, "", null) + .QueryInterface(Ci.nsIHttpChannel); +} + +function serverHandler(metadata, response) { + response.write("HTTP/1.0 200 OK\r\n\r\nfoobar"); + respose.finish(); +} + +function checkRequest(request, data, context) { + do_check_eq(get_device_entry_count("disk"), 0); + do_check_eq(get_device_entry_count("memory"), 1); + httpserver.stop(do_test_finished); +} diff --git a/netwerk/test/unit/xpcshell.ini b/netwerk/test/unit/xpcshell.ini index 138603db10c..91d2e39c873 100644 --- a/netwerk/test/unit/xpcshell.ini +++ b/netwerk/test/unit/xpcshell.ini @@ -155,6 +155,7 @@ skip-if = os == "win" [test_permmgr.js] [test_plaintext_sniff.js] [test_post.js] +[test_private_channel.js] [test_progress.js] [test_protocolproxyservice.js] [test_proxy-failover_canceled.js]