/**
* Intercept writes for head requests, do not send to client,
* but send length, and make body available in context.
+ * N.B. If persisted, ctx.responseBody will be a raw buffer, be aware when logging.
* @param {http.ClientRequest} req
* @param {http.ServerResponse} res
* @param {object} ctx
+ * @param {Boolean} persistResponseBody
*/
- static setHeadHandler(req, res, ctx) {
+ static setHeadHandler(req, res, ctx, persistResponseBody = false) {
if (req.method === 'HEAD') {
const origEnd = res.end.bind(res);
const chunks = [];
};
res.end = function (data, encoding, ...rest) {
Dingus.pushBufChunk(chunks, data, encoding);
- ctx.responseBody = Buffer.concat(chunks);
- res.setHeader(Enum.Header.ContentLength, Buffer.byteLength(ctx.responseBody));
+ const responseBody = Buffer.concat(chunks);
+ res.setHeader(Enum.Header.ContentLength, Buffer.byteLength(responseBody));
+ if (persistResponseBody) {
+ ctx.responseBody = responseBody;
+ }
return origEnd(undefined, encoding, ...rest);
};
}
/**
* Return all body data from a request.
* @param {http.ClientRequest} req
+ * @param {Number=} maximumBodySize
*/
- async bodyData(req) {
+ async bodyData(req, maximumBodySize) {
const _scope = _fileScope('bodyData');
return new Promise((resolve, reject) => {
const body = [];
- req.on('data', (chunk) => body.push(chunk));
+ let length = 0;
+ req.on('data', (chunk) => {
+ body.push(chunk);
+ length += Buffer.byteLength(chunk);
+ if (maximumBodySize && length > maximumBodySize) {
+ this.logger.debug(_scope, 'body data exceeded limit', { length, maximumBodySize });
+ reject(new ResponseError(Enum.ErrorResponse.RequestEntityTooLarge));
+ }
+ });
req.on('end', () => resolve(Buffer.concat(body).toString()));
req.on('error', (e) => {
this.logger.error(_scope, 'failed', { error: e });