Remove vendored express tests

This commit is contained in:
Ashcon Partovi
2025-04-11 18:22:01 -07:00
parent c684a0c8ce
commit a2df5195e0
20 changed files with 0 additions and 4511 deletions

View File

@@ -1 +0,0 @@
Test cases ported from [express](https://github.com/expressjs/express). MIT license.

File diff suppressed because it is too large Load Diff

View File

@@ -1,745 +0,0 @@
"use strict";
var assert = require("node:assert");
var AsyncLocalStorage = require("node:async_hooks").AsyncLocalStorage;
var express = require("express");
var request = require("supertest");
describe("express.json()", function () {
let app;
it("should parse JSON", function (done) {
request(createApp())
.post("/")
.set("Content-Type", "application/json")
.send('{"user":"tobi"}')
.expect(200, '{"user":"tobi"}', done);
});
it("should handle Content-Length: 0", function (done) {
request(createApp())
.post("/")
.set("Content-Type", "application/json")
.set("Content-Length", "0")
.expect(200, "{}", done);
});
it.todo("should handle empty message-body", function (done) {
request(createApp())
.post("/")
.set("Content-Type", "application/json")
.set("Transfer-Encoding", "chunked")
.expect(200, "{}", done);
});
it("should handle no message-body", function (done) {
request(createApp())
.post("/")
.set("Content-Type", "application/json")
.unset("Transfer-Encoding")
.expect(200, "{}", done);
});
// The old node error message modification in body parser is catching this
it("should 400 when only whitespace", function (done) {
request(createApp())
.post("/")
.set("Content-Type", "application/json")
.send(" \n")
.expect(400, "[entity.parse.failed] " + parseError(" \n"), done);
});
it("should 400 when invalid content-length", function (done) {
var app = express();
app.use(function (req, res, next) {
req.headers["content-length"] = "20"; // bad length
next();
});
app.use(express.json());
app.post("/", function (req, res) {
res.json(req.body);
});
request(app)
.post("/")
.set("Content-Type", "application/json")
.send('{"str":')
.expect(400, /content length/, done);
});
it("should handle duplicated middleware", function (done) {
var app = express();
app.use(express.json());
app.use(express.json());
app.post("/", function (req, res) {
res.json(req.body);
});
request(app)
.post("/")
.set("Content-Type", "application/json")
.send('{"user":"tobi"}')
.expect(200, '{"user":"tobi"}', done);
});
describe("when JSON is invalid", function () {
let app;
beforeAll(function () {
app = createApp();
});
it("should 400 for bad token", function (done) {
request(app)
.post("/")
.set("Content-Type", "application/json")
.send("{:")
.expect(400, "[entity.parse.failed] " + parseError("{:"), done);
});
it("should 400 for incomplete", function (done) {
request(app)
.post("/")
.set("Content-Type", "application/json")
.send('{"user"')
.expect(400, "[entity.parse.failed] " + parseError('{"user"'), done);
});
it("should include original body on error object", function (done) {
request(app)
.post("/")
.set("Content-Type", "application/json")
.set("X-Error-Property", "body")
.send(' {"user"')
.expect(400, ' {"user"', done);
});
});
describe("with limit option", function () {
it("should 413 when over limit with Content-Length", function (done) {
var buf = Buffer.alloc(1024, ".");
request(createApp({ limit: "1kb" }))
.post("/")
.set("Content-Type", "application/json")
.set("Content-Length", "1034")
.send(JSON.stringify({ str: buf.toString() }))
.expect(413, "[entity.too.large] request entity too large", done);
});
it("should 413 when over limit with chunked encoding", function (done) {
var app = createApp({ limit: "1kb" });
var buf = Buffer.alloc(1024, ".");
var test = request(app).post("/");
test.set("Content-Type", "application/json");
test.set("Transfer-Encoding", "chunked");
test.write('{"str":');
test.write('"' + buf.toString() + '"}');
test.expect(413, done);
});
it("should 413 when inflated body over limit", function (done) {
var app = createApp({ limit: "1kb" });
var test = request(app).post("/");
test.set("Content-Encoding", "gzip");
test.set("Content-Type", "application/json");
test.write(Buffer.from("1f8b080000000000000aab562a2e2952b252d21b05a360148c58a0540b0066f7ce1e0a040000", "hex"));
test.expect(413, done);
});
it("should accept number of bytes", function (done) {
var buf = Buffer.alloc(1024, ".");
request(createApp({ limit: 1024 }))
.post("/")
.set("Content-Type", "application/json")
.send(JSON.stringify({ str: buf.toString() }))
.expect(413, done);
});
it("should not change when options altered", function (done) {
var buf = Buffer.alloc(1024, ".");
var options = { limit: "1kb" };
var app = createApp(options);
options.limit = "100kb";
request(app)
.post("/")
.set("Content-Type", "application/json")
.send(JSON.stringify({ str: buf.toString() }))
.expect(413, done);
});
it("should not hang response", function (done) {
var buf = Buffer.alloc(10240, ".");
var app = createApp({ limit: "8kb" });
var test = request(app).post("/");
test.set("Content-Type", "application/json");
test.write(buf);
test.write(buf);
test.write(buf);
test.expect(413, done);
});
it("should not error when inflating", function (done) {
var app = createApp({ limit: "1kb" });
var test = request(app).post("/");
test.set("Content-Encoding", "gzip");
test.set("Content-Type", "application/json");
test.write(Buffer.from("1f8b080000000000000aab562a2e2952b252d21b05a360148c58a0540b0066f7ce1e0a0400", "hex"));
test.expect(413, done);
});
});
describe("with inflate option", function () {
describe("when false", function () {
beforeAll(function () {
app = createApp({ inflate: false });
});
it.todo("should not accept content-encoding", function (done) {
var test = request(app).post("/");
test.set("Content-Encoding", "gzip");
test.set("Content-Type", "application/json");
test.write(Buffer.from("1f8b080000000000000bab56ca4bcc4d55b2527ab16e97522d00515be1cc0e000000", "hex"));
test.expect(415, "[encoding.unsupported] content encoding unsupported", done);
});
});
describe("when true", function () {
beforeAll(function () {
app = createApp({ inflate: true });
});
it("should accept content-encoding", function (done) {
var test = request(app).post("/");
test.set("Content-Encoding", "gzip");
test.set("Content-Type", "application/json");
test.write(Buffer.from("1f8b080000000000000bab56ca4bcc4d55b2527ab16e97522d00515be1cc0e000000", "hex"));
test.expect(200, '{"name":"论"}', done);
});
});
});
describe("with strict option", function () {
describe("when undefined", function () {
beforeAll(function () {
app = createApp();
});
it("should 400 on primitives", function (done) {
request(app)
.post("/")
.set("Content-Type", "application/json")
.send("true")
.expect(400, "[entity.parse.failed] " + parseError("#rue").replace(/#/g, "t"), done);
});
});
describe("when false", function () {
beforeAll(function () {
app = createApp({ strict: false });
});
it.todo("should parse primitives", function (done) {
request(app).post("/").set("Content-Type", "application/json").send("true").expect(200, "true", done);
});
});
describe("when true", function () {
beforeAll(function () {
app = createApp({ strict: true });
});
it("should not parse primitives", function (done) {
request(app)
.post("/")
.set("Content-Type", "application/json")
.send("true")
.expect(400, "[entity.parse.failed] " + parseError("#rue").replace(/#/g, "t"), done);
});
it("should not parse primitives with leading whitespaces", function (done) {
request(app)
.post("/")
.set("Content-Type", "application/json")
.send(" true")
.expect(400, "[entity.parse.failed] " + parseError(" #rue").replace(/#/g, "t"), done);
});
it("should allow leading whitespaces in JSON", function (done) {
request(app)
.post("/")
.set("Content-Type", "application/json")
.send(' { "user": "tobi" }')
.expect(200, '{"user":"tobi"}', done);
});
it("should include correct message in stack trace", function (done) {
request(app)
.post("/")
.set("Content-Type", "application/json")
.set("X-Error-Property", "stack")
.send("true")
.expect(400)
.expect(shouldContainInBody(parseError("#rue").replace(/#/g, "t")))
.end(done);
});
});
});
describe("with type option", function () {
describe.skip('when "application/vnd.api+json"', function () {
beforeAll(function () {
app = createApp({ type: "application/vnd.api+json" });
});
it("should parse JSON for custom type", function (done) {
request(app)
.post("/")
.set("Content-Type", "application/vnd.api+json")
.send('{"user":"tobi"}')
.expect(200, '{"user":"tobi"}', done);
});
it("should ignore standard type", function (done) {
request(app).post("/").set("Content-Type", "application/json").send('{"user":"tobi"}').expect(200, "", done);
});
});
describe('when ["application/json", "application/vnd.api+json"]', function () {
beforeAll(function () {
app = createApp({
type: ["application/json", "application/vnd.api+json"],
});
});
it('should parse JSON for "application/json"', function (done) {
request(app)
.post("/")
.set("Content-Type", "application/json")
.send('{"user":"tobi"}')
.expect(200, '{"user":"tobi"}', done);
});
it.todo('should parse JSON for "application/vnd.api+json"', function (done) {
request(app)
.post("/")
.set("Content-Type", "application/vnd.api+json")
.send('{"user":"tobi"}')
.expect(200, '{"user":"tobi"}', done);
});
it.todo('should ignore "application/x-json"', function (done) {
request(app).post("/").set("Content-Type", "application/x-json").send('{"user":"tobi"}').expect(200, "", done);
});
});
describe("when a function", function () {
it("should parse when truthy value returned", function (done) {
var app = createApp({ type: accept });
function accept(req) {
return req.headers["content-type"] === "application/vnd.api+json";
}
request(app)
.post("/")
.set("Content-Type", "application/vnd.api+json")
.send('{"user":"tobi"}')
.expect(200, '{"user":"tobi"}', done);
});
it("should work without content-type", function (done) {
var app = createApp({ type: accept });
function accept(req) {
return true;
}
var test = request(app).post("/");
test.write('{"user":"tobi"}');
test.expect(200, '{"user":"tobi"}', done);
});
it("should not invoke without a body", function (done) {
var app = createApp({ type: accept });
function accept(req) {
throw new Error("oops!");
}
request(app).get("/").expect(404, done);
});
});
});
describe("with verify option", function () {
it("should assert value if function", function () {
assert.throws(createApp.bind(null, { verify: "lol" }), /TypeError: option verify must be function/);
});
it("should error from verify", function (done) {
var app = createApp({
verify: function (req, res, buf) {
if (buf[0] === 0x5b) throw new Error("no arrays");
},
});
request(app)
.post("/")
.set("Content-Type", "application/json")
.send('["tobi"]')
.expect(403, "[entity.verify.failed] no arrays", done);
});
it("should allow custom codes", function (done) {
var app = createApp({
verify: function (req, res, buf) {
if (buf[0] !== 0x5b) return;
var err = new Error("no arrays");
err.status = 400;
throw err;
},
});
request(app)
.post("/")
.set("Content-Type", "application/json")
.send('["tobi"]')
.expect(400, "[entity.verify.failed] no arrays", done);
});
it("should allow custom type", function (done) {
var app = createApp({
verify: function (req, res, buf) {
if (buf[0] !== 0x5b) return;
var err = new Error("no arrays");
err.type = "foo.bar";
throw err;
},
});
request(app)
.post("/")
.set("Content-Type", "application/json")
.send('["tobi"]')
.expect(403, "[foo.bar] no arrays", done);
});
it("should include original body on error object", function (done) {
var app = createApp({
verify: function (req, res, buf) {
if (buf[0] === 0x5b) throw new Error("no arrays");
},
});
request(app)
.post("/")
.set("Content-Type", "application/json")
.set("X-Error-Property", "body")
.send('["tobi"]')
.expect(403, '["tobi"]', done);
});
it("should allow pass-through", function (done) {
var app = createApp({
verify: function (req, res, buf) {
if (buf[0] === 0x5b) throw new Error("no arrays");
},
});
request(app)
.post("/")
.set("Content-Type", "application/json")
.send('{"user":"tobi"}')
.expect(200, '{"user":"tobi"}', done);
});
it("should work with different charsets", function (done) {
var app = createApp({
verify: function (req, res, buf) {
if (buf[0] === 0x5b) throw new Error("no arrays");
},
});
var test = request(app).post("/");
test.set("Content-Type", "application/json; charset=utf-16");
test.write(Buffer.from("feff007b0022006e0061006d00650022003a00228bba0022007d", "hex"));
test.expect(200, '{"name":"论"}', done);
});
it("should 415 on unknown charset prior to verify", function (done) {
var app = createApp({
verify: function (req, res, buf) {
throw new Error("unexpected verify call");
},
});
var test = request(app).post("/");
test.set("Content-Type", "application/json; charset=x-bogus");
test.write(Buffer.from("00000000", "hex"));
test.expect(415, '[charset.unsupported] unsupported charset "X-BOGUS"', done);
});
});
describe.todo("async local storage", function () {
beforeAll(function () {
var app = express();
var store = { foo: "bar" };
app.use(function (req, res, next) {
req.asyncLocalStorage = new AsyncLocalStorage();
req.asyncLocalStorage.run(store, next);
});
app.use(express.json());
app.use(function (req, res, next) {
var local = req.asyncLocalStorage.getStore();
if (local) {
res.setHeader("x-store-foo", String(local.foo));
}
next();
});
app.use(function (err, req, res, next) {
var local = req.asyncLocalStorage.getStore();
if (local) {
res.setHeader("x-store-foo", String(local.foo));
}
res.status(err.status || 500);
res.send("[" + err.type + "] " + err.message);
});
app.post("/", function (req, res) {
res.json(req.body);
});
app = app;
});
it("should presist store", function (done) {
request(app)
.post("/")
.set("Content-Type", "application/json")
.send('{"user":"tobi"}')
.expect(200)
.expect("x-store-foo", "bar")
.expect('{"user":"tobi"}')
.end(done);
});
it("should persist store when unmatched content-type", function (done) {
request(app)
.post("/")
.set("Content-Type", "application/fizzbuzz")
.send("buzz")
.expect(200)
.expect("x-store-foo", "bar")
.expect("")
.end(done);
});
it("should presist store when inflated", function (done) {
var test = request(app).post("/");
test.set("Content-Encoding", "gzip");
test.set("Content-Type", "application/json");
test.write(Buffer.from("1f8b080000000000000bab56ca4bcc4d55b2527ab16e97522d00515be1cc0e000000", "hex"));
test.expect(200);
test.expect("x-store-foo", "bar");
test.expect('{"name":"论"}');
test.end(done);
});
it("should presist store when inflate error", function (done) {
var test = request(app).post("/");
test.set("Content-Encoding", "gzip");
test.set("Content-Type", "application/json");
test.write(Buffer.from("1f8b080000000000000bab56cc4d55b2527ab16e97522d00515be1cc0e000000", "hex"));
test.expect(400);
test.expect("x-store-foo", "bar");
test.end(done);
});
it("should presist store when parse error", function (done) {
request(app)
.post("/")
.set("Content-Type", "application/json")
.send('{"user":')
.expect(400)
.expect("x-store-foo", "bar")
.end(done);
});
it("should presist store when limit exceeded", function (done) {
request(app)
.post("/")
.set("Content-Type", "application/json")
.send('{"user":"' + Buffer.alloc(1024 * 100, ".").toString() + '"}')
.expect(413)
.expect("x-store-foo", "bar")
.end(done);
});
});
describe("charset", function () {
beforeAll(function () {
app = createApp();
});
it("should parse utf-8", function (done) {
var test = request(app).post("/");
test.set("Content-Type", "application/json; charset=utf-8");
test.write(Buffer.from("7b226e616d65223a22e8aeba227d", "hex"));
test.expect(200, '{"name":"论"}', done);
});
it("should parse utf-16", function (done) {
var test = request(app).post("/");
test.set("Content-Type", "application/json; charset=utf-16");
test.write(Buffer.from("feff007b0022006e0061006d00650022003a00228bba0022007d", "hex"));
test.expect(200, '{"name":"论"}', done);
});
it("should parse when content-length != char length", function (done) {
var test = request(app).post("/");
test.set("Content-Type", "application/json; charset=utf-8");
test.set("Content-Length", "13");
test.write(Buffer.from("7b2274657374223a22c3a5227d", "hex"));
test.expect(200, '{"test":"å"}', done);
});
it("should default to utf-8", function (done) {
var test = request(app).post("/");
test.set("Content-Type", "application/json");
test.write(Buffer.from("7b226e616d65223a22e8aeba227d", "hex"));
test.expect(200, '{"name":"论"}', done);
});
it("should fail on unknown charset", function (done) {
var test = request(app).post("/");
test.set("Content-Type", "application/json; charset=koi8-r");
test.write(Buffer.from("7b226e616d65223a22cec5d4227d", "hex"));
test.expect(415, '[charset.unsupported] unsupported charset "KOI8-R"', done);
});
});
describe("encoding", function () {
let app;
beforeAll(function () {
app = createApp({ limit: "1kb" });
});
it("should parse without encoding", function (done) {
var test = request(app).post("/");
test.set("Content-Type", "application/json");
test.write(Buffer.from("7b226e616d65223a22e8aeba227d", "hex"));
test.expect(200, '{"name":"论"}', done);
});
it("should support identity encoding", function (done) {
var test = request(app).post("/");
test.set("Content-Encoding", "identity");
test.set("Content-Type", "application/json");
test.write(Buffer.from("7b226e616d65223a22e8aeba227d", "hex"));
test.expect(200, '{"name":"论"}', done);
});
it("should support gzip encoding", function (done) {
var test = request(app).post("/");
test.set("Content-Encoding", "gzip");
test.set("Content-Type", "application/json");
test.write(Buffer.from("1f8b080000000000000bab56ca4bcc4d55b2527ab16e97522d00515be1cc0e000000", "hex"));
test.expect(200, '{"name":"论"}', done);
});
it("should support deflate encoding", function (done) {
var test = request(app).post("/");
test.set("Content-Encoding", "deflate");
test.set("Content-Type", "application/json");
test.write(Buffer.from("789cab56ca4bcc4d55b2527ab16e97522d00274505ac", "hex"));
test.expect(200, '{"name":"论"}', done);
});
it("should be case-insensitive", function (done) {
var test = request(app).post("/");
test.set("Content-Encoding", "GZIP");
test.set("Content-Type", "application/json");
test.write(Buffer.from("1f8b080000000000000bab56ca4bcc4d55b2527ab16e97522d00515be1cc0e000000", "hex"));
test.expect(200, '{"name":"论"}', done);
});
it("should 415 on unknown encoding", function (done) {
var test = request(app).post("/");
test.set("Content-Encoding", "nulls");
test.set("Content-Type", "application/json");
test.write(Buffer.from("000000000000", "hex"));
test.expect(415, '[encoding.unsupported] unsupported content encoding "nulls"', done);
});
it("should 400 on malformed encoding", function (done) {
var test = request(app).post("/");
test.set("Content-Encoding", "gzip");
test.set("Content-Type", "application/json");
test.write(Buffer.from("1f8b080000000000000bab56cc4d55b2527ab16e97522d00515be1cc0e000000", "hex"));
test.expect(400, done);
});
it("should 413 when inflated value exceeds limit", function (done) {
// gzip'd data exceeds 1kb, but deflated below 1kb
var test = request(app).post("/");
test.set("Content-Encoding", "gzip");
test.set("Content-Type", "application/json");
test.write(Buffer.from("1f8b080000000000000bedc1010d000000c2a0f74f6d0f071400000000000000", "hex"));
test.write(Buffer.from("0000000000000000000000000000000000000000000000000000000000000000", "hex"));
test.write(Buffer.from("0000000000000000004f0625b3b71650c30000", "hex"));
test.expect(413, done);
});
});
});
function createApp(options?) {
var app = express();
app.use(express.json(options));
app.use(function (err, req, res, next) {
// console.log(err)
res.status(err.status || 500);
res.send(
String(
req.headers["x-error-property"] ? err[req.headers["x-error-property"]] : "[" + err.type + "] " + err.message,
),
);
});
app.post("/", function (req, res) {
res.json(req.body);
});
return app;
}
function parseError(str) {
try {
JSON.parse(str);
throw new SyntaxError("strict violation");
} catch (e) {
return e.message;
}
}
function shouldContainInBody(str) {
return function (res) {
assert.ok(res.text.indexOf(str) !== -1, "expected '" + res.text + "' to contain '" + str + "'");
};
}

View File

@@ -1,44 +0,0 @@
// @ts-nocheck
// can't use @types/express or @types/body-parser because they
// depend on @types/node which conflicts with bun-types
import { expect, test } from "bun:test";
import express from "express";
import { isIPv6 } from "node:net";
// https://github.com/oven-sh/bun/issues/8926
test("should respond with 404 when wrong method is used", async () => {
const { promise: serve, resolve } = Promise.withResolvers();
const app = express();
app.use(express.json());
app.get("/api/hotels", (req, res) => {
res.json({
success: true,
});
});
const server = app.listen(0, (_, host, port) => {
if (isIPv6(host)) {
resolve(`http://[${host}]:${port}`);
} else {
resolve(`http://${host}:${port}`);
}
});
try {
const url = await serve;
const response = await fetch(`${url}/api/hotels`, {
method: "POST",
signal: AbortSignal.timeout(500),
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Hotel 1",
price: 100,
}),
});
expect(response.status).toBe(404);
} finally {
server.close();
}
});

View File

@@ -1,531 +0,0 @@
"use strict";
var assert = require("node:assert");
var AsyncLocalStorage = require("node:async_hooks").AsyncLocalStorage;
var express = require("express");
var request = require("supertest");
describe("express.text()", function () {
let app;
beforeAll(function () {
app = createApp();
});
it("should parse text/plain", function (done) {
request(app).post("/").set("Content-Type", "text/plain").send("user is tobi").expect(200, '"user is tobi"', done);
});
it("should 400 when invalid content-length", function (done) {
var app = express();
app.use(function (req, res, next) {
req.headers["content-length"] = "20"; // bad length
next();
});
app.use(express.text());
app.post("/", function (req, res) {
res.json(req.body);
});
request(app)
.post("/")
.set("Content-Type", "text/plain")
.send("user")
.expect(400, /content length/, done);
});
it("should handle Content-Length: 0", function (done) {
request(createApp({ limit: "1kb" }))
.post("/")
.set("Content-Type", "text/plain")
.set("Content-Length", "0")
.expect(200, '""', done);
});
it.todo("should handle empty message-body", function (done) {
request(createApp({ limit: "1kb" }))
.post("/")
.set("Content-Type", "text/plain")
.set("Transfer-Encoding", "chunked")
.send("")
.expect(200, '""', done);
});
it("should handle duplicated middleware", function (done) {
var app = express();
app.use(express.text());
app.use(express.text());
app.post("/", function (req, res) {
res.json(req.body);
});
request(app).post("/").set("Content-Type", "text/plain").send("user is tobi").expect(200, '"user is tobi"', done);
});
describe("with defaultCharset option", function () {
it("should change default charset", function (done) {
var server = createApp({ defaultCharset: "koi8-r" });
var test = request(server).post("/");
test.set("Content-Type", "text/plain");
test.write(Buffer.from("6e616d6520697320cec5d4", "hex"));
test.expect(200, '"name is нет"', done);
});
it("should honor content-type charset", function (done) {
var server = createApp({ defaultCharset: "koi8-r" });
var test = request(server).post("/");
test.set("Content-Type", "text/plain; charset=utf-8");
test.write(Buffer.from("6e616d6520697320e8aeba", "hex"));
test.expect(200, '"name is 论"', done);
});
});
describe("with limit option", function () {
it("should 413 when over limit with Content-Length", function (done) {
var buf = Buffer.alloc(1028, ".");
request(createApp({ limit: "1kb" }))
.post("/")
.set("Content-Type", "text/plain")
.set("Content-Length", "1028")
.send(buf.toString())
.expect(413, done);
});
it.todo("should 413 when over limit with chunked encoding", function (done) {
var app = createApp({ limit: "1kb" });
var buf = Buffer.alloc(1028, ".");
var test = request(app).post("/");
test.set("Content-Type", "text/plain");
test.set("Transfer-Encoding", "chunked");
test.write(buf.toString());
test.expect(413, done);
});
it("should 413 when inflated body over limit", function (done) {
var app = createApp({ limit: "1kb" });
var test = request(app).post("/");
test.set("Content-Encoding", "gzip");
test.set("Content-Type", "text/plain");
test.write(Buffer.from("1f8b080000000000000ad3d31b05a360148c64000087e5a14704040000", "hex"));
test.expect(413, done);
});
it("should accept number of bytes", function (done) {
var buf = Buffer.alloc(1028, ".");
request(createApp({ limit: 1024 }))
.post("/")
.set("Content-Type", "text/plain")
.send(buf.toString())
.expect(413, done);
});
it("should not change when options altered", function (done) {
var buf = Buffer.alloc(1028, ".");
var options = { limit: "1kb" };
var app = createApp(options);
options.limit = "100kb";
request(app).post("/").set("Content-Type", "text/plain").send(buf.toString()).expect(413, done);
});
it("should not hang response", function (done) {
var app = createApp({ limit: "8kb" });
var buf = Buffer.alloc(10240, ".");
var test = request(app).post("/");
test.set("Content-Type", "text/plain");
test.write(buf);
test.write(buf);
test.write(buf);
test.expect(413, done);
});
it("should not error when inflating", function (done) {
var app = createApp({ limit: "1kb" });
var test = request(app).post("/");
test.set("Content-Encoding", "gzip");
test.set("Content-Type", "text/plain");
test.write(Buffer.from("1f8b080000000000000ad3d31b05a360148c64000087e5a1470404", "hex"));
setTimeout(function () {
test.expect(413, done);
}, 100);
});
});
describe("with inflate option", function () {
describe.todo("when false", function () {
beforeAll(function () {
app = createApp({ inflate: false });
});
it("should not accept content-encoding", function (done) {
var test = request(app).post("/");
test.set("Content-Encoding", "gzip");
test.set("Content-Type", "text/plain");
test.write(Buffer.from("1f8b080000000000000bcb4bcc4d55c82c5678b16e170072b3e0200b000000", "hex"));
test.expect(415, "[encoding.unsupported] content encoding unsupported", done);
});
});
describe("when true", function () {
beforeAll(function () {
app = createApp({ inflate: true });
});
it("should accept content-encoding", function (done) {
var test = request(app).post("/");
test.set("Content-Encoding", "gzip");
test.set("Content-Type", "text/plain");
test.write(Buffer.from("1f8b080000000000000bcb4bcc4d55c82c5678b16e170072b3e0200b000000", "hex"));
test.expect(200, '"name is 论"', done);
});
});
});
describe("with type option", function () {
describe.todo('when "text/html"', function () {
beforeAll(function () {
app = createApp({ type: "text/html" });
});
it("should parse for custom type", function (done) {
request(app).post("/").set("Content-Type", "text/html").send("<b>tobi</b>").expect(200, '"<b>tobi</b>"', done);
});
it("should ignore standard type", function (done) {
request(app).post("/").set("Content-Type", "text/plain").send("user is tobi").expect(200, "", done);
});
});
describe('when ["text/html", "text/plain"]', function () {
beforeAll(function () {
app = createApp({ type: ["text/html", "text/plain"] });
});
it.todo('should parse "text/html"', function (done) {
request(app).post("/").set("Content-Type", "text/html").send("<b>tobi</b>").expect(200, '"<b>tobi</b>"', done);
});
it('should parse "text/plain"', function (done) {
request(app).post("/").set("Content-Type", "text/plain").send("tobi").expect(200, '"tobi"', done);
});
it.todo('should ignore "text/xml"', function (done) {
request(app).post("/").set("Content-Type", "text/xml").send("<user>tobi</user>").expect(200, "", done);
});
});
describe("when a function", function () {
it("should parse when truthy value returned", function (done) {
var app = createApp({ type: accept });
function accept(req) {
return req.headers["content-type"] === "text/vnd.something";
}
request(app)
.post("/")
.set("Content-Type", "text/vnd.something")
.send("user is tobi")
.expect(200, '"user is tobi"', done);
});
it("should work without content-type", function (done) {
var app = createApp({ type: accept });
function accept(req) {
return true;
}
var test = request(app).post("/");
test.write("user is tobi");
test.expect(200, '"user is tobi"', done);
});
it("should not invoke without a body", function (done) {
var app = createApp({ type: accept });
function accept(req) {
throw new Error("oops!");
}
request(app).get("/").expect(404, done);
});
});
});
describe("with verify option", function () {
it("should assert value is function", function () {
assert.throws(createApp.bind(null, { verify: "lol" }), /TypeError: option verify must be function/);
});
it("should error from verify", function (done) {
var app = createApp({
verify: function (req, res, buf) {
if (buf[0] === 0x20) throw new Error("no leading space");
},
});
request(app)
.post("/")
.set("Content-Type", "text/plain")
.send(" user is tobi")
.expect(403, "[entity.verify.failed] no leading space", done);
});
it("should allow custom codes", function (done) {
var app = createApp({
verify: function (req, res, buf) {
if (buf[0] !== 0x20) return;
var err = new Error("no leading space");
err.status = 400;
throw err;
},
});
request(app)
.post("/")
.set("Content-Type", "text/plain")
.send(" user is tobi")
.expect(400, "[entity.verify.failed] no leading space", done);
});
it("should allow pass-through", function (done) {
var app = createApp({
verify: function (req, res, buf) {
if (buf[0] === 0x20) throw new Error("no leading space");
},
});
request(app).post("/").set("Content-Type", "text/plain").send("user is tobi").expect(200, '"user is tobi"', done);
});
it("should 415 on unknown charset prior to verify", function (done) {
var app = createApp({
verify: function (req, res, buf) {
throw new Error("unexpected verify call");
},
});
var test = request(app).post("/");
test.set("Content-Type", "text/plain; charset=x-bogus");
test.write(Buffer.from("00000000", "hex"));
test.expect(415, '[charset.unsupported] unsupported charset "X-BOGUS"', done);
});
});
describe.todo("async local storage", function () {
beforeAll(function () {
var app = express();
var store = { foo: "bar" };
app.use(function (req, res, next) {
req.asyncLocalStorage = new AsyncLocalStorage();
req.asyncLocalStorage.run(store, next);
});
app.use(express.text());
app.use(function (req, res, next) {
var local = req.asyncLocalStorage.getStore();
if (local) {
res.setHeader("x-store-foo", String(local.foo));
}
next();
});
app.use(function (err, req, res, next) {
var local = req.asyncLocalStorage.getStore();
if (local) {
res.setHeader("x-store-foo", String(local.foo));
}
res.status(err.status || 500);
res.send("[" + err.type + "] " + err.message);
});
app.post("/", function (req, res) {
res.json(req.body);
});
app = app;
});
it("should presist store", function (done) {
request(app)
.post("/")
.set("Content-Type", "text/plain")
.send("user is tobi")
.expect(200)
.expect("x-store-foo", "bar")
.expect('"user is tobi"')
.end(done);
});
it("should presist store when unmatched content-type", function (done) {
request(app)
.post("/")
.set("Content-Type", "application/fizzbuzz")
.send("buzz")
.expect(200)
.expect("x-store-foo", "bar")
.end(done);
});
it("should presist store when inflated", function (done) {
var test = request(app).post("/");
test.set("Content-Encoding", "gzip");
test.set("Content-Type", "text/plain");
test.write(Buffer.from("1f8b080000000000000bcb4bcc4d55c82c5678b16e170072b3e0200b000000", "hex"));
test.expect(200);
test.expect("x-store-foo", "bar");
test.expect('"name is 论"');
test.end(done);
});
it("should presist store when inflate error", function (done) {
var test = request(app).post("/");
test.set("Content-Encoding", "gzip");
test.set("Content-Type", "text/plain");
test.write(Buffer.from("1f8b080000000000000bcb4bcc4d55c82c5678b16e170072b3e0200b0000", "hex"));
test.expect(400);
test.expect("x-store-foo", "bar");
test.end(done);
});
it("should presist store when limit exceeded", function (done) {
request(app)
.post("/")
.set("Content-Type", "text/plain")
.send("user is " + Buffer.alloc(1024 * 100, ".").toString())
.expect(413)
.expect("x-store-foo", "bar")
.end(done);
});
});
describe("charset", function () {
beforeAll(function () {
app = createApp();
});
it("should parse utf-8", function (done) {
var test = request(app).post("/");
test.set("Content-Type", "text/plain; charset=utf-8");
test.write(Buffer.from("6e616d6520697320e8aeba", "hex"));
test.expect(200, '"name is 论"', done);
});
it("should parse codepage charsets", function (done) {
var test = request(app).post("/");
test.set("Content-Type", "text/plain; charset=koi8-r");
test.write(Buffer.from("6e616d6520697320cec5d4", "hex"));
test.expect(200, '"name is нет"', done);
});
it("should parse when content-length != char length", function (done) {
var test = request(app).post("/");
test.set("Content-Type", "text/plain; charset=utf-8");
test.set("Content-Length", "11");
test.write(Buffer.from("6e616d6520697320e8aeba", "hex"));
test.expect(200, '"name is 论"', done);
});
it("should default to utf-8", function (done) {
var test = request(app).post("/");
test.set("Content-Type", "text/plain");
test.write(Buffer.from("6e616d6520697320e8aeba", "hex"));
test.expect(200, '"name is 论"', done);
});
it("should 415 on unknown charset", function (done) {
var test = request(app).post("/");
test.set("Content-Type", "text/plain; charset=x-bogus");
test.write(Buffer.from("00000000", "hex"));
test.expect(415, '[charset.unsupported] unsupported charset "X-BOGUS"', done);
});
});
describe("encoding", function () {
beforeAll(function () {
app = createApp({ limit: "10kb" });
});
it("should parse without encoding", function (done) {
var test = request(app).post("/");
test.set("Content-Type", "text/plain");
test.write(Buffer.from("6e616d6520697320e8aeba", "hex"));
test.expect(200, '"name is 论"', done);
});
it("should support identity encoding", function (done) {
var test = request(app).post("/");
test.set("Content-Encoding", "identity");
test.set("Content-Type", "text/plain");
test.write(Buffer.from("6e616d6520697320e8aeba", "hex"));
test.expect(200, '"name is 论"', done);
});
it("should support gzip encoding", function (done) {
var test = request(app).post("/");
test.set("Content-Encoding", "gzip");
test.set("Content-Type", "text/plain");
test.write(Buffer.from("1f8b080000000000000bcb4bcc4d55c82c5678b16e170072b3e0200b000000", "hex"));
test.expect(200, '"name is 论"', done);
});
it("should support deflate encoding", function (done) {
var test = request(app).post("/");
test.set("Content-Encoding", "deflate");
test.set("Content-Type", "text/plain");
test.write(Buffer.from("789ccb4bcc4d55c82c5678b16e17001a6f050e", "hex"));
test.expect(200, '"name is 论"', done);
});
it("should be case-insensitive", function (done) {
var test = request(app).post("/");
test.set("Content-Encoding", "GZIP");
test.set("Content-Type", "text/plain");
test.write(Buffer.from("1f8b080000000000000bcb4bcc4d55c82c5678b16e170072b3e0200b000000", "hex"));
test.expect(200, '"name is 论"', done);
});
it("should 415 on unknown encoding", function (done) {
var test = request(app).post("/");
test.set("Content-Encoding", "nulls");
test.set("Content-Type", "text/plain");
test.write(Buffer.from("000000000000", "hex"));
test.expect(415, '[encoding.unsupported] unsupported content encoding "nulls"', done);
});
});
});
function createApp(options) {
var app = express();
app.use(express.text(options));
app.use(function (err, req, res, next) {
res.status(err.status || 500);
res.send(
String(
req.headers["x-error-property"] ? err[req.headers["x-error-property"]] : "[" + err.type + "] " + err.message,
),
);
});
app.post("/", function (req, res) {
res.json(req.body);
});
return app;
}

View File

@@ -1 +0,0 @@
20%

View File

@@ -1 +0,0 @@
tobi

View File

@@ -1 +0,0 @@
<b>index</b>

View File

@@ -1 +0,0 @@
<h1>blog post</h1>

View File

@@ -1 +0,0 @@
tobi

View File

@@ -1 +0,0 @@
123456789

View File

@@ -1 +0,0 @@
<p>{{user.name}}</p>

View File

@@ -1,7 +0,0 @@
{
"name": "express-test",
"version": "1.0.0",
"dependencies": {
"express": "4.18.2"
}
}

View File

@@ -1,170 +0,0 @@
"use strict";
var express = require("express"),
request = require("supertest"),
assert = require("node:assert");
describe("res", function () {
describe(".json(object)", function () {
it("should not support jsonp callbacks", function (done) {
var app = express();
app.use(function (req, res) {
res.json({ foo: "bar" });
});
request(app).get("/?callback=foo").expect('{"foo":"bar"}', done);
});
it("should not override previous Content-Types", function (done) {
var app = express();
app.get("/", function (req, res) {
res.type("application/vnd.example+json");
res.json({ hello: "world" });
});
request(app)
.get("/")
.expect("Content-Type", "application/vnd.example+json; charset=utf-8")
.expect(200, '{"hello":"world"}', done);
});
describe("when given primitives", function () {
it("should respond with json for null", function (done) {
var app = express();
app.use(function (req, res) {
res.json(null);
});
request(app).get("/").expect("Content-Type", "application/json; charset=utf-8").expect(200, "null", done);
});
it("should respond with json for Number", function (done) {
var app = express();
app.use(function (req, res) {
res.json(300);
});
request(app).get("/").expect("Content-Type", "application/json; charset=utf-8").expect(200, "300", done);
});
it("should respond with json for String", function (done) {
var app = express();
app.use(function (req, res) {
res.json("str");
});
request(app).get("/").expect("Content-Type", "application/json; charset=utf-8").expect(200, '"str"', done);
});
});
describe("when given an array", function () {
it("should respond with json", function (done) {
var app = express();
app.use(function (req, res) {
res.json(["foo", "bar", "baz"]);
});
request(app)
.get("/")
.expect("Content-Type", "application/json; charset=utf-8")
.expect(200, '["foo","bar","baz"]', done);
});
});
describe("when given an object", function () {
it("should respond with json", function (done) {
var app = express();
app.use(function (req, res) {
res.json({ name: "tobi" });
});
request(app)
.get("/")
.expect("Content-Type", "application/json; charset=utf-8")
.expect(200, '{"name":"tobi"}', done);
});
});
describe('"json escape" setting', function () {
it("should be undefined by default", function () {
var app = express();
assert.strictEqual(app.get("json escape"), undefined);
});
it("should unicode escape HTML-sniffing characters", function (done) {
var app = express();
app.enable("json escape");
app.use(function (req, res) {
res.json({ "&": "<script>" });
});
request(app)
.get("/")
.expect("Content-Type", "application/json; charset=utf-8")
.expect(200, '{"\\u0026":"\\u003cscript\\u003e"}', done);
});
it("should not break undefined escape", function (done) {
var app = express();
app.enable("json escape");
app.use(function (req, res) {
res.json(undefined);
});
request(app).get("/").expect("Content-Type", "application/json; charset=utf-8").expect(200, "", done);
});
});
describe('"json replacer" setting', function () {
it("should be passed to JSON.stringify()", function (done) {
var app = express();
app.set("json replacer", function (key, val) {
return key[0] === "_" ? undefined : val;
});
app.use(function (req, res) {
res.json({ name: "tobi", _id: 12345 });
});
request(app)
.get("/")
.expect("Content-Type", "application/json; charset=utf-8")
.expect(200, '{"name":"tobi"}', done);
});
});
describe('"json spaces" setting', function () {
it("should be undefined by default", function () {
var app = express();
assert(undefined === app.get("json spaces"));
});
it("should be passed to JSON.stringify()", function (done) {
var app = express();
app.set("json spaces", 2);
app.use(function (req, res) {
res.json({ name: "tobi", age: 2 });
});
request(app)
.get("/")
.expect("Content-Type", "application/json; charset=utf-8")
.expect(200, '{\n "name": "tobi",\n "age": 2\n}', done);
});
});
});
});

View File

@@ -1,316 +0,0 @@
'use strict'
var express = require('express')
, request = require('supertest')
, assert = require('node:assert')
, url = require('node:url');
describe('res', function(){
describe('.location(url)', function(){
it('should set the header', function(done){
var app = express();
app.use(function(req, res){
res.location('http://google.com/').end();
});
request(app)
.get('/')
.expect('Location', 'http://google.com/')
.expect(200, done)
})
it('should preserve trailing slashes when not present', function(done){
var app = express();
app.use(function(req, res){
res.location('http://google.com').end();
});
request(app)
.get('/')
.expect('Location', 'http://google.com')
.expect(200, done)
})
it('should encode "url"', function (done) {
var app = express()
app.use(function (req, res) {
res.location('https://google.com?q=\u2603 §10').end()
})
request(app)
.get('/')
.expect('Location', 'https://google.com?q=%E2%98%83%20%C2%A710')
.expect(200, done)
})
it('should encode data uri1', function (done) {
var app = express()
app.use(function (req, res) {
res.location('data:text/javascript,export default () => { }').end();
});
request(app)
.get('/')
.expect('Location', 'data:text/javascript,export%20default%20()%20=%3E%20%7B%20%7D')
.expect(200, done)
})
it('should encode data uri2', function (done) {
var app = express()
app.use(function (req, res) {
res.location('data:text/javascript,export default () => { }').end();
});
request(app)
.get('/')
.expect('Location', 'data:text/javascript,export%20default%20()%20=%3E%20%7B%20%7D')
.expect(200, done)
})
it('should consistently handle non-string input: boolean', function (done) {
var app = express()
app.use(function (req, res) {
res.location(true).end();
});
request(app)
.get('/')
.expect('Location', 'true')
.expect(200, done)
});
it('should consistently handle non-string inputs: object', function (done) {
var app = express()
app.use(function (req, res) {
res.location({}).end();
});
request(app)
.get('/')
.expect('Location', '[object%20Object]')
.expect(200, done)
});
it.todo('should consistently handle non-string inputs: array', function (done) {
var app = express()
app.use(function (req, res) {
res.location([]).end();
});
request(app)
.get('/')
.expect('Location', '')
.expect(200, done)
});
it.todo('should consistently handle empty string input', function (done) {
var app = express()
app.use(function (req, res) {
res.location('').end();
});
request(app)
.get('/')
.expect('Location', '')
.expect(200, done)
});
if (typeof URL !== 'undefined') {
it('should accept an instance of URL', function (done) {
var app = express();
app.use(function(req, res){
res.location(new URL('http://google.com/')).end();
});
request(app)
.get('/')
.expect('Location', 'http://google.com/')
.expect(200, done);
});
}
})
describe('location header encoding', function() {
function createRedirectServerForDomain (domain) {
var app = express();
app.use(function (req, res) {
var host = url.parse(req.query.q, false, true).host;
// This is here to show a basic check one might do which
// would pass but then the location header would still be bad
if (host !== domain) {
res.status(400).end('Bad host: ' + host + ' !== ' + domain);
}
res.location(req.query.q).end();
});
return app;
}
function testRequestedRedirect (app, inputUrl, expected, expectedHost, done) {
return request(app)
// Encode uri because old supertest does not and is required
// to test older node versions. New supertest doesn't re-encode
// so this works in both.
.get('/?q=' + encodeURIComponent(inputUrl))
.expect('') // No body.
.expect(200)
.expect('Location', expected)
.end(function (err, res) {
if (err) {
console.log('headers:', res.headers)
console.error('error', res.error, err);
return done(err, res);
}
// Parse the hosts from the input URL and the Location header
var inputHost = url.parse(inputUrl, false, true).host;
var locationHost = url.parse(res.headers['location'], false, true).host;
assert.strictEqual(locationHost, expectedHost);
// Assert that the hosts are the same
if (inputHost !== locationHost) {
return done(new Error('Hosts do not match: ' + inputHost + " !== " + locationHost));
}
return done(null, res);
});
}
it('should not touch already-encoded sequences in "url"', function (done) {
var app = createRedirectServerForDomain('google.com');
testRequestedRedirect(
app,
'https://google.com?q=%A710',
'https://google.com?q=%A710',
'google.com',
done
);
});
it('should consistently handle relative urls', function (done) {
var app = createRedirectServerForDomain(null);
testRequestedRedirect(
app,
'/foo/bar',
'/foo/bar',
null,
done
);
});
it.todo('should not encode urls in such a way that they can bypass redirect allow lists', function (done) {
var app = createRedirectServerForDomain('google.com');
testRequestedRedirect(
app,
'http://google.com\\@apple.com',
'http://google.com\\@apple.com',
'google.com',
done
);
});
it.todo('should not be case sensitive', function (done) {
var app = createRedirectServerForDomain('google.com');
testRequestedRedirect(
app,
'HTTP://google.com\\@apple.com',
'HTTP://google.com\\@apple.com',
'google.com',
done
);
});
it.todo('should work with https', function (done) {
var app = createRedirectServerForDomain('google.com');
testRequestedRedirect(
app,
'https://google.com\\@apple.com',
'https://google.com\\@apple.com',
'google.com',
done
);
});
it.todo('should correctly encode schemaless paths', function (done) {
var app = createRedirectServerForDomain('google.com');
testRequestedRedirect(
app,
'//google.com\\@apple.com/',
'//google.com\\@apple.com/',
'google.com',
done
);
});
it.todo('should keep backslashes in the path', function (done) {
var app = createRedirectServerForDomain('google.com');
testRequestedRedirect(
app,
'https://google.com/foo\\bar\\baz',
'https://google.com/foo\\bar\\baz',
'google.com',
done
);
});
it.todo('should escape header splitting for old node versions', function (done) {
var app = createRedirectServerForDomain('google.com');
testRequestedRedirect(
app,
'http://google.com\\@apple.com/%0d%0afoo:%20bar',
'http://google.com\\@apple.com/%0d%0afoo:%20bar',
'google.com',
done
);
});
it('should encode unicode correctly', function (done) {
var app = createRedirectServerForDomain(null);
testRequestedRedirect(
app,
'/%e2%98%83',
'/%e2%98%83',
null,
done
);
});
it.todo('should encode unicode correctly even with a bad host', function (done) {
var app = createRedirectServerForDomain('google.com');
testRequestedRedirect(
app,
'http://google.com\\@apple.com/%e2%98%83',
'http://google.com\\@apple.com/%e2%98%83',
'google.com',
done
);
});
it('should work correctly despite using deprecated url.parse', function (done) {
var app = createRedirectServerForDomain('google.com');
testRequestedRedirect(
app,
'https://google.com\'.bb.com/1.html',
'https://google.com\'.bb.com/1.html',
'google.com',
done
);
});
it.todo('should encode file uri path', function (done) {
var app = createRedirectServerForDomain('');
testRequestedRedirect(
app,
'file:///etc\\passwd',
'file:///etc\\passwd',
'',
done
);
});
});
})

View File

@@ -1,214 +0,0 @@
'use strict'
var express = require('express');
var request = require('supertest');
var utils = require('./support/utils');
describe('res', function(){
describe('.redirect(url)', function(){
it('should default to a 302 redirect', function(done){
var app = express();
app.use(function(req, res){
res.redirect('http://google.com');
});
request(app)
.get('/')
.expect('location', 'http://google.com')
.expect(302, done)
})
it('should encode "url"', function (done) {
var app = express()
app.use(function (req, res) {
res.redirect('https://google.com?q=\u2603 §10')
})
request(app)
.get('/')
.expect('Location', 'https://google.com?q=%E2%98%83%20%C2%A710')
.expect(302, done)
})
it('should not touch already-encoded sequences in "url"', function (done) {
var app = express()
app.use(function (req, res) {
res.redirect('https://google.com?q=%A710')
})
request(app)
.get('/')
.expect('Location', 'https://google.com?q=%A710')
.expect(302, done)
})
})
describe('.redirect(status, url)', function(){
it('should set the response status', function(done){
var app = express();
app.use(function(req, res){
res.redirect(303, 'http://google.com');
});
request(app)
.get('/')
.expect('Location', 'http://google.com')
.expect(303, done)
})
})
describe('when the request method is HEAD', function(){
it('should ignore the body', function(done){
var app = express();
app.use(function(req, res){
res.redirect('http://google.com');
});
request(app)
.head('/')
.expect(302)
.expect('Location', 'http://google.com')
.expect(utils.shouldNotHaveBody())
.end(done)
})
})
describe('when accepting html', function(){
it.todo('should respond with html', function(done){
var app = express();
app.use(function(req, res){
res.redirect('http://google.com');
});
request(app)
.get('/')
.set('Accept', 'text/html')
.expect('Content-Type', /html/)
.expect('Location', 'http://google.com')
.expect(302, '<p>Found. Redirecting to http://google.com</p>', done)
})
it.todo('should escape the url', function(done){
var app = express();
app.use(function(req, res){
res.redirect('<la\'me>');
});
request(app)
.get('/')
.set('Host', 'http://example.com')
.set('Accept', 'text/html')
.expect('Content-Type', /html/)
.expect('Location', '%3Cla\'me%3E')
.expect(302, '<p>Found. Redirecting to %3Cla&#39;me%3E</p>', done)
})
it.todo('should not render evil javascript links in anchor href (prevent XSS)', function(done){
var app = express();
var xss = 'javascript:eval(document.body.innerHTML=`<p>XSS</p>`);';
var encodedXss = 'javascript:eval(document.body.innerHTML=%60%3Cp%3EXSS%3C/p%3E%60);';
app.use(function(req, res){
res.redirect(xss);
});
request(app)
.get('/')
.set('Host', 'http://example.com')
.set('Accept', 'text/html')
.expect('Content-Type', /html/)
.expect('Location', encodedXss)
.expect(302, '<p>Found. Redirecting to ' + encodedXss +'</p>', done);
});
it.todo('should include the redirect type', function(done){
var app = express();
app.use(function(req, res){
res.redirect(301, 'http://google.com');
});
request(app)
.get('/')
.set('Accept', 'text/html')
.expect('Content-Type', /html/)
.expect('Location', 'http://google.com')
.expect(301, '<p>Moved Permanently. Redirecting to http://google.com</p>', done);
})
})
describe('when accepting text', function(){
it('should respond with text', function(done){
var app = express();
app.use(function(req, res){
res.redirect('http://google.com');
});
request(app)
.get('/')
.set('Accept', 'text/plain, */*')
.expect('Content-Type', /plain/)
.expect('Location', 'http://google.com')
.expect(302, 'Found. Redirecting to http://google.com', done)
})
it('should encode the url', function(done){
var app = express();
app.use(function(req, res){
res.redirect('http://example.com/?param=<script>alert("hax");</script>');
});
request(app)
.get('/')
.set('Host', 'http://example.com')
.set('Accept', 'text/plain, */*')
.expect('Content-Type', /plain/)
.expect('Location', 'http://example.com/?param=%3Cscript%3Ealert(%22hax%22);%3C/script%3E')
.expect(302, 'Found. Redirecting to http://example.com/?param=%3Cscript%3Ealert(%22hax%22);%3C/script%3E', done)
})
it('should include the redirect type', function(done){
var app = express();
app.use(function(req, res){
res.redirect(301, 'http://google.com');
});
request(app)
.get('/')
.set('Accept', 'text/plain, */*')
.expect('Content-Type', /plain/)
.expect('Location', 'http://google.com')
.expect(301, 'Moved Permanently. Redirecting to http://google.com', done);
})
})
describe('when accepting neither text or html', function(){
it('should respond with an empty body', function(done){
var app = express();
app.use(function(req, res){
res.redirect('http://google.com');
});
request(app)
.get('/')
.set('Accept', 'application/octet-stream')
.expect(302)
.expect('location', 'http://google.com')
.expect('content-length', '0')
.expect(utils.shouldNotHaveHeader('Content-Type'))
.expect(utils.shouldNotHaveBody())
.end(done)
})
})
})

View File

@@ -1,475 +0,0 @@
"use strict";
var assert = require("node:assert");
var express = require("express");
var request = require("supertest");
var utils = require("./support/utils");
var shouldSkipQuery = require("./support/utils").shouldSkipQuery;
var methods = utils.methods;
describe("res", function () {
describe(".send()", function () {
it('should set body to ""', function (done) {
var app = express();
app.use(function (req, res) {
res.send();
});
request(app).get("/").expect(200, "", done);
});
});
describe(".send(null)", function () {
it('should set body to ""', function (done) {
var app = express();
app.use(function (req, res) {
res.send(null);
});
request(app).get("/").expect("Content-Length", "0").expect(200, "", done);
});
});
describe(".send(undefined)", function () {
it('should set body to ""', function (done) {
var app = express();
app.use(function (req, res) {
res.send(undefined);
});
request(app).get("/").expect(200, "", done);
});
});
describe(".send(Number)", function () {
it.todo("should send as application/json", function (done) {
var app = express();
app.use(function (req, res) {
res.send(1000);
});
request(app).get("/").expect("Content-Type", "application/json; charset=utf-8").expect(200, "1000", done);
});
});
describe(".send(String)", function () {
it("should send as html", function (done) {
var app = express();
app.use(function (req, res) {
res.send("<p>hey</p>");
});
request(app).get("/").expect("Content-Type", "text/html; charset=utf-8").expect(200, "<p>hey</p>", done);
});
it("should set ETag", function (done) {
var app = express();
app.use(function (req, res) {
var str = Array(1000).join("-");
res.send(str);
});
request(app).get("/").expect("ETag", 'W/"3e7-qPnkJ3CVdVhFJQvUBfF10TmVA7g"').expect(200, done);
});
it("should not override Content-Type", function (done) {
var app = express();
app.use(function (req, res) {
res.set("Content-Type", "text/plain").send("hey");
});
request(app).get("/").expect("Content-Type", "text/plain; charset=utf-8").expect(200, "hey", done);
});
it("should override charset in Content-Type", function (done) {
var app = express();
app.use(function (req, res) {
res.set("Content-Type", "text/plain; charset=iso-8859-1").send("hey");
});
request(app).get("/").expect("Content-Type", "text/plain; charset=utf-8").expect(200, "hey", done);
});
it("should keep charset in Content-Type for Buffers", function (done) {
var app = express();
app.use(function (req, res) {
res.set("Content-Type", "text/plain; charset=iso-8859-1").send(Buffer.from("hi"));
});
request(app).get("/").expect("Content-Type", "text/plain; charset=iso-8859-1").expect(200, "hi", done);
});
});
describe(".send(Buffer)", function () {
it("should send as octet-stream", function (done) {
var app = express();
app.use(function (req, res) {
res.send(Buffer.from("hello"));
});
request(app)
.get("/")
.expect(200)
.expect("Content-Type", "application/octet-stream")
.expect(utils.shouldHaveBody(Buffer.from("hello")))
.end(done);
});
it("should set ETag", function (done) {
var app = express();
app.use(function (req, res) {
res.send(Buffer.alloc(999, "-"));
});
request(app).get("/").expect("ETag", 'W/"3e7-qPnkJ3CVdVhFJQvUBfF10TmVA7g"').expect(200, done);
});
it("should not override Content-Type", function (done) {
var app = express();
app.use(function (req, res) {
res.set("Content-Type", "text/plain").send(Buffer.from("hey"));
});
request(app).get("/").expect("Content-Type", "text/plain; charset=utf-8").expect(200, "hey", done);
});
it.todo("should accept Uint8Array", function (done) {
var app = express();
app.use(function (req, res) {
const encodedHey = new TextEncoder().encode("hey");
res.set("Content-Type", "text/plain").send(encodedHey);
});
request(app).get("/").expect("Content-Type", "text/plain; charset=utf-8").expect(200, "hey", done);
});
it("should not override ETag", function (done) {
var app = express();
app.use(function (req, res) {
res.type("text/plain").set("ETag", '"foo"').send(Buffer.from("hey"));
});
request(app).get("/").expect("ETag", '"foo"').expect(200, "hey", done);
});
});
describe(".send(Object)", function () {
it("should send as application/json", function (done) {
var app = express();
app.use(function (req, res) {
res.send({ name: "tobi" });
});
request(app)
.get("/")
.expect("Content-Type", "application/json; charset=utf-8")
.expect(200, '{"name":"tobi"}', done);
});
});
describe("when the request method is HEAD", function () {
it("should ignore the body", function (done) {
var app = express();
app.use(function (req, res) {
res.send("yay");
});
request(app).head("/").expect(200).expect(utils.shouldNotHaveBody()).end(done);
});
});
describe("when .statusCode is 204", function () {
it.todo("should strip Content-* fields, Transfer-Encoding field, and body", function (done) {
var app = express();
app.use(function (req, res) {
res.status(204).set("Transfer-Encoding", "chunked").send("foo");
});
request(app)
.get("/")
.expect(utils.shouldNotHaveHeader("Content-Type"))
.expect(utils.shouldNotHaveHeader("Content-Length"))
.expect(utils.shouldNotHaveHeader("Transfer-Encoding"))
.expect(204, "", done);
});
});
describe("when .statusCode is 205", function () {
it("should strip Transfer-Encoding field and body, set Content-Length", function (done) {
var app = express();
app.use(function (req, res) {
res.status(205).set("Transfer-Encoding", "chunked").send("foo");
});
request(app)
.get("/")
.expect(utils.shouldNotHaveHeader("Transfer-Encoding"))
.expect("Content-Length", "0")
.expect(205, "", done);
});
});
describe("when .statusCode is 304", function () {
it.todo("should strip Content-* fields, Transfer-Encoding field, and body", function (done) {
var app = express();
app.use(function (req, res) {
res.status(304).set("Transfer-Encoding", "chunked").send("foo");
});
request(app)
.get("/")
.expect(utils.shouldNotHaveHeader("Content-Type"))
.expect(utils.shouldNotHaveHeader("Content-Length"))
.expect(utils.shouldNotHaveHeader("Transfer-Encoding"))
.expect(304, "", done);
});
});
it("should always check regardless of length", function (done) {
var app = express();
var etag = '"asdf"';
app.use(function (req, res, next) {
res.set("ETag", etag);
res.send("hey");
});
request(app).get("/").set("If-None-Match", etag).expect(304, done);
});
it("should respond with 304 Not Modified when fresh", function (done) {
var app = express();
var etag = '"asdf"';
app.use(function (req, res) {
var str = Array(1000).join("-");
res.set("ETag", etag);
res.send(str);
});
request(app).get("/").set("If-None-Match", etag).expect(304, done);
});
it("should not perform freshness check unless 2xx or 304", function (done) {
var app = express();
var etag = '"asdf"';
app.use(function (req, res, next) {
res.status(500);
res.set("ETag", etag);
res.send("hey");
});
request(app).get("/").set("If-None-Match", etag).expect("hey").expect(500, done);
});
it("should not support jsonp callbacks", function (done) {
var app = express();
app.use(function (req, res) {
res.send({ foo: "bar" });
});
request(app).get("/?callback=foo").expect('{"foo":"bar"}', done);
});
it("should be chainable", function (done) {
var app = express();
app.use(function (req, res) {
assert.equal(res.send("hey"), res);
});
request(app).get("/").expect(200, "hey", done);
});
describe('"etag" setting', function () {
describe("when enabled", function () {
it("should send ETag", function (done) {
var app = express();
app.use(function (req, res) {
res.send("kajdslfkasdf");
});
app.enable("etag");
request(app).get("/").expect("ETag", 'W/"c-IgR/L5SF7CJQff4wxKGF/vfPuZ0"').expect(200, done);
});
methods.forEach(function (method) {
if (method === "connect") return;
it("should send ETag in response to " + method.toUpperCase() + " request", function (done) {
if (method === "query" && shouldSkipQuery(process.versions.node)) {
this.skip();
}
var app = express();
app[method]("/", function (req, res) {
res.send("kajdslfkasdf");
});
request(app)[method]("/").expect("ETag", 'W/"c-IgR/L5SF7CJQff4wxKGF/vfPuZ0"').expect(200, done);
});
});
it("should send ETag for empty string response", function (done) {
var app = express();
app.use(function (req, res) {
res.send("");
});
app.enable("etag");
request(app).get("/").expect("ETag", 'W/"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"').expect(200, done);
});
it("should send ETag for long response", function (done) {
var app = express();
app.use(function (req, res) {
var str = Array(1000).join("-");
res.send(str);
});
app.enable("etag");
request(app).get("/").expect("ETag", 'W/"3e7-qPnkJ3CVdVhFJQvUBfF10TmVA7g"').expect(200, done);
});
it("should not override ETag when manually set", function (done) {
var app = express();
app.use(function (req, res) {
res.set("etag", '"asdf"');
res.send("hello!");
});
app.enable("etag");
request(app).get("/").expect("ETag", '"asdf"').expect(200, done);
});
it("should not send ETag for res.send()", function (done) {
var app = express();
app.use(function (req, res) {
res.send();
});
app.enable("etag");
request(app).get("/").expect(utils.shouldNotHaveHeader("ETag")).expect(200, done);
});
});
describe("when disabled", function () {
it("should send no ETag", function (done) {
var app = express();
app.use(function (req, res) {
var str = Array(1000).join("-");
res.send(str);
});
app.disable("etag");
request(app).get("/").expect(utils.shouldNotHaveHeader("ETag")).expect(200, done);
});
it("should send ETag when manually set", function (done) {
var app = express();
app.disable("etag");
app.use(function (req, res) {
res.set("etag", '"asdf"');
res.send("hello!");
});
request(app).get("/").expect("ETag", '"asdf"').expect(200, done);
});
});
describe('when "strong"', function () {
it("should send strong ETag", function (done) {
var app = express();
app.set("etag", "strong");
app.use(function (req, res) {
res.send("hello, world!");
});
request(app).get("/").expect("ETag", '"d-HwnTDHB9U/PRbFMN1z1wps51lqk"').expect(200, done);
});
});
describe('when "weak"', function () {
it("should send weak ETag", function (done) {
var app = express();
app.set("etag", "weak");
app.use(function (req, res) {
res.send("hello, world!");
});
request(app).get("/").expect("ETag", 'W/"d-HwnTDHB9U/PRbFMN1z1wps51lqk"').expect(200, done);
});
});
describe("when a function", function () {
it("should send custom ETag", function (done) {
var app = express();
app.set("etag", function (body, encoding) {
var chunk = !Buffer.isBuffer(body) ? Buffer.from(body, encoding) : body;
assert.strictEqual(chunk.toString(), "hello, world!");
return '"custom"';
});
app.use(function (req, res) {
res.send("hello, world!");
});
request(app).get("/").expect("ETag", '"custom"').expect(200, done);
});
it("should not send falsy ETag", function (done) {
var app = express();
app.set("etag", function (body, encoding) {
return undefined;
});
app.use(function (req, res) {
res.send("hello, world!");
});
request(app).get("/").expect(utils.shouldNotHaveHeader("ETag")).expect(200, done);
});
});
});
});

View File

@@ -1,774 +0,0 @@
"use strict";
var after = require("./support/after");
var assert = require("node:assert");
var AsyncLocalStorage = require("node:async_hooks").AsyncLocalStorage;
var express = require("express"),
request = require("supertest");
// var onFinished = require("on-finished");
var path = require("node:path");
var fixtures = path.join(__dirname, "fixtures");
var utils = require("./support/utils");
describe("res", function () {
describe(".sendFile(path)", function () {
it("should error missing path", function (done) {
var app = createApp();
request(app)
.get("/")
.expect(500, /path.*required/, done);
});
it("should error for non-string path", function (done) {
var app = createApp(42);
request(app)
.get("/")
.expect(500, /TypeError: path must be a string to res.sendFile/, done);
});
it("should error for non-absolute path", function (done) {
var app = createApp("name.txt");
request(app)
.get("/")
.expect(500, /TypeError: path must be absolute/, done);
});
it.todo("should transfer a file", function (done) {
var app = createApp(path.resolve(fixtures, "name.txt"));
request(app).get("/").expect(200, "tobi", done);
});
it("should transfer a file with special characters in string", function (done) {
var app = createApp(path.resolve(fixtures, "% of dogs.txt"));
request(app).get("/").expect(200, "20%", done);
});
it.todo("should include ETag", function (done) {
var app = createApp(path.resolve(fixtures, "name.txt"));
request(app)
.get("/")
.expect("ETag", /^(?:W\/)?"[^"]+"$/)
.expect(200, "tobi", done);
});
it.todo("should 304 when ETag matches", function (done) {
var app = createApp(path.resolve(fixtures, "name.txt"));
request(app)
.get("/")
.expect("ETag", /^(?:W\/)?"[^"]+"$/)
.expect(200, "tobi", function (err, res) {
if (err) return done(err);
var etag = res.headers.etag;
request(app).get("/").set("If-None-Match", etag).expect(304, done);
});
});
it.todo("should disable the ETag function if requested", function (done) {
var app = createApp(path.resolve(fixtures, "name.txt")).disable("etag");
request(app).get("/").expect(handleHeaders).expect(200, done);
function handleHeaders(res) {
assert(res.headers.etag === undefined);
}
});
it("should 404 for directory", function (done) {
var app = createApp(path.resolve(fixtures, "blog"));
request(app).get("/").expect(404, done);
});
it("should 404 when not found", function (done) {
var app = createApp(path.resolve(fixtures, "does-no-exist"));
app.use(function (req, res) {
res.statusCode = 200;
res.send("no!");
});
request(app).get("/").expect(404, done);
});
it("should send cache-control by default", function (done) {
var app = createApp(path.resolve(__dirname, "fixtures/name.txt"));
request(app).get("/").expect("Cache-Control", "public, max-age=0").expect(200, done);
});
it("should not serve dotfiles by default", function (done) {
var app = createApp(path.resolve(__dirname, "fixtures/.name"));
request(app).get("/").expect(404, done);
});
it("should not override manual content-types", function (done) {
var app = express();
app.use(function (req, res) {
res.contentType("application/x-bogus");
res.sendFile(path.resolve(fixtures, "name.txt"));
});
request(app).get("/").expect("Content-Type", "application/x-bogus").end(done);
});
it.todo("should not error if the client aborts", function (done) {
var app = express();
var cb = after(2, done);
var error = null;
app.use(function (req, res) {
setImmediate(function () {
res.sendFile(path.resolve(fixtures, "name.txt"));
setTimeout(function () {
cb(error);
}, 10);
});
test.req.abort();
});
app.use(function (err, req, res, next) {
error = err;
next(err);
});
var server = app.listen();
var test = request(server).get("/");
test.end(function (err) {
assert.ok(err);
server.close(cb);
});
});
});
describe(".sendFile(path, fn)", function () {
it("should invoke the callback when complete", function (done) {
var cb = after(2, done);
var app = createApp(path.resolve(fixtures, "name.txt"), cb);
request(app).get("/").expect(200, cb);
});
it.todo("should invoke the callback when client aborts", function (done) {
var cb = after(2, done);
var app = express();
app.use(function (req, res) {
setImmediate(function () {
res.sendFile(path.resolve(fixtures, "name.txt"), function (err) {
assert.ok(err);
assert.strictEqual(err.code, "ECONNABORTED");
cb();
});
});
test.req.abort();
});
var server = app.listen();
var test = request(server).get("/");
test.end(function (err) {
assert.ok(err);
server.close(cb);
});
});
// TODO: refactor to not use onFinished
// it("should invoke the callback when client already aborted", function (done) {
// var cb = after(2, done);
// var app = express();
// app.use(function (req, res) {
// onFinished(res, function () {
// res.sendFile(path.resolve(fixtures, "name.txt"), function (err) {
// assert.ok(err);
// assert.strictEqual(err.code, "ECONNABORTED");
// cb();
// });
// });
// test.req.abort();
// });
// var server = app.listen();
// var test = request(server).get("/");
// test.end(function (err) {
// assert.ok(err);
// server.close(cb);
// });
// });
it("should invoke the callback without error when HEAD", function (done) {
var app = express();
var cb = after(2, done);
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, "name.txt"), cb);
});
request(app).head("/").expect(200, cb);
});
it.todo("should invoke the callback without error when 304", function (done) {
var app = express();
var cb = after(3, done);
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, "name.txt"), cb);
});
request(app)
.get("/")
.expect("ETag", /^(?:W\/)?"[^"]+"$/)
.expect(200, "tobi", function (err, res) {
if (err) return cb(err);
var etag = res.headers.etag;
request(app).get("/").set("If-None-Match", etag).expect(304, cb);
});
});
it("should invoke the callback on 404", function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, "does-not-exist"), function (err) {
res.send(err ? "got " + err.status + " error" : "no error");
});
});
request(app).get("/").expect(200, "got 404 error", done);
});
describe.todo("async local storage", function () {
it("should presist store", function (done) {
var app = express();
var cb = after(2, done);
var store = { foo: "bar" };
app.use(function (req, res, next) {
req.asyncLocalStorage = new AsyncLocalStorage();
req.asyncLocalStorage.run(store, next);
});
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, "name.txt"), function (err) {
if (err) return cb(err);
var local = req.asyncLocalStorage.getStore();
assert.strictEqual(local.foo, "bar");
cb();
});
});
request(app).get("/").expect("Content-Type", "text/plain; charset=utf-8").expect(200, "tobi", cb);
});
it("should presist store on error", function (done) {
var app = express();
var store = { foo: "bar" };
app.use(function (req, res, next) {
req.asyncLocalStorage = new AsyncLocalStorage();
req.asyncLocalStorage.run(store, next);
});
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, "does-not-exist"), function (err) {
var local = req.asyncLocalStorage.getStore();
if (local) {
res.setHeader("x-store-foo", String(local.foo));
}
res.send(err ? "got " + err.status + " error" : "no error");
});
});
request(app).get("/").expect(200).expect("x-store-foo", "bar").expect("got 404 error").end(done);
});
});
});
describe(".sendFile(path, options)", function () {
it("should pass options to send module", function (done) {
request(createApp(path.resolve(fixtures, "name.txt"), { start: 0, end: 1 }))
.get("/")
.expect(200, "to", done);
});
describe('with "acceptRanges" option', function () {
describe("when true", function () {
it("should advertise byte range accepted", function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, "nums.txt"), {
acceptRanges: true,
});
});
request(app).get("/").expect(200).expect("Accept-Ranges", "bytes").expect("123456789").end(done);
});
it("should respond to range request", function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, "nums.txt"), {
acceptRanges: true,
});
});
request(app).get("/").set("Range", "bytes=0-4").expect(206, "12345", done);
});
});
describe("when false", function () {
it("should not advertise accept-ranges", function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, "nums.txt"), {
acceptRanges: false,
});
});
request(app).get("/").expect(200).expect(utils.shouldNotHaveHeader("Accept-Ranges")).end(done);
});
it("should not honor range requests", function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, "nums.txt"), {
acceptRanges: false,
});
});
request(app).get("/").set("Range", "bytes=0-4").expect(200, "123456789", done);
});
});
});
describe('with "cacheControl" option', function () {
describe("when true", function () {
it("should send cache-control header", function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, "user.html"), {
cacheControl: true,
});
});
request(app).get("/").expect(200).expect("Cache-Control", "public, max-age=0").end(done);
});
});
describe("when false", function () {
it("should not send cache-control header", function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, "user.html"), {
cacheControl: false,
});
});
request(app).get("/").expect(200).expect(utils.shouldNotHaveHeader("Cache-Control")).end(done);
});
});
});
describe('with "dotfiles" option', function () {
describe('when "allow"', function () {
it("should allow dotfiles", function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, ".name"), {
dotfiles: "allow",
});
});
request(app)
.get("/")
.expect(200)
.expect(utils.shouldHaveBody(Buffer.from("tobi")))
.end(done);
});
});
describe('when "deny"', function () {
it("should deny dotfiles", function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, ".name"), {
dotfiles: "deny",
});
});
request(app)
.get("/")
.expect(403)
.expect(/Forbidden/)
.end(done);
});
});
describe('when "ignore"', function () {
it("should ignore dotfiles", function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, ".name"), {
dotfiles: "ignore",
});
});
request(app)
.get("/")
.expect(404)
.expect(/Not Found/)
.end(done);
});
});
});
describe('with "headers" option', function () {
it("should set headers on response", function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, "user.html"), {
headers: {
"X-Foo": "Bar",
"X-Bar": "Foo",
},
});
});
request(app).get("/").expect(200).expect("X-Foo", "Bar").expect("X-Bar", "Foo").end(done);
});
it("should use last header when duplicated", function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, "user.html"), {
headers: {
"X-Foo": "Bar",
"x-foo": "bar",
},
});
});
request(app).get("/").expect(200).expect("X-Foo", "bar").end(done);
});
it("should override Content-Type", function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, "user.html"), {
headers: {
"Content-Type": "text/x-custom",
},
});
});
request(app).get("/").expect(200).expect("Content-Type", "text/x-custom").end(done);
});
it("should not set headers on 404", function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, "does-not-exist"), {
headers: {
"X-Foo": "Bar",
},
});
});
request(app).get("/").expect(404).expect(utils.shouldNotHaveHeader("X-Foo")).end(done);
});
});
describe('with "immutable" option', function () {
describe("when true", function () {
it("should send cache-control header with immutable", function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, "user.html"), {
immutable: true,
});
});
request(app).get("/").expect(200).expect("Cache-Control", "public, max-age=0, immutable").end(done);
});
});
describe("when false", function () {
it("should not send cache-control header with immutable", function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, "user.html"), {
immutable: false,
});
});
request(app).get("/").expect(200).expect("Cache-Control", "public, max-age=0").end(done);
});
});
});
describe('with "lastModified" option', function () {
describe("when true", function () {
it("should send last-modified header", function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, "user.html"), {
lastModified: true,
});
});
request(app).get("/").expect(200).expect(utils.shouldHaveHeader("Last-Modified")).end(done);
});
it("should conditionally respond with if-modified-since", function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, "user.html"), {
lastModified: true,
});
});
request(app)
.get("/")
.set("If-Modified-Since", new Date(Date.now() + 99999).toUTCString())
.expect(304, done);
});
});
describe("when false", function () {
it("should not have last-modified header", function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, "user.html"), {
lastModified: false,
});
});
request(app).get("/").expect(200).expect(utils.shouldNotHaveHeader("Last-Modified")).end(done);
});
it("should not honor if-modified-since", function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, "user.html"), {
lastModified: false,
});
});
request(app)
.get("/")
.set("If-Modified-Since", new Date(Date.now() + 99999).toUTCString())
.expect(200)
.expect(utils.shouldNotHaveHeader("Last-Modified"))
.end(done);
});
});
});
describe('with "maxAge" option', function () {
it("should set cache-control max-age to milliseconds", function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, "user.html"), {
maxAge: 20000,
});
});
request(app).get("/").expect(200).expect("Cache-Control", "public, max-age=20").end(done);
});
it("should cap cache-control max-age to 1 year", function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, "user.html"), {
maxAge: 99999999999,
});
});
request(app).get("/").expect(200).expect("Cache-Control", "public, max-age=31536000").end(done);
});
it.todo("should min cache-control max-age to 0", function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, "user.html"), {
maxAge: -20000,
});
});
request(app).get("/").expect(200).expect("Cache-Control", "public, max-age=0").end(done);
});
it.todo("should floor cache-control max-age", function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, "user.html"), {
maxAge: 21911.23,
});
});
request(app).get("/").expect(200).expect("Cache-Control", "public, max-age=21").end(done);
});
describe("when cacheControl: false", function () {
it("should not send cache-control", function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, "user.html"), {
cacheControl: false,
maxAge: 20000,
});
});
request(app).get("/").expect(200).expect(utils.shouldNotHaveHeader("Cache-Control")).end(done);
});
});
describe("when string", function () {
it("should accept plain number as milliseconds", function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, "user.html"), {
maxAge: "20000",
});
});
request(app).get("/").expect(200).expect("Cache-Control", "public, max-age=20").end(done);
});
it('should accept suffix "s" for seconds', function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, "user.html"), {
maxAge: "20s",
});
});
request(app).get("/").expect(200).expect("Cache-Control", "public, max-age=20").end(done);
});
it('should accept suffix "m" for minutes', function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, "user.html"), {
maxAge: "20m",
});
});
request(app).get("/").expect(200).expect("Cache-Control", "public, max-age=1200").end(done);
});
it('should accept suffix "d" for days', function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile(path.resolve(fixtures, "user.html"), {
maxAge: "20d",
});
});
request(app).get("/").expect(200).expect("Cache-Control", "public, max-age=1728000").end(done);
});
});
});
describe.todo('with "root" option', function () {
it("should allow relative path", function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile("name.txt", {
root: fixtures,
});
});
request(app).get("/").expect(200, "tobi", done);
});
it("should allow up within root", function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile("fake/../name.txt", {
root: fixtures,
});
});
request(app).get("/").expect(200, "tobi", done);
});
it.todo("should reject up outside root", function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile(".." + path.sep + path.relative(path.dirname(fixtures), path.join(fixtures, "name.txt")), {
root: fixtures,
});
});
request(app).get("/").expect(403, done);
});
it("should reject reading outside root", function (done) {
var app = express();
app.use(function (req, res) {
res.sendFile("../name.txt", {
root: fixtures,
});
});
request(app).get("/").expect(403, done);
});
});
});
});
function createApp(path?, options?, fn?) {
var app = express();
app.use(function sendFileMiddleware (req, res) {
res.sendFile(path, options, fn);
});
return app;
}

View File

@@ -1,36 +0,0 @@
/**
* https://www.npmjs.com/package/after
*
* I refuse to install a 30 line function via npm
*/
module.exports = after;
/**
* Invoke a callback after `n` calls
*/
function after(count, callback, err_cb) {
var bail = false;
err_cb = err_cb || noop;
proxy.count = count;
return count === 0 ? callback() : proxy;
function proxy(err, result) {
if (proxy.count <= 0) {
throw new Error("after called too many times");
}
--proxy.count;
// after first error, rest are passed to err_cb
if (err) {
bail = true;
callback(err);
// future error callbacks will go to error handler
callback = err_cb;
} else if (proxy.count === 0 && !bail) {
callback(null, result);
}
}
}
function noop() {}

View File

@@ -1,83 +0,0 @@
/**
* Module dependencies.
* @private
*/
var assert = require("node:assert");
var { METHODS } = require("node:http");
/**
* Module exports.
* @public
*/
exports.shouldHaveBody = shouldHaveBody;
exports.shouldHaveHeader = shouldHaveHeader;
exports.shouldNotHaveBody = shouldNotHaveBody;
exports.shouldNotHaveHeader = shouldNotHaveHeader;
exports.shouldSkipQuery = shouldSkipQuery;
exports.methods = METHODS.map(method => method.toLowerCase()); // from lib/utils.js
/**
* Assert that a supertest response has a specific body.
*
* @param {Buffer} buf
* @returns {function}
*/
function shouldHaveBody(buf) {
return function (res) {
var body = !Buffer.isBuffer(res.body) ? Buffer.from(res.text) : res.body;
assert.ok(body, "response has body");
assert.strictEqual(body.toString("hex"), buf.toString("hex"));
};
}
/**
* Assert that a supertest response does have a header.
*
* @param {string} header Header name to check
* @returns {function}
*/
function shouldHaveHeader(header) {
return function (res) {
assert.ok(header.toLowerCase() in res.headers, "should have header " + header);
};
}
/**
* Assert that a supertest response does not have a body.
*
* @returns {function}
*/
function shouldNotHaveBody() {
return function (res) {
assert.ok(res.text === "" || res.text === undefined);
};
}
/**
* Assert that a supertest response does not have a header.
*
* @param {string} header Header name to check
* @returns {function}
*/
function shouldNotHaveHeader(header) {
return function (res) {
assert.ok(!(header.toLowerCase() in res.headers), "should not have header " + header);
};
}
function getMajorVersion(versionString) {
return versionString.split(".")[0];
}
function shouldSkipQuery(versionString) {
// Skipping HTTP QUERY tests on Node 21, it is reported in http.METHODS on 21.7.2 but not supported
// update this implementation to run on supported versions of 21 once they exist
// upstream tracking https://github.com/nodejs/node/issues/51562
// express tracking issue: https://github.com/expressjs/express/issues/5615
return Number(getMajorVersion(versionString)) === 21;
}