diff --git a/config/http/notifications/streaming-http/http.json b/config/http/notifications/streaming-http/http.json index 264d5f042..4e8afb087 100644 --- a/config/http/notifications/streaming-http/http.json +++ b/config/http/notifications/streaming-http/http.json @@ -32,6 +32,7 @@ "@id": "urn:solid-server:default:StreamingHttp2023RequestHandler", "@type": "StreamingHttpRequestHandler", "streamMap": { "@id": "urn:solid-server:default:StreamingHttpMap" }, + "baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" }, "pathPrefix": { "@id": "urn:solid-server:default:variable:streamingHTTPReceiveFromPrefix" }, "generator": { "@id": "urn:solid-server:default:BaseNotificationGenerator" }, "serializer": { "@id": "urn:solid-server:default:BaseNotificationSerializer" }, diff --git a/src/server/notifications/StreamingHttpChannel2023/StreamingHttpMetadataWriter.ts b/src/server/notifications/StreamingHttpChannel2023/StreamingHttpMetadataWriter.ts index b345853dd..c3365f6ef 100644 --- a/src/server/notifications/StreamingHttpChannel2023/StreamingHttpMetadataWriter.ts +++ b/src/server/notifications/StreamingHttpChannel2023/StreamingHttpMetadataWriter.ts @@ -19,8 +19,8 @@ export class StreamingHttpMetadataWriter extends MetadataWriter { } public async handle(input: { response: HttpResponse; metadata: RepresentationMetadata }): Promise { - const resourcePath = input.metadata.identifier.value.replace(this.baseUrl, ''); - const receiveFrom = `${this.baseUrl}${this.pathPrefix}${resourcePath}`; + const encodedUrl = encodeURIComponent(input.metadata.identifier.value); + const receiveFrom = `${this.baseUrl}${this.pathPrefix}${encodedUrl}`; const link = `<${receiveFrom}>; rel="http://www.w3.org/ns/solid/terms#updatesViaStreamingHttp2023"`; this.logger.debug('Adding updatesViaStreamingHttp2023 to the Link header'); addHeader(input.response, 'Link', link); diff --git a/src/server/notifications/StreamingHttpChannel2023/StreamingHttpRequestHandler.ts b/src/server/notifications/StreamingHttpChannel2023/StreamingHttpRequestHandler.ts index 6d060e5ea..20e00bc21 100644 --- a/src/server/notifications/StreamingHttpChannel2023/StreamingHttpRequestHandler.ts +++ b/src/server/notifications/StreamingHttpChannel2023/StreamingHttpRequestHandler.ts @@ -28,6 +28,7 @@ export class StreamingHttpRequestHandler extends OperationHttpHandler { public constructor( private readonly streamMap: StreamingHttpMap, + private readonly baseUrl: string, private readonly pathPrefix: string, private readonly generator: NotificationGenerator, private readonly serializer: NotificationSerializer, @@ -39,7 +40,7 @@ export class StreamingHttpRequestHandler extends OperationHttpHandler { } public async handle({ operation, request }: OperationHttpHandlerInput): Promise { - const topic = operation.target.path.replace(this.pathPrefix, ''); + const topic = decodeURIComponent(operation.target.path.replace(this.baseUrl + this.pathPrefix, '')); // Verify if the client is allowed to connect const credentials = await this.credentialsExtractor.handleSafe(request); diff --git a/test/integration/StreamingHttpChannel2023.test.ts b/test/integration/StreamingHttpChannel2023.test.ts index 4368070b4..e2c69828a 100644 --- a/test/integration/StreamingHttpChannel2023.test.ts +++ b/test/integration/StreamingHttpChannel2023.test.ts @@ -17,6 +17,7 @@ import namedNode = DataFactory.namedNode; const port = getPort('StreamingHTTPChannel2023'); const baseUrl = `http://localhost:${port}/`; +const pathPrefix = '.notifications/StreamingHTTPChannel2023'; const rootFilePath = getTestFolder('StreamingHTTPChannel2023'); const stores: [string, any][] = [ @@ -38,13 +39,16 @@ async function readChunk(reader: ReadableStreamDefaultReader): Promise { return new Store(parser.parse(notification)); } +function endpoint(topic: string): string { + return joinUrl(baseUrl, pathPrefix, encodeURIComponent(topic)); +} + describe.each(stores)('A server supporting StreamingHTTPChannel2023 using %s', (name, { configs, teardown }): void => { let app: App; let store: ResourceStore; const webId = 'http://example.com/card/#me'; const topic = joinUrl(baseUrl, '/foo'); - const pathPrefix = '.notifications/StreamingHTTPChannel2023'; - const receiveFrom = joinUrl(baseUrl, pathPrefix, '/foo'); + const receiveFrom = endpoint(topic); beforeAll(async(): Promise => { const variables = { @@ -246,7 +250,7 @@ describe.each(stores)('A server supporting StreamingHTTPChannel2023 using %s', ( it('prevents connecting to channels of restricted topics.', async(): Promise => { const restricted = joinUrl(baseUrl, '/restricted'); - const restrictedReceiveFrom = joinUrl(baseUrl, pathPrefix, '/restricted'); + const restrictedReceiveFrom = endpoint(restricted); await store.setRepresentation({ path: restricted }, new BasicRepresentation('new', 'text/plain')); // Only allow our WebID to read @@ -285,7 +289,7 @@ describe.each(stores)('A server supporting StreamingHTTPChannel2023 using %s', ( it('emits container notifications if contents get added or removed.', async(): Promise => { const resource = joinUrl(baseUrl, '/resource'); - const baseReceiveFrom = joinUrl(baseUrl, pathPrefix, '/'); + const baseReceiveFrom = endpoint(joinUrl(baseUrl, '/')); // Connecting to the base URL, which is the parent container const streamingResponse = await fetch(baseReceiveFrom); diff --git a/test/unit/server/notifications/StreamingHttpChannel2023/StreamingHttpMetadataWriter.test.ts b/test/unit/server/notifications/StreamingHttpChannel2023/StreamingHttpMetadataWriter.test.ts index 7b2110895..20ada8132 100644 --- a/test/unit/server/notifications/StreamingHttpChannel2023/StreamingHttpMetadataWriter.test.ts +++ b/test/unit/server/notifications/StreamingHttpChannel2023/StreamingHttpMetadataWriter.test.ts @@ -4,6 +4,7 @@ import { } from '../../../../../src/server/notifications/StreamingHttpChannel2023/StreamingHttpMetadataWriter'; import { RepresentationMetadata } from '../../../../../src/http/representation/RepresentationMetadata'; import type { HttpResponse } from '../../../../../src/server/HttpResponse'; +import type { ResourceIdentifier } from '../../../../../src/http/representation/ResourceIdentifier'; describe('A StreamingHttpMetadataWriter', (): void => { const baseUrl = 'http://example.org/'; @@ -12,9 +13,10 @@ describe('A StreamingHttpMetadataWriter', (): void => { const rel = 'http://www.w3.org/ns/solid/terms#updatesViaStreamingHttp2023'; it('adds the correct link header.', async(): Promise => { + const topic: ResourceIdentifier = { path: 'http://example.com/foo' }; const response = createResponse() as HttpResponse; - const metadata = new RepresentationMetadata({ path: 'http://example.org/foo/bar/baz' }); + const metadata = new RepresentationMetadata(topic); await expect(writer.handle({ response, metadata })).resolves.toBeUndefined(); - expect(response.getHeaders()).toEqual({ link: `; rel="${rel}"` }); + expect(response.getHeaders()).toEqual({ link: `; rel="${rel}"` }); }); }); diff --git a/test/unit/server/notifications/StreamingHttpChannel2023/StreamingHttpRequestHandler.test.ts b/test/unit/server/notifications/StreamingHttpChannel2023/StreamingHttpRequestHandler.test.ts index 756297008..79fcd3ee8 100644 --- a/test/unit/server/notifications/StreamingHttpChannel2023/StreamingHttpRequestHandler.test.ts +++ b/test/unit/server/notifications/StreamingHttpChannel2023/StreamingHttpRequestHandler.test.ts @@ -31,6 +31,7 @@ jest.mock('../../../../../src/logging/LogUtil', (): any => { describe('A StreamingHttpRequestHandler', (): void => { const logger: jest.Mocked = getLoggerFor('mock') as any; const topic: ResourceIdentifier = { path: 'http://example.com/foo' }; + const baseUrl = 'http://example.com/'; const pathPrefix = '.notifications/StreamingHTTPChannel2023/'; const channel: NotificationChannel = { id: 'id', @@ -64,7 +65,7 @@ describe('A StreamingHttpRequestHandler', (): void => { beforeEach(async(): Promise => { operation = { method: 'GET', - target: { path: 'http://example.com/.notifications/StreamingHTTPChannel2023/foo' }, + target: { path: `http://example.com/.notifications/StreamingHTTPChannel2023/${encodeURIComponent(topic.path)}` }, body: new BasicRepresentation(), preferences: {}, }; @@ -95,6 +96,7 @@ describe('A StreamingHttpRequestHandler', (): void => { handler = new StreamingHttpRequestHandler( streamMap, + baseUrl, pathPrefix, generator, serializer, @@ -151,6 +153,7 @@ describe('A StreamingHttpRequestHandler', (): void => { } as any; handler = new StreamingHttpRequestHandler( streamMap, + baseUrl, pathPrefix, generator, serializer,