3
3
// This file is licensed under the MIT License.
4
4
// License text available at https://opensource.org/licenses/MIT
5
5
6
- import { IncomingMessage , ServerResponse } from 'http' ;
7
6
import * as http from 'http' ;
8
7
import * as https from 'https' ;
9
8
import { AddressInfo } from 'net' ;
10
-
11
9
import * as pEvent from 'p-event' ;
12
-
13
- export type RequestListener = (
14
- req : IncomingMessage ,
15
- res : ServerResponse ,
16
- ) => void ;
17
-
18
- /**
19
- * Basic HTTP server listener options
20
- *
21
- * @export
22
- * @interface ListenerOptions
23
- */
24
- export interface ListenerOptions {
25
- host ?: string ;
26
- port ?: number ;
27
- }
28
-
29
- /**
30
- * HTTP server options
31
- *
32
- * @export
33
- * @interface HttpOptions
34
- */
35
- export interface HttpOptions extends ListenerOptions {
36
- protocol ?: 'http' ;
37
- }
38
-
39
- /**
40
- * HTTPS server options
41
- *
42
- * @export
43
- * @interface HttpsOptions
44
- */
45
- export interface HttpsOptions extends ListenerOptions , https . ServerOptions {
46
- protocol : 'https' ;
47
- }
48
-
49
- /**
50
- * Possible server options
51
- *
52
- * @export
53
- * @type HttpServerOptions
54
- */
55
- export type HttpServerOptions = HttpOptions | HttpsOptions ;
56
-
57
- /**
58
- * Supported protocols
59
- *
60
- * @export
61
- * @type HttpProtocol
62
- */
63
- export type HttpProtocol = 'http' | 'https' ; // Will be extended to `http2` in the future
10
+ import {
11
+ HttpProtocol ,
12
+ HttpServer ,
13
+ HttpServerOptions ,
14
+ RequestListener ,
15
+ ProtocolServerFactory ,
16
+ } from './types' ;
64
17
65
18
/**
66
19
* HTTP / HTTPS server used by LoopBack's RestServer
67
20
*
68
21
* @export
69
22
* @class HttpServer
70
23
*/
71
- export class HttpServer {
24
+ export class DefaultHttpServer implements HttpServer {
72
25
private _port : number ;
73
26
private _host ?: string ;
74
27
private _listening : boolean = false ;
75
- private _protocol : HttpProtocol ;
28
+ protected _protocol : string ;
29
+ private _urlScheme : string ;
76
30
private _address : AddressInfo ;
77
- private requestListener : RequestListener ;
78
- readonly server : http . Server | https . Server ;
79
- private serverOptions ?: HttpServerOptions ;
31
+ protected readonly requestListener : RequestListener ;
32
+ protected _server : http . Server | https . Server ;
33
+ protected readonly serverOptions : HttpServerOptions ;
34
+
35
+ protected protocolServerFactories : ProtocolServerFactory [ ] ;
80
36
81
37
/**
82
38
* @param requestListener
83
39
* @param serverOptions
84
40
*/
85
41
constructor (
86
42
requestListener : RequestListener ,
87
- serverOptions ?: HttpServerOptions ,
43
+ serverOptions : HttpServerOptions = { } ,
44
+ protocolServerFactories ?: ProtocolServerFactory [ ] ,
88
45
) {
89
46
this . requestListener = requestListener ;
47
+ serverOptions = serverOptions || { } ;
90
48
this . serverOptions = serverOptions ;
91
- this . _port = serverOptions ? serverOptions . port || 0 : 0 ;
92
- this . _host = serverOptions ? serverOptions . host : undefined ;
93
- this . _protocol = serverOptions ? serverOptions . protocol || 'http' : 'http' ;
94
- if ( this . _protocol === 'https' ) {
95
- this . server = https . createServer (
96
- this . serverOptions as https . ServerOptions ,
97
- this . requestListener ,
98
- ) ;
99
- } else {
100
- this . server = http . createServer ( this . requestListener ) ;
49
+ this . _port = serverOptions . port || 0 ;
50
+ this . _host = serverOptions . host || undefined ;
51
+ this . _protocol = serverOptions . protocol || 'http' ;
52
+ this . protocolServerFactories = protocolServerFactories || [
53
+ new HttpProtocolServerFactory ( ) ,
54
+ ] ;
55
+ const server = this . createServer ( ) ;
56
+ this . _server = server . server ;
57
+ this . _urlScheme = server . urlScheme ;
58
+ }
59
+
60
+ /**
61
+ * Create a server for the given protocol
62
+ */
63
+ protected createServer ( ) {
64
+ for ( const factory of this . protocolServerFactories ) {
65
+ if ( factory . supports ( this . _protocol , this . serverOptions ) ) {
66
+ const server = factory . createServer (
67
+ this . _protocol ,
68
+ this . requestListener ,
69
+ this . serverOptions ,
70
+ ) ;
71
+ if ( server ) {
72
+ return server ;
73
+ }
74
+ }
101
75
}
76
+ throw new Error ( `The ${ this . _protocol } protocol is not supported` ) ;
102
77
}
103
78
104
79
/**
105
80
* Starts the HTTP / HTTPS server
106
81
*/
107
82
public async start ( ) {
108
- this . server . listen ( this . _port , this . _host ) ;
109
- await pEvent ( this . server , 'listening' ) ;
83
+ this . _server . listen ( this . _port , this . _host ) ;
84
+ await pEvent ( this . _server , 'listening' ) ;
110
85
this . _listening = true ;
111
- this . _address = this . server . address ( ) as AddressInfo ;
86
+ this . _address = this . _server . address ( ) as AddressInfo ;
112
87
}
113
88
114
89
/**
115
90
* Stops the HTTP / HTTPS server
116
91
*/
117
92
public async stop ( ) {
118
- if ( ! this . server ) return ;
119
- this . server . close ( ) ;
120
- await pEvent ( this . server , 'close' ) ;
93
+ if ( ! this . _server ) return ;
94
+ this . _server . close ( ) ;
95
+ await pEvent ( this . _server , 'close' ) ;
121
96
this . _listening = false ;
122
97
}
123
98
124
99
/**
125
100
* Protocol of the HTTP / HTTPS server
126
101
*/
127
- public get protocol ( ) : HttpProtocol {
128
- return this . _protocol ;
102
+ public get protocol ( ) : string {
103
+ return this . _urlScheme || this . _protocol ;
129
104
}
130
105
131
106
/**
@@ -147,13 +122,13 @@ export class HttpServer {
147
122
*/
148
123
public get url ( ) : string {
149
124
let host = this . host ;
150
- if ( this . _address . family === 'IPv6' ) {
125
+ if ( this . _address && this . _address . family === 'IPv6' ) {
151
126
if ( host === '::' ) host = '::1' ;
152
127
host = `[${ host } ]` ;
153
128
} else if ( host === '0.0.0.0' ) {
154
129
host = '127.0.0.1' ;
155
130
}
156
- return `${ this . _protocol } ://${ host } :${ this . port } ` ;
131
+ return `${ this . protocol } ://${ host } :${ this . port } ` ;
157
132
}
158
133
159
134
/**
@@ -163,10 +138,45 @@ export class HttpServer {
163
138
return this . _listening ;
164
139
}
165
140
141
+ public get server ( ) : http . Server | https . Server {
142
+ return this . _server ;
143
+ }
144
+
166
145
/**
167
146
* Address of the HTTP / HTTPS server
168
147
*/
169
148
public get address ( ) : AddressInfo | undefined {
170
149
return this . _listening ? this . _address : undefined ;
171
150
}
172
151
}
152
+
153
+ export class HttpProtocolServerFactory implements ProtocolServerFactory {
154
+ /**
155
+ * Supports http and https
156
+ * @param protocol
157
+ */
158
+ supports ( protocol : string ) {
159
+ return protocol === 'http' || protocol === 'https' ;
160
+ }
161
+
162
+ /**
163
+ * Create a server for the given protocol
164
+ */
165
+ createServer (
166
+ protocol : string ,
167
+ requestListener : RequestListener ,
168
+ serverOptions : HttpServerOptions ,
169
+ ) {
170
+ if ( protocol === 'https' ) {
171
+ const server = https . createServer (
172
+ serverOptions as https . ServerOptions ,
173
+ requestListener ,
174
+ ) ;
175
+ return { server, urlScheme : protocol } ;
176
+ } else if ( protocol === 'http' ) {
177
+ const server = http . createServer ( requestListener ) ;
178
+ return { server, urlScheme : protocol } ;
179
+ }
180
+ throw new Error ( `The ${ protocol } protocol is not supported` ) ;
181
+ }
182
+ }
0 commit comments