fix: couldn't download plugins in case of outbound_proxy

Massimo Melina committed Dec 5, 2025 at 11:22 UTC d10341d5cb2e4c5c3d9820241315c53bdf483627
1 file changed +13 -10
src/util-http.ts
+13 -10
@@ -32,7 +32,7 @@ export interface XRequestOptions extends https.RequestOptions {
32 }
33
34 export declare namespace httpStream { let defaultProxy: string | undefined }
35 -export function httpStream(url: string, { body, proxy, jar, noRedirect, httpThrow=true, ...options }: XRequestOptions ={}) {
35 +export function httpStream(url: string, { body, proxy, jar, noRedirect, httpThrow=true, ...options }: XRequestOptions ={}, redirected: string[]=[]) {
36 const controller = new AbortController()
37 options.signal ??= controller.signal
38 return Object.assign(new Promise<IncomingMessage>(async (resolve, reject) => {
@@ -82,15 +82,18 @@ export function httpStream(url: string, { body, proxy, jar, noRedirect, httpThro
82 return reject(new Error(String(res.statusCode), { cause: res }))
83 let r = res.headers.location
84 if (r && !noRedirect) {
85 - r = new URL(r, url).toString() // rewrite in case r is just a path, and thus relative to current url
86 - const stack = ((options as any)._stack ||= [])
87 - if (stack.length > 20 || stack.includes(r))
88 - return reject(new Error('endless http redirection'))
89 - stack.push(r)
90 - delete options.method // redirections are always GET
91 - delete options.headers?.['content-length']
92 - delete options.auth
93 - return resolve(httpStream(r, options))
85 + const dest = new URL(r, url) // rewrite in case r is just a path, and thus relative to the current url
86 + r = dest.toString()
87 + const src = new URL(url)
88 + const sameOrigin = src.protocol === dest.protocol && src.host === dest.host
89 + return redirected.includes(r) ? reject(new Error('endless http redirection'))
90 + : redirected.length > 20 ? reject(new Error('excessive http redirection'))
91 + : resolve(httpStream(r, {
92 + httpThrow, jar, proxy,
93 + ..._.pick(options, ['agent', 'rejectUnauthorized', 'timeout']),
94 + // forward some headers and exclude authorization if it's cross-origin
95 + headers: options.headers && _.omit(options.headers, ['content-length', 'host', 'connection', 'transfer-encoding', sameOrigin ? '' : 'authorization']),
96 + }, [...redirected, r]))
97 }
98 resolve(res)
99 }).on('error', (e: any) => {