diff --git a/config/presets/ldp/credentials-extractor.json b/config/presets/ldp/credentials-extractor.json index 339544a16..6d6b91f3f 100644 --- a/config/presets/ldp/credentials-extractor.json +++ b/config/presets/ldp/credentials-extractor.json @@ -3,8 +3,8 @@ "@graph": [ { "@id": "urn:solid-server:default:CredentialsExtractor", - "@type": "FirstCompositeHandler", - "FirstCompositeHandler:_handlers": [ + "@type": "WaterfallHandler", + "WaterfallHandler:_handlers": [ { "@type": "DPoPWebIdExtractor", "DPoPWebIdExtractor:_targetExtractor": { diff --git a/config/presets/ldp/operation-handler.json b/config/presets/ldp/operation-handler.json index cc9a9bc1d..2090c5a5c 100644 --- a/config/presets/ldp/operation-handler.json +++ b/config/presets/ldp/operation-handler.json @@ -3,8 +3,8 @@ "@graph": [ { "@id": "urn:solid-server:default:OperationHandler", - "@type": "FirstCompositeHandler", - "FirstCompositeHandler:_handlers": [ + "@type": "WaterfallHandler", + "WaterfallHandler:_handlers": [ { "@type": "DeleteOperationHandler", "DeleteOperationHandler:_store": { diff --git a/config/presets/ldp/permissions-extractor.json b/config/presets/ldp/permissions-extractor.json index 769f210b9..f0b40f39b 100644 --- a/config/presets/ldp/permissions-extractor.json +++ b/config/presets/ldp/permissions-extractor.json @@ -3,8 +3,8 @@ "@graph": [ { "@id": "urn:solid-server:default:PermissionsExtractor", - "@type": "FirstCompositeHandler", - "FirstCompositeHandler:_handlers": [ + "@type": "WaterfallHandler", + "WaterfallHandler:_handlers": [ { "@type": "MethodPermissionsExtractor" }, diff --git a/config/presets/ldp/request-parser.json b/config/presets/ldp/request-parser.json index f5c0658a1..f66c75884 100644 --- a/config/presets/ldp/request-parser.json +++ b/config/presets/ldp/request-parser.json @@ -14,8 +14,8 @@ "@id": "urn:solid-server:default:MetadataExtractor" }, "BasicRequestParser:_args_bodyParser": { - "@type": "FirstCompositeHandler", - "FirstCompositeHandler:_handlers": [ + "@type": "WaterfallHandler", + "WaterfallHandler:_handlers": [ { "@type": "SparqlUpdateBodyParser" }, diff --git a/config/presets/ldp/response-writer.json b/config/presets/ldp/response-writer.json index a92c1342a..fd0f7a3d3 100644 --- a/config/presets/ldp/response-writer.json +++ b/config/presets/ldp/response-writer.json @@ -31,8 +31,8 @@ }, { "@id": "urn:solid-server:default:ResponseWriter", - "@type": "FirstCompositeHandler", - "FirstCompositeHandler:_handlers": [ + "@type": "WaterfallHandler", + "WaterfallHandler:_handlers": [ { "@type": "ErrorResponseWriter" }, diff --git a/config/presets/representation-conversion.json b/config/presets/representation-conversion.json index d98607bf7..d47665371 100644 --- a/config/presets/representation-conversion.json +++ b/config/presets/representation-conversion.json @@ -26,8 +26,8 @@ { "@id": "urn:solid-server:default:RepresentationConverter", - "@type": "FirstCompositeHandler", - "FirstCompositeHandler:_handlers": [ + "@type": "WaterfallHandler", + "WaterfallHandler:_handlers": [ { "@id": "urn:solid-server:default:RdfToQuadConverter" }, diff --git a/src/index.ts b/src/index.ts index 0987f4d13..cdc5ff814 100644 --- a/src/index.ts +++ b/src/index.ts @@ -182,9 +182,9 @@ export * from './util/locking/WrappedExpiringResourceLocker'; // Util export * from './util/AsyncHandler'; -export * from './util/FirstCompositeHandler'; export * from './util/HeaderUtil'; export * from './util/PathUtil'; export * from './util/QuadUtil'; export * from './util/SequenceHandler'; export * from './util/StreamUtil'; +export * from './util/WaterfallHandler'; diff --git a/src/util/FirstCompositeHandler.ts b/src/util/WaterfallHandler.ts similarity index 92% rename from src/util/FirstCompositeHandler.ts rename to src/util/WaterfallHandler.ts index 4372650f6..cae5c5918 100644 --- a/src/util/FirstCompositeHandler.ts +++ b/src/util/WaterfallHandler.ts @@ -5,18 +5,18 @@ import { HttpError } from './errors/HttpError'; import { InternalServerError } from './errors/InternalServerError'; /** - * Handler that combines several other handlers, - * thereby allowing other classes that depend on a single handler to still use multiple. + * A composite handler that tries multiple handlers one by one + * until it finds a handler that supports the input. * The handlers will be checked in the order they appear in the input array, * allowing for more fine-grained handlers to check before catch-all handlers. */ -export class FirstCompositeHandler implements AsyncHandler { +export class WaterfallHandler implements AsyncHandler { protected readonly logger = getLoggerFor(this); private readonly handlers: AsyncHandler[]; /** - * Creates a new FirstCompositeHandler that stores the given handlers. + * Creates a new WaterfallHandler that stores the given handlers. * @param handlers - Handlers over which it will run. */ public constructor(handlers: AsyncHandler[]) { diff --git a/test/configs/AuthenticatedDataAccessorBasedConfig.ts b/test/configs/AuthenticatedDataAccessorBasedConfig.ts index b018f1875..1c4ccd92b 100644 --- a/test/configs/AuthenticatedDataAccessorBasedConfig.ts +++ b/test/configs/AuthenticatedDataAccessorBasedConfig.ts @@ -6,10 +6,10 @@ import type { import { AuthenticatedLdpHandler, EmptyCredentialsExtractor, - FirstCompositeHandler, MethodPermissionsExtractor, RdfToQuadConverter, QuadToRdfConverter, + WaterfallHandler, } from '../../src/index'; import type { ServerConfig } from './ServerConfig'; import { @@ -44,7 +44,7 @@ export class AuthenticatedDataAccessorBasedConfig implements ServerConfig { const requestParser = getBasicRequestParser(); const credentialsExtractor = new EmptyCredentialsExtractor(); - const permissionsExtractor = new FirstCompositeHandler([ + const permissionsExtractor = new WaterfallHandler([ new MethodPermissionsExtractor(), ]); diff --git a/test/configs/BasicHandlersConfig.ts b/test/configs/BasicHandlersConfig.ts index b2f7fc9fb..2412c4943 100644 --- a/test/configs/BasicHandlersConfig.ts +++ b/test/configs/BasicHandlersConfig.ts @@ -6,13 +6,13 @@ import { AllowEverythingAuthorizer, AuthenticatedLdpHandler, EmptyCredentialsExtractor, - FirstCompositeHandler, MethodPermissionsExtractor, QuadToRdfConverter, RawBodyParser, RdfToQuadConverter, SparqlUpdateBodyParser, SparqlPatchPermissionsExtractor, + WaterfallHandler, } from '../../src/index'; import type { ServerConfig } from './ServerConfig'; @@ -50,7 +50,7 @@ export class BasicHandlersConfig implements ServerConfig { ]); const credentialsExtractor = new EmptyCredentialsExtractor(); - const permissionsExtractor = new FirstCompositeHandler([ + const permissionsExtractor = new WaterfallHandler([ new MethodPermissionsExtractor(), new SparqlPatchPermissionsExtractor(), ]); diff --git a/test/configs/BasicHandlersWithAclConfig.ts b/test/configs/BasicHandlersWithAclConfig.ts index acaae9150..561f873f9 100644 --- a/test/configs/BasicHandlersWithAclConfig.ts +++ b/test/configs/BasicHandlersWithAclConfig.ts @@ -5,10 +5,10 @@ import type { import { AuthenticatedLdpHandler, EmptyCredentialsExtractor, - FirstCompositeHandler, MethodPermissionsExtractor, RdfToQuadConverter, QuadToRdfConverter, + WaterfallHandler, } from '../../src/index'; import type { ServerConfig } from './ServerConfig'; import { @@ -42,7 +42,7 @@ export class BasicHandlersWithAclConfig implements ServerConfig { const requestParser = getBasicRequestParser(); const credentialsExtractor = new EmptyCredentialsExtractor(); - const permissionsExtractor = new FirstCompositeHandler([ + const permissionsExtractor = new WaterfallHandler([ new MethodPermissionsExtractor(), ]); diff --git a/test/configs/DataAccessorBasedConfig.ts b/test/configs/DataAccessorBasedConfig.ts index c62bfbf62..fc421463a 100644 --- a/test/configs/DataAccessorBasedConfig.ts +++ b/test/configs/DataAccessorBasedConfig.ts @@ -7,11 +7,11 @@ import { AllowEverythingAuthorizer, AuthenticatedLdpHandler, EmptyCredentialsExtractor, - FirstCompositeHandler, MethodPermissionsExtractor, QuadToRdfConverter, RawBodyParser, RdfToQuadConverter, + WaterfallHandler, } from '../../src/index'; import type { ServerConfig } from './ServerConfig'; import { @@ -44,7 +44,7 @@ export class DataAccessorBasedConfig implements ServerConfig { const requestParser = getBasicRequestParser([ new RawBodyParser() ]); const credentialsExtractor = new EmptyCredentialsExtractor(); - const permissionsExtractor = new FirstCompositeHandler([ + const permissionsExtractor = new WaterfallHandler([ new MethodPermissionsExtractor(), ]); const authorizer = new AllowEverythingAuthorizer(); diff --git a/test/configs/Util.ts b/test/configs/Util.ts index b8720e3dc..99729cbe1 100644 --- a/test/configs/Util.ts +++ b/test/configs/Util.ts @@ -22,7 +22,6 @@ import { DataAccessorBasedStore, DeleteOperationHandler, ErrorResponseWriter, - FirstCompositeHandler, GetOperationHandler, HeadOperationHandler, InMemoryDataAccessor, @@ -40,6 +39,7 @@ import { SlugParser, SparqlUpdatePatchHandler, UrlBasedAclManager, + WaterfallHandler, WebAclAuthorizer, } from '../../src/index'; import { CONTENT_TYPE, HTTP, RDF } from '../../src/util/UriConstants'; @@ -82,8 +82,8 @@ export const getConvertingStore = (store: ResourceStore, converters: RepresentationConverter[], inType?: string): RepresentationConvertingStore => new RepresentationConvertingStore(store, { - inConverter: new FirstCompositeHandler(converters), - outConverter: new FirstCompositeHandler(converters), + inConverter: new WaterfallHandler(converters), + outConverter: new WaterfallHandler(converters), inType, }); @@ -114,7 +114,7 @@ export const getOperationHandler = (store: ResourceStore): OperationHandler => { new PatchOperationHandler(store), new DeleteOperationHandler(store), ]; - return new FirstCompositeHandler(handlers); + return new WaterfallHandler(handlers); }; export const getResponseWriter = (): ResponseWriter => { @@ -128,7 +128,7 @@ export const getResponseWriter = (): ResponseWriter => { }), ]); - return new FirstCompositeHandler<{ response: HttpResponse; result: ResponseDescription | Error }, void>([ + return new WaterfallHandler<{ response: HttpResponse; result: ResponseDescription | Error }, void>([ new ErrorResponseWriter(), new BasicResponseWriter(serializer), ]); @@ -157,7 +157,7 @@ export const getBasicRequestParser = (bodyParsers: BodyParser[] = []): BasicRequ // If no body parser is given (array is empty), default to RawBodyParser bodyParser = new RawBodyParser(); } else { - bodyParser = new FirstCompositeHandler(bodyParsers); + bodyParser = new WaterfallHandler(bodyParsers); } return new BasicRequestParser({ targetExtractor: new BasicTargetExtractor(), diff --git a/test/unit/util/FirstCompositeHandler.test.ts b/test/unit/util/WaterfallHandler.test.ts similarity index 80% rename from test/unit/util/FirstCompositeHandler.test.ts rename to test/unit/util/WaterfallHandler.test.ts index 87605fd2d..d86d4ff5e 100644 --- a/test/unit/util/FirstCompositeHandler.test.ts +++ b/test/unit/util/WaterfallHandler.test.ts @@ -1,19 +1,19 @@ import type { AsyncHandler } from '../../../src/util/AsyncHandler'; import { BadRequestHttpError } from '../../../src/util/errors/BadRequestHttpError'; import { HttpError } from '../../../src/util/errors/HttpError'; -import { FirstCompositeHandler } from '../../../src/util/FirstCompositeHandler'; +import { WaterfallHandler } from '../../../src/util/WaterfallHandler'; import { StaticAsyncHandler } from '../../util/StaticAsyncHandler'; -describe('A FirstCompositeHandler', (): void => { +describe('A WaterfallHandler', (): void => { describe('with no handlers', (): void => { it('can never handle data.', async(): Promise => { - const handler = new FirstCompositeHandler([]); + const handler = new WaterfallHandler([]); await expect(handler.canHandle(null)).rejects.toThrow(Error); }); it('errors if its handle function is called.', async(): Promise => { - const handler = new FirstCompositeHandler([]); + const handler = new WaterfallHandler([]); await expect(handler.handle(null)).rejects.toThrow(Error); }); @@ -36,13 +36,13 @@ describe('A FirstCompositeHandler', (): void => { }); it('can handle data if a handler supports it.', async(): Promise => { - const handler = new FirstCompositeHandler([ handlerFalse, handlerTrue ]); + const handler = new WaterfallHandler([ handlerFalse, handlerTrue ]); await expect(handler.canHandle(null)).resolves.toBeUndefined(); }); it('can not handle data if no handler supports it.', async(): Promise => { - const handler = new FirstCompositeHandler([ handlerFalse, handlerFalse ]); + const handler = new WaterfallHandler([ handlerFalse, handlerFalse ]); await expect(handler.canHandle(null)).rejects.toThrow('[Not supported, Not supported]'); }); @@ -51,13 +51,13 @@ describe('A FirstCompositeHandler', (): void => { handlerFalse.canHandle = async(): Promise => { throw 'apple'; }; - const handler = new FirstCompositeHandler([ handlerFalse, handlerFalse ]); + const handler = new WaterfallHandler([ handlerFalse, handlerFalse ]); await expect(handler.canHandle(null)).rejects.toThrow('[Unknown error, Unknown error]'); }); it('handles data if a handler supports it.', async(): Promise => { - const handler = new FirstCompositeHandler([ handlerFalse, handlerTrue ]); + const handler = new WaterfallHandler([ handlerFalse, handlerTrue ]); await expect(handler.handle('test')).resolves.toEqual('test'); expect(canHandleFn).toHaveBeenCalledTimes(1); @@ -65,13 +65,13 @@ describe('A FirstCompositeHandler', (): void => { }); it('errors if the handle function is called but no handler supports the data.', async(): Promise => { - const handler = new FirstCompositeHandler([ handlerFalse, handlerFalse ]); + const handler = new WaterfallHandler([ handlerFalse, handlerFalse ]); await expect(handler.handle('test')).rejects.toThrow('All handlers failed'); }); it('only calls the canHandle function once of its handlers when handleSafe is called.', async(): Promise => { - const handler = new FirstCompositeHandler([ handlerFalse, handlerTrue ]); + const handler = new WaterfallHandler([ handlerFalse, handlerTrue ]); await expect(handler.handleSafe('test')).resolves.toEqual('test'); expect(canHandleFn).toHaveBeenCalledTimes(1); @@ -79,7 +79,7 @@ describe('A FirstCompositeHandler', (): void => { }); it('throws the canHandle error when calling handleSafe if the data is not supported.', async(): Promise => { - const handler = new FirstCompositeHandler([ handlerFalse, handlerFalse ]); + const handler = new WaterfallHandler([ handlerFalse, handlerFalse ]); await expect(handler.handleSafe(null)).rejects.toThrow('[Not supported, Not supported]'); }); @@ -88,7 +88,7 @@ describe('A FirstCompositeHandler', (): void => { handlerTrue.canHandle = async(): Promise => { throw new HttpError(401, 'UnauthorizedHttpError'); }; - const handler = new FirstCompositeHandler([ handlerTrue, handlerTrue ]); + const handler = new WaterfallHandler([ handlerTrue, handlerTrue ]); await expect(handler.canHandle(null)).rejects.toMatchObject({ statusCode: 401, @@ -103,7 +103,7 @@ describe('A FirstCompositeHandler', (): void => { handlerFalse.canHandle = async(): Promise => { throw new Error('Server is crashing!'); }; - const handler = new FirstCompositeHandler([ handlerTrue, handlerFalse ]); + const handler = new WaterfallHandler([ handlerTrue, handlerFalse ]); await expect(handler.canHandle(null)).rejects.toMatchObject({ statusCode: 500, @@ -118,7 +118,7 @@ describe('A FirstCompositeHandler', (): void => { handlerFalse.canHandle = async(): Promise => { throw new HttpError(415, 'UnsupportedMediaTypeHttpError'); }; - const handler = new FirstCompositeHandler([ handlerTrue, handlerFalse ]); + const handler = new WaterfallHandler([ handlerTrue, handlerFalse ]); await expect(handler.canHandle(null)).rejects.toThrow(BadRequestHttpError); });