fix: Do not reuse the same error in StaticThrowHandler

This commit is contained in:
Joachim Van Herwegen 2024-04-05 10:25:52 +02:00
parent 2846c711ab
commit f73dfb31c0
3 changed files with 32 additions and 6 deletions

View File

@ -1,11 +1,11 @@
import type { HttpError } from '../errors/HttpError'; import type { HttpError, HttpErrorClass } from '../errors/HttpError';
import { AsyncHandler } from './AsyncHandler'; import { AsyncHandler } from './AsyncHandler';
/** /**
* Utility handler that can handle all input and always throws the given error. * Utility handler that can handle all input and always throws an instance of the given error.
*/ */
export class StaticThrowHandler extends AsyncHandler<unknown, never> { export class StaticThrowHandler extends AsyncHandler<unknown, never> {
private readonly error: HttpError; protected readonly error: HttpError;
public constructor(error: HttpError) { public constructor(error: HttpError) {
super(); super();
@ -13,6 +13,8 @@ export class StaticThrowHandler extends AsyncHandler<unknown, never> {
} }
public async handle(): Promise<never> { public async handle(): Promise<never> {
throw this.error; // We are creating a new instance of the error instead of rethrowing the error,
// as reusing the same error can cause problem as the metadata is then also reused.
throw new (this.error.constructor as HttpErrorClass)();
} }
} }

View File

@ -506,7 +506,11 @@ describe.each(stores)('An LDP handler allowing all requests %s', (name, { storeC
}); });
it('returns 405 for unsupported methods.', async(): Promise<void> => { it('returns 405 for unsupported methods.', async(): Promise<void> => {
const response = await fetch(baseUrl, { method: 'TRACE' }); let response = await fetch(baseUrl, { method: 'TRACE' });
expect(response.status).toBe(405);
// Testing two different URLs as there used to be a problem with this
response = await fetch(joinUrl(baseUrl, 'foo'), { method: 'TRACE' });
expect(response.status).toBe(405); expect(response.status).toBe(405);
}); });

View File

@ -1,5 +1,6 @@
import { BadRequestHttpError } from '../../../../src/util/errors/BadRequestHttpError'; import { BadRequestHttpError } from '../../../../src/util/errors/BadRequestHttpError';
import { StaticThrowHandler } from '../../../../src/util/handlers/StaticThrowHandler'; import { StaticThrowHandler } from '../../../../src/util/handlers/StaticThrowHandler';
import { SOLID_ERROR } from '../../../../src/util/Vocabularies';
describe('A StaticThrowHandler', (): void => { describe('A StaticThrowHandler', (): void => {
const error = new BadRequestHttpError(); const error = new BadRequestHttpError();
@ -9,7 +10,26 @@ describe('A StaticThrowHandler', (): void => {
await expect(handler.canHandle({})).resolves.toBeUndefined(); await expect(handler.canHandle({})).resolves.toBeUndefined();
}); });
it('always throws the given error.', async(): Promise<void> => { it('always throws an instance of the given error.', async(): Promise<void> => {
await expect(handler.handle()).rejects.toThrow(error); await expect(handler.handle()).rejects.toThrow(error);
}); });
it('creates a new instance every time.', async(): Promise<void> => {
/* eslint-disable jest/no-conditional-expect */
try {
await handler.handle();
} catch (error: unknown) {
expect(BadRequestHttpError.isInstance(error)).toBe(true);
// Change the metadata
(error as BadRequestHttpError).metadata.add(SOLID_ERROR.terms.target, 'http://example.com/foo');
}
try {
await handler.handle();
} catch (error: unknown) {
expect(BadRequestHttpError.isInstance(error)).toBe(true);
// Metadata should not have the change
expect((error as BadRequestHttpError).metadata.has(SOLID_ERROR.terms.target)).toBe(false);
}
/* eslint-enable jest/no-conditional-expect */
});
}); });