mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-27 04:05:32 +00:00
540 lines
20 KiB
JavaScript
540 lines
20 KiB
JavaScript
function testDefaultCtor() {
|
|
var req = new Request("");
|
|
is(req.method, "GET", "Default Request method is GET");
|
|
ok(req.headers instanceof Headers, "Request should have non-null Headers object");
|
|
is(req.url, self.location.href, "URL should be resolved with entry settings object's API base URL");
|
|
is(req.destination, "", "Default destination is the empty string.");
|
|
is(req.referrer, "about:client", "Default referrer is `client` which serializes to about:client.");
|
|
is(req.mode, "cors", "Request mode for string input is cors");
|
|
is(req.credentials, "same-origin", "Default Request credentials is same-origin");
|
|
is(req.cache, "default", "Default Request cache is default");
|
|
|
|
var req = new Request(req);
|
|
is(req.method, "GET", "Default Request method is GET");
|
|
ok(req.headers instanceof Headers, "Request should have non-null Headers object");
|
|
is(req.url, self.location.href, "URL should be resolved with entry settings object's API base URL");
|
|
is(req.destination, "", "Default destination is the empty string.");
|
|
is(req.referrer, "about:client", "Default referrer is `client` which serializes to about:client.");
|
|
is(req.mode, "cors", "Request mode string input is cors");
|
|
is(req.credentials, "same-origin", "Default Request credentials is same-origin");
|
|
is(req.cache, "default", "Default Request cache is default");
|
|
}
|
|
|
|
function testClone() {
|
|
var orig = new Request("./cloned_request.txt", {
|
|
method: 'POST',
|
|
headers: { "Sample-Header": "5" },
|
|
body: "Sample body",
|
|
mode: "same-origin",
|
|
credentials: "same-origin",
|
|
cache: "no-store",
|
|
});
|
|
var clone = orig.clone();
|
|
ok(clone.method === "POST", "Request method is POST");
|
|
ok(clone.headers instanceof Headers, "Request should have non-null Headers object");
|
|
|
|
is(clone.headers.get('sample-header'), "5", "Request sample-header should be 5.");
|
|
orig.headers.set('sample-header', 6);
|
|
is(clone.headers.get('sample-header'), "5", "Cloned Request sample-header should continue to be 5.");
|
|
|
|
ok(clone.url === (new URL("./cloned_request.txt", self.location.href)).href,
|
|
"URL should be resolved with entry settings object's API base URL");
|
|
ok(clone.referrer === "about:client", "Default referrer is `client` which serializes to about:client.");
|
|
ok(clone.mode === "same-origin", "Request mode is same-origin");
|
|
ok(clone.credentials === "same-origin", "Default credentials is same-origin");
|
|
ok(clone.cache === "no-store", "Default cache is no-store");
|
|
|
|
ok(!orig.bodyUsed, "Original body is not consumed.");
|
|
ok(!clone.bodyUsed, "Clone body is not consumed.");
|
|
|
|
var origBody = null;
|
|
var clone2 = null;
|
|
return orig.text().then(function (body) {
|
|
origBody = body;
|
|
is(origBody, "Sample body", "Original body string matches");
|
|
ok(orig.bodyUsed, "Original body is consumed.");
|
|
ok(!clone.bodyUsed, "Clone body is not consumed.");
|
|
|
|
try {
|
|
orig.clone()
|
|
ok(false, "Cannot clone Request whose body is already consumed");
|
|
} catch (e) {
|
|
is(e.name, "TypeError", "clone() of consumed body should throw TypeError");
|
|
}
|
|
|
|
clone2 = clone.clone();
|
|
return clone.text();
|
|
}).then(function (body) {
|
|
is(body, origBody, "Clone body matches original body.");
|
|
ok(clone.bodyUsed, "Clone body is consumed.");
|
|
|
|
try {
|
|
clone.clone()
|
|
ok(false, "Cannot clone Request whose body is already consumed");
|
|
} catch (e) {
|
|
is(e.name, "TypeError", "clone() of consumed body should throw TypeError");
|
|
}
|
|
|
|
return clone2.text();
|
|
}).then(function (body) {
|
|
is(body, origBody, "Clone body matches original body.");
|
|
ok(clone2.bodyUsed, "Clone body is consumed.");
|
|
|
|
try {
|
|
clone2.clone()
|
|
ok(false, "Cannot clone Request whose body is already consumed");
|
|
} catch (e) {
|
|
is(e.name, "TypeError", "clone() of consumed body should throw TypeError");
|
|
}
|
|
});
|
|
}
|
|
|
|
function testUsedRequest() {
|
|
// Passing a used request should fail.
|
|
var req = new Request("", { method: 'post', body: "This is foo" });
|
|
var p1 = req.text().then(function(v) {
|
|
try {
|
|
var req2 = new Request(req);
|
|
ok(false, "Used Request cannot be passed to new Request");
|
|
} catch(e) {
|
|
ok(true, "Used Request cannot be passed to new Request");
|
|
}
|
|
});
|
|
|
|
// Passing a request should set the request as used.
|
|
var reqA = new Request("", { method: 'post', body: "This is foo" });
|
|
var reqB = new Request(reqA);
|
|
is(reqA.bodyUsed, true, "Passing a Request to another Request should set the former as used");
|
|
return p1;
|
|
}
|
|
|
|
function testSimpleUrlParse() {
|
|
// Just checks that the URL parser is actually being used.
|
|
var req = new Request("/file.html");
|
|
is(req.url, (new URL("/file.html", self.location.href)).href, "URL parser should be used to resolve Request URL");
|
|
}
|
|
|
|
// Bug 1109574 - Passing a Request with null body should keep bodyUsed unset.
|
|
function testBug1109574() {
|
|
var r1 = new Request("");
|
|
is(r1.bodyUsed, false, "Initial value of bodyUsed should be false");
|
|
var r2 = new Request(r1);
|
|
is(r1.bodyUsed, false, "Request with null body should not have bodyUsed set");
|
|
// This should succeed.
|
|
var r3 = new Request(r1);
|
|
}
|
|
|
|
// Bug 1184550 - Request constructor should always throw if used flag is set,
|
|
// even if body is null
|
|
function testBug1184550() {
|
|
var req = new Request("", { method: 'post', body: "Test" });
|
|
fetch(req);
|
|
ok(req.bodyUsed, "Request body should be used immediately after fetch()");
|
|
return fetch(req).then(function(resp) {
|
|
ok(false, "Second fetch with same request should fail.");
|
|
}).catch(function(err) {
|
|
is(err.name, 'TypeError', "Second fetch with same request should fail.");
|
|
});
|
|
}
|
|
|
|
function testHeaderGuard() {
|
|
var headers = {
|
|
"Cookie": "Custom cookie",
|
|
"Non-Simple-Header": "value",
|
|
};
|
|
var r1 = new Request("", { headers: headers });
|
|
ok(!r1.headers.has("Cookie"), "Default Request header should have guard request and prevent setting forbidden header.");
|
|
ok(r1.headers.has("Non-Simple-Header"), "Default Request header should have guard request and allow setting non-simple header.");
|
|
|
|
var r2 = new Request("", { mode: "no-cors", headers: headers });
|
|
ok(!r2.headers.has("Cookie"), "no-cors Request header should have guard request-no-cors and prevent setting non-simple header.");
|
|
ok(!r2.headers.has("Non-Simple-Header"), "no-cors Request header should have guard request-no-cors and prevent setting non-simple header.");
|
|
}
|
|
|
|
function testMode() {
|
|
var req = new Request("http://example.com", {mode: "navigate"});
|
|
ok(true, "Creating a Request with navigate RequestMode should not throw.");
|
|
is(req.mode, "same-origin", "Request mode becomes same-origin");
|
|
}
|
|
|
|
function testMethod() {
|
|
// These get normalized.
|
|
var allowed = ["delete", "get", "head", "options", "post", "put" ];
|
|
for (var i = 0; i < allowed.length; ++i) {
|
|
try {
|
|
var r = new Request("", { method: allowed[i] });
|
|
ok(true, "Method " + allowed[i] + " should be allowed");
|
|
is(r.method, allowed[i].toUpperCase(),
|
|
"Standard HTTP method " + allowed[i] + " should be normalized");
|
|
} catch(e) {
|
|
ok(false, "Method " + allowed[i] + " should be allowed");
|
|
}
|
|
}
|
|
|
|
var allowed = [ "pAtCh", "foo" ];
|
|
for (var i = 0; i < allowed.length; ++i) {
|
|
try {
|
|
var r = new Request("", { method: allowed[i] });
|
|
ok(true, "Method " + allowed[i] + " should be allowed");
|
|
is(r.method, allowed[i],
|
|
"Non-standard but valid HTTP method " + allowed[i] +
|
|
" should not be normalized");
|
|
} catch(e) {
|
|
ok(false, "Method " + allowed[i] + " should be allowed");
|
|
}
|
|
}
|
|
|
|
var forbidden = ["connect", "trace", "track", "<invalid token??"];
|
|
for (var i = 0; i < forbidden.length; ++i) {
|
|
try {
|
|
var r = new Request("", { method: forbidden[i] });
|
|
ok(false, "Method " + forbidden[i] + " should be forbidden");
|
|
} catch(e) {
|
|
ok(true, "Method " + forbidden[i] + " should be forbidden");
|
|
}
|
|
}
|
|
|
|
var allowedNoCors = ["get", "head", "post"];
|
|
for (var i = 0; i < allowedNoCors.length; ++i) {
|
|
try {
|
|
var r = new Request("", { method: allowedNoCors[i], mode: "no-cors" });
|
|
ok(true, "Method " + allowedNoCors[i] + " should be allowed in no-cors mode");
|
|
} catch(e) {
|
|
ok(false, "Method " + allowedNoCors[i] + " should be allowed in no-cors mode");
|
|
}
|
|
}
|
|
|
|
var forbiddenNoCors = ["aardvark", "delete", "options", "put"];
|
|
for (var i = 0; i < forbiddenNoCors.length; ++i) {
|
|
try {
|
|
var r = new Request("", { method: forbiddenNoCors[i], mode: "no-cors" });
|
|
ok(false, "Method " + forbiddenNoCors[i] + " should be forbidden in no-cors mode");
|
|
} catch(e) {
|
|
ok(true, "Method " + forbiddenNoCors[i] + " should be forbidden in no-cors mode");
|
|
}
|
|
}
|
|
|
|
// HEAD/GET requests cannot have a body.
|
|
try {
|
|
var r = new Request("", { method: "get", body: "hello" });
|
|
ok(false, "HEAD/GET request cannot have a body");
|
|
} catch(e) {
|
|
is(e.name, "TypeError", "HEAD/GET request cannot have a body");
|
|
}
|
|
|
|
try {
|
|
var r = new Request("", { method: "head", body: "hello" });
|
|
ok(false, "HEAD/GET request cannot have a body");
|
|
} catch(e) {
|
|
is(e.name, "TypeError", "HEAD/GET request cannot have a body");
|
|
}
|
|
// Non HEAD/GET should not throw.
|
|
var r = new Request("", { method: "patch", body: "hello" });
|
|
}
|
|
function testUrlFragment() {
|
|
var req = new Request("./request#withfragment");
|
|
is(req.url, (new URL("./request#withfragment", self.location.href)).href,
|
|
"request.url should be serialized without exclude fragment flag set");
|
|
}
|
|
function testUrlMalformed() {
|
|
try {
|
|
var req = new Request("http:// example.com");
|
|
ok(false, "Creating a Request with a malformed URL should throw a TypeError");
|
|
} catch(e) {
|
|
is(e.name, "TypeError", "Creating a Request with a malformed URL should throw a TypeError");
|
|
}
|
|
}
|
|
|
|
function testUrlCredentials() {
|
|
try {
|
|
var req = new Request("http://user@example.com");
|
|
ok(false, "URLs with credentials should be rejected");
|
|
} catch(e) {
|
|
is(e.name, "TypeError", "URLs with credentials should be rejected");
|
|
}
|
|
|
|
try {
|
|
var req = new Request("http://user:password@example.com");
|
|
ok(false, "URLs with credentials should be rejected");
|
|
} catch(e) {
|
|
is(e.name, "TypeError", "URLs with credentials should be rejected");
|
|
}
|
|
}
|
|
|
|
function testBodyUsed() {
|
|
var req = new Request("./bodyused", { method: 'post', body: "Sample body" });
|
|
is(req.bodyUsed, false, "bodyUsed is initially false.");
|
|
return req.text().then((v) => {
|
|
is(v, "Sample body", "Body should match");
|
|
is(req.bodyUsed, true, "After reading body, bodyUsed should be true.");
|
|
}).then((v) => {
|
|
return req.blob().then((v) => {
|
|
ok(false, "Attempting to read body again should fail.");
|
|
}, (e) => {
|
|
ok(true, "Attempting to read body again should fail.");
|
|
})
|
|
});
|
|
}
|
|
|
|
var text = "κόσμε";
|
|
function testBodyCreation() {
|
|
var req1 = new Request("", { method: 'post', body: text });
|
|
var p1 = req1.text().then(function(v) {
|
|
ok(typeof v === "string", "Should resolve to string");
|
|
is(text, v, "Extracted string should match");
|
|
});
|
|
|
|
var req2 = new Request("", { method: 'post', body: new Uint8Array([72, 101, 108, 108, 111]) });
|
|
var p2 = req2.text().then(function(v) {
|
|
is("Hello", v, "Extracted string should match");
|
|
});
|
|
|
|
var req2b = new Request("", { method: 'post', body: (new Uint8Array([72, 101, 108, 108, 111])).buffer });
|
|
var p2b = req2b.text().then(function(v) {
|
|
is("Hello", v, "Extracted string should match");
|
|
});
|
|
|
|
var reqblob = new Request("", { method: 'post', body: new Blob([text]) });
|
|
var pblob = reqblob.text().then(function(v) {
|
|
is(v, text, "Extracted string should match");
|
|
});
|
|
|
|
// FormData has its own function since it has blobs and files.
|
|
|
|
var params = new URLSearchParams();
|
|
params.append("item", "Geckos");
|
|
params.append("feature", "stickyfeet");
|
|
params.append("quantity", "700");
|
|
var req3 = new Request("", { method: 'post', body: params });
|
|
var p3 = req3.text().then(function(v) {
|
|
var extracted = new URLSearchParams(v);
|
|
is(extracted.get("item"), "Geckos", "Param should match");
|
|
is(extracted.get("feature"), "stickyfeet", "Param should match");
|
|
is(extracted.get("quantity"), "700", "Param should match");
|
|
});
|
|
|
|
return Promise.all([p1, p2, p2b, pblob, p3]);
|
|
}
|
|
|
|
function testFormDataBodyCreation() {
|
|
var f1 = new FormData();
|
|
f1.append("key", "value");
|
|
f1.append("foo", "bar");
|
|
|
|
var r1 = new Request("", { method: 'post', body: f1 })
|
|
// Since f1 is serialized immediately, later additions should not show up.
|
|
f1.append("more", "stuff");
|
|
var p1 = r1.formData().then(function(fd) {
|
|
ok(fd instanceof FormData, "Valid FormData extracted.");
|
|
ok(fd.has("key"), "key should exist.");
|
|
ok(fd.has("foo"), "foo should exist.");
|
|
ok(!fd.has("more"), "more should not exist.");
|
|
});
|
|
|
|
f1.append("blob", new Blob([text]));
|
|
var r2 = new Request("", { method: 'post', body: f1 });
|
|
f1.delete("key");
|
|
var p2 = r2.formData().then(function(fd) {
|
|
ok(fd instanceof FormData, "Valid FormData extracted.");
|
|
ok(fd.has("more"), "more should exist.");
|
|
|
|
var b = fd.get("blob");
|
|
ok(b.name, "blob", "blob entry should be a Blob.");
|
|
ok(b instanceof Blob, "blob entry should be a Blob.");
|
|
|
|
return readAsText(b).then(function(output) {
|
|
is(output, text, "Blob contents should match.");
|
|
});
|
|
});
|
|
|
|
return Promise.all([p1, p2]);
|
|
}
|
|
|
|
function testBodyExtraction() {
|
|
var text = "κόσμε";
|
|
var newReq = function() { return new Request("", { method: 'post', body: text }); }
|
|
return newReq().text().then(function(v) {
|
|
ok(typeof v === "string", "Should resolve to string");
|
|
is(text, v, "Extracted string should match");
|
|
}).then(function() {
|
|
return newReq().blob().then(function(v) {
|
|
ok(v instanceof Blob, "Should resolve to Blob");
|
|
return readAsText(v).then(function(result) {
|
|
is(result, text, "Decoded Blob should match original");
|
|
});
|
|
});
|
|
}).then(function() {
|
|
return newReq().json().then(function(v) {
|
|
ok(false, "Invalid json should reject");
|
|
}, function(e) {
|
|
ok(true, "Invalid json should reject");
|
|
})
|
|
}).then(function() {
|
|
return newReq().arrayBuffer().then(function(v) {
|
|
ok(v instanceof ArrayBuffer, "Should resolve to ArrayBuffer");
|
|
var dec = new TextDecoder();
|
|
is(dec.decode(new Uint8Array(v)), text, "UTF-8 decoded ArrayBuffer should match original");
|
|
});
|
|
}).then(function() {
|
|
return newReq().formData().then(function(v) {
|
|
ok(false, "invalid FormData read should fail.");
|
|
}, function(e) {
|
|
ok(e.name == "TypeError", "invalid FormData read should fail.");
|
|
});
|
|
});
|
|
}
|
|
|
|
function testFormDataBodyExtraction() {
|
|
// URLSearchParams translates to application/x-www-form-urlencoded.
|
|
var params = new URLSearchParams();
|
|
params.append("item", "Geckos");
|
|
params.append("feature", "stickyfeet");
|
|
params.append("quantity", "700");
|
|
params.append("quantity", "800");
|
|
|
|
var req = new Request("", { method: 'POST', body: params });
|
|
var p1 = req.formData().then(function(fd) {
|
|
ok(fd.has("item"), "Has entry 'item'.");
|
|
ok(fd.has("feature"), "Has entry 'feature'.");
|
|
var entries = fd.getAll("quantity");
|
|
is(entries.length, 2, "Entries with same name are correctly handled.");
|
|
is(entries[0], "700", "Entries with same name are correctly handled.");
|
|
is(entries[1], "800", "Entries with same name are correctly handled.");
|
|
});
|
|
|
|
var f1 = new FormData();
|
|
f1.append("key", "value");
|
|
f1.append("foo", "bar");
|
|
f1.append("blob", new Blob([text]));
|
|
var r2 = new Request("", { method: 'post', body: f1 });
|
|
var p2 = r2.formData().then(function(fd) {
|
|
ok(fd.has("key"), "Has entry 'key'.");
|
|
ok(fd.has("foo"), "Has entry 'foo'.");
|
|
ok(fd.has("blob"), "Has entry 'blob'.");
|
|
var entries = fd.getAll("blob");
|
|
is(entries.length, 1, "getAll returns all items.");
|
|
is(entries[0].name, "blob", "Filename should be blob.");
|
|
ok(entries[0] instanceof Blob, "getAll returns blobs.");
|
|
});
|
|
|
|
var ws = "\r\n\r\n\r\n\r\n";
|
|
f1.set("key", new File([ws], 'file name has spaces.txt', { type: 'new/lines' }));
|
|
var r3 = new Request("", { method: 'post', body: f1 });
|
|
var p3 = r3.formData().then(function(fd) {
|
|
ok(fd.has("foo"), "Has entry 'foo'.");
|
|
ok(fd.has("blob"), "Has entry 'blob'.");
|
|
var entries = fd.getAll("blob");
|
|
is(entries.length, 1, "getAll returns all items.");
|
|
is(entries[0].name, "blob", "Filename should be blob.");
|
|
ok(entries[0] instanceof Blob, "getAll returns blobs.");
|
|
|
|
ok(fd.has("key"), "Has entry 'key'.");
|
|
var f = fd.get("key");
|
|
ok(f instanceof File, "entry should be a File.");
|
|
is(f.name, "file name has spaces.txt", "File name should match.");
|
|
is(f.type, "new/lines", "File type should match.");
|
|
is(f.size, ws.length, "File size should match.");
|
|
return readAsText(f).then(function(text) {
|
|
is(text, ws, "File contents should match.");
|
|
});
|
|
});
|
|
|
|
// Override header and ensure parse fails.
|
|
var boundary = "1234567891011121314151617";
|
|
var body = boundary +
|
|
'\r\nContent-Disposition: form-data; name="greeting"\r\n\r\n"hello"\r\n' +
|
|
boundary + '-';
|
|
|
|
var r4 = new Request("", { method: 'post', body: body, headers: {
|
|
"Content-Type": "multipart/form-datafoobar; boundary="+boundary,
|
|
}});
|
|
var p4 = r4.formData().then(function() {
|
|
ok(false, "Invalid mimetype should fail.");
|
|
}, function() {
|
|
ok(true, "Invalid mimetype should fail.");
|
|
});
|
|
|
|
var r5 = new Request("", { method: 'POST', body: params, headers: {
|
|
"Content-Type": "application/x-www-form-urlencodedfoobar",
|
|
}});
|
|
var p5 = r5.formData().then(function() {
|
|
ok(false, "Invalid mimetype should fail.");
|
|
}, function() {
|
|
ok(true, "Invalid mimetype should fail.");
|
|
});
|
|
return Promise.all([p1, p2, p3, p4]);
|
|
}
|
|
|
|
// mode cannot be set to "CORS-with-forced-preflight" from javascript.
|
|
function testModeCorsPreflightEnumValue() {
|
|
try {
|
|
var r = new Request(".", { mode: "cors-with-forced-preflight" });
|
|
ok(false, "Creating Request with mode cors-with-forced-preflight should fail.");
|
|
} catch(e) {
|
|
ok(true, "Creating Request with mode cors-with-forced-preflight should fail.");
|
|
// Also ensure that the error message matches error messages for truly
|
|
// invalid strings.
|
|
var invalidMode = "not-in-requestmode-enum";
|
|
var invalidExc;
|
|
try {
|
|
var r = new Request(".", { mode: invalidMode });
|
|
} catch(e) {
|
|
invalidExc = e;
|
|
}
|
|
var expectedMessage = invalidExc.message.replace(invalidMode, 'cors-with-forced-preflight');
|
|
is(e.message, expectedMessage,
|
|
"mode cors-with-forced-preflight should throw same error as invalid RequestMode strings.");
|
|
}
|
|
}
|
|
|
|
// HEAD/GET Requests are not allowed to have a body even when copying another
|
|
// Request.
|
|
function testBug1154268() {
|
|
var r1 = new Request("/index.html", { method: "POST", body: "Hi there" });
|
|
["HEAD", "GET"].forEach(function(method) {
|
|
try {
|
|
var r2 = new Request(r1, { method: method });
|
|
ok(false, method + " Request copied from POST Request with body should fail.");
|
|
} catch (e) {
|
|
is(e.name, "TypeError", method + " Request copied from POST Request with body should fail.");
|
|
}
|
|
});
|
|
}
|
|
|
|
function testRequestConsumedByFailedConstructor(){
|
|
var r1 = new Request('http://example.com', { method: 'POST', body: 'hello world' });
|
|
try{
|
|
var r2 = new Request(r1, { method: 'GET' });
|
|
ok(false, 'GET Request copied from POST Request with body should fail.');
|
|
} catch(e) {
|
|
ok(true, 'GET Request copied from POST Request with body should fail.');
|
|
}
|
|
ok(!r1.bodyUsed, 'Initial request should not be consumed by failed Request constructor');
|
|
}
|
|
|
|
function runTest() {
|
|
testDefaultCtor();
|
|
testSimpleUrlParse();
|
|
testUrlFragment();
|
|
testUrlCredentials();
|
|
testUrlMalformed();
|
|
testMode();
|
|
testMethod();
|
|
testBug1109574();
|
|
testBug1184550();
|
|
testHeaderGuard();
|
|
testModeCorsPreflightEnumValue();
|
|
testBug1154268();
|
|
testRequestConsumedByFailedConstructor();
|
|
|
|
return Promise.resolve()
|
|
.then(testBodyCreation)
|
|
.then(testBodyUsed)
|
|
.then(testBodyExtraction)
|
|
.then(testFormDataBodyCreation)
|
|
.then(testFormDataBodyExtraction)
|
|
.then(testUsedRequest)
|
|
.then(testClone())
|
|
// Put more promise based tests here.
|
|
}
|