-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
96 lines (84 loc) · 2.72 KB
/
index.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
88
89
90
91
92
93
94
95
96
'use strict'
const {promisify} = require('util')
const {gzip, brotliCompress} = require('zlib')
const {performance} = require('perf_hooks')
const computeEtag = require('etag')
const debugCompression = require('debug')('serve-buffer:compression')
const _serveBuffer = require('./lib/serve-buffer')
const pGzip = promisify(gzip)
const pBrotliCompress = promisify(brotliCompress)
const compression = (compress, name, maxSize, unmutatedBuffers, cache) => {
return async (buf) => {
if (buf.length > maxSize) {
debugCompression(`buffer is larger than ${maxSize} (${buf.length}), skipping compression`)
return {compressedBuffer: null, compressedEtag: null}
}
if (unmutatedBuffers && cache.has(buf)) return cache.get(buf)
const t0 = performance.now()
const compressedBuffer = await compress(buf)
const t1 = performance.now()
// todo: is there an async version of this?
const compressedEtag = computeEtag(compressedBuffer)
const t2 = performance.now()
debugCompression(`${name}-compressed in ${(t1 - t0).toFixed(1)}ms, computed ETag in ${(t2 - t1).toFixed(1)}ms`)
const res = {compressedBuffer, compressedEtag}
if (unmutatedBuffers) cache.set(buf, res)
return res
}
}
// todo [breaking]: this is ugly, make `serveBuffer` a closure
const gzipCache = new WeakMap()
const brotliCompressCache = new WeakMap()
const serveBuffer = (req, res, buf, opt, cb) => {
if (cb === undefined && 'function' === typeof opt) {
cb = opt
opt = {}
}
opt = {
gzip: true,
gzipMaxSize: 10 * 1024 * 1024, // 10mb
brotliCompress: true,
brotliCompressMaxSize: 512 * 1024, // 512kb
// Assume that Buffers passed in as `buf` never get mutated? If `true`,
// each compressed buffer & compressed ETag will be cached as long as
// the buffer instance exists.
unmutatedBuffers: false,
...opt,
}
if (opt.gzip === true) {
opt.gzip = compression(
pGzip,
'gzip',
opt.gzipMaxSize,
opt.unmutatedBuffers,
gzipCache,
)
} else if (opt.gzip === false) {
opt.gzip = null
} else if ('function' !== typeof opt.gzip) {
throw new TypeError('opt.gzip must be true, false or an async function')
}
if (opt.brotliCompress === true) {
opt.brotliCompress = compression(
pBrotliCompress,
'brotliCompress',
opt.brotliCompressMaxSize,
opt.unmutatedBuffers,
brotliCompressCache,
)
} else if (opt.brotliCompress === false) {
opt.brotliCompress = null
} else if ('function' !== typeof opt.brotliCompress) {
throw new TypeError('opt.brotliCompress must be true, false or an async function')
}
if ('function' !== typeof cb) {
cb = (err) => {
if (!err) return
if (err.code === 'ERR_STREAM_PREMATURE_CLOSE') return;
throw err
}
}
_serveBuffer(req, res, buf, opt)
.then(() => cb(), cb)
}
module.exports = serveBuffer