From 785ec1ee07504e18acdd8ab4996342b6b9903af4 Mon Sep 17 00:00:00 2001 From: Joachim Van Herwegen Date: Thu, 3 Sep 2020 10:46:26 +0200 Subject: [PATCH] fix: Don't buffer data before sending response with InMemoryResourceStore --- src/storage/InMemoryResourceStore.ts | 17 ++++++++++++----- test/unit/storage/InMemoryResourceStore.test.ts | 6 +++--- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/storage/InMemoryResourceStore.ts b/src/storage/InMemoryResourceStore.ts index f2cfb8d28..46e7bb007 100644 --- a/src/storage/InMemoryResourceStore.ts +++ b/src/storage/InMemoryResourceStore.ts @@ -1,3 +1,4 @@ +import { PassThrough } from 'stream'; import arrayifyStream from 'arrayify-stream'; import streamifyArray from 'streamify-array'; import { RuntimeConfig } from '../init/RuntimeConfig'; @@ -113,7 +114,7 @@ export class InMemoryResourceStore implements ResourceStore { /** * Checks if the relative path is in the store. - * @param identifier - Incoming identifier. + * @param path - Incoming identifier. * * @throws {@link NotFoundHttpError} * If the path is not in the store. @@ -127,7 +128,7 @@ export class InMemoryResourceStore implements ResourceStore { /** * Copies the Representation by draining the original data stream and creating a new one. * - * @param data - Incoming Representation. + * @param source - Incoming Representation. */ private async copyRepresentation(source: Representation): Promise { const arr = await arrayifyStream(source.data); @@ -147,13 +148,19 @@ export class InMemoryResourceStore implements ResourceStore { * @returns The resulting Representation. */ private async generateRepresentation(path: string): Promise { + // Note: when converting to a complete ResourceStore and using readable-stream + // object mode should be set correctly here (now fixed due to Node 10) const source = this.store[path]; - const arr = await arrayifyStream(source.data); - source.data = streamifyArray([ ...arr ]); + const streamInternal = new PassThrough({ writableObjectMode: true, readableObjectMode: true }); + const streamOutput = new PassThrough({ writableObjectMode: true, readableObjectMode: true }); + source.data.pipe(streamInternal); + source.data.pipe(streamOutput); + + source.data = streamInternal; return { binary: source.binary, - data: streamifyArray([ ...arr ]), + data: streamOutput, metadata: source.metadata, }; } diff --git a/test/unit/storage/InMemoryResourceStore.test.ts b/test/unit/storage/InMemoryResourceStore.test.ts index 8e8d26e30..dd5b79044 100644 --- a/test/unit/storage/InMemoryResourceStore.test.ts +++ b/test/unit/storage/InMemoryResourceStore.test.ts @@ -1,11 +1,11 @@ import { Readable } from 'stream'; -import arrayifyStream from 'arrayify-stream'; import streamifyArray from 'streamify-array'; import { RuntimeConfig } from '../../../src/init/RuntimeConfig'; import { Representation } from '../../../src/ldp/representation/Representation'; import { RepresentationMetadata } from '../../../src/ldp/representation/RepresentationMetadata'; import { InMemoryResourceStore } from '../../../src/storage/InMemoryResourceStore'; import { NotFoundHttpError } from '../../../src/util/errors/NotFoundHttpError'; +import { readableToString } from '../../../src/util/Util'; const base = 'http://test.com/'; @@ -46,7 +46,7 @@ describe('A InMemoryResourceStore', (): void => { data: expect.any(Readable), metadata: representation.metadata, }); - await expect(arrayifyStream(result.data)).resolves.toEqual([ dataString ]); + await expect(readableToString(result.data)).resolves.toEqual(dataString); }); it('can add resources to previously added resources.', async(): Promise => { @@ -64,7 +64,7 @@ describe('A InMemoryResourceStore', (): void => { data: expect.any(Readable), metadata: representation.metadata, }); - await expect(arrayifyStream(result.data)).resolves.toEqual([ dataString ]); + await expect(readableToString(result.data)).resolves.toEqual(dataString); }); it('can delete data.', async(): Promise => {