@@ -6,6 +6,10 @@ import * as querystring from "querystring"
6
6
import { HttpCode , HttpError } from "../../common/http"
7
7
import { HttpProvider , HttpProviderOptions , HttpProxyProvider , HttpResponse , Route } from "../http"
8
8
9
+ interface Request extends http . IncomingMessage {
10
+ base ?: string
11
+ }
12
+
9
13
/**
10
14
* Proxy HTTP provider.
11
15
*/
@@ -24,6 +28,12 @@ export class ProxyHttpProvider extends HttpProvider implements HttpProxyProvider
24
28
super ( options )
25
29
this . proxyDomains = proxyDomains . map ( ( d ) => d . replace ( / ^ \* \. / , "" ) ) . filter ( ( d , i , arr ) => arr . indexOf ( d ) === i )
26
30
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
+ } )
27
37
}
28
38
29
39
public async handleRequest (
@@ -41,14 +51,15 @@ export class ProxyHttpProvider extends HttpProvider implements HttpProxyProvider
41
51
}
42
52
43
53
// 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 ( "/" ) ) {
46
57
return {
47
- redirect : `/proxy/ ${ base } /` ,
58
+ redirect : `${ base } /` ,
48
59
}
49
60
}
50
61
51
- const payload = this . doProxy ( route . requestPath , route . query , request , response , base )
62
+ const payload = this . doProxy ( route , request , response , port , base )
52
63
if ( payload ) {
53
64
return payload
54
65
}
@@ -63,7 +74,9 @@ export class ProxyHttpProvider extends HttpProvider implements HttpProxyProvider
63
74
head : Buffer ,
64
75
) : Promise < void > {
65
76
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 )
67
80
}
68
81
69
82
public getCookieDomain ( host : string ) : string {
@@ -84,7 +97,7 @@ export class ProxyHttpProvider extends HttpProvider implements HttpProxyProvider
84
97
response : http . ServerResponse ,
85
98
) : HttpResponse | undefined {
86
99
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
88
101
}
89
102
90
103
public maybeProxyWebSocket (
@@ -94,7 +107,7 @@ export class ProxyHttpProvider extends HttpProvider implements HttpProxyProvider
94
107
head : Buffer ,
95
108
) : HttpResponse | undefined {
96
109
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
98
111
}
99
112
100
113
private getPort ( request : http . IncomingMessage ) : string | undefined {
@@ -121,57 +134,55 @@ export class ProxyHttpProvider extends HttpProvider implements HttpProxyProvider
121
134
}
122
135
123
136
private doProxy (
124
- path : string ,
125
- query : querystring . ParsedUrlQuery ,
137
+ route : Route ,
126
138
request : http . IncomingMessage ,
127
139
response : http . ServerResponse ,
128
140
portStr : string ,
141
+ base ?: string ,
129
142
) : HttpResponse
130
143
private doProxy (
131
- path : string ,
132
- query : querystring . ParsedUrlQuery ,
144
+ route : Route ,
133
145
request : http . IncomingMessage ,
134
- socket : net . Socket ,
135
- head : Buffer ,
146
+ response : { socket : net . Socket ; head : Buffer } ,
136
147
portStr : string ,
148
+ base ?: string ,
137
149
) : HttpResponse
138
150
private doProxy (
139
- path : string ,
140
- query : querystring . ParsedUrlQuery ,
151
+ route : Route ,
141
152
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 ,
145
156
) : 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 )
155
158
if ( isNaN ( port ) ) {
156
159
return {
157
160
code : HttpCode . BadRequest ,
158
- content : `"${ _portStr } " is not a valid number` ,
161
+ content : `"${ portStr } " is not a valid number` ,
159
162
}
160
163
}
161
164
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
162
173
const options : proxy . ServerOptions = {
163
- autoRewrite : true ,
164
174
changeOrigin : true ,
165
175
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 ) } ` : ""
168
178
} `,
179
+ ws : ! hxxp ,
169
180
}
170
181
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 )
173
184
} else {
174
- this . proxy . web ( request , responseOrSocket , options )
185
+ this . proxy . ws ( request , response . socket , response . head , options )
175
186
}
176
187
177
188
return { handled : true }
0 commit comments