@@ -161,6 +161,7 @@ function createPreviewRouteRegistry(): InternalPreviewRouteRegistry {
161161
162162function proxyPreviewRequest ( target : URL , incoming : IncomingMessage , outgoing : ServerResponse ) : Promise < void > {
163163 return new Promise ( ( resolve ) => {
164+ const requestTarget = previewProxyRequestTarget ( incoming )
164165 let settled = false
165166 let targetResponse : IncomingMessage | undefined
166167 const settle = ( ) => {
@@ -182,12 +183,12 @@ function proxyPreviewRequest(target: URL, incoming: IncomingMessage, outgoing: S
182183 hostname : target . hostname ,
183184 port : target . port ,
184185 method : incoming . method ,
185- path : previewProxyRequestPath ( incoming . url ) ,
186- headers : proxyRequestHeaders ( incoming . headers ) ,
186+ path : requestTarget . path ,
187+ headers : proxyRequestHeaders ( incoming . headers , requestTarget ) ,
187188 } ,
188189 ( response ) => {
189190 targetResponse = response
190- outgoing . writeHead ( response . statusCode ?? 502 , response . statusMessage , proxyResponseHeaders ( response . headers , incoming , target ) )
191+ outgoing . writeHead ( response . statusCode ?? 502 , response . statusMessage , proxyResponseHeaders ( response . headers , requestTarget , target ) )
191192 response . on ( "error" , ( error ) => {
192193 outgoing . destroy ( error )
193194 settle ( )
@@ -211,16 +212,31 @@ function proxyPreviewRequest(target: URL, incoming: IncomingMessage, outgoing: S
211212 } )
212213}
213214
214- function previewProxyRequestPath ( rawUrl : string | undefined ) : string {
215- if ( ! rawUrl ) {
216- return "/"
217- }
215+ interface PreviewProxyRequestTarget {
216+ host : string
217+ path : string
218+ port : string
219+ protocol : "http:" | "https:"
220+ }
221+
222+ function previewProxyRequestTarget ( incoming : IncomingMessage ) : PreviewProxyRequestTarget {
223+ const rawUrl = incoming . url ?? "/"
218224 try {
219225 const url = new URL ( rawUrl )
220- return `${ url . pathname } ${ url . search } `
226+ if ( url . protocol === "http:" || url . protocol === "https:" ) {
227+ return {
228+ host : url . host ,
229+ path : `${ url . pathname } ${ url . search } ` ,
230+ port : url . port || ( url . protocol === "https:" ? "443" : "80" ) ,
231+ protocol : url . protocol ,
232+ }
233+ }
221234 } catch {
222- return rawUrl
235+ // Origin-form requests use the proxy listener's HTTP authority.
223236 }
237+ const host = incoming . headers . host ?? "localhost"
238+ const authority = new URL ( `http://${ host } ` )
239+ return { host : authority . host , path : rawUrl , port : authority . port || "80" , protocol : "http:" }
224240}
225241
226242function createPreviewProxyQueue ( ) : ( task : ( ) => Promise < void > ) => Promise < void > {
@@ -279,28 +295,36 @@ function formatPreviewHost(host: string): string {
279295 return host . includes ( ":" ) && ! host . startsWith ( "[" ) ? `[${ host } ]` : host
280296}
281297
282- function proxyRequestHeaders ( headers : IncomingHttpHeaders ) : IncomingHttpHeaders {
298+ function proxyRequestHeaders ( headers : IncomingHttpHeaders , requestTarget : PreviewProxyRequestTarget ) : IncomingHttpHeaders {
283299 const forwarded = { ...headers }
284300 delete forwarded . connection
285301 delete forwarded [ "transfer-encoding" ]
302+ delete forwarded . forwarded
303+ delete forwarded [ "x-forwarded-for" ]
304+ delete forwarded [ "x-forwarded-host" ]
305+ delete forwarded [ "x-forwarded-port" ]
306+ delete forwarded [ "x-forwarded-proto" ]
286307
287308 return {
288309 ...forwarded ,
310+ host : requestTarget . host ,
311+ "x-forwarded-host" : requestTarget . host ,
312+ "x-forwarded-port" : requestTarget . port ,
313+ "x-forwarded-proto" : requestTarget . protocol . slice ( 0 , - 1 ) ,
289314 }
290315}
291316
292- function proxyResponseHeaders ( headers : IncomingHttpHeaders , incoming : IncomingMessage , target : URL ) : IncomingHttpHeaders {
317+ function proxyResponseHeaders ( headers : IncomingHttpHeaders , requestTarget : PreviewProxyRequestTarget , target : URL ) : IncomingHttpHeaders {
293318 const forwarded = { ...headers }
294319 delete forwarded . connection
295320 delete forwarded [ "transfer-encoding" ]
296321
297322 if ( typeof forwarded . location === "string" ) {
298323 try {
299324 const location = new URL ( forwarded . location , target )
300- if ( location . origin === target . origin && incoming . headers . host ) {
301- const protocol = firstHeaderValue ( incoming . headers [ "x-forwarded-proto" ] ) ?? "http"
302- location . protocol = `${ protocol . replace ( / : $ / , "" ) } :`
303- const visible = new URL ( `${ location . protocol } //${ incoming . headers . host } ` )
325+ if ( location . origin === target . origin ) {
326+ location . protocol = requestTarget . protocol
327+ const visible = new URL ( `${ requestTarget . protocol } //${ requestTarget . host } ` )
304328 location . hostname = visible . hostname
305329 location . port = visible . port
306330 forwarded . location = location . toString ( )
@@ -313,10 +337,6 @@ function proxyResponseHeaders(headers: IncomingHttpHeaders, incoming: IncomingMe
313337 return forwarded
314338}
315339
316- function firstHeaderValue ( value : string | string [ ] | undefined ) : string | undefined {
317- return Array . isArray ( value ) ? value [ 0 ] : value
318- }
319-
320340function writeProxyError ( outgoing : ServerResponse , error : Error ) : void {
321341 if ( outgoing . headersSent ) {
322342 outgoing . destroy ( error )
0 commit comments