Merge pull request #44 from o-development/fix/accept-header

Removed requirement to have link headers
main
jaxoncreed 1 year ago committed by GitHub
commit 14521fa0c4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 11
      packages/solid/src/requester/requests/checkRootContainer.ts
  2. 1
      packages/solid/src/requester/requests/readResource.ts
  3. 17
      packages/solid/src/requester/results/error/NoRootContainerError.ts
  4. 16
      packages/solid/src/resource/Container.ts
  5. 5
      packages/solid/src/resource/Leaf.ts
  6. 5
      packages/solid/src/resource/Resource.ts
  7. 33
      packages/solid/test/Integration.test.ts

@ -1,6 +1,5 @@
import type { BasicRequestOptions } from "./requestOptions";
import { parse as parseLinkHeader } from "http-link-header";
import { NoncompliantPodError } from "../results/error/NoncompliantPodError";
import type { CheckRootContainerSuccess } from "../results/success/CheckRootContainerSuccess";
import type {
HttpErrorResultType,
@ -21,7 +20,6 @@ export type CheckRootResult = CheckRootContainerSuccess | CheckRootResultError;
*/
export type CheckRootResultError =
| HttpErrorResultType
| NoncompliantPodError
| UnexpectedHttpError
| UnexpectedResourceError;
@ -37,10 +35,15 @@ export type CheckRootResultError =
export function checkHeadersForRootContainer(
uri: ContainerUri,
headers: Headers,
): CheckRootContainerSuccess | NoncompliantPodError {
): CheckRootContainerSuccess {
const linkHeader = headers.get("link");
if (!linkHeader) {
return new NoncompliantPodError(uri, "No link header present in request.");
return {
uri,
isRootContainer: false,
type: "checkRootContainerSuccess",
isError: false,
};
}
const parsedLinkHeader = parseLinkHeader(linkHeader);
const types = parsedLinkHeader.get("rel", "type");

@ -139,7 +139,6 @@ export async function readResource(
}
if (isContainerUri(uri)) {
const result = checkHeadersForRootContainer(uri, response.headers);
if (result.isError) return result;
return {
isError: false,
type: "containerReadSuccess",

@ -0,0 +1,17 @@
import { ResourceError } from "./ErrorResult";
/**
* A NoncompliantPodError is returned when the server responded in a way that is
* not compliant with the Solid specification.
*/
export class NoRootContainerError extends ResourceError {
readonly type = "noRootContainerError" as const;
/**
* @param uri - the URI of the requested resource
* @param message - a custom message for the error
*/
constructor(uri: string) {
super(uri, `${uri} has not root container.`);
}
}

@ -19,7 +19,6 @@ import type {
ReadResultError,
} from "../requester/requests/readResource";
import { AggregateError } from "../requester/results/error/ErrorResult";
import { NoncompliantPodError } from "../requester/results/error/NoncompliantPodError";
import type { DeleteSuccess } from "../requester/results/success/DeleteSuccess";
import type { AbsentReadSuccess } from "../requester/results/success/ReadSuccess";
import type { ContainerReadSuccess } from "../requester/results/success/ReadSuccess";
@ -31,6 +30,7 @@ import type { Leaf } from "./Leaf";
import type { SharedStatuses } from "./Resource";
import { Resource } from "./Resource";
import type { ResourceResult } from "./resourceResult/ResourceResult";
import { NoRootContainerError } from "../requester/results/error/NoRootContainerError";
/**
* Represents the current status of a specific container on a Pod as known by
@ -222,7 +222,8 @@ export class Container extends Resource {
/**
* Gets the root container of this container. If this container is the root
* container, this function returns itself.
* @returns The root container for this container
* @returns The root container for this container or undefined if there is no
* root container.
*
* @example
* Suppose the root container is at `https://example.com/`
@ -237,11 +238,13 @@ export class Container extends Resource {
* }
* ```
*/
async getRootContainer(): Promise<Container | CheckRootResultError> {
async getRootContainer(): Promise<
Container | CheckRootResultError | NoRootContainerError
> {
const parentContainerResult = await this.getParentContainer();
if (parentContainerResult?.isError) return parentContainerResult;
if (!parentContainerResult) {
return this;
return this.isRootContainer() ? this : new NoRootContainerError(this.uri);
}
return parentContainerResult.getRootContainer();
}
@ -277,10 +280,7 @@ export class Container extends Resource {
if (this.rootContainer) return undefined;
const parentUri = getParentUri(this.uri);
if (!parentUri) {
return new NoncompliantPodError(
this.uri,
`${this.uri} is not root does not have a parent container`,
);
return undefined;
}
return this.context.resourceStore.get(parentUri);
}

@ -23,6 +23,7 @@ import type { Container } from "./Container";
import type { SharedStatuses } from "./Resource";
import { Resource } from "./Resource";
import type { ResourceResult } from "./resourceResult/ResourceResult";
import type { NoRootContainerError } from "../requester/results/error/NoRootContainerError";
/**
* Represents the current status of a specific Leaf on a Pod as known by LDO.
@ -338,7 +339,9 @@ export class Leaf extends Resource {
* }
* ```
*/
async getRootContainer(): Promise<Container | CheckRootResultError> {
async getRootContainer(): Promise<
Container | CheckRootResultError | NoRootContainerError
> {
const parent = await this.getParentContainer();
return parent.getRootContainer();
}

@ -32,6 +32,7 @@ import { getWacRuleWithAclUri, type GetWacRuleResult } from "./wac/getWacRule";
import { NoncompliantPodError } from "../requester/results/error/NoncompliantPodError";
import { setWacRuleForAclUri, type SetWacRuleResult } from "./wac/setWacRule";
import type { LeafUri } from "../util/uriTypes";
import type { NoRootContainerError } from "../requester/results/error/NoRootContainerError";
/**
* Statuses shared between both Leaf and Container
@ -524,7 +525,9 @@ export abstract class Resource extends (EventEmitter as new () => TypedEmitter<{
* }
* ```
*/
abstract getRootContainer(): Promise<Container | CheckRootResultError>;
abstract getRootContainer(): Promise<
Container | CheckRootResultError | NoRootContainerError
>;
abstract getParentContainer(): Promise<
Container | CheckRootResultError | undefined

@ -417,7 +417,7 @@ describe("Integration", () => {
expect(result.message).toBe("Something happened.");
});
it("Returns an error if there is no link header for a container request", async () => {
it("Does not return an error if there is no link header for a container request", async () => {
fetchMock.mockResolvedValueOnce(
new Response(TEST_CONTAINER_TTL, {
status: 200,
@ -430,12 +430,9 @@ describe("Integration", () => {
isReading: true,
isDoingInitialFetch: true,
});
expect(result.isError).toBe(true);
if (!result.isError) return;
expect(result.type).toBe("noncompliantPodError");
expect(result.message).toMatch(
/\Response from .* is not compliant with the Solid Specification: No link header present in request\./,
);
expect(result.isError).toBe(false);
if (result.isError) return;
expect(result.resource.isRootContainer()).toBe(false);
});
it("knows nothing about a leaf resource if it is not fetched", () => {
@ -577,7 +574,19 @@ describe("Integration", () => {
expect(result.isRootContainer()).toBe(true);
});
it("Returns an error if there is no link header for a container request", async () => {
it("Returns an error if there is no root container", async () => {
fetchMock.mockResolvedValueOnce(
new Response(TEST_CONTAINER_TTL, {
status: 200,
headers: new Headers({ "content-type": "text/turtle" }),
}),
);
fetchMock.mockResolvedValueOnce(
new Response(TEST_CONTAINER_TTL, {
status: 200,
headers: new Headers({ "content-type": "text/turtle" }),
}),
);
fetchMock.mockResolvedValueOnce(
new Response(TEST_CONTAINER_TTL, {
status: 200,
@ -588,10 +597,8 @@ describe("Integration", () => {
const result = await resource.getRootContainer();
expect(result.isError).toBe(true);
if (!result.isError) return;
expect(result.type).toBe("noncompliantPodError");
expect(result.message).toMatch(
/\Response from .* is not compliant with the Solid Specification: No link header present in request\./,
);
expect(result.type).toBe("noRootContainerError");
expect(result.message).toMatch(/\.* has not root container\./);
});
it("An error to be returned if a common http error is encountered", async () => {
@ -629,7 +636,7 @@ describe("Integration", () => {
const resource = solidLdoDataset.getResource(ROOT_CONTAINER);
const result = await resource.getRootContainer();
expect(result.isError).toBe(true);
expect(result.type).toBe("noncompliantPodError");
expect(result.type).toBe("noRootContainerError");
});
});

Loading…
Cancel
Save