Commit ea86d5a7 authored by Honfika's avatar Honfika

TunnelConnect event added to ProxyServer

common HeaderCollection class added and used in Request and Resposne classes
parent f6a32641
...@@ -43,6 +43,8 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -43,6 +43,8 @@ namespace Titanium.Web.Proxy.Examples.Basic
{ {
proxyServer.BeforeRequest += OnRequest; proxyServer.BeforeRequest += OnRequest;
proxyServer.BeforeResponse += OnResponse; proxyServer.BeforeResponse += OnResponse;
proxyServer.TunnelConnectRequest += OnTunnelConnectRequest;
proxyServer.TunnelConnectResponse += OnTunnelConnectResponse;
proxyServer.ServerCertificateValidationCallback += OnCertificateValidation; proxyServer.ServerCertificateValidationCallback += OnCertificateValidation;
proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection; proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection;
...@@ -105,6 +107,8 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -105,6 +107,8 @@ namespace Titanium.Web.Proxy.Examples.Basic
public void Stop() public void Stop()
{ {
proxyServer.TunnelConnectRequest -= OnTunnelConnectRequest;
proxyServer.TunnelConnectResponse -= OnTunnelConnectResponse;
proxyServer.BeforeRequest -= OnRequest; proxyServer.BeforeRequest -= OnRequest;
proxyServer.BeforeResponse -= OnResponse; proxyServer.BeforeResponse -= OnResponse;
proxyServer.ServerCertificateValidationCallback -= OnCertificateValidation; proxyServer.ServerCertificateValidationCallback -= OnCertificateValidation;
...@@ -116,6 +120,15 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -116,6 +120,15 @@ namespace Titanium.Web.Proxy.Examples.Basic
//proxyServer.CertificateManager.RemoveTrustedRootCertificates(); //proxyServer.CertificateManager.RemoveTrustedRootCertificates();
} }
private async Task OnTunnelConnectRequest(object sender, TunnelConnectEventArgs e)
{
Console.WriteLine("Tunnel to: " + e.ConnectRequest.Host);
}
private async Task OnTunnelConnectResponse(object sender, TunnelConnectEventArgs e)
{
}
//intecept & cancel redirect or update requests //intecept & cancel redirect or update requests
public async Task OnRequest(object sender, SessionEventArgs e) public async Task OnRequest(object sender, SessionEventArgs e)
{ {
......
...@@ -434,7 +434,10 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -434,7 +434,10 @@ namespace Titanium.Web.Proxy.EventArguments
if (headers != null && headers.Count > 0) if (headers != null && headers.Count > 0)
{ {
response.ResponseHeaders = headers; foreach (var header in headers)
{
response.ResponseHeaders.AddHeader(header.Key, header.Value.Value);
}
} }
response.HttpVersion = WebSession.Request.HttpVersion; response.HttpVersion = WebSession.Request.HttpVersion;
...@@ -501,7 +504,10 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -501,7 +504,10 @@ namespace Titanium.Web.Proxy.EventArguments
if (headers != null && headers.Count > 0) if (headers != null && headers.Count > 0)
{ {
response.ResponseHeaders = headers; foreach (var header in headers)
{
response.ResponseHeaders.AddHeader(header.Key, header.Value.Value);
}
} }
response.HttpVersion = WebSession.Request.HttpVersion; response.HttpVersion = WebSession.Request.HttpVersion;
...@@ -523,7 +529,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -523,7 +529,7 @@ namespace Titanium.Web.Proxy.EventArguments
var response = new RedirectResponse(); var response = new RedirectResponse();
response.HttpVersion = WebSession.Request.HttpVersion; response.HttpVersion = WebSession.Request.HttpVersion;
response.ResponseHeaders.Add("Location", new HttpHeader("Location", url)); response.ResponseHeaders.AddHeader("Location", url);
response.ResponseBody = Encoding.ASCII.GetBytes(string.Empty); response.ResponseBody = Encoding.ASCII.GetBytes(string.Empty);
await Respond(response); await Respond(response);
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Titanium.Web.Proxy.Http;
namespace Titanium.Web.Proxy.EventArguments
{
public class TunnelConnectEventArgs : EventArgs
{
public bool IsHttps { get; set; }
public Request ConnectRequest { get; set; }
public Request ConnectResponse { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Http
{
public class ConnectRequest : Request
{
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Http
{
public class ConnectResponse : Response
{
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.Http
{
public class HeaderCollection : IEnumerable<HttpHeader>
{
/// <summary>
/// Unique Request header collection
/// </summary>
public Dictionary<string, HttpHeader> Headers { get; set; }
/// <summary>
/// Non Unique headers
/// </summary>
public Dictionary<string, List<HttpHeader>> NonUniqueHeaders { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="HeaderCollection"/> class.
/// </summary>
public HeaderCollection()
{
Headers = new Dictionary<string, HttpHeader>(StringComparer.OrdinalIgnoreCase);
NonUniqueHeaders = new Dictionary<string, List<HttpHeader>>(StringComparer.OrdinalIgnoreCase);
}
/// <summary>
/// True if header exists
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public bool HeaderExists(string name)
{
return Headers.ContainsKey(name) || NonUniqueHeaders.ContainsKey(name);
}
/// <summary>
/// Returns all headers with given name if exists
/// Returns null if does'nt exist
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public List<HttpHeader> GetHeaders(string name)
{
if (Headers.ContainsKey(name))
{
return new List<HttpHeader>
{
Headers[name]
};
}
if (NonUniqueHeaders.ContainsKey(name))
{
return new List<HttpHeader>(NonUniqueHeaders[name]);
}
return null;
}
/// <summary>
/// Returns all headers
/// </summary>
/// <returns></returns>
public List<HttpHeader> GetAllHeaders()
{
var result = new List<HttpHeader>();
result.AddRange(Headers.Select(x => x.Value));
result.AddRange(NonUniqueHeaders.SelectMany(x => x.Value));
return result;
}
/// <summary>
/// Add a new header with given name and value
/// </summary>
/// <param name="name"></param>
/// <param name="value"></param>
public void AddHeader(string name, string value)
{
AddHeader(new HttpHeader(name, value));
}
/// <summary>
/// Adds the given header object to Request
/// </summary>
/// <param name="newHeader"></param>
public void AddHeader(HttpHeader newHeader)
{
if (NonUniqueHeaders.ContainsKey(newHeader.Name))
{
NonUniqueHeaders[newHeader.Name].Add(newHeader);
return;
}
if (Headers.ContainsKey(newHeader.Name))
{
var existing = Headers[newHeader.Name];
Headers.Remove(newHeader.Name);
NonUniqueHeaders.Add(newHeader.Name, new List<HttpHeader>
{
existing,
newHeader
});
}
else
{
Headers.Add(newHeader.Name, newHeader);
}
}
/// <summary>
/// removes all headers with given name
/// </summary>
/// <param name="headerName"></param>
/// <returns>True if header was removed
/// False if no header exists with given name</returns>
public bool RemoveHeader(string headerName)
{
bool result = Headers.Remove(headerName);
// do not convert to '||' expression to avoid lazy evaluation
if (NonUniqueHeaders.Remove(headerName))
{
result = true;
}
return result;
}
/// <summary>
/// Removes given header object if it exist
/// </summary>
/// <param name="header">Returns true if header exists and was removed </param>
public bool RemoveHeader(HttpHeader header)
{
if (Headers.ContainsKey(header.Name))
{
if (Headers[header.Name].Equals(header))
{
Headers.Remove(header.Name);
return true;
}
}
else if (NonUniqueHeaders.ContainsKey(header.Name))
{
if (NonUniqueHeaders[header.Name].RemoveAll(x => x.Equals(header)) > 0)
{
return true;
}
}
return false;
}
internal string GetHeaderValueOrNull(string headerName)
{
HttpHeader header;
if (Headers.TryGetValue(headerName, out header))
{
return header.Value;
}
return null;
}
internal string SetOrAddHeaderValue(string headerName, string value)
{
HttpHeader header;
if (Headers.TryGetValue(headerName, out header))
{
header.Value = value;
}
else
{
Headers.Add(headerName, new HttpHeader(headerName, value));
}
return null;
}
/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>
/// An enumerator that can be used to iterate through the collection.
/// </returns>
public IEnumerator<HttpHeader> GetEnumerator()
{
return Headers.Values.Concat(NonUniqueHeaders.Values.SelectMany(x => x)).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
...@@ -8,9 +8,11 @@ namespace Titanium.Web.Proxy.Http ...@@ -8,9 +8,11 @@ namespace Titanium.Web.Proxy.Http
{ {
internal static class HeaderParser internal static class HeaderParser
{ {
internal static async Task ReadHeaders(CustomBinaryReader reader, Dictionary<string, List<HttpHeader>> nonUniqueResponseHeaders, internal static async Task ReadHeaders(CustomBinaryReader reader, HeaderCollection headerCollection)
Dictionary<string, HttpHeader> headers)
{ {
var nonUniqueResponseHeaders = headerCollection.NonUniqueHeaders;
var headers = headerCollection.Headers;
string tmpLine; string tmpLine;
while (!string.IsNullOrEmpty(tmpLine = await reader.ReadLineAsync())) while (!string.IsNullOrEmpty(tmpLine = await reader.ReadLineAsync()))
{ {
......
...@@ -27,7 +27,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -27,7 +27,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary> /// <summary>
/// Headers passed with Connect. /// Headers passed with Connect.
/// </summary> /// </summary>
public List<HttpHeader> ConnectHeaders { get; set; } public ConnectRequest ConnectRequest { get; set; }
/// <summary> /// <summary>
/// Web Request. /// Web Request.
...@@ -94,28 +94,14 @@ namespace Titanium.Web.Proxy.Http ...@@ -94,28 +94,14 @@ namespace Titanium.Web.Proxy.Http
$"{ServerConnection.UpStreamHttpProxy.UserName}:{ServerConnection.UpStreamHttpProxy.Password}"))); $"{ServerConnection.UpStreamHttpProxy.UserName}:{ServerConnection.UpStreamHttpProxy.Password}")));
} }
//write request headers //write request headers
foreach (var headerItem in Request.RequestHeaders) foreach (var header in Request.RequestHeaders)
{ {
var header = headerItem.Value; if (header.Name != "Proxy-Authorization")
if (headerItem.Key != "Proxy-Authorization")
{ {
requestLines.AppendLine($"{header.Name}: {header.Value}"); requestLines.AppendLine($"{header.Name}: {header.Value}");
} }
} }
//write non unique request headers
foreach (var headerItem in Request.NonUniqueRequestHeaders)
{
var headers = headerItem.Value;
foreach (var header in headers)
{
if (headerItem.Key != "Proxy-Authorization")
{
requestLines.AppendLine($"{header.Name}: {header.Value}");
}
}
}
requestLines.AppendLine(); requestLines.AppendLine();
string request = requestLines.ToString(); string request = requestLines.ToString();
...@@ -211,7 +197,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -211,7 +197,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.NonUniqueResponseHeaders, Response.ResponseHeaders); await HeaderParser.ReadHeaders(ServerConnection.StreamReader, Response.ResponseHeaders);
} }
/// <summary> /// <summary>
...@@ -219,7 +205,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -219,7 +205,7 @@ namespace Titanium.Web.Proxy.Http
/// </summary> /// </summary>
public void Dispose() public void Dispose()
{ {
ConnectHeaders = null; ConnectRequest = null;
Request.Dispose(); Request.Dispose();
Response.Dispose(); Response.Dispose();
......
This diff is collapsed.
This diff is collapsed.
...@@ -12,14 +12,14 @@ namespace Titanium.Web.Proxy ...@@ -12,14 +12,14 @@ namespace Titanium.Web.Proxy
{ {
public partial class ProxyServer public partial class ProxyServer
{ {
private async Task<bool> CheckAuthorization(StreamWriter clientStreamWriter, IEnumerable<HttpHeader> headers) private async Task<bool> CheckAuthorization(StreamWriter clientStreamWriter, Request request)
{ {
if (AuthenticateUserFunc == null) if (AuthenticateUserFunc == null)
{ {
return true; return true;
} }
var httpHeaders = headers as ICollection<HttpHeader> ?? headers.ToArray(); var httpHeaders = request.RequestHeaders.ToArray();
try try
{ {
...@@ -67,14 +67,10 @@ namespace Titanium.Web.Proxy ...@@ -67,14 +67,10 @@ namespace Titanium.Web.Proxy
private async Task SendAuthentication407Response(StreamWriter clientStreamWriter, string description) private async Task SendAuthentication407Response(StreamWriter clientStreamWriter, string description)
{ {
await WriteResponseStatus(HttpHeader.Version11, "407", description, clientStreamWriter); await WriteResponseStatus(HttpHeader.Version11, "407", description, clientStreamWriter);
var response = new Response var response = new Response();
{ response.ResponseHeaders.AddHeader("Proxy-Authenticate", "Basic realm=\"TitaniumProxy\"");
ResponseHeaders = new Dictionary<string, HttpHeader> response.ResponseHeaders.AddHeader("Proxy-Connection", "close");
{
{ "Proxy-Authenticate", new HttpHeader("Proxy-Authenticate", "Basic realm=\"TitaniumProxy\"") },
{ "Proxy-Connection", new HttpHeader("Proxy-Connection", "close") }
}
};
await WriteResponseHeaders(clientStreamWriter, response); await WriteResponseHeaders(clientStreamWriter, response);
await clientStreamWriter.WriteLineAsync(); await clientStreamWriter.WriteLineAsync();
......
...@@ -172,6 +172,10 @@ namespace Titanium.Web.Proxy ...@@ -172,6 +172,10 @@ namespace Titanium.Web.Proxy
/// </summary> /// </summary>
public event Func<object, SessionEventArgs, Task> BeforeResponse; public event Func<object, SessionEventArgs, Task> BeforeResponse;
public event Func<object, TunnelConnectEventArgs, Task> TunnelConnectRequest;
public event Func<object, TunnelConnectEventArgs, Task> TunnelConnectResponse;
/// <summary> /// <summary>
/// External proxy for Http /// External proxy for Http
/// </summary> /// </summary>
......
...@@ -88,20 +88,13 @@ namespace Titanium.Web.Proxy ...@@ -88,20 +88,13 @@ namespace Titanium.Web.Proxy
excluded = !endPoint.IncludedHttpsHostNameRegexList.Any(x => x.IsMatch(httpRemoteUri.Host)); excluded = !endPoint.IncludedHttpsHostNameRegexList.Any(x => x.IsMatch(httpRemoteUri.Host));
} }
List<HttpHeader> connectRequestHeaders = null; ConnectRequest connectRequest = null;
//Client wants to create a secure tcp tunnel (probably its a HTTPS or Websocket request) //Client wants to create a secure tcp tunnel (probably its a HTTPS or Websocket request)
if (httpVerb == "CONNECT") if (httpVerb == "CONNECT")
{ {
connectRequestHeaders = new List<HttpHeader>(); connectRequest = new ConnectRequest();
string tmpLine; await HeaderParser.ReadHeaders(clientStreamReader, connectRequest.RequestHeaders);
while (!string.IsNullOrEmpty(tmpLine = await clientStreamReader.ReadLineAsync()))
{
var header = tmpLine.Split(ProxyConstants.ColonSplit, 2);
var newHeader = new HttpHeader(header[0], header[1]);
connectRequestHeaders.Add(newHeader);
}
if (httpRemoteUri.Port == 80) if (httpRemoteUri.Port == 80)
{ {
...@@ -109,7 +102,7 @@ namespace Titanium.Web.Proxy ...@@ -109,7 +102,7 @@ namespace Titanium.Web.Proxy
excluded = true; excluded = true;
} }
if (!excluded && await CheckAuthorization(clientStreamWriter, connectRequestHeaders) == false) if (!excluded && await CheckAuthorization(clientStreamWriter, connectRequest) == false)
{ {
return; return;
} }
...@@ -117,12 +110,17 @@ namespace Titanium.Web.Proxy ...@@ -117,12 +110,17 @@ namespace Titanium.Web.Proxy
//write back successfull CONNECT response //write back successfull CONNECT response
await WriteConnectResponse(clientStreamWriter, version); await WriteConnectResponse(clientStreamWriter, version);
if (!excluded && !await HttpsTools.IsClientHello(clientStream)) bool isClientHello = await HttpsTools.IsClientHello(clientStream);
if (TunnelConnectRequest != null)
{ {
excluded = true; var args = new TunnelConnectEventArgs();
args.IsHttps = isClientHello;
args.ConnectRequest = connectRequest;
await TunnelConnectRequest.InvokeParallelAsync(this, args);
} }
if (!excluded) if (!excluded && isClientHello)
{ {
httpRemoteUri = new Uri("https://" + httpCmdSplit[1]); httpRemoteUri = new Uri("https://" + httpCmdSplit[1]);
...@@ -188,7 +186,7 @@ namespace Titanium.Web.Proxy ...@@ -188,7 +186,7 @@ namespace Titanium.Web.Proxy
//Now create the request //Now create the request
disposed = await HandleHttpSessionRequest(tcpClient, httpCmd, clientStream, clientStreamReader, clientStreamWriter, disposed = await HandleHttpSessionRequest(tcpClient, httpCmd, clientStream, clientStreamReader, clientStreamWriter,
httpRemoteUri.Scheme == Uri.UriSchemeHttps ? httpRemoteUri.Host : null, endPoint, connectRequestHeaders); httpRemoteUri.Scheme == Uri.UriSchemeHttps ? httpRemoteUri.Host : null, endPoint, connectRequest);
} }
catch (Exception e) catch (Exception e)
{ {
...@@ -268,11 +266,11 @@ namespace Titanium.Web.Proxy ...@@ -268,11 +266,11 @@ namespace Titanium.Web.Proxy
/// <param name="clientStreamWriter"></param> /// <param name="clientStreamWriter"></param>
/// <param name="httpsConnectHostname"></param> /// <param name="httpsConnectHostname"></param>
/// <param name="endPoint"></param> /// <param name="endPoint"></param>
/// <param name="connectHeaders"></param> /// <param name="connectRequest"></param>
/// <returns></returns> /// <returns></returns>
private async Task<bool> HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream, private async Task<bool> HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream,
CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, string httpsConnectHostname, CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, string httpsConnectHostname,
ProxyEndPoint endPoint, List<HttpHeader> connectHeaders) ProxyEndPoint endPoint, ConnectRequest connectRequest)
{ {
bool disposed = false; bool disposed = false;
...@@ -290,7 +288,7 @@ namespace Titanium.Web.Proxy ...@@ -290,7 +288,7 @@ namespace Titanium.Web.Proxy
var args = new SessionEventArgs(BufferSize, HandleHttpSessionResponse) var args = new SessionEventArgs(BufferSize, HandleHttpSessionResponse)
{ {
ProxyClient = { TcpClient = client }, ProxyClient = { TcpClient = client },
WebSession = { ConnectHeaders = connectHeaders } WebSession = { ConnectRequest = connectRequest }
}; };
args.WebSession.ProcessId = new Lazy<int>(() => args.WebSession.ProcessId = new Lazy<int>(() =>
...@@ -327,7 +325,7 @@ namespace Titanium.Web.Proxy ...@@ -327,7 +325,7 @@ namespace Titanium.Web.Proxy
} }
//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.NonUniqueRequestHeaders, args.WebSession.Request.RequestHeaders); await HeaderParser.ReadHeaders(clientStreamReader, args.WebSession.Request.RequestHeaders);
var httpRemoteUri = new Uri(httpsConnectHostname == null var httpRemoteUri = new Uri(httpsConnectHostname == null
? httpCmdSplit[1] ? httpCmdSplit[1]
...@@ -342,7 +340,7 @@ namespace Titanium.Web.Proxy ...@@ -342,7 +340,7 @@ namespace Titanium.Web.Proxy
args.ProxyClient.ClientStreamWriter = clientStreamWriter; args.ProxyClient.ClientStreamWriter = clientStreamWriter;
//proxy authorization check //proxy authorization check
if (httpsConnectHostname == null && await CheckAuthorization(clientStreamWriter, args.WebSession.Request.RequestHeaders.Values) == false) if (httpsConnectHostname == null && await CheckAuthorization(clientStreamWriter, args.WebSession.Request) == false)
{ {
args.Dispose(); args.Dispose();
break; break;
...@@ -386,7 +384,7 @@ namespace Titanium.Web.Proxy ...@@ -386,7 +384,7 @@ namespace Titanium.Web.Proxy
//if upgrading to websocket then relay the requet without reading the contents //if upgrading to websocket then relay the requet without reading the contents
if (args.WebSession.Request.UpgradeToWebSocket) if (args.WebSession.Request.UpgradeToWebSocket)
{ {
await TcpHelper.SendRaw(httpCmd, args.WebSession.Request.RequestHeaders.Values, clientStream, connection); await TcpHelper.SendRaw(httpCmd, args.WebSession.Request.RequestHeaders, clientStream, connection);
args.Dispose(); args.Dispose();
break; break;
...@@ -604,12 +602,10 @@ namespace Titanium.Web.Proxy ...@@ -604,12 +602,10 @@ namespace Titanium.Web.Proxy
/// </summary> /// </summary>
/// <param name="requestHeaders"></param> /// <param name="requestHeaders"></param>
/// <param name="webRequest"></param> /// <param name="webRequest"></param>
private void PrepareRequestHeaders(Dictionary<string, HttpHeader> requestHeaders, HttpWebClient webRequest) private void PrepareRequestHeaders(HeaderCollection requestHeaders, HttpWebClient webRequest)
{ {
foreach (var headerItem in requestHeaders) foreach (var header in requestHeaders)
{ {
var header = headerItem.Value;
switch (header.Name.ToLower()) switch (header.Name.ToLower())
{ {
//these are the only encoding this proxy can read //these are the only encoding this proxy can read
......
...@@ -174,17 +174,7 @@ namespace Titanium.Web.Proxy ...@@ -174,17 +174,7 @@ namespace Titanium.Web.Proxy
foreach (var header in response.ResponseHeaders) foreach (var header in response.ResponseHeaders)
{ {
await header.Value.WriteToStream(responseWriter); await header.WriteToStream(responseWriter);
}
//write non unique request headers
foreach (var headerItem in response.NonUniqueResponseHeaders)
{
var headers = headerItem.Value;
foreach (var header in headers)
{
await header.WriteToStream(responseWriter);
}
} }
await responseWriter.WriteLineAsync(); await responseWriter.WriteLineAsync();
...@@ -195,26 +185,15 @@ namespace Titanium.Web.Proxy ...@@ -195,26 +185,15 @@ namespace Titanium.Web.Proxy
/// Fix proxy specific headers /// Fix proxy specific headers
/// </summary> /// </summary>
/// <param name="headers"></param> /// <param name="headers"></param>
private void FixProxyHeaders(Dictionary<string, HttpHeader> headers) private void FixProxyHeaders(HeaderCollection headers)
{ {
//If proxy-connection close was returned inform to close the connection //If proxy-connection close was returned inform to close the connection
bool hasProxyHeader = headers.ContainsKey("proxy-connection"); string proxyHeader = headers.GetHeaderValueOrNull("proxy-connection");
bool hasConnectionheader = headers.ContainsKey("connection"); headers.RemoveHeader("proxy-connection");
if (hasProxyHeader) if (proxyHeader != null)
{ {
var proxyHeader = headers["proxy-connection"]; headers.SetOrAddHeaderValue("connection", proxyHeader);
if (hasConnectionheader == false)
{
headers.Add("connection", new HttpHeader("connection", proxyHeader.Value));
}
else
{
var connectionHeader = headers["connection"];
connectionHeader.Value = proxyHeader.Value;
}
headers.Remove("proxy-connection");
} }
} }
......
...@@ -73,6 +73,7 @@ ...@@ -73,6 +73,7 @@
<Compile Include="Decompression\IDecompression.cs" /> <Compile Include="Decompression\IDecompression.cs" />
<Compile Include="EventArguments\CertificateSelectionEventArgs.cs" /> <Compile Include="EventArguments\CertificateSelectionEventArgs.cs" />
<Compile Include="EventArguments\CertificateValidationEventArgs.cs" /> <Compile Include="EventArguments\CertificateValidationEventArgs.cs" />
<Compile Include="EventArguments\TunnelConnectEventArgs.cs" />
<Compile Include="Extensions\ByteArrayExtensions.cs" /> <Compile Include="Extensions\ByteArrayExtensions.cs" />
<Compile Include="Extensions\FuncExtensions.cs" /> <Compile Include="Extensions\FuncExtensions.cs" />
<Compile Include="Helpers\HttpHelper.cs" /> <Compile Include="Helpers\HttpHelper.cs" />
...@@ -85,6 +86,9 @@ ...@@ -85,6 +86,9 @@
<Compile Include="Helpers\RunTime.cs" /> <Compile Include="Helpers\RunTime.cs" />
<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\ConnectRequest.cs" />
<Compile Include="Http\ConnectResponse.cs" />
<Compile Include="Http\HeaderCollection.cs" />
<Compile Include="Http\HeaderParser.cs" /> <Compile Include="Http\HeaderParser.cs" />
<Compile Include="Http\HttpsTools.cs" /> <Compile Include="Http\HttpsTools.cs" />
<Compile Include="Http\Responses\GenericResponse.cs" /> <Compile Include="Http\Responses\GenericResponse.cs" />
......
...@@ -44,7 +44,7 @@ namespace Titanium.Web.Proxy ...@@ -44,7 +44,7 @@ namespace Titanium.Web.Proxy
//check in non-unique headers first //check in non-unique headers first
var header = var header =
args.WebSession.Response.NonUniqueResponseHeaders.FirstOrDefault( args.WebSession.Response.ResponseHeaders.NonUniqueHeaders.FirstOrDefault(
x => authHeaderNames.Any(y => x.Key.Equals(y, StringComparison.OrdinalIgnoreCase))); x => authHeaderNames.Any(y => x.Key.Equals(y, StringComparison.OrdinalIgnoreCase)));
if (!header.Equals(new KeyValuePair<string, List<HttpHeader>>())) if (!header.Equals(new KeyValuePair<string, List<HttpHeader>>()))
...@@ -54,7 +54,7 @@ namespace Titanium.Web.Proxy ...@@ -54,7 +54,7 @@ namespace Titanium.Web.Proxy
if (headerName != null) if (headerName != null)
{ {
authHeader = args.WebSession.Response.NonUniqueResponseHeaders[headerName] authHeader = args.WebSession.Response.ResponseHeaders.NonUniqueHeaders[headerName]
.FirstOrDefault(x => authSchemes.Any(y => x.Value.StartsWith(y, StringComparison.OrdinalIgnoreCase))); .FirstOrDefault(x => authSchemes.Any(y => x.Value.StartsWith(y, StringComparison.OrdinalIgnoreCase)));
} }
...@@ -63,7 +63,7 @@ namespace Titanium.Web.Proxy ...@@ -63,7 +63,7 @@ namespace Titanium.Web.Proxy
{ {
//check in non-unique headers first //check in non-unique headers first
var uHeader = var uHeader =
args.WebSession.Response.ResponseHeaders.FirstOrDefault(x => authHeaderNames.Any(y => x.Key.Equals(y, StringComparison.OrdinalIgnoreCase))); args.WebSession.Response.ResponseHeaders.Headers.FirstOrDefault(x => authHeaderNames.Any(y => x.Key.Equals(y, StringComparison.OrdinalIgnoreCase)));
if (!uHeader.Equals(new KeyValuePair<string, HttpHeader>())) if (!uHeader.Equals(new KeyValuePair<string, HttpHeader>()))
{ {
...@@ -72,9 +72,9 @@ namespace Titanium.Web.Proxy ...@@ -72,9 +72,9 @@ namespace Titanium.Web.Proxy
if (headerName != null) if (headerName != null)
{ {
authHeader = authSchemes.Any(x => args.WebSession.Response.ResponseHeaders[headerName].Value authHeader = authSchemes.Any(x => args.WebSession.Response.ResponseHeaders.Headers[headerName].Value
.StartsWith(x, StringComparison.OrdinalIgnoreCase)) .StartsWith(x, StringComparison.OrdinalIgnoreCase))
? args.WebSession.Response.ResponseHeaders[headerName] ? args.WebSession.Response.ResponseHeaders.Headers[headerName]
: null; : null;
} }
} }
...@@ -84,9 +84,9 @@ namespace Titanium.Web.Proxy ...@@ -84,9 +84,9 @@ namespace Titanium.Web.Proxy
string scheme = authSchemes.FirstOrDefault(x => authHeader.Value.Equals(x, StringComparison.OrdinalIgnoreCase)); string scheme = authSchemes.FirstOrDefault(x => authHeader.Value.Equals(x, StringComparison.OrdinalIgnoreCase));
//clear any existing headers to avoid confusing bad servers //clear any existing headers to avoid confusing bad servers
if (args.WebSession.Request.NonUniqueRequestHeaders.ContainsKey("Authorization")) if (args.WebSession.Request.RequestHeaders.NonUniqueHeaders.ContainsKey("Authorization"))
{ {
args.WebSession.Request.NonUniqueRequestHeaders.Remove("Authorization"); args.WebSession.Request.RequestHeaders.NonUniqueHeaders.Remove("Authorization");
} }
//initial value will match exactly any of the schemes //initial value will match exactly any of the schemes
...@@ -97,13 +97,13 @@ namespace Titanium.Web.Proxy ...@@ -97,13 +97,13 @@ namespace Titanium.Web.Proxy
var auth = new HttpHeader("Authorization", string.Concat(scheme, clientToken)); var auth = new HttpHeader("Authorization", string.Concat(scheme, clientToken));
//replace existing authorization header if any //replace existing authorization header if any
if (args.WebSession.Request.RequestHeaders.ContainsKey("Authorization")) if (args.WebSession.Request.RequestHeaders.Headers.ContainsKey("Authorization"))
{ {
args.WebSession.Request.RequestHeaders["Authorization"] = auth; args.WebSession.Request.RequestHeaders.Headers["Authorization"] = auth;
} }
else else
{ {
args.WebSession.Request.RequestHeaders.Add("Authorization", auth); args.WebSession.Request.RequestHeaders.Headers.Add("Authorization", auth);
} }
//don't need to send body for Authorization request //don't need to send body for Authorization request
...@@ -122,7 +122,7 @@ namespace Titanium.Web.Proxy ...@@ -122,7 +122,7 @@ namespace Titanium.Web.Proxy
string clientToken = WinAuthHandler.GetFinalAuthToken(args.WebSession.Request.Host, serverToken, args.Id); string clientToken = WinAuthHandler.GetFinalAuthToken(args.WebSession.Request.Host, serverToken, args.Id);
//there will be an existing header from initial client request //there will be an existing header from initial client request
args.WebSession.Request.RequestHeaders["Authorization"] = new HttpHeader("Authorization", string.Concat(scheme, clientToken)); args.WebSession.Request.RequestHeaders.Headers["Authorization"] = new HttpHeader("Authorization", string.Concat(scheme, clientToken));
//send body for final auth request //send body for final auth request
if (args.WebSession.Request.HasBody) if (args.WebSession.Request.HasBody)
......
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