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) => {