Skip to content

Commit aeb3ec8

Browse files
authoredJan 21, 2025··
fix: preview.allowedHosts with specific values was not respected (#19246)
1 parent 9654348 commit aeb3ec8

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
@@ -208,7 +208,7 @@ export async function preview(
208208
const { allowedHosts } = config.preview
209209
// no need to check for HTTPS as HTTPS is not vulnerable to DNS rebinding attacks
210210
if (allowedHosts !== true && !config.preview.https) {
211-
app.use(hostCheckMiddleware(config))
211+
app.use(hostCheckMiddleware(config, true))
212212
}
213213

214214
// proxy

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -862,7 +862,7 @@ export async function _createServer(
862862
const { allowedHosts } = serverConfig
863863
// no need to check for HTTPS as HTTPS is not vulnerable to DNS rebinding attacks
864864
if (allowedHosts !== true && !serverConfig.https) {
865-
middlewares.use(hostCheckMiddleware(config))
865+
middlewares.use(hostCheckMiddleware(config, false))
866866
}
867867

868868
middlewares.use(cachedTransformMiddleware(server))

‎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
@@ -167,7 +167,7 @@ export function createWebSocketServer(
167167
if (protocol === 'vite-ping') return true
168168

169169
const hostHeader = req.headers.host
170-
if (!hostHeader || !isHostAllowed(config, hostHeader)) {
170+
if (!hostHeader || !isHostAllowed(config, false, hostHeader)) {
171171
return false
172172
}
173173

0 commit comments

Comments
 (0)
Please sign in to comment.