Commit 34a68075 authored by justcoding121's avatar justcoding121

Asyncify fixes

parent 03205075
......@@ -12,9 +12,9 @@ namespace Titanium.Web.Proxy.Examples.Basic
{
public void StartProxy()
{
ProxyServer.BeforeRequest += OnRequest;
ProxyServer.BeforeResponse += OnResponse;
ProxyServer.ServerCertificateValidationCallback += OnCertificateValidation;
// ProxyServer.BeforeRequest += OnRequest;
// ProxyServer.BeforeResponse += OnResponse;
// ProxyServer.ServerCertificateValidationCallback += OnCertificateValidation;
//Exclude Https addresses you don't want to proxy
//Usefull for clients that use certificate pinning
......@@ -112,7 +112,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
{
if (e.WebSession.Response.ResponseStatusCode == "200")
{
if (e.WebSession.Response.ContentType.Trim().ToLower().Contains("text/html"))
if (e.WebSession.Response.ContentType!=null && e.WebSession.Response.ContentType.Trim().ToLower().Contains("text/html"))
{
byte[] bodyBytes = await e.GetResponseBody();
await e.SetResponseBody(bodyBytes);
......
......@@ -136,7 +136,7 @@ Sample request and response event handlers
{
if (e.WebSession.Response.ResponseStatusCode == "200")
{
if (e.WebSession.Response.ContentType.Trim().ToLower().Contains("text/html"))
if (e.WebSession.Response.ContentType!=null && e.WebSession.Response.ContentType.Trim().ToLower().Contains("text/html"))
{
byte[] bodyBytes = await e.GetResponseBody();
await e.SetResponseBody(bodyBytes);
......@@ -148,11 +148,8 @@ Sample request and response event handlers
}
}
/// <summary>
/// Allows overriding default certificate validation logic
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// Allows overriding default certificate validation logic
public async Task OnCertificateValidation(object sender, CertificateValidationEventArgs e)
{
//set IsValid to true/false based on Certificate Errors
......
......@@ -7,6 +7,7 @@ using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Http.Responses;
using Titanium.Web.Proxy.Extensions;
using System.Threading.Tasks;
using Titanium.Web.Proxy.Network;
namespace Titanium.Web.Proxy.EventArguments
{
......@@ -86,14 +87,17 @@ namespace Titanium.Web.Proxy.EventArguments
await this.Client.ClientStreamReader.CopyBytesToStream(requestBodyStream, WebSession.Request.ContentLength).ConfigureAwait(false);
}
else if (WebSession.Request.HttpVersion.ToLower().Trim().Equals("http/1.0"))
await WebSession.ServerConnection.StreamReader.CopyBytesToStream(requestBodyStream, long.MaxValue).ConfigureAwait(false);
}
WebSession.Request.RequestBody = await GetDecompressedResponseBody(WebSession.Request.ContentEncoding, requestBodyStream.ToArray()).ConfigureAwait(false);
}
}
//Now set the flag to true
//So that next time we can deliver body from cache
WebSession.Request.RequestBodyRead = true;
//Now set the flag to true
//So that next time we can deliver body from cache
WebSession.Request.RequestBodyRead = true;
}
}
/// <summary>
......@@ -109,16 +113,18 @@ namespace Titanium.Web.Proxy.EventArguments
//If chuncked the read chunk by chunk until we hit chunk end symbol
if (WebSession.Response.IsChunked)
{
await WebSession.ProxyClient.ServerStreamReader.CopyBytesToStreamChunked(responseBodyStream).ConfigureAwait(false);
await WebSession.ServerConnection.StreamReader.CopyBytesToStreamChunked(responseBodyStream).ConfigureAwait(false);
}
else
{
if (WebSession.Response.ContentLength > 0)
{
//If not chunked then its easy just read the amount of bytes mentioned in content length header of response
await WebSession.ProxyClient.ServerStreamReader.CopyBytesToStream(responseBodyStream, WebSession.Response.ContentLength).ConfigureAwait(false);
await WebSession.ServerConnection.StreamReader.CopyBytesToStream(responseBodyStream, WebSession.Response.ContentLength).ConfigureAwait(false);
}
else if(WebSession.Response.HttpVersion.ToLower().Trim().Equals("http/1.0"))
await WebSession.ServerConnection.StreamReader.CopyBytesToStream(responseBodyStream, long.MaxValue).ConfigureAwait(false);
}
WebSession.Response.ResponseBody = await GetDecompressedResponseBody(WebSession.Response.ContentEncoding, responseBodyStream.ToArray()).ConfigureAwait(false);
......@@ -173,7 +179,11 @@ namespace Titanium.Web.Proxy.EventArguments
}
WebSession.Request.RequestBody = body;
WebSession.Request.RequestBodyRead = true;
if (WebSession.Request.IsChunked == false)
WebSession.Request.ContentLength = body.Length;
else
WebSession.Request.ContentLength = -1;
}
/// <summary>
......@@ -191,13 +201,8 @@ namespace Titanium.Web.Proxy.EventArguments
await ReadRequestBody().ConfigureAwait(false);
}
WebSession.Request.RequestBody = WebSession.Request.Encoding.GetBytes(body);
//If there is a content length header update it
if (!WebSession.Request.IsChunked)
WebSession.Request.ContentLength = body.Length;
await SetRequestBody(WebSession.Request.Encoding.GetBytes(body));
WebSession.Request.RequestBodyRead = true;
}
/// <summary>
......@@ -245,9 +250,10 @@ namespace Titanium.Web.Proxy.EventArguments
WebSession.Response.ResponseBody = body;
//If there is a content length header update it
if (!WebSession.Response.IsChunked)
if (WebSession.Response.IsChunked == false)
WebSession.Response.ContentLength = body.Length;
else
WebSession.Response.ContentLength = -1;
}
/// <summary>
......@@ -266,8 +272,9 @@ namespace Titanium.Web.Proxy.EventArguments
}
var bodyBytes = WebSession.Response.Encoding.GetBytes(body);
await SetResponseBody(bodyBytes).ConfigureAwait(false);
}
}
private async Task<byte[]> GetDecompressedResponseBody(string encodingType, byte[] responseBodyStream)
{
......
......@@ -15,7 +15,8 @@ namespace Titanium.Web.Proxy.Extensions
try
{
//return default if not specified
if (request.ContentType == null) return Encoding.GetEncoding("ISO-8859-1");
if (request.ContentType == null)
return Encoding.GetEncoding("ISO-8859-1");
//extract the encoding by finding the charset
var contentTypes = request.ContentType.Split(Constants.SemiColonSplit);
......
using System.Text;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Shared;
namespace Titanium.Web.Proxy.Extensions
{
public static class HttpWebResponseExtensions
{
public static Encoding GetResponseEncoding(this Response response)
public static Encoding GetResponseCharacterEncoding(this Response response)
{
if (string.IsNullOrEmpty(response.CharacterSet))
return Encoding.GetEncoding("ISO-8859-1");
try
{
return Encoding.GetEncoding(response.CharacterSet.Replace(@"""", string.Empty));
//return default if not specified
if (response.ContentType == null)
return Encoding.GetEncoding("ISO-8859-1");
//extract the encoding by finding the charset
var contentTypes = response.ContentType.Split(Constants.SemiColonSplit);
foreach (var contentType in contentTypes)
{
var encodingSplit = contentType.Split('=');
if (encodingSplit.Length == 2 && encodingSplit[0].ToLower().Trim() == "charset")
{
return Encoding.GetEncoding(encodingSplit[1]);
}
}
}
catch { return Encoding.GetEncoding("ISO-8859-1"); }
catch
{
//parsing errors
// ignored
}
//return default if not specified
return Encoding.GetEncoding("ISO-8859-1");
}
}
}
\ No newline at end of file
......@@ -20,25 +20,29 @@ namespace Titanium.Web.Proxy.Extensions
await input.CopyToAsync(output);
}
internal static async Task CopyBytesToStream(this CustomBinaryReader clientStreamReader, Stream stream, long totalBytesToRead)
internal static async Task CopyBytesToStream(this CustomBinaryReader streamReader, Stream stream, long totalBytesToRead)
{
var totalbytesRead = 0;
int bytesToRead;
long bytesToRead;
if (totalBytesToRead < Constants.BUFFER_SIZE)
{
bytesToRead = (int)totalBytesToRead;
bytesToRead = totalBytesToRead;
}
else
bytesToRead = Constants.BUFFER_SIZE;
while (totalbytesRead < (int)totalBytesToRead)
while (totalbytesRead < totalBytesToRead)
{
var buffer = await clientStreamReader.ReadBytesAsync(bytesToRead);
var buffer = await streamReader.ReadBytesAsync(bytesToRead);
if (buffer.Length == 0)
break;
totalbytesRead += buffer.Length;
var remainingBytes = (int)totalBytesToRead - totalbytesRead;
var remainingBytes = totalBytesToRead - totalbytesRead;
if (remainingBytes < bytesToRead)
{
bytesToRead = remainingBytes;
......
......@@ -4,15 +4,18 @@ using System.Diagnostics;
using System.Collections.Generic;
using System.Security.Cryptography.X509Certificates;
using System.Reflection;
using System.Threading.Tasks;
using System.Threading;
namespace Titanium.Web.Proxy.Helpers
{
public class CertificateManager : IDisposable
public class CertificateManager : IDisposable
{
private const string CertCreateFormat =
"-ss {0} -n \"CN={1}, O={2}\" -sky {3} -cy {4} -m 120 -a sha256 -eku 1.3.6.1.5.5.7.3.1 {5}";
private readonly IDictionary<string, X509Certificate2> _certificateCache;
private static SemaphoreSlim semaphoreLock = new SemaphoreSlim(1);
public string Issuer { get; private set; }
public string RootCertificateName { get; private set; }
......@@ -35,10 +38,10 @@ namespace Titanium.Web.Proxy.Helpers
/// Attempts to move a self-signed certificate to the root store.
/// </summary>
/// <returns>true if succeeded, else false</returns>
public bool CreateTrustedRootCertificate()
public async Task<bool> CreateTrustedRootCertificate()
{
X509Certificate2 rootCertificate =
CreateCertificate(RootStore, RootCertificateName);
await CreateCertificate(RootStore, RootCertificateName);
return rootCertificate != null;
}
......@@ -46,9 +49,9 @@ namespace Titanium.Web.Proxy.Helpers
/// Attempts to remove the self-signed certificate from the root store.
/// </summary>
/// <returns>true if succeeded, else false</returns>
public bool DestroyTrustedRootCertificate()
public async Task<bool> DestroyTrustedRootCertificate()
{
return DestroyCertificate(RootStore, RootCertificateName);
return await DestroyCertificate(RootStore, RootCertificateName);
}
public X509Certificate2Collection FindCertificates(string certificateSubject)
......@@ -64,103 +67,126 @@ namespace Titanium.Web.Proxy.Helpers
discoveredCertificates : null;
}
public X509Certificate2 CreateCertificate(string certificateName)
public async Task<X509Certificate2> CreateCertificate(string certificateName)
{
return CreateCertificate(MyStore, certificateName);
return await CreateCertificate(MyStore, certificateName);
}
protected virtual X509Certificate2 CreateCertificate(X509Store store, string certificateName)
protected async virtual Task<X509Certificate2> CreateCertificate(X509Store store, string certificateName)
{
if (_certificateCache.ContainsKey(certificateName))
return _certificateCache[certificateName];
lock (store)
await semaphoreLock.WaitAsync();
X509Certificate2 certificate = null;
try
{
X509Certificate2 certificate = null;
try
{
store.Open(OpenFlags.ReadWrite);
string certificateSubject = string.Format("CN={0}, O={1}", certificateName, Issuer);
store.Open(OpenFlags.ReadWrite);
string certificateSubject = string.Format("CN={0}, O={1}", certificateName, Issuer);
var certificates =
FindCertificates(store, certificateSubject);
var certificates =
FindCertificates(store, certificateSubject);
if (certificates != null)
certificate = certificates[0];
if (certificates != null)
certificate = certificates[0];
if (certificate == null)
{
string[] args = new[] {
if (certificate == null)
{
string[] args = new[] {
GetCertificateCreateArgs(store, certificateName) };
CreateCertificate(args);
certificates = FindCertificates(store, certificateSubject);
await CreateCertificate(args);
certificates = FindCertificates(store, certificateSubject);
return certificates != null ?
certificates[0] : null;
}
return certificate;
}
finally
{
store.Close();
if (certificate != null && !_certificateCache.ContainsKey(certificateName))
_certificateCache.Add(certificateName, certificate);
return certificates != null ?
certificates[0] : null;
}
store.Close();
if (certificate != null && !_certificateCache.ContainsKey(certificateName))
_certificateCache.Add(certificateName, certificate);
return certificate;
}
finally
{
semaphoreLock.Release();
}
}
protected virtual void CreateCertificate(string[] args)
protected virtual Task<int> CreateCertificate(string[] args)
{
using (var process = new Process())
{
string file = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "makecert.exe");
if (!File.Exists(file))
throw new Exception("Unable to locate 'makecert.exe'.");
// there is no non-generic TaskCompletionSource
var tcs = new TaskCompletionSource<int>();
var process = new Process();
process.StartInfo.Verb = "runas";
process.StartInfo.Arguments = args != null ? args[0] : string.Empty;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.FileName = file;
string file = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "makecert.exe");
process.Start();
process.WaitForExit();
if (!File.Exists(file))
throw new Exception("Unable to locate 'makecert.exe'.");
process.StartInfo.Verb = "runas";
process.StartInfo.Arguments = args != null ? args[0] : string.Empty;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.FileName = file;
process.EnableRaisingEvents = true;
process.Exited += (sender, processArgs) =>
{
tcs.SetResult(process.ExitCode);
process.Dispose();
};
bool started = process.Start();
if (!started)
{
//you may allow for the process to be re-used (started = false)
//but I'm not sure about the guarantees of the Exited event in such a case
throw new InvalidOperationException("Could not start process: " + process);
}
return tcs.Task;
}
public bool DestroyCertificate(string certificateName)
public async Task<bool> DestroyCertificate(string certificateName)
{
return DestroyCertificate(MyStore, certificateName);
return await DestroyCertificate(MyStore, certificateName);
}
protected virtual bool DestroyCertificate(X509Store store, string certificateName)
protected virtual async Task<bool> DestroyCertificate(X509Store store, string certificateName)
{
lock (store)
await semaphoreLock.WaitAsync();
X509Certificate2Collection certificates = null;
try
{
X509Certificate2Collection certificates = null;
try
{
store.Open(OpenFlags.ReadWrite);
string certificateSubject = string.Format("CN={0}, O={1}", certificateName, Issuer);
store.Open(OpenFlags.ReadWrite);
string certificateSubject = string.Format("CN={0}, O={1}", certificateName, Issuer);
certificates = FindCertificates(store, certificateSubject);
if (certificates != null)
{
store.RemoveRange(certificates);
certificates = FindCertificates(store, certificateSubject);
if (certificates != null)
{
store.RemoveRange(certificates);
certificates = FindCertificates(store, certificateSubject);
}
return certificates == null;
}
finally
store.Close();
if (certificates == null &&
_certificateCache.ContainsKey(certificateName))
{
store.Close();
if (certificates == null &&
_certificateCache.ContainsKey(certificateName))
{
_certificateCache.Remove(certificateName);
}
_certificateCache.Remove(certificateName);
}
return certificates == null;
}
finally
{
semaphoreLock.Release();
}
}
protected virtual string GetCertificateCreateArgs(X509Store store, string certificateName)
......
......@@ -11,7 +11,7 @@ namespace Titanium.Web.Proxy.Http
{
public class HttpWebSession
{
internal TcpConnection ProxyClient { get; set; }
internal TcpConnection ServerConnection { get; set; }
public Request Request { get; set; }
public Response Response { get; set; }
......@@ -27,7 +27,7 @@ namespace Titanium.Web.Proxy.Http
internal void SetConnection(TcpConnection Connection)
{
Connection.LastAccess = DateTime.Now;
ProxyClient = Connection;
ServerConnection = Connection;
}
internal HttpWebSession()
......@@ -38,7 +38,7 @@ namespace Titanium.Web.Proxy.Http
internal async Task SendRequest()
{
Stream stream = ProxyClient.Stream;
Stream stream = ServerConnection.Stream;
StringBuilder requestLines = new StringBuilder();
......@@ -59,12 +59,12 @@ namespace Titanium.Web.Proxy.Http
string request = requestLines.ToString();
byte[] requestBytes = Encoding.ASCII.GetBytes(request);
await stream.WriteAsync(requestBytes, 0, requestBytes.Length);
stream.Flush();
await stream.FlushAsync();
if (ProxyServer.Enable100ContinueBehaviour)
if (this.Request.ExpectContinue)
{
var httpResult = (await ProxyClient.ServerStreamReader.ReadLineAsync()).Split(Constants.SpaceSplit, 3);
var httpResult = (await ServerConnection.StreamReader.ReadLineAsync()).Split(Constants.SpaceSplit, 3);
var responseStatusCode = httpResult[1].Trim();
var responseStatusDescription = httpResult[2].Trim();
......@@ -73,13 +73,13 @@ namespace Titanium.Web.Proxy.Http
&& responseStatusDescription.ToLower().Equals("continue"))
{
this.Request.Is100Continue = true;
await ProxyClient.ServerStreamReader.ReadLineAsync().ConfigureAwait(false);
await ServerConnection.StreamReader.ReadLineAsync().ConfigureAwait(false);
}
else if (responseStatusCode.Equals("417")
&& responseStatusDescription.ToLower().Equals("expectation failed"))
{
this.Request.ExpectationFailed = true;
await ProxyClient.ServerStreamReader.ReadLineAsync().ConfigureAwait(false);
await ServerConnection.StreamReader.ReadLineAsync().ConfigureAwait(false);
}
}
}
......@@ -89,11 +89,11 @@ namespace Titanium.Web.Proxy.Http
//return if this is already read
if (this.Response.ResponseStatusCode != null) return;
var httpResult = (await ProxyClient.ServerStreamReader.ReadLineAsync()).Split(Constants.SpaceSplit, 3);
var httpResult = (await ServerConnection.StreamReader.ReadLineAsync()).Split(Constants.SpaceSplit, 3);
if (string.IsNullOrEmpty(httpResult[0]))
{
await ProxyClient.ServerStreamReader.ReadLineAsync().ConfigureAwait(false);
await ServerConnection.StreamReader.ReadLineAsync().ConfigureAwait(false);
}
this.Response.HttpVersion = httpResult[0].Trim();
......@@ -106,7 +106,7 @@ namespace Titanium.Web.Proxy.Http
{
this.Response.Is100Continue = true;
this.Response.ResponseStatusCode = null;
await ProxyClient.ServerStreamReader.ReadLineAsync().ConfigureAwait(false);
await ServerConnection.StreamReader.ReadLineAsync().ConfigureAwait(false);
await ReceiveResponse();
return;
}
......@@ -115,12 +115,12 @@ namespace Titanium.Web.Proxy.Http
{
this.Response.ExpectationFailed = true;
this.Response.ResponseStatusCode = null;
await ProxyClient.ServerStreamReader.ReadLineAsync().ConfigureAwait(false);
await ServerConnection.StreamReader.ReadLineAsync().ConfigureAwait(false);
await ReceiveResponse();
return;
}
List<string> responseLines = await ProxyClient.ServerStreamReader.ReadAllLinesAsync().ConfigureAwait(false);
List<string> responseLines = await ServerConnection.StreamReader.ReadAllLinesAsync().ConfigureAwait(false);
for (int index = 0; index < responseLines.Count; ++index)
{
......
......@@ -13,22 +13,9 @@ namespace Titanium.Web.Proxy.Http
public string ResponseStatusCode { get; set; }
public string ResponseStatusDescription { get; set; }
internal Encoding Encoding { get { return this.GetResponseEncoding(); } }
internal Encoding Encoding { get { return this.GetResponseCharacterEncoding(); } }
internal string CharacterSet
{
get
{
if (this.ContentType.Contains(";"))
{
return this.ContentType.Split(';')[1].Substring(9).Trim();
}
return null;
}
}
internal string ContentEncoding
{
get
......@@ -69,13 +56,7 @@ namespace Titanium.Web.Proxy.Http
if (header != null)
{
if (header.Value.Contains(";"))
{
return header.Value.Split(';')[0].Trim();
}
else
return header.Value.ToLower().Trim();
return header.Value;
}
return null;
......
......@@ -2,7 +2,7 @@
using System.Net.Sockets;
using Titanium.Web.Proxy.Helpers;
namespace Titanium.Web.Proxy.EventArguments
namespace Titanium.Web.Proxy.Network
{
/// <summary>
/// This class wraps Tcp connection to Server
......
......@@ -23,7 +23,7 @@ namespace Titanium.Web.Proxy.Network
internal Version Version { get; set; }
internal TcpClient TcpClient { get; set; }
internal CustomBinaryReader ServerStreamReader { get; set; }
internal CustomBinaryReader StreamReader { get; set; }
internal Stream Stream { get; set; }
internal DateTime LastAccess { get; set; }
......@@ -88,21 +88,25 @@ namespace Titanium.Web.Proxy.Network
client = new TcpClient(ProxyServer.UpStreamHttpsProxy.HostName, ProxyServer.UpStreamHttpsProxy.Port);
stream = (Stream)client.GetStream();
var writer = new StreamWriter(stream, Encoding.ASCII, Constants.BUFFER_SIZE, true);
writer.WriteLine(string.Format("CONNECT {0}:{1} {2}", sessionArgs.WebSession.Request.RequestUri.Host, sessionArgs.WebSession.Request.RequestUri.Port, sessionArgs.WebSession.Request.HttpVersion));
writer.WriteLine(string.Format("Host: {0}:{1}", sessionArgs.WebSession.Request.RequestUri.Host, sessionArgs.WebSession.Request.RequestUri.Port));
writer.WriteLine("Connection: Keep-Alive");
writer.WriteLine();
writer.Flush();
var reader = new CustomBinaryReader(stream);
var result = await reader.ReadLineAsync().ConfigureAwait(false);
if (!result.ToLower().Contains("200 connection established"))
throw new Exception("Upstream proxy failed to create a secure tunnel");
await reader.ReadAllLinesAsync().ConfigureAwait(false);
using (var writer = new StreamWriter(stream, Encoding.ASCII, Constants.BUFFER_SIZE, true))
{
await writer.WriteLineAsync(string.Format("CONNECT {0}:{1} {2}", sessionArgs.WebSession.Request.RequestUri.Host, sessionArgs.WebSession.Request.RequestUri.Port, sessionArgs.WebSession.Request.HttpVersion));
await writer.WriteLineAsync(string.Format("Host: {0}:{1}", sessionArgs.WebSession.Request.RequestUri.Host, sessionArgs.WebSession.Request.RequestUri.Port));
await writer.WriteLineAsync("Connection: Keep-Alive");
await writer.WriteLineAsync();
await writer.FlushAsync();
writer.Close();
}
using (var reader = new CustomBinaryReader(stream))
{
var result = await reader.ReadLineAsync().ConfigureAwait(false);
if (!result.ToLower().Contains("200 connection established"))
throw new Exception("Upstream proxy failed to create a secure tunnel");
await reader.ReadAllLinesAsync().ConfigureAwait(false);
}
}
else
{
......@@ -144,7 +148,7 @@ namespace Titanium.Web.Proxy.Network
port = port,
IsSecure = isSecure,
TcpClient = client,
ServerStreamReader = new CustomBinaryReader(stream),
StreamReader = new CustomBinaryReader(stream),
Stream = stream,
Version = version
};
......@@ -178,6 +182,5 @@ namespace Titanium.Web.Proxy.Network
}
}
}
......@@ -154,7 +154,7 @@ namespace Titanium.Web.Proxy
CertManager = new CertificateManager(RootCertificateIssuerName,
RootCertificateName);
certTrusted = CertManager.CreateTrustedRootCertificate();
certTrusted = CertManager.CreateTrustedRootCertificate().Result;
foreach (var endPoint in ProxyEndPoints)
{
......@@ -222,18 +222,21 @@ namespace Titanium.Web.Proxy
{
var client = endPoint.listener.EndAcceptTcpClient(asyn);
if (endPoint.GetType() == typeof(TransparentProxyEndPoint))
Task.Factory.StartNew(() => HandleClient(endPoint as TransparentProxyEndPoint, client));
HandleClient(endPoint as TransparentProxyEndPoint, client);
else
Task.Factory.StartNew(() => HandleClient(endPoint as ExplicitProxyEndPoint, client));
HandleClient(endPoint as ExplicitProxyEndPoint, client);
// Get the listener that handles the client request.
endPoint.listener.BeginAcceptTcpClient(OnAcceptConnection, endPoint);
}
catch
catch (ObjectDisposedException)
{
// ignored
// The listener was Stop()'d, disposing the underlying socket and
// triggering the completion of the callback. We're already exiting,
// so just return.
return;
}
}
}
......
......@@ -67,7 +67,7 @@ namespace Titanium.Web.Proxy
await WriteConnectResponse(clientStreamWriter, httpVersion).ConfigureAwait(false);
var certificate = CertManager.CreateCertificate(httpRemoteUri.Host);
var certificate = await CertManager.CreateCertificate(httpRemoteUri.Host);
SslStream sslStream = null;
......@@ -139,7 +139,7 @@ namespace Titanium.Web.Proxy
// certificate = CertManager.CreateCertificate(hostName);
//}
//else
certificate = CertManager.CreateCertificate(endPoint.GenericCertificateName);
certificate = await CertManager.CreateCertificate(endPoint.GenericCertificateName);
try
{
......@@ -281,13 +281,13 @@ namespace Titanium.Web.Proxy
{
WriteResponseStatus(args.WebSession.Response.HttpVersion, "100",
"Continue", args.Client.ClientStreamWriter);
args.Client.ClientStreamWriter.WriteLine();
await args.Client.ClientStreamWriter.WriteLineAsync();
}
else if (args.WebSession.Request.ExpectationFailed)
{
WriteResponseStatus(args.WebSession.Response.HttpVersion, "417",
"Expectation Failed", args.Client.ClientStreamWriter);
args.Client.ClientStreamWriter.WriteLine();
await args.Client.ClientStreamWriter.WriteLineAsync();
}
if (!args.WebSession.Request.ExpectContinue)
......@@ -299,8 +299,14 @@ namespace Titanium.Web.Proxy
//If request was modified by user
if (args.WebSession.Request.RequestBodyRead)
{
if(args.WebSession.Request.ContentEncoding!=null)
{
args.WebSession.Request.RequestBody = await GetCompressedResponseBody(args.WebSession.Request.ContentEncoding, args.WebSession.Request.RequestBody);
}
args.WebSession.Request.ContentLength = args.WebSession.Request.RequestBody.Length;
var newStream = args.WebSession.ProxyClient.Stream;
var newStream = args.WebSession.ServerConnection.Stream;
await newStream.WriteAsync(args.WebSession.Request.RequestBody, 0, args.WebSession.Request.RequestBody.Length).ConfigureAwait(false);
}
else
......@@ -392,7 +398,7 @@ namespace Titanium.Web.Proxy
private static async Task SendClientRequestBody(SessionEventArgs args)
{
// End the operation
var postStream = args.WebSession.ProxyClient.Stream;
var postStream = args.WebSession.ServerConnection.Stream;
if (args.WebSession.Request.ContentLength > 0)
{
......@@ -466,8 +472,6 @@ namespace Titanium.Web.Proxy
if (sslPolicyErrors == SslPolicyErrors.None)
return true;
Console.WriteLine("Certificate error: {0}", sslPolicyErrors);
//By default
//do not allow this client to communicate with unauthenticated servers.
return false;
......
......@@ -24,7 +24,7 @@ namespace Titanium.Web.Proxy
try
{
if (!args.WebSession.Response.ResponseBodyRead)
args.WebSession.Response.ResponseStream = args.WebSession.ProxyClient.Stream;
args.WebSession.Response.ResponseStream = args.WebSession.ServerConnection.Stream;
if (BeforeResponse != null && !args.WebSession.Response.ResponseLocked)
......@@ -46,13 +46,13 @@ namespace Titanium.Web.Proxy
{
WriteResponseStatus(args.WebSession.Response.HttpVersion, "100",
"Continue", args.Client.ClientStreamWriter);
args.Client.ClientStreamWriter.WriteLine();
await args.Client.ClientStreamWriter.WriteLineAsync();
}
else if (args.WebSession.Response.ExpectationFailed)
{
WriteResponseStatus(args.WebSession.Response.HttpVersion, "417",
"Expectation Failed", args.Client.ClientStreamWriter);
args.Client.ClientStreamWriter.WriteLine();
await args.Client.ClientStreamWriter.WriteLineAsync();
}
WriteResponseStatus(args.WebSession.Response.HttpVersion, args.WebSession.Response.ResponseStatusCode,
......@@ -68,19 +68,20 @@ namespace Titanium.Web.Proxy
args.WebSession.Response.ResponseBody = await GetCompressedResponseBody(contentEncoding, args.WebSession.Response.ResponseBody).ConfigureAwait(false);
}
await WriteResponseHeaders(args.Client.ClientStreamWriter, args.WebSession.Response.ResponseHeaders, args.WebSession.Response.ResponseBody.Length,
isChunked).ConfigureAwait(false);
await WriteResponseBody(args.Client.ClientStream, args.WebSession.Response.ResponseBody, isChunked).ConfigureAwait(false);
args.WebSession.Response.ContentLength = args.WebSession.Response.ResponseBody.Length;
await WriteResponseHeaders(args.Client.ClientStreamWriter, args.WebSession.Response.ResponseHeaders).ConfigureAwait(false);
await WriteResponseBody(args.Client.ClientStream, args.WebSession.Response.ResponseBody, isChunked).ConfigureAwait(false);
}
else
{
WriteResponseHeaders(args.Client.ClientStreamWriter, args.WebSession.Response.ResponseHeaders);
await WriteResponseHeaders(args.Client.ClientStreamWriter, args.WebSession.Response.ResponseHeaders);
if (args.WebSession.Response.IsChunked || args.WebSession.Response.ContentLength > 0)
await WriteResponseBody(args.WebSession.ProxyClient.ServerStreamReader, args.Client.ClientStream, args.WebSession.Response.IsChunked, args.WebSession.Response.ContentLength).ConfigureAwait(false);
if (args.WebSession.Response.IsChunked || args.WebSession.Response.ContentLength > 0 || args.WebSession.Response.HttpVersion.ToLower().Trim() == "http/1.0")
await WriteResponseBody(args.WebSession.ServerConnection.StreamReader, args.Client.ClientStream, args.WebSession.Response.IsChunked, args.WebSession.Response.ContentLength).ConfigureAwait(false);
}
args.Client.ClientStream.Flush();
await args.Client.ClientStream.FlushAsync();
}
catch
......@@ -104,10 +105,10 @@ namespace Titanium.Web.Proxy
private static void WriteResponseStatus(string version, string code, string description,
StreamWriter responseWriter)
{
responseWriter.WriteLine(string.Format("{0} {1} {2}", version, code, description));
responseWriter.WriteLineAsync(string.Format("{0} {1} {2}", version, code, description));
}
private static void WriteResponseHeaders(StreamWriter responseWriter, List<HttpHeader> headers)
private static async Task WriteResponseHeaders(StreamWriter responseWriter, List<HttpHeader> headers)
{
if (headers != null)
{
......@@ -115,12 +116,12 @@ namespace Titanium.Web.Proxy
foreach (var header in headers)
{
responseWriter.WriteLine(header.ToString());
await responseWriter.WriteLineAsync(header.ToString());
}
}
responseWriter.WriteLine();
responseWriter.Flush();
await responseWriter.WriteLineAsync();
await responseWriter.FlushAsync();
}
private static void FixResponseProxyHeaders(List<HttpHeader> headers)
{
......@@ -141,34 +142,6 @@ namespace Titanium.Web.Proxy
headers.RemoveAll(x => x.Name.ToLower() == "proxy-connection");
}
private static async Task WriteResponseHeaders(StreamWriter responseWriter, List<HttpHeader> headers, int length,
bool isChunked)
{
FixResponseProxyHeaders(headers);
if (!isChunked)
{
if (headers.Any(x => x.Name.ToLower() == "content-length") == false)
{
headers.Add(new HttpHeader("Content-Length", length.ToString()));
}
}
if (headers != null)
{
foreach (var header in headers)
{
if (!isChunked && header.Name.ToLower() == "content-length")
header.Value = length.ToString();
await responseWriter.WriteLineAsync(header.ToString()).ConfigureAwait(false);
}
}
await responseWriter.WriteLineAsync().ConfigureAwait(false);
await responseWriter.FlushAsync().ConfigureAwait(false);
}
private static async Task WriteResponseBody(Stream clientStream, byte[] data, bool isChunked)
{
if (!isChunked)
......@@ -183,6 +156,10 @@ namespace Titanium.Web.Proxy
{
if (!isChunked)
{
//http 1.0
if (ContentLength == -1)
ContentLength = long.MaxValue;
int bytesToRead = Constants.BUFFER_SIZE;
if (ContentLength < Constants.BUFFER_SIZE)
......
......@@ -61,7 +61,7 @@
<Compile Include="Decompression\IDecompression.cs" />
<Compile Include="Decompression\ZlibDecompression.cs" />
<Compile Include="EventArguments\CertificateValidationEventArgs.cs" />
<Compile Include="EventArguments\ProxyClient.cs" />
<Compile Include="Network\ProxyClient.cs" />
<Compile Include="Exceptions\BodyNotFoundException.cs" />
<Compile Include="Extensions\HttpWebResponseExtensions.cs" />
<Compile Include="Extensions\HttpWebRequestExtensions.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