Commit 2ac7db57 authored by Honfika's avatar Honfika

Stream disposing fix, SslStream should dispose the inner stream (true parameter removed)

parent 02f78387
......@@ -146,14 +146,6 @@ namespace Titanium.Web.Proxy.Helpers
return baseStream.BeginWrite(buffer, offset, count, callback, state);
}
/// <summary>
/// Closes the current stream and releases any resources (such as sockets and file handles) associated with the current stream. Instead of calling this method, ensure that the stream is properly disposed.
/// </summary>
public override void Close()
{
baseStream.Close();
}
/// <summary>
/// Asynchronously reads the bytes from the current stream and writes them to another stream, using a specified buffer size and cancellation token.
/// </summary>
......
......@@ -213,7 +213,7 @@ namespace Titanium.Web.Proxy.Helpers
var tcpConnection = await tcpConnectionFactory.CreateClient(server,
remoteHostName, remotePort,
httpVersion, isHttps,
null, null, clientStream);
null, null);
try
{
......
......@@ -26,7 +26,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// </summary>
internal Version Version { get; set; }
internal TcpClient TcpClient { get; set; }
internal TcpClient TcpClient { private get; set; }
/// <summary>
/// used to read lines from server
......@@ -54,7 +54,6 @@ namespace Titanium.Web.Proxy.Network.Tcp
public void Dispose()
{
Stream?.Close();
Stream?.Dispose();
StreamReader?.Dispose();
......
......@@ -28,17 +28,12 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <param name="isHttps"></param>
/// <param name="externalHttpProxy"></param>
/// <param name="externalHttpsProxy"></param>
/// <param name="clientStream"></param>
/// <returns></returns>
internal async Task<TcpConnection> CreateClient(ProxyServer server,
string remoteHostName, int remotePort, Version httpVersion,
bool isHttps,
ExternalProxy externalHttpProxy, ExternalProxy externalHttpsProxy,
Stream clientStream)
ExternalProxy externalHttpProxy, ExternalProxy externalHttpsProxy)
{
TcpClient client;
CustomBufferedStream stream;
bool useHttpProxy = false;
//check if external proxy is set for HTTP
if (!isHttps && externalHttpProxy != null
......@@ -71,88 +66,86 @@ namespace Titanium.Web.Proxy.Network.Tcp
}
}
if (isHttps)
{
SslStream sslStream = null;
TcpClient client = null;
CustomBufferedStream stream = null;
//If this proxy uses another external proxy then create a tunnel request for HTTPS connections
if (useHttpsProxy)
try
{
if (isHttps)
{
client = new TcpClient(server.UpStreamEndPoint);
await client.ConnectAsync(externalHttpsProxy.HostName, externalHttpsProxy.Port);
stream = new CustomBufferedStream(client.GetStream(), server.BufferSize);
using (var writer = new StreamWriter(stream, Encoding.ASCII, server.BufferSize, true) { NewLine = ProxyConstants.NewLine })
//If this proxy uses another external proxy then create a tunnel request for HTTPS connections
if (useHttpsProxy)
{
await writer.WriteLineAsync($"CONNECT {remoteHostName}:{remotePort} HTTP/{httpVersion}");
await writer.WriteLineAsync($"Host: {remoteHostName}:{remotePort}");
await writer.WriteLineAsync("Connection: Keep-Alive");
client = new TcpClient(server.UpStreamEndPoint);
await client.ConnectAsync(externalHttpsProxy.HostName, externalHttpsProxy.Port);
stream = new CustomBufferedStream(client.GetStream(), server.BufferSize);
if (!string.IsNullOrEmpty(externalHttpsProxy.UserName) && externalHttpsProxy.Password != null)
using (var writer = new StreamWriter(stream, Encoding.ASCII, server.BufferSize, true) { NewLine = ProxyConstants.NewLine })
{
await writer.WriteLineAsync("Proxy-Connection: keep-alive");
await writer.WriteLineAsync("Proxy-Authorization" + ": Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(externalHttpsProxy.UserName + ":" + externalHttpsProxy.Password)));
await writer.WriteLineAsync($"CONNECT {remoteHostName}:{remotePort} HTTP/{httpVersion}");
await writer.WriteLineAsync($"Host: {remoteHostName}:{remotePort}");
await writer.WriteLineAsync("Connection: Keep-Alive");
if (!string.IsNullOrEmpty(externalHttpsProxy.UserName) && externalHttpsProxy.Password != null)
{
await writer.WriteLineAsync("Proxy-Connection: keep-alive");
await writer.WriteLineAsync("Proxy-Authorization" + ": Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(externalHttpsProxy.UserName + ":" + externalHttpsProxy.Password)));
}
await writer.WriteLineAsync();
await writer.FlushAsync();
writer.Close();
}
await writer.WriteLineAsync();
await writer.FlushAsync();
writer.Close();
}
using (var reader = new CustomBinaryReader(stream, server.BufferSize))
{
var result = await reader.ReadLineAsync();
if (!new[] { "200 OK", "connection established" }.Any(s => result.ContainsIgnoreCase(s)))
using (var reader = new CustomBinaryReader(stream, server.BufferSize))
{
throw new Exception("Upstream proxy failed to create a secure tunnel");
}
var result = await reader.ReadLineAsync();
if (!new[] { "200 OK", "connection established" }.Any(s => result.ContainsIgnoreCase(s)))
{
throw new Exception("Upstream proxy failed to create a secure tunnel");
}
await reader.ReadAndIgnoreAllLinesAsync();
await reader.ReadAndIgnoreAllLinesAsync();
}
}
else
{
client = new TcpClient(server.UpStreamEndPoint);
await client.ConnectAsync(remoteHostName, remotePort);
stream = new CustomBufferedStream(client.GetStream(), server.BufferSize);
}
}
else
{
client = new TcpClient(server.UpStreamEndPoint);
await client.ConnectAsync(remoteHostName, remotePort);
stream = new CustomBufferedStream(client.GetStream(), server.BufferSize);
}
try
{
sslStream = new SslStream(stream, true, server.ValidateServerCertificate,
server.SelectClientCertificate);
var sslStream = new SslStream(stream, false, server.ValidateServerCertificate, server.SelectClientCertificate);
stream = new CustomBufferedStream(sslStream, server.BufferSize);
await sslStream.AuthenticateAsClientAsync(remoteHostName, null, server.SupportedSslProtocols, server.CheckCertificateRevocation);
stream = new CustomBufferedStream(sslStream, server.BufferSize);
}
catch
else
{
sslStream?.Close();
sslStream?.Dispose();
throw;
if (useHttpProxy)
{
client = new TcpClient(server.UpStreamEndPoint);
await client.ConnectAsync(externalHttpProxy.HostName, externalHttpProxy.Port);
stream = new CustomBufferedStream(client.GetStream(), server.BufferSize);
}
else
{
client = new TcpClient(server.UpStreamEndPoint);
await client.ConnectAsync(remoteHostName, remotePort);
stream = new CustomBufferedStream(client.GetStream(), server.BufferSize);
}
}
client.ReceiveTimeout = server.ConnectionTimeOutSeconds * 1000;
client.SendTimeout = server.ConnectionTimeOutSeconds * 1000;
}
else
catch (Exception)
{
if (useHttpProxy)
{
client = new TcpClient(server.UpStreamEndPoint);
await client.ConnectAsync(externalHttpProxy.HostName, externalHttpProxy.Port);
stream = new CustomBufferedStream(client.GetStream(), server.BufferSize);
}
else
{
client = new TcpClient(server.UpStreamEndPoint);
await client.ConnectAsync(remoteHostName, remotePort);
stream = new CustomBufferedStream(client.GetStream(), server.BufferSize);
}
stream?.Dispose();
client?.Close();
throw;
}
client.ReceiveTimeout = server.ConnectionTimeOutSeconds * 1000;
client.SendTimeout = server.ConnectionTimeOutSeconds * 1000;
Interlocked.Increment(ref server.serverConnectionCount);
return new TcpConnection
......
......@@ -111,7 +111,7 @@ namespace Titanium.Web.Proxy
try
{
sslStream = new SslStream(clientStream, true);
sslStream = new SslStream(clientStream);
var certificate = endPoint.GenericCertificate ??
CertificateManager.CreateCertificate(httpRemoteUri.Host, false);
......@@ -191,7 +191,7 @@ namespace Titanium.Web.Proxy
{
if (endPoint.EnableSsl)
{
var sslStream = new SslStream(clientStream, true);
var sslStream = new SslStream(clientStream);
clientStream = new CustomBufferedStream(sslStream, BufferSize);
//implement in future once SNI supported by SSL stream, for now use the same certificate
......@@ -542,8 +542,7 @@ namespace Titanium.Web.Proxy
args.WebSession.Request.HttpVersion,
args.IsHttps,
customUpStreamHttpProxy ?? UpStreamHttpProxy,
customUpStreamHttpsProxy ?? UpStreamHttpsProxy,
args.ProxyClient.ClientStream);
customUpStreamHttpsProxy ?? UpStreamHttpsProxy);
}
......
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