44import { serialize as serializeCookie } from 'cookie' ;
55import { EventEmitter } from 'events' ;
66import * as http from 'http' ;
7+ import * as net from 'net' ;
78import { AzFuncSystemError , ensureErrorType } from '../errors' ;
89import { nonNullProp } from '../utils/nonNull' ;
910import { workerSystemLog } from '../utils/workerSystemLog' ;
1011import { HttpResponse } from './HttpResponse' ;
1112
1213const requests : Record < string , http . IncomingMessage > = { } ;
1314const responses : Record < string , http . ServerResponse > = { } ;
15+ const minPort = 55000 ;
16+ const maxPort = 55025 ;
1417
1518const 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