| 87 | }; |
| 88 | |
| 89 | async function headUri( |
| 90 | uri: string, |
| 91 | redirectCount = 0 |
| 92 | ): Promise<HeadInfo | undefined> { |
| 93 | const response = await fetch(uri, { |
| 94 | method: "HEAD", |
| 95 | headers: { |
| 96 | accept: "*/*", |
| 97 | "user-agent": |
| 98 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36", |
| 99 | }, |
| 100 | }); |
| 101 | |
| 102 | if (!response.ok) { |
| 103 | // If this is a 405 Method Not Allowed, do a GET request instead and if that is a redirect, return the head of the redirect url |
| 104 | if (response.status === 405 && redirectCount < 5) { |
| 105 | // Do a GET request that does not follow redirects |
| 106 | const noFollowResponse = await fetch(uri, { |
| 107 | method: "GET", |
| 108 | redirect: "manual", |
| 109 | headers: { |
| 110 | accept: "*/*", |
| 111 | "user-agent": |
| 112 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36", |
| 113 | }, |
| 114 | }); |
| 115 | |
| 116 | if (noFollowResponse.status === 301 || noFollowResponse.status === 302) { |
| 117 | // Get the url from the response Location header |
| 118 | const location = noFollowResponse.headers.get("location"); |
| 119 | |
| 120 | if (location) { |
| 121 | return headUri(location, redirectCount + 1); |
| 122 | } |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | return; |
| 127 | } |
| 128 | |
| 129 | return { |
| 130 | contentType: response.headers.get("content-type") || "", |
| 131 | contentLength: Number(response.headers.get("content-length") || "0"), |
| 132 | lastModified: response.headers.get("last-modified") || "", |
| 133 | }; |
| 134 | } |
| 135 | |
| 136 | function createPreviewJson(uri: string, json: unknown): PreviewJson { |
| 137 | return { |