Skip to content

Commit 1c18ebf

Browse files
committed
feat: add support for changeOrigin
1 parent 6199374 commit 1c18ebf

File tree

8 files changed

+291
-9
lines changed

8 files changed

+291
-9
lines changed

bin/cli.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ interface CLIOptions {
2121
startCommand?: string
2222
startCwd?: string
2323
startEnv?: string
24+
changeOrigin?: boolean
2425
verbose?: boolean
2526
}
2627

@@ -36,11 +37,13 @@ cli
3637
.option('--start-command <command>', 'Command to start the dev server')
3738
.option('--start-cwd <path>', 'Current working directory for the dev server')
3839
.option('--start-env <env>', 'Environment variables for the dev server')
40+
.option('--change-origin', 'Change the origin of the host header to the target URL')
3941
.option('--verbose', 'Enable verbose logging')
4042
.example('rpx start --from localhost:5173 --to my-project.localhost')
4143
.example('rpx start --from localhost:3000 --to my-project.localhost/api')
4244
.example('rpx start --from localhost:3000 --to localhost:3001')
4345
.example('rpx start --from localhost:5173 --to my-project.test --key-path /absolute/path/to/key --cert-path /absolute/path/to/cert')
46+
.example('rpx start --from localhost:5173 --to my-project.localhost --change-origin')
4447
.action(async (options?: CLIOptions) => {
4548
if (!options?.from || !options.to) {
4649
return startProxies(config)
@@ -60,6 +63,7 @@ cli
6063
hosts: options.hostsCleanup || false,
6164
},
6265
verbose: options.verbose || false,
66+
changeOrigin: options.changeOrigin || false,
6367
}
6468

6569
// Add start options if provided

packages/rpx/bin/cli.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ interface CLIOptions {
2121
startCommand?: string
2222
startCwd?: string
2323
startEnv?: string
24+
changeOrigin?: boolean
2425
verbose?: boolean
2526
}
2627

@@ -36,11 +37,13 @@ cli
3637
.option('--start-command <command>', 'Command to start the dev server')
3738
.option('--start-cwd <path>', 'Current working directory for the dev server')
3839
.option('--start-env <env>', 'Environment variables for the dev server')
40+
.option('--change-origin', 'Change the origin of the host header to the target URL')
3941
.option('--verbose', 'Enable verbose logging')
4042
.example('rpx start --from localhost:5173 --to my-project.localhost')
4143
.example('rpx start --from localhost:3000 --to my-project.localhost/api')
4244
.example('rpx start --from localhost:3000 --to localhost:3001')
4345
.example('rpx start --from localhost:5173 --to my-project.test --key-path /absolute/path/to/key --cert-path /absolute/path/to/cert')
46+
.example('rpx start --from localhost:5173 --to my-project.localhost --change-origin')
4447
.action(async (options?: CLIOptions) => {
4548
if (!options?.from || !options.to) {
4649
return startProxies(config)
@@ -60,6 +63,7 @@ cli
6063
hosts: options.hostsCleanup || false,
6164
},
6265
verbose: options.verbose || false,
66+
changeOrigin: options.changeOrigin || false,
6367
}
6468

6569
// Add start options if provided

packages/rpx/src/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export const defaultConfig: ProxyConfig = {
1919
},
2020
vitePluginUsage: false,
2121
verbose: true,
22+
changeOrigin: false,
2223
}
2324

2425
// eslint-disable-next-line antfu/no-top-level-await

packages/rpx/src/start.ts

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,10 @@ export async function cleanup(options?: CleanupOptions): Promise<void> {
120120
}
121121
finally {
122122
isCleaningUp = false
123-
process.exit(0)
123+
// Only exit the process if not running in a test environment
124+
if (process.env.NODE_ENV !== 'test' && process.env.BUN_ENV !== 'test') {
125+
process.exit(0)
126+
}
124127
}
125128
}
126129

@@ -366,6 +369,7 @@ async function createProxyServer(
366369
vitePluginUsage?: boolean,
367370
verbose?: boolean,
368371
cleanUrls?: boolean,
372+
changeOrigin?: boolean,
369373
): Promise<void> {
370374
debugLog('proxy', `Creating proxy server ${from} -> ${to} with cleanUrls: ${cleanUrls}`, verbose)
371375

@@ -409,12 +413,21 @@ async function createProxyServer(
409413
}
410414
}
411415

416+
// Normalize request headers
417+
const normalizedHeaders = normalizeHeaders(req.headers)
418+
419+
// Handle changeOrigin option - modify the host header to match the target
420+
if (changeOrigin) {
421+
normalizedHeaders.host = `${sourceUrl.hostname}:${fromPort}`
422+
debugLog('request', `Changed origin: setting host header to ${normalizedHeaders.host}`, verbose)
423+
}
424+
412425
const proxyOptions = {
413426
hostname: sourceUrl.hostname,
414427
port: fromPort,
415428
path,
416429
method,
417-
headers: normalizeHeaders(req.headers),
430+
headers: normalizedHeaders,
418431
}
419432

420433
debugLog('request', `Proxy request options: ${JSON.stringify(proxyOptions)}`, verbose)
@@ -546,11 +559,8 @@ async function createProxyServer(
546559
server = http.createServer(requestHandler)
547560
}
548561

549-
// Update the activeServers Set type
550-
const activeServers = new Set<http.Server | https.Server>()
551-
552562
function setupServer(serverInstance: AnyServerType) {
553-
// Type assertion since we know these servers are compatible
563+
// Use the module-level activeServers set
554564
activeServers.add(serverInstance as http.Server | https.Server)
555565

556566
return new Promise<void>((resolve, reject) => {
@@ -582,7 +592,7 @@ async function createProxyServer(
582592
export async function setupProxy(options: ProxySetupOptions): Promise<void> {
583593
debugLog('setup', `Setting up reverse proxy: ${JSON.stringify(options)}`, options.verbose)
584594

585-
const { from, to, fromPort, sourceUrl, ssl, verbose, cleanup: cleanupOptions, vitePluginUsage, portManager } = options
595+
const { from, to, fromPort, sourceUrl, ssl, verbose, cleanup: cleanupOptions, vitePluginUsage, portManager, changeOrigin, cleanUrls } = options
586596
const httpPort = 80
587597
const httpsPort = 443
588598
const hostname = '0.0.0.0'
@@ -620,7 +630,7 @@ export async function setupProxy(options: ProxySetupOptions): Promise<void> {
620630
log.info(`You can use 'sudo lsof -i :${targetPort}' (Unix) or 'netstat -ano | findstr :${targetPort}' (Windows) to check what's using the port.`)
621631
}
622632

623-
await createProxyServer(from, to, fromPort, finalPort, hostname, sourceUrl, ssl, vitePluginUsage, verbose)
633+
await createProxyServer(from, to, fromPort, finalPort, hostname, sourceUrl, ssl, vitePluginUsage, verbose, cleanUrls, changeOrigin)
624634
}
625635
catch (err) {
626636
debugLog('setup', `Setup failed: ${err}`, verbose)
@@ -666,6 +676,7 @@ export function startProxy(options: ProxyOption): void {
666676
https: httpsConfig(mergedOptions),
667677
cleanup: mergedOptions.cleanup,
668678
vitePluginUsage: mergedOptions.vitePluginUsage,
679+
changeOrigin: mergedOptions.changeOrigin,
669680
verbose: mergedOptions.verbose,
670681
}
671682

@@ -799,6 +810,7 @@ export async function startProxies(options?: ProxyOptions): Promise<void> {
799810
cleanup: mergedOptions.cleanup,
800811
cleanUrls: proxy.cleanUrls ?? ('cleanUrls' in mergedOptions ? mergedOptions.cleanUrls : false),
801812
vitePluginUsage: mergedOptions.vitePluginUsage,
813+
changeOrigin: proxy.changeOrigin ?? mergedOptions.changeOrigin,
802814
verbose: mergedOptions.verbose,
803815
_cachedSSLConfig: mergedOptions._cachedSSLConfig,
804816
}))
@@ -809,9 +821,10 @@ export async function startProxies(options?: ProxyOptions): Promise<void> {
809821
https: mergedOptions.https,
810822
cleanup: mergedOptions.cleanup,
811823
vitePluginUsage: mergedOptions.vitePluginUsage,
824+
start: mergedOptions.start,
825+
changeOrigin: mergedOptions.changeOrigin,
812826
verbose: mergedOptions.verbose,
813827
_cachedSSLConfig: mergedOptions._cachedSSLConfig,
814-
start: mergedOptions.start,
815828
}]
816829

817830
// Extract domains for cleanup
@@ -862,6 +875,7 @@ export async function startProxies(options?: ProxyOptions): Promise<void> {
862875
vitePluginUsage: option.vitePluginUsage || false,
863876
verbose: option.verbose || false,
864877
_cachedSSLConfig: sslConfig,
878+
changeOrigin: option.changeOrigin || false,
865879
})
866880
}
867881
catch (err) {

packages/rpx/src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export interface SharedProxyConfig {
3232
_cachedSSLConfig?: SSLConfig | null
3333
start?: StartOptions
3434
cleanUrls: boolean
35+
changeOrigin?: boolean // default: false - changes the origin of the host header to the target URL
3536
}
3637

3738
export type SharedProxyOptions = Partial<SharedProxyConfig>

0 commit comments

Comments
 (0)