@ceicc/range
Advanced tools
Comparing version 3.0.1 to 3.0.2
@@ -19,2 +19,2 @@ import type { IncomingMessage, ServerResponse } from "http"; | ||
}; | ||
declare function range(options?: options): (req: IncomingMessage, res: ServerResponse, next: NextFunction) => Promise<void>; | ||
declare function range({ baseDir, hushErrors, conditional, range, etag, lastModified, maxAge, notFound, implicitIndex, trailingSlash, compression, dateHeader, }?: options): (req: IncomingMessage, res: ServerResponse, next: NextFunction) => Promise<void>; |
@@ -7,3 +7,2 @@ import { createReadStream, promises } from "node:fs"; | ||
import { contentType } from "mime-types"; | ||
import optionsChecker from "@ceicc/options-checker"; | ||
import * as utils from "./utils.js"; | ||
@@ -15,17 +14,3 @@ // Im not going to use `stream/promises` library because it was added in | ||
export default range; | ||
function range(options = {}) { | ||
optionsChecker(options, { | ||
baseDir: { default: '.', type: "string" }, | ||
hushErrors: { default: false, type: "boolean" }, | ||
conditional: { default: true, type: "boolean" }, | ||
range: { default: true, type: "boolean" }, | ||
etag: { default: true, type: "boolean" }, | ||
lastModified: { default: true, type: "boolean" }, | ||
maxAge: { default: 10800, type: "number|boolean" }, | ||
notFound: { default: true, type: "boolean|string" }, | ||
implicitIndex: { default: true, type: "boolean|array" }, | ||
trailingSlash: { default: true, type: "boolean" }, | ||
compression: { default: false, type: "boolean|array" }, | ||
dateHeader: { default: true, type: "boolean" }, | ||
}); | ||
function range({ baseDir = '.', hushErrors = false, conditional = true, range = true, etag = true, lastModified = true, maxAge = 10800, notFound = true, implicitIndex = true, trailingSlash = true, compression = false, dateHeader = true, } = {}) { | ||
return async function rangeMiddleware(req, res, next) { | ||
@@ -35,21 +20,21 @@ const { pathname } = new URL(`https://example.com${req.url}`); | ||
// Using `var` to get function scope | ||
var stat = await promises.stat(options.baseDir + pathname); | ||
var stat = await promises.stat(baseDir + pathname); | ||
} | ||
catch (error) { | ||
if (error?.code === "ENOENT") { | ||
if (options.notFound === true) | ||
if (notFound === true) | ||
return utils.forgetAboutIt(res, 404); | ||
if (typeof options.notFound === "string") { | ||
req.url = `/${options.notFound}`; | ||
options.notFound = false; | ||
if (typeof notFound === "string") { | ||
req.url = `/${notFound}`; | ||
notFound = false; | ||
return rangeMiddleware(req, res, next); | ||
} | ||
return options.hushErrors ? utils.forgetAboutIt(res, 404) : next(error); | ||
return hushErrors ? utils.forgetAboutIt(res, 404) : next(error); | ||
} | ||
return options.hushErrors ? utils.forgetAboutIt(res, 500) : next(error); | ||
return hushErrors ? utils.forgetAboutIt(res, 500) : next(error); | ||
} | ||
if (stat.isDirectory()) { | ||
if (!options.implicitIndex) | ||
if (!implicitIndex) | ||
return utils.forgetAboutIt(res, 404); | ||
if (options.trailingSlash && !utils.hasTrailingSlash(pathname)) { | ||
if (trailingSlash && !utils.hasTrailingSlash(pathname)) { | ||
res.statusCode = 301; | ||
@@ -61,7 +46,7 @@ res.setHeader("Location", pathname + "/"); | ||
const extensions = new Set(); | ||
if (Array.isArray(options.implicitIndex)) | ||
options.implicitIndex.forEach(v => extensions.add(v)); | ||
else if (options.implicitIndex === true) | ||
if (Array.isArray(implicitIndex)) | ||
implicitIndex.forEach(v => extensions.add(v)); | ||
else if (implicitIndex === true) | ||
extensions.add("html"); | ||
const directory = await promises.readdir(options.baseDir + pathname); | ||
const directory = await promises.readdir(baseDir + pathname); | ||
for (const extension of extensions) { | ||
@@ -75,28 +60,28 @@ if (!directory.includes(`index.${extension}`)) | ||
} | ||
const etag = options.etag && utils.getEtag(stat.mtime, stat.size); | ||
const etagVal = etag && utils.getEtag(stat.mtime, stat.size); | ||
const extension = extname(pathname); | ||
const fileContentType = contentType(extension); | ||
etag && res.setHeader("etag", etag); | ||
options.lastModified && res.setHeader("last-modified", stat.mtime.toUTCString()); | ||
options.range && res.setHeader("accept-ranges", "bytes"); // Hint to the browser range is supported | ||
typeof options.maxAge === "number" && res.setHeader("cache-control", `max-age=${options.maxAge}`); | ||
etagVal && res.setHeader("etag", etagVal); | ||
lastModified && res.setHeader("last-modified", stat.mtime.toUTCString()); | ||
range && res.setHeader("accept-ranges", "bytes"); // Hint to the browser range is supported | ||
typeof maxAge === "number" && res.setHeader("cache-control", `max-age=${maxAge}`); | ||
typeof fileContentType === "string" && res.setHeader("content-type", fileContentType); | ||
res.setHeader("content-length", stat.size); | ||
options.dateHeader && res.setHeader("date", new Date().toUTCString()); | ||
dateHeader && res.setHeader("date", new Date().toUTCString()); | ||
// check conditional requests | ||
if (options.conditional) { | ||
if (conditional) { | ||
const ifNoneMatch = req.headers["if-none-match"]; | ||
const ifModifiedSince = req.headers["if-modified-since"]; | ||
if (ifNoneMatch === etag || | ||
if (ifNoneMatch === etagVal || | ||
ifModifiedSince && (Date.parse(ifModifiedSince) - stat.mtime.getTime()) >= -2000) | ||
return utils.forgetAboutIt(res, 304); | ||
} | ||
if (options.range && req.headers["range"]) { | ||
if (req.headers["if-range"] && req.headers["if-range"] !== etag) { | ||
if (range && req.headers["range"]) { | ||
if (req.headers["if-range"] && req.headers["if-range"] !== etagVal) { | ||
res.statusCode = 200; | ||
try { | ||
if (options.compression && fileContentType && stat.size > 1024) { | ||
if (compression && fileContentType && stat.size > 1024) { | ||
const { encoding, stream } = utils.getPossibleEncoding({ | ||
headers: req.headers, | ||
availableEncodings: options.compression, | ||
availableEncodings: compression, | ||
contentType: fileContentType | ||
@@ -107,9 +92,9 @@ }); | ||
res.setHeader("content-encoding", encoding); | ||
return await streamIt({ path: options.baseDir + pathname, res, transformStream: stream }); | ||
return await streamIt({ path: baseDir + pathname, res, transformStream: stream }); | ||
} | ||
} | ||
return await streamIt({ path: options.baseDir + pathname, res }); | ||
return await streamIt({ path: baseDir + pathname, res }); | ||
} | ||
catch (error) { | ||
options.hushErrors ? utils.hush(res) : next(error); | ||
hushErrors ? utils.hush(res) : next(error); | ||
} | ||
@@ -121,3 +106,3 @@ return; | ||
const ifUnmodifiedSince = req.headers["if-unmodified-since"]; | ||
if (ifMatch && ifMatch !== etag || | ||
if (ifMatch && ifMatch !== etagVal || | ||
ifUnmodifiedSince && (Date.parse(ifUnmodifiedSince) - stat.mtime.getTime()) < -2000) | ||
@@ -127,6 +112,6 @@ return utils.forgetAboutIt(res, 412); | ||
try { | ||
await rangeRequest(options.baseDir + pathname, res, req.headers["range"], stat.size); | ||
await rangeRequest(baseDir + pathname, res, req.headers["range"], stat.size); | ||
} | ||
catch (error) { | ||
options.hushErrors ? utils.hush(res) : next(error); | ||
hushErrors ? utils.hush(res) : next(error); | ||
} | ||
@@ -137,6 +122,6 @@ return; | ||
try { | ||
if (options.compression && fileContentType && stat.size > 1024) { | ||
if (compression && fileContentType && stat.size > 1024) { | ||
const { encoding, stream } = utils.getPossibleEncoding({ | ||
headers: req.headers, | ||
availableEncodings: options.compression, | ||
availableEncodings: compression, | ||
contentType: fileContentType || "" | ||
@@ -147,9 +132,9 @@ }); | ||
res.setHeader("content-encoding", encoding); | ||
return await streamIt({ path: options.baseDir + pathname, res, transformStream: stream }); | ||
return await streamIt({ path: baseDir + pathname, res, transformStream: stream }); | ||
} | ||
} | ||
return await streamIt({ path: options.baseDir + pathname, res }); | ||
return await streamIt({ path: baseDir + pathname, res }); | ||
} | ||
catch (error) { | ||
options.hushErrors ? utils.hush(res) : next(error); | ||
hushErrors ? utils.hush(res) : next(error); | ||
} | ||
@@ -156,0 +141,0 @@ }; |
{ | ||
"name": "@ceicc/range", | ||
"version": "3.0.1", | ||
"version": "3.0.2", | ||
"description": "http range request handler", | ||
"exports": "./lib/index.js", | ||
"type": "module", | ||
"scripts": { | ||
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js", | ||
"dev": "nodemon test/server.js" | ||
}, | ||
"repository": { | ||
@@ -41,3 +37,2 @@ "type": "git", | ||
"dependencies": { | ||
"@ceicc/options-checker": "^1.0.2", | ||
"compressible": "^2.0.18", | ||
@@ -57,3 +52,7 @@ "mime-types": "^2.1.35", | ||
"supertest": "^6.2.3" | ||
}, | ||
"scripts": { | ||
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js", | ||
"dev": "nodemon test/server.js" | ||
} | ||
} | ||
} |
3
17003
253
- Removed@ceicc/options-checker@^1.0.2
- Removed@ceicc/options-checker@1.0.2(transitive)