mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat: Store original target in error metadata
This commit is contained in:
parent
486241f3d4
commit
419312ee5f
@ -7,6 +7,11 @@
|
||||
"@type": "SafeErrorHandler",
|
||||
"showStackTrace": { "@id": "urn:solid-server:default:variable:showStackTrace" },
|
||||
"errorHandler": {
|
||||
"@id": "urn:solid-server:default:TargetExtractorErrorHandler",
|
||||
"@type": "TargetExtractorErrorHandler",
|
||||
"targetExtractor": { "@id": "urn:solid-server:default:TargetExtractor" },
|
||||
"errorHandler": {
|
||||
"@id": "urn:solid-server:default:WaterfallErrorHandler",
|
||||
"@type": "WaterfallHandler",
|
||||
"handlers": [
|
||||
{
|
||||
@ -23,5 +28,6 @@
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
30
src/http/output/error/TargetExtractorErrorHandler.ts
Normal file
30
src/http/output/error/TargetExtractorErrorHandler.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { DataFactory } from 'n3';
|
||||
import { SOLID_ERROR } from '../../../util/Vocabularies';
|
||||
import type { TargetExtractor } from '../../input/identifier/TargetExtractor';
|
||||
import type { ResponseDescription } from '../response/ResponseDescription';
|
||||
import type { ErrorHandlerArgs } from './ErrorHandler';
|
||||
import { ErrorHandler } from './ErrorHandler';
|
||||
|
||||
/**
|
||||
* Adds metadata to an error to indicate what the identifier was of the resource originally being targeted.
|
||||
*/
|
||||
export class TargetExtractorErrorHandler extends ErrorHandler {
|
||||
protected readonly errorHandler: ErrorHandler;
|
||||
protected readonly targetExtractor: TargetExtractor;
|
||||
|
||||
public constructor(errorHandler: ErrorHandler, targetExtractor: TargetExtractor) {
|
||||
super();
|
||||
this.errorHandler = errorHandler;
|
||||
this.targetExtractor = targetExtractor;
|
||||
}
|
||||
|
||||
public async canHandle(input: ErrorHandlerArgs): Promise<void> {
|
||||
return this.errorHandler.canHandle(input);
|
||||
}
|
||||
|
||||
public async handle(input: ErrorHandlerArgs): Promise<ResponseDescription> {
|
||||
const target = await this.targetExtractor.handleSafe(input);
|
||||
input.error.metadata.add(SOLID_ERROR.terms.target, DataFactory.namedNode(target.path));
|
||||
return this.errorHandler.handle(input);
|
||||
}
|
||||
}
|
@ -100,6 +100,7 @@ export * from './http/output/error/ConvertingErrorHandler';
|
||||
export * from './http/output/error/ErrorHandler';
|
||||
export * from './http/output/error/RedirectingErrorHandler';
|
||||
export * from './http/output/error/SafeErrorHandler';
|
||||
export * from './http/output/error/TargetExtractorErrorHandler';
|
||||
|
||||
// HTTP/Output/Metadata
|
||||
export * from './http/output/metadata/AllowAcceptHeaderWriter';
|
||||
|
@ -283,6 +283,7 @@ export const SOLID_ERROR = createVocabulary(
|
||||
'errorCode',
|
||||
'errorResponse',
|
||||
'stack',
|
||||
'target',
|
||||
);
|
||||
|
||||
// Used to pass parameters to error templates
|
||||
|
@ -0,0 +1,47 @@
|
||||
import type { TargetExtractor } from '../../../../../src/http/input/identifier/TargetExtractor';
|
||||
import type { ErrorHandler, ErrorHandlerArgs } from '../../../../../src/http/output/error/ErrorHandler';
|
||||
import { TargetExtractorErrorHandler } from '../../../../../src/http/output/error/TargetExtractorErrorHandler';
|
||||
import type { ResourceIdentifier } from '../../../../../src/http/representation/ResourceIdentifier';
|
||||
import { NotFoundHttpError } from '../../../../../src/util/errors/NotFoundHttpError';
|
||||
import { SOLID_ERROR } from '../../../../../src/util/Vocabularies';
|
||||
|
||||
describe('A TargetExtractorErrorHandler', (): void => {
|
||||
const identifier: ResourceIdentifier = { path: 'http://example.com/foo' };
|
||||
let input: ErrorHandlerArgs;
|
||||
let source: jest.Mocked<ErrorHandler>;
|
||||
let targetExtractor: jest.Mocked<TargetExtractor>;
|
||||
let handler: TargetExtractorErrorHandler;
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
input = {
|
||||
request: 'request' as any,
|
||||
error: new NotFoundHttpError(),
|
||||
};
|
||||
|
||||
source = {
|
||||
canHandle: jest.fn(),
|
||||
handle: jest.fn().mockResolvedValue('response'),
|
||||
} satisfies Partial<ErrorHandler> as any;
|
||||
|
||||
targetExtractor = {
|
||||
handleSafe: jest.fn().mockResolvedValue(identifier),
|
||||
} satisfies Partial<TargetExtractor> as any;
|
||||
|
||||
handler = new TargetExtractorErrorHandler(source, targetExtractor);
|
||||
});
|
||||
|
||||
it('can handle input its source can handle.', async(): Promise<void> => {
|
||||
await expect(handler.canHandle(input)).resolves.toBeUndefined();
|
||||
expect(source.canHandle).toHaveBeenLastCalledWith(input);
|
||||
|
||||
const error = new Error('bad data');
|
||||
source.canHandle.mockRejectedValueOnce(error);
|
||||
await expect(handler.canHandle(input)).rejects.toThrow(error);
|
||||
});
|
||||
|
||||
it('adds the identifier as metadata.', async(): Promise<void> => {
|
||||
await expect(handler.handle(input)).resolves.toBe('response');
|
||||
expect(input.error.metadata.get(SOLID_ERROR.terms.target)?.value).toEqual(identifier.path);
|
||||
expect(targetExtractor.handleSafe).toHaveBeenLastCalledWith(input);
|
||||
});
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user