Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
380 changes: 285 additions & 95 deletions lib/XMLHttpRequest.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"node": ">=12.0.0"
},
"scripts": {
"test": "cd ./tests && node test-constants.js && node test-events.js && node test-exceptions.js && node test-headers.js && node test-redirect-302.js && node test-redirect-303.js && node test-redirect-307.js && node test-request-methods.js && node test-request-protocols-txt-data.js && node test-request-protocols-binary-data.js && node test-sync-response.js && node test-utf8-tearing.js && node test-keepalive.js"
"test": "cd ./tests && node run-test.js"
},
"directories": {
"lib": "./lib",
Expand Down
50 changes: 50 additions & 0 deletions tests/run-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
var ignored_files = [
"run-test.js", // this file
"server.js"
];

var spawnSync = require("child_process").spawnSync;
var fs = require("fs");
var path = require("path");

// global flag to check if some of test fails, and will store location of failed test file
var fail_path = false;

// function to read and conduct test case
var run_test = function (file) {
if (fail_path) return;
// logging
console.log("Running:", file);

// spawn a nodejs process
var proc = spawnSync("node", [file]);

if (proc.status === 0) {
console.log(proc.stdout.toString());
console.log("--> PASSED");
}
else {
fail_path = file;
console.log("--> TEST FAILED - CAUGHT ERROR:", proc.stderr.toString());
}
}

var check_dir = function (dirPath) {
if (fail_path) return;
var files = fs.readdirSync(dirPath);

for (var file of files) {
// return early in case something fails
if (fail_path) return;
var full_path = path.join(dirPath, file);
if (fs.statSync(full_path).isDirectory()) check_dir(full_path);
else if (path.extname(file) === ".js" && !ignored_files.includes(full_path)) run_test(full_path);
}
}

// start test
check_dir("./");

if (fail_path) throw new Error("Test failed at file: " + fail_path);

console.log("ALL TESTS PASSED.");
22 changes: 20 additions & 2 deletions tests/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@ var http = require("http");

var server = http.createServer(function (req, res) {
switch (req.url) {
case "/": {
var body = "Hello World";
res.writeHead(200, {
"Content-Type": "text/plain",
"Content-Length": Buffer.byteLength(body),
"Date": "Thu, 30 Aug 2012 18:17:53 GMT",
"Connection": "close"
});
res.end(body);
return;
}
case "/text":
res.writeHead(200, {"Content-Type": "text/plain"})
res.end("Hello world!");
Expand All @@ -27,8 +38,15 @@ var server = http.createServer(function (req, res) {
res.end(str);
return;
default:
res.writeHead(404, {"Content-Type": "text/plain"})
res.end("Not found");
if (req.url.startsWith('/redirectingResource/')) {
let remaining = req.url.replace(/^\/redirectingResource\/*/, "") - 1;
res.writeHead(301, {'Location': remaining ? ('http://localhost:8888/redirectingResource/' + remaining) : 'http://localhost:8888/'});
res.end();
}
else {
res.writeHead(404, {"Content-Type": "text/plain"})
res.end("Not found");
}
}
}).listen(8888);

Expand Down
131 changes: 131 additions & 0 deletions tests/test-data-uri.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
var sys = require("util")
, assert = require("assert")
, XMLHttpRequest = require("../lib/XMLHttpRequest").XMLHttpRequest
, xhr;

xhr = new XMLHttpRequest();

// define test data
var tests = [
{
name: "Test plain URI Data",
data: "data:,Hello%20World",
output: "Hello World"
},
{
name: "Test plain URI Data with spaces",
data: "data:, Hello World",
output: " Hello World"
},
{
name: "Test plain URI Data with data URI headers",
data: "data:base64;example=1;args=2,Hello%20World",
output: "Hello World"
},
{
name: "Test normal bass64-encoded data URI",
data: "data:text;base64,SGVsbG8gV29ybGQ=",
output: "Hello World"
},
{
name: "Test normal bass64-encoded data URI with mixed space characters",
data: "data:text;base64,SGV sbG8gV\n29ybGQ=",
output: "Hello World"
},
{
name: "Test normal bass64-encoded data URI with mixed space characters (url-encoded)",
data: "data:text;base64,SGV%20sbG8gV%0a29ybGQ=",
output: "Hello World"
},
{
name: "Test normal bass64-encoded data URI with invalid characters",
data: "data:text;base64,SGV&&&&sbG8gV{29ybGQ=",
error: "Invalid data URI"
},
{
name: "Test normal bass64-encoded data URI with invalid characters (url-encoded)",
data: "data:text;base64,SGV%26%26%26%26sbG8gV%7B29ybGQ%3D",
error: "Invalid data URI"
},
{
name: "Test base64-encoded data with no paddings",
data: "data:text;base64,SGVsbG8gV29ybGQ",
output: "Hello World"
},
{
name: "Test base64-encoded data with excessive paddings",
data: "data:text;base64,SGVsbG8gV29ybGQ==",
error: "Invalid data URI"
}
];

var tests_passed = 0;

var runAsyncTest = function (test) {
console.log(" ASYNC");

xhr = new XMLHttpRequest;
xhr.open("get", test.data);
xhr.onreadystatechange = function () {
if (this.readyState === 4) {
if (test.error) {
assert.equal(xhr.status, 0);
assert.equal(xhr.statusText, test.error);
}
else {
assert.equal(xhr.status, 200);
assert.equal(xhr.responseText, test.output);
}
console.log(" --> SUCESS");
++tests_passed;
}
}
xhr.send();
}

var runSyncTest = function (test) {
console.log(" SYNC");

xhr = new XMLHttpRequest;
xhr.open("get", test.data, false);
try {
xhr.send();
if (test.error) throw "Expected to fail, Success with " + e.responseText;
assert.equal(xhr.status, 200);
assert.equal(xhr.responseText, test.output);
}
catch (e) {
if (!test.error) throw "Expected to success, Caught error: " + e.toString()
assert.equal(xhr.status, 0);
assert.equal(e.message, test.error);
}
console.log(" --> SUCESS");
++tests_passed;
}

var i = 0;

var startTest = function () {
let test = tests[i];

if (!test) {
console.log("Done:", tests_passed === tests.length * 2 ? "PASS" : "FAILED");
return;
}

console.log(test.name);

runAsyncTest(test);

setTimeout(function () {
try {
runSyncTest(test);
}
catch (e) { console.error(e) };
console.log("");
++i;
startTest();
}, 500);
}

startTest();
36 changes: 36 additions & 0 deletions tests/test-disallow-fs-resources.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
var sys = require("util")
, assert = require("assert")
, XMLHttpRequest = require("../lib/XMLHttpRequest").XMLHttpRequest
, xhr;

xhr = new XMLHttpRequest({ allowFileSystemResources: false });

xhr.onreadystatechange = function() {
if (this.readyState === 4) {
assert.equal(this.statusText, "Not allowed to load local resource: " + url);
assert.equal(this.status, 0);
try { runSync(); } catch (e) {
if (e instanceof assert.AssertionError) console.error(e);
}
}
};

// Async
var url = "file://" + __dirname + "/testdata.txt";
xhr.open("GET", url);
xhr.send();

// Sync
var runSync = function() {
xhr = new XMLHttpRequest({ allowFileSystemResources: false });

xhr.onreadystatechange = function() {
if (this.readyState === 4) {
assert.equal(this.statusText, "Not allowed to load local resource: " + url);
assert.equal(this.status, 0);
console.log("done");
}
};
xhr.open("GET", url, false);
xhr.send();
}
47 changes: 47 additions & 0 deletions tests/test-max-redirects.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
var sys = require("util")
, assert = require("assert")
, XMLHttpRequest = require("../lib/XMLHttpRequest").XMLHttpRequest
, spawn = require('child_process').spawn;

// Test server
var serverProcess = spawn(process.argv[0], [__dirname + "/server.js"], { stdio: 'inherit' });

var runTest = function () {
try {
let xhr = new XMLHttpRequest({ maxRedirects: 10 });
xhr.open("GET", "http://localhost:8888/redirectingResource/10", false);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
assert.equal(xhr.getRequestHeader('Location'), '');
assert.equal(xhr.responseText, "Hello World");
console.log("safe redirects count: done");
}
};
xhr.send();
} catch(e) {
console.log("ERROR: Exception raised", e);
}

try {
let xhr = new XMLHttpRequest({ maxRedirects: 10 });
xhr.open("GET", "http://localhost:8888/redirectingResource/20", false);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
assert.equal(xhr.statusText, 'Too many redirects');
assert.equal(xhr.status, 0);
console.log("excessive redirects count: done");
}
};
xhr.send();
} catch(e) {
if (e.message !== 'Too many redirects') console.log("ERROR: Exception raised", e);
}
}

setTimeout(function () {
try {
runTest();
} finally {
serverProcess.kill('SIGINT');
}
}, 100);
14 changes: 8 additions & 6 deletions tests/test-perf.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const XMLHttpRequest = require("../lib/XMLHttpRequest").XMLHttpRequest;
const supressConsoleOutput = false;
function log (_) {
if ( !supressConsoleOutput)
console.log(arguments);
console.log.apply(console, arguments);
}

var serverProcess;
Expand Down Expand Up @@ -94,12 +94,14 @@ function createServer() {
res.end(`success:len ${u8.length}`);
});
} else {
if (!storage[req.url])
if (!storage[req.url]) {
res.writeHead(404, {"Content-Type": "text/plain; charset=utf8"})
res.end("Not in storage");

res.writeHead(200, {"Content-Type": "application/octet-stream"})
res.end(storage[req.url]);
}
else {
res.writeHead(200, {"Content-Type": "application/octet-stream"})
res.end(storage[req.url]);
}
}
}).listen(8888);
process.on("SIGINT", function () {
Expand Down Expand Up @@ -216,7 +218,7 @@ function afterUpload(r) {
function afterDownload(ab) {
clearTimeout(handle);
console.log(`Download elapsed time:, ${Date.now() - _t0}ms`, ab.byteLength);
console.info(['...waiting to see elapsed time of download...'])
console.info('...waiting to see elapsed time of download...');
if (!success)
throw new Error("Download has taken far too long!");
}
Expand Down
41 changes: 41 additions & 0 deletions tests/test-redirect-301.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
var sys = require("util")
, assert = require("assert")
, XMLHttpRequest = require("../lib/XMLHttpRequest").XMLHttpRequest
, xhr = new XMLHttpRequest()
, http = require("http");

// Test server
var server = http.createServer(function (req, res) {
if (req.url === '/redirectingResource') {
res.writeHead(301, {'Location': 'http://localhost:8000/'});
res.end();
return;
}

var body = "Hello World";
res.writeHead(200, {
"Content-Type": "text/plain",
"Content-Length": Buffer.byteLength(body),
"Date": "Thu, 30 Aug 2012 18:17:53 GMT",
"Connection": "close"
});
res.write("Hello World");
res.end();

this.close();
}).listen(8000);

xhr.onreadystatechange = function() {
if (this.readyState === 4) {
assert.equal(xhr.getRequestHeader('Location'), '');
assert.equal(xhr.responseText, "Hello World");
console.log("done");
}
};

try {
xhr.open("GET", "http://localhost:8000/redirectingResource");
xhr.send();
} catch(e) {
console.log("ERROR: Exception raised", e);
}
Loading
Loading