Repository: solid/community-server (ts)

Issue:
Index.html update breaks acl link header
Since #806 the acl link for a container is now going to point to `/index.html.acl` instead of `/.acl` (discovered by integration test when adding a default index.html for the root container).

Pull request:
fix: Keep container metadata when returning index.html representation
Closes #822 

Patch:
diff --git a/src/storage/IndexRepresentationStore.ts b/src/storage/IndexRepresentationStore.ts
index 928f72e95..c07eebb90 100644
--- a/src/storage/IndexRepresentationStore.ts
+++ b/src/storage/IndexRepresentationStore.ts
@@ -41,7 +41,19 @@ export class IndexRepresentationStore extends PassthroughStore {
     if (isContainerIdentifier(identifier) && this.matchesPreferences(preferences)) {
       try {
         const indexIdentifier = { path: `${identifier.path}${this.indexName}` };
-        return await this.source.getRepresentation(indexIdentifier, preferences, conditions);
+        const index = await this.source.getRepresentation(indexIdentifier, preferences, conditions);
+        // We only care about the container metadata so preferences don't matter
+        const container = await this.source.getRepresentation(identifier, {}, conditions);
+        container.data.destroy();
+
+        // Uses the container metadata but with the index content-type.
+        // There is potential metadata loss if there is more representation-specific metadata,
+        // but that can be looked into once the issues above are resolved.
+        const { contentType } = index.metadata;
+        index.metadata = container.metadata;
+        index.metadata.contentType = contentType;
+
+        return index;
       } catch (error: unknown) {
         if (!NotFoundHttpError.isInstance(error)) {
           throw error;


Test patch:
diff --git a/test/unit/storage/IndexRepresentationstore.test.ts b/test/unit/storage/IndexRepresentationstore.test.ts
index 9c1d223d7..01b748225 100644
--- a/test/unit/storage/IndexRepresentationstore.test.ts
+++ b/test/unit/storage/IndexRepresentationstore.test.ts
@@ -16,10 +16,10 @@ describe('An IndexRepresentationStore', (): void => {
     source = {
       getRepresentation: jest.fn((identifier: ResourceIdentifier): any => {
         if (identifier.path === `${baseUrl}index.html`) {
-          return new BasicRepresentation('index data', 'text/html');
+          return new BasicRepresentation('index data', identifier, 'text/html');
         }
         if (identifier.path.endsWith('/')) {
-          return new BasicRepresentation('container data', 'text/turtle');
+          return new BasicRepresentation('container data', identifier, 'text/turtle');
         }
         throw new NotFoundHttpError();
       }),
@@ -36,7 +36,13 @@ describe('An IndexRepresentationStore', (): void => {
   it('retrieves the index resource if it exists.', async(): Promise<void> => {
     const result = await store.getRepresentation({ path: baseUrl }, {});
     await expect(readableToString(result.data)).resolves.toBe('index data');
-    expect(source.getRepresentation).toHaveBeenCalledTimes(1);
+    expect(source.getRepresentation).toHaveBeenCalledTimes(2);
+    expect(source.getRepresentation).toHaveBeenCalledWith({ path: `${baseUrl}index.html` }, {}, undefined);
+    expect(source.getRepresentation).toHaveBeenLastCalledWith({ path: baseUrl }, {}, undefined);
+
+    // Use correct metadata
+    expect(result.metadata.identifier.value).toBe(baseUrl);
+    expect(result.metadata.contentType).toBe('text/html');
   });
 
   it('errors if a non-404 error was thrown when accessing the index resource.', async(): Promise<void> => {
@@ -69,7 +75,12 @@ describe('An IndexRepresentationStore', (): void => {
     const preferences = { type: { 'text/turtle': 0.8, 'text/html': 0.5 }};
     const result = await store.getRepresentation({ path: baseUrl }, preferences);
     await expect(readableToString(result.data)).resolves.toBe('index data');
-    expect(source.getRepresentation).toHaveBeenCalledTimes(1);
-    expect(source.getRepresentation).toHaveBeenLastCalledWith({ path: `${baseUrl}base.html` }, preferences, undefined);
+    expect(source.getRepresentation).toHaveBeenCalledTimes(2);
+    expect(source.getRepresentation).toHaveBeenCalledWith({ path: `${baseUrl}base.html` }, preferences, undefined);
+    expect(source.getRepresentation).toHaveBeenLastCalledWith({ path: baseUrl }, {}, undefined);
+
+    // Use correct metadata
+    expect(result.metadata.identifier.value).toBe(baseUrl);
+    expect(result.metadata.contentType).toBe('text/html');
   });
 });