diff --git a/packages/headers/CHANGELOG.md b/packages/headers/CHANGELOG.md index 84255ec..fb35713 100644 --- a/packages/headers/CHANGELOG.md +++ b/packages/headers/CHANGELOG.md @@ -132,7 +132,10 @@ header.getPreferred(['gzip', 'deflate']); // 'gzip' - `acceptEncoding` - `acceptRanges` - `connection` + - `contentEncoding` + - `contentLanguage` - `host` + - `location` - `referer` ## v0.8.0 (2024-11-14) diff --git a/packages/headers/README.md b/packages/headers/README.md index 44040aa..87dd4dc 100644 --- a/packages/headers/README.md +++ b/packages/headers/README.md @@ -28,8 +28,8 @@ let headers = new Headers(); headers.accept = { 'text/html': 1, 'text/*': 0.9 }; // or headers.accept = 'text/html,text/*;q=0.9'; -console.log(headers.accept.mediaTypes); // [ 'text/html', 'text/*' ] -console.log(Object.fromEntries(headers.accept.entries())); // { 'text/html': 1, 'text/*': 0.9 } +headers.accept.mediaTypes; // [ 'text/html', 'text/*' ] +Object.fromEntries(headers.accept.entries()); // { 'text/html': 1, 'text/*': 0.9 } headers.accept.accepts('text/html'); // true headers.accept.accepts('text/plain'); // true @@ -40,7 +40,7 @@ headers.accept.getPreferred(['text/plain', 'text/html']); // 'text/html' headers.accept.set('text/plain', 0.9); headers.accept.set('text/*', 0.8); -console.log(headers.get('Accept')); // "text/html,text/plain;q=0.9,text/*;q=0.8" +headers.get('Accept'); // 'text/html,text/plain;q=0.9,text/*;q=0.8' // Accept-Encoding headers.acceptEncoding = { gzip: 1, deflate: 0.8 }; @@ -55,8 +55,8 @@ headers.acceptEncoding.getPreferred(['gzip', 'deflate']); // 'gzip' headers.acceptLanguage = { 'en-US': 1, en: 0.9 }; // or headers.acceptLanguage = 'en-US,en;q=0.9'; -console.log(headers.acceptLanguage.languages); // [ 'en-us', 'en' ] -console.log(Object.fromEntries(headers.acceptLanguage.entries())); // { 'en-us': 1, en: 0.9 } +headers.acceptLanguage.languages; // [ 'en-us', 'en' ] +Object.fromEntries(headers.acceptLanguage.entries()); // { 'en-us': 1, en: 0.9 } headers.acceptLanguage.accepts('en'); // true headers.acceptLanguage.accepts('ja'); // false @@ -73,51 +73,58 @@ headers.connection = 'close'; // Content-Type headers.contentType = 'application/json; charset=utf-8'; -console.log(headers.contentType.mediaType); // "application/json" -console.log(headers.contentType.charset); // "utf-8" +headers.contentType.mediaType; // "application/json" +headers.contentType.charset; // "utf-8" headers.contentType.charset = 'iso-8859-1'; -console.log(headers.get('Content-Type')); // "application/json; charset=iso-8859-1" +headers.get('Content-Type'); // "application/json; charset=iso-8859-1" // Content-Disposition headers.contentDisposition = 'attachment; filename="example.pdf"; filename*=UTF-8\'\'%E4%BE%8B%E5%AD%90.pdf'; -console.log(headers.contentDisposition.type); // 'attachment' -console.log(headers.contentDisposition.filename); // 'example.pdf' -console.log(headers.contentDisposition.filenameSplat); // 'UTF-8\'\'%E4%BE%8B%E5%AD%90.pdf' -console.log(headers.contentDisposition.preferredFilename); // '例子.pdf' +headers.contentDisposition.type; // 'attachment' +headers.contentDisposition.filename; // 'example.pdf' +headers.contentDisposition.filenameSplat; // 'UTF-8\'\'%E4%BE%8B%E5%AD%90.pdf' +headers.contentDisposition.preferredFilename; // '例子.pdf' // Cookie headers.cookie = 'session_id=abc123; user_id=12345'; -console.log(headers.cookie.get('session_id')); // 'abc123' -console.log(headers.cookie.get('user_id')); // '12345' +headers.cookie.get('session_id'); // 'abc123' +headers.cookie.get('user_id'); // '12345' headers.cookie.set('theme', 'dark'); -console.log(headers.get('Cookie')); // 'session_id=abc123; user_id=12345; theme=dark' +headers.get('Cookie'); // 'session_id=abc123; user_id=12345; theme=dark' // Host headers.host = 'example.com'; +// Last-Modified +headers.lastModified = new Date(); +// or headers.lastModified = new Date().getTime(); +headers.get('Last-Modified'); // 'Fri, 20 Dec 2024 08:08:05 GMT' + +// Location +headers.location = 'https://example.com'; + // Referer headers.referer = 'https://example.com/'; // Set-Cookie headers.setCookie = ['session_id=abc123; Path=/; HttpOnly']; -console.log(headers.setCookie[0].name); // 'session_id' -console.log(headers.setCookie[0].value); // 'abc123' -console.log(headers.setCookie[0].path); // '/' -console.log(headers.setCookie[0].httpOnly); // true +headers.setCookie[0].name; // 'session_id' +headers.setCookie[0].value; // 'abc123' +headers.setCookie[0].path; // '/' +headers.setCookie[0].httpOnly; // true // Modifying Set-Cookie attributes headers.setCookie[0].maxAge = 3600; headers.setCookie[0].secure = true; -console.log(headers.get('Set-Cookie')); -// session_id=abc123; Path=/; HttpOnly; Max-Age=3600; Secure +headers.get('Set-Cookie'); // 'session_id=abc123; Path=/; HttpOnly; Max-Age=3600; Secure' // Setting multiple cookies is easy, it's just an array headers.setCookie.push('user_id=12345; Path=/api; Secure'); diff --git a/packages/headers/src/lib/super-headers.test.ts b/packages/headers/src/lib/super-headers.test.ts index f34b426..a32ef33 100644 --- a/packages/headers/src/lib/super-headers.test.ts +++ b/packages/headers/src/lib/super-headers.test.ts @@ -200,6 +200,16 @@ describe('SuperHeaders', () => { assert.equal(headers.get('Content-Disposition'), 'attachment; filename=example.txt'); }); + it('handles the contentEncoding property', () => { + let headers = new SuperHeaders({ contentEncoding: 'gzip' }); + assert.equal(headers.get('Content-Encoding'), 'gzip'); + }); + + it('handles the contentLanguage property', () => { + let headers = new SuperHeaders({ contentLanguage: 'en-US' }); + assert.equal(headers.get('Content-Language'), 'en-US'); + }); + it('handles the contentLength property', () => { let headers = new SuperHeaders({ contentLength: 42 }); assert.equal(headers.get('Content-Length'), '42'); @@ -232,11 +242,6 @@ describe('SuperHeaders', () => { assert.equal(headers.get('Host'), 'example.com'); }); - it('handles the lastModified property', () => { - let headers = new SuperHeaders({ lastModified: new Date('2021-01-01T00:00:00Z') }); - assert.equal(headers.get('Last-Modified'), 'Fri, 01 Jan 2021 00:00:00 GMT'); - }); - it('handles the ifModifiedSince property', () => { let headers = new SuperHeaders({ ifModifiedSince: new Date('2021-01-01T00:00:00Z') }); assert.equal(headers.get('If-Modified-Since'), 'Fri, 01 Jan 2021 00:00:00 GMT'); @@ -247,6 +252,16 @@ describe('SuperHeaders', () => { assert.equal(headers.get('If-Unmodified-Since'), 'Fri, 01 Jan 2021 00:00:00 GMT'); }); + it('handles the lastModified property', () => { + let headers = new SuperHeaders({ lastModified: new Date('2021-01-01T00:00:00Z') }); + assert.equal(headers.get('Last-Modified'), 'Fri, 01 Jan 2021 00:00:00 GMT'); + }); + + it('handles the location property', () => { + let headers = new SuperHeaders({ location: 'https://example.com' }); + assert.equal(headers.get('Location'), 'https://example.com'); + }); + it('handles the referer property', () => { let headers = new SuperHeaders({ referer: 'https://example.com' }); assert.equal(headers.get('Referer'), 'https://example.com'); @@ -413,6 +428,36 @@ describe('SuperHeaders', () => { assert.equal(headers.contentDisposition.toString(), ''); }); + it('supports the contentEncoding property', () => { + let headers = new SuperHeaders(); + + assert.equal(headers.contentEncoding, null); + + headers.contentEncoding = 'gzip'; + assert.equal(headers.contentEncoding, 'gzip'); + + headers.contentEncoding = ['deflate', 'gzip']; + assert.equal(headers.contentEncoding, 'deflate, gzip'); + + headers.contentEncoding = null; + assert.equal(headers.contentEncoding, null); + }); + + it('supports the contentLanguage property', () => { + let headers = new SuperHeaders(); + + assert.equal(headers.contentLanguage, null); + + headers.contentLanguage = 'en-US'; + assert.equal(headers.contentLanguage, 'en-US'); + + headers.contentLanguage = ['en', 'fr']; + assert.equal(headers.contentLanguage, 'en, fr'); + + headers.contentLanguage = null; + assert.equal(headers.contentLanguage, null); + }); + it('supports the contentLength property', () => { let headers = new SuperHeaders(); @@ -506,19 +551,6 @@ describe('SuperHeaders', () => { assert.equal(headers.host, null); }); - it('supports the lastModified property', () => { - let headers = new SuperHeaders(); - - assert.equal(headers.lastModified, null); - - headers.lastModified = new Date('2021-01-01T00:00:00Z'); - assert.ok(headers.lastModified instanceof Date); - assert.equal(headers.lastModified.toUTCString(), 'Fri, 01 Jan 2021 00:00:00 GMT'); - - headers.lastModified = null; - assert.equal(headers.lastModified, null); - }); - it('supports the ifModifiedSince property', () => { let headers = new SuperHeaders(); @@ -545,6 +577,31 @@ describe('SuperHeaders', () => { assert.equal(headers.ifUnmodifiedSince, null); }); + it('supports the lastModified property', () => { + let headers = new SuperHeaders(); + + assert.equal(headers.lastModified, null); + + headers.lastModified = new Date('2021-01-01T00:00:00Z'); + assert.ok(headers.lastModified instanceof Date); + assert.equal(headers.lastModified.toUTCString(), 'Fri, 01 Jan 2021 00:00:00 GMT'); + + headers.lastModified = null; + assert.equal(headers.lastModified, null); + }); + + it('supports the location property', () => { + let headers = new SuperHeaders(); + + assert.equal(headers.location, null); + + headers.location = 'https://example.com'; + assert.equal(headers.location, 'https://example.com'); + + headers.location = null; + assert.equal(headers.location, null); + }); + it('supports the referer property', () => { let headers = new SuperHeaders(); diff --git a/packages/headers/src/lib/super-headers.ts b/packages/headers/src/lib/super-headers.ts index 27c125d..2de8db4 100644 --- a/packages/headers/src/lib/super-headers.ts +++ b/packages/headers/src/lib/super-headers.ts @@ -48,6 +48,14 @@ interface SuperHeadersPropertyInit { * The [`Content-Disposition`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition) header value. */ contentDisposition?: string | ContentDispositionInit; + /** + * The [`Content-Encoding`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding) header value. + */ + contentEncoding?: string | string[]; + /** + * The [`Content-Language`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Language) header value. + */ + contentLanguage?: string | string[]; /** * The [`Content-Length`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Length) header value. */ @@ -84,6 +92,10 @@ interface SuperHeadersPropertyInit { * The [`Last-Modified`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified) header value. */ lastModified?: string | DateInit; + /** + * The [`Location`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location) header value. + */ + location?: string; /** * The [`Referer`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referer) header value. */ @@ -434,6 +446,42 @@ export class SuperHeaders extends Headers { this.#setHeaderValue('content-disposition', ContentDisposition, value); } + /** + * The `Content-Encoding` header specifies the encoding of the resource. + * + * Note: If multiple encodings have been used, this value may be a comma-separated list. However, most often this + * header will only contain a single value. + * + * [MDN `Content-Encoding` Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding) + * + * [HTTP/1.1 Specification](https://httpwg.org/specs/rfc9110.html#field.content-encoding) + */ + get contentEncoding(): string | null { + return this.get('content-encoding'); + } + + set contentEncoding(value: string | string[] | undefined | null) { + this.#setValue('content-encoding', Array.isArray(value) ? value.join(', ') : value); + } + + /** + * The `Content-Language` header describes the natural language(s) of the intended audience for the response content. + * + * Note: If the response content is intended for multiple audiences, this value may be a comma-separated list. However, + * most often this header will only contain a single value. + * + * [MDN `Content-Language` Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Language) + * + * [HTTP/1.1 Specification](https://httpwg.org/specs/rfc9110.html#field.content-language) + */ + get contentLanguage(): string | null { + return this.get('content-language'); + } + + set contentLanguage(value: string | string[] | undefined | null) { + this.#setValue('content-language', Array.isArray(value) ? value.join(', ') : value); + } + /** * The `Content-Length` header indicates the size of the entity-body in bytes. * @@ -572,6 +620,21 @@ export class SuperHeaders extends Headers { this.#setDateValue('last-modified', value); } + /** + * The `Location` header indicates the URL to redirect to. + * + * [MDN `Location` Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location) + * + * [HTTP/1.1 Specification](https://datatracker.ietf.org/doc/html/rfc7231#section-7.1.2) + */ + get location(): string | null { + return this.get('location'); + } + + set location(value: string | undefined | null) { + this.#setValue('location', value); + } + /** * The `Referer` header contains the address of the previous web page from which a link to the * currently requested page was followed.