You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
86 lines
3.3 KiB
86 lines
3.3 KiB
"use strict"; |
|
Object.defineProperty(exports, "__esModule", { value: true }); |
|
exports.responseInterceptor = void 0; |
|
const zlib = require("zlib"); |
|
/** |
|
* Intercept responses from upstream. |
|
* Automatically decompress (deflate, gzip, brotli). |
|
* Give developer the opportunity to modify intercepted Buffer and http.ServerResponse |
|
* |
|
* NOTE: must set options.selfHandleResponse=true (prevent automatic call of res.end()) |
|
*/ |
|
function responseInterceptor(interceptor) { |
|
return async function proxyRes(proxyRes, req, res) { |
|
const originalProxyRes = proxyRes; |
|
let buffer = Buffer.from('', 'utf8'); |
|
// decompress proxy response |
|
const _proxyRes = decompress(proxyRes, proxyRes.headers['content-encoding']); |
|
// concat data stream |
|
_proxyRes.on('data', (chunk) => (buffer = Buffer.concat([buffer, chunk]))); |
|
_proxyRes.on('end', async () => { |
|
// copy original headers |
|
copyHeaders(proxyRes, res); |
|
// call interceptor with intercepted response (buffer) |
|
const interceptedBuffer = Buffer.from(await interceptor(buffer, originalProxyRes, req, res)); |
|
// set correct content-length (with double byte character support) |
|
res.setHeader('content-length', Buffer.byteLength(interceptedBuffer, 'utf8')); |
|
res.write(interceptedBuffer); |
|
res.end(); |
|
}); |
|
_proxyRes.on('error', (error) => { |
|
res.end(`Error fetching proxied request: ${error.message}`); |
|
}); |
|
}; |
|
} |
|
exports.responseInterceptor = responseInterceptor; |
|
/** |
|
* Streaming decompression of proxy response |
|
* source: https://github.com/apache/superset/blob/9773aba522e957ed9423045ca153219638a85d2f/superset-frontend/webpack.proxy-config.js#L116 |
|
*/ |
|
function decompress(proxyRes, contentEncoding) { |
|
let _proxyRes = proxyRes; |
|
let decompress; |
|
switch (contentEncoding) { |
|
case 'gzip': |
|
decompress = zlib.createGunzip(); |
|
break; |
|
case 'br': |
|
decompress = zlib.createBrotliDecompress(); |
|
break; |
|
case 'deflate': |
|
decompress = zlib.createInflate(); |
|
break; |
|
default: |
|
break; |
|
} |
|
if (decompress) { |
|
_proxyRes.pipe(decompress); |
|
_proxyRes = decompress; |
|
} |
|
return _proxyRes; |
|
} |
|
/** |
|
* Copy original headers |
|
* https://github.com/apache/superset/blob/9773aba522e957ed9423045ca153219638a85d2f/superset-frontend/webpack.proxy-config.js#L78 |
|
*/ |
|
function copyHeaders(originalResponse, response) { |
|
response.statusCode = originalResponse.statusCode; |
|
response.statusMessage = originalResponse.statusMessage; |
|
if (response.setHeader) { |
|
let keys = Object.keys(originalResponse.headers); |
|
// ignore chunked, brotli, gzip, deflate headers |
|
keys = keys.filter((key) => !['content-encoding', 'transfer-encoding'].includes(key)); |
|
keys.forEach((key) => { |
|
let value = originalResponse.headers[key]; |
|
if (key === 'set-cookie') { |
|
// remove cookie domain |
|
value = Array.isArray(value) ? value : [value]; |
|
value = value.map((x) => x.replace(/Domain=[^;]+?/i, '')); |
|
} |
|
response.setHeader(key, value); |
|
}); |
|
} |
|
else { |
|
response.headers = originalResponse.headers; |
|
} |
|
}
|
|
|