diff --git a/packages/vite/src/node/server/middlewares/indexHtml.ts b/packages/vite/src/node/server/middlewares/indexHtml.ts index bc9ddb3f5f93ab..c8922f0dfe489c 100644 --- a/packages/vite/src/node/server/middlewares/indexHtml.ts +++ b/packages/vite/src/node/server/middlewares/indexHtml.ts @@ -150,7 +150,6 @@ const devHtmlHook: IndexHtmlTransformHook = async ( ) => { const { config, moduleGraph, watcher } = server! const base = config.base || '/' - htmlPath = decodeURI(htmlPath) let proxyModulePath: string let proxyModuleUrl: string @@ -172,9 +171,10 @@ const devHtmlHook: IndexHtmlTransformHook = async ( const s = new MagicString(html) let inlineModuleIndex = -1 - const proxyCacheUrl = cleanUrl(proxyModulePath).replace( - normalizePath(config.root), - '', + // The key to the proxyHtml cache is decoded, as it will be compared + // against decoded URLs by the HTML plugins. + const proxyCacheUrl = decodeURI( + cleanUrl(proxyModulePath).replace(normalizePath(config.root), ''), ) const styleUrl: AssetNode[] = [] @@ -348,7 +348,12 @@ export function indexHtmlMiddleware( function preTransformRequest(server: ViteDevServer, url: string, base: string) { if (!server.config.server.preTransformRequests) return - url = unwrapId(stripBase(url, base)) + try { + url = unwrapId(stripBase(decodeURI(url), base)) + } catch { + // ignore + return + } // transform all url as non-ssr as html includes client-side assets only server.transformRequest(url).catch((e) => { diff --git a/playground/ssr/__tests__/ssr.spec.ts b/playground/ssr/__tests__/ssr.spec.ts index 2d62a7079feecb..8c29c2169f0343 100644 --- a/playground/ssr/__tests__/ssr.spec.ts +++ b/playground/ssr/__tests__/ssr.spec.ts @@ -1,6 +1,6 @@ import { expect, test } from 'vitest' import { port, serverLogs } from './serve' -import { editFile, page, withRetry } from '~utils' +import { browserLogs, editFile, isServe, page, withRetry } from '~utils' const url = `http://localhost:${port}` @@ -29,3 +29,11 @@ test('should restart ssr', async () => { ) }) }) + +test.runIf(isServe)('html proxy is encoded', async () => { + await page.goto( + `${url}?%22%3E%3C/script%3E%3Cscript%3Econsole.log(%27html proxy is not encoded%27)%3C/script%3E`, + ) + + expect(browserLogs).not.toContain('html proxy is not encoded') +}) diff --git a/playground/ssr/index.html b/playground/ssr/index.html index 8121bbab93eac1..1b901ee15cf153 100644 --- a/playground/ssr/index.html +++ b/playground/ssr/index.html @@ -4,6 +4,10 @@