-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
SendStringMiddleware.js
87 lines (81 loc) · 2.64 KB
/
SendStringMiddleware.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
/** @typedef {import('../types/index.js').IMiddleware} IMiddleware */
/** @typedef {import('../types/index.js').MiddlewareFunction} MiddlewareFunction */
/** @typedef {import('../types/index.js').ResponseFinalizer} ResponseFinalizer */
/**
* @typedef {Object} SendStringMiddlewareOptions
* @prop {string} [defaultCharset='utf-8']
* @prop {boolean} [setCharset=true]
* Automatically applies charset in `Content-Type`
*/
export default class SendStringMiddleware {
/** @param {SendStringMiddlewareOptions} [options] */
constructor(options = {}) {
this.options = {
defaultCharset: options.defaultCharset || 'utf-8',
setCharset: options.setCharset !== false,
};
// Single shared function instead of one per response
this.finalizeResponse = this.finalizeResponse.bind(this);
}
/**
* @param {string} charset
* @return {BufferEncoding}
*/
static charsetAsBufferEncoding(charset) {
switch (charset) {
case 'iso-8859-1':
case 'ascii':
case 'binary':
case 'latin1':
return 'latin1';
case 'utf-16le':
case 'ucs-2':
case 'ucs2':
case 'utf16le':
return 'utf16le';
case 'base64':
case 'hex':
return /** @type {BufferEncoding} */ (charset);
case 'utf-8':
case 'utf8':
default:
return 'utf-8';
}
}
/** @type {ResponseFinalizer} */
finalizeResponse(response) {
if (response.isStreaming || typeof response.body !== 'string') return true;
let charset;
let contentType = /** @type {string} */ (response.headers['content-type']);
if (contentType) {
contentType.split(';').some((directive) => {
const parameters = directive.split('=');
if (parameters[0].trim().toLowerCase() !== 'charset') {
return false;
}
charset = parameters[1]?.trim().toLowerCase();
const firstQuote = charset.indexOf('"');
const lastQuote = charset.lastIndexOf('"');
if (firstQuote !== -1 && lastQuote !== -1) {
charset = charset.slice(firstQuote + 1, lastQuote);
}
return true;
});
} else {
contentType = '';
}
if (!charset) {
charset = this.options.defaultCharset || 'utf-8';
if (this.options.setCharset && !response.headersSent) {
response.headers['content-type'] = `${contentType || ''};charset=${charset}`;
}
}
const bufferEncoding = SendStringMiddleware.charsetAsBufferEncoding(charset);
response.body = Buffer.from(response.body, bufferEncoding);
return true;
}
/** @type {MiddlewareFunction} */
execute({ response }) {
response.finalizers.push(this.finalizeResponse);
}
}