From 24178b05825245b9f36b5a8e4730996184cc7e8e Mon Sep 17 00:00:00 2001 From: Harry Brundage Date: Mon, 10 May 2021 01:10:20 -0400 Subject: [PATCH] fix(hmr): respect server https options when running as middleware (#1992) --- packages/vite/src/node/preview.ts | 8 +++- packages/vite/src/node/server/http.ts | 21 +++++----- packages/vite/src/node/server/index.ts | 7 ++-- packages/vite/src/node/server/ws.ts | 53 +++++++++++++++++++++++--- 4 files changed, 69 insertions(+), 20 deletions(-) diff --git a/packages/vite/src/node/preview.ts b/packages/vite/src/node/preview.ts index 9663084fd78bb4..954df92180a887 100644 --- a/packages/vite/src/node/preview.ts +++ b/packages/vite/src/node/preview.ts @@ -5,7 +5,7 @@ import connect from 'connect' import compression from 'compression' import { ResolvedConfig } from '.' import { Connect } from 'types/connect' -import { resolveHttpServer } from './server/http' +import { resolveHttpsConfig, resolveHttpServer } from './server/http' import { openBrowser } from './server/openBrowser' import corsMiddleware from 'cors' import { proxyMiddleware } from './server/middlewares/proxy' @@ -16,7 +16,11 @@ export async function preview( port = 5000 ): Promise { const app = connect() as Connect.Server - const httpServer = await resolveHttpServer(config.server, app) + const httpServer = await resolveHttpServer( + config.server, + app, + await resolveHttpsConfig(config) + ) // cors const { cors } = config.server diff --git a/packages/vite/src/node/server/http.ts b/packages/vite/src/node/server/http.ts index b31fc3be991ede..9f3d2d13a1f913 100644 --- a/packages/vite/src/node/server/http.ts +++ b/packages/vite/src/node/server/http.ts @@ -2,20 +2,18 @@ import fs from 'fs' import path from 'path' import { Server as HttpServer } from 'http' import { ServerOptions as HttpsServerOptions } from 'https' -import { ServerOptions } from '..' +import { ResolvedConfig, ServerOptions } from '..' import { Connect } from 'types/connect' export async function resolveHttpServer( - { https = false, proxy }: ServerOptions, - app: Connect.Server + { proxy }: ServerOptions, + app: Connect.Server, + httpsOptions?: HttpsServerOptions ): Promise { - if (!https) { + if (!httpsOptions) { return require('http').createServer(app) } - const httpsOptions = await resolveHttpsConfig( - typeof https === 'boolean' ? {} : https - ) if (proxy) { // #484 fallback to http1 when proxy is needed. return require('https').createServer(httpsOptions, app) @@ -31,8 +29,13 @@ export async function resolveHttpServer( } export async function resolveHttpsConfig( - httpsOption: HttpsServerOptions -): Promise { + config: ResolvedConfig +): Promise { + if (!config.server.https) return undefined + + const httpsOption = + typeof config.server.https === 'object' ? config.server.https : {} + const { ca, cert, key, pfx } = httpsOption Object.assign(httpsOption, { ca: readFileIfExists(ca), diff --git a/packages/vite/src/node/server/index.ts b/packages/vite/src/node/server/index.ts index 97db4d2f5ab827..83020339fe887e 100644 --- a/packages/vite/src/node/server/index.ts +++ b/packages/vite/src/node/server/index.ts @@ -8,7 +8,7 @@ import corsMiddleware from 'cors' import chalk from 'chalk' import { AddressInfo } from 'net' import chokidar from 'chokidar' -import { resolveHttpServer } from './http' +import { resolveHttpsConfig, resolveHttpServer } from './http' import { resolveConfig, InlineConfig, ResolvedConfig } from '../config' import { createPluginContainer, @@ -278,12 +278,13 @@ export async function createServer( const root = config.root const serverConfig = config.server || {} const middlewareMode = !!serverConfig.middlewareMode + const httpsOptions = await resolveHttpsConfig(config) const middlewares = connect() as Connect.Server const httpServer = middlewareMode ? null - : await resolveHttpServer(serverConfig, middlewares) - const ws = createWebSocketServer(httpServer, config) + : await resolveHttpServer(serverConfig, middlewares, httpsOptions) + const ws = createWebSocketServer(httpServer, config, httpsOptions) const { ignored = [], ...watchOptions } = serverConfig.watch || {} const watcher = chokidar.watch(path.resolve(root), { diff --git a/packages/vite/src/node/server/ws.ts b/packages/vite/src/node/server/ws.ts index e704717f8f2b2d..fb6ba6c68f2da4 100644 --- a/packages/vite/src/node/server/ws.ts +++ b/packages/vite/src/node/server/ws.ts @@ -1,5 +1,9 @@ import chalk from 'chalk' -import { Server } from 'http' +import { Server, STATUS_CODES } from 'http' +import { + createServer as createHttpsServer, + ServerOptions as HttpsServerOptions +} from 'https' import WebSocket from 'ws' import { ErrorPayload, HMRPayload } from 'types/hmrPayload' import { ResolvedConfig } from '..' @@ -13,9 +17,11 @@ export interface WebSocketServer { export function createWebSocketServer( server: Server | null, - config: ResolvedConfig + config: ResolvedConfig, + httpsOptions?: HttpsServerOptions ): WebSocketServer { let wss: WebSocket.Server + let httpsServer: Server | undefined = undefined const hmr = typeof config.server.hmr === 'object' && config.server.hmr const wsServer = (hmr && hmr.server) || server @@ -30,10 +36,35 @@ export function createWebSocketServer( } }) } else { + const websocketServerOptions: WebSocket.ServerOptions = {} + const port = (hmr && hmr.port) || 24678 + if (httpsOptions) { + // if we're serving the middlewares over https, the ws library doesn't support automatically creating an https server, so we need to do it ourselves + // create an inline https server and mount the websocket server to it + httpsServer = createHttpsServer(httpsOptions, (req, res) => { + const statusCode = 426 + const body = STATUS_CODES[statusCode] + if (!body) + throw new Error( + `No body text found for the ${statusCode} status code` + ) + + res.writeHead(statusCode, { + 'Content-Length': body.length, + 'Content-Type': 'text/plain' + }) + res.end(body) + }) + + httpsServer.listen(port) + websocketServerOptions.server = httpsServer + } else { + // we don't need to serve over https, just let ws handle its own server + websocketServerOptions.port = port + } + // vite dev server in middleware mode - wss = new WebSocket.Server({ - port: (hmr && hmr.port) || 24678 - }) + wss = new WebSocket.Server(websocketServerOptions) } wss.on('connection', (socket) => { @@ -79,7 +110,17 @@ export function createWebSocketServer( if (err) { reject(err) } else { - resolve() + if (httpsServer) { + httpsServer.close((err) => { + if (err) { + reject(err) + } else { + resolve() + } + }) + } else { + resolve() + } } }) })