X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=lib%2Fdingus.js;h=943aa2f91e7bfc141960b35182bbbc23ef816f16;hb=953c58b691c50950e7c5a87966b5ea56ef6ffa95;hp=1098ea7dc54041f57a6987bfad6b9560a149ae94;hpb=4ec136ae8257a1a9f40d83ad61c57954226e79e0;p=squeep-api-dingus diff --git a/lib/dingus.js b/lib/dingus.js index 1098ea7..943aa2f 100644 --- a/lib/dingus.js +++ b/lib/dingus.js @@ -27,7 +27,7 @@ const defaultOptions = { strictAccept: true, selfBaseUrl: '', staticMetadata: true, - staticPath: undefined, // no reasonable default + staticPath: undefined, // No reasonable default trustProxy: true, querystring, }; @@ -311,21 +311,27 @@ class Dingus { /** - * Parse rawBody from ctx as contentType into parsedBody. - * @param {string} contentType - * @param {object} ctx - */ - parseBody(contentType, ctx) { + * Parse rawBody as contentType into ctx.parsedBody. + * @param {string} contentType + * @param {object} ctx + * @param {string|buffer} + */ + parseBody(contentType, ctx, rawBody) { const _scope = _fileScope('parseBody'); + if (!rawBody) { + // 1.2.4 and earlier expected rawBody on context + rawBody = ctx.rawBody; + } + switch (contentType) { case Enum.ContentType.ApplicationForm: - ctx.parsedBody = this.querystring.parse(ctx.rawBody); + ctx.parsedBody = this.querystring.parse(rawBody); break; case Enum.ContentType.ApplicationJson: try { - ctx.parsedBody = JSON.parse(ctx.rawBody); + ctx.parsedBody = JSON.parse(rawBody); } catch (e) { this.logger.debug(_scope, 'JSON parse failed', { requestId: ctx.requestId, error: e }); throw new ResponseError(Enum.ErrorResponse.BadRequest, e.message); @@ -343,8 +349,9 @@ class Dingus { * Return all body data from a request. * @param {http.ClientRequest} req * @param {Number=} maximumBodySize + * @param {Boolean=} toString */ - async bodyData(req, maximumBodySize) { + async bodyData(req, maximumBodySize, toString = true) { const _scope = _fileScope('bodyData'); return new Promise((resolve, reject) => { const body = []; @@ -357,7 +364,10 @@ class Dingus { reject(new ResponseError(Enum.ErrorResponse.RequestEntityTooLarge)); } }); - req.on('end', () => resolve(Buffer.concat(body).toString())); + req.on('end', () => { + const bodyBuffer = Buffer.concat(body); + resolve(toString ? bodyBuffer.toString() : bodyBuffer); + }); req.on('error', (e) => { this.logger.error(_scope, 'failed', { error: e }); reject(e); @@ -371,11 +381,19 @@ class Dingus { * @param {http.ClientRequest} req * @param {http.ServerResponse} res * @param {object} ctx - */ - async ingestBody(req, res, ctx) { - ctx.rawBody = await this.bodyData(req); - const contentType = Dingus.getRequestContentType(req); - this.parseBody(contentType, ctx); + * @param {object} + * @param {Boolean} .parseEmptyBody + * @param {Boolean} .persistRawBody + */ + async ingestBody(req, res, ctx, { parseEmptyBody = true, persistRawBody = false, maximumBodySize } = {}) { + const rawBody = await this.bodyData(req, maximumBodySize); + if (persistRawBody) { + ctx.rawBody = rawBody; + } + if (rawBody || parseEmptyBody) { + const contentType = Dingus.getRequestContentType(req); + this.parseBody(contentType, ctx, rawBody); + } } @@ -507,7 +525,7 @@ class Dingus { */ async serveFile(req, res, ctx, directory, fileName) { const _scope = _fileScope('serveFile'); - this.logger.debug(_scope, 'called', { req: common.requestLogData(req), ctx }); + this.logger.debug(_scope, 'called', { req, ctx }); // Require a directory field. if (!directory) { @@ -547,18 +565,20 @@ class Dingus { break; } const suffix = Enum.EncodingTypeSuffix[encoding]; - if (suffix) { - const encodedFilePath = `${filePath}${suffix}`; - const [ encodedStat, encodedData ] = await this._readFileInfo(encodedFilePath); - if (encodedStat) { - ([ stat, data ] = [ encodedStat, encodedData ]); - ctx.selectedEncoding = encoding; - Dingus.addEncodingHeader(res, encoding); - res.setHeader(Enum.Header.Vary, Enum.Header.AcceptEncoding); - this.logger.debug(_scope, 'serving encoded version', { ctx, encodedFilePath }); - } - break; + if (!suffix) { + this.logger.error(_scope, 'supported encoding missing mapped suffix', { ctx, encoding }); + continue; + } + const encodedFilePath = `${filePath}${suffix}`; + const [ encodedStat, encodedData ] = await this._readFileInfo(encodedFilePath); + if (encodedStat) { + ([ stat, data ] = [ encodedStat, encodedData ]); + ctx.selectedEncoding = encoding; + Dingus.addEncodingHeader(res, encoding); + res.setHeader(Enum.Header.Vary, Enum.Header.AcceptEncoding); + this.logger.debug(_scope, 'serving encoded version', { ctx, encodedFilePath }); } + break; } const lastModifiedDate = new Date(stat.mtimeMs); @@ -635,11 +655,11 @@ class Dingus { if (err && err.statusCode) { res.statusCode = err.statusCode; body = this.renderError(res.getHeader(Enum.Header.ContentType), err); - this.logger.debug(_scope, 'handler error', { err, ...common.handlerLogData(req, res, ctx) }); + this.logger.debug(_scope, 'handler error', { err, req, res, ctx }); } else { res.statusCode = 500; body = this.renderError(res.getHeader(Enum.Header.ContentType), Enum.ErrorResponse.InternalServerError); - this.logger.error(_scope, 'handler exception', { err, ...common.handlerLogData(req, res, ctx) }); + this.logger.error(_scope, 'handler exception', { err, req, res, ctx }); } res.end(body); }