Implement cookieless requests for Access-Control. b=389508 r=biesi sr=jst

This commit is contained in:
Jonas Sicking 2008-09-30 17:52:52 -07:00
parent 7a655650a9
commit cce6fbac9b
12 changed files with 292 additions and 21 deletions

View File

@ -101,7 +101,7 @@ interface nsIXMLHttpRequestUpload : nsIXMLHttpRequestEventTarget {
* you're aware of all the security implications. And then think twice about * you're aware of all the security implications. And then think twice about
* it. * it.
*/ */
[scriptable, uuid(acda85ab-d06c-4176-b834-6d129ca97ca3)] [scriptable, uuid(48ce10a0-c585-4e8f-a5f5-1ac1e47cc501)]
interface nsIXMLHttpRequest : nsISupports interface nsIXMLHttpRequest : nsISupports
{ {
/** /**
@ -321,6 +321,16 @@ interface nsIXMLHttpRequest : nsISupports
*/ */
attribute boolean mozBackgroundRequest; attribute boolean mozBackgroundRequest;
/**
* When set to true attempts to make cross-site Access-Control requests
* with credentials such as cookies and authorization headers.
*
* Never affects same-site requests.
*
* Defaults to false.
*/
attribute boolean withCredentials;
/** /**
* Initialize the object for use from C++ code with the principal, script * Initialize the object for use from C++ code with the principal, script
* context, and owner window that should be used. * context, and owner window that should be used.

View File

@ -63,9 +63,11 @@ NS_IMPL_ISUPPORTS4(nsCrossSiteListenerProxy, nsIStreamListener,
nsCrossSiteListenerProxy::nsCrossSiteListenerProxy(nsIStreamListener* aOuter, nsCrossSiteListenerProxy::nsCrossSiteListenerProxy(nsIStreamListener* aOuter,
nsIPrincipal* aRequestingPrincipal, nsIPrincipal* aRequestingPrincipal,
nsIChannel* aChannel, nsIChannel* aChannel,
PRBool aWithCredentials,
nsresult* aResult) nsresult* aResult)
: mOuterListener(aOuter), : mOuterListener(aOuter),
mRequestingPrincipal(aRequestingPrincipal), mRequestingPrincipal(aRequestingPrincipal),
mWithCredentials(aWithCredentials),
mRequestApproved(PR_FALSE), mRequestApproved(PR_FALSE),
mHasBeenCrossSite(PR_FALSE), mHasBeenCrossSite(PR_FALSE),
mIsPreflight(PR_FALSE) mIsPreflight(PR_FALSE)
@ -80,11 +82,13 @@ nsCrossSiteListenerProxy::nsCrossSiteListenerProxy(nsIStreamListener* aOuter,
nsCrossSiteListenerProxy::nsCrossSiteListenerProxy(nsIStreamListener* aOuter, nsCrossSiteListenerProxy::nsCrossSiteListenerProxy(nsIStreamListener* aOuter,
nsIPrincipal* aRequestingPrincipal, nsIPrincipal* aRequestingPrincipal,
nsIChannel* aChannel, nsIChannel* aChannel,
PRBool aWithCredentials,
const nsCString& aPreflightMethod, const nsCString& aPreflightMethod,
const nsTArray<nsCString>& aPreflightHeaders, const nsTArray<nsCString>& aPreflightHeaders,
nsresult* aResult) nsresult* aResult)
: mOuterListener(aOuter), : mOuterListener(aOuter),
mRequestingPrincipal(aRequestingPrincipal), mRequestingPrincipal(aRequestingPrincipal),
mWithCredentials(aWithCredentials),
mRequestApproved(PR_FALSE), mRequestApproved(PR_FALSE),
mHasBeenCrossSite(PR_FALSE), mHasBeenCrossSite(PR_FALSE),
mIsPreflight(PR_TRUE), mIsPreflight(PR_TRUE),
@ -219,7 +223,7 @@ nsCrossSiteListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
NS_LITERAL_CSTRING("Access-Control-Allow-Origin"), allowedOriginHeader); NS_LITERAL_CSTRING("Access-Control-Allow-Origin"), allowedOriginHeader);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
if (!allowedOriginHeader.EqualsLiteral("*")) { if (mWithCredentials || !allowedOriginHeader.EqualsLiteral("*")) {
nsCAutoString origin; nsCAutoString origin;
rv = GetOrigin(mRequestingPrincipal, origin); rv = GetOrigin(mRequestingPrincipal, origin);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
@ -229,6 +233,17 @@ nsCrossSiteListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
} }
} }
// Check Access-Control-Allow-Credentials header
if (mWithCredentials) {
nsCAutoString allowCredentialsHeader;
rv = http->GetResponseHeader(
NS_LITERAL_CSTRING("Access-Control-Allow-Credentials"), allowCredentialsHeader);
NS_ENSURE_SUCCESS(rv, rv);
if (!allowCredentialsHeader.EqualsLiteral("true")) {
return NS_ERROR_DOM_BAD_URI;
}
}
if (mIsPreflight) { if (mIsPreflight) {
nsCAutoString headerVal; nsCAutoString headerVal;
@ -391,5 +406,16 @@ nsCrossSiteListenerProxy::UpdateChannel(nsIChannel* aChannel)
} }
} }
// Make cookie-less if needed
if (mIsPreflight || !mWithCredentials) {
nsLoadFlags flags;
rv = http->GetLoadFlags(&flags);
NS_ENSURE_SUCCESS(rv, rv);
flags |= nsIRequest::LOAD_ANONYMOUS;
rv = http->SetLoadFlags(flags);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK; return NS_OK;
} }

View File

@ -62,10 +62,12 @@ public:
nsCrossSiteListenerProxy(nsIStreamListener* aOuter, nsCrossSiteListenerProxy(nsIStreamListener* aOuter,
nsIPrincipal* aRequestingPrincipal, nsIPrincipal* aRequestingPrincipal,
nsIChannel* aChannel, nsIChannel* aChannel,
PRBool aWithCredentials,
nsresult* aResult); nsresult* aResult);
nsCrossSiteListenerProxy(nsIStreamListener* aOuter, nsCrossSiteListenerProxy(nsIStreamListener* aOuter,
nsIPrincipal* aRequestingPrincipal, nsIPrincipal* aRequestingPrincipal,
nsIChannel* aChannel, nsIChannel* aChannel,
PRBool aWithCredentials,
const nsCString& aPreflightMethod, const nsCString& aPreflightMethod,
const nsTArray<nsCString>& aPreflightHeaders, const nsTArray<nsCString>& aPreflightHeaders,
nsresult* aResult); nsresult* aResult);
@ -83,6 +85,7 @@ private:
nsCOMPtr<nsIStreamListener> mOuterListener; nsCOMPtr<nsIStreamListener> mOuterListener;
nsCOMPtr<nsIPrincipal> mRequestingPrincipal; nsCOMPtr<nsIPrincipal> mRequestingPrincipal;
nsCOMPtr<nsIInterfaceRequestor> mOuterNotificationCallbacks; nsCOMPtr<nsIInterfaceRequestor> mOuterNotificationCallbacks;
PRBool mWithCredentials;
PRBool mRequestApproved; PRBool mRequestApproved;
PRBool mHasBeenCrossSite; PRBool mHasBeenCrossSite;
PRBool mIsPreflight; PRBool mIsPreflight;

View File

@ -221,7 +221,7 @@ nsSyncLoader::LoadDocument(nsIChannel* aChannel,
if (aLoaderPrincipal) { if (aLoaderPrincipal) {
listener = new nsCrossSiteListenerProxy(listener, aLoaderPrincipal, listener = new nsCrossSiteListenerProxy(listener, aLoaderPrincipal,
mChannel, &rv); mChannel, PR_FALSE, &rv);
NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY); NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
} }

View File

@ -127,6 +127,7 @@
#define XML_HTTP_REQUEST_MPART_HEADERS (1 << 15) // Internal #define XML_HTTP_REQUEST_MPART_HEADERS (1 << 15) // Internal
#define XML_HTTP_REQUEST_USE_XSITE_AC (1 << 16) // Internal #define XML_HTTP_REQUEST_USE_XSITE_AC (1 << 16) // Internal
#define XML_HTTP_REQUEST_NEED_AC_PREFLIGHT (1 << 17) // Internal #define XML_HTTP_REQUEST_NEED_AC_PREFLIGHT (1 << 17) // Internal
#define XML_HTTP_REQUEST_AC_WITH_CREDENTIALS (1 << 18) // Internal
#define XML_HTTP_REQUEST_LOADSTATES \ #define XML_HTTP_REQUEST_LOADSTATES \
(XML_HTTP_REQUEST_UNINITIALIZED | \ (XML_HTTP_REQUEST_UNINITIALIZED | \
@ -293,10 +294,11 @@ public:
nsIStreamListener* aOuterListener, nsIStreamListener* aOuterListener,
nsISupports* aOuterContext, nsISupports* aOuterContext,
nsIPrincipal* aReferrerPrincipal, nsIPrincipal* aReferrerPrincipal,
const nsACString& aRequestMethod) const nsACString& aRequestMethod,
PRBool aWithCredentials)
: mOuterChannel(aOuterChannel), mOuterListener(aOuterListener), : mOuterChannel(aOuterChannel), mOuterListener(aOuterListener),
mOuterContext(aOuterContext), mReferrerPrincipal(aReferrerPrincipal), mOuterContext(aOuterContext), mReferrerPrincipal(aReferrerPrincipal),
mRequestMethod(aRequestMethod) mRequestMethod(aRequestMethod), mWithCredentials(aWithCredentials)
{ } { }
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
@ -313,6 +315,7 @@ private:
nsCOMPtr<nsISupports> mOuterContext; nsCOMPtr<nsISupports> mOuterContext;
nsCOMPtr<nsIPrincipal> mReferrerPrincipal; nsCOMPtr<nsIPrincipal> mReferrerPrincipal;
nsCString mRequestMethod; nsCString mRequestMethod;
PRBool mWithCredentials;
}; };
NS_IMPL_ISUPPORTS4(nsACProxyListener, nsIStreamListener, nsIRequestObserver, NS_IMPL_ISUPPORTS4(nsACProxyListener, nsIStreamListener, nsIRequestObserver,
@ -366,7 +369,7 @@ nsACProxyListener::AddResultToCache(nsIRequest *aRequest)
nsAccessControlLRUCache::CacheEntry* entry = nsAccessControlLRUCache::CacheEntry* entry =
nsXMLHttpRequest::sAccessControlCache-> nsXMLHttpRequest::sAccessControlCache->
GetEntry(uri, mReferrerPrincipal, PR_TRUE); GetEntry(uri, mReferrerPrincipal, mWithCredentials, PR_TRUE);
if (!entry) { if (!entry) {
return; return;
} }
@ -886,10 +889,11 @@ nsAccessControlLRUCache::CacheEntry::CheckRequest(const nsCString& aMethod,
nsAccessControlLRUCache::CacheEntry* nsAccessControlLRUCache::CacheEntry*
nsAccessControlLRUCache::GetEntry(nsIURI* aURI, nsAccessControlLRUCache::GetEntry(nsIURI* aURI,
nsIPrincipal* aPrincipal, nsIPrincipal* aPrincipal,
PRBool aWithCredentials,
PRBool aCreate) PRBool aCreate)
{ {
nsCString key; nsCString key;
if (!GetCacheKey(aURI, aPrincipal, key)) { if (!GetCacheKey(aURI, aPrincipal, aWithCredentials, key)) {
NS_WARNING("Invalid cache key!"); NS_WARNING("Invalid cache key!");
return nsnull; return nsnull;
} }
@ -983,6 +987,7 @@ nsAccessControlLRUCache::RemoveExpiredEntries(const nsACString& aKey,
/* static */ PRBool /* static */ PRBool
nsAccessControlLRUCache::GetCacheKey(nsIURI* aURI, nsAccessControlLRUCache::GetCacheKey(nsIURI* aURI,
nsIPrincipal* aPrincipal, nsIPrincipal* aPrincipal,
PRBool aWithCredentials,
nsACString& _retval) nsACString& _retval)
{ {
NS_ASSERTION(aURI, "Null uri!"); NS_ASSERTION(aURI, "Null uri!");
@ -1002,11 +1007,20 @@ nsAccessControlLRUCache::GetCacheKey(nsIURI* aURI,
port.AppendInt(portInt); port.AppendInt(portInt);
} }
nsCAutoString cred;
if (aWithCredentials) {
_retval.AssignLiteral("cred");
}
else {
_retval.AssignLiteral("nocred");
}
nsCAutoString spec; nsCAutoString spec;
rv = aURI->GetSpec(spec); rv = aURI->GetSpec(spec);
NS_ENSURE_SUCCESS(rv, PR_FALSE); NS_ENSURE_SUCCESS(rv, PR_FALSE);
_retval.Assign(scheme + space + host + space + port + space + spec); _retval.Assign(cred + space + scheme + space + host + space + port + space +
spec);
return PR_TRUE; return PR_TRUE;
} }
@ -2572,6 +2586,8 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
rv = CheckChannelForCrossSiteRequest(mChannel); rv = CheckChannelForCrossSiteRequest(mChannel);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
PRBool withCredentials = !!(mState & XML_HTTP_REQUEST_AC_WITH_CREDENTIALS);
if (mState & XML_HTTP_REQUEST_USE_XSITE_AC) { if (mState & XML_HTTP_REQUEST_USE_XSITE_AC) {
// Check if we need to do a preflight request. // Check if we need to do a preflight request.
NS_ENSURE_TRUE(httpChannel, NS_ERROR_DOM_BAD_URI); NS_ENSURE_TRUE(httpChannel, NS_ERROR_DOM_BAD_URI);
@ -2610,7 +2626,7 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
nsAccessControlLRUCache::CacheEntry* entry = nsAccessControlLRUCache::CacheEntry* entry =
sAccessControlCache ? sAccessControlCache ?
sAccessControlCache->GetEntry(uri, mPrincipal, PR_FALSE) : sAccessControlCache->GetEntry(uri, mPrincipal, withCredentials, PR_FALSE) :
nsnull; nsnull;
if (!entry || !entry->CheckRequest(method, mACUnsafeHeaders)) { if (!entry || !entry->CheckRequest(method, mACUnsafeHeaders)) {
@ -2653,7 +2669,7 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
// Always create a nsCrossSiteListenerProxy here even if it's // Always create a nsCrossSiteListenerProxy here even if it's
// a same-origin request right now, since it could be redirected. // a same-origin request right now, since it could be redirected.
listener = new nsCrossSiteListenerProxy(listener, mPrincipal, mChannel, listener = new nsCrossSiteListenerProxy(listener, mPrincipal, mChannel,
&rv); withCredentials, &rv);
NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY); NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
} }
@ -2689,12 +2705,14 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
// a GET request to the same URI. Set that up if needed // a GET request to the same URI. Set that up if needed
if (mACGetChannel) { if (mACGetChannel) {
nsCOMPtr<nsIStreamListener> acProxyListener = nsCOMPtr<nsIStreamListener> acProxyListener =
new nsACProxyListener(mChannel, listener, nsnull, mPrincipal, method); new nsACProxyListener(mChannel, listener, nsnull, mPrincipal, method,
withCredentials);
NS_ENSURE_TRUE(acProxyListener, NS_ERROR_OUT_OF_MEMORY); NS_ENSURE_TRUE(acProxyListener, NS_ERROR_OUT_OF_MEMORY);
acProxyListener = acProxyListener =
new nsCrossSiteListenerProxy(acProxyListener, mPrincipal, mACGetChannel, new nsCrossSiteListenerProxy(acProxyListener, mPrincipal, mACGetChannel,
method, mACUnsafeHeaders, &rv); withCredentials, method, mACUnsafeHeaders,
&rv);
NS_ENSURE_TRUE(acProxyListener, NS_ERROR_OUT_OF_MEMORY); NS_ENSURE_TRUE(acProxyListener, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
@ -2924,6 +2942,33 @@ nsXMLHttpRequest::SetMozBackgroundRequest(PRBool aMozBackgroundRequest)
return NS_OK; return NS_OK;
} }
/* attribute boolean withCredentials; */
NS_IMETHODIMP
nsXMLHttpRequest::GetWithCredentials(PRBool *_retval)
{
*_retval = !!(mState & XML_HTTP_REQUEST_AC_WITH_CREDENTIALS);
return NS_OK;
}
/* attribute boolean withCredentials; */
NS_IMETHODIMP
nsXMLHttpRequest::SetWithCredentials(PRBool aWithCredentials)
{
// Return error if we're already processing a request
if (XML_HTTP_REQUEST_SENT & mState) {
return NS_ERROR_FAILURE;
}
if (aWithCredentials) {
mState |= XML_HTTP_REQUEST_AC_WITH_CREDENTIALS;
}
else {
mState &= ~XML_HTTP_REQUEST_AC_WITH_CREDENTIALS;
}
return NS_OK;
}
// nsIDOMEventListener // nsIDOMEventListener
nsresult nsresult

View File

@ -124,7 +124,7 @@ public:
} }
CacheEntry* GetEntry(nsIURI* aURI, nsIPrincipal* aPrincipal, CacheEntry* GetEntry(nsIURI* aURI, nsIPrincipal* aPrincipal,
PRBool aCreate); PRBool aWithCredentials, PRBool aCreate);
void Clear(); void Clear();
@ -134,7 +134,7 @@ private:
void* aUserData); void* aUserData);
static PRBool GetCacheKey(nsIURI* aURI, nsIPrincipal* aPrincipal, static PRBool GetCacheKey(nsIURI* aURI, nsIPrincipal* aPrincipal,
nsACString& _retval); PRBool aWithCredentials, nsACString& _retval);
nsClassHashtable<nsCStringHashKey, CacheEntry> mTable; nsClassHashtable<nsCStringHashKey, CacheEntry> mTable;
PRCList mList; PRCList mList;

View File

@ -55,6 +55,9 @@ window.addEventListener('message', function(e) {
post(e, res); post(e, res);
} }
if (req.withCred)
xhr.withCredentials = true;
res.events.push("opening"); res.events.push("opening");
xhr.open(req.method, req.url, true); xhr.open(req.method, req.url, true);

View File

@ -3,7 +3,7 @@ function handleRequest(request, response)
try { try {
var query = {}; var query = {};
request.queryString.split('&').forEach(function (val) { request.queryString.split('&').forEach(function (val) {
var [name, value] = val.split('='); [name, value] = val.split('=');
query[name] = unescape(value); query[name] = unescape(value);
}); });
@ -35,6 +35,24 @@ function handleRequest(request, response)
throw "Origin had wrong value. Expected " + query.origin + " got " + throw "Origin had wrong value. Expected " + query.origin + " got " +
request.getHeader("Origin"); request.getHeader("Origin");
} }
if ("cookie" in query) {
cookies = {};
request.getHeader("Cookie").split(/ *; */).forEach(function (val) {
[name, value] = val.split('=');
cookies[name] = unescape(value);
});
query.cookie.split(",").forEach(function (val) {
[name, value] = val.split('=');
if (cookies[name] != value) {
throw "Cookie " + name + " had wrong value. Expected " + value +
" got " + cookies[name];
}
});
}
if ("noCookie" in query && request.hasHeader("Cookie")) {
throw "Got cookies when didn't expect to";
}
// Send response // Send response
@ -42,6 +60,12 @@ function handleRequest(request, response)
if (query.allowOrigin && (!isPreflight || !query.noAllowPreflight)) if (query.allowOrigin && (!isPreflight || !query.noAllowPreflight))
response.setHeader("Access-Control-Allow-Origin", query.allowOrigin); response.setHeader("Access-Control-Allow-Origin", query.allowOrigin);
if (query.allowCred)
response.setHeader("Access-Control-Allow-Credentials", "true");
if (query.setCookie)
response.setHeader("Set-Cookie", query.setCookie + "; path=/");
if (isPreflight) { if (isPreflight) {
if (query.allowHeaders) if (query.allowHeaders)

View File

@ -436,6 +436,133 @@ function runTest() {
} }
// Test cookie behavior
tests = [{ pass: 1,
method: "GET",
withCred: 1,
allowCred: 1,
},
{ pass: 0,
method: "GET",
withCred: 1,
allowCred: 0,
},
{ pass: 0,
method: "GET",
withCred: 1,
allowCred: 1,
origin: "*",
},
{ pass: 1,
method: "GET",
withCred: 0,
allowCred: 1,
origin: "*",
},
{ pass: 1,
method: "GET",
setCookie: "a=1",
withCred: 1,
allowCred: 1,
},
{ pass: 1,
method: "GET",
cookie: "a=1",
withCred: 1,
allowCred: 1,
},
{ pass: 1,
method: "GET",
noCookie: 1,
withCred: 0,
allowCred: 1,
},
{ pass: 0,
method: "GET",
noCookie: 1,
withCred: 1,
allowCred: 1,
},
{ pass: 1,
method: "GET",
setCookie: "a=2",
withCred: 0,
allowCred: 1,
},
{ pass: 1,
method: "GET",
cookie: "a=1",
withCred: 1,
allowCred: 1,
},
{ pass: 1,
method: "GET",
setCookie: "a=2",
withCred: 1,
allowCred: 1,
},
{ pass: 1,
method: "GET",
cookie: "a=2",
withCred: 1,
allowCred: 1,
},
];
for each(test in tests) {
req = {
url: baseURL + "allowOrigin=" + escape(test.origin || origin),
method: test.method,
headers: test.headers,
withCred: test.withCred,
};
if (test.allowCred)
req.url += "&allowCred";
if (test.setCookie)
req.url += "&setCookie=" + escape(test.setCookie);
if (test.cookie)
req.url += "&cookie=" + escape(test.cookie);
if (test.noCookie)
req.url += "&noCookie";
if ("allowHeaders" in test)
req.url += "&allowHeaders=" + escape(test.allowHeaders);
if ("allowMethods" in test)
req.url += "&allowMethods=" + escape(test.allowMethods);
loaderWindow.postMessage(req.toSource(), origin);
res = eval(yield);
if (test.pass) {
is(res.didFail, false,
"shouldn't have failed in test for " + test.toSource());
is(res.status, 200, "wrong status in test for " + test.toSource());
is(res.responseXML, "<res>hello pass</res>",
"wrong responseXML in test for " + test.toSource());
is(res.responseText, "<res>hello pass</res>\n",
"wrong responseText in test for " + test.toSource());
is(res.events.join(","),
"opening,rs1,sending,rs1,loadstart,rs2,rs3,rs4,load",
"wrong responseText in test for " + test.toSource());
}
else {
is(res.didFail, true,
"should have failed in test for " + test.toSource());
is(res.status, 0, "wrong status in test for " + test.toSource());
is(res.responseXML, null,
"wrong responseXML in test for " + test.toSource());
is(res.responseText, "",
"wrong responseText in test for " + test.toSource());
is(res.events.join(","),
"opening,rs1,sending,rs1,loadstart,rs2,rs4,error",
"wrong events in test for " + test.toSource());
is(res.progressEvents, 0,
"wrong events in test for " + test.toSource());
}
}
SimpleTest.finish(); SimpleTest.finish();
yield; yield;

View File

@ -539,7 +539,8 @@ txCompileObserver::startLoad(nsIURI* aUri, txStylesheetCompiler* aCompiler,
// Always install in case of redirects // Always install in case of redirects
nsCOMPtr<nsIStreamListener> listener = nsCOMPtr<nsIStreamListener> listener =
new nsCrossSiteListenerProxy(sink, aReferrerPrincipal, channel, &rv); new nsCrossSiteListenerProxy(sink, aReferrerPrincipal, channel,
PR_FALSE, &rv);
NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY); NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);

View File

@ -214,4 +214,11 @@ interface nsIRequest : nsISupports
const unsigned long VALIDATE_ALWAYS = 1 << 11; const unsigned long VALIDATE_ALWAYS = 1 << 11;
const unsigned long VALIDATE_NEVER = 1 << 12; const unsigned long VALIDATE_NEVER = 1 << 12;
const unsigned long VALIDATE_ONCE_PER_SESSION = 1 << 13; const unsigned long VALIDATE_ONCE_PER_SESSION = 1 << 13;
/**
* When set, this flag indicates that no user-specific data should be added
* to the request when opened. This means that things like authorization
* tokens or cookie headers should not be added.
*/
const unsigned long LOAD_ANONYMOUS = 1 << 14;
}; };

View File

@ -663,6 +663,10 @@ nsHttpChannel::SetupTransaction()
void void
nsHttpChannel::AddCookiesToRequest() nsHttpChannel::AddCookiesToRequest()
{ {
if (mLoadFlags & LOAD_ANONYMOUS) {
return;
}
nsXPIDLCString cookie; nsXPIDLCString cookie;
nsICookieService *cs = gHttpHandler->GetCookieService(); nsICookieService *cs = gHttpHandler->GetCookieService();
@ -1746,13 +1750,22 @@ nsHttpChannel::OpenOfflineCacheEntryForWriting()
nsresult nsresult
nsHttpChannel::GenerateCacheKey(nsACString &cacheKey) nsHttpChannel::GenerateCacheKey(nsACString &cacheKey)
{ {
cacheKey.Truncate();
if (mLoadFlags & LOAD_ANONYMOUS) {
cacheKey.AssignLiteral("anon&");
}
if (mPostID) { if (mPostID) {
char buf[32]; char buf[32];
PR_snprintf(buf, sizeof(buf), "id=%x&uri=", mPostID); PR_snprintf(buf, sizeof(buf), "id=%x&", mPostID);
cacheKey.Assign(buf); cacheKey.Append(buf);
} else }
cacheKey.Truncate();
if (!cacheKey.IsEmpty()) {
cacheKey.AppendLiteral("uri=");
}
// Strip any trailing #ref from the URL before using it as the key // Strip any trailing #ref from the URL before using it as the key
const char *spec = mFallbackChannel ? mFallbackKey.get() : mSpec.get(); const char *spec = mFallbackChannel ? mFallbackKey.get() : mSpec.get();
const char *p = strchr(spec, '#'); const char *p = strchr(spec, '#');
@ -2888,6 +2901,10 @@ nsHttpChannel::ProcessAuthentication(PRUint32 httpStatus)
LOG(("nsHttpChannel::ProcessAuthentication [this=%x code=%u]\n", LOG(("nsHttpChannel::ProcessAuthentication [this=%x code=%u]\n",
this, httpStatus)); this, httpStatus));
if (mLoadFlags & LOAD_ANONYMOUS) {
return NS_ERROR_NOT_AVAILABLE;
}
const char *challenges; const char *challenges;
PRBool proxyAuth = (httpStatus == 407); PRBool proxyAuth = (httpStatus == 407);
@ -3608,6 +3625,10 @@ nsHttpChannel::AddAuthorizationHeaders()
{ {
LOG(("nsHttpChannel::AddAuthorizationHeaders? [this=%x]\n", this)); LOG(("nsHttpChannel::AddAuthorizationHeaders? [this=%x]\n", this));
if (mLoadFlags & LOAD_ANONYMOUS) {
return;
}
// this getter never fails // this getter never fails
nsHttpAuthCache *authCache = gHttpHandler->AuthCache(); nsHttpAuthCache *authCache = gHttpHandler->AuthCache();
@ -4500,6 +4521,10 @@ nsHttpChannel::GetResponseVersion(PRUint32 *major, PRUint32 *minor)
NS_IMETHODIMP NS_IMETHODIMP
nsHttpChannel::SetCookie(const char *aCookieHeader) nsHttpChannel::SetCookie(const char *aCookieHeader)
{ {
if (mLoadFlags & LOAD_ANONYMOUS) {
return NS_OK;
}
// empty header isn't an error // empty header isn't an error
if (!(aCookieHeader && *aCookieHeader)) if (!(aCookieHeader && *aCookieHeader))
return NS_OK; return NS_OK;