Unverified Commit d3829eab authored by honfika's avatar honfika Committed by GitHub

Merge pull request #409 from justcoding121/develop

Merge to beta
parents abe87ce7 26d815c3
......@@ -80,8 +80,6 @@ namespace Titanium.Web.Proxy.Examples.Basic
explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000)
{
//You can set only one of the ExcludedHttpsHostNameRegex and IncludedHttpsHostNameRegex properties, otherwise ArgumentException will be thrown
//Use self-issued generic certificate on all https requests
//Optimizes performance by not creating a certificate for each https-enabled domain
//Useful when certificate trust is not required by proxy clients
......@@ -152,7 +150,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
//Exclude Https addresses you don't want to proxy
//Useful for clients that use certificate pinning
//for example dropbox.com
e.Excluded = true;
e.DecryptSsl = false;
}
}
......
......@@ -119,7 +119,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf
string hostname = e.WebSession.Request.RequestUri.Host;
if (hostname.EndsWith("webex.com"))
{
e.Excluded = true;
e.DecryptSsl = false;
}
await Dispatcher.InvokeAsync(() =>
......@@ -128,7 +128,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf
});
}
private async Task ProxyServer_BeforeTunnelConnectResponse(object sender, SessionEventArgs e)
private async Task ProxyServer_BeforeTunnelConnectResponse(object sender, TunnelConnectSessionEventArgs e)
{
await Dispatcher.InvokeAsync(() =>
{
......@@ -191,7 +191,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf
});
}
private SessionListItem AddSession(SessionEventArgs e)
private SessionListItem AddSession(SessionEventArgsBase e)
{
var item = CreateSessionListItem(e);
Sessions.Add(item);
......@@ -199,7 +199,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf
return item;
}
private SessionListItem CreateSessionListItem(SessionEventArgs e)
private SessionListItem CreateSessionListItem(SessionEventArgsBase e)
{
lastSessionNumber++;
bool isTunnelConnect = e is TunnelConnectSessionEventArgs;
......
......@@ -66,8 +66,6 @@ proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection;
var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true)
{
//You can set only one of the ExcludedHttpsHostNameRegex and IncludedHttpsHostNameRegex properties, otherwise ArgumentException will be thrown
//Use self-issued generic certificate on all https requests
//Optimizes performance by not creating a certificate for each https-enabled domain
//Useful when certificate trust is not required by proxy clients
......@@ -135,7 +133,7 @@ private async Task OnBeforeTunnelConnectRequest(object sender, TunnelConnectSess
//Exclude Https addresses you don't want to proxy
//Useful for clients that use certificate pinning
//for example dropbox.com
e.Excluded = true;
e.DecryptSsl = false;
}
}
......@@ -232,7 +230,6 @@ public Task OnCertificateSelection(object sender, CertificateSelectionEventArgs
#### Roadmap
* Support HTTP 2.0
* Support SOCKS protocol
#### Collaborators
......
......@@ -22,35 +22,17 @@ namespace Titanium.Web.Proxy.EventArguments
/// A proxy session ends when client terminates connection to proxy
/// or when server terminates connection from proxy
/// </summary>
public class SessionEventArgs : EventArgs, IDisposable
public class SessionEventArgs : SessionEventArgsBase
{
private static readonly byte[] emptyData = new byte[0];
/// <summary>
/// Size of Buffers used by this object
/// </summary>
private readonly int bufferSize;
private readonly ExceptionHandler exceptionFunc;
/// <summary>
/// Backing field for corresponding public property
/// </summary>
private bool reRequest;
/// <summary>
/// Holds a reference to client
/// </summary>
internal ProxyClient ProxyClient { get; }
private bool hasMulipartEventSubscribers => MultipartRequestPartSent != null;
/// <summary>
/// Returns a unique Id for this request/response session
/// same as RequestId of WebSession
/// </summary>
public Guid Id => WebSession.RequestId;
/// <summary>
/// Should we send the request again
/// </summary>
......@@ -68,42 +50,11 @@ namespace Titanium.Web.Proxy.EventArguments
}
}
/// <summary>
/// Does this session uses SSL
/// </summary>
public bool IsHttps => WebSession.Request.IsHttps;
/// <summary>
/// Client End Point.
/// </summary>
public IPEndPoint ClientEndPoint => (IPEndPoint)ProxyClient.TcpClient.Client.RemoteEndPoint;
/// <summary>
/// A web session corresponding to a single request/response sequence
/// within a proxy connection
/// </summary>
public HttpWebClient WebSession { get; }
/// <summary>
/// Are we using a custom upstream HTTP(S) proxy?
/// </summary>
public ExternalProxy CustomUpStreamProxyUsed { get; internal set; }
public event EventHandler<DataEventArgs> DataSent;
public event EventHandler<DataEventArgs> DataReceived;
/// <summary>
/// Occurs when multipart request part sent.
/// </summary>
public event EventHandler<MultipartRequestPartSentEventArgs> MultipartRequestPartSent;
public ProxyEndPoint LocalEndPoint { get; }
public bool IsTransparent => LocalEndPoint is TransparentProxyEndPoint;
public Exception Exception { get; internal set; }
/// <summary>
/// Constructor to initialize the proxy
/// </summary>
......@@ -113,32 +64,8 @@ namespace Titanium.Web.Proxy.EventArguments
}
protected SessionEventArgs(int bufferSize, ProxyEndPoint endPoint, ExceptionHandler exceptionFunc, Request request)
: base(bufferSize, endPoint, exceptionFunc, request)
{
this.bufferSize = bufferSize;
this.exceptionFunc = exceptionFunc;
ProxyClient = new ProxyClient();
WebSession = new HttpWebClient(bufferSize, request);
LocalEndPoint = endPoint;
WebSession.ProcessId = new Lazy<int>(() =>
{
if (RunTime.IsWindows)
{
var remoteEndPoint = (IPEndPoint)ProxyClient.TcpClient.Client.RemoteEndPoint;
//If client is localhost get the process id
if (NetworkHelper.IsLocalIpAddress(remoteEndPoint.Address))
{
return NetworkHelper.GetProcessIdFromPort(remoteEndPoint.Port, endPoint.IpV6Enabled);
}
//can't access process Id of remote request from remote machine
return -1;
}
throw new PlatformNotSupportedException();
});
}
private CustomBufferedStream GetStream(bool isRequest)
......@@ -188,30 +115,6 @@ namespace Titanium.Web.Proxy.EventArguments
WebSession.Response = new Response();
}
internal void OnDataSent(byte[] buffer, int offset, int count)
{
try
{
DataSent?.Invoke(this, new DataEventArgs(buffer, offset, count));
}
catch (Exception ex)
{
exceptionFunc(new Exception("Exception thrown in user event", ex));
}
}
internal void OnDataReceived(byte[] buffer, int offset, int count)
{
try
{
DataReceived?.Invoke(this, new DataEventArgs(buffer, offset, count));
}
catch (Exception ex)
{
exceptionFunc(new Exception("Exception thrown in user event", ex));
}
}
internal void OnMultipartRequestPartSent(string boundary, HeaderCollection headers)
{
try
......@@ -220,7 +123,7 @@ namespace Titanium.Web.Proxy.EventArguments
}
catch (Exception ex)
{
exceptionFunc(new Exception("Exception thrown in user event", ex));
ExceptionFunc(new Exception("Exception thrown in user event", ex));
}
}
......@@ -257,7 +160,7 @@ namespace Titanium.Web.Proxy.EventArguments
{
using (var bodyStream = new MemoryStream())
{
var writer = new HttpWriter(bodyStream, bufferSize);
var writer = new HttpWriter(bodyStream, BufferSize);
if (isRequest)
{
......@@ -282,7 +185,7 @@ namespace Titanium.Web.Proxy.EventArguments
using (var bodyStream = new MemoryStream())
{
var writer = new HttpWriter(bodyStream, bufferSize);
var writer = new HttpWriter(bodyStream, BufferSize);
await CopyBodyAsync(isRequest, writer, TransformationMode.None, null);
}
}
......@@ -303,8 +206,8 @@ namespace Titanium.Web.Proxy.EventArguments
var reader = GetStreamReader(true);
string boundary = HttpHelper.GetBoundaryFromContentType(request.ContentType);
using (var copyStream = new CopyStream(reader, writer, bufferSize))
using (var copyStreamReader = new CustomBinaryReader(copyStream, bufferSize))
using (var copyStream = new CopyStream(reader, writer, BufferSize))
using (var copyStreamReader = new CustomBinaryReader(copyStream, BufferSize))
{
while (contentLength > copyStream.ReadBytes)
{
......@@ -365,8 +268,8 @@ namespace Titanium.Web.Proxy.EventArguments
try
{
var bufStream = new CustomBufferedStream(s, bufferSize, true);
reader = new CustomBinaryReader(bufStream, bufferSize);
var bufStream = new CustomBufferedStream(s, BufferSize, true);
reader = new CustomBinaryReader(bufStream, BufferSize);
await writer.CopyBodyAsync(reader, false, -1, onCopy);
}
......@@ -388,7 +291,7 @@ namespace Titanium.Web.Proxy.EventArguments
{
int bufferDataLength = 0;
var buffer = BufferPool.GetBuffer(bufferSize);
var buffer = BufferPool.GetBuffer(BufferSize);
try
{
int boundaryLength = boundary.Length + 4;
......@@ -684,16 +587,10 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary>
/// implement any cleanup here
/// </summary>
public void Dispose()
public override void Dispose()
{
CustomUpStreamProxyUsed = null;
DataSent = null;
DataReceived = null;
MultipartRequestPartSent = null;
Exception = null;
WebSession.FinishSession();
base.Dispose();
}
}
}
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Net;
using System.Reflection;
using System.Threading.Tasks;
using StreamExtended.Helpers;
using StreamExtended.Network;
using Titanium.Web.Proxy.Decompression;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Http.Responses;
using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Network;
namespace Titanium.Web.Proxy.EventArguments
{
/// <summary>
/// Holds info related to a single proxy session (single request/response sequence)
/// A proxy session is bounded to a single connection from client
/// A proxy session ends when client terminates connection to proxy
/// or when server terminates connection from proxy
/// </summary>
public class SessionEventArgsBase : EventArgs, IDisposable
{
/// <summary>
/// Size of Buffers used by this object
/// </summary>
protected readonly int BufferSize;
protected readonly ExceptionHandler ExceptionFunc;
/// <summary>
/// Holds a reference to client
/// </summary>
internal ProxyClient ProxyClient { get; }
/// <summary>
/// Returns a unique Id for this request/response session
/// same as RequestId of WebSession
/// </summary>
public Guid Id => WebSession.RequestId;
/// <summary>
/// Does this session uses SSL
/// </summary>
public bool IsHttps => WebSession.Request.IsHttps;
/// <summary>
/// Client End Point.
/// </summary>
public IPEndPoint ClientEndPoint => (IPEndPoint)ProxyClient.TcpClient.Client.RemoteEndPoint;
/// <summary>
/// A web session corresponding to a single request/response sequence
/// within a proxy connection
/// </summary>
public HttpWebClient WebSession { get; }
/// <summary>
/// Are we using a custom upstream HTTP(S) proxy?
/// </summary>
public ExternalProxy CustomUpStreamProxyUsed { get; internal set; }
public event EventHandler<DataEventArgs> DataSent;
public event EventHandler<DataEventArgs> DataReceived;
public ProxyEndPoint LocalEndPoint { get; }
public bool IsTransparent => LocalEndPoint is TransparentProxyEndPoint;
public Exception Exception { get; internal set; }
/// <summary>
/// Constructor to initialize the proxy
/// </summary>
internal SessionEventArgsBase(int bufferSize, ProxyEndPoint endPoint, ExceptionHandler exceptionFunc)
: this(bufferSize, endPoint, exceptionFunc, null)
{
}
protected SessionEventArgsBase(int bufferSize, ProxyEndPoint endPoint, ExceptionHandler exceptionFunc, Request request)
{
this.BufferSize = bufferSize;
this.ExceptionFunc = exceptionFunc;
ProxyClient = new ProxyClient();
WebSession = new HttpWebClient(bufferSize, request);
LocalEndPoint = endPoint;
WebSession.ProcessId = new Lazy<int>(() =>
{
if (RunTime.IsWindows)
{
var remoteEndPoint = (IPEndPoint)ProxyClient.TcpClient.Client.RemoteEndPoint;
//If client is localhost get the process id
if (NetworkHelper.IsLocalIpAddress(remoteEndPoint.Address))
{
return NetworkHelper.GetProcessIdFromPort(remoteEndPoint.Port, endPoint.IpV6Enabled);
}
//can't access process Id of remote request from remote machine
return -1;
}
throw new PlatformNotSupportedException();
});
}
internal void OnDataSent(byte[] buffer, int offset, int count)
{
try
{
DataSent?.Invoke(this, new DataEventArgs(buffer, offset, count));
}
catch (Exception ex)
{
ExceptionFunc(new Exception("Exception thrown in user event", ex));
}
}
internal void OnDataReceived(byte[] buffer, int offset, int count)
{
try
{
DataReceived?.Invoke(this, new DataEventArgs(buffer, offset, count));
}
catch (Exception ex)
{
ExceptionFunc(new Exception("Exception thrown in user event", ex));
}
}
/// <summary>
/// implement any cleanup here
/// </summary>
public virtual void Dispose()
{
CustomUpStreamProxyUsed = null;
DataSent = null;
DataReceived = null;
Exception = null;
WebSession.FinishSession();
}
}
}
......@@ -4,9 +4,11 @@ using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.EventArguments
{
public class TunnelConnectSessionEventArgs : SessionEventArgs
public class TunnelConnectSessionEventArgs : SessionEventArgsBase
{
public bool Excluded { get; set; }
public bool DecryptSsl { get; set; } = true;
public bool BlockConnect { get; set; }
public bool IsHttpsConnect { get; internal set; }
......
......@@ -17,13 +17,13 @@ namespace Titanium.Web.Proxy.Exceptions
/// <param name="session">The <see cref="SessionEventArgs"/> instance containing the event data.</param>
/// <param name="innerException">Inner exception associated to upstream proxy authorization</param>
/// <param name="headers">Http's headers associated</param>
internal ProxyAuthorizationException(string message, SessionEventArgs session, Exception innerException, IEnumerable<HttpHeader> headers) : base(message, innerException)
internal ProxyAuthorizationException(string message, SessionEventArgsBase session, Exception innerException, IEnumerable<HttpHeader> headers) : base(message, innerException)
{
Session = session;
Headers = headers;
}
public SessionEventArgs Session { get; }
public SessionEventArgsBase Session { get; }
/// <summary>
/// Headers associated with the authorization exception
......
......@@ -17,11 +17,6 @@ namespace Titanium.Web.Proxy.Models
internal bool IsSystemHttpsProxy { get; set; }
/// <summary>
/// Enable SSL?
/// </summary>
public bool DecryptSsl { get; }
/// <summary>
/// Generic certificate to use for SSL decryption.
/// </summary>
......@@ -30,7 +25,7 @@ namespace Titanium.Web.Proxy.Models
/// <summary>
/// Intercept tunnel connect request
/// Valid only for explicit endpoints
/// Set the <see cref="TunnelConnectSessionEventArgs.Excluded"/> property to true if this HTTP connect request should'nt be decrypted and instead be relayed
/// Set the <see cref="TunnelConnectSessionEventArgs.DecryptSsl"/> property to false if this HTTP connect request should'nt be decrypted and instead be relayed
/// </summary>
public event AsyncEventHandler<TunnelConnectSessionEventArgs> BeforeTunnelConnectRequest;
......@@ -46,9 +41,8 @@ namespace Titanium.Web.Proxy.Models
/// <param name="ipAddress"></param>
/// <param name="port"></param>
/// <param name="decryptSsl"></param>
public ExplicitProxyEndPoint(IPAddress ipAddress, int port, bool decryptSsl = true) : base(ipAddress, port)
public ExplicitProxyEndPoint(IPAddress ipAddress, int port, bool decryptSsl = true) : base(ipAddress, port, decryptSsl)
{
this.DecryptSsl = decryptSsl;
}
internal async Task InvokeBeforeTunnelConnectRequest(ProxyServer proxyServer, TunnelConnectSessionEventArgs connectArgs, ExceptionHandler exceptionFunc)
......
......@@ -16,13 +16,14 @@ namespace Titanium.Web.Proxy.Models
/// </summary>
/// <param name="ipAddress"></param>
/// <param name="port"></param>
/// <param name="enableSsl"></param>
protected ProxyEndPoint(IPAddress ipAddress, int port)
/// <param name="decryptSsl"></param>
protected ProxyEndPoint(IPAddress ipAddress, int port, bool decryptSsl)
{
IpAddress = ipAddress;
Port = port;
DecryptSsl = decryptSsl;
}
/// <summary>
/// underlying TCP Listener object
/// </summary>
......@@ -38,6 +39,10 @@ namespace Titanium.Web.Proxy.Models
/// </summary>
public int Port { get; internal set; }
/// <summary>
/// Enable SSL?
/// </summary>
public bool DecryptSsl { get; }
/// <summary>
/// Is IPv6 enabled?
......
......@@ -19,8 +19,8 @@ namespace Titanium.Web.Proxy.Models
/// </summary>
/// <param name="ipAddress"></param>
/// <param name="port"></param>
/// <param name="enableSsl"></param>
public TransparentProxyEndPoint(IPAddress ipAddress, int port) : base(ipAddress, port)
/// <param name="decryptSsl"></param>
public TransparentProxyEndPoint(IPAddress ipAddress, int port, bool decryptSsl = true) : base(ipAddress, port, decryptSsl)
{
GenericCertificateName = "localhost";
}
......
......@@ -15,7 +15,7 @@ namespace Titanium.Web.Proxy
{
public partial class ProxyServer
{
private async Task<bool> CheckAuthorization(SessionEventArgs session)
private async Task<bool> CheckAuthorization(SessionEventArgsBase session)
{
if (AuthenticateUserFunc == null)
{
......
......@@ -177,7 +177,7 @@ namespace Titanium.Web.Proxy
/// A callback to provide authentication credentials for up stream proxy this proxy is using for HTTP(S) requests
/// return the ExternalProxy object with valid credentials
/// </summary>
public Func<SessionEventArgs, Task<ExternalProxy>> GetCustomUpStreamProxyFunc { get; set; }
public Func<SessionEventArgsBase, Task<ExternalProxy>> GetCustomUpStreamProxyFunc { get; set; }
/// <summary>
/// Intercept request to server
......@@ -581,7 +581,7 @@ namespace Titanium.Web.Proxy
/// </summary>
/// <param name="sessionEventArgs">The <see cref="SessionEventArgs"/> instance containing the event data.</param>
/// <returns><see cref="ExternalProxy"/> instance containing valid proxy configuration from PAC/WAPD scripts if any exists.</returns>
private Task<ExternalProxy> GetSystemUpStreamProxy(SessionEventArgs sessionEventArgs)
private Task<ExternalProxy> GetSystemUpStreamProxy(SessionEventArgsBase sessionEventArgs)
{
var proxy = systemProxyResolver.GetProxy(sessionEventArgs.WebSession.Request.RequestUri);
return Task.FromResult(proxy);
......
......@@ -79,7 +79,24 @@ namespace Titanium.Web.Proxy
await endPoint.InvokeBeforeTunnelConnectRequest(this, connectArgs, ExceptionFunc);
//filter out excluded host names
bool excluded = !endPoint.DecryptSsl || connectArgs.Excluded;
bool decryptSsl = endPoint.DecryptSsl && connectArgs.DecryptSsl;
if (connectArgs.BlockConnect)
{
if (connectArgs.WebSession.Response.StatusCode == 0)
{
connectArgs.WebSession.Response = new Response
{
HttpVersion = HttpHeader.Version11,
StatusCode = (int)HttpStatusCode.Forbidden,
StatusDescription = "Forbidden",
};
}
//send the response
await clientStreamWriter.WriteResponseAsync(connectArgs.WebSession.Response);
return;
}
if (await CheckAuthorization(connectArgs) == false)
{
......@@ -109,7 +126,7 @@ namespace Titanium.Web.Proxy
await endPoint.InvokeBeforeTunnectConnectResponse(this, connectArgs, ExceptionFunc, isClientHello);
if (!excluded && isClientHello)
if (decryptSsl && isClientHello)
{
connectRequest.RequestUri = new Uri("https://" + httpUrl);
......@@ -143,12 +160,12 @@ namespace Titanium.Web.Proxy
if (await HttpHelper.IsConnectMethod(clientStream) == -1)
{
// It can be for example some Google (Cloude Messaging for Chrome) magic
excluded = true;
decryptSsl = false;
}
}
//Hostname is excluded or it is not an HTTPS connect
if (excluded || !isClientHello)
if (!decryptSsl || !isClientHello)
{
//create new connection
using (var connection = await GetServerConnection(connectArgs, true))
......@@ -237,32 +254,72 @@ namespace Titanium.Web.Proxy
if (isHttps)
{
SslStream sslStream = null;
try
httpsHostName = clientHelloInfo.GetServerName() ?? endPoint.GenericCertificateName;
if (endPoint.DecryptSsl)
{
sslStream = new SslStream(clientStream);
SslStream sslStream = null;
httpsHostName = clientHelloInfo.GetServerName() ?? endPoint.GenericCertificateName;
try
{
sslStream = new SslStream(clientStream);
string certName = HttpHelper.GetWildCardDomainName(httpsHostName);
var certificate = await CertificateManager.CreateCertificateAsync(certName);
string certName = HttpHelper.GetWildCardDomainName(httpsHostName);
var certificate = await CertificateManager.CreateCertificateAsync(certName);
//Successfully managed to authenticate the client using the fake certificate
await sslStream.AuthenticateAsServerAsync(certificate, false, SslProtocols.Tls, false);
//Successfully managed to authenticate the client using the fake certificate
await sslStream.AuthenticateAsServerAsync(certificate, false, SslProtocols.Tls, false);
//HTTPS server created - we can now decrypt the client's traffic
clientStream = new CustomBufferedStream(sslStream, BufferSize);
//HTTPS server created - we can now decrypt the client's traffic
clientStream = new CustomBufferedStream(sslStream, BufferSize);
clientStreamReader.Dispose();
clientStreamReader = new CustomBinaryReader(clientStream, BufferSize);
clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize);
clientStreamReader.Dispose();
clientStreamReader = new CustomBinaryReader(clientStream, BufferSize);
clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize);
}
catch (Exception e)
{
ExceptionFunc(new Exception($"Could'nt authenticate client '{httpsHostName}' with fake certificate.", e));
sslStream?.Dispose();
return;
}
}
catch (Exception e)
else
{
ExceptionFunc(new Exception($"Could'nt authenticate client '{httpsHostName}' with fake certificate.", e));
sslStream?.Dispose();
return;
//create new connection
var connection = new TcpClient(UpStreamEndPoint);
await connection.ConnectAsync(httpsHostName, endPoint.Port);
connection.ReceiveTimeout = ConnectionTimeOutSeconds * 1000;
connection.SendTimeout = ConnectionTimeOutSeconds * 1000;
using (connection)
{
var serverStream = connection.GetStream();
int available = clientStream.Available;
if (available > 0)
{
//send the buffered data
var data = BufferPool.GetBuffer(BufferSize);
try
{
// clientStream.Available sbould be at most BufferSize because it is using the same buffer size
await clientStream.ReadAsync(data, 0, available);
await serverStream.WriteAsync(data, 0, available);
await serverStream.FlushAsync();
}
finally
{
BufferPool.ReturnBuffer(data);
}
}
//var serverHelloInfo = await SslTools.PeekServerHello(serverStream);
await TcpHelper.SendRaw(clientStream, serverStream, BufferSize,
null, null, ExceptionFunc);
}
}
}
......@@ -590,7 +647,7 @@ namespace Titanium.Web.Proxy
/// <param name="args"></param>
/// <param name="isConnect"></param>
/// <returns></returns>
private async Task<TcpConnection> GetServerConnection(SessionEventArgs args, bool isConnect)
private async Task<TcpConnection> GetServerConnection(SessionEventArgsBase args, bool isConnect)
{
ExternalProxy customUpStreamProxy = null;
......
......@@ -14,14 +14,14 @@ namespace Titanium.Web.Proxy
public partial class ProxyServer
{
//possible header names
private static readonly HashSet<string> authHeaderNames = new HashSet<string>
private static readonly HashSet<string> authHeaderNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"WWW-Authenticate".ToLower(),
"WWW-Authenticate",
//IIS 6.0 messed up names below
"WWWAuthenticate".ToLower(),
"NTLMAuthorization".ToLower(),
"NegotiateAuthorization".ToLower(),
"KerberosAuthorization".ToLower()
"WWWAuthenticate",
"NTLMAuthorization",
"NegotiateAuthorization",
"KerberosAuthorization"
};
private static readonly HashSet<string> authSchemes = new HashSet<string>
......@@ -48,8 +48,7 @@ namespace Titanium.Web.Proxy
var response = args.WebSession.Response;
//check in non-unique headers first
var header = response.Headers.NonUniqueHeaders.FirstOrDefault(
x => authHeaderNames.Contains(x.Key.ToLower()));
var header = response.Headers.NonUniqueHeaders.FirstOrDefault(x => authHeaderNames.Contains(x.Key));
if (!header.Equals(new KeyValuePair<string, List<HttpHeader>>()))
{
......@@ -68,7 +67,7 @@ namespace Titanium.Web.Proxy
headerName = null;
//check in non-unique headers first
var uHeader = response.Headers.Headers.FirstOrDefault(x => authHeaderNames.Contains(x.Key.ToLower()));
var uHeader = response.Headers.Headers.FirstOrDefault(x => authHeaderNames.Contains(x.Key));
if (!uHeader.Equals(new KeyValuePair<string, HttpHeader>()))
{
......
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