hastily
Version:
express middleware to simulate fastly cdn
180 lines • 13 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const on_headers_1 = __importDefault(require("on-headers"));
const logging_1 = require("./logging");
const log = logging_1.createLogger('splice');
/**
* @hidden
*/
function splice(req, res, next, makeStream) {
log.debug({ res }, 'splicing hastily into response for %s', req.originalUrl);
let ended = false;
let length;
const listeners = [];
let stream;
const resEnd = res.end.bind(res);
const resOn = res.on.bind(res);
const resWrite = res.write.bind(res);
const resFlush = typeof res.flush === 'function' ? res.flush.bind(res) : () => null;
const tryImplicitHeader = (instance) => {
try {
instance._implicitHeader();
return true;
}
catch (e) {
return false;
}
};
// flush
res.flush = function flush() {
log.debug('response.flush() called');
if (stream) {
stream.flush();
}
else {
resFlush();
}
};
// proxy
res.write = function write(chunk, encoding) {
log.debug('outgoing response.write() called with chunk of length %s', chunk.length);
if (ended) {
log.debug('response.write(): ended flag is true, returning');
return false;
}
if (!this._header) {
log.debug('response.write(): this._header is false, calling this._implicitHeader()');
if (!tryImplicitHeader(this)) {
return false;
}
}
if (stream) {
log.debug('res.write() has access to stream! writing buffer');
return stream.write(Buffer.from(chunk, encoding));
}
log.debug('res.write() has no access to stream yet. calling underlying response');
return resWrite.call(this, chunk, encoding);
};
res.end = function end(chunk, encoding) {
log.debug('outgoing response.end() called');
if (ended) {
log.debug('response.end(): ended is already true, returning');
return false;
}
if (!this._header) {
log.debug('response.end(): this._header is false, checking content length');
if (!this.getHeader('Content-Length')) {
length = chunkLength(chunk, encoding);
log.debug('response.end(): no Content-Length, %s bytes and counting', length);
}
log.debug('response.end(): calling this._implicitHeader()');
if (tryImplicitHeader(this)) {
log.debug('tryImplicitHeader succeeded');
}
}
if (!stream) {
log.debug('response.end(): stream never became available');
return resEnd.call(this, chunk, encoding);
}
log.debug('response.end(): stream is available, flushing? %s', chunk);
// mark ended
ended = true;
// write Buffer for Node.js 0.8
if (chunk) {
log.debug('chunk of length %s exists in .end, writing it to stream', chunk.length);
stream.end(Buffer.from(chunk, encoding));
}
else {
log.debug({ res }, 'no chunk exists in .end, ending stream clean');
stream.end();
}
};
function addBufferedListener(type, listener) {
log.debug('res.on called for "%s" event', type);
if (!listeners || type !== 'drain') {
log.debug('%s listeners, eventType %s, calling underlying res.on', listeners.length, type);
return resOn.call(this, type, listener);
}
if (stream) {
log.debug('res.on() has access to stream, passing listener');
return stream.on(type, listener);
}
log.debug('stream does not exist; buffering listeners for future stream');
listeners.push([type, listener]);
return this;
}
res.on = addBufferedListener;
const unsplice = () => {
res.on = resOn;
res.end = resEnd;
res.write = resWrite;
addListeners(res, resOn, listeners);
listeners.length = 0;
};
on_headers_1.default(res, function onResponseHeaders() {
try {
if (ended) {
return;
}
stream = makeStream();
if (!stream) {
// request is filtered
unsplice();
return;
}
else {
stream.on('error', () => {
log.debug('stream error, unsplicing');
unsplice();
});
}
// add buffered listeners to stream
addListeners(stream, stream.on, listeners);
// header fields
res.removeHeader('Content-Length');
// compression
stream.on('data', function onStreamData(chunk) {
if (resWrite(chunk) === false) {
stream.pause();
}
});
stream.on('end', resEnd);
resOn.call(res, 'drain', function onResponseDrain() {
stream.resume();
});
}
catch (e) {
console.error(e);
res.statusCode = 400;
res.statusMessage = e.message;
resEnd();
ended = true;
}
});
next();
}
exports.default = splice;
/**
* Add bufferred listeners to stream
* @private
*/
function addListeners(stream, on, listeners) {
for (const listener of listeners) {
on.apply(stream, listener);
}
}
/**
* Get the length of a given chunk
*/
function chunkLength(chunk, encoding) {
if (!chunk) {
return 0;
}
return !Buffer.isBuffer(chunk)
? Buffer.byteLength(chunk, encoding)
: chunk.length;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BsaWNlLXJlc3BvbnNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2xpYi9zcGxpY2UtcmVzcG9uc2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWSxDQUFDOzs7OztBQUdiLDREQUFtQztBQUNuQyx1Q0FBeUM7QUFRekMsTUFBTSxHQUFHLEdBQUcsc0JBQVksQ0FBQyxRQUFRLENBQUMsQ0FBQztBQUVuQzs7R0FFRztBQUNILFNBQXdCLE1BQU0sQ0FDNUIsR0FBWSxFQUNaLEdBQXFCLEVBQ3JCLElBQXdCLEVBQ3hCLFVBQXFDO0lBRXJDLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxHQUFHLEVBQUUsRUFBRSx1Q0FBdUMsRUFBRSxHQUFHLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDN0UsSUFBSSxLQUFLLEdBQUcsS0FBSyxDQUFDO0lBQ2xCLElBQUksTUFBTSxDQUFDO0lBQ1gsTUFBTSxTQUFTLEdBQWUsRUFBRSxDQUFDO0lBQ2pDLElBQUksTUFBMkIsQ0FBQztJQUVoQyxNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNqQyxNQUFNLEtBQUssR0FBRyxHQUFHLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUMvQixNQUFNLFFBQVEsR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNyQyxNQUFNLFFBQVEsR0FDWixPQUFPLEdBQUcsQ0FBQyxLQUFLLEtBQUssVUFBVSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDO0lBRXJFLE1BQU0saUJBQWlCLEdBQUcsQ0FBQyxRQUEwQixFQUFXLEVBQUU7UUFDaEUsSUFBSTtZQUNGLFFBQVEsQ0FBQyxlQUFl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