@@ -17,7 +17,7 @@ import type { Socket } from "node:net";
1717import type Stream from "node:stream" ;
1818import * as followRedirects from "follow-redirects" ;
1919import { Agent , type Dispatcher , interceptors } from "undici" ;
20- import type { ErrorCallback , NormalizedServerOptions , NormalizeProxyTarget , ProxyServer , ProxyTarget , ProxyTargetUrl , ServerOptions } from ".." ;
20+ import type { ErrorCallback , NormalizedServerOptions , NormalizeProxyTarget , ProxyServer , ProxyTarget , ProxyTargetUrl , ServerOptions , UndiciOptions } from ".." ;
2121import * as common from "../common" ;
2222import { type EditableResponse , OUTGOING_PASSES } from "./web-outgoing" ;
2323
@@ -79,8 +79,7 @@ export function stream(req: Request, res: Response, options: NormalizedServerOpt
7979 // And we begin!
8080 server . emit ( "start" , req , res , options . target || options . forward ! ) ;
8181
82- if ( options . agentOptions || options . requestOptions
83- ) {
82+ if ( options . undici ) {
8483 return stream2 ( req , res , options , _ , server , cb ) ;
8584 }
8685
@@ -213,12 +212,16 @@ async function stream2(
213212 }
214213 ) ;
215214
215+ const undiciOptions = options . undici === true ? { } as UndiciOptions : options . undici ;
216+ if ( ! undiciOptions ) {
217+ throw new Error ( "stream2 called without undici options" ) ;
218+ }
216219 const agentOptions : Agent . Options = {
217- ...options . agentOptions ,
218220 allowH2 : true ,
219221 connect : {
220222 rejectUnauthorized : options . secure !== false ,
221223 } ,
224+ ...( undiciOptions . agentOptions || { } ) ,
222225 } ;
223226
224227 let agent : Agent | Dispatcher = new Agent ( agentOptions )
@@ -249,8 +252,36 @@ async function stream2(
249252 requestOptions . body = req ;
250253 }
251254
255+ // Call onBeforeRequest callback before making the forward request
256+ if ( undiciOptions . onBeforeRequest ) {
257+ try {
258+ await undiciOptions . onBeforeRequest ( requestOptions , req , res , options ) ;
259+ } catch ( err ) {
260+ if ( cb ) {
261+ cb ( err as Error , req , res , options . forward ) ;
262+ } else {
263+ server . emit ( "error" , err as Error , req , res , options . forward ) ;
264+ }
265+ return ;
266+ }
267+ }
268+
252269 try {
253- await agent . request ( requestOptions )
270+ const result = await agent . request ( requestOptions ) ;
271+
272+ // Call onAfterResponse callback for forward requests (though they typically don't expect responses)
273+ if ( undiciOptions . onAfterResponse ) {
274+ try {
275+ await undiciOptions . onAfterResponse ( result , req , res , options ) ;
276+ } catch ( err ) {
277+ if ( cb ) {
278+ cb ( err as Error , req , res , options . forward ) ;
279+ } else {
280+ server . emit ( "error" , err as Error , req , res , options . forward ) ;
281+ }
282+ return ;
283+ }
284+ }
254285 } catch ( err ) {
255286 if ( cb ) {
256287 cb ( err as Error , req , res , options . forward ) ;
@@ -272,6 +303,7 @@ async function stream2(
272303 headers : outgoingOptions . headers || { } ,
273304 path : outgoingOptions . path || "/" ,
274305 headersTimeout : options . proxyTimeout ,
306+ ...undiciOptions . requestOptions
275307 } ;
276308
277309 if ( options . auth ) {
@@ -284,29 +316,47 @@ async function stream2(
284316 requestOptions . body = req ;
285317 }
286318
287-
288-
289-
319+ // Call onBeforeRequest callback before making the request
320+ if ( undiciOptions . onBeforeRequest ) {
321+ try {
322+ await undiciOptions . onBeforeRequest ( requestOptions , req , res , options ) ;
323+ } catch ( err ) {
324+ if ( cb ) {
325+ cb ( err as Error , req , res , options . target ) ;
326+ } else {
327+ server . emit ( "error" , err as Error , req , res , options . target ) ;
328+ }
329+ return ;
330+ }
331+ }
332+
290333 try {
291- const { statusCode, headers, body } = await agent . request (
292- requestOptions
293- ) ;
334+ const response = await agent . request ( requestOptions ) ;
335+
336+ // Call onAfterResponse callback after receiving the response
337+ if ( undiciOptions . onAfterResponse ) {
338+ try {
339+ await undiciOptions . onAfterResponse ( response , req , res , options ) ;
340+ } catch ( err ) {
341+ if ( cb ) {
342+ cb ( err as Error , req , res , options . target ) ;
343+ } else {
344+ server . emit ( "error" , err as Error , req , res , options . target ) ;
345+ }
346+ return ;
347+ }
348+ }
349+
294350
295351 // ProxyRes is used in the outgoing passes
296352 // But since only certain properties are used, we can fake it here
297353 // to avoid having to refactor everything.
298- const fakeProxyRes = { } as ProxyResponse ;
299-
300- fakeProxyRes . statusCode = statusCode ;
301- fakeProxyRes . headers = headers as { [ key : string ] : string | string [ ] } ;
302- fakeProxyRes . rawHeaders = Object . entries ( headers ) . flatMap ( ( [ key , value ] ) => {
354+ const fakeProxyRes = { ...response , rawHeaders : Object . entries ( response . headers ) . flatMap ( ( [ key , value ] ) => {
303355 if ( Array . isArray ( value ) ) {
304356 return value . flatMap ( v => ( v != null ? [ key , v ] : [ ] ) ) ;
305357 }
306358 return value != null ? [ key , value ] : [ ] ;
307- } ) as string [ ] ;
308- fakeProxyRes . pipe = body . pipe . bind ( body ) ;
309-
359+ } ) as string [ ] } as unknown as ProxyResponse ;
310360
311361 if ( ! res . headersSent && ! options . selfHandleResponse ) {
312362 for ( const pass of web_o ) {
@@ -317,12 +367,12 @@ async function stream2(
317367
318368 if ( ! res . writableEnded ) {
319369 // Allow us to listen for when the proxy has completed
320- body . on ( "end" , ( ) => {
370+ response . body . on ( "end" , ( ) => {
321371 server ?. emit ( "end" , req , res , fakeProxyRes ) ;
322372 } ) ;
323373 // We pipe to the response unless its expected to be handled by the user
324374 if ( ! options . selfHandleResponse ) {
325- body . pipe ( res ) ;
375+ response . body . pipe ( res ) ;
326376 }
327377 } else {
328378 server ?. emit ( "end" , req , res , fakeProxyRes ) ;
0 commit comments