forked from APIDevTools/json-schema-ref-parser
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathurl.ts
95 lines (84 loc) · 2.37 KB
/
url.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import { ono } from "@jsdevtools/ono";
import { resolve } from "../util/url.js";
import { ResolverError } from "../util/errors.js";
import type { FileInfo } from "../types/index.js";
export const sendRequest = async ({
fetchOptions,
redirects = [],
timeout = 60_000,
url,
}: {
fetchOptions?: RequestInit;
redirects?: string[];
timeout?: number;
url: URL | string;
}): Promise<{
fetchOptions?: RequestInit;
response: Response;
}> => {
url = new URL(url);
redirects.push(url.href);
const controller = new AbortController();
const timeoutId = setTimeout(() => {
controller.abort();
}, timeout);
const response = await fetch(url, {
signal: controller.signal,
...fetchOptions,
});
clearTimeout(timeoutId);
if (response.status >= 300 && response.status <= 399) {
if (redirects.length > 5) {
throw new ResolverError(
ono(
{ status: response.status },
`Error requesting ${redirects[0]}. \nToo many redirects: \n ${redirects.join(" \n ")}`,
),
);
}
if (!("location" in response.headers) || !response.headers.location) {
throw ono({ status: response.status }, `HTTP ${response.status} redirect with no location header`);
}
return sendRequest({
fetchOptions,
redirects,
timeout,
url: resolve(url.href, response.headers.location as string),
});
}
return { fetchOptions, response };
}
export const urlResolver = {
handler: async ({
arrayBuffer,
fetch: _fetch,
file,
}: {
arrayBuffer?: ArrayBuffer;
fetch?: RequestInit;
file: FileInfo;
}): Promise<void> => {
let data = arrayBuffer;
if (!data) {
try {
const { fetchOptions, response } = await sendRequest({
fetchOptions: {
method: 'GET',
..._fetch,
},
url: file.url,
});
if (response.status >= 400) {
// gracefully handle HEAD method not allowed
if (response.status !== 405 || fetchOptions?.method !== 'HEAD') {
throw ono({ status: response.status }, `HTTP ERROR ${response.status}`);
}
data = response.body ? await response.arrayBuffer() : new ArrayBuffer(0)
}
} catch (error: any) {
throw new ResolverError(ono(error, `Error requesting ${file.url}`), file.url);
}
}
file.data = Buffer.from(data!);
},
};