@@ -83,14 +83,117 @@ public class IlpEndpoint : Endpoint<Request, JsonErrorResponse?>
8383{
8484 private const string Username = "admin" ;
8585 private const string Password = "quest" ;
86- public static readonly StringBuilder ReceiveBuffer = new ( ) ;
87- public static readonly List < byte > ReceiveBytes = new ( ) ;
88- public static Exception ? LastError = new ( ) ;
86+
87+ // Port-keyed storage to support multiple concurrent DummyHttpServer instances
88+ private static readonly Dictionary < int , ( StringBuilder Buffer , List < byte > Bytes , Exception ? Error , int Counter ) >
89+ PortData = new ( ) ;
90+
91+ // Port-keyed configuration to support multiple concurrent DummyHttpServer instances
92+ private static readonly Dictionary < int , ( bool TokenAuth , bool BasicAuth , bool RetriableError , bool ErrorMessage ) >
93+ PortConfig = new ( ) ;
94+
95+ // Configuration flags (global, apply to all servers) - kept for backwards compatibility
8996 public static bool WithTokenAuth = false ;
9097 public static bool WithBasicAuth = false ;
9198 public static bool WithRetriableError = false ;
9299 public static bool WithErrorMessage = false ;
93- public static int Counter ;
100+
101+ // Get the port from request headers (set by DummyHttpServer)
102+ private static int GetPortKey ( HttpContext context )
103+ {
104+ if ( context ? . Request . Headers . TryGetValue ( "X-Server-Port" , out var portHeader ) == true
105+ && int . TryParse ( portHeader . ToString ( ) , out var port ) )
106+ {
107+ return port ;
108+ }
109+ return context ? . Connection ? . LocalPort ?? 0 ;
110+ }
111+
112+ private static ( StringBuilder Buffer , List < byte > Bytes , Exception ? Error , int Counter ) GetOrCreatePortData ( int port )
113+ {
114+ lock ( PortData )
115+ {
116+ if ( ! PortData . TryGetValue ( port , out var data ) )
117+ {
118+ data = ( new StringBuilder ( ) , new List < byte > ( ) , null , 0 ) ;
119+ PortData [ port ] = data ;
120+ }
121+ return data ;
122+ }
123+ }
124+
125+
126+ // Public methods for accessing port-specific data (used by DummyHttpServer)
127+ public static StringBuilder GetReceiveBuffer ( int port ) => GetOrCreatePortData ( port ) . Buffer ;
128+ public static List < byte > GetReceiveBytes ( int port ) => GetOrCreatePortData ( port ) . Bytes ;
129+
130+ public static Exception ? GetLastError ( int port )
131+ {
132+ lock ( PortData )
133+ {
134+ return GetOrCreatePortData ( port ) . Error ;
135+ }
136+ }
137+
138+ public static void SetLastError ( int port , Exception ? error )
139+ {
140+ lock ( PortData )
141+ {
142+ var data = GetOrCreatePortData ( port ) ;
143+ PortData [ port ] = ( data . Buffer , data . Bytes , error , data . Counter ) ;
144+ }
145+ }
146+
147+ public static int GetCounter ( int port )
148+ {
149+ lock ( PortData )
150+ {
151+ return GetOrCreatePortData ( port ) . Counter ;
152+ }
153+ }
154+
155+ public static void SetCounter ( int port , int value )
156+ {
157+ lock ( PortData )
158+ {
159+ var data = GetOrCreatePortData ( port ) ;
160+ PortData [ port ] = ( data . Buffer , data . Bytes , data . Error , value ) ;
161+ }
162+ }
163+
164+ public static void ClearPort ( int port )
165+ {
166+ lock ( PortData )
167+ {
168+ if ( PortData . TryGetValue ( port , out var data ) )
169+ {
170+ data . Buffer . Clear ( ) ;
171+ data . Bytes . Clear ( ) ;
172+ PortData [ port ] = ( data . Buffer , data . Bytes , null , 0 ) ;
173+ }
174+ }
175+ }
176+
177+ public static void SetPortConfig ( int port , bool tokenAuth , bool basicAuth , bool retriableError , bool errorMessage )
178+ {
179+ lock ( PortConfig )
180+ {
181+ PortConfig [ port ] = ( tokenAuth , basicAuth , retriableError , errorMessage ) ;
182+ }
183+ }
184+
185+ private static ( bool TokenAuth , bool BasicAuth , bool RetriableError , bool ErrorMessage ) GetPortConfig ( int port )
186+ {
187+ lock ( PortConfig )
188+ {
189+ if ( PortConfig . TryGetValue ( port , out var config ) )
190+ {
191+ return config ;
192+ }
193+ // Return static flags as defaults for backwards compatibility
194+ return ( WithTokenAuth , WithBasicAuth , WithRetriableError , WithErrorMessage ) ;
195+ }
196+ }
94197
95198 public override void Configure ( )
96199 {
@@ -111,14 +214,24 @@ public override void Configure()
111214
112215 public override async Task HandleAsync ( Request req , CancellationToken ct )
113216 {
114- Counter ++ ;
115- if ( WithRetriableError )
217+ int port = GetPortKey ( HttpContext ) ;
218+ var data = GetOrCreatePortData ( port ) ;
219+ var config = GetPortConfig ( port ) ;
220+
221+ lock ( PortData )
222+ {
223+ // Increment counter for this port
224+ data = GetOrCreatePortData ( port ) ;
225+ PortData [ port ] = ( data . Buffer , data . Bytes , data . Error , data . Counter + 1 ) ;
226+ }
227+
228+ if ( config . RetriableError )
116229 {
117230 await SendAsync ( null , 500 , ct ) ;
118231 return ;
119232 }
120233
121- if ( WithErrorMessage )
234+ if ( config . ErrorMessage )
122235 {
123236 await SendAsync ( new JsonErrorResponse
124237 { code = "code" , errorId = "errorid" , line = 1 , message = "message" , } , 400 , ct ) ;
@@ -127,13 +240,22 @@ await SendAsync(new JsonErrorResponse
127240
128241 try
129242 {
130- ReceiveBuffer . Append ( req . StringContent ) ;
131- ReceiveBytes . AddRange ( req . ByteContent ) ;
243+ lock ( PortData )
244+ {
245+ data = GetOrCreatePortData ( port ) ;
246+ data . Buffer . Append ( req . StringContent ) ;
247+ data . Bytes . AddRange ( req . ByteContent ) ;
248+ PortData [ port ] = data ;
249+ }
132250 await SendNoContentAsync ( ct ) ;
133251 }
134252 catch ( Exception ex )
135253 {
136- LastError = ex ;
254+ lock ( PortData )
255+ {
256+ data = GetOrCreatePortData ( port ) ;
257+ PortData [ port ] = ( data . Buffer , data . Bytes , ex , data . Counter ) ;
258+ }
137259 throw ;
138260 }
139261 }
0 commit comments