@loopback/http-server 2.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +25 -0
- package/README.md +64 -0
- package/dist/http-server.d.ts +103 -0
- package/dist/http-server.js +184 -0
- package/dist/http-server.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/package.json +49 -0
- package/src/http-server.ts +281 -0
- package/src/index.ts +15 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
Copyright (c) IBM Corp. 2018,2019.
|
|
2
|
+
Node module: @loopback/http-server
|
|
3
|
+
This project is licensed under the MIT License, full text below.
|
|
4
|
+
|
|
5
|
+
--------
|
|
6
|
+
|
|
7
|
+
MIT license
|
|
8
|
+
|
|
9
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
10
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
11
|
+
in the Software without restriction, including without limitation the rights
|
|
12
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
13
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
14
|
+
furnished to do so, subject to the following conditions:
|
|
15
|
+
|
|
16
|
+
The above copyright notice and this permission notice shall be included in
|
|
17
|
+
all copies or substantial portions of the Software.
|
|
18
|
+
|
|
19
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
20
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
21
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
22
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
23
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
24
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
25
|
+
THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# @loopback/http-server
|
|
2
|
+
|
|
3
|
+
This package implements the HTTP / HTTPS server endpoint for LoopBack 4 apps.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This is an internal package used by LoopBack 4 for creating HTTP / HTTPS server.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
To use this package, you'll need to install `@loopback/http-server`.
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
npm i @loopback/http-server
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
`@loopback/http-server` should be instantiated with a request handler function,
|
|
20
|
+
and an HTTP / HTTPS options object.
|
|
21
|
+
|
|
22
|
+
```js
|
|
23
|
+
const httpServer = new HttpServer(
|
|
24
|
+
(req, res) => {
|
|
25
|
+
res.end('Hello world');
|
|
26
|
+
},
|
|
27
|
+
{port: 3000, host: ''},
|
|
28
|
+
);
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Instance methods of `HttpServer`.
|
|
32
|
+
|
|
33
|
+
| Method | Description |
|
|
34
|
+
| --------- | ----------------- |
|
|
35
|
+
| `start()` | Starts the server |
|
|
36
|
+
| `stop()` | Stops the server |
|
|
37
|
+
|
|
38
|
+
Instance properties of `HttpServer`.
|
|
39
|
+
|
|
40
|
+
| Property | Description |
|
|
41
|
+
| ---------- | ---------------------- |
|
|
42
|
+
| `address` | Address details |
|
|
43
|
+
| `host` | host of the server |
|
|
44
|
+
| `port` | port of the server |
|
|
45
|
+
| `protocol` | protocol of the server |
|
|
46
|
+
| `url` | url the server |
|
|
47
|
+
|
|
48
|
+
## Contributions
|
|
49
|
+
|
|
50
|
+
- [Guidelines](https://github.com/loopbackio/loopback-next/wiki/Contributing#guidelines)
|
|
51
|
+
- [Join the team](https://github.com/loopbackio/loopback-next/issues/110)
|
|
52
|
+
|
|
53
|
+
## Tests
|
|
54
|
+
|
|
55
|
+
Run `npm test` from the root folder.
|
|
56
|
+
|
|
57
|
+
## Contributors
|
|
58
|
+
|
|
59
|
+
See
|
|
60
|
+
[all contributors](https://github.com/loopbackio/loopback-next/graphs/contributors).
|
|
61
|
+
|
|
62
|
+
## License
|
|
63
|
+
|
|
64
|
+
MIT
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import http, { IncomingMessage, Server, ServerResponse } from 'http';
|
|
3
|
+
import https from 'https';
|
|
4
|
+
import { AddressInfo, ListenOptions } from 'net';
|
|
5
|
+
/**
|
|
6
|
+
* Request listener function for http/https requests
|
|
7
|
+
*/
|
|
8
|
+
export declare type RequestListener = (req: IncomingMessage, res: ServerResponse) => void;
|
|
9
|
+
/**
|
|
10
|
+
* The following are for configuring properties which are directly set on
|
|
11
|
+
* https://nodejs.org/api/http.html#http_class_http_server and
|
|
12
|
+
* https://nodejs.org/api/net.html#net_class_net_server
|
|
13
|
+
*/
|
|
14
|
+
export declare type HttpServerProperties = Pick<Server, 'keepAliveTimeout' | 'headersTimeout' | 'maxConnections' | 'maxHeadersCount' | 'timeout'>;
|
|
15
|
+
/**
|
|
16
|
+
* Base options that are common to http and https servers
|
|
17
|
+
*/
|
|
18
|
+
export interface BaseHttpOptions extends ListenOptions, Partial<HttpServerProperties> {
|
|
19
|
+
/**
|
|
20
|
+
* The `gracePeriodForClose` property controls how to stop the server
|
|
21
|
+
* gracefully. Its value is the number of milliseconds to wait before
|
|
22
|
+
* in-flight requests finish when the server is being stopped. With this
|
|
23
|
+
* setting, we also reject new requests from existing keep-alive connections
|
|
24
|
+
* in addition to stopping accepting new connections.
|
|
25
|
+
*
|
|
26
|
+
* Defaults to Infinity (don't force-close). If you want to immediately
|
|
27
|
+
* destroy all sockets set its value to `0`.
|
|
28
|
+
*
|
|
29
|
+
* See {@link https://www.npmjs.com/package/stoppable | stoppable}
|
|
30
|
+
*/
|
|
31
|
+
gracePeriodForClose?: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* HTTP server options
|
|
35
|
+
*/
|
|
36
|
+
export interface HttpOptions extends BaseHttpOptions {
|
|
37
|
+
protocol?: 'http';
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* HTTPS server options
|
|
41
|
+
*/
|
|
42
|
+
export interface HttpsOptions extends BaseHttpOptions, https.ServerOptions {
|
|
43
|
+
protocol: 'https';
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Possible server options
|
|
47
|
+
*
|
|
48
|
+
*/
|
|
49
|
+
export declare type HttpServerOptions = HttpOptions | HttpsOptions;
|
|
50
|
+
/**
|
|
51
|
+
* Supported protocols
|
|
52
|
+
*
|
|
53
|
+
*/
|
|
54
|
+
export declare type HttpProtocol = 'http' | 'https';
|
|
55
|
+
/**
|
|
56
|
+
* HTTP / HTTPS server used by LoopBack's RestServer
|
|
57
|
+
*/
|
|
58
|
+
export declare class HttpServer {
|
|
59
|
+
private _listening;
|
|
60
|
+
private _protocol;
|
|
61
|
+
private _address;
|
|
62
|
+
private requestListener;
|
|
63
|
+
readonly server: http.Server | https.Server;
|
|
64
|
+
private _stoppable;
|
|
65
|
+
readonly serverOptions: HttpServerOptions;
|
|
66
|
+
/**
|
|
67
|
+
* @param requestListener
|
|
68
|
+
* @param serverOptions
|
|
69
|
+
*/
|
|
70
|
+
constructor(requestListener: RequestListener, serverOptions?: HttpServerOptions);
|
|
71
|
+
/**
|
|
72
|
+
* Starts the HTTP / HTTPS server
|
|
73
|
+
*/
|
|
74
|
+
start(): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* Stops the HTTP / HTTPS server
|
|
77
|
+
*/
|
|
78
|
+
stop(): Promise<void>;
|
|
79
|
+
/**
|
|
80
|
+
* Protocol of the HTTP / HTTPS server
|
|
81
|
+
*/
|
|
82
|
+
get protocol(): HttpProtocol;
|
|
83
|
+
/**
|
|
84
|
+
* Port number of the HTTP / HTTPS server
|
|
85
|
+
*/
|
|
86
|
+
get port(): number;
|
|
87
|
+
/**
|
|
88
|
+
* Host of the HTTP / HTTPS server
|
|
89
|
+
*/
|
|
90
|
+
get host(): string | undefined;
|
|
91
|
+
/**
|
|
92
|
+
* URL of the HTTP / HTTPS server
|
|
93
|
+
*/
|
|
94
|
+
get url(): string;
|
|
95
|
+
/**
|
|
96
|
+
* State of the HTTP / HTTPS server
|
|
97
|
+
*/
|
|
98
|
+
get listening(): boolean;
|
|
99
|
+
/**
|
|
100
|
+
* Address of the HTTP / HTTPS server
|
|
101
|
+
*/
|
|
102
|
+
get address(): string | AddressInfo | undefined;
|
|
103
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright IBM Corp. 2018,2020. All Rights Reserved.
|
|
3
|
+
// Node module: @loopback/http-server
|
|
4
|
+
// This file is licensed under the MIT License.
|
|
5
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.HttpServer = void 0;
|
|
8
|
+
const tslib_1 = require("tslib");
|
|
9
|
+
const assert_1 = tslib_1.__importDefault(require("assert"));
|
|
10
|
+
const debug_1 = tslib_1.__importDefault(require("debug"));
|
|
11
|
+
const events_1 = require("events");
|
|
12
|
+
const http_1 = tslib_1.__importDefault(require("http"));
|
|
13
|
+
const https_1 = tslib_1.__importDefault(require("https"));
|
|
14
|
+
const os_1 = tslib_1.__importDefault(require("os"));
|
|
15
|
+
const stoppable_1 = tslib_1.__importDefault(require("stoppable"));
|
|
16
|
+
const debug = debug_1.default('loopback:http-server');
|
|
17
|
+
/**
|
|
18
|
+
* HTTP / HTTPS server used by LoopBack's RestServer
|
|
19
|
+
*/
|
|
20
|
+
class HttpServer {
|
|
21
|
+
/**
|
|
22
|
+
* @param requestListener
|
|
23
|
+
* @param serverOptions
|
|
24
|
+
*/
|
|
25
|
+
constructor(requestListener, serverOptions) {
|
|
26
|
+
var _a;
|
|
27
|
+
this._listening = false;
|
|
28
|
+
debug('Http server options', serverOptions);
|
|
29
|
+
this.requestListener = requestListener;
|
|
30
|
+
this.serverOptions = {
|
|
31
|
+
port: 0,
|
|
32
|
+
host: undefined,
|
|
33
|
+
...serverOptions,
|
|
34
|
+
};
|
|
35
|
+
if (this.serverOptions.path) {
|
|
36
|
+
debug('Http server with IPC path %s', this.serverOptions.path);
|
|
37
|
+
const ipcPath = this.serverOptions.path;
|
|
38
|
+
checkNamedPipe(ipcPath);
|
|
39
|
+
// Remove `port` so that `path` is honored
|
|
40
|
+
delete this.serverOptions.port;
|
|
41
|
+
}
|
|
42
|
+
this._protocol = serverOptions ? (_a = serverOptions.protocol) !== null && _a !== void 0 ? _a : 'http' : 'http';
|
|
43
|
+
if (this._protocol === 'https') {
|
|
44
|
+
this.server = https_1.default.createServer(this.serverOptions, this.requestListener);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
this.server = http_1.default.createServer(this.requestListener);
|
|
48
|
+
}
|
|
49
|
+
// Apply server properties
|
|
50
|
+
const { keepAliveTimeout, headersTimeout, maxConnections, maxHeadersCount, timeout, } = this.serverOptions;
|
|
51
|
+
if (keepAliveTimeout) {
|
|
52
|
+
this.server.keepAliveTimeout = keepAliveTimeout;
|
|
53
|
+
}
|
|
54
|
+
if (headersTimeout) {
|
|
55
|
+
this.server.headersTimeout = headersTimeout;
|
|
56
|
+
}
|
|
57
|
+
if (maxConnections) {
|
|
58
|
+
this.server.maxConnections = maxConnections;
|
|
59
|
+
}
|
|
60
|
+
if (maxHeadersCount) {
|
|
61
|
+
this.server.maxHeadersCount = maxHeadersCount;
|
|
62
|
+
}
|
|
63
|
+
if (timeout) {
|
|
64
|
+
this.server.timeout = timeout;
|
|
65
|
+
}
|
|
66
|
+
// Set up graceful stop for http server
|
|
67
|
+
if (typeof this.serverOptions.gracePeriodForClose === 'number') {
|
|
68
|
+
debug('Http server gracePeriodForClose %d', this.serverOptions.gracePeriodForClose);
|
|
69
|
+
this._stoppable = stoppable_1.default(this.server, this.serverOptions.gracePeriodForClose);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Starts the HTTP / HTTPS server
|
|
74
|
+
*/
|
|
75
|
+
async start() {
|
|
76
|
+
debug('Starting http server', this.serverOptions);
|
|
77
|
+
this.server.listen(this.serverOptions);
|
|
78
|
+
await events_1.once(this.server, 'listening');
|
|
79
|
+
this._listening = true;
|
|
80
|
+
const address = this.server.address();
|
|
81
|
+
assert_1.default(address != null);
|
|
82
|
+
this._address = address;
|
|
83
|
+
debug('Http server is listening on', this.url);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Stops the HTTP / HTTPS server
|
|
87
|
+
*/
|
|
88
|
+
async stop() {
|
|
89
|
+
if (!this._listening)
|
|
90
|
+
return;
|
|
91
|
+
debug('Stopping http server');
|
|
92
|
+
if (this._stoppable != null) {
|
|
93
|
+
debug('Stopping http server with graceful close');
|
|
94
|
+
this._stoppable.stop();
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
this.server.close();
|
|
98
|
+
}
|
|
99
|
+
await events_1.once(this.server, 'close');
|
|
100
|
+
this._listening = false;
|
|
101
|
+
debug('Http server is stopped');
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Protocol of the HTTP / HTTPS server
|
|
105
|
+
*/
|
|
106
|
+
get protocol() {
|
|
107
|
+
return this._protocol;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Port number of the HTTP / HTTPS server
|
|
111
|
+
*/
|
|
112
|
+
get port() {
|
|
113
|
+
var _a;
|
|
114
|
+
if (typeof this._address === 'string')
|
|
115
|
+
return 0;
|
|
116
|
+
return ((_a = this._address) === null || _a === void 0 ? void 0 : _a.port) || this.serverOptions.port;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Host of the HTTP / HTTPS server
|
|
120
|
+
*/
|
|
121
|
+
get host() {
|
|
122
|
+
var _a;
|
|
123
|
+
if (typeof this._address === 'string')
|
|
124
|
+
return undefined;
|
|
125
|
+
return ((_a = this._address) === null || _a === void 0 ? void 0 : _a.address) || this.serverOptions.host;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* URL of the HTTP / HTTPS server
|
|
129
|
+
*/
|
|
130
|
+
get url() {
|
|
131
|
+
if (typeof this._address === 'string') {
|
|
132
|
+
/* istanbul ignore if */
|
|
133
|
+
if (isWin32()) {
|
|
134
|
+
return this._address;
|
|
135
|
+
}
|
|
136
|
+
const basePath = encodeURIComponent(this._address);
|
|
137
|
+
return `${this.protocol}+unix://${basePath}`;
|
|
138
|
+
}
|
|
139
|
+
let host = this.host;
|
|
140
|
+
if (this._address.family === 'IPv6') {
|
|
141
|
+
if (host === '::')
|
|
142
|
+
host = '::1';
|
|
143
|
+
host = `[${host}]`;
|
|
144
|
+
}
|
|
145
|
+
else if (host === '0.0.0.0') {
|
|
146
|
+
host = '127.0.0.1';
|
|
147
|
+
}
|
|
148
|
+
return `${this._protocol}://${host}:${this.port}`;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* State of the HTTP / HTTPS server
|
|
152
|
+
*/
|
|
153
|
+
get listening() {
|
|
154
|
+
return this._listening;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Address of the HTTP / HTTPS server
|
|
158
|
+
*/
|
|
159
|
+
get address() {
|
|
160
|
+
return this._listening ? this._address : undefined;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
exports.HttpServer = HttpServer;
|
|
164
|
+
/**
|
|
165
|
+
* Makes sure `path` conform to named pipe naming requirement on Windows
|
|
166
|
+
*
|
|
167
|
+
* See https://nodejs.org/api/net.html#net_identifying_paths_for_ipc_connections
|
|
168
|
+
*
|
|
169
|
+
* @param ipcPath - Named pipe path
|
|
170
|
+
*/
|
|
171
|
+
function checkNamedPipe(ipcPath) {
|
|
172
|
+
/* istanbul ignore if */
|
|
173
|
+
if (isWin32()) {
|
|
174
|
+
const pipes = ['\\\\?\\pipe\\', '\\\\.\\pipe\\'];
|
|
175
|
+
assert_1.default(pipes.some(p => ipcPath.startsWith(p)), `Named pipe ${ipcPath} does NOT start with + ${pipes.join(' or ')}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Check if it's Windows OS
|
|
180
|
+
*/
|
|
181
|
+
function isWin32() {
|
|
182
|
+
return os_1.default.platform() === 'win32';
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=http-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-server.js","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,qCAAqC;AACrC,+CAA+C;AAC/C,gEAAgE;;;;AAEhE,4DAA4B;AAC5B,0DAAiC;AACjC,mCAA4B;AAC5B,wDAAmE;AACnE,0DAA0B;AAE1B,oDAAoB;AACpB,kEAAkC;AAClC,MAAM,KAAK,GAAG,eAAY,CAAC,sBAAsB,CAAC,CAAC;AAuEnD;;GAEG;AACH,MAAa,UAAU;IASrB;;;OAGG;IACH,YACE,eAAgC,EAChC,aAAiC;;QAd3B,eAAU,GAAG,KAAK,CAAC;QAgBzB,KAAK,CAAC,qBAAqB,EAAE,aAAa,CAAC,CAAC;QAC5C,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;QACvC,IAAI,CAAC,aAAa,GAAG;YACnB,IAAI,EAAE,CAAC;YACP,IAAI,EAAE,SAAS;YACf,GAAG,aAAa;SACjB,CAAC;QACF,IAAI,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE;YAC3B,KAAK,CAAC,8BAA8B,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;YAC/D,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC;YACxC,cAAc,CAAC,OAAO,CAAC,CAAC;YACxB,0CAA0C;YAC1C,OAAO,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC;SAChC;QACD,IAAI,CAAC,SAAS,GAAG,aAAa,CAAC,CAAC,CAAC,MAAA,aAAa,CAAC,QAAQ,mCAAI,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;QAC3E,IAAI,IAAI,CAAC,SAAS,KAAK,OAAO,EAAE;YAC9B,IAAI,CAAC,MAAM,GAAG,eAAK,CAAC,YAAY,CAC9B,IAAI,CAAC,aAAoC,EACzC,IAAI,CAAC,eAAe,CACrB,CAAC;SACH;aAAM;YACL,IAAI,CAAC,MAAM,GAAG,cAAI,CAAC,YAAY,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;SACvD;QAED,0BAA0B;QAC1B,MAAM,EACJ,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,eAAe,EACf,OAAO,GACR,GAAG,IAAI,CAAC,aAAa,CAAC;QACvB,IAAI,gBAAgB,EAAE;YACpB,IAAI,CAAC,MAAM,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;SACjD;QACD,IAAI,cAAc,EAAE;YAClB,IAAI,CAAC,MAAM,CAAC,cAAc,GAAG,cAAc,CAAC;SAC7C;QACD,IAAI,cAAc,EAAE;YAClB,IAAI,CAAC,MAAM,CAAC,cAAc,GAAG,cAAc,CAAC;SAC7C;QACD,IAAI,eAAe,EAAE;YACnB,IAAI,CAAC,MAAM,CAAC,eAAe,GAAG,eAAe,CAAC;SAC/C;QACD,IAAI,OAAO,EAAE;YACX,IAAI,CAAC,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC;SAC/B;QAED,uCAAuC;QACvC,IAAI,OAAO,IAAI,CAAC,aAAa,CAAC,mBAAmB,KAAK,QAAQ,EAAE;YAC9D,KAAK,CACH,oCAAoC,EACpC,IAAI,CAAC,aAAa,CAAC,mBAAmB,CACvC,CAAC;YACF,IAAI,CAAC,UAAU,GAAG,mBAAS,CACzB,IAAI,CAAC,MAAM,EACX,IAAI,CAAC,aAAa,CAAC,mBAAmB,CACvC,CAAC;SACH;IACH,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,KAAK;QAChB,KAAK,CAAC,sBAAsB,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QAClD,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACvC,MAAM,aAAI,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;QACrC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QAEvB,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACtC,gBAAM,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC;QACxB,IAAI,CAAC,QAAQ,GAAG,OAAQ,CAAC;QACzB,KAAK,CAAC,6BAA6B,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;IACjD,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,IAAI;QACf,IAAI,CAAC,IAAI,CAAC,UAAU;YAAE,OAAO;QAC7B,KAAK,CAAC,sBAAsB,CAAC,CAAC;QAC9B,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,EAAE;YAC3B,KAAK,CAAC,0CAA0C,CAAC,CAAC;YAClD,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;SACxB;aAAM;YACL,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;SACrB;QACD,MAAM,aAAI,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACjC,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QACxB,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAClC,CAAC;IAED;;OAEG;IACH,IAAW,QAAQ;QACjB,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED;;OAEG;IACH,IAAW,IAAI;;QACb,IAAI,OAAO,IAAI,CAAC,QAAQ,KAAK,QAAQ;YAAE,OAAO,CAAC,CAAC;QAChD,OAAO,CAAA,MAAA,IAAI,CAAC,QAAQ,0CAAE,IAAI,KAAI,IAAI,CAAC,aAAa,CAAC,IAAK,CAAC;IACzD,CAAC;IAED;;OAEG;IACH,IAAW,IAAI;;QACb,IAAI,OAAO,IAAI,CAAC,QAAQ,KAAK,QAAQ;YAAE,OAAO,SAAS,CAAC;QACxD,OAAO,CAAA,MAAA,IAAI,CAAC,QAAQ,0CAAE,OAAO,KAAI,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC;IAC3D,CAAC;IAED;;OAEG;IACH,IAAW,GAAG;QACZ,IAAI,OAAO,IAAI,CAAC,QAAQ,KAAK,QAAQ,EAAE;YACrC,wBAAwB;YACxB,IAAI,OAAO,EAAE,EAAE;gBACb,OAAO,IAAI,CAAC,QAAQ,CAAC;aACtB;YACD,MAAM,QAAQ,GAAG,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACnD,OAAO,GAAG,IAAI,CAAC,QAAQ,WAAW,QAAQ,EAAE,CAAC;SAC9C;QACD,IAAI,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACrB,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,MAAM,EAAE;YACnC,IAAI,IAAI,KAAK,IAAI;gBAAE,IAAI,GAAG,KAAK,CAAC;YAChC,IAAI,GAAG,IAAI,IAAI,GAAG,CAAC;SACpB;aAAM,IAAI,IAAI,KAAK,SAAS,EAAE;YAC7B,IAAI,GAAG,WAAW,CAAC;SACpB;QACD,OAAO,GAAG,IAAI,CAAC,SAAS,MAAM,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;IACpD,CAAC;IAED;;OAEG;IACH,IAAW,SAAS;QAClB,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED;;OAEG;IACH,IAAW,OAAO;QAChB,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;IACrD,CAAC;CACF;AAxKD,gCAwKC;AAED;;;;;;GAMG;AACH,SAAS,cAAc,CAAC,OAAe;IACrC,wBAAwB;IACxB,IAAI,OAAO,EAAE,EAAE;QACb,MAAM,KAAK,GAAG,CAAC,eAAe,EAAE,eAAe,CAAC,CAAC;QACjD,gBAAM,CACJ,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EACtC,cAAc,OAAO,0BAA0B,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CACpE,CAAC;KACH;AACH,CAAC;AAED;;GAEG;AACH,SAAS,OAAO;IACd,OAAO,YAAE,CAAC,QAAQ,EAAE,KAAK,OAAO,CAAC;AACnC,CAAC"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright IBM Corp. 2018,2020. All Rights Reserved.
|
|
3
|
+
// Node module: @loopback/http-server
|
|
4
|
+
// This file is licensed under the MIT License.
|
|
5
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const tslib_1 = require("tslib");
|
|
8
|
+
/**
|
|
9
|
+
* HTTP / HTTPS server endpoints for LoopBack 4 apps.
|
|
10
|
+
*
|
|
11
|
+
* @remarks
|
|
12
|
+
* A package used by LoopBack 4 for creating HTTP / HTTPS server.
|
|
13
|
+
*
|
|
14
|
+
* @packageDocumentation
|
|
15
|
+
*/
|
|
16
|
+
tslib_1.__exportStar(require("./http-server"), exports);
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,qCAAqC;AACrC,+CAA+C;AAC/C,gEAAgE;;;AAEhE;;;;;;;GAOG;AAEH,wDAA8B"}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@loopback/http-server",
|
|
3
|
+
"description": "A wrapper for creating HTTP/HTTPS servers",
|
|
4
|
+
"version": "2.5.3",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"author": "IBM Corp.",
|
|
9
|
+
"copyright.owner": "IBM Corp.",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/loopbackio/loopback-next.git",
|
|
13
|
+
"directory": "packages/http-server"
|
|
14
|
+
},
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": "^10.16 || 12 || 14 || 16"
|
|
17
|
+
},
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "lb-tsc",
|
|
20
|
+
"clean": "lb-clean loopback-http-server*.tgz dist *.tsbuildinfo package",
|
|
21
|
+
"pretest": "npm run build",
|
|
22
|
+
"test": "lb-mocha \"dist/__tests__/**/*.js\"",
|
|
23
|
+
"verify": "npm pack && tar xf loopback-http-server*.tgz && tree package && npm run clean"
|
|
24
|
+
},
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"README.md",
|
|
30
|
+
"dist",
|
|
31
|
+
"src",
|
|
32
|
+
"!*/__tests__"
|
|
33
|
+
],
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"debug": "^4.3.2",
|
|
36
|
+
"stoppable": "^1.1.0",
|
|
37
|
+
"tslib": "^2.3.1"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@loopback/build": "^7.0.1",
|
|
41
|
+
"@loopback/core": "^2.17.0",
|
|
42
|
+
"@loopback/eslint-config": "^11.0.1",
|
|
43
|
+
"@loopback/testlab": "^3.4.3",
|
|
44
|
+
"@types/debug": "^4.1.7",
|
|
45
|
+
"@types/node": "^10.17.60",
|
|
46
|
+
"@types/stoppable": "^1.1.1"
|
|
47
|
+
},
|
|
48
|
+
"gitHead": "1df36bb1ee2e513d9e197bd6010c4cfb296d50b8"
|
|
49
|
+
}
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
// Copyright IBM Corp. 2018,2020. All Rights Reserved.
|
|
2
|
+
// Node module: @loopback/http-server
|
|
3
|
+
// This file is licensed under the MIT License.
|
|
4
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
5
|
+
|
|
6
|
+
import assert from 'assert';
|
|
7
|
+
import debugFactory from 'debug';
|
|
8
|
+
import {once} from 'events';
|
|
9
|
+
import http, {IncomingMessage, Server, ServerResponse} from 'http';
|
|
10
|
+
import https from 'https';
|
|
11
|
+
import {AddressInfo, ListenOptions} from 'net';
|
|
12
|
+
import os from 'os';
|
|
13
|
+
import stoppable from 'stoppable';
|
|
14
|
+
const debug = debugFactory('loopback:http-server');
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Request listener function for http/https requests
|
|
18
|
+
*/
|
|
19
|
+
export type RequestListener = (
|
|
20
|
+
req: IncomingMessage,
|
|
21
|
+
res: ServerResponse,
|
|
22
|
+
) => void;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The following are for configuring properties which are directly set on
|
|
26
|
+
* https://nodejs.org/api/http.html#http_class_http_server and
|
|
27
|
+
* https://nodejs.org/api/net.html#net_class_net_server
|
|
28
|
+
*/
|
|
29
|
+
export type HttpServerProperties = Pick<
|
|
30
|
+
Server,
|
|
31
|
+
| 'keepAliveTimeout'
|
|
32
|
+
| 'headersTimeout'
|
|
33
|
+
| 'maxConnections'
|
|
34
|
+
| 'maxHeadersCount'
|
|
35
|
+
| 'timeout'
|
|
36
|
+
>;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Base options that are common to http and https servers
|
|
40
|
+
*/
|
|
41
|
+
export interface BaseHttpOptions
|
|
42
|
+
extends ListenOptions,
|
|
43
|
+
Partial<HttpServerProperties> {
|
|
44
|
+
/**
|
|
45
|
+
* The `gracePeriodForClose` property controls how to stop the server
|
|
46
|
+
* gracefully. Its value is the number of milliseconds to wait before
|
|
47
|
+
* in-flight requests finish when the server is being stopped. With this
|
|
48
|
+
* setting, we also reject new requests from existing keep-alive connections
|
|
49
|
+
* in addition to stopping accepting new connections.
|
|
50
|
+
*
|
|
51
|
+
* Defaults to Infinity (don't force-close). If you want to immediately
|
|
52
|
+
* destroy all sockets set its value to `0`.
|
|
53
|
+
*
|
|
54
|
+
* See {@link https://www.npmjs.com/package/stoppable | stoppable}
|
|
55
|
+
*/
|
|
56
|
+
gracePeriodForClose?: number;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* HTTP server options
|
|
61
|
+
*/
|
|
62
|
+
export interface HttpOptions extends BaseHttpOptions {
|
|
63
|
+
protocol?: 'http';
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* HTTPS server options
|
|
68
|
+
*/
|
|
69
|
+
export interface HttpsOptions extends BaseHttpOptions, https.ServerOptions {
|
|
70
|
+
protocol: 'https';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Possible server options
|
|
75
|
+
*
|
|
76
|
+
*/
|
|
77
|
+
export type HttpServerOptions = HttpOptions | HttpsOptions;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Supported protocols
|
|
81
|
+
*
|
|
82
|
+
*/
|
|
83
|
+
export type HttpProtocol = 'http' | 'https'; // Will be extended to `http2` in the future
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* HTTP / HTTPS server used by LoopBack's RestServer
|
|
87
|
+
*/
|
|
88
|
+
export class HttpServer {
|
|
89
|
+
private _listening = false;
|
|
90
|
+
private _protocol: HttpProtocol;
|
|
91
|
+
private _address: string | AddressInfo;
|
|
92
|
+
private requestListener: RequestListener;
|
|
93
|
+
readonly server: http.Server | https.Server;
|
|
94
|
+
private _stoppable: stoppable.StoppableServer;
|
|
95
|
+
readonly serverOptions: HttpServerOptions;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* @param requestListener
|
|
99
|
+
* @param serverOptions
|
|
100
|
+
*/
|
|
101
|
+
constructor(
|
|
102
|
+
requestListener: RequestListener,
|
|
103
|
+
serverOptions?: HttpServerOptions,
|
|
104
|
+
) {
|
|
105
|
+
debug('Http server options', serverOptions);
|
|
106
|
+
this.requestListener = requestListener;
|
|
107
|
+
this.serverOptions = {
|
|
108
|
+
port: 0,
|
|
109
|
+
host: undefined,
|
|
110
|
+
...serverOptions,
|
|
111
|
+
};
|
|
112
|
+
if (this.serverOptions.path) {
|
|
113
|
+
debug('Http server with IPC path %s', this.serverOptions.path);
|
|
114
|
+
const ipcPath = this.serverOptions.path;
|
|
115
|
+
checkNamedPipe(ipcPath);
|
|
116
|
+
// Remove `port` so that `path` is honored
|
|
117
|
+
delete this.serverOptions.port;
|
|
118
|
+
}
|
|
119
|
+
this._protocol = serverOptions ? serverOptions.protocol ?? 'http' : 'http';
|
|
120
|
+
if (this._protocol === 'https') {
|
|
121
|
+
this.server = https.createServer(
|
|
122
|
+
this.serverOptions as https.ServerOptions,
|
|
123
|
+
this.requestListener,
|
|
124
|
+
);
|
|
125
|
+
} else {
|
|
126
|
+
this.server = http.createServer(this.requestListener);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Apply server properties
|
|
130
|
+
const {
|
|
131
|
+
keepAliveTimeout,
|
|
132
|
+
headersTimeout,
|
|
133
|
+
maxConnections,
|
|
134
|
+
maxHeadersCount,
|
|
135
|
+
timeout,
|
|
136
|
+
} = this.serverOptions;
|
|
137
|
+
if (keepAliveTimeout) {
|
|
138
|
+
this.server.keepAliveTimeout = keepAliveTimeout;
|
|
139
|
+
}
|
|
140
|
+
if (headersTimeout) {
|
|
141
|
+
this.server.headersTimeout = headersTimeout;
|
|
142
|
+
}
|
|
143
|
+
if (maxConnections) {
|
|
144
|
+
this.server.maxConnections = maxConnections;
|
|
145
|
+
}
|
|
146
|
+
if (maxHeadersCount) {
|
|
147
|
+
this.server.maxHeadersCount = maxHeadersCount;
|
|
148
|
+
}
|
|
149
|
+
if (timeout) {
|
|
150
|
+
this.server.timeout = timeout;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Set up graceful stop for http server
|
|
154
|
+
if (typeof this.serverOptions.gracePeriodForClose === 'number') {
|
|
155
|
+
debug(
|
|
156
|
+
'Http server gracePeriodForClose %d',
|
|
157
|
+
this.serverOptions.gracePeriodForClose,
|
|
158
|
+
);
|
|
159
|
+
this._stoppable = stoppable(
|
|
160
|
+
this.server,
|
|
161
|
+
this.serverOptions.gracePeriodForClose,
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Starts the HTTP / HTTPS server
|
|
168
|
+
*/
|
|
169
|
+
public async start() {
|
|
170
|
+
debug('Starting http server', this.serverOptions);
|
|
171
|
+
this.server.listen(this.serverOptions);
|
|
172
|
+
await once(this.server, 'listening');
|
|
173
|
+
this._listening = true;
|
|
174
|
+
|
|
175
|
+
const address = this.server.address();
|
|
176
|
+
assert(address != null);
|
|
177
|
+
this._address = address!;
|
|
178
|
+
debug('Http server is listening on', this.url);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Stops the HTTP / HTTPS server
|
|
183
|
+
*/
|
|
184
|
+
public async stop() {
|
|
185
|
+
if (!this._listening) return;
|
|
186
|
+
debug('Stopping http server');
|
|
187
|
+
if (this._stoppable != null) {
|
|
188
|
+
debug('Stopping http server with graceful close');
|
|
189
|
+
this._stoppable.stop();
|
|
190
|
+
} else {
|
|
191
|
+
this.server.close();
|
|
192
|
+
}
|
|
193
|
+
await once(this.server, 'close');
|
|
194
|
+
this._listening = false;
|
|
195
|
+
debug('Http server is stopped');
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Protocol of the HTTP / HTTPS server
|
|
200
|
+
*/
|
|
201
|
+
public get protocol(): HttpProtocol {
|
|
202
|
+
return this._protocol;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Port number of the HTTP / HTTPS server
|
|
207
|
+
*/
|
|
208
|
+
public get port(): number {
|
|
209
|
+
if (typeof this._address === 'string') return 0;
|
|
210
|
+
return this._address?.port || this.serverOptions.port!;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Host of the HTTP / HTTPS server
|
|
215
|
+
*/
|
|
216
|
+
public get host(): string | undefined {
|
|
217
|
+
if (typeof this._address === 'string') return undefined;
|
|
218
|
+
return this._address?.address || this.serverOptions.host;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* URL of the HTTP / HTTPS server
|
|
223
|
+
*/
|
|
224
|
+
public get url(): string {
|
|
225
|
+
if (typeof this._address === 'string') {
|
|
226
|
+
/* istanbul ignore if */
|
|
227
|
+
if (isWin32()) {
|
|
228
|
+
return this._address;
|
|
229
|
+
}
|
|
230
|
+
const basePath = encodeURIComponent(this._address);
|
|
231
|
+
return `${this.protocol}+unix://${basePath}`;
|
|
232
|
+
}
|
|
233
|
+
let host = this.host;
|
|
234
|
+
if (this._address.family === 'IPv6') {
|
|
235
|
+
if (host === '::') host = '::1';
|
|
236
|
+
host = `[${host}]`;
|
|
237
|
+
} else if (host === '0.0.0.0') {
|
|
238
|
+
host = '127.0.0.1';
|
|
239
|
+
}
|
|
240
|
+
return `${this._protocol}://${host}:${this.port}`;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* State of the HTTP / HTTPS server
|
|
245
|
+
*/
|
|
246
|
+
public get listening(): boolean {
|
|
247
|
+
return this._listening;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Address of the HTTP / HTTPS server
|
|
252
|
+
*/
|
|
253
|
+
public get address(): string | AddressInfo | undefined {
|
|
254
|
+
return this._listening ? this._address : undefined;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Makes sure `path` conform to named pipe naming requirement on Windows
|
|
260
|
+
*
|
|
261
|
+
* See https://nodejs.org/api/net.html#net_identifying_paths_for_ipc_connections
|
|
262
|
+
*
|
|
263
|
+
* @param ipcPath - Named pipe path
|
|
264
|
+
*/
|
|
265
|
+
function checkNamedPipe(ipcPath: string) {
|
|
266
|
+
/* istanbul ignore if */
|
|
267
|
+
if (isWin32()) {
|
|
268
|
+
const pipes = ['\\\\?\\pipe\\', '\\\\.\\pipe\\'];
|
|
269
|
+
assert(
|
|
270
|
+
pipes.some(p => ipcPath.startsWith(p)),
|
|
271
|
+
`Named pipe ${ipcPath} does NOT start with + ${pipes.join(' or ')}`,
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Check if it's Windows OS
|
|
278
|
+
*/
|
|
279
|
+
function isWin32() {
|
|
280
|
+
return os.platform() === 'win32';
|
|
281
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Copyright IBM Corp. 2018,2020. All Rights Reserved.
|
|
2
|
+
// Node module: @loopback/http-server
|
|
3
|
+
// This file is licensed under the MIT License.
|
|
4
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* HTTP / HTTPS server endpoints for LoopBack 4 apps.
|
|
8
|
+
*
|
|
9
|
+
* @remarks
|
|
10
|
+
* A package used by LoopBack 4 for creating HTTP / HTTPS server.
|
|
11
|
+
*
|
|
12
|
+
* @packageDocumentation
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export * from './http-server';
|