@loopback/http-server 1.4.18 → 1.5.2

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/CHANGELOG.md CHANGED
@@ -3,6 +3,41 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [1.5.2](https://github.com/strongloop/loopback-next/compare/@loopback/http-server@1.5.1...@loopback/http-server@1.5.2) (2020-01-27)
7
+
8
+ **Note:** Version bump only for package @loopback/http-server
9
+
10
+
11
+
12
+
13
+
14
+ ## [1.5.1](https://github.com/strongloop/loopback-next/compare/@loopback/http-server@1.5.0...@loopback/http-server@1.5.1) (2020-01-07)
15
+
16
+ **Note:** Version bump only for package @loopback/http-server
17
+
18
+
19
+
20
+
21
+
22
+ # [1.5.0](https://github.com/strongloop/loopback-next/compare/@loopback/http-server@1.4.19...@loopback/http-server@1.5.0) (2019-12-09)
23
+
24
+
25
+ ### Features
26
+
27
+ * **http-server:** use stoppable to handle http keep-alive gracefully ([c5fc495](https://github.com/strongloop/loopback-next/commit/c5fc495639301a494313afb33c5d156b427257e0))
28
+
29
+
30
+
31
+
32
+
33
+ ## [1.4.19](https://github.com/strongloop/loopback-next/compare/@loopback/http-server@1.4.18...@loopback/http-server@1.4.19) (2019-11-25)
34
+
35
+ **Note:** Version bump only for package @loopback/http-server
36
+
37
+
38
+
39
+
40
+
6
41
  ## [1.4.18](https://github.com/strongloop/loopback-next/compare/@loopback/http-server@1.4.17...@loopback/http-server@1.4.18) (2019-11-12)
7
42
 
8
43
  **Note:** Version bump only for package @loopback/http-server
@@ -1,21 +1,39 @@
1
1
  /// <reference types="node" />
2
- import * as http from 'http';
3
- import { IncomingMessage, ServerResponse } from 'http';
4
- import * as https from 'https';
2
+ import http, { IncomingMessage, ServerResponse } from 'http';
3
+ import https from 'https';
5
4
  import { AddressInfo, ListenOptions } from 'net';
5
+ /**
6
+ * Request listener function for http/https requests
7
+ */
6
8
  export declare type RequestListener = (req: IncomingMessage, res: ServerResponse) => void;
9
+ /**
10
+ * Base options that are common to http and https servers
11
+ */
12
+ export interface BaseHttpOptions extends ListenOptions {
13
+ /**
14
+ * The `gracePeriodForClose` property controls how to stop the server
15
+ * gracefully. Its value is the number of milliseconds to wait before
16
+ * in-flight requests finish when the server is being stopped. With this
17
+ * setting, we also reject new requests from existing keep-alive connections
18
+ * in addition to stopping accepting new connections.
19
+ *
20
+ * Defaults to Infinity (don't force-close). If you want to immediately
21
+ * destroy all sockets set its value to `0`.
22
+ *
23
+ * @see https://www.npmjs.com/package/stoppable
24
+ */
25
+ gracePeriodForClose?: number;
26
+ }
7
27
  /**
8
28
  * HTTP server options
9
- *
10
29
  */
11
- export interface HttpOptions extends ListenOptions {
30
+ export interface HttpOptions extends BaseHttpOptions {
12
31
  protocol?: 'http';
13
32
  }
14
33
  /**
15
34
  * HTTPS server options
16
- *
17
35
  */
18
- export interface HttpsOptions extends ListenOptions, https.ServerOptions {
36
+ export interface HttpsOptions extends BaseHttpOptions, https.ServerOptions {
19
37
  protocol: 'https';
20
38
  }
21
39
  /**
@@ -37,6 +55,7 @@ export declare class HttpServer {
37
55
  private _address;
38
56
  private requestListener;
39
57
  readonly server: http.Server | https.Server;
58
+ private _stoppable;
40
59
  private serverOptions;
41
60
  /**
42
61
  * @param requestListener
@@ -3,12 +3,16 @@
3
3
  // Node module: @loopback/http-server
4
4
  // This file is licensed under the MIT License.
5
5
  // License text available at https://opensource.org/licenses/MIT
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
6
9
  Object.defineProperty(exports, "__esModule", { value: true });
7
- const assert = require("assert");
8
- const http = require("http");
9
- const https = require("https");
10
- const os = require("os");
11
- const p_event_1 = require("p-event");
10
+ const assert_1 = __importDefault(require("assert"));
11
+ const http_1 = __importDefault(require("http"));
12
+ const https_1 = __importDefault(require("https"));
13
+ const os_1 = __importDefault(require("os"));
14
+ const p_event_1 = __importDefault(require("p-event"));
15
+ const stoppable_1 = __importDefault(require("stoppable"));
12
16
  /**
13
17
  * HTTP / HTTPS server used by LoopBack's RestServer
14
18
  */
@@ -18,6 +22,7 @@ class HttpServer {
18
22
  * @param serverOptions
19
23
  */
20
24
  constructor(requestListener, serverOptions) {
25
+ var _a;
21
26
  this._listening = false;
22
27
  this.requestListener = requestListener;
23
28
  this.serverOptions = Object.assign({ port: 0, host: undefined }, serverOptions);
@@ -27,12 +32,16 @@ class HttpServer {
27
32
  // Remove `port` so that `path` is honored
28
33
  delete this.serverOptions.port;
29
34
  }
30
- this._protocol = serverOptions ? serverOptions.protocol || 'http' : 'http';
35
+ this._protocol = serverOptions ? (_a = serverOptions.protocol, (_a !== null && _a !== void 0 ? _a : 'http')) : 'http';
31
36
  if (this._protocol === 'https') {
32
- this.server = https.createServer(this.serverOptions, this.requestListener);
37
+ this.server = https_1.default.createServer(this.serverOptions, this.requestListener);
33
38
  }
34
39
  else {
35
- this.server = http.createServer(this.requestListener);
40
+ this.server = http_1.default.createServer(this.requestListener);
41
+ }
42
+ // Set up graceful stop for http server
43
+ if (typeof this.serverOptions.gracePeriodForClose === 'number') {
44
+ this._stoppable = stoppable_1.default(this.server, this.serverOptions.gracePeriodForClose);
36
45
  }
37
46
  }
38
47
  /**
@@ -43,7 +52,7 @@ class HttpServer {
43
52
  await p_event_1.default(this.server, 'listening');
44
53
  this._listening = true;
45
54
  const address = this.server.address();
46
- assert(address != null);
55
+ assert_1.default(address != null);
47
56
  this._address = address;
48
57
  }
49
58
  /**
@@ -52,7 +61,12 @@ class HttpServer {
52
61
  async stop() {
53
62
  if (!this._listening)
54
63
  return;
55
- this.server.close();
64
+ if (this._stoppable != null) {
65
+ this._stoppable.stop();
66
+ }
67
+ else {
68
+ this.server.close();
69
+ }
56
70
  await p_event_1.default(this.server, 'close');
57
71
  this._listening = false;
58
72
  }
@@ -126,13 +140,13 @@ function checkNamedPipe(ipcPath) {
126
140
  /* istanbul ignore if */
127
141
  if (isWin32()) {
128
142
  const pipes = ['\\\\?\\pipe\\', '\\\\.\\pipe\\'];
129
- assert(pipes.some(p => ipcPath.startsWith(p)), `Named pipe ${ipcPath} does NOT start with + ${pipes.join(' or ')}`);
143
+ assert_1.default(pipes.some(p => ipcPath.startsWith(p)), `Named pipe ${ipcPath} does NOT start with + ${pipes.join(' or ')}`);
130
144
  }
131
145
  }
132
146
  /**
133
147
  * Check if it's Windows OS
134
148
  */
135
149
  function isWin32() {
136
- return os.platform() === 'win32';
150
+ return os_1.default.platform() === 'win32';
137
151
  }
138
152
  //# sourceMappingURL=http-server.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"http-server.js","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"http-server.js","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loopback/http-server",
3
- "version": "1.4.18",
3
+ "version": "1.5.2",
4
4
  "description": "A wrapper for creating HTTP/HTTPS servers",
5
5
  "engines": {
6
6
  "node": ">=8.9"
@@ -16,14 +16,16 @@
16
16
  "copyright.owner": "IBM Corp.",
17
17
  "license": "MIT",
18
18
  "dependencies": {
19
- "p-event": "^4.1.0"
19
+ "p-event": "^4.1.0",
20
+ "stoppable": "^1.1.0"
20
21
  },
21
22
  "devDependencies": {
22
- "@loopback/build": "^2.0.16",
23
- "@loopback/core": "^1.10.7",
24
- "@loopback/eslint-config": "^4.1.4",
25
- "@loopback/testlab": "^1.9.4",
26
- "@types/node": "^10.17.5"
23
+ "@loopback/build": "^3.1.0",
24
+ "@loopback/core": "^1.12.2",
25
+ "@loopback/eslint-config": "^5.0.2",
26
+ "@loopback/testlab": "^1.10.2",
27
+ "@types/node": "^10.17.13",
28
+ "@types/stoppable": "^1.1.0"
27
29
  },
28
30
  "files": [
29
31
  "README.md",
@@ -41,5 +43,5 @@
41
43
  "url": "https://github.com/strongloop/loopback-next.git",
42
44
  "directory": "packages/http-server"
43
45
  },
44
- "gitHead": "7f0ae6ec124c19357c3016cd11f9bc9c739dffcb"
46
+ "gitHead": "d08f135a0d1040edc61497739a8d86a866e4e29a"
45
47
  }
@@ -3,32 +3,52 @@
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 * as assert from 'assert';
7
- import * as http from 'http';
8
- import {IncomingMessage, ServerResponse} from 'http';
9
- import * as https from 'https';
6
+ import assert from 'assert';
7
+ import http, {IncomingMessage, ServerResponse} from 'http';
8
+ import https from 'https';
10
9
  import {AddressInfo, ListenOptions} from 'net';
11
- import * as os from 'os';
10
+ import os from 'os';
12
11
  import pEvent from 'p-event';
12
+ import stoppable from 'stoppable';
13
13
 
14
+ /**
15
+ * Request listener function for http/https requests
16
+ */
14
17
  export type RequestListener = (
15
18
  req: IncomingMessage,
16
19
  res: ServerResponse,
17
20
  ) => void;
18
21
 
22
+ /**
23
+ * Base options that are common to http and https servers
24
+ */
25
+ export interface BaseHttpOptions extends ListenOptions {
26
+ /**
27
+ * The `gracePeriodForClose` property controls how to stop the server
28
+ * gracefully. Its value is the number of milliseconds to wait before
29
+ * in-flight requests finish when the server is being stopped. With this
30
+ * setting, we also reject new requests from existing keep-alive connections
31
+ * in addition to stopping accepting new connections.
32
+ *
33
+ * Defaults to Infinity (don't force-close). If you want to immediately
34
+ * destroy all sockets set its value to `0`.
35
+ *
36
+ * @see https://www.npmjs.com/package/stoppable
37
+ */
38
+ gracePeriodForClose?: number;
39
+ }
40
+
19
41
  /**
20
42
  * HTTP server options
21
- *
22
43
  */
23
- export interface HttpOptions extends ListenOptions {
44
+ export interface HttpOptions extends BaseHttpOptions {
24
45
  protocol?: 'http';
25
46
  }
26
47
 
27
48
  /**
28
49
  * HTTPS server options
29
- *
30
50
  */
31
- export interface HttpsOptions extends ListenOptions, https.ServerOptions {
51
+ export interface HttpsOptions extends BaseHttpOptions, https.ServerOptions {
32
52
  protocol: 'https';
33
53
  }
34
54
 
@@ -53,6 +73,7 @@ export class HttpServer {
53
73
  private _address: string | AddressInfo;
54
74
  private requestListener: RequestListener;
55
75
  readonly server: http.Server | https.Server;
76
+ private _stoppable: stoppable.StoppableServer;
56
77
  private serverOptions: HttpServerOptions;
57
78
 
58
79
  /**
@@ -74,7 +95,7 @@ export class HttpServer {
74
95
  // Remove `port` so that `path` is honored
75
96
  delete this.serverOptions.port;
76
97
  }
77
- this._protocol = serverOptions ? serverOptions.protocol || 'http' : 'http';
98
+ this._protocol = serverOptions ? serverOptions.protocol ?? 'http' : 'http';
78
99
  if (this._protocol === 'https') {
79
100
  this.server = https.createServer(
80
101
  this.serverOptions as https.ServerOptions,
@@ -83,6 +104,13 @@ export class HttpServer {
83
104
  } else {
84
105
  this.server = http.createServer(this.requestListener);
85
106
  }
107
+ // Set up graceful stop for http server
108
+ if (typeof this.serverOptions.gracePeriodForClose === 'number') {
109
+ this._stoppable = stoppable(
110
+ this.server,
111
+ this.serverOptions.gracePeriodForClose,
112
+ );
113
+ }
86
114
  }
87
115
 
88
116
  /**
@@ -103,7 +131,11 @@ export class HttpServer {
103
131
  */
104
132
  public async stop() {
105
133
  if (!this._listening) return;
106
- this.server.close();
134
+ if (this._stoppable != null) {
135
+ this._stoppable.stop();
136
+ } else {
137
+ this.server.close();
138
+ }
107
139
  await pEvent(this.server, 'close');
108
140
  this._listening = false;
109
141
  }