Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/validate-listen-port.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'serve': patch
---

Validate `--listen` port numbers instead of crashing with a RangeError
19 changes: 15 additions & 4 deletions source/utilities/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,14 @@ export const getHelpText = (): string => helpText;
* @returns A list of parsed endpoints.
*/
export const parseEndpoint = (uriOrPort: string): ParsedEndpoint => {
// If the endpoint is a port number, return it as is.
if (!isNaN(Number(uriOrPort))) return { port: Number(uriOrPort) };
// If the endpoint is a port number, return it as is. Reject numbers the
// socket layer cannot bind to, instead of crashing later with a RangeError.
if (!isNaN(Number(uriOrPort))) {
const port = Number(uriOrPort);
if (!Number.isInteger(port) || port < 0 || port > 65535)
throw new Error(`Invalid port number: ${uriOrPort}`);
return { port };
}

// Cast it as a string, since we know for sure it is not a number.
const endpoint = uriOrPort;
Expand All @@ -125,14 +131,19 @@ export const parseEndpoint = (uriOrPort: string): ParsedEndpoint => {
throw new Error(`Invalid UNIX domain socket endpoint: ${endpoint}`);

return { host: url.pathname };
case 'tcp:':
case 'tcp:': {
url.port = url.port ?? '3000';
url.hostname = url.hostname ?? 'localhost';

const port = Number(url.port);
if (!Number.isInteger(port) || port < 0 || port > 65535)
throw new Error(`Invalid port number: ${url.port}`);

return {
port: Number(url.port),
port,
host: url.hostname,
};
}
default:
throw new Error(
`Unknown --listen endpoint scheme (protocol): ${
Expand Down
5 changes: 5 additions & 0 deletions tests/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ const invalidEndpoints = [
['protocol', 'ws://localhost', /unknown.*endpoint.*scheme.*/i],
['unix socket', 'unix://', /invalid.*unix.*socket.*/i],
['windows pipe', 'pipe:\\localhost', /invalid.*pipe.*/i],
['negative port', '-1', /invalid.*port/i],
['out of range port', '99999', /invalid.*port/i],
['fractional port', '3000.5', /invalid.*port/i],
['non-finite port', 'Infinity', /invalid.*port/i],
['tcp out of range port', 'tcp://localhost:99999', /invalid.*port/i],
] as InvalidEndpointTestCase[];

describe('utilities/cli', () => {
Expand Down