Commit a9c29243 authored by Honfika's avatar Honfika

content length limit fix

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