mirror of
https://github.com/protomaps/PMTiles.git
synced 2026-02-04 19:01:08 +00:00
Merge pull request #102 from protomaps/handle-416-servers
FetchSource handles servers that return 416 for requests beyond end of file
This commit is contained in:
37
js/index.ts
37
js/index.ts
@@ -283,24 +283,41 @@ export class FetchSource implements Source {
|
|||||||
signal = controller.signal;
|
signal = controller.signal;
|
||||||
}
|
}
|
||||||
|
|
||||||
const resp = await fetch(this.url, {
|
let resp = await fetch(this.url, {
|
||||||
signal: signal,
|
signal: signal,
|
||||||
headers: { Range: "bytes=" + offset + "-" + (offset + length - 1) },
|
headers: { Range: "bytes=" + offset + "-" + (offset + length - 1) },
|
||||||
});
|
});
|
||||||
|
|
||||||
// can return 416, which will have a blank etag on S3.
|
// TODO: can return 416 with offset > 0 if content changed, which will have a blank etag.
|
||||||
// See https://github.com/protomaps/PMTiles/issues/90
|
// See https://github.com/protomaps/PMTiles/issues/90
|
||||||
|
|
||||||
if (resp.status >= 300) {
|
if (resp.status === 416 && offset === 0) {
|
||||||
throw Error("404");
|
// some HTTP servers don't accept ranges beyond the end of the resource.
|
||||||
controller.abort();
|
// Retry with the exact length
|
||||||
|
const content_range = resp.headers.get("Content-Range");
|
||||||
|
if (!content_range || !content_range.startsWith("bytes */")) {
|
||||||
|
throw Error("Missing content-length on 416 response");
|
||||||
}
|
}
|
||||||
const contentLength = resp.headers.get("Content-Length");
|
const actual_length = +content_range.substr(8);
|
||||||
if (!contentLength || +contentLength !== length) {
|
resp = await fetch(this.url, {
|
||||||
console.error(
|
signal: signal,
|
||||||
"Content-Length mismatch indicates byte serving not supported; aborting."
|
headers: { Range: "bytes=0-" + (actual_length - 1) },
|
||||||
);
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resp.status >= 300) {
|
||||||
|
throw Error("Bad response code: " + resp.status);
|
||||||
|
}
|
||||||
|
|
||||||
|
const content_length = resp.headers.get("Content-Length");
|
||||||
|
|
||||||
|
// some well-behaved backends, e.g. DigitalOcean CDN, respond with 200 instead of 206
|
||||||
|
// but we also need to detect no support for Byte Serving which is returning the whole file
|
||||||
|
if (resp.status === 200 && (!content_length || +content_length > length)) {
|
||||||
if (controller) controller.abort();
|
if (controller) controller.abort();
|
||||||
|
throw Error(
|
||||||
|
"Server returned no content-length header or content-length exceeding request. Check that your storage backend supports HTTP Byte Serving."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const a = await resp.arrayBuffer();
|
const a = await resp.arrayBuffer();
|
||||||
|
|||||||
Reference in New Issue
Block a user