mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-07-31 21:29:00 +00:00
1630 lines
55 KiB
JavaScript
1630 lines
55 KiB
JavaScript
var path = "/tests/dom/base/test/";
|
|
|
|
function isOpaqueResponse(response) {
|
|
return response.type == "opaque" && response.status === 0 && response.statusText === "";
|
|
}
|
|
|
|
function testModeSameOrigin() {
|
|
// Fetch spec Section 4, step 4, "request's mode is same-origin".
|
|
var req = new Request("http://example.com", { mode: "same-origin" });
|
|
return fetch(req).then(function(res) {
|
|
ok(false, "Attempting to fetch a resource from a different origin with mode same-origin should fail.");
|
|
}, function(e) {
|
|
ok(e instanceof TypeError, "Attempting to fetch a resource from a different origin with mode same-origin should fail.");
|
|
});
|
|
}
|
|
|
|
function testNoCorsCtor() {
|
|
// Request constructor Step 19.1
|
|
var simpleMethods = ["GET", "HEAD", "POST"];
|
|
for (var i = 0; i < simpleMethods.length; ++i) {
|
|
var r = new Request("http://example.com", { method: simpleMethods[i], mode: "no-cors" });
|
|
ok(true, "no-cors Request with simple method " + simpleMethods[i] + " is allowed.");
|
|
}
|
|
|
|
var otherMethods = ["DELETE", "OPTIONS", "PUT"];
|
|
for (var i = 0; i < otherMethods.length; ++i) {
|
|
try {
|
|
var r = new Request("http://example.com", { method: otherMethods[i], mode: "no-cors" });
|
|
ok(false, "no-cors Request with non-simple method " + otherMethods[i] + " is not allowed.");
|
|
} catch(e) {
|
|
ok(true, "no-cors Request with non-simple method " + otherMethods[i] + " is not allowed.");
|
|
}
|
|
}
|
|
|
|
// Request constructor Step 19.2, check guarded headers.
|
|
var r = new Request(".", { mode: "no-cors" });
|
|
r.headers.append("Content-Type", "multipart/form-data");
|
|
is(r.headers.get("content-type"), "multipart/form-data", "Appending simple header should succeed");
|
|
r.headers.append("custom", "value");
|
|
ok(!r.headers.has("custom"), "Appending custom header should fail");
|
|
r.headers.append("DNT", "value");
|
|
ok(!r.headers.has("DNT"), "Appending forbidden header should fail");
|
|
}
|
|
|
|
var corsServerPath = "/tests/dom/security/test/cors/file_CrossSiteXHR_server.sjs?";
|
|
function testModeNoCors() {
|
|
// Fetch spec, section 4, step 4, response tainting should be set opaque, so
|
|
// that fetching leads to an opaque filtered response in step 8.
|
|
var r = new Request("http://example.com" + corsServerPath + "status=200", { mode: "no-cors" });
|
|
return fetch(r).then(function(res) {
|
|
ok(isOpaqueResponse(res), "no-cors Request fetch should result in opaque response");
|
|
}, function(e) {
|
|
ok(false, "no-cors Request fetch should not error");
|
|
});
|
|
}
|
|
|
|
function testSameOriginCredentials() {
|
|
var cookieStr = "type=chocolatechip";
|
|
var tests = [
|
|
{
|
|
// Initialize by setting a cookie.
|
|
pass: 1,
|
|
setCookie: cookieStr,
|
|
withCred: "same-origin",
|
|
},
|
|
{
|
|
// Default mode is "omit".
|
|
pass: 1,
|
|
noCookie: 1,
|
|
},
|
|
{
|
|
pass: 1,
|
|
noCookie: 1,
|
|
withCred: "omit",
|
|
},
|
|
{
|
|
pass: 1,
|
|
cookie: cookieStr,
|
|
withCred: "same-origin",
|
|
},
|
|
{
|
|
pass: 1,
|
|
cookie: cookieStr,
|
|
withCred: "include",
|
|
},
|
|
];
|
|
|
|
var finalPromiseResolve, finalPromiseReject;
|
|
var finalPromise = new Promise(function(res, rej) {
|
|
finalPromiseResolve = res;
|
|
finalPromiseReject = rej;
|
|
});
|
|
|
|
function makeRequest(test) {
|
|
req = {
|
|
// Add a default query param just to make formatting the actual params
|
|
// easier.
|
|
url: corsServerPath + "a=b",
|
|
method: test.method,
|
|
headers: test.headers,
|
|
withCred: test.withCred,
|
|
};
|
|
|
|
if (test.setCookie)
|
|
req.url += "&setCookie=" + escape(test.setCookie);
|
|
if (test.cookie)
|
|
req.url += "&cookie=" + escape(test.cookie);
|
|
if (test.noCookie)
|
|
req.url += "&noCookie";
|
|
|
|
return new Request(req.url, { method: req.method,
|
|
headers: req.headers,
|
|
credentials: req.withCred });
|
|
}
|
|
|
|
function testResponse(res, test) {
|
|
ok(test.pass, "Expected test to pass " + test.toSource());
|
|
is(res.status, 200, "wrong status in test for " + test.toSource());
|
|
is(res.statusText, "OK", "wrong status text for " + test.toSource());
|
|
return res.text().then(function(v) {
|
|
is(v, "<res>hello pass</res>\n",
|
|
"wrong text in test for " + test.toSource());
|
|
});
|
|
}
|
|
|
|
function runATest(tests, i) {
|
|
var test = tests[i];
|
|
var request = makeRequest(test);
|
|
console.log(request.url);
|
|
fetch(request).then(function(res) {
|
|
testResponse(res, test);
|
|
if (i < tests.length-1) {
|
|
runATest(tests, i+1);
|
|
} else {
|
|
finalPromiseResolve();
|
|
}
|
|
}, function(e) {
|
|
ok(!test.pass, "Expected test to fail " + test.toSource());
|
|
ok(e instanceof TypeError, "Test should fail " + test.toSource());
|
|
if (i < tests.length-1) {
|
|
runATest(tests, i+1);
|
|
} else {
|
|
finalPromiseResolve();
|
|
}
|
|
});
|
|
}
|
|
|
|
runATest(tests, 0);
|
|
return finalPromise;
|
|
}
|
|
|
|
function testModeCors() {
|
|
var tests = [// Plain request
|
|
{ pass: 1,
|
|
method: "GET",
|
|
noAllowPreflight: 1,
|
|
},
|
|
|
|
// undefined username
|
|
{ pass: 1,
|
|
method: "GET",
|
|
noAllowPreflight: 1,
|
|
username: undefined
|
|
},
|
|
|
|
// undefined username and password
|
|
{ pass: 1,
|
|
method: "GET",
|
|
noAllowPreflight: 1,
|
|
username: undefined,
|
|
password: undefined
|
|
},
|
|
|
|
// nonempty username
|
|
{ pass: 0,
|
|
method: "GET",
|
|
noAllowPreflight: 1,
|
|
username: "user",
|
|
},
|
|
|
|
// nonempty password
|
|
// XXXbz this passes for now, because we ignore passwords
|
|
// without usernames in most cases.
|
|
{ pass: 1,
|
|
method: "GET",
|
|
noAllowPreflight: 1,
|
|
password: "password",
|
|
},
|
|
|
|
// Default allowed headers
|
|
{ pass: 1,
|
|
method: "GET",
|
|
headers: { "Content-Type": "text/plain",
|
|
"Accept": "foo/bar",
|
|
"Accept-Language": "sv-SE" },
|
|
noAllowPreflight: 1,
|
|
},
|
|
|
|
{ pass: 0,
|
|
method: "GET",
|
|
headers: { "Content-Type": "foo/bar",
|
|
"Accept": "foo/bar",
|
|
"Accept-Language": "sv-SE" },
|
|
noAllowPreflight: 1,
|
|
},
|
|
|
|
{ pass: 0,
|
|
method: "GET",
|
|
headers: { "Content-Type": "foo/bar, text/plain" },
|
|
noAllowPreflight: 1,
|
|
},
|
|
|
|
{ pass: 0,
|
|
method: "GET",
|
|
headers: { "Content-Type": "foo/bar, text/plain, garbage" },
|
|
noAllowPreflight: 1,
|
|
},
|
|
|
|
// Custom headers
|
|
{ pass: 1,
|
|
method: "GET",
|
|
headers: { "x-my-header": "myValue" },
|
|
allowHeaders: "x-my-header",
|
|
},
|
|
{ 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",
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
headers: { "User-Agent": "myValue" },
|
|
allowHeaders: "User-Agent",
|
|
},
|
|
{ pass: 0,
|
|
method: "GET",
|
|
headers: { "User-Agent": "myValue" },
|
|
},
|
|
|
|
// 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",
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
headers: { "x-my-header": "myValue",
|
|
"second-header": "secondValue",
|
|
"third-header": "thirdValue" },
|
|
allowHeaders: "x-my-header,second-header,third-header",
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
headers: { "x-my-header": "myValue",
|
|
"second-header": "secondValue",
|
|
"third-header": "thirdValue" },
|
|
allowHeaders: "x-my-header ,second-header ,third-header",
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
headers: { "x-my-header": "myValue",
|
|
"second-header": "secondValue",
|
|
"third-header": "thirdValue" },
|
|
allowHeaders: "x-my-header , second-header , third-header",
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
headers: { "x-my-header": "myValue",
|
|
"second-header": "secondValue" },
|
|
allowHeaders: ", x-my-header, , ,, second-header, , ",
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
headers: { "x-my-header": "myValue",
|
|
"second-header": "secondValue" },
|
|
allowHeaders: "x-my-header, second-header, unused-header",
|
|
},
|
|
{ pass: 0,
|
|
method: "GET",
|
|
headers: { "x-my-header": "myValue",
|
|
"y-my-header": "secondValue" },
|
|
allowHeaders: "x-my-header",
|
|
},
|
|
{ pass: 0,
|
|
method: "GET",
|
|
headers: { "x-my-header": "",
|
|
"y-my-header": "" },
|
|
allowHeaders: "x-my-header",
|
|
},
|
|
|
|
// HEAD requests
|
|
{ pass: 1,
|
|
method: "HEAD",
|
|
noAllowPreflight: 1,
|
|
},
|
|
|
|
// HEAD with safe headers
|
|
{ pass: 1,
|
|
method: "HEAD",
|
|
headers: { "Content-Type": "text/plain",
|
|
"Accept": "foo/bar",
|
|
"Accept-Language": "sv-SE" },
|
|
noAllowPreflight: 1,
|
|
},
|
|
{ pass: 0,
|
|
method: "HEAD",
|
|
headers: { "Content-Type": "foo/bar",
|
|
"Accept": "foo/bar",
|
|
"Accept-Language": "sv-SE" },
|
|
noAllowPreflight: 1,
|
|
},
|
|
{ pass: 0,
|
|
method: "HEAD",
|
|
headers: { "Content-Type": "foo/bar, text/plain" },
|
|
noAllowPreflight: 1,
|
|
},
|
|
{ pass: 0,
|
|
method: "HEAD",
|
|
headers: { "Content-Type": "foo/bar, text/plain, garbage" },
|
|
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,
|
|
},
|
|
{ pass: 1,
|
|
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,
|
|
},
|
|
{ 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" },
|
|
},
|
|
{ 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,
|
|
},
|
|
{ pass: 0,
|
|
method: "POST",
|
|
body: "hi there",
|
|
headers: { "Content-Type": "foo/bar, text/plain" },
|
|
noAllowPreflight: 1,
|
|
},
|
|
{ pass: 0,
|
|
method: "POST",
|
|
body: "hi there",
|
|
headers: { "Content-Type": "foo/bar, text/plain, garbage" },
|
|
noAllowPreflight: 1,
|
|
},
|
|
|
|
// 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",
|
|
},
|
|
{ pass: 1,
|
|
method: "POST",
|
|
headers: { "Content-Type": "text/plain",
|
|
"x-my-header": "myValue" },
|
|
allowHeaders: "x-my-header",
|
|
},
|
|
{ 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",
|
|
},
|
|
{ pass: 1,
|
|
method: "POST",
|
|
headers: { "x-my-header": "myValue" },
|
|
allowHeaders: "x-my-header",
|
|
},
|
|
{ pass: 1,
|
|
method: "POST",
|
|
body: "hi there",
|
|
headers: { "x-my-header": "myValue" },
|
|
allowHeaders: "x-my-header, $_%",
|
|
},
|
|
|
|
// Other methods
|
|
{ pass: 1,
|
|
method: "DELETE",
|
|
allowMethods: "DELETE",
|
|
},
|
|
{ pass: 0,
|
|
method: "DELETE",
|
|
allowHeaders: "DELETE",
|
|
},
|
|
{ pass: 0,
|
|
method: "DELETE",
|
|
},
|
|
{ pass: 0,
|
|
method: "DELETE",
|
|
allowMethods: "",
|
|
},
|
|
{ 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",
|
|
},
|
|
{ pass: 0,
|
|
method: "DELETE",
|
|
allowMethods: "DELETEZ",
|
|
},
|
|
{ pass: 0,
|
|
method: "DELETE",
|
|
allowMethods: "DELETE PUT",
|
|
},
|
|
{ pass: 0,
|
|
method: "DELETE",
|
|
allowMethods: "DELETE, PUT Z",
|
|
},
|
|
{ pass: 0,
|
|
method: "DELETE",
|
|
allowMethods: "DELETE, PU(T",
|
|
},
|
|
{ pass: 0,
|
|
method: "DELETE",
|
|
allowMethods: "PUT DELETE",
|
|
},
|
|
{ pass: 0,
|
|
method: "DELETE",
|
|
allowMethods: "PUT Z, DELETE",
|
|
},
|
|
{ pass: 0,
|
|
method: "DELETE",
|
|
allowMethods: "PU(T, DELETE",
|
|
},
|
|
{ pass: 0,
|
|
method: "PUT",
|
|
allowMethods: "put",
|
|
},
|
|
|
|
// 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
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
headers: { "x-my-header": "header value" },
|
|
allowHeaders: "x-my-header",
|
|
preflightStatus: 204
|
|
},
|
|
|
|
// exposed headers
|
|
{ pass: 1,
|
|
method: "GET",
|
|
responseHeaders: { "x-my-header": "x header" },
|
|
exposeHeaders: "x-my-header",
|
|
expectedResponseHeaders: ["x-my-header"],
|
|
},
|
|
{ pass: 0,
|
|
method: "GET",
|
|
origin: "http://invalid",
|
|
responseHeaders: { "x-my-header": "x header" },
|
|
exposeHeaders: "x-my-header",
|
|
expectedResponseHeaders: [],
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
responseHeaders: { "x-my-header": "x header" },
|
|
expectedResponseHeaders: [],
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
responseHeaders: { "x-my-header": "x header" },
|
|
exposeHeaders: "x-my-header y",
|
|
expectedResponseHeaders: [],
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
responseHeaders: { "x-my-header": "x header" },
|
|
exposeHeaders: "y x-my-header",
|
|
expectedResponseHeaders: [],
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
responseHeaders: { "x-my-header": "x header" },
|
|
exposeHeaders: "x-my-header, y-my-header z",
|
|
expectedResponseHeaders: [],
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
responseHeaders: { "x-my-header": "x header" },
|
|
exposeHeaders: "x-my-header, y-my-hea(er",
|
|
expectedResponseHeaders: [],
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
responseHeaders: { "x-my-header": "x header",
|
|
"y-my-header": "y header" },
|
|
exposeHeaders: " , ,,y-my-header,z-my-header, ",
|
|
expectedResponseHeaders: ["y-my-header"],
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
responseHeaders: { "Cache-Control": "cacheControl header",
|
|
"Content-Language": "contentLanguage header",
|
|
"Expires":"expires header",
|
|
"Last-Modified":"lastModified header",
|
|
"Pragma":"pragma header",
|
|
"Unexpected":"unexpected header" },
|
|
expectedResponseHeaders: ["Cache-Control","Content-Language","Content-Type","Expires","Last-Modified","Pragma"],
|
|
},
|
|
// Check that sending a body in the OPTIONS response works
|
|
{ pass: 1,
|
|
method: "DELETE",
|
|
allowMethods: "DELETE",
|
|
preflightBody: "I'm a preflight response body",
|
|
},
|
|
];
|
|
|
|
var baseURL = "http://example.org" + corsServerPath;
|
|
var origin = "http://mochi.test:8888";
|
|
var fetches = [];
|
|
for (test of tests) {
|
|
var req = {
|
|
url: baseURL + "allowOrigin=" + escape(test.origin || origin),
|
|
method: test.method,
|
|
headers: test.headers,
|
|
uploadProgress: test.uploadProgress,
|
|
body: test.body,
|
|
responseHeaders: test.responseHeaders,
|
|
};
|
|
|
|
if (test.pass) {
|
|
req.url += "&origin=" + escape(origin) +
|
|
"&requestMethod=" + test.method;
|
|
}
|
|
|
|
if ("username" in test) {
|
|
var u = new URL(req.url);
|
|
u.username = test.username || "";
|
|
req.url = u.href;
|
|
}
|
|
|
|
if ("password" in test) {
|
|
var u = new URL(req.url);
|
|
u.password = test.password || "";
|
|
req.url = u.href;
|
|
}
|
|
|
|
if (test.noAllowPreflight)
|
|
req.url += "&noAllowPreflight";
|
|
|
|
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)]
|
|
.filter(isUnsafeHeader)
|
|
.map(String.toLowerCase)
|
|
.sort()
|
|
.join(","));
|
|
req.url += reqHeaders ? "&requestHeaders=" + reqHeaders : "";
|
|
}
|
|
if ("allowHeaders" in test)
|
|
req.url += "&allowHeaders=" + escape(test.allowHeaders);
|
|
if ("allowMethods" in test)
|
|
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;
|
|
if (test.responseHeaders)
|
|
req.url += "&responseHeaders=" + escape(test.responseHeaders.toSource());
|
|
if (test.exposeHeaders)
|
|
req.url += "&exposeHeaders=" + escape(test.exposeHeaders);
|
|
if (test.preflightBody)
|
|
req.url += "&preflightBody=" + escape(test.preflightBody);
|
|
|
|
fetches.push((function(test) {
|
|
return new Promise(function(resolve) {
|
|
resolve(new Request(req.url, { method: req.method, mode: "cors",
|
|
headers: req.headers, body: req.body }));
|
|
}).then(function(request) {
|
|
return fetch(request);
|
|
}).then(function(res) {
|
|
ok(test.pass, "Expected test to pass 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.responseHeaders) {
|
|
for (header in test.responseHeaders) {
|
|
if (test.expectedResponseHeaders.indexOf(header) == -1) {
|
|
is(res.headers.has(header), false,
|
|
"|Headers.has()|wrong response header (" + header + ") in test for " +
|
|
test.toSource());
|
|
}
|
|
else {
|
|
is(res.headers.get(header), test.responseHeaders[header],
|
|
"|Headers.get()|wrong response header (" + header + ") in test for " +
|
|
test.toSource());
|
|
}
|
|
}
|
|
}
|
|
|
|
return res.text();
|
|
}).then(function(v) {
|
|
if (test.method !== "HEAD") {
|
|
is(v, "<res>hello pass</res>\n",
|
|
"wrong responseText in test for " + test.toSource());
|
|
}
|
|
else {
|
|
is(v, "",
|
|
"wrong responseText in HEAD test for " + test.toSource());
|
|
}
|
|
}).catch(function(e) {
|
|
ok(!test.pass, "Expected test failure for " + test.toSource());
|
|
ok(e instanceof TypeError, "Exception should be TypeError for " + test.toSource());
|
|
});
|
|
})(test));
|
|
}
|
|
|
|
return Promise.all(fetches);
|
|
}
|
|
|
|
function testCrossOriginCredentials() {
|
|
var origin = "http://mochi.test:8888";
|
|
var tests = [
|
|
{ pass: 1,
|
|
method: "GET",
|
|
withCred: "include",
|
|
allowCred: 1,
|
|
},
|
|
{ pass: 0,
|
|
method: "GET",
|
|
withCred: "include",
|
|
allowCred: 0,
|
|
},
|
|
{ pass: 0,
|
|
method: "GET",
|
|
withCred: "include",
|
|
allowCred: 1,
|
|
origin: "*",
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
withCred: "omit",
|
|
allowCred: 1,
|
|
origin: "*",
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
setCookie: "a=1",
|
|
withCred: "include",
|
|
allowCred: 1,
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
cookie: "a=1",
|
|
withCred: "include",
|
|
allowCred: 1,
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
noCookie: 1,
|
|
withCred: "omit",
|
|
allowCred: 1,
|
|
},
|
|
{ pass: 0,
|
|
method: "GET",
|
|
noCookie: 1,
|
|
withCred: "include",
|
|
allowCred: 1,
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
setCookie: "a=2",
|
|
withCred: "omit",
|
|
allowCred: 1,
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
cookie: "a=1",
|
|
withCred: "include",
|
|
allowCred: 1,
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
setCookie: "a=2",
|
|
withCred: "include",
|
|
allowCred: 1,
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
cookie: "a=2",
|
|
withCred: "include",
|
|
allowCred: 1,
|
|
},
|
|
{
|
|
// When credentials mode is same-origin, but mode is cors, no
|
|
// cookie should be sent cross origin.
|
|
pass: 0,
|
|
method: "GET",
|
|
cookie: "a=2",
|
|
withCred: "same-origin",
|
|
allowCred: 1,
|
|
},
|
|
{
|
|
// When credentials mode is same-origin, but mode is cors, no
|
|
// cookie should be sent cross origin. This test checks the same
|
|
// thing as above, but uses the noCookie check on the server
|
|
// instead, and expects a valid response.
|
|
pass: 1,
|
|
method: "GET",
|
|
noCookie: 1,
|
|
withCred: "same-origin",
|
|
},
|
|
{
|
|
// Initialize by setting a cookies for same- and cross- origins.
|
|
pass: 1,
|
|
hops: [{ server: origin,
|
|
setCookie: escape("a=1"),
|
|
},
|
|
{ server: "http://example.com",
|
|
allowOrigin: origin,
|
|
allowCred: 1,
|
|
setCookie: escape("a=2"),
|
|
},
|
|
],
|
|
withCred: "include",
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
hops: [{ server: origin,
|
|
cookie: escape("a=1"),
|
|
},
|
|
{ server: origin,
|
|
cookie: escape("a=1"),
|
|
},
|
|
{ server: "http://example.com",
|
|
allowOrigin: origin,
|
|
noCookie: 1,
|
|
},
|
|
],
|
|
withCred: "same-origin",
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
hops: [{ server: origin,
|
|
cookie: escape("a=1"),
|
|
},
|
|
{ server: origin,
|
|
cookie: escape("a=1"),
|
|
},
|
|
{ server: "http://example.com",
|
|
allowOrigin: origin,
|
|
allowCred: 1,
|
|
cookie: escape("a=2"),
|
|
},
|
|
],
|
|
withCred: "include",
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
hops: [{ server: origin,
|
|
cookie: escape("a=1"),
|
|
},
|
|
{ server: origin,
|
|
cookie: escape("a=1"),
|
|
},
|
|
{ server: "http://example.com",
|
|
allowOrigin: '*',
|
|
noCookie: 1,
|
|
},
|
|
],
|
|
withCred: "same-origin",
|
|
},
|
|
{ pass: 0,
|
|
method: "GET",
|
|
hops: [{ server: origin,
|
|
cookie: escape("a=1"),
|
|
},
|
|
{ server: origin,
|
|
cookie: escape("a=1"),
|
|
},
|
|
{ server: "http://example.com",
|
|
allowOrigin: '*',
|
|
allowCred: 1,
|
|
cookie: escape("a=2"),
|
|
},
|
|
],
|
|
withCred: "include",
|
|
},
|
|
// fails because allow-credentials CORS header is not set by server
|
|
{ pass: 0,
|
|
method: "GET",
|
|
hops: [{ server: origin,
|
|
cookie: escape("a=1"),
|
|
},
|
|
{ server: origin,
|
|
cookie: escape("a=1"),
|
|
},
|
|
{ server: "http://example.com",
|
|
allowOrigin: origin,
|
|
cookie: escape("a=2"),
|
|
},
|
|
],
|
|
withCred: "include",
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
hops: [{ server: origin,
|
|
noCookie: 1,
|
|
},
|
|
{ server: origin,
|
|
noCookie: 1,
|
|
},
|
|
{ server: "http://example.com",
|
|
allowOrigin: origin,
|
|
noCookie: 1,
|
|
},
|
|
],
|
|
withCred: "omit",
|
|
},
|
|
];
|
|
|
|
var baseURL = "http://example.org" + corsServerPath;
|
|
var origin = "http://mochi.test:8888";
|
|
|
|
var finalPromiseResolve, finalPromiseReject;
|
|
var finalPromise = new Promise(function(res, rej) {
|
|
finalPromiseResolve = res;
|
|
finalPromiseReject = rej;
|
|
});
|
|
|
|
function makeRequest(test) {
|
|
var url;
|
|
if (test.hops) {
|
|
url = test.hops[0].server + corsServerPath + "hop=1&hops=" +
|
|
escape(test.hops.toSource());
|
|
} else {
|
|
url = baseURL + "allowOrigin=" + escape(test.origin || origin);
|
|
}
|
|
req = {
|
|
url: url,
|
|
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);
|
|
|
|
return new Request(req.url, { method: req.method,
|
|
headers: req.headers,
|
|
credentials: req.withCred });
|
|
}
|
|
|
|
function testResponse(res, test) {
|
|
ok(test.pass, "Expected test to pass for " + test.toSource());
|
|
is(res.status, 200, "wrong status in test for " + test.toSource());
|
|
is(res.statusText, "OK", "wrong status text for " + test.toSource());
|
|
return res.text().then(function(v) {
|
|
is(v, "<res>hello pass</res>\n",
|
|
"wrong text in test for " + test.toSource());
|
|
});
|
|
}
|
|
|
|
function runATest(tests, i) {
|
|
var test = tests[i];
|
|
var request = makeRequest(test);
|
|
fetch(request).then(function(res) {
|
|
testResponse(res, test);
|
|
if (i < tests.length-1) {
|
|
runATest(tests, i+1);
|
|
} else {
|
|
finalPromiseResolve();
|
|
}
|
|
}, function(e) {
|
|
ok(!test.pass, "Expected test failure for " + test.toSource());
|
|
ok(e instanceof TypeError, "Exception should be TypeError for " + test.toSource());
|
|
if (i < tests.length-1) {
|
|
runATest(tests, i+1);
|
|
} else {
|
|
finalPromiseResolve();
|
|
}
|
|
});
|
|
}
|
|
|
|
runATest(tests, 0);
|
|
return finalPromise;
|
|
}
|
|
|
|
function testCORSRedirects() {
|
|
var origin = "http://mochi.test:8888";
|
|
|
|
var tests = [
|
|
{ pass: 1,
|
|
method: "GET",
|
|
hops: [{ server: "http://example.com",
|
|
allowOrigin: origin
|
|
},
|
|
],
|
|
},
|
|
{ pass: 0,
|
|
method: "GET",
|
|
hops: [{ server: "http://example.com",
|
|
allowOrigin: origin
|
|
},
|
|
{ server: "http://mochi.test:8888",
|
|
allowOrigin: origin
|
|
},
|
|
],
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
hops: [{ server: "http://example.com",
|
|
allowOrigin: origin
|
|
},
|
|
{ server: "http://mochi.test:8888",
|
|
allowOrigin: "*"
|
|
},
|
|
],
|
|
},
|
|
{ pass: 0,
|
|
method: "GET",
|
|
hops: [{ server: "http://example.com",
|
|
allowOrigin: origin
|
|
},
|
|
{ server: "http://mochi.test:8888",
|
|
},
|
|
],
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
hops: [{ server: "http://mochi.test:8888",
|
|
},
|
|
{ server: "http://mochi.test:8888",
|
|
},
|
|
{ server: "http://example.com",
|
|
allowOrigin: origin
|
|
},
|
|
],
|
|
},
|
|
{ pass: 0,
|
|
method: "GET",
|
|
hops: [{ server: "http://mochi.test:8888",
|
|
},
|
|
{ server: "http://mochi.test:8888",
|
|
},
|
|
{ server: "http://example.com",
|
|
allowOrigin: origin
|
|
},
|
|
{ server: "http://mochi.test:8888",
|
|
},
|
|
],
|
|
},
|
|
{ pass: 0,
|
|
method: "GET",
|
|
hops: [{ server: "http://example.com",
|
|
allowOrigin: origin
|
|
},
|
|
{ server: "http://test2.mochi.test:8888",
|
|
allowOrigin: origin
|
|
},
|
|
{ server: "http://sub2.xn--lt-uia.mochi.test:8888",
|
|
allowOrigin: origin
|
|
},
|
|
{ server: "http://sub1.test1.mochi.test:8888",
|
|
allowOrigin: origin
|
|
},
|
|
],
|
|
},
|
|
{ pass: 0,
|
|
method: "GET",
|
|
hops: [{ server: "http://example.com",
|
|
allowOrigin: origin
|
|
},
|
|
{ server: "http://test2.mochi.test:8888",
|
|
allowOrigin: origin
|
|
},
|
|
{ server: "http://sub2.xn--lt-uia.mochi.test:8888",
|
|
allowOrigin: "*"
|
|
},
|
|
{ server: "http://sub1.test1.mochi.test:8888",
|
|
allowOrigin: "*"
|
|
},
|
|
],
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
hops: [{ server: "http://example.com",
|
|
allowOrigin: origin
|
|
},
|
|
{ server: "http://test2.mochi.test:8888",
|
|
allowOrigin: "*"
|
|
},
|
|
{ server: "http://sub2.xn--lt-uia.mochi.test:8888",
|
|
allowOrigin: "*"
|
|
},
|
|
{ server: "http://sub1.test1.mochi.test:8888",
|
|
allowOrigin: "*"
|
|
},
|
|
],
|
|
},
|
|
{ pass: 0,
|
|
method: "GET",
|
|
hops: [{ server: "http://example.com",
|
|
allowOrigin: origin
|
|
},
|
|
{ server: "http://test2.mochi.test:8888",
|
|
allowOrigin: origin
|
|
},
|
|
{ server: "http://sub2.xn--lt-uia.mochi.test:8888",
|
|
allowOrigin: "x"
|
|
},
|
|
{ server: "http://sub1.test1.mochi.test:8888",
|
|
allowOrigin: origin
|
|
},
|
|
],
|
|
},
|
|
{ pass: 0,
|
|
method: "GET",
|
|
hops: [{ server: "http://example.com",
|
|
allowOrigin: origin
|
|
},
|
|
{ server: "http://test2.mochi.test:8888",
|
|
allowOrigin: origin
|
|
},
|
|
{ server: "http://sub2.xn--lt-uia.mochi.test:8888",
|
|
allowOrigin: "*"
|
|
},
|
|
{ server: "http://sub1.test1.mochi.test:8888",
|
|
allowOrigin: origin
|
|
},
|
|
],
|
|
},
|
|
{ pass: 0,
|
|
method: "GET",
|
|
hops: [{ server: "http://example.com",
|
|
allowOrigin: origin
|
|
},
|
|
{ server: "http://test2.mochi.test:8888",
|
|
allowOrigin: origin
|
|
},
|
|
{ server: "http://sub2.xn--lt-uia.mochi.test:8888",
|
|
allowOrigin: "*"
|
|
},
|
|
{ server: "http://sub1.test1.mochi.test:8888",
|
|
},
|
|
],
|
|
},
|
|
{ pass: 1,
|
|
method: "POST",
|
|
body: "hi there",
|
|
headers: { "Content-Type": "text/plain" },
|
|
hops: [{ server: "http://mochi.test:8888",
|
|
},
|
|
{ server: "http://example.com",
|
|
allowOrigin: origin,
|
|
},
|
|
],
|
|
},
|
|
{ pass: 1,
|
|
method: "POST",
|
|
body: "hi there",
|
|
headers: { "Content-Type": "text/plain",
|
|
"my-header": "myValue",
|
|
},
|
|
hops: [{ server: "http://mochi.test:8888",
|
|
},
|
|
{ server: "http://example.com",
|
|
allowOrigin: origin,
|
|
allowHeaders: "my-header",
|
|
},
|
|
],
|
|
},
|
|
{ pass: 0,
|
|
method: "POST",
|
|
body: "hi there",
|
|
headers: { "Content-Type": "text/plain",
|
|
"my-header": "myValue",
|
|
},
|
|
hops: [{ server: "http://mochi.test:8888",
|
|
},
|
|
{ server: "http://example.com",
|
|
allowOrigin: origin,
|
|
allowHeaders: "my-header",
|
|
noAllowPreflight: 1,
|
|
},
|
|
],
|
|
},
|
|
{ pass: 0,
|
|
method: "POST",
|
|
body: "hi there",
|
|
headers: { "Content-Type": "text/plain",
|
|
"my-header": "myValue",
|
|
},
|
|
hops: [{ server: "http://mochi.test:8888",
|
|
},
|
|
{ server: "http://test1.example.com",
|
|
allowOrigin: origin,
|
|
allowHeaders: "my-header",
|
|
},
|
|
{ server: "http://test2.example.com",
|
|
allowOrigin: origin,
|
|
allowHeaders: "my-header",
|
|
}
|
|
],
|
|
},
|
|
{ pass: 1,
|
|
method: "DELETE",
|
|
hops: [{ server: "http://mochi.test:8888",
|
|
},
|
|
{ server: "http://example.com",
|
|
allowOrigin: origin,
|
|
allowMethods: "DELETE",
|
|
},
|
|
],
|
|
},
|
|
{ pass: 0,
|
|
method: "DELETE",
|
|
hops: [{ server: "http://mochi.test:8888",
|
|
},
|
|
{ server: "http://example.com",
|
|
allowOrigin: origin,
|
|
allowMethods: "DELETE",
|
|
noAllowPreflight: 1,
|
|
},
|
|
],
|
|
},
|
|
{ pass: 0,
|
|
method: "DELETE",
|
|
hops: [{ server: "http://mochi.test:8888",
|
|
},
|
|
{ server: "http://test1.example.com",
|
|
allowOrigin: origin,
|
|
allowMethods: "DELETE",
|
|
},
|
|
{ server: "http://test2.example.com",
|
|
allowOrigin: origin,
|
|
allowMethods: "DELETE",
|
|
},
|
|
],
|
|
},
|
|
{ pass: 0,
|
|
method: "POST",
|
|
body: "hi there",
|
|
headers: { "Content-Type": "text/plain",
|
|
"my-header": "myValue",
|
|
},
|
|
hops: [{ server: "http://example.com",
|
|
allowOrigin: origin,
|
|
},
|
|
{ server: "http://sub1.test1.mochi.test:8888",
|
|
allowOrigin: origin,
|
|
},
|
|
],
|
|
},
|
|
{ pass: 0,
|
|
method: "DELETE",
|
|
hops: [{ server: "http://example.com",
|
|
allowOrigin: origin,
|
|
allowMethods: "DELETE",
|
|
},
|
|
{ server: "http://sub1.test1.mochi.test:8888",
|
|
allowOrigin: origin,
|
|
allowMethods: "DELETE",
|
|
},
|
|
],
|
|
},
|
|
{ pass: 0,
|
|
method: "POST",
|
|
body: "hi there",
|
|
headers: { "Content-Type": "text/plain",
|
|
"my-header": "myValue",
|
|
},
|
|
hops: [{ server: "http://example.com",
|
|
},
|
|
{ server: "http://sub1.test1.mochi.test:8888",
|
|
allowOrigin: origin,
|
|
allowHeaders: "my-header",
|
|
},
|
|
],
|
|
},
|
|
{ pass: 1,
|
|
method: "POST",
|
|
body: "hi there",
|
|
headers: { "Content-Type": "text/plain" },
|
|
hops: [{ server: "http://mochi.test:8888",
|
|
},
|
|
{ server: "http://example.com",
|
|
allowOrigin: origin,
|
|
},
|
|
],
|
|
},
|
|
{ pass: 0,
|
|
method: "POST",
|
|
body: "hi there",
|
|
headers: { "Content-Type": "text/plain",
|
|
"my-header": "myValue",
|
|
},
|
|
hops: [{ server: "http://example.com",
|
|
allowOrigin: origin,
|
|
allowHeaders: "my-header",
|
|
},
|
|
{ server: "http://mochi.test:8888",
|
|
allowOrigin: origin,
|
|
allowHeaders: "my-header",
|
|
},
|
|
],
|
|
},
|
|
];
|
|
|
|
var fetches = [];
|
|
for (test of tests) {
|
|
req = {
|
|
url: test.hops[0].server + corsServerPath + "hop=1&hops=" +
|
|
escape(test.hops.toSource()),
|
|
method: test.method,
|
|
headers: test.headers,
|
|
body: test.body,
|
|
};
|
|
|
|
if (test.headers) {
|
|
req.url += "&headers=" + escape(test.headers.toSource());
|
|
}
|
|
|
|
if (test.pass) {
|
|
if (test.body)
|
|
req.url += "&body=" + escape(test.body);
|
|
}
|
|
|
|
var request = new Request(req.url, { method: req.method,
|
|
headers: req.headers,
|
|
body: req.body });
|
|
fetches.push((function(request, test) {
|
|
return fetch(request).then(function(res) {
|
|
ok(test.pass, "Expected test to pass for " + test.toSource());
|
|
is(res.status, 200, "wrong status in test for " + test.toSource());
|
|
is(res.statusText, "OK", "wrong status text for " + test.toSource());
|
|
is(res.type, 'cors', 'wrong response type for ' + test.toSource());
|
|
var reqHost = (new URL(req.url)).host;
|
|
// If there is a service worker present, the redirections will be
|
|
// transparent, assuming that the original request is to the current
|
|
// site and would be intercepted.
|
|
if (isSWPresent) {
|
|
if (reqHost === location.host) {
|
|
is((new URL(res.url)).host, reqHost, "Response URL should be original URL with a SW present");
|
|
}
|
|
} else {
|
|
is((new URL(res.url)).host, (new URL(test.hops[test.hops.length-1].server)).host, "Response URL should be redirected URL");
|
|
}
|
|
return res.text().then(function(v) {
|
|
is(v, "<res>hello pass</res>\n",
|
|
"wrong responseText in test for " + test.toSource());
|
|
});
|
|
}, function(e) {
|
|
ok(!test.pass, "Expected test failure for " + test.toSource());
|
|
ok(e instanceof TypeError, "Exception should be TypeError for " + test.toSource());
|
|
});
|
|
})(request, test));
|
|
}
|
|
|
|
return Promise.all(fetches);
|
|
}
|
|
|
|
function testNoCORSRedirects() {
|
|
var origin = "http://mochi.test:8888";
|
|
|
|
var tests = [
|
|
{ pass: 1,
|
|
method: "GET",
|
|
hops: [{ server: "http://example.com",
|
|
},
|
|
],
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
hops: [{ server: origin,
|
|
},
|
|
{ server: "http://example.com",
|
|
},
|
|
],
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
// Must use a simple header due to no-cors header restrictions.
|
|
headers: { "accept-language": "en-us",
|
|
},
|
|
hops: [{ server: origin,
|
|
},
|
|
{ server: "http://example.com",
|
|
},
|
|
],
|
|
},
|
|
{ pass: 1,
|
|
method: "GET",
|
|
hops: [{ server: origin,
|
|
},
|
|
{ server: "http://example.com",
|
|
},
|
|
{ server: origin,
|
|
}
|
|
],
|
|
},
|
|
{ pass: 1,
|
|
method: "POST",
|
|
body: 'upload body here',
|
|
hops: [{ server: origin
|
|
},
|
|
{ server: "http://example.com",
|
|
},
|
|
],
|
|
},
|
|
{ pass: 0,
|
|
method: "DELETE",
|
|
hops: [{ server: origin
|
|
},
|
|
{ server: "http://example.com",
|
|
},
|
|
],
|
|
},
|
|
];
|
|
|
|
var fetches = [];
|
|
for (test of tests) {
|
|
req = {
|
|
url: test.hops[0].server + corsServerPath + "hop=1&hops=" +
|
|
escape(test.hops.toSource()),
|
|
method: test.method,
|
|
headers: test.headers,
|
|
body: test.body,
|
|
};
|
|
|
|
if (test.headers) {
|
|
req.url += "&headers=" + escape(test.headers.toSource());
|
|
}
|
|
|
|
if (test.pass) {
|
|
if (test.body)
|
|
req.url += "&body=" + escape(test.body);
|
|
}
|
|
|
|
fetches.push((function(req, test) {
|
|
return new Promise(function(resolve, reject) {
|
|
resolve(new Request(req.url, { mode: 'no-cors',
|
|
method: req.method,
|
|
headers: req.headers,
|
|
body: req.body }));
|
|
}).then(function(request) {
|
|
return fetch(request);
|
|
}).then(function(res) {
|
|
ok(test.pass, "Expected test to pass for " + test.toSource());
|
|
// All requests are cross-origin no-cors, we should always have
|
|
// an opaque response here. All values on the opaque response
|
|
// should be hidden.
|
|
is(res.type, 'opaque', 'wrong response type for ' + test.toSource());
|
|
is(res.status, 0, "wrong status in test for " + test.toSource());
|
|
is(res.statusText, "", "wrong status text for " + test.toSource());
|
|
is(res.url, '', 'wrong response url for ' + test.toSource());
|
|
return res.text().then(function(v) {
|
|
is(v, "", "wrong responseText in test for " + test.toSource());
|
|
});
|
|
}, function(e) {
|
|
ok(!test.pass, "Expected test failure for " + test.toSource());
|
|
ok(e instanceof TypeError, "Exception should be TypeError for " + test.toSource());
|
|
});
|
|
})(req, test));
|
|
}
|
|
|
|
return Promise.all(fetches);
|
|
}
|
|
|
|
function testReferrer() {
|
|
var referrer;
|
|
if (self && self.location) {
|
|
referrer = self.location.href;
|
|
} else {
|
|
referrer = document.documentURI;
|
|
}
|
|
|
|
var dict = {
|
|
'Referer': referrer
|
|
};
|
|
return fetch(corsServerPath + "headers=" + dict.toSource()).then(function(res) {
|
|
is(res.status, 200, "expected correct referrer header to be sent");
|
|
dump(res.statusText);
|
|
}, function(e) {
|
|
ok(false, "expected correct referrer header to be sent");
|
|
});
|
|
}
|
|
|
|
function runTest() {
|
|
testNoCorsCtor();
|
|
|
|
return Promise.resolve()
|
|
.then(testModeSameOrigin)
|
|
.then(testModeNoCors)
|
|
.then(testModeCors)
|
|
.then(testSameOriginCredentials)
|
|
.then(testCrossOriginCredentials)
|
|
.then(testCORSRedirects)
|
|
.then(testNoCORSRedirects)
|
|
.then(testReferrer)
|
|
// Put more promise based tests here.
|
|
}
|