## [Unreleased]
+## [v2.1.0] - TBD
+
+- cookies are now parsed and populated into ctx.cookie as a default behavior
- added HTTP status and message enums
- updated devDependencies
---
-[Unreleased]: https://git.squeep.com/?p=squeep-api-dingus;a=commitdiff;h=HEAD;hp=v2.0.1
+[Unreleased]: https://git.squeep.com/?p=squeep-api-dingus;a=commitdiff;h=HEAD;hp=v2.1.0
+[v2.1.0]: https://git.squeep.com/?p=squeep-api-dingus;a=commitdiff;h=v2.1.0;hp=v2.0.1
[v2.0.1]: https://git.squeep.com/?p=squeep-api-dingus;a=commitdiff;h=v2.0.1;hp=v2.0.0
[v2.0.0]: https://git.squeep.com/?p=squeep-api-dingus;a=commitdiff;h=v2.0.0;hp=v1.2.10
[v1.2.10]: https://git.squeep.com/?p=squeep-api-dingus;a=commitdiff;h=v1.2.10;hp=v1.2.9
querystring,
};
+const cookieSplitRE = /; */;
+
class Dingus {
/**
* @param {Object} logger object which implements logging methods
/**
- * Called before every request handler.
- * Sets tracking identifiers and client information on ctx.
+ * Sets ctx.cookie from Cookie header.
* @param {http.ClientRequest} req
* @param {http.ServerResponse} res
* @param {object} ctx
*/
+ static ingestCookie(req, res, ctx) {
+ ctx.cookie = {};
+ req.getHeader(Enum.Header.Cookie)?.split(cookieSplitRE).forEach((cookie) => {
+ const [ name, value ] = common.splitFirst(cookie, '=', null).map((x) => {
+ try {
+ return decodeURIComponent(x.trim());
+ } catch (e) {
+ return x;
+ }
+ });
+ if (name && !(name in ctx.cookie)) {
+ const isQuoted = value?.startsWith('"') && value.endsWith('"');
+ ctx.cookie[name] = isQuoted ? value.slice(1, -1) : value; // eslint-disable-line security/detect-object-injection
+ }
+ });
+ }
+
+
+ /**
+ * Called before every request handler.
+ * Sets tracking identifiers and client information on ctx.
+ * @param {http.ClientRequest} req
+ * @param {http.ServerResponse} res
+ * @param {object} ctx
+ */
async preHandler(req, res, ctx) {
- Dingus.tagContext(req, res, ctx);
+ this.constructor.tagContext(req, res, ctx);
this.clientAddressContext(req, res, ctx);
+ this.constructor.ingestCookie(req, res, ctx);
}
ContentEncoding: 'Content-Encoding',
ContentLength: 'Content-Length',
ContentType: 'Content-Type',
+ Cookie: 'Cookie',
ETag: 'ETag',
IfModifiedSince: 'If-Modified-Since',
IfNoneMatch: 'If-None-Match',
LastModified: 'Last-Modified',
Location: 'Location',
RequestId: 'Request-ID',
+ SetCookie: 'Set-Cookie',
Vary: 'Vary',
XCorrelationId: 'X-Correlation-ID',
XForwardedFor: 'X-Forwarded-For',
if (typeof name !== 'string') {
throw new TypeError('\'name\' must be a string');
}
- return this.headers && this.headers[name.toLowerCase()];
+ return this.headers?.[name.toLowerCase()];
};
}
const noExpectedException = 'did not get expected exception';
-const _nop = () => {};
+const _nop = () => undefined;
const _logFn = (process.env['VERBOSE_TESTS'] && console.log) || _nop;
const noLogger = {
debug: _logFn,
});
}); // clientAddressContext
+ describe('ingestCookie', function () {
+ let req, res, ctx;
+ beforeEach(function () {
+ req = {
+ getHeader: sinon.stub(),
+ };
+ ctx = {};
+ });
+ it('covers no header', function () {
+ const expected = {};
+ Dingus.ingestCookie(req, res, ctx);
+ assert.deepStrictEqual(ctx.cookie, expected);
+ });
+ it('covers non variable', function () {
+ req.getHeader.returns('foo');
+ const expected = {
+ foo: null,
+ };
+ Dingus.ingestCookie(req, res, ctx);
+ assert.deepStrictEqual(ctx.cookie, expected);
+ });
+ it('parses cookies', function () {
+ req.getHeader.returns('foo=bar; baz="quux"');
+ const expected = {
+ foo: 'bar',
+ baz: 'quux',
+ };
+ Dingus.ingestCookie(req, res, ctx);
+ assert.deepStrictEqual(ctx.cookie, expected);
+ });
+ it('parses nulls', function () {
+ req.getHeader.returns('foo=; bar=');
+ const expected = {
+ foo: '',
+ bar: '',
+ };
+ Dingus.ingestCookie(req, res, ctx);
+ assert.deepStrictEqual(ctx.cookie, expected);
+ });
+ it('parses non-uri-encoded', function () {
+ req.getHeader.returns('foo%=%qux');
+ const expected = {
+ 'foo%': '%qux',
+ };
+ Dingus.ingestCookie(req, res, ctx);
+ assert.deepStrictEqual(ctx.cookie, expected);
+ });
+ it('covers nameless cookie', function () {
+ req.getHeader.returns('=bar');
+ const expected = {
+ };
+ Dingus.ingestCookie(req, res, ctx);
+ assert.deepStrictEqual(ctx.cookie, expected);
+
+ });
+ it('covers duplicate cookie', function () {
+ req.getHeader.returns('foo=bar; foo="quux"');
+ const expected = {
+ foo: 'bar',
+ };
+ Dingus.ingestCookie(req, res, ctx);
+ assert.deepStrictEqual(ctx.cookie, expected);
+ });
+ }); // ingestCookie
+
describe('getRequestContentType', function () {
let req;
beforeEach(function () {