Skip to content

Commit 9403062

Browse files
authored
feat!: update getFilenameFromUrl to throw errors and return undefined when not found (#34)
1 parent b226d37 commit 9403062

10 files changed

Lines changed: 421 additions & 144 deletions

File tree

README.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -457,9 +457,21 @@ const app = new express();
457457
app.use(instance);
458458

459459
instance.waitUntilValid(() => {
460-
const filename = instance.getFilenameFromUrl("/bundle.js");
460+
let resolved;
461461

462-
console.log(`Filename is ${filename}`);
462+
try {
463+
resolved = instance.getFilenameFromUrl("/bundle.js");
464+
} catch (error) {
465+
console.error(error);
466+
return;
467+
}
468+
469+
if (!resolved) {
470+
console.log("Not found");
471+
return;
472+
}
473+
474+
console.log(`Filename is ${resolved.filename}`);
463475
});
464476
```
465477

src/index.js

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -133,19 +133,18 @@ const noop = () => {};
133133
* @template {IncomingMessage} [RequestInternal=IncomingMessage]
134134
* @template {ServerResponse} [ResponseInternal=ServerResponse]
135135
* @callback Middleware
136-
* @param {RequestInternal} req
137-
* @param {ResponseInternal} res
138-
* @param {NextFunction} next
136+
* @param {RequestInternal} req request
137+
* @param {ResponseInternal} res response
138+
* @param {NextFunction} next next function
139139
* @returns {Promise<void>}
140140
*/
141141

142142
/** @typedef {import("./utils/getFilenameFromUrl.js").Extra} Extra */
143143

144144
/**
145145
* @callback GetFilenameFromUrl
146-
* @param {string} url
147-
* @param {Extra=} extra
148-
* @returns {string | undefined}
146+
* @param {string} url request URL
147+
* @returns {{ filename: string, extra: Extra } | undefined} a filename with additional information, or `undefined` if nothing is found
149148
*/
150149

151150
/**
@@ -273,8 +272,7 @@ function rdm(compiler, options = {}) {
273272
(middleware(filledContext));
274273

275274
// API
276-
instance.getFilenameFromUrl = (url, extra) =>
277-
getFilenameFromUrl(filledContext, url, extra);
275+
instance.getFilenameFromUrl = (url) => getFilenameFromUrl(filledContext, url);
278276

279277
instance.waitUntilValid = (callback = noop) => {
280278
ready(filledContext, callback);

src/middleware.js

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,12 @@ import ready from "./utils/ready.js";
3434
/** @typedef {import("./index.js").IncomingMessage} IncomingMessage */
3535
/** @typedef {import("./index.js").ServerResponse} ServerResponse */
3636
/** @typedef {import("./index.js").NormalizedHeaders} NormalizedHeaders */
37+
/** @typedef {import("./utils/getFilenameFromUrl.js").FilenameError} FilenameError */
38+
/** @typedef {import("./utils/getFilenameFromUrl.js").Extra} Extra */
3739
/** @typedef {import("fs").ReadStream} ReadStream */
3840

41+
/** @typedef {{ filename: string, extra: Extra }} FilenameWithExtra */
42+
3943
const BYTES_RANGE_REGEXP = /^ *bytes/i;
4044
const UTF8_CHARSET_MIME_TYPES = new Set([
4145
"application/javascript",
@@ -279,9 +283,11 @@ function wrapper(context) {
279283

280284
/**
281285
* @param {NodeJS.ErrnoException} error error
286+
* @param {string=} message override message
287+
* @param {number=} code override code
282288
* @returns {Promise<void>}
283289
*/
284-
async function errorHandler(error) {
290+
async function errorHandler(error, message, code) {
285291
switch (error.code) {
286292
case "ENAMETOOLONG":
287293
case "ENOENT":
@@ -291,7 +297,7 @@ function wrapper(context) {
291297
});
292298
break;
293299
default:
294-
await sendError(error.message, 500, {
300+
await sendError(message || error.message, code || 500, {
295301
modifyResponseData: context.options.modifyResponseData,
296302
});
297303
break;
@@ -532,30 +538,38 @@ function wrapper(context) {
532538
*/
533539
async function processRequest() {
534540
// Pipe and SendFile
535-
/** @type {import("./utils/getFilenameFromUrl.js").Extra} */
536-
const extra = {};
537-
const filename = getFilenameFromUrl(
538-
context,
539-
/** @type {string} */ (getRequestURL(req)),
540-
extra,
541-
);
542-
543-
if (extra.errorCode) {
544-
if (extra.errorCode === 403) {
545-
context.logger.error(`Malicious path "${filename}".`);
541+
/** @type {FilenameWithExtra | undefined} */
542+
let resolved;
543+
const requestUrl = /** @type {string} */ (getRequestURL(req));
544+
545+
try {
546+
resolved = getFilenameFromUrl(context, requestUrl);
547+
} catch (error) {
548+
const errorCode =
549+
typeof error === "object" &&
550+
error !== null &&
551+
typeof (/** @type {FilenameError} */ (error).statusCode) !==
552+
"undefined"
553+
? /** @type {FilenameError} */ (error).statusCode
554+
: undefined;
555+
556+
if (errorCode === 403) {
557+
context.logger.error(`Malicious path "${requestUrl}".`);
546558
}
547559

548-
await sendError(
549-
extra.errorCode === 400 ? "Bad Request" : "Forbidden",
550-
extra.errorCode,
551-
{
552-
modifyResponseData: context.options.modifyResponseData,
553-
},
560+
await errorHandler(
561+
/** @type {NodeJS.ErrnoException} */ (error),
562+
errorCode === 400
563+
? "Bad Request"
564+
: errorCode === 403
565+
? "Forbidden"
566+
: undefined,
567+
errorCode,
554568
);
555569
return;
556570
}
557571

558-
if (!filename) {
572+
if (!resolved) {
559573
await goNext();
560574
return;
561575
}
@@ -565,7 +579,8 @@ function wrapper(context) {
565579
return;
566580
}
567581

568-
const { size } = /** @type {import("fs").Stats} */ (extra.stats);
582+
const { extra, filename } = resolved;
583+
const { size } = extra.stats;
569584

570585
let len = size;
571586
let offset = 0;
@@ -686,7 +701,7 @@ function wrapper(context) {
686701
try {
687702
const result = createReadStreamOrReadFileSync(
688703
filename,
689-
context.outputFileSystem,
704+
extra.outputFileSystem,
690705
start,
691706
end,
692707
);
@@ -831,7 +846,7 @@ function wrapper(context) {
831846
try {
832847
({ bufferOrStream, byteLength } = createReadStreamOrReadFileSync(
833848
filename,
834-
context.outputFileSystem,
849+
extra.outputFileSystem,
835850
start,
836851
end,
837852
));

0 commit comments

Comments
 (0)