@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 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":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * HTTP / HTTPS server endpoints for LoopBack 4 apps.
3
+ *
4
+ * @remarks
5
+ * A package used by LoopBack 4 for creating HTTP / HTTPS server.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ export * from './http-server';
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';