Commit ebd9baca authored by Honfika's avatar Honfika

simplify custom stream

parent 94c1bfc6
...@@ -205,4 +205,4 @@ FakesAssemblies/ ...@@ -205,4 +205,4 @@ FakesAssemblies/
*.opt *.opt
# Docfx # Docfx
docs/manifest.json docs/manifest.json
\ No newline at end of file
...@@ -51,8 +51,8 @@ ...@@ -51,8 +51,8 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="StreamExtended, Version=1.0.147.0, Culture=neutral, PublicKeyToken=bbfa0f1d54f50043, processorArchitecture=MSIL"> <Reference Include="StreamExtended, Version=1.0.160.0, Culture=neutral, PublicKeyToken=bbfa0f1d54f50043, processorArchitecture=MSIL">
<HintPath>..\..\packages\StreamExtended.1.0.147-beta\lib\net45\StreamExtended.dll</HintPath> <HintPath>..\..\packages\StreamExtended.1.0.160-beta\lib\net45\StreamExtended.dll</HintPath>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Data" /> <Reference Include="System.Data" />
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="StreamExtended" version="1.0.147-beta" targetFramework="net45" /> <package id="StreamExtended" version="1.0.160-beta" targetFramework="net45" />
</packages> </packages>
\ No newline at end of file
using System;
namespace Titanium.Web.Proxy.EventArguments
{
/// <summary>
/// Wraps the data sent/received by a proxy server instance.
/// </summary>
public class DataEventArgs : EventArgs
{
internal DataEventArgs(byte[] buffer, int offset, int count)
{
Buffer = buffer;
Offset = offset;
Count = count;
}
/// <summary>
/// The buffer with data.
/// </summary>
public byte[] Buffer { get; }
/// <summary>
/// Offset in buffer from which valid data begins.
/// </summary>
public int Offset { get; }
/// <summary>
/// Length from offset in buffer with valid data.
/// </summary>
public int Count { get; }
}
}
...@@ -9,18 +9,16 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -9,18 +9,16 @@ namespace Titanium.Web.Proxy.EventArguments
{ {
internal class LimitedStream : Stream internal class LimitedStream : Stream
{ {
private readonly CustomBinaryReader baseReader; private readonly ICustomStreamReader baseStream;
private readonly CustomBufferedStream baseStream;
private readonly bool isChunked; private readonly bool isChunked;
private long bytesRemaining; private long bytesRemaining;
private bool readChunkTrail; private bool readChunkTrail;
internal LimitedStream(CustomBufferedStream baseStream, CustomBinaryReader baseReader, bool isChunked, internal LimitedStream(ICustomStreamReader baseStream, bool isChunked,
long contentLength) long contentLength)
{ {
this.baseStream = baseStream; this.baseStream = baseStream;
this.baseReader = baseReader;
this.isChunked = isChunked; this.isChunked = isChunked;
bytesRemaining = isChunked bytesRemaining = isChunked
? 0 ? 0
...@@ -48,12 +46,12 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -48,12 +46,12 @@ namespace Titanium.Web.Proxy.EventArguments
if (readChunkTrail) if (readChunkTrail)
{ {
// read the chunk trail of the previous chunk // read the chunk trail of the previous chunk
string s = baseReader.ReadLineAsync().Result; string s = baseStream.ReadLineAsync().Result;
} }
readChunkTrail = true; readChunkTrail = true;
string chunkHead = baseReader.ReadLineAsync().Result; string chunkHead = baseStream.ReadLineAsync().Result;
int idx = chunkHead.IndexOf(";", StringComparison.Ordinal); int idx = chunkHead.IndexOf(";", StringComparison.Ordinal);
if (idx >= 0) if (idx >= 0)
{ {
...@@ -68,7 +66,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -68,7 +66,7 @@ namespace Titanium.Web.Proxy.EventArguments
bytesRemaining = -1; bytesRemaining = -1;
//chunk trail //chunk trail
baseReader.ReadLineAsync().Wait(); baseStream.ReadLineAsync().Wait();
} }
} }
...@@ -127,7 +125,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -127,7 +125,7 @@ namespace Titanium.Web.Proxy.EventArguments
{ {
if (bytesRemaining != -1) if (bytesRemaining != -1)
{ {
var buffer = BufferPool.GetBuffer(baseReader.Buffer.Length); var buffer = BufferPool.GetBuffer(baseStream.BufferSize);
try try
{ {
int res = await ReadAsync(buffer, 0, buffer.Length); int res = await ReadAsync(buffer, 0, buffer.Length);
......
...@@ -68,16 +68,11 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -68,16 +68,11 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary> /// </summary>
public event EventHandler<MultipartRequestPartSentEventArgs> MultipartRequestPartSent; public event EventHandler<MultipartRequestPartSentEventArgs> MultipartRequestPartSent;
private CustomBufferedStream GetStream(bool isRequest) private ICustomStreamReader GetStreamReader(bool isRequest)
{ {
return isRequest ? ProxyClient.ClientStream : WebSession.ServerConnection.Stream; return isRequest ? ProxyClient.ClientStream : WebSession.ServerConnection.Stream;
} }
private CustomBinaryReader GetStreamReader(bool isRequest)
{
return isRequest ? ProxyClient.ClientStreamReader : WebSession.ServerConnection.StreamReader;
}
private HttpWriter GetStreamWriter(bool isRequest) private HttpWriter GetStreamWriter(bool isRequest)
{ {
return isRequest ? (HttpWriter)ProxyClient.ClientStreamWriter : WebSession.ServerConnection.StreamWriter; return isRequest ? (HttpWriter)ProxyClient.ClientStreamWriter : WebSession.ServerConnection.StreamWriter;
...@@ -207,11 +202,10 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -207,11 +202,10 @@ namespace Titanium.Web.Proxy.EventArguments
string boundary = HttpHelper.GetBoundaryFromContentType(request.ContentType); string boundary = HttpHelper.GetBoundaryFromContentType(request.ContentType);
using (var copyStream = new CopyStream(reader, writer, BufferSize)) using (var copyStream = new CopyStream(reader, writer, BufferSize))
using (var copyStreamReader = new CustomBinaryReader(copyStream, BufferSize))
{ {
while (contentLength > copyStream.ReadBytes) while (contentLength > copyStream.ReadBytes)
{ {
long read = await ReadUntilBoundaryAsync(copyStreamReader, contentLength, boundary, cancellationToken); long read = await ReadUntilBoundaryAsync(copyStream, contentLength, boundary, cancellationToken);
if (read == 0) if (read == 0)
{ {
break; break;
...@@ -220,7 +214,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -220,7 +214,7 @@ namespace Titanium.Web.Proxy.EventArguments
if (contentLength > copyStream.ReadBytes) if (contentLength > copyStream.ReadBytes)
{ {
var headers = new HeaderCollection(); var headers = new HeaderCollection();
await HeaderParser.ReadHeaders(copyStreamReader, headers, cancellationToken); await HeaderParser.ReadHeaders(copyStream, headers, cancellationToken);
OnMultipartRequestPartSent(boundary, headers); OnMultipartRequestPartSent(boundary, headers);
} }
} }
...@@ -241,8 +235,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -241,8 +235,7 @@ namespace Titanium.Web.Proxy.EventArguments
private async Task CopyBodyAsync(bool isRequest, HttpWriter writer, TransformationMode transformation, Action<byte[], int, int> onCopy, CancellationToken cancellationToken) private async Task CopyBodyAsync(bool isRequest, HttpWriter writer, TransformationMode transformation, Action<byte[], int, int> onCopy, CancellationToken cancellationToken)
{ {
var stream = GetStream(isRequest); var stream = GetStreamReader(isRequest);
var reader = GetStreamReader(isRequest);
var requestResponse = isRequest ? (RequestResponseBase)WebSession.Request : WebSession.Response; var requestResponse = isRequest ? (RequestResponseBase)WebSession.Request : WebSession.Response;
...@@ -250,7 +243,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -250,7 +243,7 @@ namespace Titanium.Web.Proxy.EventArguments
long contentLength = requestResponse.ContentLength; long contentLength = requestResponse.ContentLength;
if (transformation == TransformationMode.None) if (transformation == TransformationMode.None)
{ {
await writer.CopyBodyAsync(reader, isChunked, contentLength, onCopy, cancellationToken); await writer.CopyBodyAsync(stream, isChunked, contentLength, onCopy, cancellationToken);
return; return;
} }
...@@ -259,7 +252,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -259,7 +252,7 @@ namespace Titanium.Web.Proxy.EventArguments
string contentEncoding = requestResponse.ContentEncoding; string contentEncoding = requestResponse.ContentEncoding;
Stream s = limitedStream = new LimitedStream(stream, reader, isChunked, contentLength); Stream s = limitedStream = new LimitedStream(stream, isChunked, contentLength);
if (transformation == TransformationMode.Uncompress && contentEncoding != null) if (transformation == TransformationMode.Uncompress && contentEncoding != null)
{ {
...@@ -269,13 +262,10 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -269,13 +262,10 @@ namespace Titanium.Web.Proxy.EventArguments
try try
{ {
var bufStream = new CustomBufferedStream(s, BufferSize, true); var bufStream = new CustomBufferedStream(s, BufferSize, true);
reader = new CustomBinaryReader(bufStream, BufferSize); await writer.CopyBodyAsync(bufStream, false, -1, onCopy, cancellationToken);
await writer.CopyBodyAsync(reader, false, -1, onCopy, cancellationToken);
} }
finally finally
{ {
reader?.Dispose();
decompressStream?.Dispose(); decompressStream?.Dispose();
await limitedStream.Finish(); await limitedStream.Finish();
...@@ -287,7 +277,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -287,7 +277,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// Read a line from the byte stream /// Read a line from the byte stream
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
private async Task<long> ReadUntilBoundaryAsync(CustomBinaryReader reader, long totalBytesToRead, string boundary, CancellationToken cancellationToken) private async Task<long> ReadUntilBoundaryAsync(ICustomStreamReader reader, long totalBytesToRead, string boundary, CancellationToken cancellationToken)
{ {
int bufferDataLength = 0; int bufferDataLength = 0;
......
using System; using System;
using System.Net; using System.Net;
using System.Threading; using System.Threading;
using StreamExtended.Network;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
...@@ -50,7 +51,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -50,7 +51,7 @@ namespace Titanium.Web.Proxy.EventArguments
{ {
if (RunTime.IsWindows) if (RunTime.IsWindows)
{ {
var remoteEndPoint = (IPEndPoint)ProxyClient.TcpClient.Client.RemoteEndPoint; var remoteEndPoint = ClientEndPoint;
//If client is localhost get the process id //If client is localhost get the process id
if (NetworkHelper.IsLocalIpAddress(remoteEndPoint.Address)) if (NetworkHelper.IsLocalIpAddress(remoteEndPoint.Address))
......
...@@ -34,7 +34,6 @@ namespace Titanium.Web.Proxy ...@@ -34,7 +34,6 @@ namespace Titanium.Web.Proxy
var clientStream = new CustomBufferedStream(tcpClient.GetStream(), BufferSize); var clientStream = new CustomBufferedStream(tcpClient.GetStream(), BufferSize);
var clientStreamReader = new CustomBinaryReader(clientStream, BufferSize);
var clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize); var clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize);
try try
...@@ -46,7 +45,7 @@ namespace Titanium.Web.Proxy ...@@ -46,7 +45,7 @@ namespace Titanium.Web.Proxy
if (await HttpHelper.IsConnectMethod(clientStream) == 1) if (await HttpHelper.IsConnectMethod(clientStream) == 1)
{ {
//read the first line HTTP command //read the first line HTTP command
string httpCmd = await clientStreamReader.ReadLineAsync(cancellationToken); string httpCmd = await clientStream.ReadLineAsync(cancellationToken);
if (string.IsNullOrEmpty(httpCmd)) if (string.IsNullOrEmpty(httpCmd))
{ {
return; return;
...@@ -64,7 +63,7 @@ namespace Titanium.Web.Proxy ...@@ -64,7 +63,7 @@ namespace Titanium.Web.Proxy
HttpVersion = version HttpVersion = version
}; };
await HeaderParser.ReadHeaders(clientStreamReader, connectRequest.Headers, cancellationToken); await HeaderParser.ReadHeaders(clientStream, connectRequest.Headers, cancellationToken);
connectArgs = new TunnelConnectSessionEventArgs(BufferSize, endPoint, connectRequest, connectArgs = new TunnelConnectSessionEventArgs(BufferSize, endPoint, connectRequest,
cancellationTokenSource, ExceptionFunc); cancellationTokenSource, ExceptionFunc);
...@@ -159,7 +158,7 @@ namespace Titanium.Web.Proxy ...@@ -159,7 +158,7 @@ namespace Titanium.Web.Proxy
options.ApplicationProtocols = clientHelloInfo.GetAlpn(); options.ApplicationProtocols = clientHelloInfo.GetAlpn();
if (options.ApplicationProtocols == null || options.ApplicationProtocols.Count == 0) if (options.ApplicationProtocols == null || options.ApplicationProtocols.Count == 0)
{ {
options.ApplicationProtocols = SslExtensions.Http11ProtocolAsList; options.ApplicationProtocols = Titanium.Web.Proxy.Extensions.SslExtensions.Http11ProtocolAsList;
} }
} }
...@@ -172,8 +171,6 @@ namespace Titanium.Web.Proxy ...@@ -172,8 +171,6 @@ namespace Titanium.Web.Proxy
//HTTPS server created - we can now decrypt the client's traffic //HTTPS server created - we can now decrypt the client's traffic
clientStream = new CustomBufferedStream(sslStream, BufferSize); clientStream = new CustomBufferedStream(sslStream, BufferSize);
clientStreamReader.Dispose();
clientStreamReader = new CustomBinaryReader(clientStream, BufferSize);
clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize); clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize);
} }
catch (Exception e) catch (Exception e)
...@@ -240,23 +237,23 @@ namespace Titanium.Web.Proxy ...@@ -240,23 +237,23 @@ namespace Titanium.Web.Proxy
if (connectArgs != null && await HttpHelper.IsPriMethod(clientStream) == 1) if (connectArgs != null && await HttpHelper.IsPriMethod(clientStream) == 1)
{ {
// todo // todo
string httpCmd = await clientStreamReader.ReadLineAsync(cancellationToken); string httpCmd = await clientStream.ReadLineAsync(cancellationToken);
if (httpCmd == "PRI * HTTP/2.0") if (httpCmd == "PRI * HTTP/2.0")
{ {
// HTTP/2 Connection Preface // HTTP/2 Connection Preface
string line = await clientStreamReader.ReadLineAsync(cancellationToken); string line = await clientStream.ReadLineAsync(cancellationToken);
if (line != string.Empty) if (line != string.Empty)
{ {
throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received"); throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received");
} }
line = await clientStreamReader.ReadLineAsync(cancellationToken); line = await clientStream.ReadLineAsync(cancellationToken);
if (line != "SM") if (line != "SM")
{ {
throw new Exception($"HTTP/2 Protocol violation. 'SM' expected, '{line}' received"); throw new Exception($"HTTP/2 Protocol violation. 'SM' expected, '{line}' received");
} }
line = await clientStreamReader.ReadLineAsync(cancellationToken); line = await clientStream.ReadLineAsync(cancellationToken);
if (line != string.Empty) if (line != string.Empty)
{ {
throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received"); throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received");
...@@ -279,7 +276,7 @@ namespace Titanium.Web.Proxy ...@@ -279,7 +276,7 @@ namespace Titanium.Web.Proxy
} }
//Now create the request //Now create the request
await HandleHttpSessionRequest(endPoint, tcpClient, clientStream, clientStreamReader, await HandleHttpSessionRequest(endPoint, tcpClient, clientStream,
clientStreamWriter, cancellationTokenSource, connectHostname, clientStreamWriter, cancellationTokenSource, connectHostname,
connectArgs?.WebSession.ConnectRequest); connectArgs?.WebSession.ConnectRequest);
} }
...@@ -301,7 +298,6 @@ namespace Titanium.Web.Proxy ...@@ -301,7 +298,6 @@ namespace Titanium.Web.Proxy
} }
finally finally
{ {
clientStreamReader.Dispose();
clientStream.Dispose(); clientStream.Dispose();
if (!cancellationTokenSource.IsCancellationRequested) if (!cancellationTokenSource.IsCancellationRequested)
{ {
......
...@@ -11,17 +11,20 @@ using Titanium.Web.Proxy.Shared; ...@@ -11,17 +11,20 @@ using Titanium.Web.Proxy.Shared;
namespace Titanium.Web.Proxy.Helpers namespace Titanium.Web.Proxy.Helpers
{ {
internal class HttpWriter : CustomBinaryWriter internal class HttpWriter : ICustomStreamWriter
{ {
private readonly Stream stream;
private static readonly byte[] newLine = ProxyConstants.NewLine; private static readonly byte[] newLine = ProxyConstants.NewLine;
private static readonly Encoder encoder = Encoding.ASCII.GetEncoder(); private static readonly Encoder encoder = Encoding.ASCII.GetEncoder();
private readonly char[] charBuffer; private readonly char[] charBuffer;
internal HttpWriter(Stream stream, int bufferSize) : base(stream) internal HttpWriter(Stream stream, int bufferSize)
{ {
BufferSize = bufferSize; BufferSize = bufferSize;
this.stream = stream;
// ASCII encoder max byte count is char count + 1 // ASCII encoder max byte count is char count + 1
charBuffer = new char[BufferSize - 1]; charBuffer = new char[BufferSize - 1];
...@@ -62,7 +65,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -62,7 +65,7 @@ namespace Titanium.Web.Proxy.Helpers
idx += newLineChars; idx += newLineChars;
} }
return WriteAsync(buffer, 0, idx, cancellationToken); return stream.WriteAsync(buffer, 0, idx, cancellationToken);
} }
finally finally
{ {
...@@ -82,7 +85,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -82,7 +85,7 @@ namespace Titanium.Web.Proxy.Helpers
idx += newLineChars; idx += newLineChars;
} }
return WriteAsync(buffer, 0, idx, cancellationToken); return stream.WriteAsync(buffer, 0, idx, cancellationToken);
} }
} }
...@@ -109,26 +112,26 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -109,26 +112,26 @@ namespace Titanium.Web.Proxy.Helpers
await WriteLineAsync(cancellationToken); await WriteLineAsync(cancellationToken);
if (flush) if (flush)
{ {
await FlushAsync(cancellationToken); await stream.FlushAsync(cancellationToken);
} }
} }
internal async Task WriteAsync(byte[] data, bool flush = false, CancellationToken cancellationToken = default) internal async Task WriteAsync(byte[] data, bool flush = false, CancellationToken cancellationToken = default)
{ {
await WriteAsync(data, 0, data.Length, cancellationToken); await stream.WriteAsync(data, 0, data.Length, cancellationToken);
if (flush) if (flush)
{ {
await FlushAsync(cancellationToken); await stream.FlushAsync(cancellationToken);
} }
} }
internal async Task WriteAsync(byte[] data, int offset, int count, bool flush, internal async Task WriteAsync(byte[] data, int offset, int count, bool flush,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
await WriteAsync(data, offset, count, cancellationToken); await stream.WriteAsync(data, offset, count, cancellationToken);
if (flush) if (flush)
{ {
await FlushAsync(cancellationToken); await stream.FlushAsync(cancellationToken);
} }
} }
...@@ -159,7 +162,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -159,7 +162,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="onCopy"></param> /// <param name="onCopy"></param>
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
internal Task CopyBodyAsync(CustomBinaryReader streamReader, bool isChunked, long contentLength, internal Task CopyBodyAsync(ICustomStreamReader streamReader, bool isChunked, long contentLength,
Action<byte[], int, int> onCopy, CancellationToken cancellationToken) Action<byte[], int, int> onCopy, CancellationToken cancellationToken)
{ {
//For chunked request we need to read data as they arrive, until we reach a chunk end symbol //For chunked request we need to read data as they arrive, until we reach a chunk end symbol
...@@ -204,7 +207,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -204,7 +207,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="onCopy"></param> /// <param name="onCopy"></param>
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
private async Task CopyBodyChunkedAsync(CustomBinaryReader reader, Action<byte[], int, int> onCopy, private async Task CopyBodyChunkedAsync(ICustomStreamReader reader, Action<byte[], int, int> onCopy,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
while (true) while (true)
...@@ -245,31 +248,39 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -245,31 +248,39 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="onCopy"></param> /// <param name="onCopy"></param>
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
private async Task CopyBytesFromStream(CustomBinaryReader reader, long count, Action<byte[], int, int> onCopy, private async Task CopyBytesFromStream(ICustomStreamReader reader, long count, Action<byte[], int, int> onCopy,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
var buffer = reader.Buffer; var buffer = BufferPool.GetBuffer(BufferSize);
long remainingBytes = count;
while (remainingBytes > 0) try
{ {
int bytesToRead = buffer.Length; long remainingBytes = count;
if (remainingBytes < bytesToRead)
{
bytesToRead = (int)remainingBytes;
}
int bytesRead = await reader.ReadBytesAsync(buffer, bytesToRead, cancellationToken); while (remainingBytes > 0)
if (bytesRead == 0)
{ {
break; int bytesToRead = buffer.Length;
} if (remainingBytes < bytesToRead)
{
bytesToRead = (int)remainingBytes;
}
remainingBytes -= bytesRead; int bytesRead = await reader.ReadAsync(buffer, 0, bytesToRead, cancellationToken);
if (bytesRead == 0)
{
break;
}
await WriteAsync(buffer, 0, bytesRead, cancellationToken); remainingBytes -= bytesRead;
onCopy?.Invoke(buffer, 0, bytesRead); await stream.WriteAsync(buffer, 0, bytesRead, cancellationToken);
onCopy?.Invoke(buffer, 0, bytesRead);
}
}
finally
{
BufferPool.ReturnBuffer(buffer);
} }
} }
...@@ -291,5 +302,33 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -291,5 +302,33 @@ namespace Titanium.Web.Proxy.Helpers
await WriteBodyAsync(body, requestResponse.IsChunked, cancellationToken); await WriteBodyAsync(body, requestResponse.IsChunked, cancellationToken);
} }
} }
/// <summary>When overridden in a derived class, writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written.</summary>
/// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</param>
/// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current stream.</param>
/// <param name="count">The number of bytes to be written to the current stream.</param>
/// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length.</exception>
/// <exception cref="T:System.ArgumentNullException">buffer is null.</exception>
/// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative.</exception>
/// <exception cref="T:System.IO.IOException">An I/O error occured, such as the specified file cannot be found.</exception>
/// <exception cref="T:System.NotSupportedException">The stream does not support writing.</exception>
/// <exception cref="T:System.ObjectDisposedException"><see cref="M:System.IO.Stream.Write(System.Byte[],System.Int32,System.Int32)"></see> was called after the stream was closed.</exception>
public void Write(byte[] buffer, int offset, int count)
{
stream.Write(buffer, offset, count);
}
/// <summary>
/// Asynchronously writes a sequence of bytes to the current stream, advances the current position within this stream by the number of bytes written, and monitors cancellation requests.
/// </summary>
/// <param name="buffer">The buffer to write data from.</param>
/// <param name="offset">The zero-based byte offset in <paramref name="buffer" /> from which to begin copying bytes to the stream.</param>
/// <param name="count">The maximum number of bytes to write.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="P:System.Threading.CancellationToken.None" />.</param>
/// <returns>A task that represents the asynchronous write operation.</returns>
public Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return stream.WriteAsync(buffer, offset, count, cancellationToken);
}
} }
} }
...@@ -8,7 +8,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -8,7 +8,7 @@ namespace Titanium.Web.Proxy.Http
{ {
internal static class HeaderParser internal static class HeaderParser
{ {
internal static async Task ReadHeaders(CustomBinaryReader reader, HeaderCollection headerCollection, internal static async Task ReadHeaders(ICustomStreamReader reader, HeaderCollection headerCollection,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
string tmpLine; string tmpLine;
......
...@@ -121,7 +121,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -121,7 +121,7 @@ namespace Titanium.Web.Proxy.Http
{ {
if (Request.ExpectContinue) if (Request.ExpectContinue)
{ {
string httpStatus = await ServerConnection.StreamReader.ReadLineAsync(cancellationToken); string httpStatus = await ServerConnection.Stream.ReadLineAsync(cancellationToken);
Response.ParseResponseLine(httpStatus, out _, out int responseStatusCode, Response.ParseResponseLine(httpStatus, out _, out int responseStatusCode,
out string responseStatusDescription); out string responseStatusDescription);
...@@ -131,13 +131,13 @@ namespace Titanium.Web.Proxy.Http ...@@ -131,13 +131,13 @@ namespace Titanium.Web.Proxy.Http
&& responseStatusDescription.EqualsIgnoreCase("continue")) && responseStatusDescription.EqualsIgnoreCase("continue"))
{ {
Request.Is100Continue = true; Request.Is100Continue = true;
await ServerConnection.StreamReader.ReadLineAsync(cancellationToken); await ServerConnection.Stream.ReadLineAsync(cancellationToken);
} }
else if (responseStatusCode == (int)HttpStatusCode.ExpectationFailed else if (responseStatusCode == (int)HttpStatusCode.ExpectationFailed
&& responseStatusDescription.EqualsIgnoreCase("expectation failed")) && responseStatusDescription.EqualsIgnoreCase("expectation failed"))
{ {
Request.ExpectationFailed = true; Request.ExpectationFailed = true;
await ServerConnection.StreamReader.ReadLineAsync(cancellationToken); await ServerConnection.Stream.ReadLineAsync(cancellationToken);
} }
} }
} }
...@@ -155,7 +155,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -155,7 +155,7 @@ namespace Titanium.Web.Proxy.Http
return; return;
} }
string httpStatus = await ServerConnection.StreamReader.ReadLineAsync(cancellationToken); string httpStatus = await ServerConnection.Stream.ReadLineAsync(cancellationToken);
if (httpStatus == null) if (httpStatus == null)
{ {
throw new IOException(); throw new IOException();
...@@ -163,7 +163,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -163,7 +163,7 @@ namespace Titanium.Web.Proxy.Http
if (httpStatus == string.Empty) if (httpStatus == string.Empty)
{ {
httpStatus = await ServerConnection.StreamReader.ReadLineAsync(cancellationToken); httpStatus = await ServerConnection.Stream.ReadLineAsync(cancellationToken);
} }
Response.ParseResponseLine(httpStatus, out var version, out int statusCode, out string statusDescription); Response.ParseResponseLine(httpStatus, out var version, out int statusCode, out string statusDescription);
...@@ -179,7 +179,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -179,7 +179,7 @@ namespace Titanium.Web.Proxy.Http
//Read the next line after 100-continue //Read the next line after 100-continue
Response.Is100Continue = true; Response.Is100Continue = true;
Response.StatusCode = 0; Response.StatusCode = 0;
await ServerConnection.StreamReader.ReadLineAsync(cancellationToken); await ServerConnection.Stream.ReadLineAsync(cancellationToken);
//now receive response //now receive response
await ReceiveResponse(cancellationToken); await ReceiveResponse(cancellationToken);
...@@ -192,7 +192,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -192,7 +192,7 @@ namespace Titanium.Web.Proxy.Http
//read next line after expectation failed response //read next line after expectation failed response
Response.ExpectationFailed = true; Response.ExpectationFailed = true;
Response.StatusCode = 0; Response.StatusCode = 0;
await ServerConnection.StreamReader.ReadLineAsync(cancellationToken); await ServerConnection.Stream.ReadLineAsync(cancellationToken);
//now receive response //now receive response
await ReceiveResponse(cancellationToken); await ReceiveResponse(cancellationToken);
...@@ -200,7 +200,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -200,7 +200,7 @@ namespace Titanium.Web.Proxy.Http
} }
//Read the response headers in to unique and non-unique header collections //Read the response headers in to unique and non-unique header collections
await HeaderParser.ReadHeaders(ServerConnection.StreamReader, Response.Headers, cancellationToken); await HeaderParser.ReadHeaders(ServerConnection.Stream, Response.Headers, cancellationToken);
} }
/// <summary> /// <summary>
......
...@@ -24,12 +24,12 @@ namespace Titanium.Web.Proxy.Network ...@@ -24,12 +24,12 @@ namespace Titanium.Web.Proxy.Network
public int Counter { get; } public int Counter { get; }
protected override void OnDataSent(byte[] buffer, int offset, int count) protected override void OnDataWrite(byte[] buffer, int offset, int count)
{ {
fileStreamSent.Write(buffer, offset, count); fileStreamSent.Write(buffer, offset, count);
} }
protected override void OnDataReceived(byte[] buffer, int offset, int count) protected override void OnDataRead(byte[] buffer, int offset, int count)
{ {
fileStreamReceived.Write(buffer, offset, count); fileStreamReceived.Write(buffer, offset, count);
} }
......
...@@ -19,11 +19,6 @@ namespace Titanium.Web.Proxy.Network ...@@ -19,11 +19,6 @@ namespace Titanium.Web.Proxy.Network
/// </summary> /// </summary>
internal CustomBufferedStream ClientStream { get; set; } internal CustomBufferedStream ClientStream { get; set; }
/// <summary>
/// Used to read line by line from client
/// </summary>
internal CustomBinaryReader ClientStreamReader { get; set; }
/// <summary> /// <summary>
/// Used to write line by line to client /// Used to write line by line to client
/// </summary> /// </summary>
......
...@@ -46,11 +46,6 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -46,11 +46,6 @@ namespace Titanium.Web.Proxy.Network.Tcp
internal TcpClient TcpClient { private get; set; } internal TcpClient TcpClient { private get; set; }
/// <summary>
/// Used to read lines from server
/// </summary>
internal CustomBinaryReader StreamReader { get; set; }
/// <summary> /// <summary>
/// Used to write lines to server /// Used to write lines to server
/// </summary> /// </summary>
...@@ -71,8 +66,6 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -71,8 +66,6 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// </summary> /// </summary>
public void Dispose() public void Dispose()
{ {
StreamReader?.Dispose();
Stream?.Dispose(); Stream?.Dispose();
TcpClient.CloseSocket(); TcpClient.CloseSocket();
......
...@@ -93,20 +93,17 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -93,20 +93,17 @@ namespace Titanium.Web.Proxy.Network.Tcp
await writer.WriteRequestAsync(connectRequest, cancellationToken: cancellationToken); await writer.WriteRequestAsync(connectRequest, cancellationToken: cancellationToken);
using (var reader = new CustomBinaryReader(stream, proxyServer.BufferSize)) string httpStatus = await stream.ReadLineAsync(cancellationToken);
{
string httpStatus = await reader.ReadLineAsync(cancellationToken);
Response.ParseResponseLine(httpStatus, out _, out int statusCode, out string statusDescription);
if (statusCode != 200 && !statusDescription.EqualsIgnoreCase("OK") Response.ParseResponseLine(httpStatus, out _, out int statusCode, out string statusDescription);
&& !statusDescription.EqualsIgnoreCase("Connection Established"))
{
throw new Exception("Upstream proxy failed to create a secure tunnel");
}
await reader.ReadAndIgnoreAllLinesAsync(cancellationToken); if (statusCode != 200 && !statusDescription.EqualsIgnoreCase("OK")
&& !statusDescription.EqualsIgnoreCase("Connection Established"))
{
throw new Exception("Upstream proxy failed to create a secure tunnel");
} }
await stream.ReadAndIgnoreAllLinesAsync(cancellationToken);
} }
if (decryptSsl) if (decryptSsl)
...@@ -152,7 +149,6 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -152,7 +149,6 @@ namespace Titanium.Web.Proxy.Network.Tcp
IsHttp2Supported = http2Supported, IsHttp2Supported = http2Supported,
UseUpstreamProxy = useUpstreamProxy, UseUpstreamProxy = useUpstreamProxy,
TcpClient = client, TcpClient = client,
StreamReader = new CustomBinaryReader(stream, proxyServer.BufferSize),
StreamWriter = new HttpRequestWriter(stream, proxyServer.BufferSize), StreamWriter = new HttpRequestWriter(stream, proxyServer.BufferSize),
Stream = stream, Stream = stream,
Version = httpVersion Version = httpVersion
......
...@@ -34,7 +34,6 @@ namespace Titanium.Web.Proxy ...@@ -34,7 +34,6 @@ namespace Titanium.Web.Proxy
/// <param name="endPoint">The proxy endpoint.</param> /// <param name="endPoint">The proxy endpoint.</param>
/// <param name="client">The client.</param> /// <param name="client">The client.</param>
/// <param name="clientStream">The client stream.</param> /// <param name="clientStream">The client stream.</param>
/// <param name="clientStreamReader">The client stream reader.</param>
/// <param name="clientStreamWriter">The client stream writer.</param> /// <param name="clientStreamWriter">The client stream writer.</param>
/// <param name="cancellationTokenSource">The cancellation token source for this async task.</param> /// <param name="cancellationTokenSource">The cancellation token source for this async task.</param>
/// <param name="httpsConnectHostname"> /// <param name="httpsConnectHostname">
...@@ -45,8 +44,7 @@ namespace Titanium.Web.Proxy ...@@ -45,8 +44,7 @@ namespace Titanium.Web.Proxy
/// <param name="isTransparentEndPoint">Is this a request from transparent endpoint?</param> /// <param name="isTransparentEndPoint">Is this a request from transparent endpoint?</param>
/// <returns></returns> /// <returns></returns>
private async Task HandleHttpSessionRequest(ProxyEndPoint endPoint, TcpClient client, private async Task HandleHttpSessionRequest(ProxyEndPoint endPoint, TcpClient client,
CustomBufferedStream clientStream, CustomBinaryReader clientStreamReader, CustomBufferedStream clientStream, HttpResponseWriter clientStreamWriter,
HttpResponseWriter clientStreamWriter,
CancellationTokenSource cancellationTokenSource, string httpsConnectHostname, ConnectRequest connectRequest, CancellationTokenSource cancellationTokenSource, string httpsConnectHostname, ConnectRequest connectRequest,
bool isTransparentEndPoint = false) bool isTransparentEndPoint = false)
{ {
...@@ -60,7 +58,7 @@ namespace Titanium.Web.Proxy ...@@ -60,7 +58,7 @@ namespace Titanium.Web.Proxy
while (true) while (true)
{ {
// read the request line // read the request line
string httpCmd = await clientStreamReader.ReadLineAsync(cancellationToken); string httpCmd = await clientStream.ReadLineAsync(cancellationToken);
if (string.IsNullOrEmpty(httpCmd)) if (string.IsNullOrEmpty(httpCmd))
{ {
...@@ -81,7 +79,7 @@ namespace Titanium.Web.Proxy ...@@ -81,7 +79,7 @@ namespace Titanium.Web.Proxy
out var version); out var version);
//Read the request headers in to unique and non-unique header collections //Read the request headers in to unique and non-unique header collections
await HeaderParser.ReadHeaders(clientStreamReader, args.WebSession.Request.Headers, await HeaderParser.ReadHeaders(clientStream, args.WebSession.Request.Headers,
cancellationToken); cancellationToken);
Uri httpRemoteUri; Uri httpRemoteUri;
...@@ -124,7 +122,6 @@ namespace Titanium.Web.Proxy ...@@ -124,7 +122,6 @@ namespace Titanium.Web.Proxy
request.Method = httpMethod; request.Method = httpMethod;
request.HttpVersion = version; request.HttpVersion = version;
args.ProxyClient.ClientStream = clientStream; args.ProxyClient.ClientStream = clientStream;
args.ProxyClient.ClientStreamReader = clientStreamReader;
args.ProxyClient.ClientStreamWriter = clientStreamWriter; args.ProxyClient.ClientStreamWriter = clientStreamWriter;
//proxy authorization check //proxy authorization check
...@@ -198,7 +195,7 @@ namespace Titanium.Web.Proxy ...@@ -198,7 +195,7 @@ namespace Titanium.Web.Proxy
await connection.StreamWriter.WriteLineAsync(httpCmd, cancellationToken); await connection.StreamWriter.WriteLineAsync(httpCmd, cancellationToken);
await connection.StreamWriter.WriteHeadersAsync(request.Headers, await connection.StreamWriter.WriteHeadersAsync(request.Headers,
cancellationToken: cancellationToken); cancellationToken: cancellationToken);
string httpStatus = await connection.StreamReader.ReadLineAsync(cancellationToken); string httpStatus = await connection.Stream.ReadLineAsync(cancellationToken);
Response.ParseResponseLine(httpStatus, out var responseVersion, Response.ParseResponseLine(httpStatus, out var responseVersion,
out int responseStatusCode, out int responseStatusCode,
...@@ -207,7 +204,7 @@ namespace Titanium.Web.Proxy ...@@ -207,7 +204,7 @@ namespace Titanium.Web.Proxy
response.StatusCode = responseStatusCode; response.StatusCode = responseStatusCode;
response.StatusDescription = responseStatusDescription; response.StatusDescription = responseStatusDescription;
await HeaderParser.ReadHeaders(connection.StreamReader, response.Headers, await HeaderParser.ReadHeaders(connection.Stream, response.Headers,
cancellationToken); cancellationToken);
if (!args.IsTransparent) if (!args.IsTransparent)
......
...@@ -37,8 +37,8 @@ ...@@ -37,8 +37,8 @@
<Reference Include="BouncyCastle.Crypto, Version=1.8.2.0, Culture=neutral, PublicKeyToken=0e99375e54769942, processorArchitecture=MSIL"> <Reference Include="BouncyCastle.Crypto, Version=1.8.2.0, Culture=neutral, PublicKeyToken=0e99375e54769942, processorArchitecture=MSIL">
<HintPath>..\packages\Portable.BouncyCastle.1.8.2\lib\net40\BouncyCastle.Crypto.dll</HintPath> <HintPath>..\packages\Portable.BouncyCastle.1.8.2\lib\net40\BouncyCastle.Crypto.dll</HintPath>
</Reference> </Reference>
<Reference Include="StreamExtended, Version=1.0.147.0, Culture=neutral, PublicKeyToken=bbfa0f1d54f50043, processorArchitecture=MSIL"> <Reference Include="StreamExtended, Version=1.0.160.0, Culture=neutral, PublicKeyToken=bbfa0f1d54f50043, processorArchitecture=MSIL">
<HintPath>..\packages\StreamExtended.1.0.147-beta\lib\net45\StreamExtended.dll</HintPath> <HintPath>..\packages\StreamExtended.1.0.160-beta\lib\net45\StreamExtended.dll</HintPath>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Portable.BouncyCastle" Version="1.8.2" /> <PackageReference Include="Portable.BouncyCastle" Version="1.8.2" />
<PackageReference Include="StreamExtended" Version="1.0.147-beta" /> <PackageReference Include="StreamExtended" Version="1.0.160-beta" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'"> <ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
<copyright>Copyright &#x00A9; Titanium. All rights reserved.</copyright> <copyright>Copyright &#x00A9; Titanium. All rights reserved.</copyright>
<tags></tags> <tags></tags>
<dependencies> <dependencies>
<dependency id="StreamExtended" version="1.0.147-beta" /> <dependency id="StreamExtended" version="1.0.160-beta" />
<dependency id="Portable.BouncyCastle" version="1.8.2" /> <dependency id="Portable.BouncyCastle" version="1.8.2" />
</dependencies> </dependencies>
</metadata> </metadata>
......
...@@ -30,7 +30,6 @@ namespace Titanium.Web.Proxy ...@@ -30,7 +30,6 @@ namespace Titanium.Web.Proxy
var clientStream = new CustomBufferedStream(tcpClient.GetStream(), BufferSize); var clientStream = new CustomBufferedStream(tcpClient.GetStream(), BufferSize);
var clientStreamReader = new CustomBinaryReader(clientStream, BufferSize);
var clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize); var clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize);
try try
...@@ -73,8 +72,6 @@ namespace Titanium.Web.Proxy ...@@ -73,8 +72,6 @@ namespace Titanium.Web.Proxy
//HTTPS server created - we can now decrypt the client's traffic //HTTPS server created - we can now decrypt the client's traffic
clientStream = new CustomBufferedStream(sslStream, BufferSize); clientStream = new CustomBufferedStream(sslStream, BufferSize);
clientStreamReader.Dispose();
clientStreamReader = new CustomBinaryReader(clientStream, BufferSize);
clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize); clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize);
} }
catch (Exception e) catch (Exception e)
...@@ -126,12 +123,11 @@ namespace Titanium.Web.Proxy ...@@ -126,12 +123,11 @@ namespace Titanium.Web.Proxy
//HTTPS server created - we can now decrypt the client's traffic //HTTPS server created - we can now decrypt the client's traffic
//Now create the request //Now create the request
await HandleHttpSessionRequest(endPoint, tcpClient, clientStream, clientStreamReader, await HandleHttpSessionRequest(endPoint, tcpClient, clientStream, clientStreamWriter,
clientStreamWriter, cancellationTokenSource, isHttps ? httpsHostName : null, null, true); cancellationTokenSource, isHttps ? httpsHostName : null, null, true);
} }
finally finally
{ {
clientStreamReader.Dispose();
clientStream.Dispose(); clientStream.Dispose();
if (!cancellationTokenSource.IsCancellationRequested) if (!cancellationTokenSource.IsCancellationRequested)
{ {
......
...@@ -2,5 +2,5 @@ ...@@ -2,5 +2,5 @@
<packages> <packages>
<package id="Portable.BouncyCastle" version="1.8.2" targetFramework="net45" /> <package id="Portable.BouncyCastle" version="1.8.2" targetFramework="net45" />
<package id="StreamExtended" version="1.0.147-beta" targetFramework="net45" /> <package id="StreamExtended" version="1.0.160-beta" targetFramework="net45" />
</packages> </packages>
\ No newline at end of file
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