Skip to content

Commit d1b8ba6

Browse files
aleclarsonlukeed
andauthored
fix(sirv): append charset=utf-8 to HTML content-type (#122)
* fix: append charset=utf-8 to text/html Closes #106 I considered fixing this upstream in "mime" or "mime-db" packages, but then I came across these issues, which indicated that it was not a viable path. broofa/mime#174 jshttp/mime-db#94 * test: check for charset=utf-8 in .html requests * fix(test): prevent undefined `full` access * chore: add `charset=utf-8` to test expectants * chore: light code style/spacing Co-authored-by: Luke Edwards <luke.edwards05@gmail.com>
1 parent 881c4c7 commit d1b8ba6

File tree

3 files changed

+22
-12
lines changed

3 files changed

+22
-12
lines changed

packages/sirv/index.js

+13-7
Original file line numberDiff line numberDiff line change
@@ -88,20 +88,26 @@ function send(req, res, file, stats, headers) {
8888
fs.createReadStream(file, opts).pipe(res);
8989
}
9090

91-
function isEncoding(name, type, headers) {
92-
headers['Content-Encoding'] = type;
93-
headers['Content-Type'] = mime.getType(name.replace(/\.([^.]*)$/, '')) || '';
94-
}
91+
const ENCODING = {
92+
'.br': 'br',
93+
'.gz': 'gzip',
94+
};
9595

9696
function toHeaders(name, stats, isEtag) {
97+
let enc = ENCODING[name.slice(-3)];
98+
99+
let ctype = mime.getType(name.slice(0, enc && -3)) || '';
100+
if (ctype === 'text/html') ctype += ';charset=utf-8';
101+
97102
let headers = {
98103
'Content-Length': stats.size,
99-
'Content-Type': mime.getType(name) || '',
104+
'Content-Type': ctype,
100105
'Last-Modified': stats.mtime.toUTCString(),
101106
};
107+
108+
if (enc) headers['Content-Encoding'] = enc;
102109
if (isEtag) headers['ETag'] = `W/"${stats.size}-${stats.mtime.getTime()}"`;
103-
if (/\.br$/.test(name)) isEncoding(name, 'br', headers);
104-
if (/\.gz$/.test(name)) isEncoding(name, 'gzip', headers);
110+
105111
return headers;
106112
}
107113

tests/helpers.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,14 @@ export async function lookup(filepath, enc) {
7676
let full = join(www, filepath);
7777
let stats = await statfile(full);
7878
filedata = await readfile(full, enc);
79+
80+
let ctype = mime.getType(full) || '';
81+
if (ctype === 'text/html') ctype += ';charset=utf-8';
82+
7983
return CACHE[filepath] = {
8084
data: filedata,
8185
size: stats.size,
82-
type: mime.getType(full) || '',
86+
type: ctype,
8387
mtime: stats.mtime.getTime(),
8488
};
8589
}

tests/sirv.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -733,7 +733,7 @@ brotli('should serve prepared `.br` file of any asset, if found', async () => {
733733

734734
try {
735735
let res1 = await server.send('GET', '/', { headers });
736-
assert.is(res1.headers['content-type'], 'text/html');
736+
assert.is(res1.headers['content-type'], 'text/html;charset=utf-8');
737737
assert.is(res1.headers['content-encoding'], 'br');
738738
assert.is(res1.data, 'brotli html\n');
739739
assert.is(res1.statusCode, 200);
@@ -751,7 +751,7 @@ brotli('should be preferred when "Accept-Encoding" allows both', async () => {
751751

752752
try {
753753
let res1 = await server.send('GET', '/', { headers });
754-
assert.is(res1.headers['content-type'], 'text/html');
754+
assert.is(res1.headers['content-type'], 'text/html;charset=utf-8');
755755
assert.is(res1.headers['content-encoding'], 'br');
756756
assert.is(res1.data, 'brotli html\n');
757757
assert.is(res1.statusCode, 200);
@@ -798,7 +798,7 @@ gzip('should serve prepared `.gz` file of any asset, if found', async () => {
798798

799799
try {
800800
let res1 = await server.send('GET', '/', { headers });
801-
assert.is(res1.headers['content-type'], 'text/html');
801+
assert.is(res1.headers['content-type'], 'text/html;charset=utf-8');
802802
assert.is(res1.headers['content-encoding'], 'gzip');
803803
assert.is(res1.data, 'gzip html\n');
804804
assert.is(res1.statusCode, 200);
@@ -816,7 +816,7 @@ gzip('should defer to brotli when "Accept-Encoding" allows both', async () => {
816816

817817
try {
818818
let res1 = await server.send('GET', '/', { headers });
819-
assert.is(res1.headers['content-type'], 'text/html');
819+
assert.is(res1.headers['content-type'], 'text/html;charset=utf-8');
820820
assert.is(res1.headers['content-encoding'], 'br');
821821
assert.is(res1.data, 'brotli html\n');
822822
assert.is(res1.statusCode, 200);

0 commit comments

Comments
 (0)