@@ -415,6 +415,19 @@ export class PassThroughHandler extends PassThroughHandlerDefinition {
415
415
let { method, url : reqUrl , rawHeaders } = clientReq as OngoingRequest ;
416
416
let { protocol, hostname, port, path } = url . parse ( reqUrl ) ;
417
417
418
+ // Check if this request is a request loop:
419
+ if ( isSocketLoop ( this . outgoingSockets , ( < any > clientReq ) . socket ) ) {
420
+ throw new Error ( oneLine `
421
+ Passthrough loop detected. This probably means you're sending a request directly
422
+ to a passthrough endpoint, which is forwarding it to the target URL, which is a
423
+ passthrough endpoint, which is forwarding it to the target URL, which is a
424
+ passthrough endpoint...` +
425
+ '\n\n' + oneLine `
426
+ You should either explicitly mock a response for this URL (${ reqUrl } ), or use
427
+ the server as a proxy, instead of making requests to it directly.
428
+ ` ) ;
429
+ }
430
+
418
431
// We have to capture the request stream immediately, to make sure nothing is lost if it
419
432
// goes past its max length (truncating the data) before we start sending upstream.
420
433
const clientReqBody = clientReq . body . asStream ( ) ;
@@ -456,19 +469,8 @@ export class PassThroughHandler extends PassThroughHandlerDefinition {
456
469
// If it's an explicit custom value, use that directly.
457
470
hostHeader [ 1 ] = updateHostHeader ;
458
471
} // Otherwise: falsey means don't touch it.
459
- }
460
472
461
- // Check if this request is a request loop:
462
- if ( isSocketLoop ( this . outgoingSockets , ( < any > clientReq ) . socket ) ) {
463
- throw new Error ( oneLine `
464
- Passthrough loop detected. This probably means you're sending a request directly
465
- to a passthrough endpoint, which is forwarding it to the target URL, which is a
466
- passthrough endpoint, which is forwarding it to the target URL, which is a
467
- passthrough endpoint...` +
468
- '\n\n' + oneLine `
469
- You should either explicitly mock a response for this URL (${ reqUrl } ), or use
470
- the server as a proxy, instead of making requests to it directly.
471
- ` ) ;
473
+ reqUrl = new URL ( `${ protocol } //${ hostname } ${ ( port ? `:${ port } ` : '' ) } /${ path } ` ) . toString ( ) ;
472
474
}
473
475
474
476
// Override the request details, if a transform or callback is specified:
@@ -571,10 +573,14 @@ export class PassThroughHandler extends PassThroughHandlerDefinition {
571
573
}
572
574
} else if ( this . beforeRequest ) {
573
575
const completedRequest = await waitForCompletedRequest ( clientReq ) ;
576
+ const clientRawHeaders = completedRequest . rawHeaders ;
577
+ const clientHeaders = rawHeadersToObject ( clientRawHeaders ) ;
578
+
574
579
const modifiedReq = await this . beforeRequest ( {
575
580
...completedRequest ,
576
- headers : _ . cloneDeep ( rawHeadersToObject ( completedRequest . rawHeaders ) ) ,
577
- rawHeaders : _ . cloneDeep ( completedRequest . rawHeaders )
581
+ url : reqUrl , // May have been overwritten by forwarding
582
+ headers : _ . cloneDeep ( clientHeaders ) ,
583
+ rawHeaders : _ . cloneDeep ( clientRawHeaders )
578
584
} ) ;
579
585
580
586
if ( modifiedReq ?. response ) {
@@ -597,15 +603,24 @@ export class PassThroughHandler extends PassThroughHandlerDefinition {
597
603
reqUrl = modifiedReq ?. url || reqUrl ;
598
604
599
605
headersManuallyModified = ! ! modifiedReq ?. headers ;
600
- const clientHeaders = rawHeadersToObject ( clientReq . rawHeaders )
601
606
let headers = modifiedReq ?. headers || clientHeaders ;
602
- if ( ! this . forwarding || this . forwarding . updateHostHeader === false ) {
603
- Object . assign ( headers ,
604
- isH2Downstream
605
- ? getH2HeadersAfterModification ( reqUrl , clientHeaders , modifiedReq ?. headers )
606
- : { 'host' : getHostAfterModification ( reqUrl , clientHeaders , modifiedReq ?. headers ) }
607
+
608
+ // We need to make sure the Host/:authority header is updated correctly - following the user's returned value if
609
+ // they provided one, but updating it if not to match the effective target URL of the request:
610
+ const expectedTargetUrl = modifiedReq ?. url
611
+ ?? (
612
+ // If not overridden, we fall back to the original value, but we need to handle changes that forwarding
613
+ // might have made as well, especially if it's intentionally left URL & headers out of sync:
614
+ this . forwarding ?. updateHostHeader === false
615
+ ? clientReq . url
616
+ : reqUrl
607
617
) ;
608
- }
618
+
619
+ Object . assign ( headers ,
620
+ isH2Downstream
621
+ ? getH2HeadersAfterModification ( expectedTargetUrl , clientHeaders , modifiedReq ?. headers )
622
+ : { 'host' : getHostAfterModification ( expectedTargetUrl , clientHeaders , modifiedReq ?. headers ) }
623
+ ) ;
609
624
610
625
validateCustomHeaders (
611
626
clientHeaders ,
0 commit comments