$OpenBSD$ index 6d4111b..59ba71b 100644 --- netwerk/protocol/http/nsHttpChannel.cpp.orig Fri Feb 20 15:40:37 2015 +++ netwerk/protocol/http/nsHttpChannel.cpp Fri Feb 20 15:40:37 2015 @@ -66,6 +66,7 @@ #include "nsPerformance.h" #include "CacheObserver.h" #include "mozilla/Telemetry.h" +#include "mozIThirdPartyUtil.h" namespace mozilla { namespace net { @@ -1237,7 +1238,12 @@ nsHttpChannel::ProcessResponse() // notify "http-on-examine-response" observers gHttpHandler->OnExamineResponse(this); - SetCookie(mResponseHead->PeekHeader(nsHttp::Set_Cookie)); + // Cookies should not be handled on proxy failure either. + // This would be consolidated with ProcessSecurityHeaders but it should + // happen after OnExamineResponse. + if (!mTransaction->ProxyConnectFailed() && (httpStatus != 407)) { + SetCookie(mResponseHead->PeekHeader(nsHttp::Set_Cookie)); + } // handle unused username and password in url (see bug 232567) if (httpStatus != 401 && httpStatus != 407) { @@ -1823,10 +1829,10 @@ nsHttpChannel::ResolveProxy() // then it is ok to use that version. nsCOMPtr pps2 = do_QueryInterface(pps); if (pps2) { - rv = pps2->AsyncResolve2(mProxyURI ? mProxyURI : mURI, mProxyResolveFlags, + rv = pps2->AsyncResolve2(this, mProxyResolveFlags, this, getter_AddRefs(mProxyRequest)); } else { - rv = pps->AsyncResolve(mProxyURI ? mProxyURI : mURI, mProxyResolveFlags, + rv = pps->AsyncResolve(this, mProxyResolveFlags, this, getter_AddRefs(mProxyRequest)); } @@ -2558,6 +2564,19 @@ nsHttpChannel::OpenCacheEntry(bool usingSSL) nsRefPtr info = GetLoadContextInfo(this); nsCOMPtr cacheStorage; nsCOMPtr openURI; + + /* Obtain optional third party isolation domain */ + nsAutoCString cacheDomain; + nsCOMPtr firstPartyIsolationURI; + nsCOMPtr thirdPartySvc + = do_GetService(THIRDPARTYUTIL_CONTRACTID); + rv = thirdPartySvc->GetFirstPartyIsolationURI(this, nullptr, + getter_AddRefs(firstPartyIsolationURI)); + if (NS_SUCCEEDED(rv) && firstPartyIsolationURI) { + thirdPartySvc->GetFirstPartyHostForIsolation(firstPartyIsolationURI, + cacheDomain); + } + if (!mFallbackKey.IsEmpty() && mFallbackChannel) { // This is a fallback channel, open fallback URI instead rv = NS_NewURI(getter_AddRefs(openURI), mFallbackKey); @@ -2612,7 +2631,7 @@ nsHttpChannel::OpenCacheEntry(bool usingSSL) cacheEntryOpenFlags |= nsICacheStorage::OPEN_BYPASS_IF_BUSY; rv = cacheStorage->AsyncOpenURI( - openURI, mPostID ? nsPrintfCString("%d", mPostID) : EmptyCString(), + openURI, nsPrintfCString("%s@%d", cacheDomain.get(), mPostID), cacheEntryOpenFlags, this); NS_ENSURE_SUCCESS(rv, rv); @@ -2647,7 +2666,7 @@ bypassCacheEntryOpen: NS_ENSURE_SUCCESS(rv, rv); rv = cacheStorage->AsyncOpenURI( - mURI, EmptyCString(), nsICacheStorage::OPEN_TRUNCATE, this); + mURI, cacheDomain, nsICacheStorage::OPEN_TRUNCATE, this); NS_ENSURE_SUCCESS(rv, rv); waitFlags.Keep(WAIT_FOR_OFFLINE_CACHE_ENTRY); @@ -3252,6 +3271,12 @@ nsHttpChannel::AssembleCacheKey(const char *spec, uint32_t postID, cacheKey.Append(buf); } + if (strlen(mCacheDomain.get()) > 0) { + cacheKey.AppendLiteral("domain="); + cacheKey.Append(mCacheDomain.get()); + cacheKey.AppendLiteral("&"); + } + if (!cacheKey.IsEmpty()) { cacheKey.AppendLiteral("uri="); } @@ -4575,6 +4600,8 @@ nsHttpChannel::BeginConnect() // notify "http-on-modify-request" observers CallOnModifyRequestObservers(); + RemoveAuthorizationHeaderIfAppropriate(); + // Check to see if we should redirect this channel elsewhere by // nsIHttpChannel.redirectTo API request if (mAPIRedirectToURI) { @@ -4701,7 +4728,7 @@ nsHttpChannel::SetPriority(int32_t value) //----------------------------------------------------------------------------- NS_IMETHODIMP -nsHttpChannel::OnProxyAvailable(nsICancelable *request, nsIURI *uri, +nsHttpChannel::OnProxyAvailable(nsICancelable *request, nsIChannel *channel, nsIProxyInfo *pi, nsresult status) { LOG(("nsHttpChannel::OnProxyAvailable [this=%p pi=%p status=%x mStatus=%x]\n", @@ -5083,7 +5110,7 @@ nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult st // nsRefPtr conn; if (authRetry && (mCaps & NS_HTTP_STICKY_CONNECTION)) { - conn = mTransaction->Connection(); + conn = mTransaction->GetConnectionReference(); // This is so far a workaround to fix leak when reusing unpersistent // connection for authentication retry. See bug 459620 comment 4 // for details. @@ -5093,7 +5120,7 @@ nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult st nsRefPtr stickyConn; if (mCaps & NS_HTTP_STICKY_CONNECTION) - stickyConn = mTransaction->Connection(); + stickyConn = mTransaction->GetConnectionReference(); // at this point, we're done with the transaction mTransactionTimings = mTransaction->Timings(); @@ -5536,6 +5563,23 @@ nsHttpChannel::SetCacheTokenCachedCharset(const nsACString &aCharset) PromiseFlatCString(aCharset).get()); } + +NS_IMETHODIMP +nsHttpChannel::GetCacheDomain(nsACString &value) +{ + value = mCacheDomain; + + return NS_OK; +} + +NS_IMETHODIMP +nsHttpChannel::SetCacheDomain(const nsACString &value) +{ + mCacheDomain = value; + + return NS_OK; +} + //----------------------------------------------------------------------------- // nsHttpChannel::nsICachingChannel //----------------------------------------------------------------------------- @@ -5708,6 +5752,72 @@ nsHttpChannel::ResumeAt(uint64_t aStartPos, return NS_OK; } +// Remove the Authorization header if first party isolation is active and +// this channel is processing a third party request. This prevents user +// tracking via HTTP Basic Authentication. +// Note that this approach disables authentication for 3rd party domains. It +// would be better if we could isolate the authentication while still allowing +// it to be transmitted... but HTTP authentication is rarely used anyway. +void +nsHttpChannel::RemoveAuthorizationHeaderIfAppropriate() +{ + if (!mRequestHead.PeekHeader(nsHttp::Authorization)) { + return; // No Authorization header is present. + } + + nsCOMPtr thirdPartySvc + = do_GetService(THIRDPARTYUTIL_CONTRACTID); + bool isolationActive = true; + (void)thirdPartySvc->IsFirstPartyIsolationActive(this, nullptr, + &isolationActive); + if (!isolationActive) + return; // First party isolation is disabled for this channel. + + bool isAuthAllowed = false; + nsCOMPtr firstPartyURI; + nsresult rv = thirdPartySvc->GetFirstPartyURIFromChannel(this, false, + getter_AddRefs(firstPartyURI)); + if (NS_SUCCEEDED(rv) && firstPartyURI) { + isAuthAllowed = (mURI == firstPartyURI) + || HostPartIsTheSame(firstPartyURI); + } else { + // We failed to get the first party URI. Check the document URI so + // that we can allow authentication if the request originates from the + // the browser chrome, e.g., some favicon requests. If there is no + // document URI associated with this request, it cannot be associated + // with a content document, so it must be a special request (e.g., + // favicon fetch or OSCP), for which we also allow authenication. + nsCOMPtr docURI; + rv = GetDocumentURI(getter_AddRefs(docURI)); + if (NS_FAILED(rv) || !docURI) { + isAuthAllowed = true; + } else { + nsAutoCString docURISpec; + docURI->GetAsciiSpec(docURISpec); + if (docURISpec == "chrome://browser/content/browser.xul") + isAuthAllowed = true; + } + } + + if (!isAuthAllowed) { + mRequestHead.ClearHeader(nsHttp::Authorization); + mRequestHead.ClearHeader(nsHttp::Cache_Control); + mRequestHead.ClearHeader(nsHttp::Pragma); + +#ifdef PR_LOGGING + nsAutoCString requestURIStr, firstPartyURIStr; + mURI->GetAsciiSpec(requestURIStr); + if (firstPartyURI) + firstPartyURI->GetAsciiSpec(firstPartyURIStr); + else + firstPartyURIStr = "--N/A--"; + LOG(("Removed Authorization header from third party request" + " [Request URI=%s, First Party URI=%s]\n", + requestURIStr.get(), firstPartyURIStr.get())); +#endif + } +} + nsresult nsHttpChannel::DoAuthRetry(nsAHttpConnection *conn) { @@ -5729,6 +5839,8 @@ nsHttpChannel::DoAuthRetry(nsAHttpConnection *conn) // notify "http-on-modify-request" observers CallOnModifyRequestObservers(); + RemoveAuthorizationHeaderIfAppropriate(); + mIsPending = true; // get rid of the old response headers