routing fixes

This commit is contained in:
ProgrammerIn-wonderland committed 2026-10-26 16:35:44 -04:00
1 parent f61b3ea546
commit df9ce2c76f
2 files changed
+79 -9

No files matched your search

+52
View File
@@ -468,6 +468,58 @@ describe('PuterServer host header validation — permissive modes', () => {
});
});
describe('PuterServer host header validation — custom domains with every host accepted', () => {
let server: PuterServer;
let port: number;
beforeAll(async () => {
port = await allocateEphemeralPort();
server = await setupTestServer(
{
port,
domain: 'puter.localhost',
origin: `http://puter.localhost:${port}`,
allow_all_host_values: true,
custom_domains_enabled: true,
static_hosting_domain: 'site.puter.localhost',
} as unknown as IConfig,
{ listen: true },
);
});
afterAll(async () => {
await server?.shutdown();
});
it('still hands a host outside our domains to site hosting', async () => {
const res = await rawRequest(port, '/', {
host: 'www.my-own-domain.example',
});
expect(res.status).toBe(404);
expect(res.body).toBe('Site not found');
});
it('leaves our own domain to the GUI', async () => {
const res = await rawRequest(port, '/healthcheck', {
host: `puter.localhost:${port}`,
});
expect(res.status).toBe(200);
});
it('never treats an IP or localhost as a custom domain', async () => {
for (const host of [
`127.0.0.1:${port}`,
`[::1]:${port}`,
`localhost:${port}`,
]) {
const res = await rawRequest(port, '/healthcheck', { host });
expect(res.status, host).toBe(200);
const root = await rawRequest(port, '/', { host });
expect(root.body, host).not.toBe('Site not found');
}
});
});
describe('PuterServer request parsing', () => {
let server: PuterServer;
let port: number;
+27 -9
View File
@@ -29,6 +29,7 @@ import path from 'node:path';
import { pathToFileURL } from 'node:url';
import { parseArgs } from 'node:util';
import http from 'node:http';
import { isIP } from 'node:net';
import { puterClients } from './clients';
import { puterControllers } from './controllers';
import { createAuthProbe } from './core/http/middleware/authProbe';
@@ -597,7 +598,32 @@ export class PuterServer {
// Build the allowed-domain set from config.
this.#app.use((req, res, next) => {
const hostName = (req.headers.host ?? '')
.split(':')[0]
.trim()
.toLowerCase();
const isOwnHost =
!hostName ||
this.#getAllowedDomains().some((d) =>
PuterServer.#hostMatchesDomain(hostName, d),
);
// Accepting every host still has to tell custom domains apart, or
// they fall through to the API/GUI instead of site hosting. An IP
// or localhost is never one: load balancer health checks and
// in-cluster callers address the server that way.
if (config.allow_all_host_values) {
if (
config.custom_domains_enabled &&
!isOwnHost &&
req.path !== '/healthcheck' &&
// `[` is what an IPv6 literal's `[::1]:port` splits to.
!hostName.startsWith('[') &&
isIP(hostName) === 0 &&
hostName !== 'localhost'
) {
req.is_custom_domain = true;
}
next();
return;
}
@@ -613,15 +639,7 @@ export class PuterServer {
return;
}
const hostName = (req.headers.host ?? '')
.split(':')[0]
.trim()
.toLowerCase();
const allowed = this.#getAllowedDomains();
if (
allowed.some((d) => PuterServer.#hostMatchesDomain(hostName, d))
) {
if (isOwnHost) {
next();
return;
}