Commit a9c29243 authored by Honfika's avatar Honfika

content length limit fix

parent 72cd50d5
......@@ -6,14 +6,11 @@ namespace Titanium.Web.Proxy.Compression
/// <summary>
/// A factory to generate the compression methods based on the type of compression
/// </summary>
internal class CompressionFactory
internal static class CompressionFactory
{
public static readonly CompressionFactory Instance = new CompressionFactory();
//cache
private static readonly Lazy<ICompression> gzip = new Lazy<ICompression>(() => new GZipCompression());
private static readonly Lazy<ICompression> deflate = new Lazy<ICompression>(() => new DeflateCompression());
private static readonly Lazy<ICompression> def = new Lazy<ICompression>(() => new DefaultCompression());
public static ICompression GetCompression(string type)
{
......@@ -24,7 +21,7 @@ namespace Titanium.Web.Proxy.Compression
case KnownHeaders.ContentEncodingDeflate:
return deflate.Value;
default:
return def.Value;
throw new Exception($"Unsupported compression mode: {type}");
}
}
}
......
using System.IO;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Compression
{
/// <summary>
/// When no compression is specified just return the stream
/// </summary>
internal class DefaultCompression : ICompression
{
public Stream GetStream(Stream stream)
{
return stream;
}
}
}
......@@ -8,14 +8,11 @@ namespace Titanium.Web.Proxy.Decompression
/// </summary>
internal class DecompressionFactory
{
public static readonly DecompressionFactory Instance = new DecompressionFactory();
//cache
private static readonly Lazy<IDecompression> gzip = new Lazy<IDecompression>(() => new GZipDecompression());
private static readonly Lazy<IDecompression> deflate = new Lazy<IDecompression>(() => new DeflateDecompression());
private static readonly Lazy<IDecompression> def = new Lazy<IDecompression>(() => new DefaultDecompression());
internal IDecompression Create(string type)
public static IDecompression Create(string type)
{
switch (type)
{
......@@ -24,7 +21,7 @@ namespace Titanium.Web.Proxy.Decompression
case KnownHeaders.ContentEncodingDeflate:
return deflate.Value;
default:
return def.Value;
throw new Exception($"Unsupported decompression mode: {type}");
}
}
}
......
using System.IO;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Decompression
{
/// <summary>
/// When no compression is specified just return the stream
/// </summary>
internal class DefaultDecompression : IDecompression
{
public Stream GetStream(Stream stream)
{
return stream;
}
}
}
......@@ -8,18 +8,21 @@ using StreamExtended.Network;
namespace Titanium.Web.Proxy.EventArguments
{
internal class ChunkedStream : Stream
internal class LimitedStream : Stream
{
private readonly CustomBufferedStream baseStream;
private readonly CustomBinaryReader baseReader;
private readonly bool isChunked;
private bool readChunkTrail;
private int chunkBytesRemaining;
private long bytesRemaining;
public ChunkedStream(CustomBufferedStream baseStream, CustomBinaryReader baseReader)
public LimitedStream(CustomBufferedStream baseStream, CustomBinaryReader baseReader, bool isChunked, long contentLength)
{
this.baseStream = baseStream;
this.baseReader = baseReader;
this.isChunked = isChunked;
bytesRemaining = isChunked ? 0 : contentLength;
}
private void GetNextChunk()
......@@ -41,11 +44,11 @@ namespace Titanium.Web.Proxy.EventArguments
}
int chunkSize = int.Parse(chunkHead, NumberStyles.HexNumber);
chunkBytesRemaining = chunkSize;
bytesRemaining = chunkSize;
if (chunkSize == 0)
{
chunkBytesRemaining = -1;
bytesRemaining = -1;
//chunk trail
string s = baseReader.ReadLineAsync().Result;
......@@ -69,24 +72,31 @@ namespace Titanium.Web.Proxy.EventArguments
public override int Read(byte[] buffer, int offset, int count)
{
if (chunkBytesRemaining == -1)
if (bytesRemaining == -1)
{
return 0;
}
if (chunkBytesRemaining == 0)
if (bytesRemaining == 0)
{
GetNextChunk();
if (isChunked)
{
GetNextChunk();
}
else
{
bytesRemaining = -1;
}
}
if (chunkBytesRemaining == -1)
if (bytesRemaining == -1)
{
return 0;
}
int toRead = Math.Min(count, chunkBytesRemaining);
int toRead = (int)Math.Min(count, bytesRemaining);
int res = baseStream.Read(buffer, offset, toRead);
chunkBytesRemaining -= res;
bytesRemaining -= res;
return res;
}
......@@ -96,7 +106,7 @@ namespace Titanium.Web.Proxy.EventArguments
var buffer = BufferPool.GetBuffer(baseReader.Buffer.Length);
try
{
while (chunkBytesRemaining != -1)
while (bytesRemaining != -1)
{
await ReadAsync(buffer, 0, buffer.Length);
}
......
......@@ -294,73 +294,58 @@ namespace Titanium.Web.Proxy.EventArguments
}
else
{
await CopyBodyAsync(ProxyClient.ClientStream, reader, writer,
request.IsChunked, transformation, request.ContentEncoding, contentLength, OnDataSent);
await CopyBodyAsync(ProxyClient.ClientStream, reader, writer, request, transformation, OnDataSent);
}
}
private async Task CopyBodyAsync(CustomBufferedStream stream, CustomBinaryReader reader, HttpWriter writer,
bool isChunked, TransformationMode transformation, string contentEncoding, long contentLength,
Action<byte[], int, int> onCopy)
internal async Task CopyResponseBodyAsync(HttpWriter writer, TransformationMode transformation)
{
bool newReader = false;
var response = WebSession.Response;
var reader = WebSession.ServerConnection.StreamReader;
Stream s = stream;
ChunkedStream chunkedStream = null;
Stream decompressStream = null;
await CopyBodyAsync(WebSession.ServerConnection.Stream, reader, writer, response, transformation, OnDataReceived);
}
if (isChunked && transformation != TransformationMode.None)
private async Task CopyBodyAsync(CustomBufferedStream stream, CustomBinaryReader reader, HttpWriter writer,
RequestResponseBase requestResponse, TransformationMode transformation, Action<byte[], int, int> onCopy)
{
bool isChunked = requestResponse.IsChunked;
long contentLength = requestResponse.ContentLength;
if (transformation == TransformationMode.None)
{
s = chunkedStream = new ChunkedStream(stream, reader);
isChunked = false;
newReader = true;
await writer.CopyBodyAsync(reader, isChunked, contentLength, onCopy);
return;
}
if (transformation == TransformationMode.Uncompress)
LimitedStream limitedStream;
Stream decompressStream = null;
string contentEncoding = requestResponse.ContentEncoding;
Stream s = limitedStream = new LimitedStream(stream, reader, isChunked, contentLength);
if (transformation == TransformationMode.Uncompress && contentEncoding != null)
{
s = decompressStream = DecompressionFactory.Instance.Create(contentEncoding).GetStream(s);
newReader = true;
s = decompressStream = DecompressionFactory.Create(contentEncoding).GetStream(s);
}
try
{
if (newReader)
{
var bufStream = new CustomBufferedStream(s, bufferSize, true);
s = bufStream;
reader = new CustomBinaryReader(bufStream, bufferSize);
}
var bufStream = new CustomBufferedStream(s, bufferSize, true);
reader = new CustomBinaryReader(bufStream, bufferSize);
await writer.CopyBodyAsync(reader, isChunked, contentLength, onCopy);
await writer.CopyBodyAsync(reader, false, -1, onCopy);
}
finally
{
if (newReader)
{
reader?.Dispose();
if (decompressStream != null && decompressStream != stream)
{
decompressStream.Dispose();
}
reader?.Dispose();
decompressStream?.Dispose();
if (chunkedStream != null)
{
await chunkedStream.Finish();
chunkedStream.Dispose();
}
}
await limitedStream.Finish();
limitedStream.Dispose();
}
}
internal async Task CopyResponseBodyAsync(HttpWriter writer, TransformationMode transformation)
{
var response = WebSession.Response;
var reader = WebSession.ServerConnection.StreamReader;
await CopyBodyAsync(WebSession.ServerConnection.Stream, reader, writer,
response.IsChunked, transformation, response.ContentEncoding, response.ContentLength, OnDataReceived);
}
/// <summary>
/// Read a line from the byte stream
/// </summary>
......
......@@ -165,7 +165,7 @@ namespace Titanium.Web.Proxy.Helpers
return CopyBodyChunkedAsync(streamReader, onCopy);
}
//http 1.0
//http 1.0 or the stream reader limits the stream
if (contentLength == -1)
{
contentLength = long.MaxValue;
......
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