[tor-commits] [torbrowser/master] Add patches for #5477 and #5472.

mikeperry at torproject.org mikeperry at torproject.org
Wed Aug 1 21:32:14 UTC 2012


commit d8e36b11e0b149a0d44dada9b3978f766e26c40a
Author: Mike Perry <mikeperry-git at fscked.org>
Date:   Wed Aug 1 14:24:30 2012 -0700

    Add patches for #5477 and #5472.
---
 ...0-Add-a-redirect-API-for-HTTPS-Everywhere.patch |  346 ++++++++
 ...solate-the-Image-Cache-per-url-bar-domain.patch |  904 ++++++++++++++++++++
 2 files changed, 1250 insertions(+), 0 deletions(-)

diff --git a/src/current-patches/firefox/alpha/0020-Add-a-redirect-API-for-HTTPS-Everywhere.patch b/src/current-patches/firefox/alpha/0020-Add-a-redirect-API-for-HTTPS-Everywhere.patch
new file mode 100644
index 0000000..dd15f05
--- /dev/null
+++ b/src/current-patches/firefox/alpha/0020-Add-a-redirect-API-for-HTTPS-Everywhere.patch
@@ -0,0 +1,346 @@
+From 046d49340c963f140c618866a4ddd47cc75f576f Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git at torproject.org>
+Date: Thu, 26 Jul 2012 15:13:44 -0700
+Subject: [PATCH 20/21] Add a redirect API for HTTPS-Everywhere.
+
+---
+ netwerk/protocol/http/HttpChannelChild.cpp         |   15 ++++-
+ netwerk/protocol/http/HttpChannelChild.h           |    4 +
+ netwerk/protocol/http/HttpChannelParent.cpp        |    4 +
+ netwerk/protocol/http/HttpChannelParent.h          |    1 +
+ netwerk/protocol/http/PHttpChannel.ipdl            |    1 +
+ netwerk/protocol/http/nsHttpChannel.cpp            |   67 +++++++++++++++++---
+ netwerk/protocol/http/nsHttpChannel.h              |   13 +++-
+ netwerk/protocol/http/nsIHttpChannel.idl           |   12 ++++
+ .../protocol/viewsource/nsViewSourceChannel.cpp    |   13 ++++-
+ 9 files changed, 118 insertions(+), 12 deletions(-)
+
+diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp
+index 777dfb6..a563438 100644
+--- a/netwerk/protocol/http/HttpChannelChild.cpp
++++ b/netwerk/protocol/http/HttpChannelChild.cpp
+@@ -1070,7 +1070,8 @@ HttpChannelChild::AsyncOpen(nsIStreamListener *listener, nsISupports *aContext)
+   gNeckoChild->SendPHttpChannelConstructor(this, tabChild);
+ 
+   SendAsyncOpen(IPC::URI(mURI), IPC::URI(mOriginalURI),
+-                IPC::URI(mDocumentURI), IPC::URI(mReferrer), mLoadFlags,
++                IPC::URI(mDocumentURI), IPC::URI(mReferrer),
++                IPC::URI(mInternalRedirectURI), mLoadFlags,
+                 mClientSetRequestHeaders, mRequestHead.Method(),
+                 IPC::InputStream(mUploadStream), mUploadStreamHasHeaders,
+                 mPriority, mRedirectionLimit, mAllowPipelining,
+@@ -1114,6 +1115,18 @@ HttpChannelChild::SetupFallbackChannel(const char *aFallbackKey)
+   DROP_DEAD();
+ }
+ 
++NS_IMETHODIMP
++HttpChannelChild::RedirectTo(nsIURI *uri)
++{
++  // We can only redirect unopened channels
++  NS_ENSURE_TRUE(!mIPCOpen, NS_ERROR_ALREADY_OPENED);
++
++  // The redirect is stored internally for use in AsyncOpen
++  mInternalRedirectURI = uri;
++
++  return NS_OK;
++}
++
+ // The next four _should_ be implemented, but we need to figure out how
+ // to transfer the data from the chrome process first.
+ 
+diff --git a/netwerk/protocol/http/HttpChannelChild.h b/netwerk/protocol/http/HttpChannelChild.h
+index 43617ef..f595c4d 100644
+--- a/netwerk/protocol/http/HttpChannelChild.h
++++ b/netwerk/protocol/http/HttpChannelChild.h
+@@ -110,6 +110,9 @@ public:
+   NS_IMETHOD GetLocalPort(PRInt32* port);
+   NS_IMETHOD GetRemoteAddress(nsACString& addr);
+   NS_IMETHOD GetRemotePort(PRInt32* port);
++
++  NS_IMETHOD RedirectTo(nsIURI *uri);
++
+   // nsISupportsPriority
+   NS_IMETHOD SetPriority(PRInt32 value);
+   // nsIResumableChannel
+@@ -160,6 +163,7 @@ private:
+   RequestHeaderTuples mClientSetRequestHeaders;
+   nsCOMPtr<nsIChildChannel> mRedirectChannelChild;
+   nsCOMPtr<nsISupports> mSecurityInfo;
++  nsCOMPtr<nsIURI>      mInternalRedirectURI;
+ 
+   bool mIsFromCache;
+   bool mCacheEntryAvailable;
+diff --git a/netwerk/protocol/http/HttpChannelParent.cpp b/netwerk/protocol/http/HttpChannelParent.cpp
+index 464cbe7..3ce94b8 100644
+--- a/netwerk/protocol/http/HttpChannelParent.cpp
++++ b/netwerk/protocol/http/HttpChannelParent.cpp
+@@ -132,6 +132,7 @@ HttpChannelParent::RecvAsyncOpen(const IPC::URI&            aURI,
+                                  const IPC::URI&            aOriginalURI,
+                                  const IPC::URI&            aDocURI,
+                                  const IPC::URI&            aReferrerURI,
++                                 const IPC::URI&            aInternalRedirectURI,
+                                  const PRUint32&            loadFlags,
+                                  const RequestHeaderTuples& requestHeaders,
+                                  const nsHttpAtom&          requestMethod,
+@@ -152,6 +153,7 @@ HttpChannelParent::RecvAsyncOpen(const IPC::URI&            aURI,
+   nsCOMPtr<nsIURI> originalUri(aOriginalURI);
+   nsCOMPtr<nsIURI> docUri(aDocURI);
+   nsCOMPtr<nsIURI> referrerUri(aReferrerURI);
++  nsCOMPtr<nsIURI> internalRedirectUri(aInternalRedirectURI);
+ 
+   nsCString uriSpec;
+   uri->GetSpec(uriSpec);
+@@ -179,6 +181,8 @@ HttpChannelParent::RecvAsyncOpen(const IPC::URI&            aURI,
+     httpChan->SetDocumentURI(docUri);
+   if (referrerUri)
+     httpChan->SetReferrerInternal(referrerUri);
++  if (internalRedirectUri)
++    httpChan->SetInternalRedirectURI(internalRedirectUri);
+   if (loadFlags != nsIRequest::LOAD_NORMAL)
+     httpChan->SetLoadFlags(loadFlags);
+ 
+diff --git a/netwerk/protocol/http/HttpChannelParent.h b/netwerk/protocol/http/HttpChannelParent.h
+index 6cfc3a6..a4b410a 100644
+--- a/netwerk/protocol/http/HttpChannelParent.h
++++ b/netwerk/protocol/http/HttpChannelParent.h
+@@ -82,6 +82,7 @@ protected:
+                              const IPC::URI&            originalUri,
+                              const IPC::URI&            docUri,
+                              const IPC::URI&            referrerUri,
++                             const IPC::URI&            internalRedirectUri,
+                              const PRUint32&            loadFlags,
+                              const RequestHeaderTuples& requestHeaders,
+                              const nsHttpAtom&          requestMethod,
+diff --git a/netwerk/protocol/http/PHttpChannel.ipdl b/netwerk/protocol/http/PHttpChannel.ipdl
+index 252a6ee..23a912e 100644
+--- a/netwerk/protocol/http/PHttpChannel.ipdl
++++ b/netwerk/protocol/http/PHttpChannel.ipdl
+@@ -69,6 +69,7 @@ parent:
+             URI                 original,
+             URI                 doc,
+             URI                 referrer,
++            URI                 internalRedirect,
+             PRUint32            loadFlags,
+             RequestHeaderTuples requestHeaders,
+             nsHttpAtom          requestMethod,
+diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp
+index 23edc3c..c55fe4d 100644
+--- a/netwerk/protocol/http/nsHttpChannel.cpp
++++ b/netwerk/protocol/http/nsHttpChannel.cpp
+@@ -1403,18 +1403,17 @@ nsHttpChannel::HandleAsyncRedirectChannelToHttps()
+         return;
+     }
+ 
+-    nsresult rv = AsyncRedirectChannelToHttps();
++    nsresult rv = InternalRedirectChannelToHttps();
+     if (NS_FAILED(rv))
+-        ContinueAsyncRedirectChannelToHttps(rv);
++        ContinueInternalRedirectChannelToURI(rv);
+ }
+ 
+ nsresult
+-nsHttpChannel::AsyncRedirectChannelToHttps()
++nsHttpChannel::InternalRedirectChannelToHttps()
+ {
+     nsresult rv = NS_OK;
+     LOG(("nsHttpChannel::HandleAsyncRedirectChannelToHttps() [STS]\n"));
+ 
+-    nsCOMPtr<nsIChannel> newChannel;
+     nsCOMPtr<nsIURI> upgradedURI;
+ 
+     rv = mURI->Clone(getter_AddRefs(upgradedURI));
+@@ -1436,6 +1435,48 @@ nsHttpChannel::AsyncRedirectChannelToHttps()
+     else
+         upgradedURI->SetPort(oldPort);
+ 
++    return InternalRedirectChannelToURI(upgradedURI);
++}
++
++NS_IMETHODIMP
++nsHttpChannel::RedirectTo(nsIURI *newURI)
++{
++    // We can only redirect unopened channels
++    NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
++
++    // The redirect is stored internally for use in AsyncOpen
++    mInternalRedirectURI = newURI;
++
++    return NS_OK;
++}
++
++void
++nsHttpChannel::HandleAsyncInternalRedirect()
++{
++    NS_PRECONDITION(!mCallOnResume, "How did that happen?");
++    NS_PRECONDITION(mInternalRedirectURI, "How did that happen?");
++
++    if (mSuspendCount) {
++        LOG(("Waiting until resume to do async API redirect [this=%p]\n", this));
++        mCallOnResume = &nsHttpChannel::HandleAsyncInternalRedirect;
++        return;
++    }
++
++    nsresult rv = InternalRedirectChannelToURI(mInternalRedirectURI);
++    if (NS_FAILED(rv))
++        ContinueInternalRedirectChannelToURI(rv);
++
++    return;
++}
++
++nsresult
++nsHttpChannel::InternalRedirectChannelToURI(nsIURI *upgradedURI)
++{
++    nsresult rv = NS_OK;
++    LOG(("nsHttpChannel::InternalRedirectChannelToURI()\n"));
++
++    nsCOMPtr<nsIChannel> newChannel;
++
+     nsCOMPtr<nsIIOService> ioService;
+     rv = gHttpHandler->GetIOService(getter_AddRefs(ioService));
+     NS_ENSURE_SUCCESS(rv, rv);
+@@ -1451,7 +1492,7 @@ nsHttpChannel::AsyncRedirectChannelToHttps()
+     PRUint32 flags = nsIChannelEventSink::REDIRECT_PERMANENT;
+ 
+     PushRedirectAsyncFunc(
+-        &nsHttpChannel::ContinueAsyncRedirectChannelToHttps);
++        &nsHttpChannel::ContinueInternalRedirectChannelToURI);
+     rv = gHttpHandler->AsyncOnChannelRedirect(this, newChannel, flags);
+ 
+     if (NS_SUCCEEDED(rv))
+@@ -1460,14 +1501,18 @@ nsHttpChannel::AsyncRedirectChannelToHttps()
+     if (NS_FAILED(rv)) {
+         AutoRedirectVetoNotifier notifier(this);
+         PopRedirectAsyncFunc(
+-            &nsHttpChannel::ContinueAsyncRedirectChannelToHttps);
++            &nsHttpChannel::ContinueInternalRedirectChannelToURI);
++
++        // If we've failed so far, cancel the current channel, too,
++        // as both HSTS and the redirectTo codepaths prefer
++        // request failure to insecurity.
++        Cancel(rv);
+     }
+ 
+     return rv;
+ }
+-
+ nsresult
+-nsHttpChannel::ContinueAsyncRedirectChannelToHttps(nsresult rv)
++nsHttpChannel::ContinueInternalRedirectChannelToURI(nsresult rv)
+ {
+     AutoRedirectVetoNotifier notifier(this);
+ 
+@@ -3929,6 +3974,12 @@ nsHttpChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *context)
+     if (mLoadGroup)
+         mLoadGroup->AddRequest(this, nsnull);
+ 
++    // Check to see if we should redirect this channel elsewhere by 
++    // nsIHttpChannel.redirectTo API request
++    if (mInternalRedirectURI) {
++        return AsyncCall(&nsHttpChannel::HandleAsyncInternalRedirect);
++    }
++
+     // Collect mAsyncOpenTime after we have called all obsrevers like
+     // "http-on-modify-request" and load group observers that may set
+     // mTimingEnabled flag.
+diff --git a/netwerk/protocol/http/nsHttpChannel.h b/netwerk/protocol/http/nsHttpChannel.h
+index 5a61e21..d156c28 100644
+--- a/netwerk/protocol/http/nsHttpChannel.h
++++ b/netwerk/protocol/http/nsHttpChannel.h
+@@ -138,6 +138,8 @@ public:
+     // nsIChannel
+     NS_IMETHOD GetSecurityInfo(nsISupports **aSecurityInfo);
+     NS_IMETHOD AsyncOpen(nsIStreamListener *listener, nsISupports *aContext);
++    // nsIHttpChannel
++    NS_IMETHOD RedirectTo(nsIURI *newURI);
+     // nsIHttpChannelInternal
+     NS_IMETHOD SetupFallbackChannel(const char *aFallbackKey);
+     // nsISupportsPriority
+@@ -152,6 +154,9 @@ public: /* internal necko use only */
+     void SetUploadStreamHasHeaders(bool hasHeaders) 
+       { mUploadStreamHasHeaders = hasHeaders; }
+ 
++    void SetInternalRedirectURI(nsIURI *redirectTo) 
++      { mInternalRedirectURI = redirectTo; }
++
+     nsresult SetReferrerInternal(nsIURI *referrer) {
+         nsCAutoString spec;
+         nsresult rv = referrer->GetAsciiSpec(spec);
+@@ -190,11 +195,14 @@ private:
+ 
+     // redirection specific methods
+     void     HandleAsyncRedirect();
++    void     HandleAsyncInternalRedirect();
+     nsresult ContinueHandleAsyncRedirect(nsresult);
+     void     HandleAsyncNotModified();
+     void     HandleAsyncFallback();
+     nsresult ContinueHandleAsyncFallback(nsresult);
+     nsresult PromptTempRedirect();
++    nsresult InternalRedirectChannelToURI(nsIURI *);
++
+     virtual nsresult SetupReplacementChannel(nsIURI *, nsIChannel *,
+                                              bool preserveMethod,
+                                              bool forProxy);
+@@ -256,8 +264,8 @@ private:
+     bool     MustValidateBasedOnQueryUrl();
+ 
+     void     HandleAsyncRedirectChannelToHttps();
+-    nsresult AsyncRedirectChannelToHttps();
+-    nsresult ContinueAsyncRedirectChannelToHttps(nsresult rv);
++    nsresult InternalRedirectChannelToHttps();
++    nsresult ContinueInternalRedirectChannelToURI(nsresult rv);
+ 
+     /**
+      * A function that takes care of reading STS headers and enforcing STS 
+@@ -327,6 +335,7 @@ private:
+     friend class AutoRedirectVetoNotifier;
+     friend class HttpAsyncAborter<nsHttpChannel>;
+     nsCOMPtr<nsIURI>                  mRedirectURI;
++    nsCOMPtr<nsIURI>                  mInternalRedirectURI;
+     nsCOMPtr<nsIChannel>              mRedirectChannel;
+     PRUint32                          mRedirectType;
+ 
+diff --git a/netwerk/protocol/http/nsIHttpChannel.idl b/netwerk/protocol/http/nsIHttpChannel.idl
+index 2d3f01a..39b2ee5 100644
+--- a/netwerk/protocol/http/nsIHttpChannel.idl
++++ b/netwerk/protocol/http/nsIHttpChannel.idl
+@@ -291,4 +291,16 @@ interface nsIHttpChannel : nsIChannel
+      *         has been received (before onStartRequest).
+      */
+     boolean isNoCacheResponse();
++    
++    /**
++     * Instructs the channel to immediately redirect to a new destination.
++     * Can only be called on channels not yet opened.
++     * 
++     * This method provides no explicit conflict resolution. The last
++     * caller to call it wins.
++     *
++     * @throws NS_ERROR_ALREADY_OPENED if called after the channel
++     *         has been opened.
++     */ 
++    void redirectTo(in nsIURI aNewURI);
+ };
+diff --git a/netwerk/protocol/viewsource/nsViewSourceChannel.cpp b/netwerk/protocol/viewsource/nsViewSourceChannel.cpp
+index 919c3f7..e286b8f 100644
+--- a/netwerk/protocol/viewsource/nsViewSourceChannel.cpp
++++ b/netwerk/protocol/viewsource/nsViewSourceChannel.cpp
+@@ -703,4 +703,15 @@ nsViewSourceChannel::IsNoCacheResponse(bool *_retval)
+ {
+     return !mHttpChannel ? NS_ERROR_NULL_POINTER :
+         mHttpChannel->IsNoCacheResponse(_retval);
+-} 
++}
++
++// XXX: Is this the right thing to do here? Or should we have
++// made an nsIHTTPChannelRedirect that only nsHttpChannel implements?
++// Also, will this mean that some ViewSource requests may be non-https?
++// Or will the mHttpChannel take care of that for us?
++NS_IMETHODIMP
++nsViewSourceChannel::RedirectTo(nsIURI *uri)
++{
++    return NS_ERROR_NOT_IMPLEMENTED;
++}
++
+-- 
+1.7.5.4
+
diff --git a/src/current-patches/firefox/alpha/0021-Isolate-the-Image-Cache-per-url-bar-domain.patch b/src/current-patches/firefox/alpha/0021-Isolate-the-Image-Cache-per-url-bar-domain.patch
new file mode 100644
index 0000000..2478af8
--- /dev/null
+++ b/src/current-patches/firefox/alpha/0021-Isolate-the-Image-Cache-per-url-bar-domain.patch
@@ -0,0 +1,904 @@
+From 0b3b4970954c9dd7d85929491b887e45abe9c194 Mon Sep 17 00:00:00 2001
+From: Mike Perry <mikeperry-git at torproject.org>
+Date: Mon, 30 Jul 2012 18:37:36 -0700
+Subject: [PATCH 21/21] Isolate the Image Cache per url bar domain.
+
+Also adds a new API to mozIThirdPartyUtil to allow you to get the url bar URI
+for a channel or nsIDocument.
+---
+ content/base/src/ThirdPartyUtil.cpp                |   52 +++++
+ content/base/src/ThirdPartyUtil.h                  |    2 +
+ content/base/src/nsContentUtils.cpp                |   13 +-
+ embedding/browser/webBrowser/nsContextMenuInfo.cpp |   29 ++-
+ extensions/cookie/nsCookiePermission.cpp           |    3 +
+ image/public/imgILoader.idl                        |    4 +-
+ image/src/imgLoader.cpp                            |  202 ++++++++++++--------
+ image/src/imgLoader.h                              |   13 +-
+ image/src/imgRequest.cpp                           |    9 +-
+ image/src/imgRequest.h                             |    3 +
+ layout/generic/nsImageFrame.cpp                    |   11 +-
+ netwerk/base/public/mozIThirdPartyUtil.idl         |   21 ++
+ netwerk/cookie/nsICookiePermission.idl             |    1 +
+ toolkit/system/gnome/nsAlertsIconListener.cpp      |    3 +-
+ widget/cocoa/nsMenuItemIconX.mm                    |    8 +-
+ 15 files changed, 272 insertions(+), 102 deletions(-)
+
+diff --git a/content/base/src/ThirdPartyUtil.cpp b/content/base/src/ThirdPartyUtil.cpp
+index 6a415e9..abf2eed 100644
+--- a/content/base/src/ThirdPartyUtil.cpp
++++ b/content/base/src/ThirdPartyUtil.cpp
+@@ -39,7 +39,10 @@
+ #include "nsNetUtil.h"
+ #include "nsIServiceManager.h"
+ #include "nsIHttpChannelInternal.h"
++#include "nsICookiePermission.h"
+ #include "nsIDOMWindow.h"
++#include "nsIDOMDocument.h"
++#include "nsIDocument.h"
+ #include "nsILoadContext.h"
+ #include "nsIPrincipal.h"
+ #include "nsIScriptObjectPrincipal.h"
+@@ -54,6 +57,7 @@ ThirdPartyUtil::Init()
+ 
+   nsresult rv;
+   mTLDService = do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID, &rv);
++  mCookiePermissions = do_GetService(NS_COOKIEPERMISSION_CONTRACTID);
+   return rv;
+ }
+ 
+@@ -315,3 +319,51 @@ ThirdPartyUtil::GetBaseDomain(nsIURI* aHostURI,
+ 
+   return NS_OK;
+ }
++
++NS_IMETHODIMP
++ThirdPartyUtil::GetFirstPartyURI(nsIChannel *aChannel,
++                                 nsIDocument *aDoc,
++                                 nsIURI **aOutput)
++{
++  nsresult rv = NS_ERROR_NULL_POINTER;
++
++  if (!aChannel && aDoc) {
++    aChannel = aDoc->GetChannel();
++  }
++
++  // If aChannel is specified or available, use the official route
++  // for sure
++  if (aChannel) {
++    rv = mCookiePermissions->GetOriginatingURI(aChannel, aOutput);
++  }
++
++  // If the channel was missing, closed or broken, try the
++  // window hierarchy directly. 
++  //
++  // This might fail to work for first-party loads themselves, but 
++  // we don't need this codepath for that case.
++  if (NS_FAILED(rv) && aDoc) {
++    nsCOMPtr<nsIDOMWindow> top;
++    nsCOMPtr<nsIDOMDocument> topDDoc;
++    
++    aDoc->GetWindow()->GetTop(getter_AddRefs(top));
++    top->GetDocument(getter_AddRefs(topDDoc));
++
++    nsCOMPtr<nsIDocument> topDoc(do_QueryInterface(topDDoc));
++    *aOutput = topDoc->GetOriginalURI();
++
++    if (*aOutput)
++      rv = NS_OK;
++  }
++
++  // TODO: We could provide a route through the loadgroup + notification
++  // callbacks too, but either channel or document was always available
++  // in the cases where this function was originally needed (the image cache).
++  // The notification callbacks also appear to suffers from the same limitation
++  // as the document path. See nsICookiePermissions.GetOriginatingURI() for
++  // details.
++
++  return rv;
++}
++
++
+diff --git a/content/base/src/ThirdPartyUtil.h b/content/base/src/ThirdPartyUtil.h
+index 58ddb15..ba70162 100644
+--- a/content/base/src/ThirdPartyUtil.h
++++ b/content/base/src/ThirdPartyUtil.h
+@@ -46,6 +46,7 @@
+ class nsIURI;
+ class nsIChannel;
+ class nsIDOMWindow;
++class nsICookiePermission;
+ 
+ class ThirdPartyUtil : public mozIThirdPartyUtil
+ {
+@@ -61,6 +62,7 @@ private:
+   static already_AddRefed<nsIURI> GetURIFromWindow(nsIDOMWindow* aWin);
+ 
+   nsCOMPtr<nsIEffectiveTLDService> mTLDService;
++  nsCOMPtr<nsICookiePermission> mCookiePermissions;
+ };
+ 
+ #endif
+diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp
+index 5c85697..4368609 100644
+--- a/content/base/src/nsContentUtils.cpp
++++ b/content/base/src/nsContentUtils.cpp
+@@ -179,6 +179,7 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID);
+ #include "nsIDOMHTMLInputElement.h"
+ #include "nsParserConstants.h"
+ #include "nsIWebNavigation.h"
++#include "mozIThirdPartyUtil.h"
+ 
+ #ifdef IBMBIDI
+ #include "nsIBidiKeyboard.h"
+@@ -2629,8 +2630,6 @@ nsContentUtils::LoadImage(nsIURI* aURI, nsIDocument* aLoadingDocument,
+   nsCOMPtr<nsILoadGroup> loadGroup = aLoadingDocument->GetDocumentLoadGroup();
+   NS_ASSERTION(loadGroup, "Could not get loadgroup; onload may fire too early");
+ 
+-  nsIURI *documentURI = aLoadingDocument->GetDocumentURI();
+-
+   // check for a Content Security Policy to pass down to the channel that
+   // will get created to load the image
+   nsCOMPtr<nsIChannelPolicy> channelPolicy;
+@@ -2647,11 +2646,15 @@ nsContentUtils::LoadImage(nsIURI* aURI, nsIDocument* aLoadingDocument,
+     
+   // Make the URI immutable so people won't change it under us
+   NS_TryToSetImmutable(aURI);
++ 
++  nsCOMPtr<nsIURI> firstPartyURI;
++  nsCOMPtr<mozIThirdPartyUtil> thirdPartySvc
++                               = do_GetService(THIRDPARTYUTIL_CONTRACTID);
++  thirdPartySvc->GetFirstPartyURI(nsnull, aLoadingDocument,
++                                  getter_AddRefs(firstPartyURI));
+ 
+-  // XXXbz using "documentURI" for the initialDocumentURI is not quite
+-  // right, but the best we can do here...
+   return imgLoader->LoadImage(aURI,                 /* uri to load */
+-                              documentURI,          /* initialDocumentURI */
++                              firstPartyURI,        /* firstPartyURI */
+                               aReferrer,            /* referrer */
+                               aLoadingPrincipal,    /* loading principal */
+                               loadGroup,            /* loadgroup */
+diff --git a/embedding/browser/webBrowser/nsContextMenuInfo.cpp b/embedding/browser/webBrowser/nsContextMenuInfo.cpp
+index 045482a..78f5fc4 100644
+--- a/embedding/browser/webBrowser/nsContextMenuInfo.cpp
++++ b/embedding/browser/webBrowser/nsContextMenuInfo.cpp
+@@ -62,6 +62,7 @@
+ #include "nsIChannelPolicy.h"
+ #include "nsIContentSecurityPolicy.h"
+ #include "nsIContentPolicy.h"
++#include "mozIThirdPartyUtil.h"
+ 
+ //*****************************************************************************
+ // class nsContextMenuInfo
+@@ -305,15 +306,15 @@ nsContextMenuInfo::GetBackgroundImageRequestInternal(nsIDOMNode *aDOMNode, imgIR
+   nsCOMPtr<nsIPrincipal> principal;
+   nsCOMPtr<nsIChannelPolicy> channelPolicy;
+   nsCOMPtr<nsIContentSecurityPolicy> csp;
+-  if (doc) {
+-    principal = doc->NodePrincipal();
+-    nsresult rv = principal->GetCsp(getter_AddRefs(csp));
+-    NS_ENSURE_SUCCESS(rv, rv);
+-    if (csp) {
+-      channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
+-      channelPolicy->SetContentSecurityPolicy(csp);
+-      channelPolicy->SetLoadType(nsIContentPolicy::TYPE_IMAGE);
+-    }
++  NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
++
++  principal = doc->NodePrincipal();
++  nsresult rv = principal->GetCsp(getter_AddRefs(csp));
++  NS_ENSURE_SUCCESS(rv, rv);
++  if (csp) {
++    channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
++    channelPolicy->SetContentSecurityPolicy(csp);
++    channelPolicy->SetLoadType(nsIContentPolicy::TYPE_IMAGE);
+   }
+   
+   while (true) {
+@@ -340,8 +341,14 @@ nsContextMenuInfo::GetBackgroundImageRequestInternal(nsIDOMNode *aDOMNode, imgIR
+           nsCOMPtr<imgILoader> il(do_GetService(
+                                     "@mozilla.org/image/loader;1"));
+           NS_ENSURE_TRUE(il, NS_ERROR_FAILURE);
+-
+-          return il->LoadImage(bgUri, nsnull, nsnull, principal, nsnull,
++          
++          nsCOMPtr<nsIURI> firstPartyURI;
++          nsCOMPtr<mozIThirdPartyUtil> thirdPartySvc
++              = do_GetService(THIRDPARTYUTIL_CONTRACTID);
++          thirdPartySvc->GetFirstPartyURI(nsnull, doc,
++                                          getter_AddRefs(firstPartyURI));
++
++          return il->LoadImage(bgUri, firstPartyURI, nsnull, principal, nsnull,
+                                nsnull, nsnull, nsIRequest::LOAD_NORMAL, nsnull,
+                                nsnull, channelPolicy, aRequest);
+         }
+diff --git a/extensions/cookie/nsCookiePermission.cpp b/extensions/cookie/nsCookiePermission.cpp
+index 577ee7e..c15ddc9 100644
+--- a/extensions/cookie/nsCookiePermission.cpp
++++ b/extensions/cookie/nsCookiePermission.cpp
+@@ -445,6 +445,9 @@ nsCookiePermission::GetOriginatingURI(nsIChannel  *aChannel,
+ 
+       return NS_OK;
+     }
++
++    // TODO: Why don't we just use this here:
++    // httpChannelInternal->GetDocumentURI(aURI);
+   }
+ 
+   // find the associated window and its top window
+diff --git a/image/public/imgILoader.idl b/image/public/imgILoader.idl
+index 611b939..db9320b 100644
+--- a/image/public/imgILoader.idl
++++ b/image/public/imgILoader.idl
+@@ -71,7 +71,7 @@ interface imgILoader : nsISupports
+   /**
+    * Start the load and decode of an image.
+    * @param aURI the URI to load
+-   * @param aInitialDocumentURI the URI that 'initiated' the load -- used for 3rd party cookie blocking
++   * @param aFirstPartyURI the urlbar URI that 'initiated' the load -- used for 3rd party blocking
+    * @param aReferrerURI the 'referring' URI
+    * @param aLoadingPrincipal the principal of the loading document
+    * @param aLoadGroup Loadgroup to put the image load into
+@@ -90,7 +90,7 @@ interface imgILoader : nsISupports
+    * goes away.
+    */
+   imgIRequest loadImage(in nsIURI aURI,
+-                        in nsIURI aInitialDocumentURL,
++                        in nsIURI aFirstPartyURI,
+                         in nsIURI aReferrerURI,
+                         in nsIPrincipal aLoadingPrincipal,
+                         in nsILoadGroup aLoadGroup,
+diff --git a/image/src/imgLoader.cpp b/image/src/imgLoader.cpp
+index 36c8e6a..8ed12dc 100644
+--- a/image/src/imgLoader.cpp
++++ b/image/src/imgLoader.cpp
+@@ -92,6 +92,7 @@
+ #include "nsIHttpChannelInternal.h"  
+ #include "nsIContentSecurityPolicy.h"
+ #include "nsIChannelPolicy.h"
++#include "mozIThirdPartyUtil.h"
+ 
+ #include "nsContentUtils.h"
+ 
+@@ -504,7 +505,7 @@ static nsresult NewImageChannel(nsIChannel **aResult,
+                                 // aLoadingPrincipal and false otherwise.
+                                 bool *aForcePrincipalCheckForCacheEntry,
+                                 nsIURI *aURI,
+-                                nsIURI *aInitialDocumentURI,
++                                nsIURI *aFirstPartyURI,
+                                 nsIURI *aReferringURI,
+                                 nsILoadGroup *aLoadGroup,
+                                 const nsCString& aAcceptHeader,
+@@ -556,7 +557,7 @@ static nsresult NewImageChannel(nsIChannel **aResult,
+ 
+     nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal = do_QueryInterface(newHttpChannel);
+     NS_ENSURE_TRUE(httpChannelInternal, NS_ERROR_UNEXPECTED);
+-    httpChannelInternal->SetDocumentURI(aInitialDocumentURI);
++    httpChannelInternal->SetDocumentURI(aFirstPartyURI);
+     newHttpChannel->SetReferrer(aReferringURI);
+   }
+ 
+@@ -999,34 +1000,61 @@ NS_IMETHODIMP imgLoader::ClearCache(bool chrome)
+ /* void removeEntry(in nsIURI uri); */
+ NS_IMETHODIMP imgLoader::RemoveEntry(nsIURI *uri)
+ {
+-  if (RemoveFromCache(uri))
++  if (RemoveMatchingUrlsFromCache(uri))
+     return NS_OK;
+ 
+   return NS_ERROR_NOT_AVAILABLE;
+ }
+ 
++static PLDHashOperator EnumAllEntries(const nsACString&, 
++                                        nsRefPtr<imgCacheEntry> &aData,
++                                        void *data)
++{
++  nsTArray<nsRefPtr<imgCacheEntry> > *entries = 
++    reinterpret_cast<nsTArray<nsRefPtr<imgCacheEntry> > *>(data);
++
++  entries->AppendElement(aData);
++
++  return PL_DHASH_NEXT;
++}
++
+ /* imgIRequest findEntry(in nsIURI uri); */
+ NS_IMETHODIMP imgLoader::FindEntryProperties(nsIURI *uri, nsIProperties **_retval)
+ {
+   nsRefPtr<imgCacheEntry> entry;
+-  nsCAutoString spec;
+   imgCacheTable &cache = GetCache(uri);
+-
+-  uri->GetSpec(spec);
+   *_retval = nsnull;
+ 
+-  if (cache.Get(spec, getter_AddRefs(entry)) && entry) {
+-    if (gCacheTracker && entry->HasNoProxies())
+-      gCacheTracker->MarkUsed(entry);
++  // We must traverse the whole cache in O(N) looking for the first
++  // matching URI.
++  //
++  // TODO: For now, it's ok to pick at random here. The images should be
++  // identical unless there is a cache-tracking attack. And even if they
++  // are not identical due to attack, this code is only used for save
++  // dialogs at this point, so no differentiating info is leaked to
++  // content.
++  nsTArray<nsRefPtr<imgCacheEntry> > entries;
++  cache.Enumerate(EnumAllEntries, &entries);
++
++  for (PRUint32 i = 0; i < entries.Length(); ++i) {
++    bool isEqual = false;
+ 
+-    nsRefPtr<imgRequest> request = getter_AddRefs(entry->GetRequest());
++    nsRefPtr<imgRequest> request = getter_AddRefs(entries[i]->GetRequest());
+     if (request) {
+-      *_retval = request->Properties();
+-      NS_ADDREF(*_retval);
++      request->mURI->Equals(uri, &isEqual);
++      if (isEqual) {
++        if (gCacheTracker && entries[i]->HasNoProxies())
++          gCacheTracker->MarkUsed(entries[i]);
++
++        *_retval = request->Properties();
++      }
+     }
+   }
+ 
+-  return NS_OK;
++  if (*_retval)
++    return NS_OK;
++  
++  return NS_ERROR_NOT_AVAILABLE;
+ }
+ 
+ void imgLoader::Shutdown()
+@@ -1054,20 +1082,18 @@ void imgLoader::MinimizeCaches()
+   EvictEntries(sChromeCacheQueue);
+ }
+ 
+-bool imgLoader::PutIntoCache(nsIURI *key, imgCacheEntry *entry)
++bool imgLoader::PutIntoCache(nsCAutoString key, 
++                             imgCacheEntry *entry)
+ {
+-  imgCacheTable &cache = GetCache(key);
+-
+-  nsCAutoString spec;
+-  key->GetSpec(spec);
+-
+-  LOG_STATIC_FUNC_WITH_PARAM(gImgLog, "imgLoader::PutIntoCache", "uri", spec.get());
++  LOG_STATIC_FUNC_WITH_PARAM(gImgLog, "imgLoader::PutIntoCache", "uri", key.get());
++  imgCacheTable &cache = GetCache(entry->mRequest->mURI);
++  imgCacheQueue &queue = GetCacheQueue(entry->mRequest->mURI);
+ 
+   // Check to see if this request already exists in the cache and is being
+   // loaded on a different thread. If so, don't allow this entry to be added to
+   // the cache.
+   nsRefPtr<imgCacheEntry> tmpCacheEntry;
+-  if (cache.Get(spec, getter_AddRefs(tmpCacheEntry)) && tmpCacheEntry) {
++  if (cache.Get(key, getter_AddRefs(tmpCacheEntry)) && tmpCacheEntry) {
+     PR_LOG(gImgLog, PR_LOG_DEBUG,
+            ("[this=%p] imgLoader::PutIntoCache -- Element already in the cache", nsnull));
+     nsRefPtr<imgRequest> tmpRequest = getter_AddRefs(tmpCacheEntry->GetRequest());
+@@ -1077,13 +1103,13 @@ bool imgLoader::PutIntoCache(nsIURI *key, imgCacheEntry *entry)
+     PR_LOG(gImgLog, PR_LOG_DEBUG,
+            ("[this=%p] imgLoader::PutIntoCache -- Replacing cached element", nsnull));
+ 
+-    RemoveFromCache(key);
++    RemoveKeyFromCache(cache, queue, key);
+   } else {
+     PR_LOG(gImgLog, PR_LOG_DEBUG,
+            ("[this=%p] imgLoader::PutIntoCache -- Element NOT already in the cache", nsnull));
+   }
+ 
+-  if (!cache.Put(spec, entry))
++  if (!cache.Put(key, entry))
+     return false;
+ 
+   // We can be called to resurrect an evicted entry.
+@@ -1099,7 +1125,6 @@ bool imgLoader::PutIntoCache(nsIURI *key, imgCacheEntry *entry)
+       addrv = gCacheTracker->AddObject(entry);
+ 
+     if (NS_SUCCEEDED(addrv)) {
+-      imgCacheQueue &queue = GetCacheQueue(key);
+       queue.Push(entry);
+     }
+   }
+@@ -1205,7 +1230,7 @@ void imgLoader::CheckCacheLimits(imgCacheTable &cache, imgCacheQueue &queue)
+ 
+ bool imgLoader::ValidateRequestWithNewChannel(imgRequest *request,
+                                                 nsIURI *aURI,
+-                                                nsIURI *aInitialDocumentURI,
++                                                nsIURI *aFirstPartyURI,
+                                                 nsIURI *aReferrerURI,
+                                                 nsILoadGroup *aLoadGroup,
+                                                 imgIDecoderObserver *aObserver,
+@@ -1257,7 +1282,7 @@ bool imgLoader::ValidateRequestWithNewChannel(imgRequest *request,
+     rv = NewImageChannel(getter_AddRefs(newChannel),
+                          &forcePrincipalCheck,
+                          aURI,
+-                         aInitialDocumentURI,
++                         aFirstPartyURI,
+                          aReferrerURI,
+                          aLoadGroup,
+                          mAcceptHeader,
+@@ -1326,7 +1351,7 @@ bool imgLoader::ValidateRequestWithNewChannel(imgRequest *request,
+ 
+ bool imgLoader::ValidateEntry(imgCacheEntry *aEntry,
+                                 nsIURI *aURI,
+-                                nsIURI *aInitialDocumentURI,
++                                nsIURI *aFirstPartyURI,
+                                 nsIURI *aReferrerURI,
+                                 nsILoadGroup *aLoadGroup,
+                                 imgIDecoderObserver *aObserver,
+@@ -1432,7 +1457,7 @@ bool imgLoader::ValidateEntry(imgCacheEntry *aEntry,
+   if (validateRequest && aCanMakeNewChannel) {
+     LOG_SCOPE(gImgLog, "imgLoader::ValidateRequest |cache hit| must validate");
+ 
+-    return ValidateRequestWithNewChannel(request, aURI, aInitialDocumentURI,
++    return ValidateRequestWithNewChannel(request, aURI, aFirstPartyURI,
+                                          aReferrerURI, aLoadGroup, aObserver,
+                                          aCX, aLoadFlags, aExistingRequest,
+                                          aProxyRequest, aPolicy,
+@@ -1442,16 +1467,32 @@ bool imgLoader::ValidateEntry(imgCacheEntry *aEntry,
+   return !validateRequest;
+ }
+ 
+-
+-bool imgLoader::RemoveFromCache(nsIURI *aKey)
++bool imgLoader::RemoveMatchingUrlsFromCache(nsIURI *aKey)
+ {
+-  if (!aKey) return false;
+-
++  bool rv = true;
+   imgCacheTable &cache = GetCache(aKey);
+-  imgCacheQueue &queue = GetCacheQueue(aKey);
+ 
+-  nsCAutoString spec;
+-  aKey->GetSpec(spec);
++  // We have to make a temporary, since RemoveFromCache removes the element
++  // from the queue, invalidating iterators.
++  nsTArray<nsRefPtr<imgCacheEntry> > entries;
++  cache.Enumerate(EnumAllEntries, &entries);
++
++  for (PRUint32 i = 0; i < entries.Length(); ++i) {
++    bool isEqual = false;
++
++    entries[i]->mRequest->mURI->Equals(aKey, &isEqual);
++    if (isEqual && !RemoveFromCache(entries[i]))
++      rv = false;
++  }
++
++  return rv;
++}
++
++bool imgLoader::RemoveKeyFromCache(imgCacheTable &cache, 
++                                   imgCacheQueue &queue,
++                                   nsCAutoString spec)
++{
++  if (spec.IsEmpty()) return false;
+ 
+   LOG_STATIC_FUNC_WITH_PARAM(gImgLog, "imgLoader::RemoveFromCache", "uri", spec.get());
+ 
+@@ -1485,12 +1526,13 @@ bool imgLoader::RemoveFromCache(imgCacheEntry *entry)
+ 
+   nsRefPtr<imgRequest> request(getter_AddRefs(entry->GetRequest()));
+   if (request) {
+-    nsCOMPtr<nsIURI> key;
+-    if (NS_SUCCEEDED(request->GetURI(getter_AddRefs(key))) && key) {
+-      imgCacheTable &cache = GetCache(key);
+-      imgCacheQueue &queue = GetCacheQueue(key);
+-      nsCAutoString spec;
+-      key->GetSpec(spec);
++    nsCOMPtr<nsIURI> imgURI = request->mURI;
++    nsCOMPtr<nsIURI> firstPartyURI = request->mFirstPartyURI;
++
++    if (imgURI && firstPartyURI) {
++      imgCacheTable &cache = GetCache(imgURI);
++      imgCacheQueue &queue = GetCacheQueue(imgURI);
++      nsCAutoString spec = GetCacheKey(firstPartyURI, imgURI);
+ 
+       LOG_STATIC_FUNC_WITH_PARAM(gImgLog, "imgLoader::RemoveFromCache", "entry's uri", spec.get());
+ 
+@@ -1513,18 +1555,6 @@ bool imgLoader::RemoveFromCache(imgCacheEntry *entry)
+   return false;
+ }
+ 
+-static PLDHashOperator EnumEvictEntries(const nsACString&, 
+-                                        nsRefPtr<imgCacheEntry> &aData,
+-                                        void *data)
+-{
+-  nsTArray<nsRefPtr<imgCacheEntry> > *entries = 
+-    reinterpret_cast<nsTArray<nsRefPtr<imgCacheEntry> > *>(data);
+-
+-  entries->AppendElement(aData);
+-
+-  return PL_DHASH_NEXT;
+-}
+-
+ nsresult imgLoader::EvictEntries(imgCacheTable &aCacheToClear)
+ {
+   LOG_STATIC_FUNC(gImgLog, "imgLoader::EvictEntries table");
+@@ -1532,7 +1562,7 @@ nsresult imgLoader::EvictEntries(imgCacheTable &aCacheToClear)
+   // We have to make a temporary, since RemoveFromCache removes the element
+   // from the queue, invalidating iterators.
+   nsTArray<nsRefPtr<imgCacheEntry> > entries;
+-  aCacheToClear.Enumerate(EnumEvictEntries, &entries);
++  aCacheToClear.Enumerate(EnumAllEntries, &entries);
+ 
+   for (PRUint32 i = 0; i < entries.Length(); ++i)
+     if (!RemoveFromCache(entries[i]))
+@@ -1565,11 +1595,10 @@ nsresult imgLoader::EvictEntries(imgCacheQueue &aQueueToClear)
+                                   nsIRequest::VALIDATE_NEVER |    \
+                                   nsIRequest::VALIDATE_ONCE_PER_SESSION)
+ 
+-
+-/* imgIRequest loadImage (in nsIURI aURI, in nsIURI initialDocumentURI, in nsIPrincipal loadingPrincipal, in nsILoadGroup aLoadGroup, in imgIDecoderObserver aObserver, in nsISupports aCX, in nsLoadFlags aLoadFlags, in nsISupports cacheKey, in imgIRequest aRequest); */
++/* imgIRequest loadImage (in nsIURI aURI, in nsIURI aUrlBarURI, in nsIPrincipal loadingPrincipal, in nsILoadGroup aLoadGroup, in imgIDecoderObserver aObserver, in nsISupports aCX, in nsLoadFlags aLoadFlags, in nsISupports cacheKey, in imgIRequest aRequest); */
+ 
+ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI, 
+-                                   nsIURI *aInitialDocumentURI,
++                                   nsIURI *aFirstPartyURI,
+                                    nsIURI *aReferrerURI,
+                                    nsIPrincipal* aLoadingPrincipal,
+                                    nsILoadGroup *aLoadGroup,
+@@ -1588,8 +1617,8 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI,
+   if (!aURI)
+     return NS_ERROR_NULL_POINTER;
+ 
+-  nsCAutoString spec;
+-  aURI->GetSpec(spec);
++  nsCAutoString spec = GetCacheKey(aFirstPartyURI, aURI);
++
+   LOG_SCOPE_WITH_PARAM(gImgLog, "imgLoader::LoadImage", "aURI", spec.get());
+ 
+   *_retval = nsnull;
+@@ -1641,7 +1670,7 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI,
+   imgCacheTable &cache = GetCache(aURI);
+ 
+   if (cache.Get(spec, getter_AddRefs(entry)) && entry) {
+-    if (ValidateEntry(entry, aURI, aInitialDocumentURI, aReferrerURI,
++    if (ValidateEntry(entry, aURI, aFirstPartyURI, aReferrerURI,
+                       aLoadGroup, aObserver, aCX, requestFlags, true,
+                       aRequest, _retval, aPolicy, aLoadingPrincipal, corsmode)) {
+       request = getter_AddRefs(entry->GetRequest());
+@@ -1680,7 +1709,7 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI,
+     rv = NewImageChannel(getter_AddRefs(newChannel),
+                          &forcePrincipalCheck,
+                          aURI,
+-                         aInitialDocumentURI,
++                         aFirstPartyURI,
+                          aReferrerURI,
+                          aLoadGroup,
+                          mAcceptHeader,
+@@ -1702,8 +1731,8 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI,
+         do_CreateInstance(NS_LOADGROUP_CONTRACTID);
+     newChannel->SetLoadGroup(loadGroup);
+ 
+-    request->Init(aURI, aURI, loadGroup, newChannel, entry, aCX,
+-                  aLoadingPrincipal, corsmode);
++    request->Init(aURI, aURI, aFirstPartyURI, loadGroup, newChannel, entry,
++                  aCX, aLoadingPrincipal, corsmode);
+ 
+     // Pass the inner window ID of the loading document, if possible.
+     nsCOMPtr<nsIDocument> doc = do_QueryInterface(aCX);
+@@ -1751,7 +1780,7 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI,
+     }
+ 
+     // Try to add the new request into the cache.
+-    PutIntoCache(aURI, entry);
++    PutIntoCache(spec, entry);
+   } else {
+     LOG_MSG_WITH_PARAM(gImgLog, 
+                        "imgLoader::LoadImage |cache hit|", "request", request);
+@@ -1811,6 +1840,21 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI,
+   return NS_OK;
+ }
+ 
++nsCAutoString imgLoader::GetCacheKey(nsIURI *firstPartyURI, nsIURI *imgURI)
++{
++  nsCAutoString spec, hostKey;
++  imgURI->GetSpec(spec);
++
++  // FIXME: Should we use mozIThirdPartyUtil to get a domain from this?
++  firstPartyURI->GetHost(hostKey);
++
++  // Make a new key using host
++  // FIXME: This might involve a couple more copies than necessary.. 
++  // But man, 18 string types? Who knows which one I need to use to do
++  // this cheaply..
++  return hostKey + nsCAutoString("&") + spec;
++}
++
+ /* imgIRequest loadImageWithChannel(in nsIChannel channel, in imgIDecoderObserver aObserver, in nsISupports cx, out nsIStreamListener); */
+ NS_IMETHODIMP imgLoader::LoadImageWithChannel(nsIChannel *channel, imgIDecoderObserver *aObserver, nsISupports *aCX, nsIStreamListener **listener, imgIRequest **_retval)
+ {
+@@ -1821,22 +1865,27 @@ NS_IMETHODIMP imgLoader::LoadImageWithChannel(nsIChannel *channel, imgIDecoderOb
+   nsCOMPtr<nsIURI> uri;
+   channel->GetURI(getter_AddRefs(uri));
+ 
++  nsCOMPtr<nsIURI> firstPartyURI;
++  nsCOMPtr<mozIThirdPartyUtil> thirdPartySvc
++                               = do_GetService(THIRDPARTYUTIL_CONTRACTID);
++  thirdPartySvc->GetFirstPartyURI(channel, nsnull,
++                                  getter_AddRefs(firstPartyURI));
++
+   nsLoadFlags requestFlags = nsIRequest::LOAD_NORMAL;
+   channel->GetLoadFlags(&requestFlags);
+ 
+   nsRefPtr<imgCacheEntry> entry;
++  imgCacheTable &cache = GetCache(uri);
++  nsCAutoString spec = GetCacheKey(firstPartyURI, uri);
+ 
+   if (requestFlags & nsIRequest::LOAD_BYPASS_CACHE) {
+-    RemoveFromCache(uri);
++    imgCacheQueue &queue = GetCacheQueue(uri);
++    RemoveKeyFromCache(cache, queue, spec);
+   } else {
+     // Look in the cache for our URI, and then validate it.
+     // XXX For now ignore aCacheKey. We will need it in the future
+     // for correctly dealing with image load requests that are a result
+-    // of post data.
+-    imgCacheTable &cache = GetCache(uri);
+-    nsCAutoString spec;
+-
+-    uri->GetSpec(spec);
++    // of post data
+ 
+     if (cache.Get(spec, getter_AddRefs(entry)) && entry) {
+       // We don't want to kick off another network load. So we ask
+@@ -1908,7 +1957,7 @@ NS_IMETHODIMP imgLoader::LoadImageWithChannel(nsIChannel *channel, imgIDecoderOb
+     channel->GetOriginalURI(getter_AddRefs(originalURI));
+ 
+     // No principal specified here, because we're not passed one.
+-    request->Init(originalURI, uri, channel, channel, entry,
++    request->Init(originalURI, uri, firstPartyURI, channel, channel, entry,
+                   aCX, nsnull, imgIRequest::CORS_NONE);
+ 
+     ProxyListener *pl = new ProxyListener(static_cast<nsIStreamListener *>(request.get()));
+@@ -1920,7 +1969,7 @@ NS_IMETHODIMP imgLoader::LoadImageWithChannel(nsIChannel *channel, imgIDecoderOb
+     NS_RELEASE(pl);
+ 
+     // Try to add the new request into the cache.
+-    PutIntoCache(originalURI, entry);
++    PutIntoCache(GetCacheKey(originalURI, firstPartyURI), entry);
+ 
+     rv = CreateNewProxyForRequest(request, loadGroup, aObserver,
+                                   requestFlags, nsnull, _retval);
+@@ -2207,6 +2256,7 @@ NS_IMETHODIMP imgCacheValidator::OnStartRequest(nsIRequest *aRequest, nsISupport
+ 
+   PRInt32 corsmode = mRequest->GetCORSMode();
+   nsCOMPtr<nsIPrincipal> loadingPrincipal = mRequest->GetLoadingPrincipal();
++  nsCOMPtr<nsIURI> firstPartyURI = mRequest->mFirstPartyURI;
+ 
+   // Doom the old request's cache entry
+   mRequest->RemoveFromCache();
+@@ -2217,16 +2267,16 @@ NS_IMETHODIMP imgCacheValidator::OnStartRequest(nsIRequest *aRequest, nsISupport
+   // We use originalURI here to fulfil the imgIRequest contract on GetURI.
+   nsCOMPtr<nsIURI> originalURI;
+   channel->GetOriginalURI(getter_AddRefs(originalURI));
+-  mNewRequest->Init(originalURI, uri, aRequest, channel, mNewEntry,
+-                    mContext, loadingPrincipal,
+-                    corsmode);
++  mNewRequest->Init(originalURI, uri, firstPartyURI, aRequest, channel,
++                    mNewEntry, mContext, loadingPrincipal, corsmode);
+ 
+   mDestListener = new ProxyListener(mNewRequest);
+ 
+   // Try to add the new request into the cache. Note that the entry must be in
+   // the cache before the proxies' ownership changes, because adding a proxy
+   // changes the caching behaviour for imgRequests.
+-  sImgLoader.PutIntoCache(originalURI, mNewEntry);
++  sImgLoader.PutIntoCache(imgLoader::GetCacheKey(firstPartyURI, originalURI),
++                          mNewEntry);
+ 
+   PRUint32 count = mProxies.Count();
+   for (PRInt32 i = count-1; i>=0; i--) {
+diff --git a/image/src/imgLoader.h b/image/src/imgLoader.h
+index c0ba1d4..22671b3 100644
+--- a/image/src/imgLoader.h
++++ b/image/src/imgLoader.h
+@@ -261,10 +261,11 @@ public:
+ 
+   static nsresult InitCache();
+ 
+-  static bool RemoveFromCache(nsIURI *aKey);
++  static nsCAutoString GetCacheKey(nsIURI *firstPartyURI,
++                                   nsIURI *imgURI);
+   static bool RemoveFromCache(imgCacheEntry *entry);
+-
+-  static bool PutIntoCache(nsIURI *key, imgCacheEntry *entry);
++  static bool PutIntoCache(nsCAutoString key, imgCacheEntry *entry);
++  static bool RemoveMatchingUrlsFromCache(nsIURI *aKey);
+ 
+   // Returns true if we should prefer evicting cache entry |two| over cache
+   // entry |one|.
+@@ -349,9 +350,15 @@ private: // methods
+   static void CacheEntriesChanged(nsIURI *aURI, PRInt32 sizediff = 0);
+   static void CheckCacheLimits(imgCacheTable &cache, imgCacheQueue &queue);
+ 
++  static bool RemoveKeyFromCache(imgCacheTable &cache, 
++                                 imgCacheQueue &queue,
++                                 nsCAutoString key);
++
++
+ private: // data
+   friend class imgCacheEntry;
+   friend class imgMemoryReporter;
++  friend class imgRequest;
+ 
+   static imgCacheTable sCache;
+   static imgCacheQueue sCacheQueue;
+diff --git a/image/src/imgRequest.cpp b/image/src/imgRequest.cpp
+index 85ec2fa..cc40e86 100644
+--- a/image/src/imgRequest.cpp
++++ b/image/src/imgRequest.cpp
+@@ -137,6 +137,7 @@ imgRequest::~imgRequest()
+ 
+ nsresult imgRequest::Init(nsIURI *aURI,
+                           nsIURI *aCurrentURI,
++                          nsIURI *aFirstPartyURI,
+                           nsIRequest *aRequest,
+                           nsIChannel *aChannel,
+                           imgCacheEntry *aCacheEntry,
+@@ -158,6 +159,7 @@ nsresult imgRequest::Init(nsIURI *aURI,
+ 
+   mURI = aURI;
+   mCurrentURI = aCurrentURI;
++  mFirstPartyURI = aFirstPartyURI;
+   mRequest = aRequest;
+   mChannel = aChannel;
+   mTimedChannel = do_QueryInterface(mChannel);
+@@ -351,8 +353,11 @@ void imgRequest::RemoveFromCache()
+     // mCacheEntry is nulled out when we have no more observers.
+     if (mCacheEntry)
+       imgLoader::RemoveFromCache(mCacheEntry);
+-    else
+-      imgLoader::RemoveFromCache(mURI);
++    else {
++      imgLoader::RemoveKeyFromCache(imgLoader::GetCache(mURI),
++                                    imgLoader::GetCacheQueue(mURI),
++                                    imgLoader::GetCacheKey(mFirstPartyURI, mURI));
++    }
+   }
+ 
+   mCacheEntry = nsnull;
+diff --git a/image/src/imgRequest.h b/image/src/imgRequest.h
+index 7b200df..6ae7ae7 100644
+--- a/image/src/imgRequest.h
++++ b/image/src/imgRequest.h
+@@ -91,6 +91,7 @@ public:
+ 
+   nsresult Init(nsIURI *aURI,
+                 nsIURI *aCurrentURI,
++                nsIURI *aFirstPartyURI,
+                 nsIRequest *aRequest,
+                 nsIChannel *aChannel,
+                 imgCacheEntry *aCacheEntry,
+@@ -221,6 +222,8 @@ private:
+   nsCOMPtr<nsIURI> mURI;
+   // The URI of the resource we ended up loading after all redirects, etc.
+   nsCOMPtr<nsIURI> mCurrentURI;
++  // The first party that triggered the load -- for cookie + cache isolation
++  nsCOMPtr<nsIURI> mFirstPartyURI;
+   // The principal of the document which loaded this image. Used when validating for CORS.
+   nsCOMPtr<nsIPrincipal> mLoadingPrincipal;
+   // The principal of this image.
+diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp
+index 807aa6c..7bb866b 100644
+--- a/layout/generic/nsImageFrame.cpp
++++ b/layout/generic/nsImageFrame.cpp
+@@ -96,6 +96,7 @@
+ #include "nsLayoutErrors.h"
+ #include "nsBidiUtils.h"
+ #include "nsBidiPresUtils.h"
++#include "mozIThirdPartyUtil.h"
+ 
+ #include "gfxRect.h"
+ #include "ImageLayers.h"
+@@ -1760,9 +1761,17 @@ nsImageFrame::LoadIcon(const nsAString& aSpec,
+ 
+   // For icon loads, we don't need to merge with the loadgroup flags
+   nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL;
++  
++  nsCOMPtr<nsIURI> firstPartyURI;
++  nsCOMPtr<mozIThirdPartyUtil> thirdPartySvc
++      = do_GetService(THIRDPARTYUTIL_CONTRACTID);
++  // XXX: Should we pass the loadgroup, too? Is document ever likely
++  // to be unset?
++  thirdPartySvc->GetFirstPartyURI(nsnull, aPresContext->Document(),
++                                 getter_AddRefs(firstPartyURI));
+ 
+   return il->LoadImage(realURI,     /* icon URI */
+-                       nsnull,      /* initial document URI; this is only
++                       firstPartyURI,      /* initial document URI; this is only
+                                        relevant for cookies, so does not
+                                        apply to icons. */
+                        nsnull,      /* referrer (not relevant for icons) */
+diff --git a/netwerk/base/public/mozIThirdPartyUtil.idl b/netwerk/base/public/mozIThirdPartyUtil.idl
+index ad41985..fd2cb38 100644
+--- a/netwerk/base/public/mozIThirdPartyUtil.idl
++++ b/netwerk/base/public/mozIThirdPartyUtil.idl
+@@ -40,6 +40,7 @@
+ interface nsIURI;
+ interface nsIDOMWindow;
+ interface nsIChannel;
++interface nsIDocument;
+ 
+ /**
+  * Utility functions for determining whether a given URI, channel, or window
+@@ -173,6 +174,26 @@ interface mozIThirdPartyUtil : nsISupports
+    * @return the base domain.
+    */
+   AUTF8String getBaseDomain(in nsIURI aHostURI);
++
++
++  /**
++   * getFirstPartyURI
++   *
++   * Obtain the top-level url bar URI for either a channel or a document.
++   * Either parameter may be null (but not both).
++   * 
++   * @param aChannel
++   *        An arbitrary channel for some content element of a first party
++   *        load. Can be null.
++   *
++   * @param aDoc
++   *        An arbitrary third party document. Can be null.
++   *
++   * @return the first party url bar URI for the load.
++   */ 
++  nsIURI getFirstPartyURI(in nsIChannel aChannel,
++                          in nsIDocument aDoc);
++
+ };
+ 
+ %{ C++
+diff --git a/netwerk/cookie/nsICookiePermission.idl b/netwerk/cookie/nsICookiePermission.idl
+index c7f765b..d81e2e6 100644
+--- a/netwerk/cookie/nsICookiePermission.idl
++++ b/netwerk/cookie/nsICookiePermission.idl
+@@ -40,6 +40,7 @@
+ interface nsICookie2;
+ interface nsIURI;
+ interface nsIChannel;
++interface nsIDocument;
+ 
+ typedef long nsCookieAccess;
+ 
+diff --git a/toolkit/system/gnome/nsAlertsIconListener.cpp b/toolkit/system/gnome/nsAlertsIconListener.cpp
+index 250e4fb..614e70f 100644
+--- a/toolkit/system/gnome/nsAlertsIconListener.cpp
++++ b/toolkit/system/gnome/nsAlertsIconListener.cpp
+@@ -271,7 +271,8 @@ nsAlertsIconListener::StartRequest(const nsAString & aImageUrl)
+   if (!il)
+     return ShowAlert(NULL);
+ 
+-  return il->LoadImage(imageUri, nsnull, nsnull, nsnull, nsnull, this,
++  // XXX: Hrmm.... Bypass cache, or isolate to imageUrl?
++  return il->LoadImage(imageUri, imageUri, nsnull, nsnull, nsnull, this,
+                        nsnull, nsIRequest::LOAD_NORMAL, nsnull, nsnull,
+                        nsnull, getter_AddRefs(mIconRequest));
+ }
+diff --git a/widget/cocoa/nsMenuItemIconX.mm b/widget/cocoa/nsMenuItemIconX.mm
+index 9505ea2..8739c67 100644
+--- a/widget/cocoa/nsMenuItemIconX.mm
++++ b/widget/cocoa/nsMenuItemIconX.mm
+@@ -338,9 +338,15 @@ nsMenuItemIconX::LoadIcon(nsIURI* aIconURI)
+       [mNativeMenuItem setImage:sPlaceholderIconImage];
+   }
+ 
++  nsCOMPtr<nsIURI> firstPartyURI;
++  nsCOMPtr<mozIThirdPartyUtil> thirdPartySvc
++                               = do_GetService(THIRDPARTYUTIL_CONTRACTID);
++  thirdPartySvc->GetFirstPartyURI(nsnull, document,
++                                  getter_AddRefs(firstPartyURI));
++
+   // Passing in null for channelPolicy here since nsMenuItemIconX::LoadIcon is
+   // not exposed to web content
+-  rv = loader->LoadImage(aIconURI, nsnull, nsnull, nsnull, loadGroup, this,
++  rv = loader->LoadImage(aIconURI, firstPartyURI, nsnull, nsnull, loadGroup, this,
+                          nsnull, nsIRequest::LOAD_NORMAL, nsnull, nsnull,
+                          nsnull, getter_AddRefs(mIconRequest));
+   if (NS_FAILED(rv)) return rv;
+-- 
+1.7.5.4
+





More information about the tor-commits mailing list