From 0642598530e491c384b61b9269a945a7ae42d868 Mon Sep 17 00:00:00 2001 From: Joel Chen Date: Thu, 21 Jan 2021 16:20:47 -0800 Subject: [PATCH] fix handling of https/http for dev proxy --- packages/xarc-app-dev/package.json | 2 +- packages/xarc-app-dev/src/config/env-proxy.ts | 9 +-- .../xarc-app-dev/src/config/get-dev-proxy.ts | 23 ++++--- .../src/config/opt2/xarc-options.ts | 33 ++++++++-- .../src/lib/dev-admin/redbird-proxy.ts | 60 ++++++++++++------- packages/xarc-app-dev/src/lib/utils.ts | 9 +++ 6 files changed, 95 insertions(+), 41 deletions(-) diff --git a/packages/xarc-app-dev/package.json b/packages/xarc-app-dev/package.json index ffeb8c4b2..cffc44f18 100644 --- a/packages/xarc-app-dev/package.json +++ b/packages/xarc-app-dev/package.json @@ -51,7 +51,7 @@ "@babel/preset-react": "^7.0.0", "@babel/preset-typescript": "^7.0.0", "@babel/register": "^7.0.0", - "@jchip/redbird": "^1.2.1", + "@jchip/redbird": "^1.2.2", "@loadable/babel-plugin": "^5.10.0", "@xarc/subapp": "^0.1.3", "@xarc/webpack": "^9.1.0", diff --git a/packages/xarc-app-dev/src/config/env-proxy.ts b/packages/xarc-app-dev/src/config/env-proxy.ts index 99eab487e..42b953d68 100644 --- a/packages/xarc-app-dev/src/config/env-proxy.ts +++ b/packages/xarc-app-dev/src/config/env-proxy.ts @@ -1,5 +1,6 @@ +import { isValidPort } from "../lib/utils"; + /* eslint-disable @typescript-eslint/no-var-requires */ -export {}; const { merge } = require("lodash"); @@ -12,9 +13,9 @@ module.exports = function getEnvProxy() { "ELECTRODE_DEV_HTTPS", // deprecated but still check "XARC_DEV_HTTPS" ], - default: 0, - envMap: { true: 443, false: 0 }, - post: x => x || 0 + default: -1, + envMap: { true: 443, false: -1 }, + post: x => (isValidPort(x) ? x : -1) }, adminLogLevel: { env: [ diff --git a/packages/xarc-app-dev/src/config/get-dev-proxy.ts b/packages/xarc-app-dev/src/config/get-dev-proxy.ts index a5cd1729f..4fad17076 100644 --- a/packages/xarc-app-dev/src/config/get-dev-proxy.ts +++ b/packages/xarc-app-dev/src/config/get-dev-proxy.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-var-requires, max-statements, no-console, prefer-const */ -import { getDevAdminPortFromEnv } from "../lib/utils"; +import { getDevAdminPortFromEnv, isValidPort } from "../lib/utils"; const Path = require("path"); const Fs = require("fs"); @@ -81,13 +81,20 @@ module.exports = function createDevProxy() { const { elevated } = envProxy; const useDevProxy = appPort > 0; - if (httpsPort) { - port = httpsPort; + // auto do https for 443 or 8443 + if ((httpPort === 443 || httpPort === 8443) && !isValidPort(httpsPort)) { + httpsPort = httpPort; protocol = "https"; - } else if (httpPort === 443) { - port = httpsPort = httpPort; httpPort = appPort !== 3000 ? 3000 : 3300; + } + + if (isValidPort(httpsPort)) { + port = httpsPort; protocol = "https"; + // avoid http and https conflicting + if (httpPort === httpsPort) { + httpPort = -1; + } } else { port = httpPort; protocol = "http"; @@ -95,11 +102,11 @@ module.exports = function createDevProxy() { const settings = { host, - port, + port, // the primary port to listen for app, could be http or https adminLogLevel, appPort, - httpPort, - httpsPort, + httpPort, // the port to always listen on for HTTP + httpsPort, // dev proxy actually ignores this https: protocol === "https", webpackDev, webpackDevPort, diff --git a/packages/xarc-app-dev/src/config/opt2/xarc-options.ts b/packages/xarc-app-dev/src/config/opt2/xarc-options.ts index 345202c6c..977c59a59 100644 --- a/packages/xarc-app-dev/src/config/opt2/xarc-options.ts +++ b/packages/xarc-app-dev/src/config/opt2/xarc-options.ts @@ -16,32 +16,53 @@ export type XarcOptions = { * port to listen on for serving your application * * @remarks - * This is what the dev proxy listens on. Your app server - * listens on a different port that the proxy forwards to. + * In development, this is what the dev proxy listens on. Your app server + * listens on `appServerPort` that the proxy forwards to. + * + * - Typical values are `3000` for `HTTP` or `443`/`8443` for `HTTPS`. * * - **Default: `3000`** - * - If it's 443, then automatically enable HTTPS. + * - If it's `443` or `8443`, then automatically enable `HTTPS` and try + * to **also** listen on `3000` or `3300` for `http` + * - Set it to `0` and the proxy will pick a random port. + * - Set it to `-1` to disable `http` and use `httpsPort` to listen on `https` only. * - If not set, then check env `PORT` + * + * @remarks Regarding `HTTPS`: + * - If you want full control of `https` and `http` ports, set `httpsPort` and `port`. + * - If you set `port` to `443` or `8443`, then dev proxy do `https` on that port, and + * listens on something that doesn't conflict with `appServerPort`, which is + * `3000` or `3300`. + * - if `https` is enabled, the dev proxy will always try to listen on `http` also. + * + * . */ port?: number; /** - * In case you want to serve your app with https on a port other - * than 443, then you can set it with this. + * Set this to force `https` on the port you want, in case you want to serve your app + * with https on a port other than `443` or `8443`. * * - if not set, then check env then `XARC_DEV_HTTPS` + * - Set it to `0` and the proxy will pick a random port for `https`. + * - Set to `-1` to force disable `https` * * @remarks * If this is set, it cannot be the same as `port`, which then will be - * forced to be HTTP only. + * forced to be `http` only. + * + * . */ httpsPort?: number; + /** * Port number for your app server to listen on so the dev proxy * can forward request to it. * * - **Default: `3100`** * - If not set, then check env `APP_PORT_FOR_PROXY`, then `APP_SERVER_PORT` + * + * . */ appServerPort?: number; // renamed from portForProxy diff --git a/packages/xarc-app-dev/src/lib/dev-admin/redbird-proxy.ts b/packages/xarc-app-dev/src/lib/dev-admin/redbird-proxy.ts index 410b118c4..c512be61d 100644 --- a/packages/xarc-app-dev/src/lib/dev-admin/redbird-proxy.ts +++ b/packages/xarc-app-dev/src/lib/dev-admin/redbird-proxy.ts @@ -1,6 +1,6 @@ -/* eslint-disable @typescript-eslint/no-var-requires, @typescript-eslint/ban-ts-ignore */ -export {}; +import { isValidPort } from "../utils"; +/* eslint-disable @typescript-eslint/no-var-requires, @typescript-eslint/ban-ts-ignore */ /* eslint-disable max-statements, no-process-exit, global-require, no-console */ const assert = require("assert"); @@ -221,9 +221,8 @@ const startProxy = (inOptions = {}) => { const options = Object.assign( { xfwd: false, - bunyan: { - level: "warn", - name: "redbird" + pino: { + level: "warn" }, resolvers: [] }, @@ -231,17 +230,46 @@ const startProxy = (inOptions = {}) => { inOptions ); - const proxyOptions = _.pick(options, ["port", "xfwd", "bunyan", "resolvers"]); + const proxyOptions = _.pick(options, ["port", "xfwd", "pino", "resolvers"]); const { host, port, protocol } = options; const ssl = Boolean(options.httpsPort); + const enableCdnMock = process.argv.includes("--mock-cdn"); + + let listenReportTimer; + const proxyUrls = {} as any; + proxyOptions.reportListening = (proto, _port, actualPort) => { + proxyUrls[proto] = formUrl({ protocol: proto, host, port: actualPort }); + console.log(`Electrode dev proxy listening on ${proto} port`, actualPort); + clearTimeout(listenReportTimer); + listenReportTimer = setTimeout(() => { + const mockCdnMsg = enableCdnMock + ? `\nMock CDN is enabled (mapping saved to config/assets.json)\n` + : "\n"; + console.log( + ck`${mockCdnMsg}${buildProxyTree(options, ["appPort", "webpackDevPort"])} +View status at ${proxyUrls.https || proxyUrls.http}${controlPaths.status}` + ); + + const urlsShow = Object.keys(proxyUrls) + .map(x => { + return ck`${proxyUrls[x]}`; + }) + .join(" or "); + + console.log(ck`You can access your app at ${urlsShow}`); + }, 100).unref(); + }; - if (ssl) { + const enableSsl = ssl && isValidPort(options.httpsPort); + + if (enableSsl) { const proxyCerts = searchSSLCerts(); assert(proxyCerts.key && proxyCerts.cert, "Dev Proxy can't find SSL key and certs"); + const httpPort = isValidPort(options.httpPort) ? options.httpPort : -1; Object.assign(proxyOptions, { // We still setup a regular http rules even if HTTPS is enabled - port: options.httpPort, + port: httpPort, host, secure: true, ssl: { @@ -286,13 +314,12 @@ const startProxy = (inOptions = {}) => { res.end(); }); - const enableCdnMock = process.argv.includes("--mock-cdn"); const noDev = process.argv.includes("--no-dev"); // register with primary protocol/host/port - registerElectrodeDevRules({ ...options, ssl, proxy, restart, enableCdnMock, noDev }); + registerElectrodeDevRules({ ...options, ssl: enableSsl, proxy, restart, enableCdnMock, noDev }); // if primary protocol is https, then register regular http rules at httpPort - if (ssl) { + if (enableSsl && isValidPort(options.httpPort)) { // @ts-ignore registerElectrodeDevRules({ proxy, @@ -309,17 +336,6 @@ const startProxy = (inOptions = {}) => { console.log("Calling proxy setupRules from your archetype/config/dev-proxy"); userDevProxy.setupRules(proxy, options); } - - const proxyUrl = formUrl({ protocol, host, port: options.port }); - const mockCdnMsg = enableCdnMock - ? `\nMock CDN is enabled (mapping saved to config/assets.json)\n` - : "\n"; - console.log( - ck`Electrode dev proxy server running:${mockCdnMsg} -${buildProxyTree(options, ["appPort", "webpackDevPort"])} -View status at ${proxyUrl}${controlPaths.status}` - ); - console.log(ck`You can access your app at ${proxyUrl}`); }; module.exports = startProxy; diff --git a/packages/xarc-app-dev/src/lib/utils.ts b/packages/xarc-app-dev/src/lib/utils.ts index 49f35b4d6..c77a359ce 100644 --- a/packages/xarc-app-dev/src/lib/utils.ts +++ b/packages/xarc-app-dev/src/lib/utils.ts @@ -172,3 +172,12 @@ export function getDevAdminPortFromEnv(fallback?: number): number { return fromEnv || fallback || 8991; } + +/** + * Check if a port number is valid + * @param p - port number + * @returns `true` or `false` + */ +export const isValidPort = p => { + return Number.isInteger(p) && p >= 0 && p < 65536; +};