From: Justin Wind Date: Fri, 15 Aug 2025 16:27:42 +0000 (-0700) Subject: add more common headers, use proxy for headers X-Git-Url: https://git.squeep.com/?a=commitdiff_plain;h=6846d9ee789c18f93b7cddd567a195c31c434db5;p=squeep-api-dingus add more common headers, use proxy for headers --- diff --git a/lib/enum.js b/lib/enum.js index 02337f7..5344b8c 100644 --- a/lib/enum.js +++ b/lib/enum.js @@ -194,6 +194,9 @@ function errorResponseGenerator () { const ErrorResponse = errorResponseGenerator(); +/** + * Always provide an error response, 500 if unknown. + */ const ErrorResponseProxy = new Proxy(ErrorResponse, { get: (target, property) => { if (property in target) { @@ -210,40 +213,128 @@ const ErrorResponseProxy = new Proxy(ErrorResponse, { const Header = { Accept: 'Accept', AcceptEncoding: 'Accept-Encoding', + AcceptLanguage: 'Accept-Language', + AcceptPatch: 'Accept-Patch', + AcceptPost: 'Accept-Post', + AcceptRanges: 'Accept-Ranges', + AccessControlAllowCredentials: 'Access-Control-Allow-Credentials', + AccessControlAllowHeaders: 'Access-Control-Allow-Headers', + AccessControlAllowMethods: 'Access-Control-Allow-Methods', + AccessControlAllowOrigin: 'Access-Control-Allow-Origin', + AccessControlExposeHeaders: 'Access-Control-Expose-Headers', + AccessControlMaxAge: 'Access-Control-Max-Age', + AccessControlRequestHeaders: 'Access-Control-Request-Headers', + AccessControlRequestMethod: 'Access-Control-Request-Method', + Age: 'Age', Allow: 'Allow', + AltSvc: 'Alt-Svc', + AltUsed: 'Alt-Used', + Authorization: 'Authorization', CacheControl: 'Cache-Control', + ClearSiteData: 'Clear-Site-Data', + Connection: 'Connection', ContentDigest: 'Content-Digest', + ContentDisposition: 'Content-Disposition', ContentEncoding: 'Content-Encoding', + ContentLanguage: 'Content-Language', ContentLength: 'Content-Length', + ContentLocation: 'Content-Location', + ContentRange: 'Content-Range', + ContentSecurityPolicy: 'Content-Security-Policy', + ContentSecurityPolicyReportOnly: 'Content-Security-Policy-Report-Only', ContentType: 'Content-Type', Cookie: 'Cookie', + CrossOriginEmbedderPolicy: 'Cross-Origin-Embedder-Policy', + CrossOriginOpenerPolicy: 'Cross-Origin-Opener-Policy', + CrossOriginResourcePolicy: 'Cross-Origin-Resource-Policy', + Date: 'Date', Digest: 'Digest', ETag: 'ETag', + Expect: 'Expect', + Expires: 'Expires', + Forwarded: 'Forwarded', + From: 'From', + Host: 'Host', + IfMatch: 'If-Match', IfModifiedSince: 'If-Modified-Since', IfNoneMatch: 'If-None-Match', + IfUnmodifiedSince: 'If-Unmodified-Since', + IntegrityPolicy: 'Integrity-Policy', + IntegrityPolicyReportOnly: 'Integrity-Policy-Report-Only', + KeepAlive: 'Keep-Alive', LastModified: 'Last-Modified', + Link: 'Link', Location: 'Location', + MaxForwards: 'Max-Forwards', + Origin: 'Origin', + OriginAgentCluster: 'Origin-Agent-Cluster', + Prefer: 'Prefer', + PreferenceApplied: 'Preference-Applied', + Priority: 'Priority', + ProxyAuthenticate: 'Proxy-Authenticate', + ProxyAuthorization: 'Proxy-Authorization', + Range: 'Range', + Referer: 'Referer', + ReferrerPolicy: 'Referrer-Policy', + Refresh: 'Refresh', + ReportingEndpoints: 'Reporting-Endpoints', ReprDigest: 'Repr-Digest', + RetryAfter: 'Retry-After', RequestId: 'Request-ID', + SecFetchDest: 'Sec-Fetch-Dest', + SecFetchMode: 'Sec-Fetch-Mode', + SecFetchSite: 'Sec-Fetch-Site', + SecFetchUser: 'Sec-Fetch-User', + SecPurpose: 'Sec-Purpose', + Server: 'Server', + ServerTiming: 'Server-Timing', + ServiceWorker: 'Service-Worker', + ServiceWorkerAllowed: 'Service-Worker-Allowed', SetCookie: 'Set-Cookie', + SetLogin: 'Set-Login', + SourceMap: 'SourceMap', + TE: 'TE', + TimingAllowOrigin: 'Timing-Allow-Origin', + Trailer: 'Trailer', + TransferEncoding: 'Transfer-Encoding', + Upgrade: 'Upgrade', + UpgradeInsecureRequests: 'Upgrade-Insecure-Requests', + UserAgent: 'User-Agent', Vary: 'Vary', + Via: 'Via', WantContentDigest: 'Want-Content-Digest', WantDigest: 'Want-Digest', WantReprDigest: 'Want-Repr-Digest', + WWWAuthenticate: 'WWW-Authenticate', + XContentTypeOptions: 'X-Content-Type-Options', XCorrelationId: 'X-Correlation-ID', + XFrameOptions: 'X-Frame-Options', XForwardedFor: 'X-Forwarded-For', XForwardedProto: 'X-Forwarded-Proto', XRealIP: 'X-Real-IP', XRequestId: 'X-Request-ID', }; +/** + * Error if referencing an undefined header. + */ +const HeaderProxy = new Proxy(Header, { + get: (target, property) => { + if (property in target) { + return target[property]; // eslint-disable-line security/detect-object-injection + } else { + throw new RangeError(`undefined header '${property}'`); + } + }, +}); + module.exports = { ContentType, DigestAlgorithm, EncodingType, EncodingTypeSuffix, ErrorResponse: ErrorResponseProxy, - Header, + Header: HeaderProxy, HTTPStatusCode, HTTPStatusMessage, }; diff --git a/test/lib/enum.js b/test/lib/enum.js index ee702c6..58a4ef7 100644 --- a/test/lib/enum.js +++ b/test/lib/enum.js @@ -2,7 +2,7 @@ const assert = require('node:assert'); const Enum = require('../../lib/enum'); -const { mergeEnum } = require('../../lib/common'); +const { mergeEnum, mergeDeep } = require('../../lib/common'); describe('Enum', function () { @@ -40,4 +40,61 @@ describe('Enum', function () { }); }); // ErrorResponse + describe('Header', function () { + it('covers broken', function () { + assert.throws(() => Enum.Header.XNotAHeader, RangeError); + }); + it('covers success', function () { + const result = Enum.Header.Host; + const expected = 'Host'; + assert.deepStrictEqual(result, expected); + }); + it('can be merged', function () { + const XSqueep = 'X-Squeep'; + const localEnum = mergeEnum(Enum.Header, { XSqueep }); + const newResult = localEnum.XSqueep; + assert.strictEqual(newResult, 'X-Squeep'); + const oldResult = localEnum.Host; + assert.strictEqual(oldResult, 'Host'); + assert.throws(() => localEnum.XNotAHeader, RangeError); + }); + }); // Header + + describe('Sanity', function () { + it('sanity for unexpected usage', function () { + const localEnum = mergeDeep(Enum, { + ContentType: { + ApplicationSqueep: 'application/squeep', + }, + Header: { + XSqueep: 'X-Squeep', + }, + }); + assert.strictEqual(localEnum.EncodingType.Identity, 'identity'); + assert.strictEqual(localEnum.ContentType.TextPlain, 'text/plain'); + assert.strictEqual(localEnum.ContentType.ApplicationSqueep, 'application/squeep'); + assert.strictEqual(localEnum.Header.Host, 'Host'); + assert.strictEqual(localEnum.Header.XSqueep, 'X-Squeep'); + + assert.strictEqual(localEnum.Header.XNotAHeader, undefined); + // assert.throws(() => localEnum.Header.XNotAHeader, RangeError); // This returns undefined with deep merge. + }); + it('sanity', function () { + const localEnum = mergeEnum(Enum, { + ContentType: { + ApplicationSqueep: 'application/squeep', + }, + Header: { + XSqueep: 'X-Squeep', + }, + }); + assert.strictEqual(localEnum.EncodingType.Identity, 'identity'); + assert.strictEqual(localEnum.ContentType.TextPlain, 'text/plain'); + assert.strictEqual(localEnum.ContentType.ApplicationSqueep, 'application/squeep'); + assert.strictEqual(localEnum.Header.Host, 'Host'); + assert.strictEqual(localEnum.Header.XSqueep, 'X-Squeep'); + assert.throws(() => localEnum.Header.XNotAHeader, RangeError); + }); + }); // sanity + }); // Enum