1
1
import * as http from "http" ;
2
2
import * as https from "https" ;
3
+ import * as net from "net" ;
3
4
import { WEB_PASSES } from "./passes/web-incoming" ;
4
5
import { WS_PASSES } from "./passes/ws-incoming" ;
5
6
import { EventEmitter } from "events" ;
@@ -32,67 +33,165 @@ export interface ServerOptions {
32
33
// actually proxying is called. However, they can be missing when creating the
33
34
// proxy server in the first place! E.g., you could make a proxy server P with
34
35
// no options, then use P.web(req,res, {target:...}).
35
- // URL string to be parsed with the url module.
36
+ /** URL string to be parsed with the url module. */
36
37
target ?: ProxyTarget ;
37
- // URL string to be parsed with the url module or a URL object.
38
+ /** URL string to be parsed with the url module or a URL object. */
38
39
forward ?: ProxyTargetUrl ;
39
- // Object to be passed to http(s).request.
40
+ /** Object to be passed to http(s).request. */
40
41
agent ?: any ;
41
- // Object to be passed to https.createServer().
42
+ /** Object to be passed to https.createServer(). */
42
43
ssl ?: any ;
43
- // If you want to proxy websockets.
44
+ /** If you want to proxy websockets. */
44
45
ws ?: boolean ;
45
- // Adds x- forward headers.
46
+ /** Adds x- forward headers. */
46
47
xfwd ?: boolean ;
47
- // Verify SSL certificate.
48
+ /** Verify SSL certificate. */
48
49
secure ?: boolean ;
49
- // Explicitly specify if we are proxying to another proxy.
50
+ /** Explicitly specify if we are proxying to another proxy. */
50
51
toProxy ?: boolean ;
51
- // Specify whether you want to prepend the target's path to the proxy path.
52
+ /** Specify whether you want to prepend the target's path to the proxy path. */
52
53
prependPath ?: boolean ;
53
- // Specify whether you want to ignore the proxy path of the incoming request.
54
+ /** Specify whether you want to ignore the proxy path of the incoming request. */
54
55
ignorePath ?: boolean ;
55
- // Local interface string to bind for outgoing connections.
56
+ /** Local interface string to bind for outgoing connections. */
56
57
localAddress ?: string ;
57
- // Changes the origin of the host header to the target URL.
58
+ /** Changes the origin of the host header to the target URL. */
58
59
changeOrigin ?: boolean ;
59
- // specify whether you want to keep letter case of response header key
60
+ /** specify whether you want to keep letter case of response header key */
60
61
preserveHeaderKeyCase ?: boolean ;
61
- // Basic authentication i.e. 'user:password' to compute an Authorization header.
62
+ /** Basic authentication i.e. 'user:password' to compute an Authorization header. */
62
63
auth ?: string ;
63
- // Rewrites the location hostname on (301 / 302 / 307 / 308) redirects, Default: null.
64
+ /** Rewrites the location hostname on (301 / 302 / 307 / 308) redirects, Default: null. */
64
65
hostRewrite ?: string ;
65
- // Rewrites the location host/ port on (301 / 302 / 307 / 308) redirects based on requested host/ port.Default: false.
66
+ /** Rewrites the location host/ port on (301 / 302 / 307 / 308) redirects based on requested host/ port.Default: false. */
66
67
autoRewrite ?: boolean ;
67
- // Rewrites the location protocol on (301 / 302 / 307 / 308) redirects to 'http' or 'https'.Default: null.
68
+ /** Rewrites the location protocol on (301 / 302 / 307 / 308) redirects to 'http' or 'https'.Default: null. */
68
69
protocolRewrite ?: string ;
69
- // rewrites domain of set-cookie headers.
70
+ /** rewrites domain of set-cookie headers. */
70
71
cookieDomainRewrite ?: false | string | { [ oldDomain : string ] : string } ;
71
- // rewrites path of set-cookie headers. Default: false
72
+ /** rewrites path of set-cookie headers. Default: false */
72
73
cookiePathRewrite ?: false | string | { [ oldPath : string ] : string } ;
73
- // object with extra headers to be added to target requests.
74
+ /** object with extra headers to be added to target requests. */
74
75
headers ?: { [ header : string ] : string | string [ ] | undefined } ;
75
- // Timeout (in milliseconds) when proxy receives no response from target. Default: 120000 (2 minutes)
76
+ /** Timeout (in milliseconds) when proxy receives no response from target. Default: 120000 (2 minutes) */
76
77
proxyTimeout ?: number ;
77
- // Timeout (in milliseconds) for incoming requests
78
+ /** Timeout (in milliseconds) for incoming requests */
78
79
timeout ?: number ;
79
- // Specify whether you want to follow redirects. Default: false
80
+ /** Specify whether you want to follow redirects. Default: false */
80
81
followRedirects ?: boolean ;
81
- // If set to true, none of the webOutgoing passes are called and it's your responsibility to appropriately return the response by listening and acting on the proxyRes event
82
+ /** If set to true, none of the webOutgoing passes are called and it's your responsibility to appropriately return the response by listening and acting on the proxyRes event */
82
83
selfHandleResponse ?: boolean ;
83
- // Buffer
84
+ /** Buffer */
84
85
buffer ?: Stream ;
85
86
}
86
87
87
- export class ProxyServer extends EventEmitter {
88
- public readonly ws ;
89
- public readonly web ;
88
+ export type ErrorCallback =
89
+ (
90
+ err : Error ,
91
+ req : http . IncomingMessage ,
92
+ res : http . ServerResponse | net . Socket ,
93
+ target ?: ProxyTargetUrl ,
94
+ ) => void ;
95
+
96
+ type ProxyServerEventMap = {
97
+ error : Parameters < ErrorCallback > ;
98
+ start : [
99
+ req : http . IncomingMessage ,
100
+ res : http . ServerResponse ,
101
+ target : ProxyTargetUrl ,
102
+ ] ;
103
+ open : [ socket : net . Socket ] ;
104
+ proxyReq : [
105
+ proxyReq : http . ClientRequest ,
106
+ req : http . IncomingMessage ,
107
+ res : http . ServerResponse ,
108
+ options : ServerOptions ,
109
+ ] ;
110
+ proxyRes : [
111
+ proxyRes : http . IncomingMessage ,
112
+ req : http . IncomingMessage ,
113
+ res : http . ServerResponse ,
114
+ ] ;
115
+ proxyReqWs : [
116
+ proxyReq : http . ClientRequest ,
117
+ req : http . IncomingMessage ,
118
+ socket : net . Socket ,
119
+ options : ServerOptions ,
120
+ head : any ,
121
+ ] ;
122
+ econnreset : [
123
+ err : Error ,
124
+ req : http . IncomingMessage ,
125
+ res : http . ServerResponse ,
126
+ target : ProxyTargetUrl ,
127
+ ] ;
128
+ end : [
129
+ req : http . IncomingMessage ,
130
+ res : http . ServerResponse ,
131
+ proxyRes : http . IncomingMessage ,
132
+ ] ;
133
+ close : [
134
+ proxyRes : http . IncomingMessage ,
135
+ proxySocket : net . Socket ,
136
+ proxyHead : any ,
137
+ ] ;
138
+ }
139
+
140
+ export class ProxyServer extends EventEmitter < ProxyServerEventMap > {
141
+ /**
142
+ * Used for proxying WS(S) requests
143
+ * @param req - Client request.
144
+ * @param socket - Client socket.
145
+ * @param head - Client head.
146
+ * @param options - Additional options.
147
+ */
148
+ public readonly ws : (
149
+ ...args :
150
+ [
151
+ req : http . IncomingMessage ,
152
+ socket : any ,
153
+ head : any ,
154
+ options ?: ServerOptions ,
155
+ callback ?: ErrorCallback ,
156
+ ]
157
+ | [
158
+ req : http . IncomingMessage ,
159
+ socket : any ,
160
+ head : any ,
161
+ callback ?: ErrorCallback ,
162
+ ]
163
+ ) => void ;
164
+
165
+ /**
166
+ * Used for proxying regular HTTP(S) requests
167
+ * @param req - Client request.
168
+ * @param res - Client response.
169
+ * @param options - Additional options.
170
+ */
171
+ public readonly web : (
172
+ ...args :
173
+ [
174
+ req : http . IncomingMessage ,
175
+ res : http . ServerResponse ,
176
+ options : ServerOptions ,
177
+ callback ?: ErrorCallback ,
178
+ ]
179
+ | [
180
+ req : http . IncomingMessage ,
181
+ res : http . ServerResponse ,
182
+ callback ?: ErrorCallback
183
+ ]
184
+ ) => void ;
90
185
91
186
private options : ServerOptions ;
92
187
private webPasses ;
93
188
private wsPasses ;
94
189
private _server ?;
95
190
191
+ /**
192
+ * Creates the proxy server with specified options.
193
+ * @param options - Config object passed to the proxy
194
+ */
96
195
constructor ( options : ServerOptions = { } ) {
97
196
super ( ) ;
98
197
log ( "creating a ProxyServer" , options ) ;
@@ -105,6 +204,33 @@ export class ProxyServer extends EventEmitter {
105
204
this . on ( "error" , this . onError ) ;
106
205
}
107
206
207
+ /**
208
+ * Creates the proxy server with specified options.
209
+ * @param options Config object passed to the proxy
210
+ * @returns Proxy object with handlers for `ws` and `web` requests
211
+ */
212
+ static createProxyServer ( options ?: ServerOptions ) : ProxyServer {
213
+ return new ProxyServer ( options ) ;
214
+ }
215
+
216
+ /**
217
+ * Creates the proxy server with specified options.
218
+ * @param options Config object passed to the proxy
219
+ * @returns Proxy object with handlers for `ws` and `web` requests
220
+ */
221
+ static createServer ( options ?: ServerOptions ) : ProxyServer {
222
+ return new ProxyServer ( options ) ;
223
+ }
224
+
225
+ /**
226
+ * Creates the proxy server with specified options.
227
+ * @param options Config object passed to the proxy
228
+ * @returns Proxy object with handlers for `ws` and `web` requests
229
+ */
230
+ static createProxy ( options ?: ServerOptions ) : ProxyServer {
231
+ return new ProxyServer ( options ) ;
232
+ }
233
+
108
234
// createRightProxy - Returns a function that when called creates the loader for
109
235
// either `ws` or `web`'s passes.
110
236
createRightProxy = ( type : ProxyType ) : Function => {
@@ -124,8 +250,8 @@ export class ProxyServer extends EventEmitter {
124
250
// and there's no way for a user of http-proxy-3 to get ahold
125
251
// of this res object and attach their own error handler until
126
252
// after the passes. So we better attach one ASAP right here:
127
- res . on ( "error" , ( ... args ) => {
128
- this . emit ( "error" , ... args ) ;
253
+ ( res as net . Socket ) . on ( "error" , ( err ) => {
254
+ this . emit ( "error" , err , req , res ) ;
129
255
} ) ;
130
256
}
131
257
let counter = args . length - 1 ;
@@ -158,7 +284,7 @@ export class ProxyServer extends EventEmitter {
158
284
}
159
285
160
286
if ( ! requestOptions . target && ! requestOptions . forward ) {
161
- this . emit ( "error" , new Error ( "Must set target or forward" ) ) ;
287
+ this . emit ( "error" , new Error ( "Must set target or forward" ) , req , res ) ;
162
288
return ;
163
289
}
164
290
@@ -187,6 +313,11 @@ export class ProxyServer extends EventEmitter {
187
313
}
188
314
} ;
189
315
316
+ /**
317
+ * A function that wraps the object in a webserver, for your convenience
318
+ * @param port - Port to listen on
319
+ * @param hostname - The hostname to listen on
320
+ */
190
321
listen = ( port : number , hostname ?: string ) => {
191
322
log ( "listen" , { port, hostname } ) ;
192
323
@@ -210,6 +341,9 @@ export class ProxyServer extends EventEmitter {
210
341
return this . _server ?. address ( ) ;
211
342
} ;
212
343
344
+ /**
345
+ * A function that closes the inner webserver and stops listening on given port
346
+ */
213
347
close = ( cb ?: Function ) => {
214
348
if ( this . _server == null ) {
215
349
cb ?.( ) ;
0 commit comments