private void OnReceive(IAsyncResult ar)
{
try
{
if (ar == null)
{
LogWriter.Write (this, LogPrio.Debug, "Failed to end receive : NullRef");
Disconnect (SocketError.NoRecovery);
return;
}
int retry = 0;
tryAgain:
if (Stream == null)
{
System.Threading.Thread.Sleep (1);
if (retry < 5)
{
retry++;
goto tryAgain;
}
LogWriter.Write (this, LogPrio.Warning, "Failed to end receive : NullRef");
Disconnect (SocketError.NoRecovery);
return; // "Connection: Close" in effect.
}
int bytesRead = Stream.EndRead(ar);
if (bytesRead == 0)
{
Disconnect(SocketError.ConnectionReset);
return;
}
_bytesLeft += bytesRead;
if (_bytesLeft > _buffer.Length)
{
#if DEBUG
throw new BadRequestException("Too large HTTP header: " + Encoding.UTF8.GetString(_buffer, 0, bytesRead));
#else
throw new BadRequestException("Too large HTTP header: " + _bytesLeft);
#endif
}
#if DEBUG
#pragma warning disable 219
string temp = Encoding.ASCII.GetString(_buffer, 0, _bytesLeft);
LogWriter.Write(this, LogPrio.Trace, "Received: " + temp);
#pragma warning restore 219
#endif
int offset = _parser.Parse(_buffer, 0, _bytesLeft);
if (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)
int oldOffset = offset;
while (_parser.CurrentState == RequestParserState.FirstLine && offset != 0 && _bytesLeft - offset > 0)
{
#if DEBUG
temp = Encoding.ASCII.GetString(_buffer, offset, _bytesLeft - offset);
LogWriter.Write(this, LogPrio.Trace, "Processing: " + temp);
#endif
offset = _parser.Parse(_buffer, offset, _bytesLeft - offset);
if (Stream == null)
return; // "Connection: Close" in effect.
}
// need to be able to move prev bytes, so restore offset.
if (offset == 0)
offset = oldOffset;
// copy unused bytes to the beginning of the array
if (offset > 0 && _bytesLeft != offset && _bytesLeft - offset > 0)
Buffer.BlockCopy(_buffer, offset, _buffer, 0, _bytesLeft - offset);
_bytesLeft -= offset;
if (_bytesLeft >= 0 && Stream != null && Stream.CanRead)
Stream.BeginRead(_buffer, _bytesLeft, _buffer.Length - _bytesLeft, OnReceive, null);
else
{
_log.Write(this, LogPrio.Warning, "Could not read any more from the socket.");
Disconnect(SocketError.Success);
}
}
catch (BadRequestException err)
{
LogWriter.Write(this, LogPrio.Warning, "Bad request, responding with it. Error: " + err);
try
{
Respond("HTTP/1.0", HttpStatusCode.BadRequest, err.Message);
}
catch(Exception err2)
{
LogWriter.Write(this, LogPrio.Fatal, "Failed to reply to a bad request. " + err2);
}
Disconnect(SocketError.NoRecovery);
}
catch (IOException err)
{
LogWriter.Write(this, LogPrio.Debug, "Failed to end receive: " + err.Message);
if (err.InnerException is SocketException)
Disconnect((SocketError) ((SocketException) err.InnerException).ErrorCode);
else
Disconnect(SocketError.ConnectionReset);
}
catch (ObjectDisposedException err)
{
LogWriter.Write(this, LogPrio.Warning, "Failed to end receive : " + err.Message);
Disconnect(SocketError.NotSocket);
}
catch (NullReferenceException err)
{
LogWriter.Write(this, LogPrio.Debug, "Failed to end receive : NullRef: " + err.Message);
Disconnect(SocketError.NoRecovery);
}
catch (Exception err)
{
LogWriter.Write(this, LogPrio.Warning, "Failed to end receive : Exception: " + err.ToString());
Disconnect(SocketError.NoRecovery);
}
}