chore: replace RedirectAllHttpHandler with RedirectingHttpHandler

This commit is contained in:
Wouter Termont
2022-04-06 17:50:54 +02:00
parent 91ed72ef37
commit 5956385c41
4 changed files with 12 additions and 107 deletions

View File

@@ -4,11 +4,17 @@
{
"comment": "Redirects all request to the setup.",
"@id": "urn:solid-server:default:SetupRedirectHandler",
"@type": "RedirectAllHttpHandler",
"args_baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" },
"args_target": "/setup",
"args_targetExtractor": { "@id": "urn:solid-server:default:TargetExtractor" },
"args_responseWriter": { "@id": "urn:solid-server:default:ResponseWriter" }
},
"@type": "RedirectingHttpHandler",
"redirects": [
{
"RedirectingHttpHandler:_redirects_key": ".*",
"RedirectingHttpHandler:_redirects_value": "/setup-page-reachable-with-any-suffix"
}
],
"baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" },
"targetExtractor": { "@id": "urn:solid-server:default:TargetExtractor" },
"responseWriter": { "@id": "urn:solid-server:default:ResponseWriter" },
"statusCode": 302
}
]
}

View File

@@ -269,7 +269,6 @@ export * from './server/middleware/StaticAssetHandler';
export * from './server/middleware/WebSocketAdvertiser';
// Server/Util
export * from './server/util/RedirectAllHttpHandler';
export * from './server/util/RouterHandler';
// Storage/Accessors

View File

@@ -1,47 +0,0 @@
import type { TargetExtractor } from '../../http/input/identifier/TargetExtractor';
import { RedirectResponseDescription } from '../../http/output/response/RedirectResponseDescription';
import type { ResponseWriter } from '../../http/output/ResponseWriter';
import { FoundHttpError } from '../../util/errors/FoundHttpError';
import { NotImplementedHttpError } from '../../util/errors/NotImplementedHttpError';
import { getRelativeUrl, joinUrl } from '../../util/PathUtil';
import type { HttpHandlerInput } from '../HttpHandler';
import { HttpHandler } from '../HttpHandler';
export interface RedirectAllHttpHandlerArgs {
baseUrl: string;
target: string;
targetExtractor: TargetExtractor;
responseWriter: ResponseWriter;
}
/**
* Will redirect all incoming requests to the given target.
* In case the incoming request already has the correct target,
* the `canHandle` call will reject the input.
*/
export class RedirectAllHttpHandler extends HttpHandler {
private readonly baseUrl: string;
private readonly target: string;
private readonly targetExtractor: TargetExtractor;
private readonly responseWriter: ResponseWriter;
public constructor(args: RedirectAllHttpHandlerArgs) {
super();
this.baseUrl = args.baseUrl;
this.target = args.target;
this.targetExtractor = args.targetExtractor;
this.responseWriter = args.responseWriter;
}
public async canHandle({ request }: HttpHandlerInput): Promise<void> {
const target = await getRelativeUrl(this.baseUrl, request, this.targetExtractor);
if (target === this.target) {
throw new NotImplementedHttpError('Target is already correct.');
}
}
public async handle({ response }: HttpHandlerInput): Promise<void> {
const result = new RedirectResponseDescription(new FoundHttpError(joinUrl(this.baseUrl, this.target)));
await this.responseWriter.handleSafe({ response, result });
}
}

View File

@@ -1,53 +0,0 @@
import type { TargetExtractor } from '../../../../src/http/input/identifier/TargetExtractor';
import type { ResponseWriter } from '../../../../src/http/output/ResponseWriter';
import type { ResourceIdentifier } from '../../../../src/http/representation/ResourceIdentifier';
import type { HttpRequest } from '../../../../src/server/HttpRequest';
import type { HttpResponse } from '../../../../src/server/HttpResponse';
import { RedirectAllHttpHandler } from '../../../../src/server/util/RedirectAllHttpHandler';
import { NotImplementedHttpError } from '../../../../src/util/errors/NotImplementedHttpError';
import { joinUrl } from '../../../../src/util/PathUtil';
import { SOLID_HTTP } from '../../../../src/util/Vocabularies';
describe('A RedirectAllHttpHandler', (): void => {
const baseUrl = 'http://test.com/';
const target = '/foo';
const absoluteTarget = 'http://test.com/foo';
let request: HttpRequest;
const response: HttpResponse = {} as any;
let targetExtractor: jest.Mocked<TargetExtractor>;
let responseWriter: jest.Mocked<ResponseWriter>;
let handler: RedirectAllHttpHandler;
beforeEach(async(): Promise<void> => {
request = { url: '/foo' } as any;
targetExtractor = {
handleSafe: jest.fn(({ request: req }): ResourceIdentifier => ({ path: joinUrl(baseUrl, req.url!) })),
} as any;
responseWriter = { handleSafe: jest.fn() } as any;
handler = new RedirectAllHttpHandler({ baseUrl, target, targetExtractor, responseWriter });
});
it('rejects requests for the target.', async(): Promise<void> => {
request.url = target;
await expect(handler.canHandle({ request, response })).rejects.toThrow(NotImplementedHttpError);
});
it('accepts all other requests.', async(): Promise<void> => {
request.url = '/otherPath';
await expect(handler.canHandle({ request, response })).resolves.toBeUndefined();
});
it('writes out a redirect response.', async(): Promise<void> => {
await expect(handler.handle({ request, response })).resolves.toBeUndefined();
expect(responseWriter.handleSafe).toHaveBeenCalledTimes(1);
expect(responseWriter.handleSafe).toHaveBeenLastCalledWith({
response,
result: expect.objectContaining({ statusCode: 302 }),
});
const { metadata } = responseWriter.handleSafe.mock.calls[0][0].result;
expect(metadata?.get(SOLID_HTTP.terms.location)?.value).toBe(absoluteTarget);
});
});