Bug 597301: Update CORS to latest spec. r=jst a=blocker

This commit is contained in:
Jonas Sicking 2010-10-04 17:41:07 -07:00
Родитель 7c0f204334
Коммит 28a2229ea6
7 изменённых файлов: 437 добавлений и 260 удалений

Просмотреть файл

@ -155,7 +155,7 @@ NS_IMETHODIMP
nsCrossSiteListenerProxy::OnStartRequest(nsIRequest* aRequest,
nsISupports* aContext)
{
mRequestApproved = NS_SUCCEEDED(CheckRequestApproved(aRequest, PR_FALSE));
mRequestApproved = NS_SUCCEEDED(CheckRequestApproved(aRequest));
if (!mRequestApproved) {
if (nsXMLHttpRequest::sAccessControlCache) {
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
@ -219,8 +219,7 @@ IsValidHTTPToken(const nsCSubstring& aToken)
}
nsresult
nsCrossSiteListenerProxy::CheckRequestApproved(nsIRequest* aRequest,
PRBool aIsRedirect)
nsCrossSiteListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
{
// Check if this was actually a cross domain request
if (!mHasBeenCrossSite) {
@ -241,21 +240,6 @@ nsCrossSiteListenerProxy::CheckRequestApproved(nsIRequest* aRequest,
nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aRequest);
NS_ENSURE_TRUE(http, NS_ERROR_DOM_BAD_URI);
// Redirects aren't success-codes. But necko already checked that it was a
// valid redirect.
if (!aIsRedirect) {
PRBool succeeded;
rv = http->GetRequestSucceeded(&succeeded);
NS_ENSURE_SUCCESS(rv, rv);
if (!succeeded) {
PRUint32 responseStatus;
rv = http->GetResponseStatus(&responseStatus);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(mAllowedHTTPErrors.Contains(responseStatus),
NS_ERROR_DOM_BAD_URI);
}
}
// Check the Access-Control-Allow-Origin header
nsCAutoString allowedOriginHeader;
rv = http->GetResponseHeader(
@ -286,13 +270,21 @@ nsCrossSiteListenerProxy::CheckRequestApproved(nsIRequest* aRequest,
}
if (mIsPreflight) {
PRBool succeeded;
rv = http->GetRequestSucceeded(&succeeded);
NS_ENSURE_SUCCESS(rv, rv);
if (!succeeded) {
return NS_ERROR_DOM_BAD_URI;
}
nsCAutoString headerVal;
// The "Access-Control-Allow-Methods" header contains a comma separated
// list of method names.
http->GetResponseHeader(NS_LITERAL_CSTRING("Access-Control-Allow-Methods"),
headerVal);
PRBool foundMethod = mPreflightMethod.EqualsLiteral("GET") ||
mPreflightMethod.EqualsLiteral("POST");
mPreflightMethod.EqualsLiteral("HEAD") ||
mPreflightMethod.EqualsLiteral("POST");
nsCCharSeparatedTokenizer methodTokens(headerVal, ',');
while(methodTokens.hasMoreTokens()) {
const nsDependentCSubstring& method = methodTokens.nextToken();
@ -379,7 +371,7 @@ nsCrossSiteListenerProxy::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
{
nsresult rv;
if (!NS_IsInternalSameURIRedirect(aOldChannel, aNewChannel, aFlags)) {
rv = CheckRequestApproved(aOldChannel, PR_TRUE);
rv = CheckRequestApproved(aOldChannel);
if (NS_FAILED(rv)) {
if (nsXMLHttpRequest::sAccessControlCache) {
nsCOMPtr<nsIURI> oldURI;

Просмотреть файл

@ -84,14 +84,9 @@ public:
// Must be called at startup.
static void Startup();
void AllowHTTPResult(PRUint32 aResultCode)
{
mAllowedHTTPErrors.AppendElement(aResultCode);
}
private:
nsresult UpdateChannel(nsIChannel* aChannel);
nsresult CheckRequestApproved(nsIRequest* aRequest, PRBool aIsRedirect);
nsresult CheckRequestApproved(nsIRequest* aRequest);
nsCOMPtr<nsIStreamListener> mOuterListener;
nsCOMPtr<nsIPrincipal> mRequestingPrincipal;
@ -102,7 +97,6 @@ private:
PRBool mIsPreflight;
nsCString mPreflightMethod;
nsTArray<nsCString> mPreflightHeaders;
nsTArray<PRUint32> mAllowedHTTPErrors;
nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
nsCOMPtr<nsIChannel> mOldRedirectChannel;
nsCOMPtr<nsIChannel> mNewRedirectChannel;

Просмотреть файл

@ -1586,8 +1586,6 @@ nsXMLHttpRequest::GetCurrentHttpChannel()
nsresult
nsXMLHttpRequest::CheckChannelForCrossSiteRequest(nsIChannel* aChannel)
{
nsresult rv;
// First check if cross-site requests are enabled
if ((mState & XML_HTTP_REQUEST_XSITEENABLED)) {
return NS_OK;
@ -1611,24 +1609,10 @@ nsXMLHttpRequest::CheckChannelForCrossSiteRequest(nsIChannel* aChannel)
httpChannel->GetRequestMethod(method);
if (!mACUnsafeHeaders.IsEmpty() ||
HasListenersFor(NS_LITERAL_STRING(UPLOADPROGRESS_STR)) ||
(mUpload && mUpload->HasListeners())) {
mState |= XML_HTTP_REQUEST_NEED_AC_PREFLIGHT;
}
else if (method.LowerCaseEqualsLiteral("post")) {
nsCAutoString contentTypeHeader;
httpChannel->GetRequestHeader(NS_LITERAL_CSTRING("Content-Type"),
contentTypeHeader);
nsCAutoString contentType, charset;
rv = NS_ParseContentType(contentTypeHeader, contentType, charset);
NS_ENSURE_SUCCESS(rv, rv);
if (!contentType.LowerCaseEqualsLiteral("text/plain")) {
mState |= XML_HTTP_REQUEST_NEED_AC_PREFLIGHT;
}
}
else if (!method.LowerCaseEqualsLiteral("get") &&
!method.LowerCaseEqualsLiteral("head")) {
(mUpload && mUpload->HasListeners()) ||
(!method.LowerCaseEqualsLiteral("get") &&
!method.LowerCaseEqualsLiteral("post") &&
!method.LowerCaseEqualsLiteral("head"))) {
mState |= XML_HTTP_REQUEST_NEED_AC_PREFLIGHT;
}
@ -2488,7 +2472,7 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
// ignore the necessary headers for an empty Content-Type.
nsCOMPtr<nsIUploadChannel2> uploadChannel2(do_QueryInterface(httpChannel));
// This assertion will fire if buggy extensions are installed
NS_ASSERTION(uploadChannel2, "http must support nsIUploadChannel");
NS_ASSERTION(uploadChannel2, "http must support nsIUploadChannel2");
if (uploadChannel2) {
uploadChannel2->ExplicitSetUploadStream(postDataStream, contentType,
-1, method, PR_FALSE);
@ -2508,6 +2492,23 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
}
}
if (httpChannel) {
nsCAutoString contentTypeHeader;
rv = httpChannel->GetRequestHeader(NS_LITERAL_CSTRING("Content-Type"),
contentTypeHeader);
if (NS_SUCCEEDED(rv)) {
nsCAutoString contentType, charset;
rv = NS_ParseContentType(contentTypeHeader, contentType, charset);
NS_ENSURE_SUCCESS(rv, rv);
if (!contentType.LowerCaseEqualsLiteral("text/plain") &&
!contentType.LowerCaseEqualsLiteral("application/x-www-form-urlencoded") &&
!contentType.LowerCaseEqualsLiteral("multipart/form-data")) {
mACUnsafeHeaders.AppendElement(NS_LITERAL_CSTRING("Content-Type"));
}
}
}
// Reset responseBody
mResponseBody.Truncate();
mResponseBodyUnicode.SetIsVoid(PR_TRUE);
@ -2765,8 +2766,10 @@ nsXMLHttpRequest::SetRequestHeader(const nsACString& header,
// Check for dangerous cross-site headers
PRBool safeHeader = !!(mState & XML_HTTP_REQUEST_XSITEENABLED);
if (!safeHeader) {
// Content-Type isn't always safe, but we'll deal with it in Send()
const char *kCrossOriginSafeHeaders[] = {
"accept", "accept-language", "content-type"
"accept", "accept-language", "content-language", "content-type",
"last-event-id"
};
for (i = 0; i < NS_ARRAY_LENGTH(kCrossOriginSafeHeaders); ++i) {
if (header.LowerCaseEqualsASCII(kCrossOriginSafeHeaders[i])) {

Просмотреть файл

@ -100,6 +100,13 @@ function handleRequest(request, response)
query.allowOrigin = hops[query.hop-1].allowOrigin;
query.allowHeaders = hops[query.hop-1].allowHeaders;
}
if (!isPreflight && query.status) {
response.setStatusLine(null, query.status, query.statusMessage);
}
if (isPreflight && query.preflightStatus) {
response.setStatusLine(null, query.preflightStatus, "preflight status");
}
if (query.allowOrigin && (!isPreflight || !query.noAllowPreflight))
response.setHeader("Access-Control-Allow-Origin", query.allowOrigin);

Просмотреть файл

@ -43,299 +43,490 @@ function runTest() {
origin = "http://example.org";
yield;
passTests = [{ method: "GET",
tests = [// Plain request
{ pass: 1,
method: "GET",
noAllowPreflight: 1,
},
{ method: "GET",
headers: { "Content-Type": "baz/bin",
// Default allowed headers
{ pass: 1,
method: "GET",
headers: { "Content-Type": "text/plain",
"Accept": "foo/bar",
"Accept-Language": "sv-SE" },
noAllowPreflight: 1,
},
{ method: "GET",
{ pass: 0,
method: "GET",
headers: { "Content-Type": "foo/bar",
"Accept": "foo/bar",
"Accept-Language": "sv-SE" },
noAllowPreflight: 1,
},
// Custom headers
{ pass: 1,
method: "GET",
headers: { "x-my-header": "myValue" },
allowHeaders: "x-my-header",
},
{ method: "GET",
{ pass: 1,
method: "GET",
headers: { "x-my-header": "myValue" },
allowHeaders: "X-My-Header",
},
{ pass: 1,
method: "GET",
headers: { "x-my-header": "myValue",
"long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header": "secondValue" },
allowHeaders: "x-my-header, long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header",
},
{ pass: 1,
method: "GET",
headers: { "x-my%-header": "myValue" },
allowHeaders: "x-my%-header",
},
{ pass: 0,
method: "GET",
headers: { "x-my-header": "myValue" },
},
{ pass: 0,
method: "GET",
headers: { "x-my-header": "" },
},
{ pass: 0,
method: "GET",
headers: { "x-my-header": "myValue" },
allowHeaders: "",
},
{ pass: 0,
method: "GET",
headers: { "x-my-header": "myValue" },
allowHeaders: "y-my-header",
},
{ pass: 0,
method: "GET",
headers: { "x-my-header": "myValue" },
allowHeaders: "x-my-header y-my-header",
},
{ pass: 0,
method: "GET",
headers: { "x-my-header": "myValue" },
allowHeaders: "x-my-header, y-my-header z",
},
{ pass: 0,
method: "GET",
headers: { "x-my-header": "myValue" },
allowHeaders: "x-my-header, y-my-he(ader",
},
{ pass: 0,
method: "GET",
headers: { "myheader": "" },
allowMethods: "myheader",
},
// Multiple custom headers
{ pass: 1,
method: "GET",
headers: { "x-my-header": "myValue",
"second-header": "secondValue",
"third-header": "thirdValue" },
allowHeaders: "x-my-header, second-header, third-header",
},
{ method: "GET",
{ pass: 1,
method: "GET",
headers: { "x-my-header": "myValue",
"second-header": "secondValue",
"third-header": "thirdValue" },
allowHeaders: "x-my-header,second-header,third-header",
},
{ method: "GET",
{ pass: 1,
method: "GET",
headers: { "x-my-header": "myValue",
"second-header": "secondValue",
"third-header": "thirdValue" },
allowHeaders: "x-my-header ,second-header ,third-header",
},
{ method: "GET",
{ pass: 1,
method: "GET",
headers: { "x-my-header": "myValue",
"second-header": "secondValue",
"third-header": "thirdValue" },
allowHeaders: "x-my-header , second-header , third-header",
},
{ method: "GET",
{ pass: 1,
method: "GET",
headers: { "x-my-header": "myValue",
"second-header": "secondValue" },
allowHeaders: ", x-my-header, , ,, second-header, , ",
},
{ method: "GET",
{ pass: 1,
method: "GET",
headers: { "x-my-header": "myValue",
"second-header": "secondValue" },
allowHeaders: "x-my-header, second-header, unused-header",
},
{ method: "GET",
headers: { "x-my-header": "myValue" },
allowHeaders: "X-My-Header",
},
{ method: "GET",
{ pass: 0,
method: "GET",
headers: { "x-my-header": "myValue",
"long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header": "secondValue" },
allowHeaders: "x-my-header, long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header",
"y-my-header": "secondValue" },
allowHeaders: "x-my-header",
},
{ method: "GET",
headers: { "x-my%-header": "myValue" },
allowHeaders: "x-my%-header",
{ pass: 0,
method: "GET",
headers: { "x-my-header": "",
"y-my-header": "" },
allowHeaders: "x-my-header",
},
{ method: "HEAD",
// HEAD requests
{ pass: 1,
method: "HEAD",
noAllowPreflight: 1,
},
{ method: "HEAD",
headers: { "Content-Type": "baz/bin",
// HEAD with safe headers
{ pass: 1,
method: "HEAD",
headers: { "Content-Type": "text/plain",
"Accept": "foo/bar",
"Accept-Language": "sv-SE" },
noAllowPreflight: 1,
},
{ method: "POST",
{ pass: 0,
method: "HEAD",
headers: { "Content-Type": "foo/bar",
"Accept": "foo/bar",
"Accept-Language": "sv-SE" },
noAllowPreflight: 1,
},
// HEAD with custom headers
{ pass: 1,
method: "HEAD",
headers: { "x-my-header": "myValue" },
allowHeaders: "x-my-header",
},
{ pass: 0,
method: "HEAD",
headers: { "x-my-header": "myValue" },
},
{ pass: 0,
method: "HEAD",
headers: { "x-my-header": "myValue" },
allowHeaders: "",
},
{ pass: 0,
method: "HEAD",
headers: { "x-my-header": "myValue" },
allowHeaders: "y-my-header",
},
{ pass: 0,
method: "HEAD",
headers: { "x-my-header": "myValue" },
allowHeaders: "x-my-header y-my-header",
},
// POST tests
{ pass: 1,
method: "POST",
body: "hi there",
noAllowPreflight: 1,
},
{ method: "POST",
{ pass: 1,
method: "POST",
},
{ method: "POST",
{ pass: 1,
method: "POST",
noAllowPreflight: 1,
},
// POST with standard headers
{ pass: 1,
method: "POST",
body: "hi there",
headers: { "Content-Type": "text/plain" },
noAllowPreflight: 1,
},
{ method: "POST",
{ pass: 1,
method: "POST",
body: "hi there",
headers: { "Content-Type": "multipart/form-data" },
noAllowPreflight: 1,
},
{ pass: 1,
method: "POST",
body: "hi there",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
noAllowPreflight: 1,
},
{ pass: 0,
method: "POST",
body: "hi there",
headers: { "Content-Type": "foo/bar" },
},
{ method: "POST",
{ pass: 0,
method: "POST",
headers: { "Content-Type": "foo/bar" },
},
{ pass: 1,
method: "POST",
body: "hi there",
headers: { "Content-Type": "text/plain",
"Accept": "foo/bar",
"Accept-Language": "sv-SE" },
noAllowPreflight: 1,
},
{ method: "POST",
// POST with custom headers
{ pass: 1,
method: "POST",
body: "hi there",
headers: { "Accept": "foo/bar",
"Accept-Language": "sv-SE",
"x-my-header": "myValue" },
allowHeaders: "x-my-header",
},
{ method: "POST",
{ pass: 1,
method: "POST",
headers: { "Content-Type": "text/plain",
"x-my-header": "myValue" },
allowHeaders: "x-my-header",
},
{ method: "POST",
{ pass: 1,
method: "POST",
body: "hi there",
headers: { "Content-Type": "text/plain",
"x-my-header": "myValue" },
allowHeaders: "x-my-header",
},
{ pass: 1,
method: "POST",
body: "hi there",
headers: { "Content-Type": "foo/bar",
"x-my-header": "myValue" },
allowHeaders: "x-my-header, content-type",
},
{ pass: 0,
method: "POST",
body: "hi there",
headers: { "Content-Type": "foo/bar" },
noAllowPreflight: 1,
},
{ pass: 0,
method: "POST",
body: "hi there",
headers: { "Content-Type": "foo/bar",
"x-my-header": "myValue" },
allowHeaders: "x-my-header",
},
{ method: "POST",
{ pass: 1,
method: "POST",
headers: { "x-my-header": "myValue" },
allowHeaders: "x-my-header",
},
{ method: "POST",
{ pass: 1,
method: "POST",
body: "hi there",
headers: { "x-my-header": "myValue" },
allowHeaders: "x-my-header, $_%",
},
{ method: "DELETE",
// Other methods
{ pass: 1,
method: "DELETE",
allowMethods: "DELETE",
},
{ method: "DELETE",
allowMethods: "POST, PUT, DELETE",
},
{ method: "DELETE",
allowMethods: "POST, DELETE, PUT",
},
{ method: "DELETE",
allowMethods: "DELETE, POST, PUT",
},
{ method: "DELETE",
allowMethods: "POST ,PUT ,DELETE",
},
{ method: "DELETE",
allowMethods: "POST,PUT,DELETE",
},
{ method: "DELETE",
allowMethods: "POST , PUT , DELETE",
},
{ method: "DELETE",
allowMethods: " ,, PUT ,, , , DELETE , ,",
},
{ method: "POST",
body: "hi there",
headers: { "Content-Type": "text/plain" },
uploadProgress: "uploadprogress",
},
{ method: "POST",
body: "hi there",
headers: { "Content-Type": "text/plain" },
uploadProgress: "progress",
},
];
failTests = [{ method: "GET",
headers: { "x-my-header": "myValue" },
},
{ method: "GET",
headers: { "x-my-header": "myValue" },
allowHeaders: "",
},
{ method: "GET",
headers: { "x-my-header": "myValue" },
allowHeaders: "y-my-header",
},
{ method: "GET",
headers: { "x-my-header": "myValue" },
allowHeaders: "x-my-header y-my-header",
},
{ method: "GET",
headers: { "x-my-header": "myValue" },
allowHeaders: "x-my-header, y-my-header z",
},
{ method: "GET",
headers: { "x-my-header": "myValue" },
allowHeaders: "x-my-header, y-my-he(ader",
},
{ method: "GET",
headers: { "x-my-header": "myValue",
"y-my-header": "secondValue" },
allowHeaders: "x-my-header",
},
{ method: "GET",
headers: { "x-my-header": "" },
},
{ method: "GET",
headers: { "x-my-header": "",
"y-my-header": "" },
allowHeaders: "x-my-header",
},
{ method: "GET",
headers: { "myheader": "" },
allowMethods: "myheader",
},
{ method: "HEAD",
headers: { "x-my-header": "myValue" },
},
{ method: "HEAD",
headers: { "x-my-header": "myValue" },
allowHeaders: "",
},
{ method: "HEAD",
headers: { "x-my-header": "myValue" },
allowHeaders: "y-my-header",
},
{ method: "HEAD",
headers: { "x-my-header": "myValue" },
allowHeaders: "x-my-header y-my-header",
},
{ method: "DELETE",
{ pass: 0,
method: "DELETE",
allowHeaders: "DELETE",
},
{ method: "POST",
noAllowPreflight: 1,
{ pass: 0,
method: "DELETE",
},
{ method: "POST",
body: "hi there",
headers: { "Content-Type": "foo/bar" },
noAllowPreflight: 1,
},
{ method: "DELETE",
},
{ method: "DELETE",
{ pass: 0,
method: "DELETE",
allowMethods: "",
},
{ method: "DELETE",
{ pass: 1,
method: "DELETE",
allowMethods: "POST, PUT, DELETE",
},
{ pass: 1,
method: "DELETE",
allowMethods: "POST, DELETE, PUT",
},
{ pass: 1,
method: "DELETE",
allowMethods: "DELETE, POST, PUT",
},
{ pass: 1,
method: "DELETE",
allowMethods: "POST ,PUT ,DELETE",
},
{ pass: 1,
method: "DELETE",
allowMethods: "POST,PUT,DELETE",
},
{ pass: 1,
method: "DELETE",
allowMethods: "POST , PUT , DELETE",
},
{ pass: 1,
method: "DELETE",
allowMethods: " ,, PUT ,, , , DELETE , ,",
},
{ pass: 0,
method: "DELETE",
allowMethods: "PUT",
},
{ method: "DELETE",
{ pass: 0,
method: "DELETE",
allowMethods: "DELETEZ",
},
{ method: "DELETE",
{ pass: 0,
method: "DELETE",
allowMethods: "DELETE PUT",
},
{ method: "DELETE",
{ pass: 0,
method: "DELETE",
allowMethods: "DELETE, PUT Z",
},
{ method: "DELETE",
{ pass: 0,
method: "DELETE",
allowMethods: "DELETE, PU(T",
},
{ method: "DELETE",
{ pass: 0,
method: "DELETE",
allowMethods: "PUT DELETE",
},
{ method: "DELETE",
{ pass: 0,
method: "DELETE",
allowMethods: "PUT Z, DELETE",
},
{ method: "DELETE",
{ pass: 0,
method: "DELETE",
allowMethods: "PU(T, DELETE",
},
{ method: "MYMETHOD",
{ pass: 0,
method: "MYMETHOD",
allowMethods: "myMethod",
},
{ method: "PUT",
{ pass: 0,
method: "PUT",
allowMethods: "put",
},
{ method: "POST",
// Progress events
{ pass: 1,
method: "POST",
body: "hi there",
headers: { "Content-Type": "text/plain" },
noAllowPreflight: 1,
uploadProgress: "uploadprogress",
},
{ method: "POST",
{ pass: 1,
method: "POST",
body: "hi there",
headers: { "Content-Type": "text/plain" },
noAllowPreflight: 1,
uploadProgress: "progress",
},
{ pass: 0,
method: "POST",
body: "hi there",
headers: { "Content-Type": "text/plain" },
uploadProgress: "uploadprogress",
noAllowPreflight: 1,
},
{ pass: 0,
method: "POST",
body: "hi there",
headers: { "Content-Type": "text/plain" },
uploadProgress: "progress",
noAllowPreflight: 1,
},
// Status messages
{ pass: 1,
method: "GET",
noAllowPreflight: 1,
status: 404,
statusMessage: "nothin' here",
},
{ pass: 1,
method: "GET",
noAllowPreflight: 1,
status: 401,
statusMessage: "no can do",
},
{ pass: 1,
method: "POST",
body: "hi there",
headers: { "Content-Type": "foo/bar" },
allowHeaders: "content-type",
status: 500,
statusMessage: "server boo",
},
{ pass: 1,
method: "GET",
noAllowPreflight: 1,
status: 200,
statusMessage: "Yes!!",
},
{ pass: 0,
method: "GET",
headers: { "x-my-header": "header value" },
allowHeaders: "x-my-header",
preflightStatus: 400
},
{ pass: 1,
method: "GET",
headers: { "x-my-header": "header value" },
allowHeaders: "x-my-header",
preflightStatus: 200
},
];
if (!runPreflightTests) {
passTests = failTests = [];
tests = [];
}
for each(test in passTests) {
req = {
url: baseURL + "&allowOrigin=" + escape(origin) +
"&origin=" + escape(origin) +
"&requestMethod=" + test.method,
for each(test in tests) {
var req = {
url: baseURL + "allowOrigin=" + escape(origin),
method: test.method,
headers: test.headers,
uploadProgress: test.uploadProgress,
body: test.body,
};
if (test.pass) {
req.url += "&origin=" + escape(origin) +
"&requestMethod=" + test.method;
}
if (test.noAllowPreflight)
req.url += "&noAllowPreflight";
if ("headers" in test) {
if (test.pass && "headers" in test) {
function isUnsafeHeader(name) {
lName = name.toLowerCase();
return lName != "accept" &&
lName != "accept-language" &&
(lName != "content-type" ||
["text/plain",
"multipart/form-data",
"application/x-www-form-urlencoded"]
.indexOf(test.headers[name].toLowerCase()) == -1);
}
req.url += "&headers=" + escape(test.headers.toSource());
reqHeaders =
escape([name for (name in test.headers)].map(String.toLowerCase).filter(function(name)
name != "content-type" &&
name != "accept" &&
name != "accept-language").sort().join(","));
escape([name for (name in test.headers)]
.filter(isUnsafeHeader)
.map(String.toLowerCase)
.sort()
.join(","));
req.url += reqHeaders ? "&requestHeaders=" + reqHeaders : "";
}
if ("allowHeaders" in test)
@ -344,71 +535,63 @@ function runTest() {
req.url += "&allowMethods=" + escape(test.allowMethods);
if (test.body)
req.url += "&body=" + escape(test.body);
if (test.status) {
req.url += "&status=" + test.status;
req.url += "&statusMessage=" + escape(test.statusMessage);
}
if (test.preflightStatus)
req.url += "&preflightStatus=" + test.preflightStatus;
loaderWindow.postMessage(req.toSource(), origin);
res = eval(yield);
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.statusText, "OK", "wrong status text for " + test.toSource());
if (test.method !== "HEAD") {
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());
if (test.pass) {
is(res.didFail, false,
"shouldn't have failed in test for " + test.toSource());
if (test.status) {
is(res.status, test.status, "wrong status in test for " + test.toSource());
is(res.statusText, test.statusMessage, "wrong status text for " + test.toSource());
}
else {
is(res.status, 200, "wrong status in test for " + test.toSource());
is(res.statusText, "OK", "wrong status text for " + test.toSource());
}
if (test.method !== "HEAD") {
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.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,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.statusText, undefined, "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,load",
"wrong responseText in test for " + test.toSource());
"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());
}
}
for each(test in failTests) {
req = {
url: baseURL + "allowOrigin=" + escape(origin),
method: test.method,
headers: test.headers,
uploadProgress: test.uploadProgress,
body: test.body,
};
if (test.noAllowPreflight)
req.url += "&noAllowPreflight";
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);
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.statusText, undefined, "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());
}
// Test cookie behavior
tests = [{ pass: 1,
method: "GET",

Просмотреть файл

@ -973,7 +973,6 @@ nsresult nsHTMLMediaElement::LoadResource(nsIURI* aURI)
listener = crossSiteListener;
NS_ENSURE_TRUE(crossSiteListener, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_SUCCESS(rv, rv);
crossSiteListener->AllowHTTPResult(HTTP_REQUESTED_RANGE_NOT_SATISFIABLE_CODE);
} else {
rv = nsContentUtils::GetSecurityManager()->
CheckLoadURIWithPrincipal(NodePrincipal(),

Просмотреть файл

@ -449,7 +449,6 @@ nsresult nsMediaChannelStream::OpenChannel(nsIStreamListener** aStreamListener)
listener = crossSiteListener;
NS_ENSURE_TRUE(crossSiteListener, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_SUCCESS(rv, rv);
crossSiteListener->AllowHTTPResult(HTTP_REQUESTED_RANGE_NOT_SATISFIABLE_CODE);
} else {
nsresult rv = nsContentUtils::GetSecurityManager()->
CheckLoadURIWithPrincipal(element->NodePrincipal(),