Commit 4b12be58 authored by Shani Elharrar's avatar Shani Elharrar

Added limited stream to defence from attacks, This is just a minor thing out...

Added limited stream to defence from attacks, This is just a minor thing out of a set of security defences that should be added.
parent 5bbb50e0
......@@ -39,8 +39,7 @@ namespace uhttpsharp
private static readonly ILog Logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private readonly IClient _client;
private readonly StreamReader _inputStream;
private readonly StreamWriter _outputStream;
private readonly Stream _stream;
private readonly IList<IHttpRequestHandler> _requestHandlers;
private readonly IHttpRequestProvider _requestProvider;
private readonly EndPoint _remoteEndPoint;
......@@ -52,10 +51,7 @@ namespace uhttpsharp
_requestHandlers = requestHandlers;
_requestProvider = requestProvider;
var bufferedStream = new BufferedStream(_client.Stream);
_outputStream = new StreamWriter(bufferedStream) { NewLine = CrLf };
_inputStream = new StreamReader(bufferedStream);
_stream = new BufferedStream(_client.Stream);
Logger.InfoFormat("Got Client {0}", _remoteEndPoint);
......@@ -68,7 +64,9 @@ namespace uhttpsharp
{
while (_client.Connected)
{
var request = await _requestProvider.Provide(_inputStream).ConfigureAwait(false);
// TODO : Extract read and write limit to configuration.
var requestStream = new LimitedStream(_stream, readLimit: 1024*1024, writeLimit: 1024*1024);
var request = await _requestProvider.Provide(new StreamReader(requestStream)).ConfigureAwait(false);
if (request != null)
{
......@@ -85,22 +83,23 @@ namespace uhttpsharp
if (response != null)
{
var streamWriter = new StreamWriter(requestStream);
// Headers
await response.WriteHeaders(_outputStream).ConfigureAwait(false);
await response.WriteHeaders(streamWriter).ConfigureAwait(false);
// Cookies
if (context.Cookies.Touched)
{
await _outputStream.WriteAsync(context.Cookies.ToCookieData())
await streamWriter.WriteAsync(context.Cookies.ToCookieData())
.ConfigureAwait(false);
await _outputStream.FlushAsync().ConfigureAwait(false);
await streamWriter.FlushAsync().ConfigureAwait(false);
}
// Empty Line
await _outputStream.BaseStream.WriteAsync(CrLfBuffer, 0, CrLfBuffer.Length).ConfigureAwait(false);
await requestStream.WriteAsync(CrLfBuffer, 0, CrLfBuffer.Length).ConfigureAwait(false);
// Body
await response.WriteResponse(_outputStream).ConfigureAwait(false);
await response.WriteResponse(streamWriter).ConfigureAwait(false);
if (!request.Headers.KeepAliveConnection() || response.CloseConnection)
{
......@@ -120,6 +119,7 @@ namespace uhttpsharp
catch (IOException)
{
// Socket exceptions on read will be re-thrown as IOException by BufferedStream
// ALSO : LimitedStream throws IOException on limit exceed.
}
catch (Exception e)
{
......
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Remoting;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace uhttpsharp
{
class LimitedStream : Stream
{
private const string _exceptionMessageFormat = "The Stream has exceeded the {0} limit specified.";
private readonly Stream _child;
private long _readLimit;
private long _writeLimit;
public LimitedStream(Stream child, long readLimit = -1, long writeLimit = -1)
{
_child = child;
_readLimit = readLimit;
_writeLimit = writeLimit;
}
public override void Flush()
{
_child.Flush();
}
public override long Seek(long offset, SeekOrigin origin)
{
return _child.Seek(offset, origin);
}
public override void SetLength(long value)
{
_child.SetLength(value);
}
public override int Read(byte[] buffer, int offset, int count)
{
var retVal = _child.Read(buffer, offset, count);
AssertReadLimit(retVal);
return retVal;
}
private void AssertReadLimit(int coefficient)
{
if (_readLimit == -1)
{
return;
}
_readLimit -= coefficient;
if (_readLimit < 0)
{
throw new IOException(string.Format(_exceptionMessageFormat, "read"));
}
}
private void AssertWriteLimit(int coefficient)
{
if (_writeLimit == -1)
{
return;
}
_writeLimit -= coefficient;
if (_writeLimit < 0)
{
throw new IOException(string.Format(_exceptionMessageFormat, "write"));
}
}
public override int ReadByte()
{
var retVal = _child.ReadByte();
AssertReadLimit(1);
return retVal;
}
public override void Write(byte[] buffer, int offset, int count)
{
_child.Write(buffer, offset, count);
AssertWriteLimit(count);
}
public override void WriteByte(byte value)
{
_child.WriteByte(value);
AssertWriteLimit(1);
}
public override bool CanRead
{
get { return _child.CanRead; }
}
public override bool CanSeek
{
get { return _child.CanSeek; }
}
public override bool CanWrite
{
get { return _child.CanWrite; }
}
public override long Length
{
get { return _child.Length; }
}
public override long Position
{
get { return _child.Position; }
set { _child.Position = value; }
}
public override int ReadTimeout
{
get { return _child.ReadTimeout; }
set { _child.ReadTimeout = value; }
}
public override int WriteTimeout
{
get { return _child.WriteTimeout; }
set { _child.WriteTimeout = value; }
}
}
}
......@@ -81,6 +81,7 @@
<Compile Include="IEnumerable.cs" />
<Compile Include="IHttpContext.cs" />
<Compile Include="IHttpMethodProvider.cs" />
<Compile Include="LimitedStream.cs" />
<Compile Include="Listeners\IHttpListener.cs" />
<Compile Include="Listeners\SslListenerDecoerator.cs" />
<Compile Include="Listeners\TcpListenerAdapter.cs" />
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment