Skip to content

Commit 0bc52e0

Browse files
committed
fix: preview.allowedHosts with specific values was not respected (#19246)
1 parent 947f0c1 commit 0bc52e0

File tree

4 files changed

+26
-14
lines changed

4 files changed

+26
-14
lines changed

packages/vite/src/node/preview.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ export async function preview(
154154
const { allowedHosts } = config.preview
155155
// no need to check for HTTPS as HTTPS is not vulnerable to DNS rebinding attacks
156156
if (allowedHosts !== true && !config.preview.https) {
157-
app.use(hostCheckMiddleware(config))
157+
app.use(hostCheckMiddleware(config, true))
158158
}
159159

160160
// proxy

packages/vite/src/node/server/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -622,7 +622,7 @@ export async function _createServer(
622622
const { allowedHosts } = serverConfig
623623
// no need to check for HTTPS as HTTPS is not vulnerable to DNS rebinding attacks
624624
if (allowedHosts !== true && !serverConfig.https) {
625-
middlewares.use(hostCheckMiddleware(config))
625+
middlewares.use(hostCheckMiddleware(config, false))
626626
}
627627

628628
// proxy

packages/vite/src/node/server/middlewares/hostCheck.ts

+23-11
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import type { Connect } from 'dep-types/connect'
33
import type { ResolvedConfig } from '../../config'
44
import type { ResolvedPreviewOptions, ResolvedServerOptions } from '../..'
55

6-
const allowedHostsCache = new WeakMap<ResolvedConfig, Set<string>>()
6+
const allowedHostsServerCache = new WeakMap<ResolvedConfig, Set<string>>()
7+
const allowedHostsPreviewCache = new WeakMap<ResolvedConfig, Set<string>>()
78

89
const isFileOrExtensionProtocolRE = /^(?:file|.+-extension):/i
910

@@ -118,48 +119,59 @@ export function isHostAllowedWithoutCache(
118119

119120
/**
120121
* @param config resolved config
122+
* @param isPreview whether it's for the preview server or not
121123
* @param host the value of host header. See [RFC 9110 7.2](https://datatracker.ietf.org/doc/html/rfc9110#name-host-and-authority).
122124
*/
123-
export function isHostAllowed(config: ResolvedConfig, host: string): boolean {
124-
if (config.server.allowedHosts === true) {
125+
export function isHostAllowed(
126+
config: ResolvedConfig,
127+
isPreview: boolean,
128+
host: string,
129+
): boolean {
130+
const allowedHosts = isPreview
131+
? config.preview.allowedHosts
132+
: config.server.allowedHosts
133+
if (allowedHosts === true) {
125134
return true
126135
}
127136

128-
if (!allowedHostsCache.has(config)) {
129-
allowedHostsCache.set(config, new Set())
137+
const cache = isPreview ? allowedHostsPreviewCache : allowedHostsServerCache
138+
if (!cache.has(config)) {
139+
cache.set(config, new Set())
130140
}
131141

132-
const allowedHosts = allowedHostsCache.get(config)!
133-
if (allowedHosts.has(host)) {
142+
const cachedAllowedHosts = cache.get(config)!
143+
if (cachedAllowedHosts.has(host)) {
134144
return true
135145
}
136146

137147
const result = isHostAllowedWithoutCache(
138-
config.server.allowedHosts ?? [],
148+
allowedHosts ?? [],
139149
config.additionalAllowedHosts,
140150
host,
141151
)
142152
if (result) {
143-
allowedHosts.add(host)
153+
cachedAllowedHosts.add(host)
144154
}
145155
return result
146156
}
147157

148158
export function hostCheckMiddleware(
149159
config: ResolvedConfig,
160+
isPreview: boolean,
150161
): Connect.NextHandleFunction {
151162
// Keep the named function. The name is visible in debug logs via `DEBUG=connect:dispatcher ...`
152163
return function viteHostCheckMiddleware(req, res, next) {
153164
const hostHeader = req.headers.host
154-
if (!hostHeader || !isHostAllowed(config, hostHeader)) {
165+
if (!hostHeader || !isHostAllowed(config, isPreview, hostHeader)) {
155166
const hostname = hostHeader?.replace(/:\d+$/, '')
156167
const hostnameWithQuotes = JSON.stringify(hostname)
168+
const optionName = `${isPreview ? 'preview' : 'server'}.allowedHosts`
157169
res.writeHead(403, {
158170
'Content-Type': 'text/plain',
159171
})
160172
res.end(
161173
`Blocked request. This host (${hostnameWithQuotes}) is not allowed.\n` +
162-
`To allow this host, add ${hostnameWithQuotes} to \`server.allowedHosts\` in vite.config.js.`,
174+
`To allow this host, add ${hostnameWithQuotes} to \`${optionName}\` in vite.config.js.`,
163175
)
164176
return
165177
}

packages/vite/src/node/server/ws.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ export function createWebSocketServer(
141141

142142
const shouldHandle = (req: IncomingMessage) => {
143143
const hostHeader = req.headers.host
144-
if (!hostHeader || !isHostAllowed(config, hostHeader)) {
144+
if (!hostHeader || !isHostAllowed(config, false, hostHeader)) {
145145
return false
146146
}
147147

0 commit comments

Comments
 (0)