@@ -208,6 +208,12 @@ async function stream2(
208208) {
209209 // Helper function to handle errors consistently throughout the fetch path
210210 const handleError = ( err : Error , target ?: ProxyTargetUrl ) => {
211+ const e = err as any ;
212+ // Copy code from cause if available and missing on err
213+ if ( e . code === undefined && e . cause ?. code ) {
214+ e . code = e . cause . code ;
215+ }
216+
211217 if ( cb ) {
212218 cb ( err , req , res , target ) ;
213219 } else {
@@ -227,26 +233,58 @@ async function stream2(
227233 } ) ;
228234
229235 const customFetch = options . fetch || fetch ;
230-
231236 const fetchOptions = options . fetchOptions ?? { } as FetchOptions ;
232237
233-
234- if ( options . forward ) {
235- const outgoingOptions = common . setupOutgoing ( options . ssl || { } , options , req , "forward" ) ;
236-
238+ const prepareRequest = ( outgoing : common . Outgoing ) => {
237239 const requestOptions : RequestInit = {
238- method : outgoingOptions . method ,
240+ method : outgoing . method ,
241+ ...fetchOptions . requestOptions ,
239242 } ;
240243
244+ const headers = new Headers ( fetchOptions . requestOptions ?. headers ) ;
245+
246+ if ( ! fetchOptions . requestOptions ?. headers && outgoing . headers ) {
247+ for ( const [ key , value ] of Object . entries ( outgoing . headers ) ) {
248+ if ( typeof key === "string" ) {
249+ if ( Array . isArray ( value ) ) {
250+ for ( const v of value ) {
251+ headers . append ( key , v as string ) ;
252+ }
253+ } else if ( value != null ) {
254+ headers . append ( key , value as string ) ;
255+ }
256+ }
257+ }
258+ }
259+
260+ if ( options . auth ) {
261+ headers . set ( "authorization" , `Basic ${ Buffer . from ( options . auth ) . toString ( "base64" ) } ` ) ;
262+ }
263+
264+ if ( options . proxyTimeout ) {
265+ requestOptions . signal = AbortSignal . timeout ( options . proxyTimeout ) ;
266+ }
267+
268+ requestOptions . headers = headers ;
241269
242- // Handle request body
243270 if ( options . buffer ) {
244271 requestOptions . body = options . buffer as Stream . Readable ;
245272 } else if ( req . method !== "GET" && req . method !== "HEAD" ) {
246273 requestOptions . body = req ;
247274 requestOptions . duplex = "half" ;
248275 }
249276
277+ return requestOptions ;
278+ } ;
279+
280+ if ( options . forward ) {
281+ const outgoingOptions = common . setupOutgoing ( options . ssl || { } , options , req , "forward" ) ;
282+ const requestOptions = prepareRequest ( outgoingOptions ) ;
283+ let targetUrl = new URL ( outgoingOptions . url ) . origin + outgoingOptions . path ;
284+ if ( targetUrl . startsWith ( "ws" ) ) {
285+ targetUrl = targetUrl . replace ( "ws" , "http" ) ;
286+ }
287+
250288 // Call onBeforeRequest callback before making the forward request
251289 if ( fetchOptions . onBeforeRequest ) {
252290 try {
@@ -258,7 +296,7 @@ async function stream2(
258296 }
259297
260298 try {
261- const result = await customFetch ( new URL ( outgoingOptions . url ) . origin + outgoingOptions . path , requestOptions ) ;
299+ const result = await customFetch ( targetUrl , requestOptions ) ;
262300
263301 // Call onAfterResponse callback for forward requests (though they typically don't expect responses)
264302 if ( fetchOptions . onAfterResponse ) {
@@ -279,30 +317,10 @@ async function stream2(
279317 }
280318
281319 const outgoingOptions = common . setupOutgoing ( options . ssl || { } , options , req ) ;
282-
283- // Remove symbols from headers
284- const requestOptions : RequestInit = {
285- method : outgoingOptions . method ,
286- headers : Object . fromEntries (
287- Object . entries ( outgoingOptions . headers || { } ) . filter ( ( [ key , _value ] ) => {
288- return typeof key === "string" ;
289- } ) ,
290- ) as RequestInit [ "headers" ] ,
291- ...fetchOptions . requestOptions ,
292- } ;
293-
294- if ( options . auth ) {
295- requestOptions . headers = {
296- ...requestOptions . headers ,
297- authorization : `Basic ${ Buffer . from ( options . auth ) . toString ( "base64" ) } ` ,
298- } ;
299- }
300-
301- if ( options . buffer ) {
302- requestOptions . body = options . buffer as Stream . Readable ;
303- } else if ( req . method !== "GET" && req . method !== "HEAD" ) {
304- requestOptions . body = req ;
305- requestOptions . duplex = "half" ;
320+ const requestOptions = prepareRequest ( outgoingOptions ) ;
321+ let targetUrl = new URL ( outgoingOptions . url ) . origin + outgoingOptions . path ;
322+ if ( targetUrl . startsWith ( "ws" ) ) {
323+ targetUrl = targetUrl . replace ( "ws" , "http" ) ;
306324 }
307325
308326 // Call onBeforeRequest callback before making the request
@@ -316,7 +334,7 @@ async function stream2(
316334 }
317335
318336 try {
319- const response = await customFetch ( new URL ( outgoingOptions . url ) . origin + outgoingOptions . path , requestOptions ) ;
337+ const response = await customFetch ( targetUrl , requestOptions ) ;
320338
321339 // Call onAfterResponse callback after receiving the response
322340 if ( fetchOptions . onAfterResponse ) {
0 commit comments