Skip to content

Commit 735f9a1

Browse files
ctatesapphi-red
andauthored
feat(server): support multiple hosts in __VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS (#21501)
Co-authored-by: sapphi-red <49056869+sapphi-red@users.noreply.github.com>
1 parent 0b7aaed commit 735f9a1

3 files changed

Lines changed: 123 additions & 3 deletions

File tree

docs/config/server-options.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ Setting `server.allowedHosts` to `true` allows any website to send requests to y
5757
:::
5858

5959
::: details Configure via environment variable
60-
You can set the environment variable `__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS` to add an additional allowed host.
60+
You can set the environment variable `__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS` to add additional allowed hosts. Use commas to separate multiple hosts (e.g., `host1.example.com,host2.example.com`).
6161
:::
6262

6363
## server.port

packages/vite/src/node/__tests__/config.spec.ts

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ import { afterEach, describe, expect, test, vi } from 'vitest'
55
import type { InlineConfig, PluginOption } from '..'
66
import type { UserConfig, UserConfigExport } from '../config'
77
import { defineConfig, loadConfigFromFile, resolveConfig } from '../config'
8+
import { resolveServerOptions } from '../server'
89
import { resolveEnvPrefix } from '../env'
910
import { hasBothRollupOptionsAndRolldownOptions, mergeConfig } from '../utils'
1011
import { createLogger } from '../logger'
12+
import type { Logger } from '../logger'
1113

1214
describe('mergeConfig', () => {
1315
test('handles configs with different alias schemas', () => {
@@ -1417,3 +1419,106 @@ describe('loadConfigFromFile', () => {
14171419
})
14181420
})
14191421
})
1422+
1423+
describe('resolveServerOptions', () => {
1424+
const warnFn = vi.fn()
1425+
const logger = { warn: warnFn } as unknown as Logger
1426+
1427+
afterEach(() => {
1428+
delete process.env.__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS
1429+
})
1430+
1431+
test('adds single host from __VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS', async () => {
1432+
process.env.__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS = 'example.com'
1433+
const resolved = await resolveServerOptions(
1434+
'/root',
1435+
{ allowedHosts: [] },
1436+
logger,
1437+
)
1438+
expect(resolved.allowedHosts).toEqual(['example.com'])
1439+
})
1440+
1441+
test('adds multiple hosts from __VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS', async () => {
1442+
process.env.__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS =
1443+
'example.com,test.com,dev.example.org'
1444+
const resolved = await resolveServerOptions(
1445+
'/root',
1446+
{ allowedHosts: [] },
1447+
logger,
1448+
)
1449+
expect(resolved.allowedHosts).toEqual([
1450+
'example.com',
1451+
'test.com',
1452+
'dev.example.org',
1453+
])
1454+
})
1455+
1456+
test('trims whitespace from hosts in __VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS', async () => {
1457+
process.env.__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS =
1458+
' example.com , test.com , dev.example.org '
1459+
const resolved = await resolveServerOptions(
1460+
'/root',
1461+
{ allowedHosts: [] },
1462+
logger,
1463+
)
1464+
expect(resolved.allowedHosts).toEqual([
1465+
'example.com',
1466+
'test.com',
1467+
'dev.example.org',
1468+
])
1469+
})
1470+
1471+
test('filters empty hosts from __VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS', async () => {
1472+
process.env.__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS =
1473+
'example.com,,test.com,,'
1474+
const resolved = await resolveServerOptions(
1475+
'/root',
1476+
{ allowedHosts: [] },
1477+
logger,
1478+
)
1479+
expect(resolved.allowedHosts).toEqual(['example.com', 'test.com'])
1480+
})
1481+
1482+
test('appends to existing allowedHosts', async () => {
1483+
process.env.__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS = 'new.com,another.com'
1484+
const resolved = await resolveServerOptions(
1485+
'/root',
1486+
{ allowedHosts: ['existing.com'] },
1487+
logger,
1488+
)
1489+
expect(resolved.allowedHosts).toEqual([
1490+
'existing.com',
1491+
'new.com',
1492+
'another.com',
1493+
])
1494+
})
1495+
1496+
test('does not modify allowedHosts when set to true', async () => {
1497+
process.env.__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS = 'example.com'
1498+
const resolved = await resolveServerOptions(
1499+
'/root',
1500+
{ allowedHosts: true },
1501+
logger,
1502+
)
1503+
expect(resolved.allowedHosts).toBe(true)
1504+
})
1505+
1506+
test('throw an error if it contains `"` or `\'` or `\\`', async () => {
1507+
const envs = ['"example.com"', "'example.com'", '\\example.com']
1508+
for (const env of envs) {
1509+
process.env.__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS = env
1510+
const resolved = await resolveServerOptions(
1511+
'/root',
1512+
{ allowedHosts: [] },
1513+
logger,
1514+
)
1515+
expect(resolved.allowedHosts).toEqual([])
1516+
expect(warnFn).toHaveBeenCalledWith(
1517+
expect.stringContaining(
1518+
'Skipping additional allowed hosts from environment variable due to reserved characters',
1519+
),
1520+
)
1521+
warnFn.mockClear()
1522+
}
1523+
})
1524+
})

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

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1188,6 +1188,8 @@ const _serverConfigDefaults = Object.freeze({
11881188
export const serverConfigDefaults: Readonly<Partial<ServerOptions>> =
11891189
_serverConfigDefaults
11901190

1191+
const RESERVED_ALLOWED_HOSTS_CHARACTERS_RE = /[\\"']/
1192+
11911193
export async function resolveServerOptions(
11921194
root: string,
11931195
raw: ServerOptions | undefined,
@@ -1266,8 +1268,21 @@ export async function resolveServerOptions(
12661268
process.env.__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS &&
12671269
Array.isArray(server.allowedHosts)
12681270
) {
1269-
const additionalHost = process.env.__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS
1270-
server.allowedHosts = [...server.allowedHosts, additionalHost]
1271+
const rawAdditionalHosts =
1272+
process.env.__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS
1273+
if (RESERVED_ALLOWED_HOSTS_CHARACTERS_RE.test(rawAdditionalHosts)) {
1274+
logger.warn(
1275+
colors.yellow(
1276+
`${colors.bold('(!)')} Skipping additional allowed hosts from environment variable due to reserved characters. Received: "${rawAdditionalHosts}".`,
1277+
),
1278+
)
1279+
} else {
1280+
const additionalHosts = rawAdditionalHosts
1281+
.split(',')
1282+
.map((host) => host.trim())
1283+
.filter(Boolean)
1284+
server.allowedHosts = [...server.allowedHosts, ...additionalHosts]
1285+
}
12711286
}
12721287

12731288
return server

0 commit comments

Comments
 (0)