more changes on http server low level
							parent
							
								
									f0f067d05c
								
							
						
					
					
						commit
						f976d10de2
					
				|  | @ -93,17 +93,17 @@ namespace OSHttpServer | |||
|         { | ||||
|             while (!m_shuttingDown) | ||||
|             { | ||||
|                 m_processWaitEven.WaitOne(100); | ||||
|                 m_processWaitEven.WaitOne(500); | ||||
| 
 | ||||
|                 if(m_shuttingDown) | ||||
|                     return; | ||||
| 
 | ||||
|                 double now = GetTimeStampMS(); | ||||
|                 double now = GetTimeStamp(); | ||||
|                 if(m_contexts.Count > 0) | ||||
|                 { | ||||
|                     ProcessSendQueues(now); | ||||
| 
 | ||||
|                     if (now - m_lastTimeOutCheckTime > 1000) | ||||
|                     if (now - m_lastTimeOutCheckTime > 1.0) | ||||
|                     { | ||||
|                         ProcessContextTimeouts(); | ||||
|                         m_lastTimeOutCheckTime = now; | ||||
|  | @ -158,8 +158,8 @@ namespace OSHttpServer | |||
|             if(curConcurrentLimit > inqueues) | ||||
|                 curConcurrentLimit = inqueues; | ||||
| 
 | ||||
|             if (dt > 0.1) | ||||
|                 dt = 0.1; | ||||
|             if (dt > 0.5) | ||||
|                 dt = 0.5; | ||||
| 
 | ||||
|             dt /= curConcurrentLimit; | ||||
|             int curbytesLimit = (int)(m_maxBandWidth * dt); | ||||
|  | @ -250,68 +250,64 @@ namespace OSHttpServer | |||
|             if (context.contextID < 0 || context.StopMonitoring || context.StreamPassedOff) | ||||
|                 return true; | ||||
| 
 | ||||
|             // Now we start checking for actual timeouts | ||||
|             int nowMS = EnvironmentTickCount(); | ||||
| 
 | ||||
|             // First we check that we got at least one line within context.TimeoutFirstLine milliseconds | ||||
|             // First we check first contact line | ||||
|             if (!context.FirstRequestLineReceived) | ||||
|             { | ||||
|                 if (EnvironmentTickCountAdd(context.TimeoutFirstLine, context.MonitorStartMS) <= EnvironmentTickCount()) | ||||
|                 if (EnvironmentTickCountAdd(context.TimeoutFirstLine, context.LastActivityTimeMS) < nowMS) | ||||
|                 { | ||||
|                     disconnectError = SocketError.TimedOut; | ||||
|                     context.MonitorStartMS = 0; | ||||
|                     return true; | ||||
|                 } | ||||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|             // First we check first contact request | ||||
|             if (!context.FullRequestReceived) | ||||
|             { | ||||
|                 if (EnvironmentTickCountAdd(context.TimeoutRequestReceived, context.MonitorStartMS) <= EnvironmentTickCount()) | ||||
|                 if (EnvironmentTickCountAdd(context.TimeoutRequestReceived, context.LastActivityTimeMS) < nowMS) | ||||
|                 { | ||||
|                     disconnectError = SocketError.TimedOut; | ||||
|                     context.MonitorStartMS = 0; | ||||
|                     return true; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             //  | ||||
|             if (!context.FullRequestProcessed) | ||||
|             { | ||||
|                 if (EnvironmentTickCountAdd(context.TimeoutFullRequestProcessed, context.MonitorStartMS) <= EnvironmentTickCount()) | ||||
|                 { | ||||
|                     disconnectError = SocketError.TimedOut; | ||||
|                     context.MonitorStartMS = 0; | ||||
|                     return true; | ||||
|                 } | ||||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|             if (context.TriggerKeepalive) | ||||
|             { | ||||
|                 context.TriggerKeepalive = false; | ||||
|                 context.MonitorKeepaliveMS = EnvironmentTickCount(); | ||||
|                 context.MonitorKeepaliveStartMS = nowMS; | ||||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|             if (context.FullRequestProcessed && context.MonitorKeepaliveMS == 0) | ||||
|                 return true; | ||||
|             if (context.MonitorKeepaliveStartMS != 0) | ||||
|             { | ||||
|                 if (EnvironmentTickCountAdd(context.TimeoutKeepAlive, context.MonitorKeepaliveStartMS) < nowMS) | ||||
|                 { | ||||
|                     disconnectError = SocketError.TimedOut; | ||||
|                     context.MonitorKeepaliveStartMS = 0; | ||||
|                     return true; | ||||
|                 } | ||||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|             if (context.MonitorKeepaliveMS != 0 && | ||||
|                 EnvironmentTickCountAdd(context.TimeoutKeepAlive, context.MonitorKeepaliveMS) <= EnvironmentTickCount()) | ||||
|             if (EnvironmentTickCountAdd(context.TimeoutMaxIdle, context.LastActivityTimeMS) < nowMS) | ||||
|             { | ||||
|                 disconnectError = SocketError.TimedOut; | ||||
|                 context.MonitorStartMS = 0; | ||||
|                 context.MonitorKeepaliveMS = 0; | ||||
|                 context.MonitorKeepaliveStartMS = 0; | ||||
|                 return true; | ||||
|             } | ||||
| 
 | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         public static void StartMonitoringContext(HttpClientContext context) | ||||
|         { | ||||
|             context.MonitorStartMS = EnvironmentTickCount(); | ||||
|             context.LastActivityTimeMS = EnvironmentTickCount(); | ||||
|             m_contexts.Enqueue(context); | ||||
|         } | ||||
| 
 | ||||
|         public static void EnqueueSend(HttpClientContext context, int priority) | ||||
|         public static void EnqueueSend(HttpClientContext context, int priority, bool notThrottled = true) | ||||
|         { | ||||
|             switch(priority) | ||||
|             { | ||||
|  | @ -327,7 +323,8 @@ namespace OSHttpServer | |||
|                 default: | ||||
|                     return; | ||||
|             } | ||||
|             m_processWaitEven.Set(); | ||||
|             if(notThrottled) | ||||
|                 m_processWaitEven.Set(); | ||||
|         } | ||||
| 
 | ||||
|         public static void ContextEnterActiveSend() | ||||
|  |  | |||
|  | @ -20,7 +20,7 @@ namespace OSHttpServer | |||
|     /// </remarks> | ||||
|     public class HttpClientContext : IHttpClientContext, IDisposable | ||||
|     { | ||||
|         const int MAXPIPEREQUESTS = 5; | ||||
|         const int MAXREQUESTS = 20; | ||||
|         const int MAXKEEPALIVE = 60000; | ||||
| 
 | ||||
|         static private int basecontextID; | ||||
|  | @ -36,22 +36,20 @@ namespace OSHttpServer | |||
|         public bool Available = true; | ||||
|         public bool StreamPassedOff = false; | ||||
| 
 | ||||
|         public int MonitorStartMS = 0; | ||||
|         public int MonitorKeepaliveMS = 0; | ||||
|         public int LastActivityTimeMS = 0; | ||||
|         public int MonitorKeepaliveStartMS = 0; | ||||
|         public bool TriggerKeepalive = false; | ||||
|         public int TimeoutFirstLine = 70000; // 70 seconds | ||||
|         public int TimeoutRequestReceived = 180000; // 180 seconds | ||||
|         public int TimeoutFirstLine = 10000; // 10 seconds | ||||
|         public int TimeoutRequestReceived = 30000; // 30 seconds | ||||
| 
 | ||||
|         // The difference between this and request received is on POST more time is needed before we get the full request. | ||||
|         public int TimeoutFullRequestProcessed = 600000; // 10 minutes | ||||
|         public int TimeoutMaxIdle = 180000; // 3 minutes | ||||
|         public int m_TimeoutKeepAlive = MAXKEEPALIVE; // 400 seconds before keepalive timeout | ||||
|         // public int TimeoutKeepAlive = 120000; // 400 seconds before keepalive timeout | ||||
| 
 | ||||
|         public int m_maxPipeRequests = MAXPIPEREQUESTS; | ||||
|         public int m_maxRequests = MAXREQUESTS; | ||||
| 
 | ||||
|         public bool FirstRequestLineReceived; | ||||
|         public bool FullRequestReceived; | ||||
|         public bool FullRequestProcessed; | ||||
| 
 | ||||
|         private bool isSendingResponse = false; | ||||
| 
 | ||||
|  | @ -68,15 +66,15 @@ namespace OSHttpServer | |||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public int MaxPipeRequests | ||||
|         public int MaxRequests | ||||
|         { | ||||
|             get { return m_maxPipeRequests; } | ||||
|             get { return m_maxRequests; } | ||||
|             set | ||||
|             { | ||||
|                 if(value <= 1) | ||||
|                     m_maxPipeRequests = 1; | ||||
|                     m_maxRequests = 1; | ||||
|                 else | ||||
|                    m_maxPipeRequests = value > MAXPIPEREQUESTS ? MAXPIPEREQUESTS : value; | ||||
|                    m_maxRequests = value > MAXREQUESTS ? MAXREQUESTS : value; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|  | @ -118,7 +116,7 @@ namespace OSHttpServer | |||
|             m_parser.BodyBytesReceived += OnBodyBytesReceived; | ||||
|             m_currentRequest = new HttpRequest(this); | ||||
|             IsSecured = secured; | ||||
|             _stream = stream; | ||||
|             m_stream = stream; | ||||
|             m_sock = sock; | ||||
| 
 | ||||
|             m_bufferSize = 8196; | ||||
|  | @ -128,7 +126,7 @@ namespace OSHttpServer | |||
|             SSLCommonName = ""; | ||||
|             if (secured) | ||||
|             { | ||||
|                 SslStream _ssl = (SslStream)_stream; | ||||
|                 SslStream _ssl = (SslStream)m_stream; | ||||
|                 X509Certificate _cert1 = _ssl.RemoteCertificate; | ||||
|                 if (_cert1 != null) | ||||
|                 { | ||||
|  | @ -150,7 +148,7 @@ namespace OSHttpServer | |||
|             if (contextID < 0) | ||||
|                 return false; | ||||
| 
 | ||||
|             if (Stream == null || m_sock == null || !m_sock.Connected) | ||||
|             if (m_stream == null || m_sock == null || !m_sock.Connected) | ||||
|                 return false; | ||||
| 
 | ||||
|             return true; | ||||
|  | @ -191,9 +189,11 @@ namespace OSHttpServer | |||
|             m_currentRequest.UriPath = e.UriPath; | ||||
|             m_currentRequest.AddHeader("remote_addr", RemoteAddress); | ||||
|             m_currentRequest.AddHeader("remote_port", RemotePort); | ||||
| 
 | ||||
|             FirstRequestLineReceived = true; | ||||
|             TriggerKeepalive = false; | ||||
|             MonitorKeepaliveMS = 0; | ||||
|             MonitorKeepaliveStartMS = 0; | ||||
|             LastActivityTimeMS = ContextTimeoutManager.EnvironmentTickCount(); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|  | @ -218,10 +218,10 @@ namespace OSHttpServer | |||
|             if (StreamPassedOff) | ||||
|                 return; | ||||
| 
 | ||||
|             if (Stream != null) | ||||
|             if (m_stream != null) | ||||
|             { | ||||
|                 Stream.Close(); | ||||
|                 Stream = null; | ||||
|                 m_stream.Close(); | ||||
|                 m_stream = null; | ||||
|                 m_sock = null; | ||||
|             } | ||||
| 
 | ||||
|  | @ -233,10 +233,9 @@ namespace OSHttpServer | |||
| 
 | ||||
|             FirstRequestLineReceived = false; | ||||
|             FullRequestReceived = false; | ||||
|             FullRequestProcessed = false; | ||||
|             MonitorStartMS = 0; | ||||
|             LastActivityTimeMS = 0; | ||||
|             StopMonitoring = true; | ||||
|             MonitorKeepaliveMS = 0; | ||||
|             MonitorKeepaliveStartMS = 0; | ||||
|             TriggerKeepalive = false; | ||||
| 
 | ||||
|             isSendingResponse = false; | ||||
|  | @ -283,15 +282,15 @@ namespace OSHttpServer | |||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private Stream _stream; | ||||
|         private Stream m_stream; | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Gets or sets the network stream. | ||||
|         /// </summary> | ||||
|         internal Stream Stream | ||||
|         { | ||||
|             get { return _stream; } | ||||
|             set { _stream = value; } | ||||
|             get { return m_stream; } | ||||
|             set { m_stream = value; } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|  | @ -315,12 +314,12 @@ namespace OSHttpServer | |||
|             { | ||||
|                 try | ||||
|                 { | ||||
|                     if (Stream != null) | ||||
|                     if (m_stream != null) | ||||
|                     { | ||||
|                         if (error == SocketError.Success) | ||||
|                             Stream.Flush(); | ||||
|                         Stream.Close(); | ||||
|                         Stream = null; | ||||
|                             m_stream.Flush(); | ||||
|                         m_stream.Close(); | ||||
|                         m_stream = null; | ||||
|                     } | ||||
|                     m_sock = null; | ||||
|                 } | ||||
|  | @ -339,11 +338,11 @@ namespace OSHttpServer | |||
|             try | ||||
|             { | ||||
|                 int bytesRead = 0; | ||||
|                 if (Stream == null) | ||||
|                 if (m_stream == null) | ||||
|                     return; | ||||
|                 try | ||||
|                 { | ||||
|                     bytesRead = Stream.EndRead(ar); | ||||
|                     bytesRead = m_stream.EndRead(ar); | ||||
|                 } | ||||
|                 catch (NullReferenceException) | ||||
|                 { | ||||
|  | @ -357,7 +356,7 @@ namespace OSHttpServer | |||
|                     return; | ||||
|                 } | ||||
| 
 | ||||
|                 if(m_maxPipeRequests <= 0) | ||||
|                 if(m_maxRequests <= 0) | ||||
|                     return; | ||||
| 
 | ||||
|                 m_ReceiveBytesLeft += bytesRead; | ||||
|  | @ -367,7 +366,7 @@ namespace OSHttpServer | |||
|                 } | ||||
| 
 | ||||
|                 int offset = m_parser.Parse(m_ReceiveBuffer, 0, m_ReceiveBytesLeft); | ||||
|                 if (Stream == null) | ||||
|                 if (m_stream == null) | ||||
|                     return; // "Connection: Close" in effect. | ||||
| 
 | ||||
|                 // try again to see if we can parse another message (check parser to see if it is looking for a new message) | ||||
|  | @ -378,7 +377,7 @@ namespace OSHttpServer | |||
|                 { | ||||
|                     nextOffset = m_parser.Parse(m_ReceiveBuffer, offset, nextBytesleft); | ||||
| 
 | ||||
|                     if (Stream == null) | ||||
|                     if (m_stream == null) | ||||
|                         return; // "Connection: Close" in effect. | ||||
| 
 | ||||
|                     if (nextOffset == 0) | ||||
|  | @ -393,7 +392,7 @@ namespace OSHttpServer | |||
|                     Buffer.BlockCopy(m_ReceiveBuffer, offset, m_ReceiveBuffer, 0, m_ReceiveBytesLeft - offset); | ||||
| 
 | ||||
|                 m_ReceiveBytesLeft -= offset; | ||||
|                 if (Stream != null && Stream.CanRead) | ||||
|                 if (m_stream != null && m_stream.CanRead) | ||||
|                 { | ||||
|                     if (!StreamPassedOff) | ||||
|                         Stream.BeginRead(m_ReceiveBuffer, m_ReceiveBytesLeft, m_ReceiveBuffer.Length - m_ReceiveBytesLeft, OnReceive, null); | ||||
|  | @ -449,10 +448,10 @@ namespace OSHttpServer | |||
|             { | ||||
|                 while(true) | ||||
|                 { | ||||
|                     if (_stream == null || !_stream.CanRead) | ||||
|                     if (m_stream == null || !m_stream.CanRead) | ||||
|                         return; | ||||
| 
 | ||||
|                     int bytesRead = await _stream.ReadAsync(m_ReceiveBuffer, m_ReceiveBytesLeft, m_ReceiveBuffer.Length - m_ReceiveBytesLeft).ConfigureAwait(false); | ||||
|                     int bytesRead = await m_stream.ReadAsync(m_ReceiveBuffer, m_ReceiveBytesLeft, m_ReceiveBuffer.Length - m_ReceiveBytesLeft).ConfigureAwait(false); | ||||
| 
 | ||||
|                     if (bytesRead == 0) | ||||
|                     { | ||||
|  | @ -465,7 +464,7 @@ namespace OSHttpServer | |||
|                         throw new BadRequestException("HTTP header Too large: " + m_ReceiveBytesLeft); | ||||
| 
 | ||||
|                     int offset = m_parser.Parse(m_ReceiveBuffer, 0, m_ReceiveBytesLeft); | ||||
|                     if (Stream == null) | ||||
|                     if (m_stream == null) | ||||
|                         return; // "Connection: Close" in effect. | ||||
| 
 | ||||
|                     // try again to see if we can parse another message (check parser to see if it is looking for a new message) | ||||
|  | @ -476,7 +475,7 @@ namespace OSHttpServer | |||
|                     { | ||||
|                         nextOffset = m_parser.Parse(m_ReceiveBuffer, offset, nextBytesleft); | ||||
| 
 | ||||
|                         if (Stream == null) | ||||
|                         if (m_stream == null) | ||||
|                             return; // "Connection: Close" in effect. | ||||
| 
 | ||||
|                         if (nextOffset == 0) | ||||
|  | @ -536,13 +535,14 @@ namespace OSHttpServer | |||
|         private void OnRequestCompleted(object source, EventArgs args) | ||||
|         { | ||||
|             TriggerKeepalive = false; | ||||
|             MonitorKeepaliveMS = 0; | ||||
|             MonitorKeepaliveStartMS = 0; | ||||
|             FullRequestReceived = true; | ||||
|             LastActivityTimeMS = ContextTimeoutManager.EnvironmentTickCount(); | ||||
| 
 | ||||
|             if (m_maxPipeRequests == 0) | ||||
|             if (m_maxRequests == 0) | ||||
|                 return; | ||||
| 
 | ||||
|             if(--m_maxPipeRequests == 0) | ||||
|             if(--m_maxRequests == 0) | ||||
|                 m_currentRequest.Connection = ConnectionType.Close; | ||||
| 
 | ||||
|             // load cookies if they exist | ||||
|  | @ -574,13 +574,9 @@ namespace OSHttpServer | |||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public void ReqResponseAboutToSend(uint requestID) | ||||
|         { | ||||
|             isSendingResponse = true; | ||||
|         } | ||||
| 
 | ||||
|         public void StartSendResponse(HttpResponse response) | ||||
|         { | ||||
|             LastActivityTimeMS = ContextTimeoutManager.EnvironmentTickCount(); | ||||
|             isSendingResponse = true; | ||||
|             m_currentResponse = response; | ||||
|             ContextTimeoutManager.EnqueueSend(this, response.Priority); | ||||
|  | @ -595,19 +591,19 @@ namespace OSHttpServer | |||
| 
 | ||||
|             if(!CanSend()) | ||||
|                 return false; | ||||
| 
 | ||||
|   | ||||
|             m_currentResponse?.SendNextAsync(bytesLimit); | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         public void ContinueSendResponse() | ||||
|         public void ContinueSendResponse(bool notThrottled) | ||||
|         { | ||||
|             if(m_currentResponse == null) | ||||
|                 return; | ||||
|             ContextTimeoutManager.EnqueueSend(this, m_currentResponse.Priority); | ||||
|             ContextTimeoutManager.EnqueueSend(this, m_currentResponse.Priority, notThrottled); | ||||
|         } | ||||
| 
 | ||||
|         public void ReqResponseSent(uint requestID, ConnectionType ctype) | ||||
|         public void EndSendResponse(uint requestID, ConnectionType ctype) | ||||
|         { | ||||
|             isSendingResponse = false; | ||||
|             m_currentResponse?.Clear(); | ||||
|  | @ -626,6 +622,7 @@ namespace OSHttpServer | |||
|                 Disconnect(SocketError.Success); | ||||
|             else | ||||
|             { | ||||
|                 LastActivityTimeMS = ContextTimeoutManager.EnvironmentTickCount(); | ||||
|                 lock (requestsInServiceIDs) | ||||
|                 { | ||||
|                     if (requestsInServiceIDs.Count == 0) | ||||
|  | @ -645,22 +642,23 @@ namespace OSHttpServer | |||
|         /// <exception cref="ArgumentException">If <paramref name="httpVersion"/> is invalid.</exception> | ||||
|         public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body, string contentType) | ||||
|         { | ||||
|             LastActivityTimeMS = ContextTimeoutManager.EnvironmentTickCount(); | ||||
| 
 | ||||
|             if (string.IsNullOrEmpty(contentType)) | ||||
|                 contentType = "text/html"; | ||||
| 
 | ||||
|             if (string.IsNullOrEmpty(reason)) | ||||
|                 reason = statusCode.ToString(); | ||||
| 
 | ||||
|             string response = string.IsNullOrEmpty(body) | ||||
|                                   ? httpVersion + " " + (int)statusCode + " " + reason + "\r\n\r\n" | ||||
|                                   : string.Format("{0} {1} {2}\r\nContent-Type: {5}\r\nContent-Length: {3}\r\n\r\n{4}", | ||||
|             byte[] buffer; | ||||
|             if(string.IsNullOrEmpty(body)) | ||||
|                 buffer = Encoding.ASCII.GetBytes(httpVersion + " " + (int)statusCode + " " + reason ?? statusCode.ToString() + "\r\n\r\n"); | ||||
|             else | ||||
|                 buffer = Encoding.UTF8.GetBytes( | ||||
|                         string.Format("{0} {1} {2}\r\nContent-Type: {5}\r\nContent-Length: {3}\r\n\r\n{4}", | ||||
|                                                   httpVersion, (int)statusCode, reason ?? statusCode.ToString(), | ||||
|                                                   body.Length, body, contentType); | ||||
|             byte[] buffer = Encoding.ASCII.GetBytes(response); | ||||
| 
 | ||||
|                                                   body.Length, body, contentType)); | ||||
|             Send(buffer); | ||||
|             if (m_currentRequest.Connection == ConnectionType.Close) | ||||
|                 FullRequestProcessed = true; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|  | @ -671,6 +669,7 @@ namespace OSHttpServer | |||
|         /// <param name="reason">reason for the status code.</param> | ||||
|         public void Respond(string httpVersion, HttpStatusCode statusCode, string reason) | ||||
|         { | ||||
| 
 | ||||
|             Respond(httpVersion, statusCode, reason, null, null); | ||||
|         } | ||||
| 
 | ||||
|  | @ -699,7 +698,7 @@ namespace OSHttpServer | |||
| 
 | ||||
|         public bool Send(byte[] buffer, int offset, int size) | ||||
|         { | ||||
|             if (Stream == null || m_sock == null || !m_sock.Connected) | ||||
|             if (m_stream == null || m_sock == null || !m_sock.Connected) | ||||
|                 return false; | ||||
| 
 | ||||
|             if (offset + size > buffer.Length) | ||||
|  | @ -710,14 +709,14 @@ namespace OSHttpServer | |||
|             { | ||||
|                 try | ||||
|                 { | ||||
|                     Stream.Write(buffer, offset, size); | ||||
|                     m_stream.Write(buffer, offset, size); | ||||
|                 } | ||||
|                 catch | ||||
|                 { | ||||
|                     ok = false; | ||||
|                 } | ||||
| 
 | ||||
|                 if (!ok && Stream != null) | ||||
|                 if (!ok && m_stream != null) | ||||
|                     Disconnect(SocketError.NoRecovery); | ||||
|                 return ok; | ||||
|             } | ||||
|  | @ -725,7 +724,7 @@ namespace OSHttpServer | |||
| 
 | ||||
|         public async Task<bool> SendAsync(byte[] buffer, int offset, int size) | ||||
|         { | ||||
|             if (Stream == null || m_sock == null || !m_sock.Connected) | ||||
|             if (m_stream == null || m_sock == null || !m_sock.Connected) | ||||
|                 return false; | ||||
| 
 | ||||
|             if (offset + size > buffer.Length) | ||||
|  | @ -735,7 +734,7 @@ namespace OSHttpServer | |||
|             ContextTimeoutManager.ContextEnterActiveSend(); | ||||
|             try | ||||
|             { | ||||
|                 await Stream.WriteAsync(buffer, offset, size).ConfigureAwait(false); | ||||
|                 await m_stream.WriteAsync(buffer, offset, size).ConfigureAwait(false); | ||||
|             } | ||||
|             catch | ||||
|             { | ||||
|  | @ -744,7 +743,7 @@ namespace OSHttpServer | |||
| 
 | ||||
|             ContextTimeoutManager.ContextLeaveActiveSend(); | ||||
| 
 | ||||
|             if (!ok && Stream != null) | ||||
|             if (!ok && m_stream != null) | ||||
|                 Disconnect(SocketError.NoRecovery); | ||||
|             return ok; | ||||
|         } | ||||
|  | @ -770,7 +769,7 @@ namespace OSHttpServer | |||
|             m_parser.BodyBytesReceived -= OnBodyBytesReceived; | ||||
|             m_parser.Clear(); | ||||
| 
 | ||||
|             return new HTTPNetworkContext() { Socket = m_sock, Stream = _stream as NetworkStream }; | ||||
|             return new HTTPNetworkContext() { Socket = m_sock, Stream = m_stream as NetworkStream }; | ||||
|         } | ||||
| 
 | ||||
|         public void Dispose() | ||||
|  |  | |||
|  | @ -10,6 +10,8 @@ namespace OSHttpServer | |||
| { | ||||
|     public class HttpResponse : IHttpResponse | ||||
|     { | ||||
|         public event EventHandler<BandWitdhEventArgs> BandWitdhEvent; | ||||
| 
 | ||||
|         private const string DefaultContentType = "text/html;charset=UTF-8"; | ||||
|         private readonly IHttpClientContext m_context; | ||||
|         private readonly ResponseCookies m_cookies = new ResponseCookies(); | ||||
|  | @ -245,9 +247,9 @@ namespace OSHttpServer | |||
|                 sb.Append("Server: OSWebServer\r\n"); | ||||
| 
 | ||||
|             int keepaliveS = m_context.TimeoutKeepAlive / 1000; | ||||
|             if (Connection == ConnectionType.KeepAlive && keepaliveS > 0 && m_context.MaxPipeRequests > 0) | ||||
|             if (Connection == ConnectionType.KeepAlive && keepaliveS > 0 && m_context.MaxRequests > 0) | ||||
|             { | ||||
|                 sb.AppendFormat("Keep-Alive:timeout={0}, max={1}\r\n", keepaliveS, m_context.MaxPipeRequests); | ||||
|                 sb.AppendFormat("Keep-Alive:timeout={0}, max={1}\r\n", keepaliveS, m_context.MaxRequests); | ||||
|                 sb.Append("Connection: Keep-Alive\r\n"); | ||||
|             } | ||||
|             else | ||||
|  | @ -282,7 +284,7 @@ namespace OSHttpServer | |||
|             if (Sent) | ||||
|                 throw new InvalidOperationException("Everything have already been sent."); | ||||
| 
 | ||||
|             if (m_context.MaxPipeRequests == 0 || m_keepAlive == 0) | ||||
|             if (m_context.MaxRequests == 0 || m_keepAlive == 0) | ||||
|             { | ||||
|                 Connection = ConnectionType.Close; | ||||
|                 m_context.TimeoutKeepAlive = 0; | ||||
|  | @ -326,7 +328,12 @@ namespace OSHttpServer | |||
|             { | ||||
|                 if(!await m_context.SendAsync(m_headerBytes, 0, m_headerBytes.Length).ConfigureAwait(false)) | ||||
|                 { | ||||
|                     if(m_body != null) | ||||
|                     if (m_context.CanSend()) | ||||
|                     { | ||||
|                         m_context.ContinueSendResponse(true); | ||||
|                         return; | ||||
|                     } | ||||
|                     if (m_body != null) | ||||
|                         m_body.Dispose(); | ||||
|                     RawBuffer = null; | ||||
|                     Sent = true; | ||||
|  | @ -336,7 +343,7 @@ namespace OSHttpServer | |||
|                 m_headerBytes = null; | ||||
|                 if(bytesLimit <= 0) | ||||
|                 { | ||||
|                     m_context.ContinueSendResponse(); | ||||
|                     m_context.ContinueSendResponse(true); | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|  | @ -345,21 +352,34 @@ namespace OSHttpServer | |||
|             { | ||||
|                 if (RawBufferLen > 0) | ||||
|                 { | ||||
|                     if(BandWitdhEvent!=null) | ||||
|                         bytesLimit = CheckBandwidth(RawBufferLen, bytesLimit); | ||||
| 
 | ||||
|                     bool sendRes; | ||||
|                     if(RawBufferLen > bytesLimit) | ||||
|                     { | ||||
|                         sendRes = await m_context.SendAsync(RawBuffer, RawBufferStart, bytesLimit).ConfigureAwait(false); | ||||
|                         RawBufferLen -= bytesLimit; | ||||
|                         RawBufferStart += bytesLimit; | ||||
|                         sendRes = (await m_context.SendAsync(RawBuffer, RawBufferStart, bytesLimit).ConfigureAwait(false)); | ||||
|                         if (sendRes) | ||||
|                         { | ||||
|                             RawBufferLen -= bytesLimit; | ||||
|                             RawBufferStart += bytesLimit; | ||||
|                         } | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         sendRes = await m_context.SendAsync(RawBuffer, RawBufferStart, RawBufferLen).ConfigureAwait(false); | ||||
|                         RawBufferLen = 0; | ||||
|                         if(sendRes) | ||||
|                             RawBufferLen = 0; | ||||
|                     } | ||||
| 
 | ||||
|                     if (!sendRes) | ||||
|                     { | ||||
|                         if (m_context.CanSend()) | ||||
|                         { | ||||
|                             m_context.ContinueSendResponse(true); | ||||
|                             return; | ||||
|                         } | ||||
| 
 | ||||
|                         RawBuffer = null; | ||||
|                         if(m_body != null) | ||||
|                             Body.Dispose(); | ||||
|  | @ -371,7 +391,7 @@ namespace OSHttpServer | |||
|                     RawBuffer = null; | ||||
|                 else | ||||
|                 { | ||||
|                     m_context.ContinueSendResponse(); | ||||
|                     m_context.ContinueSendResponse(true); | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|  | @ -391,17 +411,26 @@ namespace OSHttpServer | |||
|                     if (RawBufferLen > bytesLimit) | ||||
|                     { | ||||
|                         sendRes = await m_context.SendAsync(RawBuffer, RawBufferStart, bytesLimit).ConfigureAwait(false); | ||||
|                         RawBufferLen -= bytesLimit; | ||||
|                         RawBufferStart += bytesLimit; | ||||
|                         if (sendRes) | ||||
|                         { | ||||
|                             RawBufferLen -= bytesLimit; | ||||
|                             RawBufferStart += bytesLimit; | ||||
|                         } | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         sendRes = await m_context.SendAsync(RawBuffer, RawBufferStart, RawBufferLen).ConfigureAwait(false); | ||||
|                         RawBufferLen = 0; | ||||
|                         if (sendRes) | ||||
|                             RawBufferLen = 0; | ||||
|                     } | ||||
| 
 | ||||
|                     if (!sendRes) | ||||
|                     { | ||||
|                         if (m_context.CanSend()) | ||||
|                         { | ||||
|                             m_context.ContinueSendResponse(true); | ||||
|                             return; | ||||
|                         } | ||||
|                         RawBuffer = null; | ||||
|                         Sent = true; | ||||
|                         return; | ||||
|  | @ -409,7 +438,7 @@ namespace OSHttpServer | |||
|                 } | ||||
|                 if (RawBufferLen > 0) | ||||
|                 { | ||||
|                     m_context.ContinueSendResponse(); | ||||
|                     m_context.ContinueSendResponse(false); | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|  | @ -417,7 +446,19 @@ namespace OSHttpServer | |||
|             if (m_body != null) | ||||
|                 m_body.Dispose(); | ||||
|             Sent = true; | ||||
|             m_context.ReqResponseSent(requestID, Connection); | ||||
|             m_context.EndSendResponse(requestID, Connection); | ||||
|         } | ||||
| 
 | ||||
|         private int CheckBandwidth(int request, int bytesLimit) | ||||
|         { | ||||
|             if(request > bytesLimit) | ||||
|                 request = bytesLimit; | ||||
|             var args = new BandWitdhEventArgs(request); | ||||
|             BandWitdhEvent?.Invoke(this, args); | ||||
|             if(args.Result > 8196) | ||||
|                 return args.Result; | ||||
| 
 | ||||
|             return 8196; | ||||
|         } | ||||
| 
 | ||||
|         public void Clear() | ||||
|  |  | |||
|  | @ -23,7 +23,7 @@ namespace OSHttpServer | |||
| 
 | ||||
|         int contextID {get;} | ||||
|         int TimeoutKeepAlive {get; set; } | ||||
|         int MaxPipeRequests{get; set; } | ||||
|         int MaxRequests{get; set; } | ||||
| 
 | ||||
|         bool CanSend(); | ||||
|         bool IsSending(); | ||||
|  | @ -92,11 +92,11 @@ namespace OSHttpServer | |||
|         HTTPNetworkContext GiveMeTheNetworkStreamIKnowWhatImDoing(); | ||||
| 
 | ||||
|         void StartSendResponse(HttpResponse response); | ||||
|         void ContinueSendResponse(); | ||||
|         void ReqResponseAboutToSend(uint requestID); | ||||
|         void ReqResponseSent(uint requestID, ConnectionType connection); | ||||
|         void ContinueSendResponse(bool notThrottled); | ||||
|         void EndSendResponse(uint requestID, ConnectionType connection); | ||||
|         bool TrySendResponse(int limit); | ||||
|     } | ||||
| 
 | ||||
|     public class HTTPNetworkContext | ||||
|     { | ||||
|         public NetworkStream Stream; | ||||
|  | @ -143,4 +143,6 @@ namespace OSHttpServer | |||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -154,12 +154,5 @@ namespace OSHttpServer | |||
|         /// </summary> | ||||
|         /// <param name="cookies">The cookies.</param> | ||||
|         void SetCookies(RequestCookies cookies); | ||||
| 
 | ||||
| 		/// <summary> | ||||
| 		/// Create a response object. | ||||
| 		/// </summary> | ||||
| 		/// <param name="context">Context for the connected client.</param> | ||||
| 		/// <returns>A new <see cref="IHttpResponse"/>.</returns> | ||||
| 		//IHttpResponse CreateResponse(IHttpClientContext context); | ||||
|     } | ||||
| } | ||||
|  | @ -26,11 +26,13 @@ namespace OSHttpServer | |||
|     /// </example> | ||||
|     public interface IHttpResponse | ||||
|     { | ||||
|         event EventHandler<BandWitdhEventArgs> BandWitdhEvent; | ||||
|         /// <summary> | ||||
|         /// The body stream is used to cache the body contents | ||||
|         /// before sending everything to the client. It's the simplest | ||||
|         /// way to serve documents. | ||||
|         /// </summary> | ||||
|         /// | ||||
|         Stream Body { get; } | ||||
|         byte[] RawBuffer { get; set; } | ||||
|         int RawBufferStart { get; set; } | ||||
|  | @ -142,4 +144,19 @@ namespace OSHttpServer | |||
|         /// </summary> | ||||
|         KeepAlive | ||||
|     } | ||||
| 
 | ||||
|     public class BandWitdhEventArgs : EventArgs | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Gets received request. | ||||
|         /// </summary> | ||||
|         public int Result; | ||||
|         public int Request; | ||||
| 
 | ||||
|         public BandWitdhEventArgs(int request) | ||||
|         { | ||||
|             Request = request; | ||||
|             Result = request; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 UbitUmarov
						UbitUmarov