diff --git a/.eslintrc.json b/.eslintrc.json index 0134e8c..c458f35 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -2,7 +2,8 @@ "env": { "browser": true, "node": true, - "es6": true + "es6": true, + "mocha": true }, "extends": [ "eslint:recommended", diff --git a/changelog.md b/changelog.md index e6dd8eb..649eb20 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,12 @@ ChangeLog ========= +2.0.0 (????-??-??) +------------------ + +* Support for a new 'Date' type, from draft [draft-ietf-httpbis-sfbis-02][7]. + + 1.0.0 (2023-06-13) ------------------ @@ -84,9 +90,10 @@ ChangeLog * First version! * Parses all of the [04 draft of the specification][1]. -[1]: https://tools.ietf.org/html/draft-ietf-httpbis-header-structure-04 [2]: -https://tools.ietf.org/html/draft-ietf-httpbis-header-structure-09 [3]: -https://tools.ietf.org/html/draft-ietf-httpbis-header-structure-10 [4]: -https://tools.ietf.org/html/draft-ietf-httpbis-header-structure-13 [5]: -https://datatracker.ietf.org/doc/html/rfc8941 [6]: -https://github.com/httpwg/structured-field-tests +[1]: https://tools.ietf.org/html/draft-ietf-httpbis-header-structure-04 +[2]: https://tools.ietf.org/html/draft-ietf-httpbis-header-structure-09 +[3]: https://tools.ietf.org/html/draft-ietf-httpbis-header-structure-10 +[4]: https://tools.ietf.org/html/draft-ietf-httpbis-header-structure-13 +[5]: https://datatracker.ietf.org/doc/html/rfc8941 +[6]: https://github.com/httpwg/structured-field-tests +[7]: https://www.ietf.org/archive/id/draft-ietf-httpbis-sfbis-02.html diff --git a/readme.md b/readme.md index 1546101..ec89b92 100644 --- a/readme.md +++ b/readme.md @@ -14,7 +14,7 @@ too, but plain Javascript is also fully supported. Compatibility ------------- -This package has 2725 unittests, the vast majority are supplied from the +This package has 2740 unittests, the vast majority are supplied from the official [HTTP WG test suite][2]. However, there are 2 differences in the serializer: diff --git a/src/parser.ts b/src/parser.ts index 10fec48..3ce6d40 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -179,7 +179,9 @@ export default class Parser { if (char === '?') { return this.parseBoolean(); } - + if (char === '@') { + return this.parseDate(); + } throw new ParseError(this.pos, 'Unexpected input'); } @@ -350,6 +352,34 @@ export default class Parser { } + private parseDate(): Date { + + this.expectChar('@'); + this.pos++; + let sign = 1; + let inputNumber = ''; + if (this.lookChar()==='-') { + sign = -1; + this.pos++; + } + + if (!isDigit(this.lookChar())) { + throw new ParseError(this.pos, 'Expected a digit (0-9)'); + } + + while(!this.eof()) { + const char = this.getChar(); + if (isDigit(char)) { + inputNumber+=char; + } else { + throw new ParseError(this.pos, 'Expected a digit (0-9), whitespace or EOL'); + } + } + + return new Date(parseInt(inputNumber,10)*sign*1000); + + } + private parseKey(): string { if (!this.lookChar().match(/^[a-z*]/)) { diff --git a/src/serializer.ts b/src/serializer.ts index 5f3697b..4c6ac77 100644 --- a/src/serializer.ts +++ b/src/serializer.ts @@ -80,6 +80,9 @@ export function serializeBareItem(input: BareItem): string { if (input instanceof ByteSequence) { return serializeByteSequence(input); } + if (input instanceof Date) { + return serializeDate(input); + } if (typeof input === 'boolean') { return serializeBoolean(input); } @@ -123,6 +126,10 @@ export function serializeToken(input: Token): string { return input.toString(); } +export function serializeDate(input: Date): string { + return '@' + Math.floor(input.getTime()/1000); +} + export function serializeParameters(input: Parameters): string { return Array.from(input).map(([key, value]) => { diff --git a/src/types.ts b/src/types.ts index f5e7ae4..7f293a5 100644 --- a/src/types.ts +++ b/src/types.ts @@ -47,6 +47,6 @@ export class ByteSequence { } -export type BareItem = number | string | Token | ByteSequence | boolean; +export type BareItem = number | string | Token | ByteSequence | Date | boolean; export type Item = [BareItem, Parameters]; diff --git a/test/httpwg-tests.js b/test/httpwg-tests.js index 362eeda..498e61f 100644 --- a/test/httpwg-tests.js +++ b/test/httpwg-tests.js @@ -14,6 +14,7 @@ describe('HTTP-WG tests', () => { 'number', 'string', 'token', + 'date', 'item', @@ -270,6 +271,12 @@ function packTestValue(input) { value: base32Encode(Buffer.from(input.toBase64(), 'base64'), 'RFC4648') } } + if (input instanceof Date) { + return { + __type: 'date', + value: Math.floor(input.getTime()/1000) + }; + } if (input instanceof Map) { return Array.from(input.entries()).map( ([key, value]) => { return [key, packTestValue(value)]; @@ -306,11 +313,17 @@ function packTestValue(input) { */ function unpackTestValue(input) { - if (input.__type === 'token') { - return new Token(input.value); - } - if (input.__type === 'binary') { - return new ByteSequence(Buffer.from(base32Decode(input.value, 'RFC4648')).toString('base64')); + if (input.__type) { + switch(input.__type) { + case 'token' : + return new Token(input.value); + case 'binary': + return new ByteSequence(Buffer.from(base32Decode(input.value, 'RFC4648')).toString('base64')); + case 'date' : + return new Date(input.value * 1000); + default: + throw new Error('Unknown input __type: ' + input.__type); + } } if (Array.isArray(input)) { return input.map(unpackTestValue);