Skip to content

Commit

Permalink
fix(datasource/zarr) HEAD to get content length (#611)
Browse files Browse the repository at this point in the history
Use a HEAD request as fallback for http 206 status with no content-length.
  • Loading branch information
d-v-b authored Jul 23, 2024
1 parent 23218f9 commit 997afee
Showing 1 changed file with 38 additions and 26 deletions.
64 changes: 38 additions & 26 deletions src/kvstore/special/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,33 @@ class SpecialProtocolKvStore implements ReadableKvStore {
public credentialsProvider: SpecialProtocolCredentialsProvider,
public baseUrl: string,
) {}

async getObjectLength(url: string, options: ReadOptions) {
// Use a HEAD request to get the length of an object
const { cancellationToken = uncancelableToken } = options;
const headResponse = await cancellableFetchSpecialOk(
this.credentialsProvider,
url,
{ method: "HEAD" },
async (response) => response,
cancellationToken,
);

if (headResponse.status !== 200) {
throw new Error(
"Failed to determine total size in order to fetch suffix",
);
}
const contentLength = headResponse.headers.get("content-length");
if (contentLength === undefined) {
throw new Error(
"Failed to determine total size in order to fetch suffix",
);
}
const contentLengthNumber = Number(contentLength);
return contentLengthNumber;
}

async read(
key: string,
options: ReadOptions,
Expand Down Expand Up @@ -83,14 +110,17 @@ class SpecialProtocolKvStore implements ReadableKvStore {
if (contentRange === null) {
if (byteRangeRequest !== undefined) {
if ("suffixLength" in byteRangeRequest) {
throw new Error(
"Content-range header not provided with HTTP 206 response. Check server CORS configuration.",
);
const objectSize = await this.getObjectLength(url, options);
byteRange = {
offset: objectSize - byteRangeRequest.suffixLength,
length: Number(response.headers.get("content-length")),
};
} else {
byteRange = {
offset: byteRangeRequest.offset,
length: data.byteLength,
};
}
byteRange = {
offset: byteRangeRequest.offset,
length: data.byteLength,
};
} else {
throw new Error(
"Unexpected HTTP 206 response when no byte range specified.",
Expand Down Expand Up @@ -134,25 +164,7 @@ class SpecialProtocolKvStore implements ReadableKvStore {
) {
// Some servers, such as the npm http-server package, do not support suffixLength
// byte-range requests.
const headResponse = await cancellableFetchSpecialOk(
this.credentialsProvider,
url,
{ method: "HEAD" },
async (response) => response,
cancellationToken,
);
if (headResponse.status !== 200) {
throw new Error(
"Failed to determine total size in order to fetch suffix",
);
}
const contentLength = headResponse.headers.get("content-length");
if (contentLength === undefined) {
throw new Error(
"Failed to determine total size in order to fetch suffix",
);
}
const contentLengthNumber = Number(contentLength);
const contentLengthNumber = await this.getObjectLength(url, options);
byteRangeRequest = composeByteRangeRequest(
{ offset: 0, length: contentLengthNumber },
byteRangeRequest,
Expand Down

0 comments on commit 997afee

Please sign in to comment.