Skip to content

Commit c64748e

Browse files
refactor: avoid unnecessary inner pseudo API (#1795)
1 parent 8203d4c commit c64748e

File tree

3 files changed

+44
-197
lines changed

3 files changed

+44
-197
lines changed

src/middleware.js

Lines changed: 18 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,7 @@ const path = require("path");
33
const mime = require("mime-types");
44

55
const getFilenameFromUrl = require("./utils/getFilenameFromUrl");
6-
const {
7-
getHeaderFromRequest,
8-
getHeaderFromResponse,
9-
setHeaderForResponse,
10-
setStatusCode,
11-
send,
12-
sendError,
13-
} = require("./utils/compatibleAPI");
6+
const { setStatusCode, send, sendError } = require("./utils/compatibleAPI");
147
const ready = require("./utils/ready");
158

169
/** @typedef {import("./index.js").NextFunction} NextFunction */
@@ -44,14 +37,6 @@ function wrapper(context) {
4437
// eslint-disable-next-line no-param-reassign
4538
res.locals = res.locals || {};
4639

47-
if (req.method && !acceptedMethods.includes(req.method)) {
48-
await goNext();
49-
50-
return;
51-
}
52-
53-
ready(context, processRequest, req);
54-
5540
async function goNext() {
5641
if (!context.options.serverSideRender) {
5742
return next();
@@ -72,6 +57,12 @@ function wrapper(context) {
7257
});
7358
}
7459

60+
if (req.method && !acceptedMethods.includes(req.method)) {
61+
await goNext();
62+
63+
return;
64+
}
65+
7566
async function processRequest() {
7667
/** @type {import("./utils/getFilenameFromUrl").Extra} */
7768
const extra = {};
@@ -121,34 +112,28 @@ function wrapper(context) {
121112
}
122113

123114
headers.forEach((header) => {
124-
setHeaderForResponse(res, header.key, header.value);
115+
res.setHeader(header.key, header.value);
125116
});
126117
}
127118

128-
if (!getHeaderFromResponse(res, "Content-Type")) {
119+
if (!res.getHeader("Content-Type")) {
129120
// content-type name(like application/javascript; charset=utf-8) or false
130121
const contentType = mime.contentType(path.extname(filename));
131122

132123
// Only set content-type header if media type is known
133124
// https://tools.ietf.org/html/rfc7231#section-3.1.1.5
134125
if (contentType) {
135-
setHeaderForResponse(res, "Content-Type", contentType);
126+
res.setHeader("Content-Type", contentType);
136127
} else if (context.options.mimeTypeDefault) {
137-
setHeaderForResponse(
138-
res,
139-
"Content-Type",
140-
context.options.mimeTypeDefault,
141-
);
128+
res.setHeader("Content-Type", context.options.mimeTypeDefault);
142129
}
143130
}
144131

145-
if (!getHeaderFromResponse(res, "Accept-Ranges")) {
146-
setHeaderForResponse(res, "Accept-Ranges", "bytes");
132+
if (!res.getHeader("Accept-Ranges")) {
133+
res.setHeader("Accept-Ranges", "bytes");
147134
}
148135

149-
const rangeHeader =
150-
/** @type {string} */
151-
(getHeaderFromRequest(req, "range"));
136+
const rangeHeader = /** @type {string} */ (req.headers.range);
152137

153138
let len = /** @type {import("fs").Stats} */ (extra.stats).size;
154139
let offset = 0;
@@ -162,8 +147,7 @@ function wrapper(context) {
162147
if (parsedRanges === -1) {
163148
context.logger.error("Unsatisfiable range for 'Range' header.");
164149

165-
setHeaderForResponse(
166-
res,
150+
res.setHeader(
167151
"Content-Range",
168152
getValueContentRangeHeader("bytes", len),
169153
);
@@ -189,8 +173,7 @@ function wrapper(context) {
189173
if (parsedRanges !== -2 && parsedRanges.length === 1) {
190174
// Content-Range
191175
setStatusCode(res, 206);
192-
setHeaderForResponse(
193-
res,
176+
res.setHeader(
194177
"Content-Range",
195178
getValueContentRangeHeader(
196179
"bytes",
@@ -212,6 +195,8 @@ function wrapper(context) {
212195
outputFileSystem: context.outputFileSystem,
213196
});
214197
}
198+
199+
ready(context, processRequest, req);
215200
};
216201
}
217202

src/utils/compatibleAPI.js

Lines changed: 22 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -13,118 +13,11 @@ const escapeHtml = require("./escapeHtml");
1313

1414
/**
1515
* @typedef {Object} ExpectedResponse
16-
* @property {(name: string) => string | string[] | undefined} get
17-
* @property {(name: string, value: number | string | string[]) => void} set
18-
* @property {(status: number) => void} status
19-
* @property {(data: any) => void} send
16+
* @property {(status: number) => void} [status]
17+
* @property {(data: any) => void} [send]
2018
* @property {(data: any) => void} [pipeInto]
2119
*/
2220

23-
/**
24-
* @template {ServerResponse} Response
25-
* @param {Response} res
26-
* @returns {string[]}
27-
*/
28-
function getHeaderNames(res) {
29-
// Pseudo API, TODO?
30-
if (typeof res.getHeaderNames !== "function") {
31-
// @ts-ignore
32-
// eslint-disable-next-line no-underscore-dangle
33-
return Object.keys(res._headers || {});
34-
}
35-
36-
// Node.js API
37-
return res.getHeaderNames();
38-
}
39-
40-
/**
41-
* @template {IncomingMessage} Request
42-
* @param {Request} req
43-
* @param {string} name
44-
* @returns {string | string[] | undefined}
45-
*/
46-
function getHeaderFromRequest(req, name) {
47-
// Express API
48-
if (
49-
typeof (/** @type {Request & ExpectedRequest} */ (req).get) === "function"
50-
) {
51-
return /** @type {Request & ExpectedRequest} */ (req).get(name);
52-
}
53-
54-
// Node.js API
55-
return req.headers[name];
56-
}
57-
58-
/**
59-
* @template {ServerResponse} Response
60-
* @param {Response} res
61-
* @param {string} name
62-
* @returns {number | string | string[] | undefined}
63-
*/
64-
function getHeaderFromResponse(res, name) {
65-
// Express API
66-
if (
67-
typeof (/** @type {Response & ExpectedResponse} */ (res).get) === "function"
68-
) {
69-
return /** @type {Response & ExpectedResponse} */ (res).get(name);
70-
}
71-
72-
// Node.js API
73-
return res.getHeader(name);
74-
}
75-
76-
/**
77-
* @template {ServerResponse} Response
78-
* @param {Response} res
79-
* @param {string} name
80-
* @param {number | string | string[]} value
81-
* @returns {void}
82-
*/
83-
function setHeaderForResponse(res, name, value) {
84-
// Express API
85-
if (
86-
typeof (/** @type {Response & ExpectedResponse} */ (res).set) === "function"
87-
) {
88-
/** @type {Response & ExpectedResponse} */
89-
(res).set(name, typeof value === "number" ? String(value) : value);
90-
91-
return;
92-
}
93-
94-
// Node.js API
95-
res.setHeader(name, value);
96-
}
97-
98-
/**
99-
* @template {ServerResponse} Response
100-
* @param {Response} res
101-
* @param {Record<string, number | string | string[] | undefined>} headers
102-
*/
103-
function setHeadersForResponse(res, headers) {
104-
const keys = Object.keys(headers);
105-
106-
for (let i = 0; i < keys.length; i++) {
107-
const key = keys[i];
108-
const value = headers[key];
109-
110-
if (typeof value !== "undefined") {
111-
setHeaderForResponse(res, key, value);
112-
}
113-
}
114-
}
115-
116-
/**
117-
* @template {ServerResponse} Response
118-
* @param {Response} res
119-
*/
120-
function clearHeadersForResponse(res) {
121-
const headers = getHeaderNames(res);
122-
123-
for (let i = 0; i < headers.length; i++) {
124-
res.removeHeader(headers[i]);
125-
}
126-
}
127-
12821
/**
12922
* @template {ServerResponse} Response
13023
* @param {Response} res
@@ -212,17 +105,30 @@ function sendError(req, res, status, options) {
212105
</html>`;
213106

214107
// Clear existing headers
215-
clearHeadersForResponse(res);
108+
const headers = res.getHeaderNames();
109+
110+
for (let i = 0; i < headers.length; i++) {
111+
res.removeHeader(headers[i]);
112+
}
216113

217114
if (options && options.headers) {
218-
setHeadersForResponse(res, options.headers);
115+
const keys = Object.keys(options.headers);
116+
117+
for (let i = 0; i < keys.length; i++) {
118+
const key = keys[i];
119+
const value = options.headers[key];
120+
121+
if (typeof value !== "undefined") {
122+
res.setHeader(key, value);
123+
}
124+
}
219125
}
220126

221127
// Send basic response
222128
setStatusCode(res, status);
223-
setHeaderForResponse(res, "Content-Type", "text/html; charset=utf-8");
224-
setHeaderForResponse(res, "Content-Security-Policy", "default-src 'none'");
225-
setHeaderForResponse(res, "X-Content-Type-Options", "nosniff");
129+
res.setHeader("Content-Type", "text/html; charset=utf-8");
130+
res.setHeader("Content-Security-Policy", "default-src 'none'");
131+
res.setHeader("X-Content-Type-Options", "nosniff");
226132

227133
let byteLength = Buffer.byteLength(document);
228134

@@ -232,7 +138,7 @@ function sendError(req, res, status, options) {
232138
(options.modifyResponseData(req, res, document, byteLength)));
233139
}
234140

235-
setHeaderForResponse(res, "Content-Length", byteLength);
141+
res.setHeader("Content-Length", byteLength);
236142

237143
res.end(document);
238144
}
@@ -328,7 +234,7 @@ async function send(req, res, filename, start, end, goNext, options) {
328234
}
329235
});
330236

331-
setHeaderForResponse(res, "Content-Length", byteLength);
237+
res.setHeader("Content-Length", byteLength);
332238

333239
// Pseudo API and Koa API
334240
if (
@@ -377,10 +283,6 @@ async function send(req, res, filename, start, end, goNext, options) {
377283
}
378284

379285
module.exports = {
380-
getHeaderNames,
381-
getHeaderFromRequest,
382-
getHeaderFromResponse,
383-
setHeaderForResponse,
384286
setStatusCode,
385287
send,
386288
sendError,

types/utils/compatibleAPI.d.ts

Lines changed: 4 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,8 @@ export type ExpectedRequest = {
66
get: (name: string) => string | undefined;
77
};
88
export type ExpectedResponse = {
9-
get: (name: string) => string | string[] | undefined;
10-
set: (name: string, value: number | string | string[]) => void;
11-
status: (status: number) => void;
12-
send: (data: any) => void;
9+
status?: ((status: number) => void) | undefined;
10+
send?: ((data: any) => void) | undefined;
1311
pipeInto?: ((data: any) => void) | undefined;
1412
};
1513
/**
@@ -43,48 +41,10 @@ export type SendOptions<
4341
*/
4442
/**
4543
* @typedef {Object} ExpectedResponse
46-
* @property {(name: string) => string | string[] | undefined} get
47-
* @property {(name: string, value: number | string | string[]) => void} set
48-
* @property {(status: number) => void} status
49-
* @property {(data: any) => void} send
44+
* @property {(status: number) => void} [status]
45+
* @property {(data: any) => void} [send]
5046
* @property {(data: any) => void} [pipeInto]
5147
*/
52-
/**
53-
* @template {ServerResponse} Response
54-
* @param {Response} res
55-
* @returns {string[]}
56-
*/
57-
export function getHeaderNames<
58-
Response extends import("../index.js").ServerResponse,
59-
>(res: Response): string[];
60-
/**
61-
* @template {IncomingMessage} Request
62-
* @param {Request} req
63-
* @param {string} name
64-
* @returns {string | string[] | undefined}
65-
*/
66-
export function getHeaderFromRequest<
67-
Request extends import("http").IncomingMessage,
68-
>(req: Request, name: string): string | string[] | undefined;
69-
/**
70-
* @template {ServerResponse} Response
71-
* @param {Response} res
72-
* @param {string} name
73-
* @returns {number | string | string[] | undefined}
74-
*/
75-
export function getHeaderFromResponse<
76-
Response extends import("../index.js").ServerResponse,
77-
>(res: Response, name: string): number | string | string[] | undefined;
78-
/**
79-
* @template {ServerResponse} Response
80-
* @param {Response} res
81-
* @param {string} name
82-
* @param {number | string | string[]} value
83-
* @returns {void}
84-
*/
85-
export function setHeaderForResponse<
86-
Response extends import("../index.js").ServerResponse,
87-
>(res: Response, name: string, value: number | string | string[]): void;
8848
/**
8949
* @template {ServerResponse} Response
9050
* @param {Response} res

0 commit comments

Comments
 (0)