diff --git a/src/authentication/DPoPWebIdExtractor.ts b/src/authentication/DPoPWebIdExtractor.ts index ddf137c27..4ddf92cc7 100644 --- a/src/authentication/DPoPWebIdExtractor.ts +++ b/src/authentication/DPoPWebIdExtractor.ts @@ -34,7 +34,7 @@ export class DPoPWebIdExtractor extends CredentialsExtractor { if (!dpop) { throw new BadRequestHttpError('No DPoP header specified.'); } - const resource = await this.targetExtractor.handleSafe(request); + const resource = await this.targetExtractor.handleSafe({ request }); try { const { webid: webId } = await this.verify( diff --git a/src/ldp/http/AcceptPreferenceParser.ts b/src/ldp/http/AcceptPreferenceParser.ts index 66330ee01..bc915d9ff 100644 --- a/src/ldp/http/AcceptPreferenceParser.ts +++ b/src/ldp/http/AcceptPreferenceParser.ts @@ -27,7 +27,7 @@ const parsers: { * Supports Accept, Accept-Charset, Accept-Encoding, Accept-Language and Accept-DateTime. */ export class AcceptPreferenceParser extends PreferenceParser { - public async handle({ headers }: HttpRequest): Promise { + public async handle({ request: { headers }}: { request: HttpRequest }): Promise { const preferences: RepresentationPreferences = {}; for (const { name, header, parse } of parsers) { const value = headers[header]; diff --git a/src/ldp/http/BasicRequestParser.ts b/src/ldp/http/BasicRequestParser.ts index c16aaf474..0e2d5287e 100644 --- a/src/ldp/http/BasicRequestParser.ts +++ b/src/ldp/http/BasicRequestParser.ts @@ -36,9 +36,9 @@ export class BasicRequestParser extends RequestParser { if (!method) { throw new Error('No method specified on the HTTP request'); } - const target = await this.targetExtractor.handleSafe(request); - const preferences = await this.preferenceParser.handleSafe(request); - const metadata = await this.metadataExtractor.handleSafe(request); + const target = await this.targetExtractor.handleSafe({ request }); + const preferences = await this.preferenceParser.handleSafe({ request }); + const metadata = await this.metadataExtractor.handleSafe({ request }); const body = await this.bodyParser.handleSafe({ request, metadata }); return { method, target, preferences, body }; diff --git a/src/ldp/http/BasicTargetExtractor.ts b/src/ldp/http/BasicTargetExtractor.ts index ae9b55fba..17d400db7 100644 --- a/src/ldp/http/BasicTargetExtractor.ts +++ b/src/ldp/http/BasicTargetExtractor.ts @@ -11,7 +11,7 @@ import { TargetExtractor } from './TargetExtractor'; * TODO: input requires more extensive cleaning/parsing based on headers (see #22). */ export class BasicTargetExtractor extends TargetExtractor { - public async handle({ url, connection, headers }: HttpRequest): Promise { + public async handle({ request: { url, connection, headers }}: { request: HttpRequest }): Promise { if (!url) { throw new Error('Missing URL'); } diff --git a/src/ldp/http/PreferenceParser.ts b/src/ldp/http/PreferenceParser.ts index 73beaa7ba..d8e9c912a 100644 --- a/src/ldp/http/PreferenceParser.ts +++ b/src/ldp/http/PreferenceParser.ts @@ -5,4 +5,4 @@ import type { RepresentationPreferences } from '../representation/Representation /** * Creates {@link RepresentationPreferences} based on the incoming HTTP headers in a {@link HttpRequest}. */ -export abstract class PreferenceParser extends AsyncHandler {} +export abstract class PreferenceParser extends AsyncHandler<{ request: HttpRequest }, RepresentationPreferences> {} diff --git a/src/ldp/http/TargetExtractor.ts b/src/ldp/http/TargetExtractor.ts index 8af184257..d6d74b368 100644 --- a/src/ldp/http/TargetExtractor.ts +++ b/src/ldp/http/TargetExtractor.ts @@ -5,4 +5,4 @@ import type { ResourceIdentifier } from '../representation/ResourceIdentifier'; /** * Extracts a {@link ResourceIdentifier} from an incoming {@link HttpRequest}. */ -export abstract class TargetExtractor extends AsyncHandler {} +export abstract class TargetExtractor extends AsyncHandler<{ request: HttpRequest }, ResourceIdentifier> {} diff --git a/src/ldp/http/metadata/BasicMetadataExtractor.ts b/src/ldp/http/metadata/BasicMetadataExtractor.ts index dbd361731..7d8c473eb 100644 --- a/src/ldp/http/metadata/BasicMetadataExtractor.ts +++ b/src/ldp/http/metadata/BasicMetadataExtractor.ts @@ -14,7 +14,7 @@ export class BasicMetadataExtractor extends MetadataExtractor { this.parsers = parsers; } - public async handle(request: HttpRequest): + public async handle({ request }: { request: HttpRequest }): Promise { const metadata = new RepresentationMetadata(); for (const parser of this.parsers) { diff --git a/src/ldp/http/metadata/MetadataExtractor.ts b/src/ldp/http/metadata/MetadataExtractor.ts index 1251de244..076abd0b3 100644 --- a/src/ldp/http/metadata/MetadataExtractor.ts +++ b/src/ldp/http/metadata/MetadataExtractor.ts @@ -6,4 +6,4 @@ import type { RepresentationMetadata } from '../../representation/Representation * Parses the metadata of a {@link HttpRequest} into a {@link RepresentationMetadata}. */ export abstract class MetadataExtractor extends - AsyncHandler {} + AsyncHandler<{ request: HttpRequest }, RepresentationMetadata> {} diff --git a/test/unit/authentication/DPoPWebIdExtractor.test.ts b/test/unit/authentication/DPoPWebIdExtractor.test.ts index caae34a15..792cff334 100644 --- a/test/unit/authentication/DPoPWebIdExtractor.test.ts +++ b/test/unit/authentication/DPoPWebIdExtractor.test.ts @@ -74,7 +74,7 @@ describe('A DPoPWebIdExtractor', (): void => { it('calls the target extractor with the correct parameters.', async(): Promise => { await webIdExtractor.handleSafe(request); expect(targetExtractor.handle).toHaveBeenCalledTimes(1); - expect(targetExtractor.handle).toHaveBeenCalledWith(request); + expect(targetExtractor.handle).toHaveBeenCalledWith({ request }); }); it('calls the DPoP verifier with the correct parameters.', async(): Promise => { diff --git a/test/unit/ldp/http/AcceptPreferenceParser.test.ts b/test/unit/ldp/http/AcceptPreferenceParser.test.ts index d47068a73..d6551b444 100644 --- a/test/unit/ldp/http/AcceptPreferenceParser.test.ts +++ b/test/unit/ldp/http/AcceptPreferenceParser.test.ts @@ -3,41 +3,47 @@ import type { HttpRequest } from '../../../../src/server/HttpRequest'; describe('An AcceptPreferenceParser', (): void => { const preferenceParser = new AcceptPreferenceParser(); + let request: HttpRequest; + beforeEach(async(): Promise => { + request = { headers: {}} as HttpRequest; + }); it('can handle all input.', async(): Promise => { - await expect(preferenceParser.canHandle({} as HttpRequest)).resolves.toBeUndefined(); + await expect(preferenceParser.canHandle({ request })).resolves.toBeUndefined(); }); it('returns an empty result if there is no relevant input.', async(): Promise => { - await expect(preferenceParser.handle({ headers: {}} as HttpRequest)).resolves.toEqual({}); + await expect(preferenceParser.handle({ request })).resolves.toEqual({}); }); it('parses accept headers.', async(): Promise => { - await expect(preferenceParser.handle({ headers: { accept: 'audio/*; q=0.2, audio/basic' }} as HttpRequest)) + request.headers = { accept: 'audio/*; q=0.2, audio/basic' }; + await expect(preferenceParser.handle({ request })) .resolves.toEqual({ type: { 'audio/basic': 1, 'audio/*': 0.2 }}); }); it('parses accept-charset headers.', async(): Promise => { - await expect(preferenceParser.handle( - { headers: { 'accept-charset': 'iso-8859-5, unicode-1-1;q=0.8' }} as unknown as HttpRequest, - )).resolves.toEqual({ charset: { 'iso-8859-5': 1, 'unicode-1-1': 0.8 }}); + request.headers = { 'accept-charset': 'iso-8859-5, unicode-1-1;q=0.8' }; + await expect(preferenceParser.handle({ request })) + .resolves.toEqual({ charset: { 'iso-8859-5': 1, 'unicode-1-1': 0.8 }}); }); it('parses accept-datetime headers.', async(): Promise => { - await expect(preferenceParser.handle( - { headers: { 'accept-datetime': 'Tue, 20 Mar 2001 20:35:00 GMT' }} as unknown as HttpRequest, - // eslint-disable-next-line @typescript-eslint/naming-convention - )).resolves.toEqual({ datetime: { 'Tue, 20 Mar 2001 20:35:00 GMT': 1 }}); + request.headers = { 'accept-datetime': 'Tue, 20 Mar 2001 20:35:00 GMT' }; + await expect(preferenceParser.handle({ request })) + // eslint-disable-next-line @typescript-eslint/naming-convention + .resolves.toEqual({ datetime: { 'Tue, 20 Mar 2001 20:35:00 GMT': 1 }}); }); it('parses accept-encoding headers.', async(): Promise => { - await expect(preferenceParser.handle( - { headers: { 'accept-encoding': 'gzip;q=1.0, identity; q=0.5, *;q=0' }} as unknown as HttpRequest, - )).resolves.toEqual({ encoding: { gzip: 1, identity: 0.5, '*': 0 }}); + request.headers = { 'accept-encoding': 'gzip;q=1.0, identity; q=0.5, *;q=0' }; + await expect(preferenceParser.handle({ request })) + .resolves.toEqual({ encoding: { gzip: 1, identity: 0.5, '*': 0 }}); }); it('parses accept-language headers.', async(): Promise => { - await expect(preferenceParser.handle({ headers: { 'accept-language': 'da, en-gb;q=0.8, en;q=0.7' }} as HttpRequest)) + request.headers = { 'accept-language': 'da, en-gb;q=0.8, en;q=0.7' }; + await expect(preferenceParser.handle({ request })) .resolves.toEqual({ language: { da: 1, 'en-gb': 0.8, en: 0.7 }}); }); }); diff --git a/test/unit/ldp/http/BasicTargetExtractor.test.ts b/test/unit/ldp/http/BasicTargetExtractor.test.ts index 0520f4055..adc65e814 100644 --- a/test/unit/ldp/http/BasicTargetExtractor.test.ts +++ b/test/unit/ldp/http/BasicTargetExtractor.test.ts @@ -8,47 +8,48 @@ describe('A BasicTargetExtractor', (): void => { }); it('errors if there is no URL.', async(): Promise => { - await expect(extractor.handle({ headers: { host: 'test.com' }} as any)).rejects.toThrow('Missing URL'); + await expect(extractor.handle({ request: { headers: { host: 'test.com' }} as any })).rejects.toThrow('Missing URL'); }); it('errors if there is no host.', async(): Promise => { - await expect(extractor.handle({ url: 'url', headers: {}} as any)).rejects.toThrow('Missing Host header'); + await expect(extractor.handle({ request: { url: 'url', headers: {}} as any })) + .rejects.toThrow('Missing Host header'); }); it('errors if the host is invalid.', async(): Promise => { - await expect(extractor.handle({ url: 'url', headers: { host: 'test.com/forbidden' }} as any)) + await expect(extractor.handle({ request: { url: 'url', headers: { host: 'test.com/forbidden' }} as any })) .rejects.toThrow('The request has an invalid Host header: test.com/forbidden'); }); it('returns the input URL.', async(): Promise => { - await expect(extractor.handle({ url: 'url', headers: { host: 'test.com' }} as any)) + await expect(extractor.handle({ request: { url: 'url', headers: { host: 'test.com' }} as any })) .resolves.toEqual({ path: 'http://test.com/url' }); }); it('supports host:port combinations.', async(): Promise => { - await expect(extractor.handle({ url: 'url', headers: { host: 'localhost:3000' }} as any)) + await expect(extractor.handle({ request: { url: 'url', headers: { host: 'localhost:3000' }} as any })) .resolves.toEqual({ path: 'http://localhost:3000/url' }); }); it('uses https protocol if the connection is secure.', async(): Promise => { await expect(extractor.handle( - { url: 'url', headers: { host: 'test.com' }, connection: { encrypted: true } as any } as any, + { request: { url: 'url', headers: { host: 'test.com' }, connection: { encrypted: true } as any } as any }, )).resolves.toEqual({ path: 'https://test.com/url' }); }); it('encodes paths.', async(): Promise => { - await expect(extractor.handle({ url: '/a%20path%26/name', headers: { host: 'test.com' }} as any)) + await expect(extractor.handle({ request: { url: '/a%20path%26/name', headers: { host: 'test.com' }} as any })) .resolves.toEqual({ path: 'http://test.com/a%20path%26/name' }); - await expect(extractor.handle({ url: '/a path%26/name', headers: { host: 'test.com' }} as any)) + await expect(extractor.handle({ request: { url: '/a path%26/name', headers: { host: 'test.com' }} as any })) .resolves.toEqual({ path: 'http://test.com/a%20path%26/name' }); - await expect(extractor.handle({ url: '/path&%26/name', headers: { host: 'test.com' }} as any)) + await expect(extractor.handle({ request: { url: '/path&%26/name', headers: { host: 'test.com' }} as any })) .resolves.toEqual({ path: 'http://test.com/path%26%26/name' }); }); it('encodes hosts.', async(): Promise => { - await expect(extractor.handle({ url: '/', headers: { host: '點看' }} as any)) + await expect(extractor.handle({ request: { url: '/', headers: { host: '點看' }} as any })) .resolves.toEqual({ path: 'http://xn--c1yn36f/' }); }); @@ -57,7 +58,7 @@ describe('A BasicTargetExtractor', (): void => { host: 'test.com', forwarded: 'by=203.0.113.60', }; - await expect(extractor.handle({ url: '/foo/bar', headers } as any)) + await expect(extractor.handle({ request: { url: '/foo/bar', headers } as any })) .resolves.toEqual({ path: 'http://test.com/foo/bar' }); }); @@ -66,7 +67,7 @@ describe('A BasicTargetExtractor', (): void => { host: 'test.com', forwarded: 'proto=https;host=pod.example', }; - await expect(extractor.handle({ url: '/foo/bar', headers } as any)) + await expect(extractor.handle({ request: { url: '/foo/bar', headers } as any })) .resolves.toEqual({ path: 'https://pod.example/foo/bar' }); }); }); diff --git a/test/unit/ldp/http/metadata/BasicMetadataExtractor.test.ts b/test/unit/ldp/http/metadata/BasicMetadataExtractor.test.ts index 78b7d7480..c83b6fb01 100644 --- a/test/unit/ldp/http/metadata/BasicMetadataExtractor.test.ts +++ b/test/unit/ldp/http/metadata/BasicMetadataExtractor.test.ts @@ -32,7 +32,7 @@ describe('A BasicMetadataExtractor', (): void => { }); it('will add metadata from the parsers.', async(): Promise => { - const metadata = await handler.handle({ headers: { aa: 'valA', bb: 'valB' } as any } as HttpRequest); + const metadata = await handler.handle({ request: { headers: { aa: 'valA', bb: 'valB' } as any } as HttpRequest }); expect(metadata.getAll(RDF.type).map((term): any => term.value)).toEqual([ 'valA', 'valB' ]); }); });