Commit 9efe4886 authored by Honfika's avatar Honfika

- Detect HTTPS ClientHello

- Using upstream proxy when host is excluded, too (earlier upstream proxy was ignored in this case which is wrong)
parent cfccb651
...@@ -16,8 +16,7 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -16,8 +16,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
//share requestBody outside handlers //share requestBody outside handlers
//Using a dictionary is not a good idea since it can cause memory overflow //Using a dictionary is not a good idea since it can cause memory overflow
//ideally the data should be moved out of memory //ideally the data should be moved out of memory
//private readonly IDictionary<Guid, string> requestBodyHistory //private readonly IDictionary<Guid, string> requestBodyHistory = new ConcurrentDictionary<Guid, string>();
// = new ConcurrentDictionary<Guid, string>();
public ProxyTestController() public ProxyTestController()
{ {
...@@ -57,11 +56,14 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -57,11 +56,14 @@ namespace Titanium.Web.Proxy.Examples.Basic
ExcludedHttpsHostNameRegex = new List<string> ExcludedHttpsHostNameRegex = new List<string>
{ {
"dropbox.com" "dropbox.com"
} },
//Include Https addresses you want to proxy (others will be excluded) //Include Https addresses you want to proxy (others will be excluded)
//for example github.com //for example github.com
//IncludedHttpsHostNameRegex = new List<string> { "github.com" } //IncludedHttpsHostNameRegex = new List<string>
//{
// "github.com"
//},
//You can set only one of the ExcludedHttpsHostNameRegex and IncludedHttpsHostNameRegex properties, otherwise ArgumentException will be thrown //You can set only one of the ExcludedHttpsHostNameRegex and IncludedHttpsHostNameRegex properties, otherwise ArgumentException will be thrown
......
...@@ -306,6 +306,21 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -306,6 +306,21 @@ namespace Titanium.Web.Proxy.Helpers
return streamBuffer[bufferPos++]; return streamBuffer[bufferPos++];
} }
public async Task<int> PeekByteAsync(int index)
{
if (Available <= index)
{
await FillBufferAsync();
}
if (Available <= index)
{
return -1;
}
return streamBuffer[bufferPos + index];
}
public byte ReadByteFromBuffer() public byte ReadByteFromBuffer()
{ {
if (bufferLength == 0) if (bufferLength == 0)
...@@ -396,6 +411,8 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -396,6 +411,8 @@ namespace Titanium.Web.Proxy.Helpers
public bool DataAvailable => bufferLength > 0; public bool DataAvailable => bufferLength > 0;
public int Available => bufferLength;
/// <summary> /// <summary>
/// When overridden in a derived class, gets or sets the position within the current stream. /// When overridden in a derived class, gets or sets the position within the current stream.
/// </summary> /// </summary>
...@@ -428,14 +445,22 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -428,14 +445,22 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary> /// </summary>
public bool FillBuffer() public bool FillBuffer()
{ {
bufferLength = baseStream.Read(streamBuffer, 0, streamBuffer.Length);
bufferPos = 0;
if (bufferLength > 0) if (bufferLength > 0)
{ {
OnDataReceived(streamBuffer, 0, bufferLength); //normally we fill the buffer only when it is empty, but sometimes we need more data
//move the remanining data to the beginning of the buffer
Buffer.BlockCopy(streamBuffer, bufferPos, streamBuffer, 0, bufferLength);
}
bufferPos = 0;
int readBytes = baseStream.Read(streamBuffer, bufferLength, streamBuffer.Length - bufferLength);
if (readBytes > 0)
{
OnDataReceived(streamBuffer, bufferLength, readBytes);
bufferLength += readBytes;
} }
return bufferLength > 0; return readBytes > 0;
} }
/// <summary> /// <summary>
...@@ -454,14 +479,22 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -454,14 +479,22 @@ namespace Titanium.Web.Proxy.Helpers
/// <returns></returns> /// <returns></returns>
public async Task<bool> FillBufferAsync(CancellationToken cancellationToken) public async Task<bool> FillBufferAsync(CancellationToken cancellationToken)
{ {
bufferLength = await baseStream.ReadAsync(streamBuffer, 0, streamBuffer.Length, cancellationToken);
bufferPos = 0;
if (bufferLength > 0) if (bufferLength > 0)
{ {
OnDataReceived(streamBuffer, 0, bufferLength); //normally we fill the buffer only when it is empty, but sometimes we need more data
//move the remanining data to the beginning of the buffer
Buffer.BlockCopy(streamBuffer, bufferPos, streamBuffer, 0, bufferLength);
}
bufferPos = 0;
int readBytes = await baseStream.ReadAsync(streamBuffer, bufferLength, streamBuffer.Length - bufferLength, cancellationToken);
if (readBytes > 0)
{
OnDataReceived(streamBuffer, bufferLength, readBytes);
bufferLength += readBytes;
} }
return bufferLength > 0; return readBytes > 0;
} }
private class ReadAsyncResult : IAsyncResult private class ReadAsyncResult : IAsyncResult
......
...@@ -170,20 +170,12 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -170,20 +170,12 @@ namespace Titanium.Web.Proxy.Helpers
/// relays the input clientStream to the server at the specified host name and port with the given httpCmd and headers as prefix /// relays the input clientStream to the server at the specified host name and port with the given httpCmd and headers as prefix
/// Usefull for websocket requests /// Usefull for websocket requests
/// </summary> /// </summary>
/// <param name="server"></param>
/// <param name="remoteHostName"></param>
/// <param name="remotePort"></param>
/// <param name="httpCmd"></param> /// <param name="httpCmd"></param>
/// <param name="httpVersion"></param>
/// <param name="requestHeaders"></param> /// <param name="requestHeaders"></param>
/// <param name="isHttps"></param>
/// <param name="clientStream"></param> /// <param name="clientStream"></param>
/// <param name="tcpConnectionFactory"></param>
/// <param name="connection"></param> /// <param name="connection"></param>
/// <returns></returns> /// <returns></returns>
internal static async Task SendRaw(ProxyServer server, string remoteHostName, int remotePort, string httpCmd, Version httpVersion, internal static async Task SendRaw(string httpCmd, IEnumerable<HttpHeader> requestHeaders, Stream clientStream, TcpConnection connection)
Dictionary<string, HttpHeader> requestHeaders, bool isHttps, Stream clientStream, TcpConnectionFactory tcpConnectionFactory,
TcpConnection connection = null)
{ {
//prepare the prefix content //prepare the prefix content
StringBuilder sb = null; StringBuilder sb = null;
...@@ -199,7 +191,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -199,7 +191,7 @@ namespace Titanium.Web.Proxy.Helpers
if (requestHeaders != null) if (requestHeaders != null)
{ {
foreach (string header in requestHeaders.Select(t => t.Value.ToString())) foreach (string header in requestHeaders.Select(t => t.ToString()))
{ {
sb.Append(header); sb.Append(header);
sb.Append(ProxyConstants.NewLine); sb.Append(ProxyConstants.NewLine);
...@@ -209,24 +201,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -209,24 +201,7 @@ namespace Titanium.Web.Proxy.Helpers
sb.Append(ProxyConstants.NewLine); sb.Append(ProxyConstants.NewLine);
} }
bool connectionCreated = false; var tunnelStream = connection.Stream;
TcpConnection tcpConnection;
//create new connection if connection is null
if (connection == null)
{
tcpConnection = await tcpConnectionFactory.CreateClient(server, remoteHostName, remotePort, httpVersion, isHttps, null, null);
connectionCreated = true;
}
else
{
tcpConnection = connection;
}
try
{
var tunnelStream = tcpConnection.Stream;
//Now async relay all server=>client & client=>server data //Now async relay all server=>client & client=>server data
var sendRelay = clientStream.CopyToAsync(sb?.ToString() ?? string.Empty, tunnelStream); var sendRelay = clientStream.CopyToAsync(sb?.ToString() ?? string.Empty, tunnelStream);
...@@ -235,17 +210,5 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -235,17 +210,5 @@ namespace Titanium.Web.Proxy.Helpers
await Task.WhenAll(sendRelay, receiveRelay); await Task.WhenAll(sendRelay, receiveRelay);
} }
finally
{
//if connection was null
//then a new connection was created
//so dispose the new connection
if (connectionCreated)
{
tcpConnection.Dispose();
Interlocked.Decrement(ref server.serverConnectionCount);
}
}
}
} }
} }
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Titanium.Web.Proxy.Helpers;
namespace Titanium.Web.Proxy.Http
{
class HttpsTools
{
public static async Task<bool> IsClientHello(CustomBufferedStream clientStream)
{
//detects the HTTPS ClientHello message as it is described in the following url:
//https://stackoverflow.com/questions/3897883/how-to-detect-an-incoming-ssl-https-handshake-ssl-wire-format
int recordType = await clientStream.PeekByteAsync(0);
if (recordType == 0x80)
{
//SSL 2
int length = await clientStream.PeekByteAsync(1);
if (length < 9)
{
// Message body too short.
return false;
}
if (await clientStream.PeekByteAsync(2) != 0x01)
{
// should be ClientHello
return false;
}
int majorVersion = await clientStream.PeekByteAsync(3);
int minorVersion = await clientStream.PeekByteAsync(4);
return true;
}
else if (recordType == 0x16)
{
//SSL 3.0 or TLS 1.0, 1.1 and 1.2
int majorVersion = await clientStream.PeekByteAsync(1);
int minorVersion = await clientStream.PeekByteAsync(2);
int length1 = await clientStream.PeekByteAsync(3);
int length2 = await clientStream.PeekByteAsync(4);
int length = (length1 << 8) + length2;
if (await clientStream.PeekByteAsync(5) != 0x01)
{
// should be ClientHello
return false;
}
return true;
}
return false;
}
}
}
...@@ -53,6 +53,7 @@ namespace Titanium.Web.Proxy.Models ...@@ -53,6 +53,7 @@ namespace Titanium.Web.Proxy.Models
public bool IpV6Enabled => Equals(IpAddress, IPAddress.IPv6Any) public bool IpV6Enabled => Equals(IpAddress, IPAddress.IPv6Any)
|| Equals(IpAddress, IPAddress.IPv6Loopback) || Equals(IpAddress, IPAddress.IPv6Loopback)
|| Equals(IpAddress, IPAddress.IPv6None); || Equals(IpAddress, IPAddress.IPv6None);
} }
/// <summary> /// <summary>
...@@ -68,12 +69,6 @@ namespace Titanium.Web.Proxy.Models ...@@ -68,12 +69,6 @@ namespace Titanium.Web.Proxy.Models
internal bool IsSystemHttpsProxy { get; set; } internal bool IsSystemHttpsProxy { get; set; }
/// <summary>
/// Remote HTTPS ports we are allowed to communicate with
/// CONNECT request to ports other than these will not be decrypted
/// </summary>
public List<int> RemoteHttpsPorts { get; set; }
/// <summary> /// <summary>
/// List of host names to exclude using Regular Expressions. /// List of host names to exclude using Regular Expressions.
/// </summary> /// </summary>
...@@ -121,12 +116,6 @@ namespace Titanium.Web.Proxy.Models ...@@ -121,12 +116,6 @@ namespace Titanium.Web.Proxy.Models
/// <param name="enableSsl"></param> /// <param name="enableSsl"></param>
public ExplicitProxyEndPoint(IPAddress ipAddress, int port, bool enableSsl) : base(ipAddress, port, enableSsl) public ExplicitProxyEndPoint(IPAddress ipAddress, int port, bool enableSsl) : base(ipAddress, port, enableSsl)
{ {
//init to well known HTTPS ports
RemoteHttpsPorts = new List<int>
{
443,
8443
};
} }
} }
......
...@@ -15,12 +15,16 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -15,12 +15,16 @@ namespace Titanium.Web.Proxy.Network.Tcp
internal ExternalProxy UpStreamHttpsProxy { get; set; } internal ExternalProxy UpStreamHttpsProxy { get; set; }
internal ExternalProxy UpStreamProxy => UseProxy ? IsHttps ? UpStreamHttpsProxy : UpStreamHttpProxy : null;
internal string HostName { get; set; } internal string HostName { get; set; }
internal int Port { get; set; } internal int Port { get; set; }
internal bool IsHttps { get; set; } internal bool IsHttps { get; set; }
internal bool UseProxy { get; set; }
/// <summary> /// <summary>
/// Http version /// Http version
/// </summary> /// </summary>
......
...@@ -32,29 +32,18 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -32,29 +32,18 @@ namespace Titanium.Web.Proxy.Network.Tcp
internal async Task<TcpConnection> CreateClient(ProxyServer server, string remoteHostName, int remotePort, Version httpVersion, bool isHttps, internal async Task<TcpConnection> CreateClient(ProxyServer server, string remoteHostName, int remotePort, Version httpVersion, bool isHttps,
ExternalProxy externalHttpProxy, ExternalProxy externalHttpsProxy) ExternalProxy externalHttpProxy, ExternalProxy externalHttpsProxy)
{ {
bool useHttpProxy = false; bool useProxy = false;
//check if external proxy is set for HTTP var externalProxy = isHttps ? externalHttpsProxy : externalHttpProxy;
if (!isHttps && externalHttpProxy != null && !(externalHttpProxy.HostName == remoteHostName && externalHttpProxy.Port == remotePort))
{
useHttpProxy = true;
//check if we need to ByPass
if (externalHttpProxy.BypassLocalhost && NetworkHelper.IsLocalIpAddress(remoteHostName))
{
useHttpProxy = false;
}
}
bool useHttpsProxy = false; //check if external proxy is set for HTTP/HTTPS
//check if external proxy is set for HTTPS if (externalProxy != null && !(externalProxy.HostName == remoteHostName && externalProxy.Port == remotePort))
if (isHttps && externalHttpsProxy != null && !(externalHttpsProxy.HostName == remoteHostName && externalHttpsProxy.Port == remotePort))
{ {
useHttpsProxy = true; useProxy = true;
//check if we need to ByPass //check if we need to ByPass
if (externalHttpsProxy.BypassLocalhost && NetworkHelper.IsLocalIpAddress(remoteHostName)) if (externalProxy.BypassLocalhost && NetworkHelper.IsLocalIpAddress(remoteHostName))
{ {
useHttpsProxy = false; useProxy = false;
} }
} }
...@@ -63,13 +52,11 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -63,13 +52,11 @@ namespace Titanium.Web.Proxy.Network.Tcp
try try
{ {
if (isHttps) //If this proxy uses another external proxy then create a tunnel request for HTTP/HTTPS connections
{ if (useProxy)
//If this proxy uses another external proxy then create a tunnel request for HTTPS connections
if (useHttpsProxy)
{ {
client = new TcpClient(server.UpStreamEndPoint); client = new TcpClient(server.UpStreamEndPoint);
await client.ConnectAsync(externalHttpsProxy.HostName, externalHttpsProxy.Port); await client.ConnectAsync(externalProxy.HostName, externalProxy.Port);
stream = new CustomBufferedStream(client.GetStream(), server.BufferSize); stream = new CustomBufferedStream(client.GetStream(), server.BufferSize);
using (var writer = new StreamWriter(stream, Encoding.ASCII, server.BufferSize, true) using (var writer = new StreamWriter(stream, Encoding.ASCII, server.BufferSize, true)
...@@ -81,12 +68,12 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -81,12 +68,12 @@ namespace Titanium.Web.Proxy.Network.Tcp
await writer.WriteLineAsync($"Host: {remoteHostName}:{remotePort}"); await writer.WriteLineAsync($"Host: {remoteHostName}:{remotePort}");
await writer.WriteLineAsync("Connection: Keep-Alive"); await writer.WriteLineAsync("Connection: Keep-Alive");
if (!string.IsNullOrEmpty(externalHttpsProxy.UserName) && externalHttpsProxy.Password != null) if (!string.IsNullOrEmpty(externalProxy.UserName) && externalProxy.Password != null)
{ {
await writer.WriteLineAsync("Proxy-Connection: keep-alive"); await writer.WriteLineAsync("Proxy-Connection: keep-alive");
await writer.WriteLineAsync("Proxy-Authorization" + ": Basic " + await writer.WriteLineAsync("Proxy-Authorization" + ": Basic " +
Convert.ToBase64String(Encoding.UTF8.GetBytes( Convert.ToBase64String(Encoding.UTF8.GetBytes(
externalHttpsProxy.UserName + ":" + externalHttpsProxy.Password))); externalProxy.UserName + ":" + externalProxy.Password)));
} }
await writer.WriteLineAsync(); await writer.WriteLineAsync();
await writer.FlushAsync(); await writer.FlushAsync();
...@@ -112,26 +99,13 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -112,26 +99,13 @@ namespace Titanium.Web.Proxy.Network.Tcp
stream = new CustomBufferedStream(client.GetStream(), server.BufferSize); stream = new CustomBufferedStream(client.GetStream(), server.BufferSize);
} }
if (isHttps)
{
var sslStream = new SslStream(stream, false, server.ValidateServerCertificate, server.SelectClientCertificate); var sslStream = new SslStream(stream, false, server.ValidateServerCertificate, server.SelectClientCertificate);
stream = new CustomBufferedStream(sslStream, server.BufferSize); stream = new CustomBufferedStream(sslStream, server.BufferSize);
await sslStream.AuthenticateAsClientAsync(remoteHostName, null, server.SupportedSslProtocols, server.CheckCertificateRevocation); await sslStream.AuthenticateAsClientAsync(remoteHostName, null, server.SupportedSslProtocols, server.CheckCertificateRevocation);
} }
else
{
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.ReceiveTimeout = server.ConnectionTimeOutSeconds * 1000;
client.SendTimeout = server.ConnectionTimeOutSeconds * 1000; client.SendTimeout = server.ConnectionTimeOutSeconds * 1000;
...@@ -152,6 +126,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -152,6 +126,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
HostName = remoteHostName, HostName = remoteHostName,
Port = remotePort, Port = remotePort,
IsHttps = isHttps, IsHttps = isHttps,
UseProxy = useProxy,
TcpClient = client, TcpClient = client,
StreamReader = new CustomBinaryReader(stream, server.BufferSize), StreamReader = new CustomBinaryReader(stream, server.BufferSize),
Stream = stream, Stream = stream,
......
...@@ -90,10 +90,9 @@ namespace Titanium.Web.Proxy ...@@ -90,10 +90,9 @@ namespace Titanium.Web.Proxy
List<HttpHeader> connectRequestHeaders = null; List<HttpHeader> connectRequestHeaders = null;
//Client wants to create a secure tcp tunnel (its a HTTPS request) //Client wants to create a secure tcp tunnel (probably its a HTTPS or Websocket request)
if (httpVerb == "CONNECT" && !excluded && endPoint.RemoteHttpsPorts.Contains(httpRemoteUri.Port)) if (httpVerb == "CONNECT")
{ {
httpRemoteUri = new Uri("https://" + httpCmdSplit[1]);
connectRequestHeaders = new List<HttpHeader>(); connectRequestHeaders = new List<HttpHeader>();
string tmpLine; string tmpLine;
while (!string.IsNullOrEmpty(tmpLine = await clientStreamReader.ReadLineAsync())) while (!string.IsNullOrEmpty(tmpLine = await clientStreamReader.ReadLineAsync()))
...@@ -104,13 +103,32 @@ namespace Titanium.Web.Proxy ...@@ -104,13 +103,32 @@ namespace Titanium.Web.Proxy
connectRequestHeaders.Add(newHeader); connectRequestHeaders.Add(newHeader);
} }
if (httpRemoteUri.Port == 80)
{
// why is this needed? HTTPS not allowed on port 80?
excluded = true;
}
if (!excluded)
{
if (await CheckAuthorization(clientStreamWriter, connectRequestHeaders) == false) if (await CheckAuthorization(clientStreamWriter, connectRequestHeaders) == false)
{ {
return; return;
} }
httpRemoteUri = new Uri("https://" + httpCmdSplit[1]);
}
//write back successfull CONNECT response
await WriteConnectResponse(clientStreamWriter, version); await WriteConnectResponse(clientStreamWriter, version);
if (!excluded && !await HttpsTools.IsClientHello(clientStream))
{
excluded = true;
}
if (!excluded)
{
SslStream sslStream = null; SslStream sslStream = null;
try try
...@@ -144,22 +162,32 @@ namespace Titanium.Web.Proxy ...@@ -144,22 +162,32 @@ namespace Titanium.Web.Proxy
httpCmd = await clientStreamReader.ReadLineAsync(); httpCmd = await clientStreamReader.ReadLineAsync();
} }
//Sorry cannot do a HTTPS request decrypt to port 80 at this time //Sorry cannot do a HTTPS request decrypt to port 80 at this time
else if (httpVerb == "CONNECT") else
{ {
//Siphon out CONNECT request headers var args = new SessionEventArgs(BufferSize, HandleHttpSessionResponse);
await clientStreamReader.ReadAndIgnoreAllLinesAsync(); args.WebSession.Request.RequestUri = httpRemoteUri;
args.WebSession.Request.HttpVersion = version;
//write back successfull CONNECT response args.WebSession.Request.Method = httpVerb;
await WriteConnectResponse(clientStreamWriter, version); args.ProxyClient.ClientStream = clientStream;
args.ProxyClient.ClientStreamReader = clientStreamReader;
args.ProxyClient.ClientStreamWriter = clientStreamWriter;
await TcpHelper.SendRaw(this, //create new connection
httpRemoteUri.Host, httpRemoteUri.Port, using (var connection = await GetServerConnection(args))
null, version, null, {
false, if (connection.UseProxy)
clientStream, tcpConnectionFactory); {
await TcpHelper.SendRaw(null, null, clientStream, connection);
}
else
{
await TcpHelper.SendRaw(null, null, clientStream, connection);
}
}
return; return;
} }
}
//Now create the request //Now create the request
disposed = await HandleHttpSessionRequest(tcpClient, httpCmd, clientStream, clientStreamReader, clientStreamWriter, disposed = await HandleHttpSessionRequest(tcpClient, httpCmd, clientStream, clientStreamReader, clientStreamWriter,
...@@ -287,7 +315,7 @@ namespace Titanium.Web.Proxy ...@@ -287,7 +315,7 @@ namespace Titanium.Web.Proxy
//break up the line into three components (method, remote URL & Http Version) //break up the line into three components (method, remote URL & Http Version)
var httpCmdSplit = httpCmd.Split(ProxyConstants.SpaceSplit, 3); var httpCmdSplit = httpCmd.Split(ProxyConstants.SpaceSplit, 3);
string httpMethod = httpCmdSplit[0]; string httpMethod = httpCmdSplit[0].ToUpper();
//find the request HTTP version //find the request HTTP version
var httpVersion = HttpHeader.Version11; var httpVersion = HttpHeader.Version11;
...@@ -310,7 +338,7 @@ namespace Titanium.Web.Proxy ...@@ -310,7 +338,7 @@ namespace Titanium.Web.Proxy
args.WebSession.Request.RequestUri = httpRemoteUri; args.WebSession.Request.RequestUri = httpRemoteUri;
args.WebSession.Request.Method = httpMethod.Trim().ToUpper(); args.WebSession.Request.Method = httpMethod;
args.WebSession.Request.HttpVersion = httpVersion; args.WebSession.Request.HttpVersion = httpVersion;
args.ProxyClient.ClientStream = clientStream; args.ProxyClient.ClientStream = clientStream;
args.ProxyClient.ClientStreamReader = clientStreamReader; args.ProxyClient.ClientStreamReader = clientStreamReader;
...@@ -346,16 +374,6 @@ namespace Titanium.Web.Proxy ...@@ -346,16 +374,6 @@ namespace Titanium.Web.Proxy
break; break;
} }
//if upgrading to websocket then relay the requet without reading the contents
if (args.WebSession.Request.UpgradeToWebSocket)
{
await TcpHelper.SendRaw(this, httpRemoteUri.Host, httpRemoteUri.Port, httpCmd, httpVersion, args.WebSession.Request.RequestHeaders,
args.IsHttps, clientStream, tcpConnectionFactory, connection);
args.Dispose();
break;
}
if (connection == null) if (connection == null)
{ {
connection = await GetServerConnection(args); connection = await GetServerConnection(args);
...@@ -368,6 +386,15 @@ namespace Titanium.Web.Proxy ...@@ -368,6 +386,15 @@ namespace Titanium.Web.Proxy
connection = await GetServerConnection(args); connection = await GetServerConnection(args);
} }
//if upgrading to websocket then relay the requet without reading the contents
if (args.WebSession.Request.UpgradeToWebSocket)
{
await TcpHelper.SendRaw(httpCmd, args.WebSession.Request.RequestHeaders.Values, clientStream, connection);
args.Dispose();
break;
}
//construct the web request that we are going to issue on behalf of the client. //construct the web request that we are going to issue on behalf of the client.
disposed = await HandleHttpSessionRequestInternal(connection, args, false); disposed = await HandleHttpSessionRequestInternal(connection, args, false);
......
...@@ -86,6 +86,7 @@ ...@@ -86,6 +86,7 @@
<Compile Include="Helpers\WinHttp\WinHttpHandle.cs" /> <Compile Include="Helpers\WinHttp\WinHttpHandle.cs" />
<Compile Include="Helpers\WinHttp\WinHttpWebProxyFinder.cs" /> <Compile Include="Helpers\WinHttp\WinHttpWebProxyFinder.cs" />
<Compile Include="Http\HeaderParser.cs" /> <Compile Include="Http\HeaderParser.cs" />
<Compile Include="Http\HttpsTools.cs" />
<Compile Include="Http\Responses\GenericResponse.cs" /> <Compile Include="Http\Responses\GenericResponse.cs" />
<Compile Include="Network\CachedCertificate.cs" /> <Compile Include="Network\CachedCertificate.cs" />
<Compile Include="Network\Certificate\WinCertificateMaker.cs" /> <Compile Include="Network\Certificate\WinCertificateMaker.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