@@ -23,15 +23,10 @@ public sealed class HttpHost : IDisposable {
2323
2424 private readonly IPEndPoint _endpoint ;
2525 private readonly TcpListener _listener ;
26+ private Thread ? _eventLoopThread ;
2627 private bool disposedValue ;
2728 private bool isListening ;
2829
29- /// <summary>
30- /// Gets or sets the client queue size of all <see cref="HttpHost"/> instances. This value indicates how many
31- /// connections the server can maintain simultaneously before queueing other connections attempts.
32- /// </summary>
33- public static int QueueSize { get ; set ; } = 1024 ;
34-
3530 /// <summary>
3631 /// Gets or sets the name of the server in the header name.
3732 /// </summary>
@@ -90,19 +85,30 @@ public void Start () {
9085
9186 _listener . Server . NoDelay = true ;
9287 _listener . Server . LingerState = new LingerOption ( true , 3 ) ;
93- _listener . Server . ReceiveBufferSize = HttpConnection . REQUEST_BUFFER_SIZE ;
94- _listener . Server . SendBufferSize = HttpConnection . RESPONSE_BUFFER_SIZE ;
88+ _listener . Server . ReceiveBufferSize = HttpConnection . RESERVED_BUFFER_SIZE ;
89+ _listener . Server . SendBufferSize = HttpConnection . RESERVED_BUFFER_SIZE ;
9590
9691 _listener . Server . SetSocketOption ( SocketOptionLevel . Tcp , SocketOptionName . TcpKeepAliveInterval , 1 ) ;
9792 _listener . Server . SetSocketOption ( SocketOptionLevel . Tcp , SocketOptionName . TcpKeepAliveTime , 120 ) ;
9893 _listener . Server . SetSocketOption ( SocketOptionLevel . Tcp , SocketOptionName . TcpKeepAliveRetryCount , 3 ) ;
9994 _listener . Server . SetSocketOption ( SocketOptionLevel . Socket , SocketOptionName . KeepAlive , true ) ;
10095 _listener . Server . SetSocketOption ( SocketOptionLevel . Socket , SocketOptionName . ReuseAddress , true ) ;
10196
102- _listener . Start ( QueueSize ) ;
97+ _listener . Start ( backlog : 8192 ) ;
10398 isListening = true ;
10499
105- _listener . BeginAcceptTcpClient ( ReceiveClient , null ) ;
100+ _eventLoopThread = new Thread ( EventLoopThreadRunner ) ;
101+ _eventLoopThread . Priority = ThreadPriority . Highest ;
102+ _eventLoopThread . Start ( ) ;
103+ }
104+
105+ async void EventLoopThreadRunner ( ) {
106+
107+ while ( isListening ) {
108+ var client = await _listener . AcceptTcpClientAsync ( ) . ConfigureAwait ( false ) ;
109+ HttpHostThreadPoolWorkItem workItem = new HttpHostThreadPoolWorkItem ( this , client ) ;
110+ ThreadPool . UnsafeQueueUserWorkItem ( workItem , preferLocal : true ) ;
111+ }
106112 }
107113
108114 /// <summary>
@@ -116,101 +122,6 @@ public void Stop () {
116122 _listener . Stop ( ) ;
117123 }
118124
119- private async void ReceiveClient ( IAsyncResult result ) {
120-
121- if ( ! isListening )
122- return ;
123-
124- _listener . BeginAcceptTcpClient ( ReceiveClient , null ) ;
125- var client = _listener . EndAcceptTcpClient ( result ) ;
126-
127- await HandleTcpClient ( client ) ;
128- }
129-
130- private byte [ ] GetBadRequestMessage ( string message ) {
131- string content = $ """
132- <HTML>
133- <HEAD>
134- <TITLE>400 - Bad Request</TITLE>
135- </HEAD>
136- <BODY>
137- <H1>400 - Bad Request</H1>
138- <P>{ message } </P>
139- <HR>
140- <P><EM>Cadente</EM></P>
141- </BODY>
142- </HTML>
143- """ ;
144-
145- string html =
146- $ "HTTP/1.1 400 Bad Request\r \n " +
147- $ "Content-Type: text/html\r \n " +
148- $ "Content-Length: { content . Length } \r \n " +
149- $ "Connection: close\r \n " +
150- $ "\r \n " +
151- content ;
152-
153- return Encoding . ASCII . GetBytes ( html ) ;
154- }
155-
156- private async Task HandleTcpClient ( TcpClient client ) {
157-
158- try {
159- int clientReadTimeoutMs = ( int ) TimeoutManager . ClientReadTimeout . TotalMilliseconds ;
160- int clientWriteTimeoutMs = ( int ) TimeoutManager . ClientWriteTimeout . TotalMilliseconds ;
161-
162- client . ReceiveTimeout = clientReadTimeoutMs ;
163- client . SendTimeout = clientWriteTimeoutMs ;
164-
165- if ( Handler is null )
166- return ;
167-
168- Stream connectionStream ;
169- using Stream clientStream = client . GetStream ( ) ;
170-
171- if ( HttpsOptions is not null ) {
172- connectionStream = new SslStream ( clientStream , leaveInnerStreamOpen : false ) ;
173- }
174- else {
175- connectionStream = clientStream ;
176- }
177-
178- IPEndPoint clientEndpoint = ( IPEndPoint ) client . Client . RemoteEndPoint ! ;
179- HttpHostClient hostClient = new HttpHostClient ( clientEndpoint , CancellationToken . None ) ;
180-
181- connectionStream . ReadTimeout = clientReadTimeoutMs ;
182- connectionStream . WriteTimeout = clientWriteTimeoutMs ;
183-
184- using ( HttpConnection connection = new HttpConnection ( hostClient , connectionStream , this , clientEndpoint ) ) {
185-
186- if ( connectionStream is SslStream sslStream ) {
187- try {
188- await sslStream . AuthenticateAsServerAsync (
189- serverCertificate : HttpsOptions ! . ServerCertificate ,
190- clientCertificateRequired : HttpsOptions . ClientCertificateRequired ,
191- checkCertificateRevocation : HttpsOptions . CheckCertificateRevocation ,
192- enabledSslProtocols : HttpsOptions . AllowedProtocols ) ;
193-
194- hostClient . ClientCertificate = sslStream . RemoteCertificate ;
195- }
196- catch ( Exception ) {
197-
198- var message = GetBadRequestMessage ( "SSL/TLS Handshake failed." ) ;
199- await clientStream . WriteAsync ( message , 0 , message . Length ) ;
200- return ;
201- }
202- }
203-
204- await Handler . OnClientConnectedAsync ( this , hostClient ) ;
205- await connection . HandleConnectionEventsAsync ( ) ;
206- await Handler . OnClientDisconnectedAsync ( this , hostClient ) ;
207- }
208- }
209- finally {
210- client . Dispose ( ) ;
211- }
212- }
213-
214125 private void Dispose ( bool disposing ) {
215126 if ( ! disposedValue ) {
216127 if ( disposing ) {
@@ -224,7 +135,7 @@ private void Dispose ( bool disposing ) {
224135 }
225136
226137 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
227- internal async ValueTask InvokeContextCreated ( HttpHostContext context ) {
138+ internal async Task InvokeContextCreated ( HttpHostContext context ) {
228139 if ( disposedValue )
229140 return ;
230141 if ( Handler is null )
0 commit comments