( rawUrl: string, init: RequestInit, fetchImpl: typeof fetch, policy: GitUrlPolicy, )
| 51 | const MAX_REDIRECTS = 5; |
| 52 | |
| 53 | const fetchGit = async ( |
| 54 | rawUrl: string, |
| 55 | init: RequestInit, |
| 56 | fetchImpl: typeof fetch, |
| 57 | policy: GitUrlPolicy, |
| 58 | ): Promise<Response> => { |
| 59 | const original = validateGitFetchUrl(rawUrl, policy); |
| 60 | let current = original; |
| 61 | for (let redirects = 0; redirects <= MAX_REDIRECTS; redirects += 1) { |
| 62 | // Strip credentials on cross-host redirects (same posture as git/curl): |
| 63 | // a host must not be able to bounce our Authorization header elsewhere. |
| 64 | let headers = init.headers as Record<string, string> | undefined; |
| 65 | if (headers?.authorization && current.host !== original.host) { |
| 66 | const { authorization: _dropped, ...rest } = headers; |
| 67 | headers = rest; |
| 68 | } |
| 69 | const response = await fetchImpl(current.toString(), { |
| 70 | ...init, |
| 71 | ...(headers ? { headers } : {}), |
| 72 | redirect: "manual", |
| 73 | }); |
| 74 | if (![301, 302, 303, 307, 308].includes(response.status)) return response; |
| 75 | const location = response.headers.get("location"); |
| 76 | if (!location) |
| 77 | throw new Error(`git redirect missing Location from ${redactUrl(current.toString())}`); |
| 78 | current = validateGitFetchUrl(new URL(location, current).toString(), policy); |
| 79 | } |
| 80 | throw new Error(`git redirect depth exceeded for ${redactUrl(rawUrl)}`); |
| 81 | }; |
| 82 | |
| 83 | // The cheap "did it change" check: GET info/refs. Returns the ref advertisement. |
| 84 | export async function checkRefs( |
no test coverage detected