(url)
| 7 | |
| 8 | // Walks the redirect chain manually, recording each Location header as got did |
| 9 | const redirectsHandler = async (url) => { |
| 10 | const redirects = [url]; |
| 11 | let current = url; |
| 12 | try { |
| 13 | for (let i = 0; i < MAX_REDIRECTS; i++) { |
| 14 | const response = await fetch(current, { |
| 15 | redirect: 'manual', |
| 16 | signal: AbortSignal.timeout(TIMEOUT_MS), |
| 17 | headers: { 'user-agent': USER_AGENT }, |
| 18 | }); |
| 19 | if (response.status < 300 || response.status >= 400) { |
| 20 | if (response.status >= 400) { |
| 21 | const err = new Error(`HTTP ${response.status}`); |
| 22 | err.response = { status: response.status }; |
| 23 | throw err; |
| 24 | } |
| 25 | break; |
| 26 | } |
| 27 | const location = response.headers.get('location'); |
| 28 | if (!location) break; |
| 29 | redirects.push(location); |
| 30 | current = new URL(location, current).href; |
| 31 | } |
| 32 | return { redirects }; |
| 33 | } catch (error) { |
| 34 | if (error.cause?.code) error.code = error.cause.code; |
| 35 | if (error.name === 'TimeoutError' || error.name === 'AbortError') { |
| 36 | error.code = 'ECONNABORTED'; |
| 37 | } |
| 38 | return upstreamError(error, 'Redirect lookup'); |
| 39 | } |
| 40 | }; |
| 41 | |
| 42 | export const handler = middleware(redirectsHandler); |
| 43 | export default handler; |
nothing calls this directly
no test coverage detected