зеркало из https://github.com/mozilla/pjs.git
Bug 597301: Update CORS to latest spec. r=jst a=blocker
This commit is contained in:
Родитель
7c0f204334
Коммит
28a2229ea6
|
@ -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])) {
|
||||
|
|
|
@ -101,6 +101,13 @@ function handleRequest(request, response)
|
|||
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(),
|
||||
|
|
Загрузка…
Ссылка в новой задаче