mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat: Create router rule based on matching the base URL
This commit is contained in:
parent
b160121176
commit
b78599182c
@ -190,6 +190,7 @@ export * from './storage/patch/PatchHandler';
|
|||||||
export * from './storage/patch/SparqlUpdatePatchHandler';
|
export * from './storage/patch/SparqlUpdatePatchHandler';
|
||||||
|
|
||||||
// Storage/Routing
|
// Storage/Routing
|
||||||
|
export * from './storage/routing/BaseUrlRouterRule';
|
||||||
export * from './storage/routing/ConvertingRouterRule';
|
export * from './storage/routing/ConvertingRouterRule';
|
||||||
export * from './storage/routing/PreferenceSupport';
|
export * from './storage/routing/PreferenceSupport';
|
||||||
export * from './storage/routing/RegexRouterRule';
|
export * from './storage/routing/RegexRouterRule';
|
||||||
|
48
src/storage/routing/BaseUrlRouterRule.ts
Normal file
48
src/storage/routing/BaseUrlRouterRule.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import type { ResourceIdentifier } from '../../ldp/representation/ResourceIdentifier';
|
||||||
|
import { NotFoundHttpError } from '../../util/errors/NotFoundHttpError';
|
||||||
|
import type { KeyValueStorage } from '../keyvalue/KeyValueStorage';
|
||||||
|
import type { ResourceStore } from '../ResourceStore';
|
||||||
|
import { RouterRule } from './RouterRule';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Routes requests based on their base url.
|
||||||
|
* Checks if any of the stored base URLs match the request identifier.
|
||||||
|
* If there are no matches the base store will be returned if one was configured.
|
||||||
|
*
|
||||||
|
* Part of the dynamic pod creation.
|
||||||
|
* Uses the identifiers that were added to the routing storage.
|
||||||
|
* @see {@link TemplatedPodGenerator}, {@link ConfigPodInitializer}, {@link ConfigPodManager}
|
||||||
|
*/
|
||||||
|
export class BaseUrlRouterRule extends RouterRule {
|
||||||
|
private readonly baseStore?: ResourceStore;
|
||||||
|
private readonly stores: KeyValueStorage<ResourceIdentifier, ResourceStore>;
|
||||||
|
|
||||||
|
public constructor(stores: KeyValueStorage<ResourceIdentifier, ResourceStore>, baseStore?: ResourceStore) {
|
||||||
|
super();
|
||||||
|
this.baseStore = baseStore;
|
||||||
|
this.stores = stores;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async handle({ identifier }: { identifier: ResourceIdentifier }): Promise<ResourceStore> {
|
||||||
|
try {
|
||||||
|
return await this.findStore(identifier);
|
||||||
|
} catch (error: unknown) {
|
||||||
|
if (this.baseStore) {
|
||||||
|
return this.baseStore;
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the store whose base url key is contained in the given identifier.
|
||||||
|
*/
|
||||||
|
private async findStore(identifier: ResourceIdentifier): Promise<ResourceStore> {
|
||||||
|
for await (const [ key, store ] of this.stores.entries()) {
|
||||||
|
if (identifier.path.startsWith(key.path)) {
|
||||||
|
return store;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new NotFoundHttpError();
|
||||||
|
}
|
||||||
|
}
|
39
test/unit/storage/routing/BaseUrlRouterRule.test.ts
Normal file
39
test/unit/storage/routing/BaseUrlRouterRule.test.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import type { ResourceIdentifier } from '../../../../src/ldp/representation/ResourceIdentifier';
|
||||||
|
import type { KeyValueStorage } from '../../../../src/storage/keyvalue/KeyValueStorage';
|
||||||
|
import type { ResourceStore } from '../../../../src/storage/ResourceStore';
|
||||||
|
import { BaseUrlRouterRule } from '../../../../src/storage/routing/BaseUrlRouterRule';
|
||||||
|
import { NotFoundHttpError } from '../../../../src/util/errors/NotFoundHttpError';
|
||||||
|
|
||||||
|
describe('A BaseUrlRouterRule', (): void => {
|
||||||
|
let stores: KeyValueStorage<ResourceIdentifier, ResourceStore>;
|
||||||
|
const baseStore = 'baseStore!' as any;
|
||||||
|
const aliceIdentifier = { path: 'http://alice.test.com/' };
|
||||||
|
const aliceStore = 'aliceStore!' as any;
|
||||||
|
let rule: BaseUrlRouterRule;
|
||||||
|
|
||||||
|
beforeEach(async(): Promise<void> => {
|
||||||
|
const map = new Map([[ aliceIdentifier.path, aliceStore ]]);
|
||||||
|
stores = {
|
||||||
|
* entries(): any {
|
||||||
|
for (const [ path, val ] of map.entries()) {
|
||||||
|
yield [{ path }, val ];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
rule = new BaseUrlRouterRule(stores, baseStore);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the matching store if the request contains the correct identifier.', async(): Promise<void> => {
|
||||||
|
await expect(rule.handle({ identifier: { path: 'http://alice.test.com/foo' }})).resolves.toEqual(aliceStore);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the base store if there is no matching identifier.', async(): Promise<void> => {
|
||||||
|
await expect(rule.handle({ identifier: { path: 'http://bob.test.com/foo' }})).resolves.toEqual(baseStore);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('errors if there is no match and no base store.', async(): Promise<void> => {
|
||||||
|
rule = new BaseUrlRouterRule(stores);
|
||||||
|
await expect(rule.handle({ identifier: { path: 'http://bob.test.com/foo' }})).rejects.toThrow(NotFoundHttpError);
|
||||||
|
});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user