@@ -6,6 +6,10 @@ import * as querystring from "querystring"
66import { HttpCode , HttpError } from "../../common/http"
77import { HttpProvider , HttpProviderOptions , HttpProxyProvider , HttpResponse , Route } from "../http"
88
9+ interface Request extends http . IncomingMessage {
10+ base ?: string
11+ }
12+
913/**
1014 * Proxy HTTP provider.
1115 */
@@ -24,6 +28,12 @@ export class ProxyHttpProvider extends HttpProvider implements HttpProxyProvider
2428 super ( options )
2529 this . proxyDomains = proxyDomains . map ( ( d ) => d . replace ( / ^ \* \. / , "" ) ) . filter ( ( d , i , arr ) => arr . indexOf ( d ) === i )
2630 this . proxy . on ( "error" , ( error ) => logger . warn ( error . message ) )
31+ // Intercept the response to rewrite absolute redirects against the base path.
32+ this . proxy . on ( "proxyRes" , ( response , request : Request ) => {
33+ if ( response . headers . location && response . headers . location . startsWith ( "/" ) && request . base ) {
34+ response . headers . location = request . base + response . headers . location
35+ }
36+ } )
2737 }
2838
2939 public async handleRequest (
@@ -41,14 +51,15 @@ export class ProxyHttpProvider extends HttpProvider implements HttpProxyProvider
4151 }
4252
4353 // Ensure there is a trailing slash so relative paths work correctly.
44- const base = route . base . replace ( / ^ \/ / , "" )
45- if ( isRoot && ! route . originalPath . endsWith ( "/" ) ) {
54+ const port = route . base . replace ( / ^ \/ / , "" )
55+ const base = `${ this . options . base } /${ port } `
56+ if ( isRoot && ! route . fullPath . endsWith ( "/" ) ) {
4657 return {
47- redirect : `/proxy/ ${ base } /` ,
58+ redirect : `${ base } /` ,
4859 }
4960 }
5061
51- const payload = this . doProxy ( route . requestPath , route . query , request , response , base )
62+ const payload = this . doProxy ( route , request , response , port , base )
5263 if ( payload ) {
5364 return payload
5465 }
@@ -63,7 +74,9 @@ export class ProxyHttpProvider extends HttpProvider implements HttpProxyProvider
6374 head : Buffer ,
6475 ) : Promise < void > {
6576 this . ensureAuthenticated ( request )
66- this . doProxy ( route . requestPath , route . query , request , socket , head , route . base . replace ( / ^ \/ / , "" ) )
77+ const port = route . base . replace ( / ^ \/ / , "" )
78+ const base = `${ this . options . base } /${ port } `
79+ this . doProxy ( route , request , { socket, head } , port , base )
6780 }
6881
6982 public getCookieDomain ( host : string ) : string {
@@ -84,7 +97,7 @@ export class ProxyHttpProvider extends HttpProvider implements HttpProxyProvider
8497 response : http . ServerResponse ,
8598 ) : HttpResponse | undefined {
8699 const port = this . getPort ( request )
87- return port ? this . doProxy ( route . fullPath , route . query , request , response , port ) : undefined
100+ return port ? this . doProxy ( route , request , response , port ) : undefined
88101 }
89102
90103 public maybeProxyWebSocket (
@@ -94,7 +107,7 @@ export class ProxyHttpProvider extends HttpProvider implements HttpProxyProvider
94107 head : Buffer ,
95108 ) : HttpResponse | undefined {
96109 const port = this . getPort ( request )
97- return port ? this . doProxy ( route . fullPath , route . query , request , socket , head , port ) : undefined
110+ return port ? this . doProxy ( route , request , { socket, head } , port ) : undefined
98111 }
99112
100113 private getPort ( request : http . IncomingMessage ) : string | undefined {
@@ -121,57 +134,55 @@ export class ProxyHttpProvider extends HttpProvider implements HttpProxyProvider
121134 }
122135
123136 private doProxy (
124- path : string ,
125- query : querystring . ParsedUrlQuery ,
137+ route : Route ,
126138 request : http . IncomingMessage ,
127139 response : http . ServerResponse ,
128140 portStr : string ,
141+ base ?: string ,
129142 ) : HttpResponse
130143 private doProxy (
131- path : string ,
132- query : querystring . ParsedUrlQuery ,
144+ route : Route ,
133145 request : http . IncomingMessage ,
134- socket : net . Socket ,
135- head : Buffer ,
146+ response : { socket : net . Socket ; head : Buffer } ,
136147 portStr : string ,
148+ base ?: string ,
137149 ) : HttpResponse
138150 private doProxy (
139- path : string ,
140- query : querystring . ParsedUrlQuery ,
151+ route : Route ,
141152 request : http . IncomingMessage ,
142- responseOrSocket : http . ServerResponse | net . Socket ,
143- headOrPortStr : Buffer | string ,
144- portStr ?: string ,
153+ response : http . ServerResponse | { socket : net . Socket ; head : Buffer } ,
154+ portStr : string ,
155+ base ?: string ,
145156 ) : HttpResponse {
146- const _portStr = typeof headOrPortStr === "string" ? headOrPortStr : portStr
147- if ( ! _portStr ) {
148- return {
149- code : HttpCode . BadRequest ,
150- content : "Port must be provided" ,
151- }
152- }
153-
154- const port = parseInt ( _portStr , 10 )
157+ const port = parseInt ( portStr , 10 )
155158 if ( isNaN ( port ) ) {
156159 return {
157160 code : HttpCode . BadRequest ,
158- content : `"${ _portStr } " is not a valid number` ,
161+ content : `"${ portStr } " is not a valid number` ,
159162 }
160163 }
161164
165+ // REVIEW: Absolute redirects need to be based on the subpath but I'm not
166+ // sure how best to get this information to the `proxyRes` event handler.
167+ // For now I'm sticking it on the request object which is passed through to
168+ // the event.
169+ ; ( request as Request ) . base = base
170+
171+ const hxxp = response instanceof http . ServerResponse
172+ const path = base ? route . fullPath . replace ( base , "" ) : route . fullPath
162173 const options : proxy . ServerOptions = {
163- autoRewrite : true ,
164174 changeOrigin : true ,
165175 ignorePath : true ,
166- target : `http://127.0.0.1:${ port } ${ path } ${
167- Object . keys ( query ) . length > 0 ? `?${ querystring . stringify ( query ) } ` : ""
176+ target : `${ hxxp ? " http" : "ws" } ://127.0.0.1:${ port } ${ path } ${
177+ Object . keys ( route . query ) . length > 0 ? `?${ querystring . stringify ( route . query ) } ` : ""
168178 } `,
179+ ws : ! hxxp ,
169180 }
170181
171- if ( responseOrSocket instanceof net . Socket ) {
172- this . proxy . ws ( request , responseOrSocket , headOrPortStr , options )
182+ if ( response instanceof http . ServerResponse ) {
183+ this . proxy . web ( request , response , options )
173184 } else {
174- this . proxy . web ( request , responseOrSocket , options )
185+ this . proxy . ws ( request , response . socket , response . head , options )
175186 }
176187
177188 return { handled : true }
0 commit comments