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