Bug 476567: Clear Access-Control preflight cache when spec says to. Also rewrite cache test-runner to make it more sane. r/sr=jst

--HG--
extra : rebase_source : d92d2eccd14bc58d3e82dff969e27f00fd185f95
This commit is contained in:
Jonas Sicking 2009-02-17 14:10:50 -08:00
parent 42dec6a621
commit b211410505
5 changed files with 221 additions and 36 deletions

View File

@ -53,6 +53,7 @@
#include "nsWhitespaceTokenizer.h"
#include "nsIChannelEventSink.h"
#include "nsCommaSeparatedTokenizer.h"
#include "nsXMLHttpRequest.h"
static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
@ -117,6 +118,18 @@ nsCrossSiteListenerProxy::OnStartRequest(nsIRequest* aRequest,
{
mRequestApproved = NS_SUCCEEDED(CheckRequestApproved(aRequest, PR_FALSE));
if (!mRequestApproved) {
if (nsXMLHttpRequest::sAccessControlCache) {
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
if (channel) {
nsCOMPtr<nsIURI> uri;
channel->GetURI(getter_AddRefs(uri));
if (uri) {
nsXMLHttpRequest::sAccessControlCache->
RemoveEntries(uri, mRequestingPrincipal);
}
}
}
aRequest->Cancel(NS_ERROR_DOM_BAD_URI);
mOuterListener->OnStartRequest(aRequest, aContext);
@ -317,7 +330,17 @@ nsCrossSiteListenerProxy::OnChannelRedirect(nsIChannel *aOldChannel,
nsresult rv;
if (!NS_IsInternalSameURIRedirect(aOldChannel, aNewChannel, aFlags)) {
rv = CheckRequestApproved(aOldChannel, PR_TRUE);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_FAILED(rv)) {
if (nsXMLHttpRequest::sAccessControlCache) {
nsCOMPtr<nsIURI> oldURI;
aOldChannel->GetURI(getter_AddRefs(oldURI));
if (oldURI) {
nsXMLHttpRequest::sAccessControlCache->
RemoveEntries(oldURI, mRequestingPrincipal);
}
}
return NS_ERROR_DOM_BAD_URI;
}
}
nsCOMPtr<nsIChannelEventSink> outer =

View File

@ -974,7 +974,7 @@ nsAccessControlLRUCache::GetEntry(nsIURI* aURI,
// This will delete 'lruEntry'.
mTable.Remove(lruEntry->mKey);
NS_ASSERTION(mTable.Count() >= ACCESS_CONTROL_CACHE_SIZE,
NS_ASSERTION(mTable.Count() == ACCESS_CONTROL_CACHE_SIZE,
"Somehow tried to remove an entry that was never added!");
}
}
@ -982,6 +982,24 @@ nsAccessControlLRUCache::GetEntry(nsIURI* aURI,
return entry;
}
void
nsAccessControlLRUCache::RemoveEntries(nsIURI* aURI, nsIPrincipal* aPrincipal)
{
CacheEntry* entry;
nsCString key;
if (GetCacheKey(aURI, aPrincipal, PR_TRUE, key) &&
mTable.Get(key, &entry)) {
PR_REMOVE_LINK(entry);
mTable.Remove(key);
}
if (GetCacheKey(aURI, aPrincipal, PR_FALSE, key) &&
mTable.Get(key, &entry)) {
PR_REMOVE_LINK(entry);
mTable.Remove(key);
}
}
void
nsAccessControlLRUCache::Clear()
{

View File

@ -127,6 +127,7 @@ public:
CacheEntry* GetEntry(nsIURI* aURI, nsIPrincipal* aPrincipal,
PRBool aWithCredentials, PRBool aCreate);
void RemoveEntries(nsIURI* aURI, nsIPrincipal* aPrincipal);
void Clear();

View File

@ -6,26 +6,28 @@ function handleRequest(request, response)
query[name] = unescape(value);
});
if ("setState" in query) {
setState("test/content/base/test_CrossSiteXHR_cache:secData",
query.setState);
response.setHeader("Cache-Control", "no-cache", false);
response.setHeader("Content-Type", "text/plain", false);
response.write("hi");
return;
}
var isPreflight = request.method == "OPTIONS";
// Send response
response.setHeader("Access-Control-Allow-Origin", query.allowOrigin);
secData =
eval(getState("test/content/base/test_CrossSiteXHR_cache:secData"));
if (secData.allowOrigin)
response.setHeader("Access-Control-Allow-Origin", secData.allowOrigin);
if (isPreflight) {
var secData = {};
if (request.hasHeader("Access-Control-Request-Headers")) {
var magicHeader =
request.getHeader("Access-Control-Request-Headers").split(",").
filter(function(name) /^magic-/.test(name))[0];
}
if (magicHeader) {
secData = eval(unescape(magicHeader.substr(6)));
secData.allowHeaders = (secData.allowHeaders || "") + "," + magicHeader;
}
if (secData.allowHeaders)
response.setHeader("Access-Control-Allow-Headers", secData.allowHeaders);
@ -38,6 +40,7 @@ function handleRequest(request, response)
return;
}
response.setHeader("Cache-Control", "no-cache", false);
response.setHeader("Content-Type", "application/xml", false);
response.write("<res>hello pass</res>\n");
}

View File

@ -69,7 +69,7 @@ function runTest() {
{ pass: 1,
method: "GET",
headers: { "y-my-header": "hello" },
allowHeaders: "y-my-header",
allowHeaders: "y-my-header,x-my-header",
cacheTime: 3600,
},
{ pass: 1,
@ -158,9 +158,33 @@ function runTest() {
allowHeaders: "second-header",
cacheTime: 3600,
},
{ pass: 0,
{ pass: 1,
method: "GET",
headers: { "third-header": "myValue" },
allowHeaders: "third-header",
cacheTime: 2,
},
{ pause: 2.1 },
{ pass: 1,
method: "GET",
headers: { "second-header": "myValue" },
},
{ pass: 0,
method: "GET",
headers: { "first-header": "myValue" },
},
{ newTest: "*******" },
{ pass: 1,
method: "GET",
headers: { "first-header": "myValue" },
allowHeaders: "first-header",
cacheTime: 2,
},
{ pass: 1,
method: "GET",
headers: { "second-header": "myValue" },
allowHeaders: "second-header",
cacheTime: 3600,
},
{ pass: 1,
method: "GET",
@ -169,10 +193,6 @@ function runTest() {
cacheTime: 2,
},
{ pause: 2.1 },
{ pass: 0,
method: "GET",
headers: { "first-header": "myValue" },
},
{ pass: 1,
method: "GET",
headers: { "second-header": "myValue" },
@ -214,7 +234,7 @@ function runTest() {
{ pass: 1,
method: "PATCH",
},
{ pass: 1,
{ pass: 0,
method: "XXDELETE",
},
{ pass: 0,
@ -259,8 +279,28 @@ function runTest() {
allowMethods: "SECOND",
cacheTime: 3600,
},
{ pass: 0,
{ pass: 1,
method: "THIRD",
allowMethods: "THIRD",
cacheTime: 2,
},
{ pause: 2.1 },
{ pass: 1,
method: "SECOND",
},
{ pass: 0,
method: "FIRST",
},
{ newTest: "*******" },
{ pass: 1,
method: "FIRST",
allowMethods: "FIRST",
cacheTime: 2,
},
{ pass: 1,
method: "SECOND",
allowMethods: "SECOND",
cacheTime: 3600,
},
{ pass: 1,
method: "THIRD",
@ -268,19 +308,120 @@ function runTest() {
cacheTime: 2,
},
{ pause: 2.1 },
{ pass: 0,
method: "FIRST",
},
{ pass: 1,
method: "SECOND",
},
{ pass: 0,
method: "THIRD",
},
{ newTest: "*******" },
{ pass: 1,
method: "GET",
headers: { "x-my-header": "x-value" },
allowHeaders: "x-my-header",
cacheTime: 3600,
},
{ pass: 1,
method: "GET",
headers: { "x-my-header": "x-value" }
},
{ pass: 0,
method: "GET",
headers: { "y-my-header": "y-value" }
},
{ pass: 0,
method: "GET",
headers: { "x-my-header": "x-value" }
},
{ newTest: "*******" },
{ pass: 1,
method: "GET",
headers: { "x-my-header": "x-value" },
allowHeaders: "x-my-header",
cacheTime: 3600,
},
{ pass: 1,
method: "GET",
headers: { "x-my-header": "x-value" },
},
{ pass: 0,
method: "XXPUT",
},
{ pass: 0,
method: "GET",
headers: { "x-my-header": "x-value" },
},
{ newTest: "*******" },
{ pass: 1,
method: "GET",
headers: { "x-my-header": "x-value" },
allowHeaders: "x-my-header",
cacheTime: 3600,
},
{ pass: 1,
method: "GET",
headers: { "x-my-header": "x-value" },
},
{ pass: 0,
method: "GET",
noOrigin: 1,
},
{ pass: 0,
method: "GET",
headers: { "x-my-header": "x-value" },
},
{ newTest: "*******" },
{ pass: 1,
method: "XXDELETE",
allowMethods: "XXDELETE",
cacheTime: 3600,
},
{ pass: 1,
method: "XXDELETE"
},
{ pass: 0,
method: "XXPUT"
},
{ pass: 0,
method: "XXDELETE"
},
{ newTest: "*******" },
{ pass: 1,
method: "XXDELETE",
allowMethods: "XXDELETE",
cacheTime: 3600,
},
{ pass: 1,
method: "XXDELETE"
},
{ pass: 0,
method: "XXDELETE",
headers: { "my-header": "value" },
},
{ pass: 0,
method: "XXDELETE"
},
{ newTest: "*******" },
{ pass: 1,
method: "XXDELETE",
allowMethods: "XXDELETE",
cacheTime: 3600,
},
{ pass: 1,
method: "XXDELETE"
},
{ pass: 0,
method: "GET",
noOrigin: 1,
},
{ pass: 0,
method: "XXDELETE"
},
];
baseURL = "http://localhost:8888/tests/content/base/test/" +
"file_CrossSiteXHR_cache_server.sjs?";
setStateURL = baseURL + "setState=";
var unique = Date.now();
for each (test in tests) {
@ -295,19 +436,18 @@ function runTest() {
}
req = {
url: baseURL + "c=" + unique +
"&allowOrigin=" + escape(origin),
url: baseURL + "c=" + unique,
method: test.method,
headers: test.headers,
};
if (test.cacheTime || test.allowHeaders || test.allowMethods) {
sec = { allowHeaders: test.allowHeaders,
allowMethods: test.allowMethods,
cacheTime: test.cacheTime };
req.headers = req.headers || {};
req.headers["magic-" + escape(sec.toSource())] = "";
}
sec = { allowOrigin: test.noOrigin ? "" : origin,
allowHeaders: test.allowHeaders,
allowMethods: test.allowMethods,
cacheTime: test.cacheTime };
xhr = new XMLHttpRequest();
xhr.open("POST", setStateURL + escape(sec.toSource()), false);
xhr.send();
loaderWindow.postMessage(req.toSource(), origin);