From ff2849a4e34e7802d8e70553a7e76d363dbd66d6 Mon Sep 17 00:00:00 2001 From: Chew Tee Ming Date: Tue, 29 Oct 2024 12:11:54 +0800 Subject: [PATCH 01/10] add fix and changeset --- .changeset/unlucky-walls-drum.md | 5 +++++ packages/kit/src/exports/node/index.js | 12 +++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 .changeset/unlucky-walls-drum.md diff --git a/.changeset/unlucky-walls-drum.md b/.changeset/unlucky-walls-drum.md new file mode 100644 index 000000000000..8389e0210462 --- /dev/null +++ b/.changeset/unlucky-walls-drum.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +fix: strip HTTP/2 pseudo-headers and symbol request header keys to get Vite HTTPS working again diff --git a/packages/kit/src/exports/node/index.js b/packages/kit/src/exports/node/index.js index b3fe17c5a4f7..722e7bef8775 100644 --- a/packages/kit/src/exports/node/index.js +++ b/packages/kit/src/exports/node/index.js @@ -106,11 +106,21 @@ function get_raw_body(req, body_size_limit) { // TODO 3.0 make the signature synchronous? // eslint-disable-next-line @typescript-eslint/require-await export async function getRequest({ request, base, bodySizeLimit }) { + const headers = /** @type {Record} */ ( + Object.fromEntries( + Object.entries(request.headers).filter(([key]) => { + // strip HTTP/2 pseudo-headers and symbol keys which the `Headers` + // implementation doesn't like + return key[0] !== ':' && typeof key !== 'symbol'; + }) + ) + ); + return new Request(base + request.url, { // @ts-expect-error duplex: 'half', method: request.method, - headers: /** @type {Record} */ (request.headers), + headers, body: request.method === 'GET' || request.method === 'HEAD' ? undefined From d3545bc01daec5f5e5fc5f047dfc31af73ec1759 Mon Sep 17 00:00:00 2001 From: Chew Tee Ming Date: Tue, 29 Oct 2024 12:31:16 +0800 Subject: [PATCH 02/10] this looks cleaner --- packages/kit/src/exports/node/index.js | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/packages/kit/src/exports/node/index.js b/packages/kit/src/exports/node/index.js index 722e7bef8775..bfb7997f9768 100644 --- a/packages/kit/src/exports/node/index.js +++ b/packages/kit/src/exports/node/index.js @@ -106,16 +106,21 @@ function get_raw_body(req, body_size_limit) { // TODO 3.0 make the signature synchronous? // eslint-disable-next-line @typescript-eslint/require-await export async function getRequest({ request, base, bodySizeLimit }) { + // strip out symbol keys which Request doesn't like const headers = /** @type {Record} */ ( - Object.fromEntries( - Object.entries(request.headers).filter(([key]) => { - // strip HTTP/2 pseudo-headers and symbol keys which the `Headers` - // implementation doesn't like - return key[0] !== ':' && typeof key !== 'symbol'; - }) - ) + Object.fromEntries(Object.entries(request.headers)) ); + if (request.httpVersionMajor === 2) { + // strip out the HTTP/2 pseudo-headers because the `Headers` + // implementation doesn't like them + delete headers[':method']; + delete headers[':path']; + delete headers[':authority']; + delete headers[':scheme']; + delete headers[':status']; + } + return new Request(base + request.url, { // @ts-expect-error duplex: 'half', From dc84496a64c55de92aff4bb05bf6191b286d56ea Mon Sep 17 00:00:00 2001 From: Chew Tee Ming Date: Tue, 29 Oct 2024 12:31:54 +0800 Subject: [PATCH 03/10] prettier comment --- packages/kit/src/exports/node/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kit/src/exports/node/index.js b/packages/kit/src/exports/node/index.js index bfb7997f9768..3f1566e11141 100644 --- a/packages/kit/src/exports/node/index.js +++ b/packages/kit/src/exports/node/index.js @@ -106,7 +106,7 @@ function get_raw_body(req, body_size_limit) { // TODO 3.0 make the signature synchronous? // eslint-disable-next-line @typescript-eslint/require-await export async function getRequest({ request, base, bodySizeLimit }) { - // strip out symbol keys which Request doesn't like + // strip out symbol keys because the `Request` implementation doesn't like them const headers = /** @type {Record} */ ( Object.fromEntries(Object.entries(request.headers)) ); From c82babfe526c7c1c4d4c3d72c5fc1dca856634ff Mon Sep 17 00:00:00 2001 From: Chew Tee Ming Date: Tue, 29 Oct 2024 18:22:04 +0800 Subject: [PATCH 04/10] alternatively add an empty proxy config --- packages/kit/src/exports/node/index.js | 17 +---------------- packages/kit/src/exports/vite/index.js | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/packages/kit/src/exports/node/index.js b/packages/kit/src/exports/node/index.js index 3f1566e11141..b3fe17c5a4f7 100644 --- a/packages/kit/src/exports/node/index.js +++ b/packages/kit/src/exports/node/index.js @@ -106,26 +106,11 @@ function get_raw_body(req, body_size_limit) { // TODO 3.0 make the signature synchronous? // eslint-disable-next-line @typescript-eslint/require-await export async function getRequest({ request, base, bodySizeLimit }) { - // strip out symbol keys because the `Request` implementation doesn't like them - const headers = /** @type {Record} */ ( - Object.fromEntries(Object.entries(request.headers)) - ); - - if (request.httpVersionMajor === 2) { - // strip out the HTTP/2 pseudo-headers because the `Headers` - // implementation doesn't like them - delete headers[':method']; - delete headers[':path']; - delete headers[':authority']; - delete headers[':scheme']; - delete headers[':status']; - } - return new Request(base + request.url, { // @ts-expect-error duplex: 'half', method: request.method, - headers, + headers: /** @type {Record} */ (request.headers), body: request.method === 'GET' || request.method === 'HEAD' ? undefined diff --git a/packages/kit/src/exports/vite/index.js b/packages/kit/src/exports/vite/index.js index 01f2c98f3f91..078c4b540487 100644 --- a/packages/kit/src/exports/vite/index.js +++ b/packages/kit/src/exports/vite/index.js @@ -348,6 +348,22 @@ async function kit({ svelte_config }) { * Stores the final config. */ configResolved(config) { + // we search for this plugin by name because we can't detect it + // since it doesn't directly modify the https config + const vite_basic_ssl = config.plugins.find(({ name }) => name === 'vite:basic-ssl'); + + // by default, when enabling HTTPS in Vite, it also enables HTTP/2 + // however, undici's Request implementation does not like the HTTP/2 headers + // we set a no-op proxy config to force Vite to downgrade to TLS-only + // see https://vitejs.dev/config/#server-https + if ((config.server.https || vite_basic_ssl) && !config.server.proxy) { + config.server.proxy = {}; + } + + if ((config.preview.https || vite_basic_ssl) && !config.preview.proxy) { + config.preview.proxy = {}; + } + vite_config = config; } }; From e01ba2a1937edbae418435ee4bdd4700d4642c19 Mon Sep 17 00:00:00 2001 From: Chew Tee Ming Date: Tue, 29 Oct 2024 18:23:22 +0800 Subject: [PATCH 05/10] changeset --- .changeset/unlucky-walls-drum.md | 2 +- packages/kit/src/exports/vite/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/unlucky-walls-drum.md b/.changeset/unlucky-walls-drum.md index 8389e0210462..30d81f0f3092 100644 --- a/.changeset/unlucky-walls-drum.md +++ b/.changeset/unlucky-walls-drum.md @@ -2,4 +2,4 @@ '@sveltejs/kit': patch --- -fix: strip HTTP/2 pseudo-headers and symbol request header keys to get Vite HTTPS working again +fix: set a no-op proxy config to force Vite to downgrade to TLS-only so that Vite HTTPS works diff --git a/packages/kit/src/exports/vite/index.js b/packages/kit/src/exports/vite/index.js index 078c4b540487..d64b0ebcebc2 100644 --- a/packages/kit/src/exports/vite/index.js +++ b/packages/kit/src/exports/vite/index.js @@ -353,7 +353,7 @@ async function kit({ svelte_config }) { const vite_basic_ssl = config.plugins.find(({ name }) => name === 'vite:basic-ssl'); // by default, when enabling HTTPS in Vite, it also enables HTTP/2 - // however, undici's Request implementation does not like the HTTP/2 headers + // however, undici's Headers implementation does not like the HTTP/2 headers // we set a no-op proxy config to force Vite to downgrade to TLS-only // see https://vitejs.dev/config/#server-https if ((config.server.https || vite_basic_ssl) && !config.server.proxy) { From 353e3f91a4677375c9adc0d90ac1b485d86ea87d Mon Sep 17 00:00:00 2001 From: Chew Tee Ming Date: Tue, 29 Oct 2024 18:24:38 +0800 Subject: [PATCH 06/10] shorter changeset --- .changeset/unlucky-walls-drum.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/unlucky-walls-drum.md b/.changeset/unlucky-walls-drum.md index 30d81f0f3092..c8d9f80fb7dd 100644 --- a/.changeset/unlucky-walls-drum.md +++ b/.changeset/unlucky-walls-drum.md @@ -2,4 +2,4 @@ '@sveltejs/kit': patch --- -fix: set a no-op proxy config to force Vite to downgrade to TLS-only so that Vite HTTPS works +fix: set a no-op proxy config so that Vite HTTPS works From 63abb4df28d3d588d15119c496114c7c38a3d0e0 Mon Sep 17 00:00:00 2001 From: Chew Tee Ming Date: Tue, 29 Oct 2024 18:30:20 +0800 Subject: [PATCH 07/10] explain more --- packages/kit/src/exports/vite/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kit/src/exports/vite/index.js b/packages/kit/src/exports/vite/index.js index d64b0ebcebc2..42a1e77bf8f2 100644 --- a/packages/kit/src/exports/vite/index.js +++ b/packages/kit/src/exports/vite/index.js @@ -349,7 +349,7 @@ async function kit({ svelte_config }) { */ configResolved(config) { // we search for this plugin by name because we can't detect it - // since it doesn't directly modify the https config + // since it doesn't directly modify the https config unlike mkcert const vite_basic_ssl = config.plugins.find(({ name }) => name === 'vite:basic-ssl'); // by default, when enabling HTTPS in Vite, it also enables HTTP/2 From 6ab649db1f2a9d9eda802d5b0595aeffcdf1b8ff Mon Sep 17 00:00:00 2001 From: Chew Tee Ming Date: Tue, 29 Oct 2024 19:51:20 +0800 Subject: [PATCH 08/10] explain mkcert plugin --- packages/kit/src/exports/vite/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kit/src/exports/vite/index.js b/packages/kit/src/exports/vite/index.js index 42a1e77bf8f2..369eb6a918ee 100644 --- a/packages/kit/src/exports/vite/index.js +++ b/packages/kit/src/exports/vite/index.js @@ -349,7 +349,7 @@ async function kit({ svelte_config }) { */ configResolved(config) { // we search for this plugin by name because we can't detect it - // since it doesn't directly modify the https config unlike mkcert + // since it doesn't directly modify the https config unlike the mkcert plugin const vite_basic_ssl = config.plugins.find(({ name }) => name === 'vite:basic-ssl'); // by default, when enabling HTTPS in Vite, it also enables HTTP/2 From 68f976ce38e5463b250ee9090a33993d9d4a87cc Mon Sep 17 00:00:00 2001 From: Ben McCann <322311+benmccann@users.noreply.github.com> Date: Mon, 4 Nov 2024 16:20:16 -0800 Subject: [PATCH 09/10] Update packages/kit/src/exports/vite/index.js --- packages/kit/src/exports/vite/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kit/src/exports/vite/index.js b/packages/kit/src/exports/vite/index.js index 369eb6a918ee..3af4b2fb08ed 100644 --- a/packages/kit/src/exports/vite/index.js +++ b/packages/kit/src/exports/vite/index.js @@ -353,7 +353,7 @@ async function kit({ svelte_config }) { const vite_basic_ssl = config.plugins.find(({ name }) => name === 'vite:basic-ssl'); // by default, when enabling HTTPS in Vite, it also enables HTTP/2 - // however, undici's Headers implementation does not like the HTTP/2 headers + // however, undici has not yet enabled HTTP/2 by default: https://github.com/nodejs/undici/issues/2750 // we set a no-op proxy config to force Vite to downgrade to TLS-only // see https://vitejs.dev/config/#server-https if ((config.server.https || vite_basic_ssl) && !config.server.proxy) { From b604ea414906c4bea289d713188afe4c4fedc752 Mon Sep 17 00:00:00 2001 From: Ben McCann <322311+benmccann@users.noreply.github.com> Date: Mon, 4 Nov 2024 16:36:52 -0800 Subject: [PATCH 10/10] Update .changeset/unlucky-walls-drum.md --- .changeset/unlucky-walls-drum.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/unlucky-walls-drum.md b/.changeset/unlucky-walls-drum.md index c8d9f80fb7dd..f0cb9a403960 100644 --- a/.changeset/unlucky-walls-drum.md +++ b/.changeset/unlucky-walls-drum.md @@ -2,4 +2,4 @@ '@sveltejs/kit': patch --- -fix: set a no-op proxy config so that Vite HTTPS works +fix: when using `@vitejs/plugin-basic-ssl`, set a no-op proxy config to downgrade from HTTP/2 to TLS since `undici` does not yet enable HTTP/2 by default