commit d8e36b11e0b149a0d44dada9b3978f766e26c40a
Author: Mike Perry <mikeperry-git(a)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(a)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(a)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
+