@loopback/http-server
Advanced tools
Comparing version 1.1.15 to 1.2.0
@@ -6,2 +6,13 @@ # Change Log | ||
# [1.2.0](https://github.com/strongloop/loopback-next/compare/@loopback/http-server@1.1.15...@loopback/http-server@1.2.0) (2019-05-06) | ||
### Features | ||
* **http-server:** add support for unix socket/windows pipe path ([22400fe](https://github.com/strongloop/loopback-next/commit/22400fe)) | ||
## [1.1.15](https://github.com/strongloop/loopback-next/compare/@loopback/http-server@1.1.14...@loopback/http-server@1.1.15) (2019-04-26) | ||
@@ -8,0 +19,0 @@ |
/// <reference types="node" /> | ||
import * as http from 'http'; | ||
import { IncomingMessage, ServerResponse } from 'http'; | ||
import * as http from 'http'; | ||
import * as https from 'https'; | ||
import { AddressInfo } from 'net'; | ||
import { AddressInfo, ListenOptions } from 'net'; | ||
export declare type RequestListener = (req: IncomingMessage, res: ServerResponse) => void; | ||
/** | ||
* Basic HTTP server listener options | ||
* | ||
* @export | ||
* @interface ListenerOptions | ||
*/ | ||
export interface ListenerOptions { | ||
host?: string; | ||
port?: number; | ||
} | ||
/** | ||
* HTTP server options | ||
* | ||
* @export | ||
* @interface HttpOptions | ||
*/ | ||
export interface HttpOptions extends ListenerOptions { | ||
export interface HttpOptions extends ListenOptions { | ||
protocol?: 'http'; | ||
@@ -29,6 +17,4 @@ } | ||
* | ||
* @export | ||
* @interface HttpsOptions | ||
*/ | ||
export interface HttpsOptions extends ListenerOptions, https.ServerOptions { | ||
export interface HttpsOptions extends ListenOptions, https.ServerOptions { | ||
protocol: 'https'; | ||
@@ -39,4 +25,2 @@ } | ||
* | ||
* @export | ||
* @type HttpServerOptions | ||
*/ | ||
@@ -47,4 +31,2 @@ export declare type HttpServerOptions = HttpOptions | HttpsOptions; | ||
* | ||
* @export | ||
* @type HttpProtocol | ||
*/ | ||
@@ -54,9 +36,4 @@ export declare type HttpProtocol = 'http' | 'https'; | ||
* HTTP / HTTPS server used by LoopBack's RestServer | ||
* | ||
* @export | ||
* @class HttpServer | ||
*/ | ||
export declare class HttpServer { | ||
private _port; | ||
private _host?; | ||
private _listening; | ||
@@ -67,3 +44,3 @@ private _protocol; | ||
readonly server: http.Server | https.Server; | ||
private serverOptions?; | ||
private serverOptions; | ||
/** | ||
@@ -105,3 +82,3 @@ * @param requestListener | ||
*/ | ||
readonly address: AddressInfo | undefined; | ||
readonly address: string | AddressInfo | undefined; | ||
} |
@@ -7,10 +7,9 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const assert = require("assert"); | ||
const http = require("http"); | ||
const https = require("https"); | ||
const os = require("os"); | ||
const p_event_1 = require("p-event"); | ||
/** | ||
* HTTP / HTTPS server used by LoopBack's RestServer | ||
* | ||
* @export | ||
* @class HttpServer | ||
*/ | ||
@@ -25,5 +24,9 @@ class HttpServer { | ||
this.requestListener = requestListener; | ||
this.serverOptions = serverOptions; | ||
this._port = serverOptions ? serverOptions.port || 0 : 0; | ||
this._host = serverOptions ? serverOptions.host : undefined; | ||
this.serverOptions = Object.assign({ port: 0, host: undefined }, serverOptions); | ||
if (this.serverOptions.path) { | ||
const ipcPath = this.serverOptions.path; | ||
checkNamedPipe(ipcPath); | ||
// Remove `port` so that `path` is honored | ||
delete this.serverOptions.port; | ||
} | ||
this._protocol = serverOptions ? serverOptions.protocol || 'http' : 'http'; | ||
@@ -41,3 +44,3 @@ if (this._protocol === 'https') { | ||
async start() { | ||
this.server.listen(this._port, this._host); | ||
this.server.listen(this.serverOptions); | ||
await p_event_1.default(this.server, 'listening'); | ||
@@ -51,3 +54,3 @@ this._listening = true; | ||
async stop() { | ||
if (!this.server) | ||
if (!this._listening) | ||
return; | ||
@@ -68,3 +71,5 @@ this.server.close(); | ||
get port() { | ||
return (this._address && this._address.port) || this._port; | ||
if (typeof this._address === 'string') | ||
return 0; | ||
return (this._address && this._address.port) || this.serverOptions.port; | ||
} | ||
@@ -75,3 +80,5 @@ /** | ||
get host() { | ||
return (this._address && this._address.address) || this._host; | ||
if (typeof this._address === 'string') | ||
return undefined; | ||
return (this._address && this._address.address) || this.serverOptions.host; | ||
} | ||
@@ -82,2 +89,10 @@ /** | ||
get url() { | ||
if (typeof this._address === 'string') { | ||
/* istanbul ignore if */ | ||
if (isWin32()) { | ||
return this._address; | ||
} | ||
const basePath = encodeURIComponent(this._address); | ||
return `${this.protocol}+unix://${basePath}`; | ||
} | ||
let host = this.host; | ||
@@ -108,2 +123,22 @@ if (this._address.family === 'IPv6') { | ||
exports.HttpServer = HttpServer; | ||
/** | ||
* Makes sure `path` conform to named pipe naming requirement on Windows | ||
* | ||
* See https://nodejs.org/api/net.html#net_identifying_paths_for_ipc_connections | ||
* | ||
* @param ipcPath Named pipe path | ||
*/ | ||
function checkNamedPipe(ipcPath) { | ||
/* istanbul ignore if */ | ||
if (isWin32()) { | ||
const pipes = ['\\\\?\\pipe\\', '\\\\.\\pipe\\']; | ||
assert(pipes.some(p => ipcPath.startsWith(p)), `Named pipe ${ipcPath} does NOT start with + ${pipes.join(' or ')}`); | ||
} | ||
} | ||
/** | ||
* Check if it's Windows OS | ||
*/ | ||
function isWin32() { | ||
return os.platform() === 'win32'; | ||
} | ||
//# sourceMappingURL=http-server.js.map |
{ | ||
"name": "@loopback/http-server", | ||
"version": "1.1.15", | ||
"version": "1.2.0", | ||
"description": "A wrapper for creating HTTP/HTTPS servers", | ||
@@ -23,5 +23,5 @@ "engines": { | ||
"devDependencies": { | ||
"@loopback/build": "^1.5.0", | ||
"@loopback/core": "^1.6.0", | ||
"@loopback/testlab": "^1.2.5", | ||
"@loopback/build": "^1.5.1", | ||
"@loopback/core": "^1.6.1", | ||
"@loopback/testlab": "^1.2.6", | ||
"@loopback/tslint-config": "^2.0.4", | ||
@@ -45,3 +45,3 @@ "@types/node": "^10.11.2" | ||
}, | ||
"gitHead": "938be7cc5bd2d9dded2e20a235052e3397afe6f6" | ||
"gitHead": "f8ecd497955fde53e77a7428d7afa57a2f1e52b8" | ||
} |
@@ -6,7 +6,8 @@ // Copyright IBM Corp. 2018,2019. All Rights Reserved. | ||
import * as assert from 'assert'; | ||
import * as http from 'http'; | ||
import {IncomingMessage, ServerResponse} from 'http'; | ||
import * as http from 'http'; | ||
import * as https from 'https'; | ||
import {AddressInfo} from 'net'; | ||
import {AddressInfo, ListenOptions} from 'net'; | ||
import * as os from 'os'; | ||
import pEvent from 'p-event'; | ||
@@ -20,19 +21,6 @@ | ||
/** | ||
* Basic HTTP server listener options | ||
* | ||
* @export | ||
* @interface ListenerOptions | ||
*/ | ||
export interface ListenerOptions { | ||
host?: string; | ||
port?: number; | ||
} | ||
/** | ||
* HTTP server options | ||
* | ||
* @export | ||
* @interface HttpOptions | ||
*/ | ||
export interface HttpOptions extends ListenerOptions { | ||
export interface HttpOptions extends ListenOptions { | ||
protocol?: 'http'; | ||
@@ -44,6 +32,4 @@ } | ||
* | ||
* @export | ||
* @interface HttpsOptions | ||
*/ | ||
export interface HttpsOptions extends ListenerOptions, https.ServerOptions { | ||
export interface HttpsOptions extends ListenOptions, https.ServerOptions { | ||
protocol: 'https'; | ||
@@ -55,4 +41,2 @@ } | ||
* | ||
* @export | ||
* @type HttpServerOptions | ||
*/ | ||
@@ -64,4 +48,2 @@ export type HttpServerOptions = HttpOptions | HttpsOptions; | ||
* | ||
* @export | ||
* @type HttpProtocol | ||
*/ | ||
@@ -72,15 +54,10 @@ export type HttpProtocol = 'http' | 'https'; // Will be extended to `http2` in the future | ||
* HTTP / HTTPS server used by LoopBack's RestServer | ||
* | ||
* @export | ||
* @class HttpServer | ||
*/ | ||
export class HttpServer { | ||
private _port: number; | ||
private _host?: string; | ||
private _listening: boolean = false; | ||
private _protocol: HttpProtocol; | ||
private _address: AddressInfo; | ||
private _address: string | AddressInfo; | ||
private requestListener: RequestListener; | ||
readonly server: http.Server | https.Server; | ||
private serverOptions?: HttpServerOptions; | ||
private serverOptions: HttpServerOptions; | ||
@@ -96,5 +73,12 @@ /** | ||
this.requestListener = requestListener; | ||
this.serverOptions = serverOptions; | ||
this._port = serverOptions ? serverOptions.port || 0 : 0; | ||
this._host = serverOptions ? serverOptions.host : undefined; | ||
this.serverOptions = Object.assign( | ||
{port: 0, host: undefined}, | ||
serverOptions, | ||
); | ||
if (this.serverOptions.path) { | ||
const ipcPath = this.serverOptions.path; | ||
checkNamedPipe(ipcPath); | ||
// Remove `port` so that `path` is honored | ||
delete this.serverOptions.port; | ||
} | ||
this._protocol = serverOptions ? serverOptions.protocol || 'http' : 'http'; | ||
@@ -115,6 +99,6 @@ if (this._protocol === 'https') { | ||
public async start() { | ||
this.server.listen(this._port, this._host); | ||
this.server.listen(this.serverOptions); | ||
await pEvent(this.server, 'listening'); | ||
this._listening = true; | ||
this._address = this.server.address() as AddressInfo; | ||
this._address = this.server.address(); | ||
} | ||
@@ -126,3 +110,3 @@ | ||
public async stop() { | ||
if (!this.server) return; | ||
if (!this._listening) return; | ||
this.server.close(); | ||
@@ -144,3 +128,4 @@ await pEvent(this.server, 'close'); | ||
public get port(): number { | ||
return (this._address && this._address.port) || this._port; | ||
if (typeof this._address === 'string') return 0; | ||
return (this._address && this._address.port) || this.serverOptions.port!; | ||
} | ||
@@ -152,3 +137,4 @@ | ||
public get host(): string | undefined { | ||
return (this._address && this._address.address) || this._host; | ||
if (typeof this._address === 'string') return undefined; | ||
return (this._address && this._address.address) || this.serverOptions.host; | ||
} | ||
@@ -160,2 +146,10 @@ | ||
public get url(): string { | ||
if (typeof this._address === 'string') { | ||
/* istanbul ignore if */ | ||
if (isWin32()) { | ||
return this._address; | ||
} | ||
const basePath = encodeURIComponent(this._address); | ||
return `${this.protocol}+unix://${basePath}`; | ||
} | ||
let host = this.host; | ||
@@ -181,5 +175,30 @@ if (this._address.family === 'IPv6') { | ||
*/ | ||
public get address(): AddressInfo | undefined { | ||
public get address(): string | AddressInfo | undefined { | ||
return this._listening ? this._address : undefined; | ||
} | ||
} | ||
/** | ||
* Makes sure `path` conform to named pipe naming requirement on Windows | ||
* | ||
* See https://nodejs.org/api/net.html#net_identifying_paths_for_ipc_connections | ||
* | ||
* @param ipcPath Named pipe path | ||
*/ | ||
function checkNamedPipe(ipcPath: string) { | ||
/* istanbul ignore if */ | ||
if (isWin32()) { | ||
const pipes = ['\\\\?\\pipe\\', '\\\\.\\pipe\\']; | ||
assert( | ||
pipes.some(p => ipcPath.startsWith(p)), | ||
`Named pipe ${ipcPath} does NOT start with + ${pipes.join(' or ')}`, | ||
); | ||
} | ||
} | ||
/** | ||
* Check if it's Windows OS | ||
*/ | ||
function isWin32() { | ||
return os.platform() === 'win32'; | ||
} |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
30229
412