Skip to content

Commit dd5912c

Browse files
hallvictoriaVictoria Hall
and
Victoria Hall
authored
Add port validation checks for HTTP streaming (#315)
* basic working prototype * cleaner implementation * typing fixes + removed logs * removed logs * trying random port * port variables * checking only 25 ports --------- Co-authored-by: Victoria Hall <victoria.hall@microsoft.com>
1 parent cc3613c commit dd5912c

File tree

1 file changed

+55
-1
lines changed

1 file changed

+55
-1
lines changed

src/http/httpProxy.ts

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@
44
import { serialize as serializeCookie } from 'cookie';
55
import { EventEmitter } from 'events';
66
import * as http from 'http';
7+
import * as net from 'net';
78
import { AzFuncSystemError, ensureErrorType } from '../errors';
89
import { nonNullProp } from '../utils/nonNull';
910
import { workerSystemLog } from '../utils/workerSystemLog';
1011
import { HttpResponse } from './HttpResponse';
1112

1213
const requests: Record<string, http.IncomingMessage> = {};
1314
const responses: Record<string, http.ServerResponse> = {};
15+
const minPort = 55000;
16+
const maxPort = 55025;
1417

1518
const invocRequestEmitter = new EventEmitter();
1619

@@ -105,8 +108,24 @@ export async function setupHttpProxy(): Promise<string> {
105108

106109
server.listen(() => {
107110
const address = server.address();
111+
// Valid address has been created
108112
if (address !== null && typeof address === 'object') {
109-
resolve(`http://localhost:${address.port}/`);
113+
if (address.port === 0) {
114+
// Auto-assigned port is 0, find and bind to an open port
115+
workerSystemLog('debug', `Port 0 assigned. Finding open port.`);
116+
findOpenPort((openPort: number) => {
117+
// Close the server and re-listen on the found open port
118+
server.close();
119+
server.listen(openPort, () => {
120+
workerSystemLog('debug', `Server is now listening on found open port: ${openPort}`);
121+
});
122+
resolve(`http://localhost:${openPort}/`);
123+
});
124+
} else {
125+
// Auto-assigned port is not 0
126+
workerSystemLog('debug', `Auto-assigned port is valid. Port: ${address.port}`);
127+
resolve(`http://localhost:${address.port}/`);
128+
}
110129
} else {
111130
reject(new AzFuncSystemError('Unexpected server address during http proxy setup'));
112131
}
@@ -117,3 +136,38 @@ export async function setupHttpProxy(): Promise<string> {
117136
});
118137
});
119138
}
139+
140+
// Function to find an open port starting from a specified port
141+
function findOpenPort(callback: (port: number) => void): void {
142+
const server = net.createServer();
143+
144+
function tryPort(port: number) {
145+
if (port > maxPort) {
146+
// If we've reached the maximum port, throw an error
147+
throw new AzFuncSystemError(
148+
`No available ports found between ${minPort} and ${maxPort}. To enable HTTP streaming, please open a port in this range.`
149+
);
150+
}
151+
152+
server.once('error', () => {
153+
// If the port is unavailable, increment and try the next one
154+
tryPort(port + 1);
155+
});
156+
157+
// If the port is available, return it
158+
server.once('listening', () => {
159+
const address = server.address();
160+
if (address !== null && typeof address === 'object') {
161+
port = address.port;
162+
server.close();
163+
callback(port);
164+
}
165+
});
166+
167+
// Try binding to the given port
168+
server.listen(port);
169+
}
170+
171+
// Start trying from the specified starting port
172+
tryPort(minPort);
173+
}

0 commit comments

Comments
 (0)