Skip to content

Commit

Permalink
[fix] handling of https/http for dev proxy (#1788)
Browse files Browse the repository at this point in the history
  • Loading branch information
jchip authored Jan 22, 2021
1 parent af93304 commit c9c5099
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 41 deletions.
2 changes: 1 addition & 1 deletion packages/xarc-app-dev/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
9 changes: 5 additions & 4 deletions packages/xarc-app-dev/src/config/env-proxy.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { isValidPort } from "../lib/utils";

/* eslint-disable @typescript-eslint/no-var-requires */
export {};

const { merge } = require("lodash");

Expand All @@ -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: [
Expand Down
23 changes: 15 additions & 8 deletions packages/xarc-app-dev/src/config/get-dev-proxy.ts
Original file line number Diff line number Diff line change
@@ -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");
Expand Down Expand Up @@ -81,25 +81,32 @@ 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";
}

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,
Expand Down
33 changes: 27 additions & 6 deletions packages/xarc-app-dev/src/config/opt2/xarc-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
60 changes: 38 additions & 22 deletions packages/xarc-app-dev/src/lib/dev-admin/redbird-proxy.ts
Original file line number Diff line number Diff line change
@@ -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");
Expand Down Expand Up @@ -221,27 +221,55 @@ const startProxy = (inOptions = {}) => {
const options = Object.assign(
{
xfwd: false,
bunyan: {
level: "warn",
name: "redbird"
pino: {
level: "warn"
},
resolvers: []
},
settings,
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 <green>${proxyUrls.https || proxyUrls.http}${controlPaths.status}</>`
);

const urlsShow = Object.keys(proxyUrls)
.map(x => {
return ck`<green>${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: {
Expand Down Expand Up @@ -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,
Expand All @@ -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 <green>${proxyUrl}${controlPaths.status}</>`
);
console.log(ck`You can access your app at <green>${proxyUrl}</>`);
};

module.exports = startProxy;
Expand Down
9 changes: 9 additions & 0 deletions packages/xarc-app-dev/src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

0 comments on commit c9c5099

Please sign in to comment.