Commit 4b86cde8 authored by justcoding121's avatar justcoding121

asyncify more

parent ff0dddf4
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Net; using System.Net;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Titanium.Web.Proxy.EventArguments; using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
...@@ -13,7 +14,7 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -13,7 +14,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
{ {
ProxyServer.BeforeRequest += OnRequest; ProxyServer.BeforeRequest += OnRequest;
ProxyServer.BeforeResponse += OnResponse; ProxyServer.BeforeResponse += OnResponse;
ProxyServer.RemoteCertificateValidationCallback += OnCertificateValidation; ProxyServer.ServerCertificateValidationCallback += OnCertificateValidation;
//Exclude Https addresses you don't want to proxy //Exclude Https addresses you don't want to proxy
//Usefull for clients that use certificate pinning //Usefull for clients that use certificate pinning
...@@ -61,9 +62,8 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -61,9 +62,8 @@ namespace Titanium.Web.Proxy.Examples.Basic
ProxyServer.Stop(); ProxyServer.Stop();
} }
//Test On Request, intecept requests //intecept & cancel, redirect or update requests
//Read browser URL send back to proxy by the injection script in OnResponse event public async Task OnRequest(object sender, SessionEventArgs e)
public void OnRequest(object sender, SessionEventArgs e)
{ {
Console.WriteLine(e.WebSession.Request.Url); Console.WriteLine(e.WebSession.Request.Url);
...@@ -73,12 +73,12 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -73,12 +73,12 @@ namespace Titanium.Web.Proxy.Examples.Basic
if ((e.WebSession.Request.Method.ToUpper() == "POST" || e.WebSession.Request.Method.ToUpper() == "PUT")) if ((e.WebSession.Request.Method.ToUpper() == "POST" || e.WebSession.Request.Method.ToUpper() == "PUT"))
{ {
//Get/Set request body bytes //Get/Set request body bytes
byte[] bodyBytes = e.GetRequestBody(); byte[] bodyBytes = await e.GetRequestBody();
e.SetRequestBody(bodyBytes); await e.SetRequestBody(bodyBytes);
//Get/Set request body as string //Get/Set request body as string
string bodyString = e.GetRequestBodyAsString(); string bodyString = await e.GetRequestBodyAsString();
e.SetRequestBodyString(bodyString); await e.SetRequestBodyString(bodyString);
} }
...@@ -86,7 +86,7 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -86,7 +86,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
//Filter URL //Filter URL
if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("google.com")) if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("google.com"))
{ {
e.Ok("<!DOCTYPE html>" + await e.Ok("<!DOCTYPE html>" +
"<html><body><h1>" + "<html><body><h1>" +
"Website Blocked" + "Website Blocked" +
"</h1>" + "</h1>" +
...@@ -97,15 +97,13 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -97,15 +97,13 @@ namespace Titanium.Web.Proxy.Examples.Basic
//Redirect example //Redirect example
if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("wikipedia.org")) if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("wikipedia.org"))
{ {
e.Redirect("https://www.paypal.com"); await e.Redirect("https://www.paypal.com");
} }
} }
//Test script injection //Modify response
//Insert script to read the Browser URL and send it back to proxy public async Task OnResponse(object sender, SessionEventArgs e)
public void OnResponse(object sender, SessionEventArgs e)
{ {
//read response headers //read response headers
var responseHeaders = e.WebSession.Response.ResponseHeaders; var responseHeaders = e.WebSession.Response.ResponseHeaders;
...@@ -116,11 +114,11 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -116,11 +114,11 @@ namespace Titanium.Web.Proxy.Examples.Basic
{ {
if (e.WebSession.Response.ContentType.Trim().ToLower().Contains("text/html")) if (e.WebSession.Response.ContentType.Trim().ToLower().Contains("text/html"))
{ {
byte[] bodyBytes = e.GetResponseBody(); byte[] bodyBytes = await e.GetResponseBody();
e.SetResponseBody(bodyBytes); await e.SetResponseBody(bodyBytes);
string body = e.GetResponseBodyAsString(); string body = await e.GetResponseBodyAsString();
e.SetResponseBodyString(body); await e.SetResponseBodyString(body);
} }
} }
} }
...@@ -131,13 +129,13 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -131,13 +129,13 @@ namespace Titanium.Web.Proxy.Examples.Basic
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="sender"></param>
/// <param name="e"></param> /// <param name="e"></param>
public void OnCertificateValidation(object sender, CertificateValidationEventArgs e) public async Task OnCertificateValidation(object sender, CertificateValidationEventArgs e)
{ {
//set IsValid to true/false based on Certificate Errors //set IsValid to true/false based on Certificate Errors
if (e.SslPolicyErrors == System.Net.Security.SslPolicyErrors.None) if (e.SslPolicyErrors == System.Net.Security.SslPolicyErrors.None)
e.IsValid = true; e.IsValid = true;
else else
e.Session.Ok("Cannot validate server certificate! Not safe to proceed."); await e.Session.Ok("Cannot validate server certificate! Not safe to proceed.");
} }
} }
} }
\ No newline at end of file
...@@ -34,7 +34,7 @@ Setup HTTP proxy: ...@@ -34,7 +34,7 @@ Setup HTTP proxy:
```csharp ```csharp
ProxyServer.BeforeRequest += OnRequest; ProxyServer.BeforeRequest += OnRequest;
ProxyServer.BeforeResponse += OnResponse; ProxyServer.BeforeResponse += OnResponse;
ProxyServer.RemoteCertificateValidationCallback += OnCertificateValidation; ProxyServer.ServerCertificateValidationCallback += OnCertificateValidation;
//Exclude Https addresses you don't want to proxy //Exclude Https addresses you don't want to proxy
//Usefull for clients that use certificate pinning //Usefull for clients that use certificate pinning
...@@ -62,7 +62,6 @@ Setup HTTP proxy: ...@@ -62,7 +62,6 @@ Setup HTTP proxy:
}; };
ProxyServer.AddEndPoint(transparentEndPoint); ProxyServer.AddEndPoint(transparentEndPoint);
//ProxyServer.UpStreamHttpProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 }; //ProxyServer.UpStreamHttpProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 };
//ProxyServer.UpStreamHttpsProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 }; //ProxyServer.UpStreamHttpsProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 };
...@@ -87,7 +86,8 @@ Sample request and response event handlers ...@@ -87,7 +86,8 @@ Sample request and response event handlers
```csharp ```csharp
public void OnRequest(object sender, SessionEventArgs e) //intecept & cancel, redirect or update requests
public async Task OnRequest(object sender, SessionEventArgs e)
{ {
Console.WriteLine(e.WebSession.Request.Url); Console.WriteLine(e.WebSession.Request.Url);
...@@ -97,12 +97,12 @@ Sample request and response event handlers ...@@ -97,12 +97,12 @@ Sample request and response event handlers
if ((e.WebSession.Request.Method.ToUpper() == "POST" || e.WebSession.Request.Method.ToUpper() == "PUT")) if ((e.WebSession.Request.Method.ToUpper() == "POST" || e.WebSession.Request.Method.ToUpper() == "PUT"))
{ {
//Get/Set request body bytes //Get/Set request body bytes
byte[] bodyBytes = e.GetRequestBody(); byte[] bodyBytes = await e.GetRequestBody();
e.SetRequestBody(bodyBytes); await e.SetRequestBody(bodyBytes);
//Get/Set request body as string //Get/Set request body as string
string bodyString = e.GetRequestBodyAsString(); string bodyString = await e.GetRequestBodyAsString();
e.SetRequestBodyString(bodyString); await e.SetRequestBodyString(bodyString);
} }
...@@ -110,7 +110,7 @@ Sample request and response event handlers ...@@ -110,7 +110,7 @@ Sample request and response event handlers
//Filter URL //Filter URL
if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("google.com")) if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("google.com"))
{ {
e.Ok("<!DOCTYPE html>" + await e.Ok("<!DOCTYPE html>" +
"<html><body><h1>" + "<html><body><h1>" +
"Website Blocked" + "Website Blocked" +
"</h1>" + "</h1>" +
...@@ -121,13 +121,13 @@ Sample request and response event handlers ...@@ -121,13 +121,13 @@ Sample request and response event handlers
//Redirect example //Redirect example
if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("wikipedia.org")) if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("wikipedia.org"))
{ {
e.Redirect("https://www.paypal.com"); await e.Redirect("https://www.paypal.com");
} }
} }
public void OnResponse(object sender, SessionEventArgs e) //Modify response
public async Task OnResponse(object sender, SessionEventArgs e)
{ {
//read response headers //read response headers
var responseHeaders = e.WebSession.Response.ResponseHeaders; var responseHeaders = e.WebSession.Response.ResponseHeaders;
...@@ -138,24 +138,28 @@ Sample request and response event handlers ...@@ -138,24 +138,28 @@ Sample request and response event handlers
{ {
if (e.WebSession.Response.ContentType.Trim().ToLower().Contains("text/html")) if (e.WebSession.Response.ContentType.Trim().ToLower().Contains("text/html"))
{ {
byte[] bodyBytes = e.GetResponseBody(); byte[] bodyBytes = await e.GetResponseBody();
e.SetResponseBody(bodyBytes); await e.SetResponseBody(bodyBytes);
string body = e.GetResponseBodyAsString(); string body = await e.GetResponseBodyAsString();
e.SetResponseBodyString(body); await e.SetResponseBodyString(body);
} }
} }
} }
} }
// Allows overriding default certificate validation logic /// <summary>
public void OnCertificateValidation(object sender, CertificateValidationEventArgs e) /// Allows overriding default certificate validation logic
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public async Task OnCertificateValidation(object sender, CertificateValidationEventArgs e)
{ {
//set IsValid to true/false based on Certificate Errors //set IsValid to true/false based on Certificate Errors
if (e.SslPolicyErrors == System.Net.Security.SslPolicyErrors.None) if (e.SslPolicyErrors == System.Net.Security.SslPolicyErrors.None)
e.IsValid = true; e.IsValid = true;
else else
e.Session.Ok("Cannot validate server certificate! Not safe to proceed."); await e.Session.Ok("Cannot validate server certificate! Not safe to proceed.");
} }
``` ```
Future roadmap Future roadmap
......
using System.IO; using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Compression namespace Titanium.Web.Proxy.Compression
{ {
class DeflateCompression : ICompression class DeflateCompression : ICompression
{ {
public byte[] Compress(byte[] responseBody) public async Task<byte[]> Compress(byte[] responseBody)
{ {
using (var ms = new MemoryStream()) using (var ms = new MemoryStream())
{ {
using (var zip = new DeflateStream(ms, CompressionMode.Compress, true)) using (var zip = new DeflateStream(ms, CompressionMode.Compress, true))
{ {
zip.Write(responseBody, 0, responseBody.Length); await zip.WriteAsync(responseBody, 0, responseBody.Length).ConfigureAwait(false);
} }
return ms.ToArray(); return ms.ToArray();
......
using Ionic.Zlib; using Ionic.Zlib;
using System.IO; using System.IO;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Compression namespace Titanium.Web.Proxy.Compression
{ {
class GZipCompression : ICompression class GZipCompression : ICompression
{ {
public byte[] Compress(byte[] responseBody) public async Task<byte[]> Compress(byte[] responseBody)
{ {
using (var ms = new MemoryStream()) using (var ms = new MemoryStream())
{ {
using (var zip = new GZipStream(ms, CompressionMode.Compress, true)) using (var zip = new GZipStream(ms, CompressionMode.Compress, true))
{ {
zip.Write(responseBody, 0, responseBody.Length); await zip.WriteAsync(responseBody, 0, responseBody.Length).ConfigureAwait(false);
} }
return ms.ToArray(); return ms.ToArray();
......
namespace Titanium.Web.Proxy.Compression using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Compression
{ {
interface ICompression interface ICompression
{ {
byte[] Compress(byte[] responseBody); Task<byte[]> Compress(byte[] responseBody);
} }
} }
using Ionic.Zlib; using Ionic.Zlib;
using System.IO; using System.IO;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Compression namespace Titanium.Web.Proxy.Compression
{ {
class ZlibCompression : ICompression class ZlibCompression : ICompression
{ {
public byte[] Compress(byte[] responseBody) public async Task<byte[]> Compress(byte[] responseBody)
{ {
using (var ms = new MemoryStream()) using (var ms = new MemoryStream())
{ {
using (var zip = new ZlibStream(ms, CompressionMode.Compress, true)) using (var zip = new ZlibStream(ms, CompressionMode.Compress, true))
{ {
zip.Write(responseBody, 0, responseBody.Length); await zip.WriteAsync(responseBody, 0, responseBody.Length).ConfigureAwait(false);
} }
return ms.ToArray(); return ms.ToArray();
......
namespace Titanium.Web.Proxy.Decompression using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Decompression
{ {
class DefaultDecompression : IDecompression class DefaultDecompression : IDecompression
{ {
public byte[] Decompress(byte[] compressedArray) public Task<byte[]> Decompress(byte[] compressedArray)
{ {
return compressedArray; return Task.FromResult(compressedArray);
} }
} }
} }
using Ionic.Zlib; using Ionic.Zlib;
using System.IO; using System.IO;
using System.Threading.Tasks;
using Titanium.Web.Proxy.Shared; using Titanium.Web.Proxy.Shared;
namespace Titanium.Web.Proxy.Decompression namespace Titanium.Web.Proxy.Decompression
{ {
class DeflateDecompression : IDecompression class DeflateDecompression : IDecompression
{ {
public byte[] Decompress(byte[] compressedArray) public async Task<byte[]> Decompress(byte[] compressedArray)
{ {
var stream = new MemoryStream(compressedArray); var stream = new MemoryStream(compressedArray);
...@@ -17,9 +18,9 @@ namespace Titanium.Web.Proxy.Decompression ...@@ -17,9 +18,9 @@ namespace Titanium.Web.Proxy.Decompression
using (var output = new MemoryStream()) using (var output = new MemoryStream())
{ {
int read; int read;
while ((read = decompressor.Read(buffer, 0, buffer.Length)) > 0) while ((read = await decompressor.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false)) > 0)
{ {
output.Write(buffer, 0, read); await output.WriteAsync(buffer, 0, read).ConfigureAwait(false);
} }
return output.ToArray(); return output.ToArray();
......
using System.IO; using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.Threading.Tasks;
using Titanium.Web.Proxy.Shared; using Titanium.Web.Proxy.Shared;
namespace Titanium.Web.Proxy.Decompression namespace Titanium.Web.Proxy.Decompression
{ {
class GZipDecompression : IDecompression class GZipDecompression : IDecompression
{ {
public byte[] Decompress(byte[] compressedArray) public async Task<byte[]> Decompress(byte[] compressedArray)
{ {
using (var decompressor = new GZipStream(new MemoryStream(compressedArray), CompressionMode.Decompress)) using (var decompressor = new GZipStream(new MemoryStream(compressedArray), CompressionMode.Decompress))
{ {
...@@ -14,9 +15,9 @@ namespace Titanium.Web.Proxy.Decompression ...@@ -14,9 +15,9 @@ namespace Titanium.Web.Proxy.Decompression
using (var output = new MemoryStream()) using (var output = new MemoryStream())
{ {
int read; int read;
while ((read = decompressor.Read(buffer, 0, buffer.Length)) > 0) while ((read = await decompressor.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false)) > 0)
{ {
output.Write(buffer, 0, read); await output.WriteAsync(buffer, 0, read).ConfigureAwait(false);
} }
return output.ToArray(); return output.ToArray();
} }
......
using System.IO; using System.IO;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Decompression namespace Titanium.Web.Proxy.Decompression
{ {
interface IDecompression interface IDecompression
{ {
byte[] Decompress(byte[] compressedArray); Task<byte[]> Decompress(byte[] compressedArray);
} }
} }
using Ionic.Zlib; using Ionic.Zlib;
using System.IO; using System.IO;
using System.Threading.Tasks;
using Titanium.Web.Proxy.Shared; using Titanium.Web.Proxy.Shared;
namespace Titanium.Web.Proxy.Decompression namespace Titanium.Web.Proxy.Decompression
{ {
class ZlibDecompression : IDecompression class ZlibDecompression : IDecompression
{ {
public byte[] Decompress(byte[] compressedArray) public async Task<byte[]> Decompress(byte[] compressedArray)
{ {
var memoryStream = new MemoryStream(compressedArray); var memoryStream = new MemoryStream(compressedArray);
using (var decompressor = new ZlibStream(memoryStream, CompressionMode.Decompress)) using (var decompressor = new ZlibStream(memoryStream, CompressionMode.Decompress))
...@@ -16,9 +17,9 @@ namespace Titanium.Web.Proxy.Decompression ...@@ -16,9 +17,9 @@ namespace Titanium.Web.Proxy.Decompression
using (var output = new MemoryStream()) using (var output = new MemoryStream())
{ {
int read; int read;
while ((read = decompressor.Read(buffer, 0, buffer.Length)) > 0) while ((read = await decompressor.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false)) > 0)
{ {
output.Write(buffer, 0, read); await output.WriteAsync(buffer, 0, read).ConfigureAwait(false);
} }
return output.ToArray(); return output.ToArray();
} }
......
...@@ -6,6 +6,7 @@ using Titanium.Web.Proxy.Decompression; ...@@ -6,6 +6,7 @@ using Titanium.Web.Proxy.Decompression;
using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Http.Responses; using Titanium.Web.Proxy.Http.Responses;
using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Extensions;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.EventArguments namespace Titanium.Web.Proxy.EventArguments
{ {
...@@ -54,7 +55,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -54,7 +55,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary> /// <summary>
/// Read request body content as bytes[] for current session /// Read request body content as bytes[] for current session
/// </summary> /// </summary>
private void ReadRequestBody() private async Task ReadRequestBody()
{ {
//GET request don't have a request body to read //GET request don't have a request body to read
if ((WebSession.Request.Method.ToUpper() != "POST" && WebSession.Request.Method.ToUpper() != "PUT")) if ((WebSession.Request.Method.ToUpper() != "POST" && WebSession.Request.Method.ToUpper() != "PUT"))
...@@ -74,7 +75,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -74,7 +75,7 @@ namespace Titanium.Web.Proxy.EventArguments
//For chunked request we need to read data as they arrive, until we reach a chunk end symbol //For chunked request we need to read data as they arrive, until we reach a chunk end symbol
if (WebSession.Request.IsChunked) if (WebSession.Request.IsChunked)
{ {
this.Client.ClientStreamReader.CopyBytesToStreamChunked(requestBodyStream); await this.Client.ClientStreamReader.CopyBytesToStreamChunked(requestBodyStream).ConfigureAwait(false);
} }
else else
{ {
...@@ -82,11 +83,11 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -82,11 +83,11 @@ namespace Titanium.Web.Proxy.EventArguments
if (WebSession.Request.ContentLength > 0) if (WebSession.Request.ContentLength > 0)
{ {
//If not chunked then its easy just read the amount of bytes mentioned in content length header of response //If not chunked then its easy just read the amount of bytes mentioned in content length header of response
this.Client.ClientStreamReader.CopyBytesToStream(requestBodyStream, WebSession.Request.ContentLength); await this.Client.ClientStreamReader.CopyBytesToStream(requestBodyStream, WebSession.Request.ContentLength).ConfigureAwait(false);
} }
} }
WebSession.Request.RequestBody = GetDecompressedResponseBody(WebSession.Request.ContentEncoding, requestBodyStream.ToArray()); WebSession.Request.RequestBody = await GetDecompressedResponseBody(WebSession.Request.ContentEncoding, requestBodyStream.ToArray()).ConfigureAwait(false);
} }
} }
...@@ -98,7 +99,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -98,7 +99,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary> /// <summary>
/// Read response body as byte[] for current response /// Read response body as byte[] for current response
/// </summary> /// </summary>
private void ReadResponseBody() private async Task ReadResponseBody()
{ {
//If not already read (not cached yet) //If not already read (not cached yet)
if (WebSession.Response.ResponseBody == null) if (WebSession.Response.ResponseBody == null)
...@@ -108,19 +109,19 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -108,19 +109,19 @@ namespace Titanium.Web.Proxy.EventArguments
//If chuncked the read chunk by chunk until we hit chunk end symbol //If chuncked the read chunk by chunk until we hit chunk end symbol
if (WebSession.Response.IsChunked) if (WebSession.Response.IsChunked)
{ {
WebSession.ProxyClient.ServerStreamReader.CopyBytesToStreamChunked(responseBodyStream); await WebSession.ProxyClient.ServerStreamReader.CopyBytesToStreamChunked(responseBodyStream).ConfigureAwait(false);
} }
else else
{ {
if (WebSession.Response.ContentLength > 0) if (WebSession.Response.ContentLength > 0)
{ {
//If not chunked then its easy just read the amount of bytes mentioned in content length header of response //If not chunked then its easy just read the amount of bytes mentioned in content length header of response
WebSession.ProxyClient.ServerStreamReader.CopyBytesToStream(responseBodyStream, WebSession.Response.ContentLength); await WebSession.ProxyClient.ServerStreamReader.CopyBytesToStream(responseBodyStream, WebSession.Response.ContentLength).ConfigureAwait(false);
} }
} }
WebSession.Response.ResponseBody = GetDecompressedResponseBody(WebSession.Response.ContentEncoding, responseBodyStream.ToArray()); WebSession.Response.ResponseBody = await GetDecompressedResponseBody(WebSession.Response.ContentEncoding, responseBodyStream.ToArray()).ConfigureAwait(false);
} }
//set this to true for caching //set this to true for caching
...@@ -132,25 +133,25 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -132,25 +133,25 @@ namespace Titanium.Web.Proxy.EventArguments
/// Gets the request body as bytes /// Gets the request body as bytes
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public byte[] GetRequestBody() public async Task<byte[]> GetRequestBody()
{ {
if (WebSession.Request.RequestLocked) if (WebSession.Request.RequestLocked)
throw new Exception("You cannot call this function after request is made to server."); throw new Exception("You cannot call this function after request is made to server.");
ReadRequestBody(); await ReadRequestBody().ConfigureAwait(false);
return WebSession.Request.RequestBody; return WebSession.Request.RequestBody;
} }
/// <summary> /// <summary>
/// Gets the request body as string /// Gets the request body as string
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public string GetRequestBodyAsString() public async Task<string> GetRequestBodyAsString()
{ {
if (WebSession.Request.RequestLocked) if (WebSession.Request.RequestLocked)
throw new Exception("You cannot call this function after request is made to server."); throw new Exception("You cannot call this function after request is made to server.");
ReadRequestBody(); await ReadRequestBody().ConfigureAwait(false);
//Use the encoding specified in request to decode the byte[] data to string //Use the encoding specified in request to decode the byte[] data to string
return WebSession.Request.RequestBodyString ?? (WebSession.Request.RequestBodyString = WebSession.Request.Encoding.GetString(WebSession.Request.RequestBody)); return WebSession.Request.RequestBodyString ?? (WebSession.Request.RequestBodyString = WebSession.Request.Encoding.GetString(WebSession.Request.RequestBody));
...@@ -160,7 +161,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -160,7 +161,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// Sets the request body /// Sets the request body
/// </summary> /// </summary>
/// <param name="body"></param> /// <param name="body"></param>
public void SetRequestBody(byte[] body) public async Task SetRequestBody(byte[] body)
{ {
if (WebSession.Request.RequestLocked) if (WebSession.Request.RequestLocked)
throw new Exception("You cannot call this function after request is made to server."); throw new Exception("You cannot call this function after request is made to server.");
...@@ -168,7 +169,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -168,7 +169,7 @@ namespace Titanium.Web.Proxy.EventArguments
//syphon out the request body from client before setting the new body //syphon out the request body from client before setting the new body
if (!WebSession.Request.RequestBodyRead) if (!WebSession.Request.RequestBodyRead)
{ {
ReadRequestBody(); await ReadRequestBody().ConfigureAwait(false);
} }
WebSession.Request.RequestBody = body; WebSession.Request.RequestBody = body;
...@@ -179,7 +180,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -179,7 +180,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// Sets the body with the specified string /// Sets the body with the specified string
/// </summary> /// </summary>
/// <param name="body"></param> /// <param name="body"></param>
public void SetRequestBodyString(string body) public async Task SetRequestBodyString(string body)
{ {
if (WebSession.Request.RequestLocked) if (WebSession.Request.RequestLocked)
throw new Exception("You cannot call this function after request is made to server."); throw new Exception("You cannot call this function after request is made to server.");
...@@ -187,7 +188,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -187,7 +188,7 @@ namespace Titanium.Web.Proxy.EventArguments
//syphon out the request body from client before setting the new body //syphon out the request body from client before setting the new body
if (!WebSession.Request.RequestBodyRead) if (!WebSession.Request.RequestBodyRead)
{ {
ReadRequestBody(); await ReadRequestBody().ConfigureAwait(false);
} }
WebSession.Request.RequestBody = WebSession.Request.Encoding.GetBytes(body); WebSession.Request.RequestBody = WebSession.Request.Encoding.GetBytes(body);
...@@ -203,12 +204,12 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -203,12 +204,12 @@ namespace Titanium.Web.Proxy.EventArguments
/// Gets the response body as byte array /// Gets the response body as byte array
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public byte[] GetResponseBody() public async Task<byte[]> GetResponseBody()
{ {
if (!WebSession.Request.RequestLocked) if (!WebSession.Request.RequestLocked)
throw new Exception("You cannot call this function before request is made to server."); throw new Exception("You cannot call this function before request is made to server.");
ReadResponseBody(); await ReadResponseBody().ConfigureAwait(false);
return WebSession.Response.ResponseBody; return WebSession.Response.ResponseBody;
} }
...@@ -216,12 +217,12 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -216,12 +217,12 @@ namespace Titanium.Web.Proxy.EventArguments
/// Gets the response body as string /// Gets the response body as string
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public string GetResponseBodyAsString() public async Task<string> GetResponseBodyAsString()
{ {
if (!WebSession.Request.RequestLocked) if (!WebSession.Request.RequestLocked)
throw new Exception("You cannot call this function before request is made to server."); throw new Exception("You cannot call this function before request is made to server.");
GetResponseBody(); await GetResponseBody().ConfigureAwait(false);
return WebSession.Response.ResponseBodyString ?? (WebSession.Response.ResponseBodyString = WebSession.Response.Encoding.GetString(WebSession.Response.ResponseBody)); return WebSession.Response.ResponseBodyString ?? (WebSession.Response.ResponseBodyString = WebSession.Response.Encoding.GetString(WebSession.Response.ResponseBody));
} }
...@@ -230,7 +231,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -230,7 +231,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// Set the response body bytes /// Set the response body bytes
/// </summary> /// </summary>
/// <param name="body"></param> /// <param name="body"></param>
public void SetResponseBody(byte[] body) public async Task SetResponseBody(byte[] body)
{ {
if (!WebSession.Request.RequestLocked) if (!WebSession.Request.RequestLocked)
throw new Exception("You cannot call this function before request is made to server."); throw new Exception("You cannot call this function before request is made to server.");
...@@ -238,7 +239,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -238,7 +239,7 @@ namespace Titanium.Web.Proxy.EventArguments
//syphon out the response body from server before setting the new body //syphon out the response body from server before setting the new body
if (WebSession.Response.ResponseBody == null) if (WebSession.Response.ResponseBody == null)
{ {
GetResponseBody(); await GetResponseBody().ConfigureAwait(false);
} }
WebSession.Response.ResponseBody = body; WebSession.Response.ResponseBody = body;
...@@ -253,7 +254,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -253,7 +254,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// Replace the response body with the specified string /// Replace the response body with the specified string
/// </summary> /// </summary>
/// <param name="body"></param> /// <param name="body"></param>
public void SetResponseBodyString(string body) public async Task SetResponseBodyString(string body)
{ {
if (!WebSession.Request.RequestLocked) if (!WebSession.Request.RequestLocked)
throw new Exception("You cannot call this function before request is made to server."); throw new Exception("You cannot call this function before request is made to server.");
...@@ -261,19 +262,19 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -261,19 +262,19 @@ namespace Titanium.Web.Proxy.EventArguments
//syphon out the response body from server before setting the new body //syphon out the response body from server before setting the new body
if (WebSession.Response.ResponseBody == null) if (WebSession.Response.ResponseBody == null)
{ {
GetResponseBody(); await GetResponseBody().ConfigureAwait(false);
} }
var bodyBytes = WebSession.Response.Encoding.GetBytes(body); var bodyBytes = WebSession.Response.Encoding.GetBytes(body);
SetResponseBody(bodyBytes); await SetResponseBody(bodyBytes).ConfigureAwait(false);
} }
private byte[] GetDecompressedResponseBody(string encodingType, byte[] responseBodyStream) private async Task<byte[]> GetDecompressedResponseBody(string encodingType, byte[] responseBodyStream)
{ {
var decompressionFactory = new DecompressionFactory(); var decompressionFactory = new DecompressionFactory();
var decompressor = decompressionFactory.Create(encodingType); var decompressor = decompressionFactory.Create(encodingType);
return decompressor.Decompress(responseBodyStream); return await decompressor.Decompress(responseBodyStream).ConfigureAwait(false);
} }
...@@ -283,7 +284,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -283,7 +284,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// and ignore the request /// and ignore the request
/// </summary> /// </summary>
/// <param name="html"></param> /// <param name="html"></param>
public void Ok(string html) public async Task Ok(string html)
{ {
if (WebSession.Request.RequestLocked) if (WebSession.Request.RequestLocked)
throw new Exception("You cannot call this function after request is made to server."); throw new Exception("You cannot call this function after request is made to server.");
...@@ -293,7 +294,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -293,7 +294,7 @@ namespace Titanium.Web.Proxy.EventArguments
var result = Encoding.Default.GetBytes(html); var result = Encoding.Default.GetBytes(html);
Ok(result); await Ok(result).ConfigureAwait(false);
} }
/// <summary> /// <summary>
...@@ -302,19 +303,19 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -302,19 +303,19 @@ namespace Titanium.Web.Proxy.EventArguments
/// and ignore the request /// and ignore the request
/// </summary> /// </summary>
/// <param name="body"></param> /// <param name="body"></param>
public void Ok(byte[] result) public async Task Ok(byte[] result)
{ {
var response = new OkResponse(); var response = new OkResponse();
response.HttpVersion = WebSession.Request.HttpVersion; response.HttpVersion = WebSession.Request.HttpVersion;
response.ResponseBody = result; response.ResponseBody = result;
Respond(response); await Respond(response).ConfigureAwait(false);
WebSession.Request.CancelRequest = true; WebSession.Request.CancelRequest = true;
} }
public void Redirect(string url) public async Task Redirect(string url)
{ {
var response = new RedirectResponse(); var response = new RedirectResponse();
...@@ -322,13 +323,13 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -322,13 +323,13 @@ namespace Titanium.Web.Proxy.EventArguments
response.ResponseHeaders.Add(new Models.HttpHeader("Location", url)); response.ResponseHeaders.Add(new Models.HttpHeader("Location", url));
response.ResponseBody = Encoding.ASCII.GetBytes(string.Empty); response.ResponseBody = Encoding.ASCII.GetBytes(string.Empty);
Respond(response); await Respond(response).ConfigureAwait(false);
WebSession.Request.CancelRequest = true; WebSession.Request.CancelRequest = true;
} }
/// a generic responder method /// a generic responder method
public void Respond(Response response) public async Task Respond(Response response)
{ {
WebSession.Request.RequestLocked = true; WebSession.Request.RequestLocked = true;
...@@ -337,7 +338,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -337,7 +338,7 @@ namespace Titanium.Web.Proxy.EventArguments
WebSession.Response = response; WebSession.Response = response;
ProxyServer.HandleHttpSessionResponse(this); await ProxyServer.HandleHttpSessionResponse(this).ConfigureAwait(false);
} }
} }
......
...@@ -15,12 +15,12 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -15,12 +15,12 @@ namespace Titanium.Web.Proxy.Extensions
if (!string.IsNullOrEmpty(initialData)) if (!string.IsNullOrEmpty(initialData))
{ {
var bytes = Encoding.ASCII.GetBytes(initialData); var bytes = Encoding.ASCII.GetBytes(initialData);
output.Write(bytes, 0, bytes.Length); await output.WriteAsync(bytes, 0, bytes.Length);
} }
await input.CopyToAsync(output); await input.CopyToAsync(output);
} }
internal static void CopyBytesToStream(this CustomBinaryReader clientStreamReader, Stream stream, long totalBytesToRead) internal static async Task CopyBytesToStream(this CustomBinaryReader clientStreamReader, Stream stream, long totalBytesToRead)
{ {
var totalbytesRead = 0; var totalbytesRead = 0;
...@@ -35,7 +35,7 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -35,7 +35,7 @@ namespace Titanium.Web.Proxy.Extensions
while (totalbytesRead < (int)totalBytesToRead) while (totalbytesRead < (int)totalBytesToRead)
{ {
var buffer = clientStreamReader.ReadBytes(bytesToRead); var buffer = await clientStreamReader.ReadBytesAsync(bytesToRead);
totalbytesRead += buffer.Length; totalbytesRead += buffer.Length;
var remainingBytes = (int)totalBytesToRead - totalbytesRead; var remainingBytes = (int)totalBytesToRead - totalbytesRead;
...@@ -43,26 +43,26 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -43,26 +43,26 @@ namespace Titanium.Web.Proxy.Extensions
{ {
bytesToRead = remainingBytes; bytesToRead = remainingBytes;
} }
stream.Write(buffer, 0, buffer.Length); await stream.WriteAsync(buffer, 0, buffer.Length);
} }
} }
internal static void CopyBytesToStreamChunked(this CustomBinaryReader clientStreamReader, Stream stream) internal static async Task CopyBytesToStreamChunked(this CustomBinaryReader clientStreamReader, Stream stream)
{ {
while (true) while (true)
{ {
var chuchkHead = clientStreamReader.ReadLine(); var chuchkHead = await clientStreamReader.ReadLineAsync();
var chunkSize = int.Parse(chuchkHead, NumberStyles.HexNumber); var chunkSize = int.Parse(chuchkHead, NumberStyles.HexNumber);
if (chunkSize != 0) if (chunkSize != 0)
{ {
var buffer = clientStreamReader.ReadBytes(chunkSize); var buffer = await clientStreamReader.ReadBytesAsync(chunkSize);
stream.Write(buffer, 0, buffer.Length); await stream.WriteAsync(buffer, 0, buffer.Length);
//chunk trail //chunk trail
clientStreamReader.ReadLine(); await clientStreamReader.ReadLineAsync();
} }
else else
{ {
clientStreamReader.ReadLine(); await clientStreamReader.ReadLineAsync();
break; break;
} }
} }
......
...@@ -4,6 +4,7 @@ using System.IO; ...@@ -4,6 +4,7 @@ using System.IO;
using System.Net.Security; using System.Net.Security;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text; using System.Text;
using System.Threading.Tasks;
using Titanium.Web.Proxy.Network; using Titanium.Web.Proxy.Network;
using Titanium.Web.Proxy.Shared; using Titanium.Web.Proxy.Shared;
...@@ -31,7 +32,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -31,7 +32,7 @@ namespace Titanium.Web.Proxy.Helpers
/// Read a line from the byte stream /// Read a line from the byte stream
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
internal string ReadLine() internal async Task<string> ReadLineAsync()
{ {
var readBuffer = new StringBuilder(); var readBuffer = new StringBuilder();
...@@ -40,7 +41,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -40,7 +41,7 @@ namespace Titanium.Web.Proxy.Helpers
var lastChar = default(char); var lastChar = default(char);
var buffer = new byte[1]; var buffer = new byte[1];
while (this.stream.Read(buffer, 0, 1) > 0) while (await this.stream.ReadAsync(buffer, 0, 1).ConfigureAwait(false) > 0)
{ {
if (lastChar == '\r' && buffer[0] == '\n') if (lastChar == '\r' && buffer[0] == '\n')
{ {
...@@ -66,18 +67,18 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -66,18 +67,18 @@ namespace Titanium.Web.Proxy.Helpers
/// Read until the last new line /// Read until the last new line
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
internal List<string> ReadAllLines() internal async Task<List<string>> ReadAllLinesAsync()
{ {
string tmpLine; string tmpLine;
var requestLines = new List<string>(); var requestLines = new List<string>();
while (!string.IsNullOrEmpty(tmpLine = ReadLine())) while (!string.IsNullOrEmpty(tmpLine = await ReadLineAsync().ConfigureAwait(false)))
{ {
requestLines.Add(tmpLine); requestLines.Add(tmpLine);
} }
return requestLines; return requestLines;
} }
internal byte[] ReadBytes(long totalBytesToRead) internal async Task<byte[]> ReadBytesAsync(long totalBytesToRead)
{ {
int bytesToRead = Constants.BUFFER_SIZE; int bytesToRead = Constants.BUFFER_SIZE;
...@@ -91,9 +92,9 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -91,9 +92,9 @@ namespace Titanium.Web.Proxy.Helpers
using (var outStream = new MemoryStream()) using (var outStream = new MemoryStream())
{ {
while ((bytesRead += this.stream.Read(buffer, 0, bytesToRead)) > 0) while ((bytesRead += await this.stream.ReadAsync(buffer, 0, bytesToRead).ConfigureAwait(false)) > 0)
{ {
outStream.Write(buffer, 0, bytesRead); await outStream.WriteAsync(buffer, 0, bytesRead).ConfigureAwait(false);
totalBytesRead += bytesRead; totalBytesRead += bytesRead;
if (totalBytesRead == totalBytesToRead) if (totalBytesRead == totalBytesToRead)
......
...@@ -14,7 +14,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -14,7 +14,7 @@ namespace Titanium.Web.Proxy.Helpers
{ {
public class TcpHelper public class TcpHelper
{ {
public static void SendRaw(Stream clientStream, string httpCmd, List<HttpHeader> requestHeaders, string hostName, public async static Task SendRaw(Stream clientStream, string httpCmd, List<HttpHeader> requestHeaders, string hostName,
int tunnelPort, bool isHttps) int tunnelPort, bool isHttps)
{ {
StringBuilder sb = null; StringBuilder sb = null;
...@@ -50,7 +50,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -50,7 +50,7 @@ namespace Titanium.Web.Proxy.Helpers
try try
{ {
sslStream = new SslStream(tunnelStream); sslStream = new SslStream(tunnelStream);
sslStream.AuthenticateAsClient(hostName, null, Constants.SupportedProtocols, false); await sslStream.AuthenticateAsClientAsync(hostName, null, Constants.SupportedProtocols, false);
tunnelStream = sslStream; tunnelStream = sslStream;
} }
catch catch
...@@ -62,17 +62,17 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -62,17 +62,17 @@ namespace Titanium.Web.Proxy.Helpers
} }
} }
var sendRelay = Task.Factory.StartNew(() => Task sendRelay;
{
if (sb != null) if (sb != null)
clientStream.CopyToAsync(sb.ToString(), tunnelStream).Wait(); sendRelay = clientStream.CopyToAsync(sb.ToString(), tunnelStream);
else else
clientStream.CopyToAsync(string.Empty, tunnelStream).Wait(); sendRelay = clientStream.CopyToAsync(string.Empty, tunnelStream);
});
var receiveRelay = Task.Factory.StartNew(() =>tunnelStream.CopyToAsync(string.Empty, clientStream).Wait()); var receiveRelay = tunnelStream.CopyToAsync(string.Empty, clientStream);
Task.WaitAll(sendRelay, receiveRelay); await Task.WhenAll(sendRelay, receiveRelay).ConfigureAwait(false);
} }
catch catch
{ {
......
...@@ -2,6 +2,7 @@ using System; ...@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
using System.Threading.Tasks;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Network; using Titanium.Web.Proxy.Network;
using Titanium.Web.Proxy.Shared; using Titanium.Web.Proxy.Shared;
...@@ -35,7 +36,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -35,7 +36,7 @@ namespace Titanium.Web.Proxy.Http
this.Response = new Response(); this.Response = new Response();
} }
internal void SendRequest() internal async Task SendRequest()
{ {
Stream stream = ProxyClient.Stream; Stream stream = ProxyClient.Stream;
...@@ -57,13 +58,13 @@ namespace Titanium.Web.Proxy.Http ...@@ -57,13 +58,13 @@ namespace Titanium.Web.Proxy.Http
string request = requestLines.ToString(); string request = requestLines.ToString();
byte[] requestBytes = Encoding.ASCII.GetBytes(request); byte[] requestBytes = Encoding.ASCII.GetBytes(request);
stream.Write(requestBytes, 0, requestBytes.Length); await stream.WriteAsync(requestBytes, 0, requestBytes.Length);
stream.Flush(); stream.Flush();
if (ProxyServer.Enable100ContinueBehaviour) if (ProxyServer.Enable100ContinueBehaviour)
if (this.Request.ExpectContinue) if (this.Request.ExpectContinue)
{ {
var httpResult = ProxyClient.ServerStreamReader.ReadLine().Split(Constants.SpaceSplit, 3); var httpResult = (await ProxyClient.ServerStreamReader.ReadLineAsync()).Split(Constants.SpaceSplit, 3);
var responseStatusCode = httpResult[1].Trim(); var responseStatusCode = httpResult[1].Trim();
var responseStatusDescription = httpResult[2].Trim(); var responseStatusDescription = httpResult[2].Trim();
...@@ -72,27 +73,27 @@ namespace Titanium.Web.Proxy.Http ...@@ -72,27 +73,27 @@ namespace Titanium.Web.Proxy.Http
&& responseStatusDescription.ToLower().Equals("continue")) && responseStatusDescription.ToLower().Equals("continue"))
{ {
this.Request.Is100Continue = true; this.Request.Is100Continue = true;
ProxyClient.ServerStreamReader.ReadLine(); await ProxyClient.ServerStreamReader.ReadLineAsync();
} }
else if (responseStatusCode.Equals("417") else if (responseStatusCode.Equals("417")
&& responseStatusDescription.ToLower().Equals("expectation failed")) && responseStatusDescription.ToLower().Equals("expectation failed"))
{ {
this.Request.ExpectationFailed = true; this.Request.ExpectationFailed = true;
ProxyClient.ServerStreamReader.ReadLine(); await ProxyClient.ServerStreamReader.ReadLineAsync();
} }
} }
} }
internal void ReceiveResponse() internal async Task ReceiveResponse()
{ {
//return if this is already read //return if this is already read
if (this.Response.ResponseStatusCode != null) return; if (this.Response.ResponseStatusCode != null) return;
var httpResult = ProxyClient.ServerStreamReader.ReadLine().Split(Constants.SpaceSplit, 3); var httpResult = (await ProxyClient.ServerStreamReader.ReadLineAsync()).Split(Constants.SpaceSplit, 3);
if (string.IsNullOrEmpty(httpResult[0])) if (string.IsNullOrEmpty(httpResult[0]))
{ {
var s = ProxyClient.ServerStreamReader.ReadLine(); await ProxyClient.ServerStreamReader.ReadLineAsync();
} }
this.Response.HttpVersion = httpResult[0].Trim(); this.Response.HttpVersion = httpResult[0].Trim();
...@@ -105,8 +106,8 @@ namespace Titanium.Web.Proxy.Http ...@@ -105,8 +106,8 @@ namespace Titanium.Web.Proxy.Http
{ {
this.Response.Is100Continue = true; this.Response.Is100Continue = true;
this.Response.ResponseStatusCode = null; this.Response.ResponseStatusCode = null;
ProxyClient.ServerStreamReader.ReadLine(); await ProxyClient.ServerStreamReader.ReadLineAsync();
ReceiveResponse(); await ReceiveResponse();
return; return;
} }
else if (this.Response.ResponseStatusCode.Equals("417") else if (this.Response.ResponseStatusCode.Equals("417")
...@@ -114,12 +115,12 @@ namespace Titanium.Web.Proxy.Http ...@@ -114,12 +115,12 @@ namespace Titanium.Web.Proxy.Http
{ {
this.Response.ExpectationFailed = true; this.Response.ExpectationFailed = true;
this.Response.ResponseStatusCode = null; this.Response.ResponseStatusCode = null;
ProxyClient.ServerStreamReader.ReadLine(); await ProxyClient.ServerStreamReader.ReadLineAsync();
ReceiveResponse(); await ReceiveResponse();
return; return;
} }
List<string> responseLines = ProxyClient.ServerStreamReader.ReadAllLines(); List<string> responseLines = await ProxyClient.ServerStreamReader.ReadAllLinesAsync();
for (int index = 0; index < responseLines.Count; ++index) for (int index = 0; index < responseLines.Count; ++index)
{ {
......
...@@ -61,13 +61,15 @@ namespace Titanium.Web.Proxy.Network ...@@ -61,13 +61,15 @@ namespace Titanium.Web.Proxy.Network
} }
if (cached == null) if (cached == null)
cached = await CreateClient(sessionArgs,hostname, port, isSecure, version); cached = await CreateClient(sessionArgs, hostname, port, isSecure, version).ConfigureAwait(false);
//if (ConnectionCache.Where(x => x.HostName == hostname && x.port == port && //just create one more preemptively
//x.IsSecure == isSecure && x.TcpClient.Connected && x.Version.Equals(version)).Count() < 2) if (ConnectionCache.Where(x => x.HostName == hostname && x.port == port &&
//{ x.IsSecure == isSecure && x.TcpClient.Connected && x.Version.Equals(version)).Count() < 2)
// Task.Factory.StartNew(() => CreateClient(sessionArgs, hostname, port, isSecure, version)); {
//} var task = CreateClient(sessionArgs, hostname, port, isSecure, version)
.ContinueWith(x => ReleaseClient(x.Result));
}
return cached; return cached;
} }
...@@ -81,12 +83,12 @@ namespace Titanium.Web.Proxy.Network ...@@ -81,12 +83,12 @@ namespace Titanium.Web.Proxy.Network
{ {
CustomSslStream sslStream = null; CustomSslStream sslStream = null;
if(ProxyServer.UpStreamHttpsProxy!=null) if (ProxyServer.UpStreamHttpsProxy != null)
{ {
client = new TcpClient(ProxyServer.UpStreamHttpsProxy.HostName, ProxyServer.UpStreamHttpsProxy.Port); client = new TcpClient(ProxyServer.UpStreamHttpsProxy.HostName, ProxyServer.UpStreamHttpsProxy.Port);
stream = (Stream)client.GetStream(); stream = (Stream)client.GetStream();
var writer = new StreamWriter(stream,Encoding.ASCII, Constants.BUFFER_SIZE, true); 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("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(string.Format("Host: {0}:{1}", sessionArgs.WebSession.Request.RequestUri.Host, sessionArgs.WebSession.Request.RequestUri.Port));
...@@ -95,12 +97,12 @@ namespace Titanium.Web.Proxy.Network ...@@ -95,12 +97,12 @@ namespace Titanium.Web.Proxy.Network
writer.Flush(); writer.Flush();
var reader = new CustomBinaryReader(stream); var reader = new CustomBinaryReader(stream);
var result = reader.ReadLine(); var result = await reader.ReadLineAsync().ConfigureAwait(false);
if (!result.ToLower().Contains("200 connection established")) if (!result.ToLower().Contains("200 connection established"))
throw new Exception("Upstream proxy failed to create a secure tunnel"); throw new Exception("Upstream proxy failed to create a secure tunnel");
reader.ReadAllLines(); await reader.ReadAllLinesAsync().ConfigureAwait(false);
} }
else else
{ {
...@@ -110,9 +112,9 @@ namespace Titanium.Web.Proxy.Network ...@@ -110,9 +112,9 @@ namespace Titanium.Web.Proxy.Network
try try
{ {
sslStream = new CustomSslStream(stream, true, ProxyServer.ValidateServerCertificate); sslStream = new CustomSslStream(stream, true, new RemoteCertificateValidationCallback(ProxyServer.ValidateServerCertificate));
sslStream.Session = sessionArgs; sslStream.Session = sessionArgs;
await sslStream.AuthenticateAsClientAsync(hostname, null, Constants.SupportedProtocols, false); await sslStream.AuthenticateAsClientAsync(hostname, null, Constants.SupportedProtocols, false).ConfigureAwait(false);
stream = (Stream)sslStream; stream = (Stream)sslStream;
} }
catch catch
...@@ -155,7 +157,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -155,7 +157,7 @@ namespace Titanium.Web.Proxy.Network
ConnectionCache.Add(Connection); ConnectionCache.Add(Connection);
} }
internal static void ClearIdleConnections() internal async static void ClearIdleConnections()
{ {
while (true) while (true)
{ {
...@@ -171,7 +173,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -171,7 +173,7 @@ namespace Titanium.Web.Proxy.Network
ConnectionCache.RemoveAll(x => x.LastAccess < cutOff); ConnectionCache.RemoveAll(x => x.LastAccess < cutOff);
} }
Thread.Sleep(1000 * 60 * 3); await Task.Delay(1000 * 60 * 3).ConfigureAwait(false);
} }
} }
......
...@@ -34,8 +34,8 @@ namespace Titanium.Web.Proxy ...@@ -34,8 +34,8 @@ namespace Titanium.Web.Proxy
public static string RootCertificateName { get; set; } public static string RootCertificateName { get; set; }
public static bool Enable100ContinueBehaviour { get; set; } public static bool Enable100ContinueBehaviour { get; set; }
public static event EventHandler<SessionEventArgs> BeforeRequest; public static event Func<object, SessionEventArgs, Task> BeforeRequest;
public static event EventHandler<SessionEventArgs> BeforeResponse; public static event Func<object, SessionEventArgs, Task> BeforeResponse;
/// <summary> /// <summary>
/// External proxy for Http /// External proxy for Http
...@@ -50,14 +50,14 @@ namespace Titanium.Web.Proxy ...@@ -50,14 +50,14 @@ namespace Titanium.Web.Proxy
/// <summary> /// <summary>
/// Verifies the remote Secure Sockets Layer (SSL) certificate used for authentication /// Verifies the remote Secure Sockets Layer (SSL) certificate used for authentication
/// </summary> /// </summary>
public static event EventHandler<CertificateValidationEventArgs> RemoteCertificateValidationCallback; public static event Func<object, CertificateValidationEventArgs, Task> ServerCertificateValidationCallback;
public static List<ProxyEndPoint> ProxyEndPoints { get; set; } public static List<ProxyEndPoint> ProxyEndPoints { get; set; }
public static void Initialize() public static void Initialize()
{ {
Task.Factory.StartNew(() => TcpConnectionManager.ClearIdleConnections()); TcpConnectionManager.ClearIdleConnections();
} }
public static void AddEndPoint(ProxyEndPoint endPoint) public static void AddEndPoint(ProxyEndPoint endPoint)
...@@ -236,50 +236,5 @@ namespace Titanium.Web.Proxy ...@@ -236,50 +236,5 @@ namespace Titanium.Web.Proxy
} }
/// <summary>
/// Call back to override server certificate validation
/// </summary>
/// <param name="sender"></param>
/// <param name="certificate"></param>
/// <param name="chain"></param>
/// <param name="sslPolicyErrors"></param>
/// <returns></returns>
internal static bool ValidateServerCertificate(
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
var param = sender as CustomSslStream;
if (RemoteCertificateValidationCallback != null)
{
var args = new CertificateValidationEventArgs();
args.Session = param.Session;
args.Certificate = certificate;
args.Chain = chain;
args.SslPolicyErrors = sslPolicyErrors;
RemoteCertificateValidationCallback.Invoke(null, args);
if(!args.IsValid)
{
param.Session.WebSession.Request.CancelRequest = true;
}
return args.IsValid;
}
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;
}
} }
} }
\ No newline at end of file
...@@ -34,7 +34,7 @@ namespace Titanium.Web.Proxy ...@@ -34,7 +34,7 @@ namespace Titanium.Web.Proxy
{ {
//read the first line HTTP command //read the first line HTTP command
var httpCmd = clientStreamReader.ReadLine(); var httpCmd = await clientStreamReader.ReadLineAsync();
if (string.IsNullOrEmpty(httpCmd)) if (string.IsNullOrEmpty(httpCmd))
{ {
...@@ -63,9 +63,9 @@ namespace Titanium.Web.Proxy ...@@ -63,9 +63,9 @@ namespace Titanium.Web.Proxy
if (httpVerb.ToUpper() == "CONNECT" && !excluded && httpRemoteUri.Port != 80) if (httpVerb.ToUpper() == "CONNECT" && !excluded && httpRemoteUri.Port != 80)
{ {
httpRemoteUri = new Uri("https://" + httpCmdSplit[1]); httpRemoteUri = new Uri("https://" + httpCmdSplit[1]);
clientStreamReader.ReadAllLines(); await clientStreamReader.ReadAllLinesAsync().ConfigureAwait(false);
WriteConnectResponse(clientStreamWriter, httpVersion); await WriteConnectResponse(clientStreamWriter, httpVersion).ConfigureAwait(false);
var certificate = CertManager.CreateCertificate(httpRemoteUri.Host); var certificate = CertManager.CreateCertificate(httpRemoteUri.Host);
...@@ -77,7 +77,7 @@ namespace Titanium.Web.Proxy ...@@ -77,7 +77,7 @@ namespace Titanium.Web.Proxy
//Successfully managed to authenticate the client using the fake certificate //Successfully managed to authenticate the client using the fake certificate
await sslStream.AuthenticateAsServerAsync(certificate, false, await sslStream.AuthenticateAsServerAsync(certificate, false,
Constants.SupportedProtocols, false); Constants.SupportedProtocols, false).ConfigureAwait(false);
clientStreamReader = new CustomBinaryReader(sslStream); clientStreamReader = new CustomBinaryReader(sslStream);
clientStreamWriter = new StreamWriter(sslStream); clientStreamWriter = new StreamWriter(sslStream);
...@@ -95,16 +95,16 @@ namespace Titanium.Web.Proxy ...@@ -95,16 +95,16 @@ namespace Titanium.Web.Proxy
} }
httpCmd = clientStreamReader.ReadLine(); httpCmd = await clientStreamReader.ReadLineAsync().ConfigureAwait(false);
} }
else if (httpVerb.ToUpper() == "CONNECT") else if (httpVerb.ToUpper() == "CONNECT")
{ {
clientStreamReader.ReadAllLines(); await clientStreamReader.ReadAllLinesAsync().ConfigureAwait(false);
WriteConnectResponse(clientStreamWriter, httpVersion); await WriteConnectResponse(clientStreamWriter, httpVersion).ConfigureAwait(false);
TcpHelper.SendRaw(clientStream, null, null, httpRemoteUri.Host, httpRemoteUri.Port, await TcpHelper.SendRaw(clientStream, null, null, httpRemoteUri.Host, httpRemoteUri.Port,
false); false).ConfigureAwait(false);
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null); Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null);
return; return;
...@@ -113,7 +113,7 @@ namespace Titanium.Web.Proxy ...@@ -113,7 +113,7 @@ namespace Titanium.Web.Proxy
//Now create the request //Now create the request
await HandleHttpSessionRequest(client, httpCmd, clientStream, clientStreamReader, clientStreamWriter, await HandleHttpSessionRequest(client, httpCmd, clientStream, clientStreamReader, clientStreamWriter,
httpRemoteUri.Scheme == Uri.UriSchemeHttps ? true : false); httpRemoteUri.Scheme == Uri.UriSchemeHttps ? true : false).ConfigureAwait(false);
} }
catch catch
{ {
...@@ -123,7 +123,7 @@ namespace Titanium.Web.Proxy ...@@ -123,7 +123,7 @@ namespace Titanium.Web.Proxy
//This is called when requests are routed through router to this endpoint //This is called when requests are routed through router to this endpoint
//For ssl requests //For ssl requests
private static async Task HandleClient(TransparentProxyEndPoint endPoint, TcpClient tcpClient) private static async void HandleClient(TransparentProxyEndPoint endPoint, TcpClient tcpClient)
{ {
Stream clientStream = tcpClient.GetStream(); Stream clientStream = tcpClient.GetStream();
CustomBinaryReader clientStreamReader = null; CustomBinaryReader clientStreamReader = null;
...@@ -144,8 +144,8 @@ namespace Titanium.Web.Proxy ...@@ -144,8 +144,8 @@ namespace Titanium.Web.Proxy
try try
{ {
//Successfully managed to authenticate the client using the fake certificate //Successfully managed to authenticate the client using the fake certificate
sslStream.AuthenticateAsServer(certificate, false, await sslStream.AuthenticateAsServerAsync(certificate, false,
SslProtocols.Tls, false); SslProtocols.Tls, false).ConfigureAwait(false);
clientStreamReader = new CustomBinaryReader(sslStream); clientStreamReader = new CustomBinaryReader(sslStream);
clientStreamWriter = new StreamWriter(sslStream); clientStreamWriter = new StreamWriter(sslStream);
...@@ -167,11 +167,11 @@ namespace Titanium.Web.Proxy ...@@ -167,11 +167,11 @@ namespace Titanium.Web.Proxy
clientStreamReader = new CustomBinaryReader(clientStream); clientStreamReader = new CustomBinaryReader(clientStream);
} }
var httpCmd = clientStreamReader.ReadLine(); var httpCmd = await clientStreamReader.ReadLineAsync().ConfigureAwait(false);
//Now create the request //Now create the request
await HandleHttpSessionRequest(tcpClient, httpCmd, clientStream, clientStreamReader, clientStreamWriter, await HandleHttpSessionRequest(tcpClient, httpCmd, clientStream, clientStreamReader, clientStreamWriter,
true); true).ConfigureAwait(false);
} }
private static async Task HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream, private static async Task HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream,
...@@ -212,7 +212,7 @@ namespace Titanium.Web.Proxy ...@@ -212,7 +212,7 @@ namespace Titanium.Web.Proxy
args.WebSession.Request.RequestHeaders = new List<HttpHeader>(); args.WebSession.Request.RequestHeaders = new List<HttpHeader>();
string tmpLine; string tmpLine;
while (!string.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine())) while (!string.IsNullOrEmpty(tmpLine = await clientStreamReader.ReadLineAsync().ConfigureAwait(false)))
{ {
var header = tmpLine.Split(new char[] { ':' }, 2); var header = tmpLine.Split(new char[] { ':' }, 2);
args.WebSession.Request.RequestHeaders.Add(new HttpHeader(header[0], header[1])); args.WebSession.Request.RequestHeaders.Add(new HttpHeader(header[0], header[1]));
...@@ -231,8 +231,8 @@ namespace Titanium.Web.Proxy ...@@ -231,8 +231,8 @@ namespace Titanium.Web.Proxy
if (args.WebSession.Request.UpgradeToWebSocket) if (args.WebSession.Request.UpgradeToWebSocket)
{ {
TcpHelper.SendRaw(clientStream, httpCmd, args.WebSession.Request.RequestHeaders, await TcpHelper.SendRaw(clientStream, httpCmd, args.WebSession.Request.RequestHeaders,
httpRemoteUri.Host, httpRemoteUri.Port, args.IsHttps); httpRemoteUri.Host, httpRemoteUri.Port, args.IsHttps).ConfigureAwait(false);
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args); Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
return; return;
} }
...@@ -241,12 +241,23 @@ namespace Titanium.Web.Proxy ...@@ -241,12 +241,23 @@ namespace Titanium.Web.Proxy
args.WebSession.Request.Host = args.WebSession.Request.RequestUri.Host; args.WebSession.Request.Host = args.WebSession.Request.RequestUri.Host;
//If requested interception //If requested interception
BeforeRequest?.Invoke(null, args); if (BeforeRequest != null)
{
Delegate[] invocationList = BeforeRequest.GetInvocationList();
Task[] handlerTasks = new Task[invocationList.Length];
for (int i = 0; i < invocationList.Length; i++)
{
handlerTasks[i] = ((Func<object, SessionEventArgs, Task>)invocationList[i])(null, args);
}
await Task.WhenAll(handlerTasks).ConfigureAwait(false);
}
//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.
connection = connection == null ? connection = connection == null ?
await TcpConnectionManager.GetClient(args, args.WebSession.Request.RequestUri.Host, args.WebSession.Request.RequestUri.Port, args.IsHttps, version) await TcpConnectionManager.GetClient(args, args.WebSession.Request.RequestUri.Host, args.WebSession.Request.RequestUri.Port, args.IsHttps, version).ConfigureAwait(false)
: lastRequestHostName != args.WebSession.Request.RequestUri.Host ? await TcpConnectionManager.GetClient(args, args.WebSession.Request.RequestUri.Host, args.WebSession.Request.RequestUri.Port, args.IsHttps, version) : lastRequestHostName != args.WebSession.Request.RequestUri.Host ? await TcpConnectionManager.GetClient(args, args.WebSession.Request.RequestUri.Host, args.WebSession.Request.RequestUri.Port, args.IsHttps, version).ConfigureAwait(false)
: connection; : connection;
lastRequestHostName = args.WebSession.Request.RequestUri.Host; lastRequestHostName = args.WebSession.Request.RequestUri.Host;
...@@ -262,7 +273,7 @@ namespace Titanium.Web.Proxy ...@@ -262,7 +273,7 @@ namespace Titanium.Web.Proxy
if (args.WebSession.Request.ExpectContinue) if (args.WebSession.Request.ExpectContinue)
{ {
args.WebSession.SetConnection(connection); args.WebSession.SetConnection(connection);
args.WebSession.SendRequest(); await args.WebSession.SendRequest().ConfigureAwait(false);
} }
if (Enable100ContinueBehaviour) if (Enable100ContinueBehaviour)
...@@ -282,7 +293,7 @@ namespace Titanium.Web.Proxy ...@@ -282,7 +293,7 @@ namespace Titanium.Web.Proxy
if (!args.WebSession.Request.ExpectContinue) if (!args.WebSession.Request.ExpectContinue)
{ {
args.WebSession.SetConnection(connection); args.WebSession.SetConnection(connection);
args.WebSession.SendRequest(); await args.WebSession.SendRequest().ConfigureAwait(false);
} }
//If request was modified by user //If request was modified by user
...@@ -290,7 +301,7 @@ namespace Titanium.Web.Proxy ...@@ -290,7 +301,7 @@ namespace Titanium.Web.Proxy
{ {
args.WebSession.Request.ContentLength = args.WebSession.Request.RequestBody.Length; args.WebSession.Request.ContentLength = args.WebSession.Request.RequestBody.Length;
var newStream = args.WebSession.ProxyClient.Stream; var newStream = args.WebSession.ProxyClient.Stream;
newStream.Write(args.WebSession.Request.RequestBody, 0, args.WebSession.Request.RequestBody.Length); await newStream.WriteAsync(args.WebSession.Request.RequestBody, 0, args.WebSession.Request.RequestBody.Length).ConfigureAwait(false);
} }
else else
{ {
...@@ -299,14 +310,14 @@ namespace Titanium.Web.Proxy ...@@ -299,14 +310,14 @@ namespace Titanium.Web.Proxy
//If its a post/put request, then read the client html body and send it to server //If its a post/put request, then read the client html body and send it to server
if (httpMethod.ToUpper() == "POST" || httpMethod.ToUpper() == "PUT") if (httpMethod.ToUpper() == "POST" || httpMethod.ToUpper() == "PUT")
{ {
SendClientRequestBody(args); await SendClientRequestBody(args).ConfigureAwait(false);
} }
} }
} }
if (!args.WebSession.Request.ExpectationFailed) if (!args.WebSession.Request.ExpectationFailed)
{ {
HandleHttpSessionResponse(args); await HandleHttpSessionResponse(args).ConfigureAwait(false);
} }
//if connection is closing exit //if connection is closing exit
...@@ -318,7 +329,7 @@ namespace Titanium.Web.Proxy ...@@ -318,7 +329,7 @@ namespace Titanium.Web.Proxy
} }
// read the next request // read the next request
httpCmd = clientStreamReader.ReadLine(); httpCmd = await clientStreamReader.ReadLineAsync().ConfigureAwait(false);
} }
catch catch
...@@ -333,12 +344,12 @@ namespace Titanium.Web.Proxy ...@@ -333,12 +344,12 @@ namespace Titanium.Web.Proxy
TcpConnectionManager.ReleaseClient(connection); TcpConnectionManager.ReleaseClient(connection);
} }
private static void WriteConnectResponse(StreamWriter clientStreamWriter, string httpVersion) private static async Task WriteConnectResponse(StreamWriter clientStreamWriter, string httpVersion)
{ {
clientStreamWriter.WriteLine(httpVersion + " 200 Connection established"); await clientStreamWriter.WriteLineAsync(httpVersion + " 200 Connection established").ConfigureAwait(false);
clientStreamWriter.WriteLine("Timestamp: {0}", DateTime.Now); await clientStreamWriter.WriteLineAsync(string.Format("Timestamp: {0}", DateTime.Now)).ConfigureAwait(false);
clientStreamWriter.WriteLine(); await clientStreamWriter.WriteLineAsync().ConfigureAwait(false);
clientStreamWriter.Flush(); await clientStreamWriter.FlushAsync().ConfigureAwait(false);
} }
private static void PrepareRequestHeaders(List<HttpHeader> requestHeaders, HttpWebSession webRequest) private static void PrepareRequestHeaders(List<HttpHeader> requestHeaders, HttpWebSession webRequest)
...@@ -378,17 +389,16 @@ namespace Titanium.Web.Proxy ...@@ -378,17 +389,16 @@ namespace Titanium.Web.Proxy
headers.RemoveAll(x => x.Name.ToLower() == "proxy-connection"); headers.RemoveAll(x => x.Name.ToLower() == "proxy-connection");
} }
//This is called when the request is PUT/POST to read the body //This is called when the request is PUT/POST to read the body
private static void SendClientRequestBody(SessionEventArgs args) private static async Task SendClientRequestBody(SessionEventArgs args)
{ {
// End the operation // End the operation
var postStream = args.WebSession.ProxyClient.Stream; var postStream = args.WebSession.ProxyClient.Stream;
if (args.WebSession.Request.ContentLength > 0) if (args.WebSession.Request.ContentLength > 0)
{ {
try try
{ {
args.Client.ClientStreamReader.CopyBytesToStream(postStream, args.WebSession.Request.ContentLength); await args.Client.ClientStreamReader.CopyBytesToStream(postStream, args.WebSession.Request.ContentLength).ConfigureAwait(false);
} }
catch catch
{ {
...@@ -400,7 +410,7 @@ namespace Titanium.Web.Proxy ...@@ -400,7 +410,7 @@ namespace Titanium.Web.Proxy
{ {
try try
{ {
args.Client.ClientStreamReader.CopyBytesToStreamChunked(postStream); await args.Client.ClientStreamReader.CopyBytesToStreamChunked(postStream).ConfigureAwait(false);
} }
catch catch
{ {
...@@ -409,6 +419,60 @@ namespace Titanium.Web.Proxy ...@@ -409,6 +419,60 @@ namespace Titanium.Web.Proxy
} }
} }
/// <summary>
/// Call back to override server certificate validation
/// </summary>
/// <param name="sender"></param>
/// <param name="certificate"></param>
/// <param name="chain"></param>
/// <param name="sslPolicyErrors"></param>
/// <returns></returns>
internal static bool ValidateServerCertificate(
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
var param = sender as CustomSslStream;
if (ServerCertificateValidationCallback != null)
{
var args = new CertificateValidationEventArgs();
args.Session = param.Session;
args.Certificate = certificate;
args.Chain = chain;
args.SslPolicyErrors = sslPolicyErrors;
Delegate[] invocationList = ServerCertificateValidationCallback.GetInvocationList();
Task[] handlerTasks = new Task[invocationList.Length];
for (int i = 0; i < invocationList.Length; i++)
{
handlerTasks[i] = ((Func<object, CertificateValidationEventArgs, Task>)invocationList[i])(null, args);
}
Task.WhenAll(handlerTasks).Wait();
if (!args.IsValid)
{
param.Session.WebSession.Request.CancelRequest = true;
}
return args.IsValid;
}
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;
}
} }
} }
\ No newline at end of file
...@@ -10,15 +10,16 @@ using Titanium.Web.Proxy.Helpers; ...@@ -10,15 +10,16 @@ using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Compression; using Titanium.Web.Proxy.Compression;
using Titanium.Web.Proxy.Shared; using Titanium.Web.Proxy.Shared;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy namespace Titanium.Web.Proxy
{ {
partial class ProxyServer partial class ProxyServer
{ {
//Called asynchronously when a request was successfully and we received the response //Called asynchronously when a request was successfully and we received the response
public static void HandleHttpSessionResponse(SessionEventArgs args) public static async Task HandleHttpSessionResponse(SessionEventArgs args)
{ {
args.WebSession.ReceiveResponse(); await args.WebSession.ReceiveResponse().ConfigureAwait(false);
try try
{ {
...@@ -28,7 +29,15 @@ namespace Titanium.Web.Proxy ...@@ -28,7 +29,15 @@ namespace Titanium.Web.Proxy
if (BeforeResponse != null && !args.WebSession.Response.ResponseLocked) if (BeforeResponse != null && !args.WebSession.Response.ResponseLocked)
{ {
BeforeResponse(null, args); Delegate[] invocationList = BeforeResponse.GetInvocationList();
Task[] handlerTasks = new Task[invocationList.Length];
for (int i = 0; i < invocationList.Length; i++)
{
handlerTasks[i] = ((Func<object, SessionEventArgs, Task>)invocationList[i])(null, args);
}
await Task.WhenAll(handlerTasks).ConfigureAwait(false);
} }
args.WebSession.Response.ResponseLocked = true; args.WebSession.Response.ResponseLocked = true;
...@@ -56,19 +65,19 @@ namespace Titanium.Web.Proxy ...@@ -56,19 +65,19 @@ namespace Titanium.Web.Proxy
if (contentEncoding != null) if (contentEncoding != null)
{ {
args.WebSession.Response.ResponseBody = GetCompressedResponseBody(contentEncoding, args.WebSession.Response.ResponseBody); args.WebSession.Response.ResponseBody = await GetCompressedResponseBody(contentEncoding, args.WebSession.Response.ResponseBody).ConfigureAwait(false);
} }
WriteResponseHeaders(args.Client.ClientStreamWriter, args.WebSession.Response.ResponseHeaders, args.WebSession.Response.ResponseBody.Length, await WriteResponseHeaders(args.Client.ClientStreamWriter, args.WebSession.Response.ResponseHeaders, args.WebSession.Response.ResponseBody.Length,
isChunked); isChunked).ConfigureAwait(false);
WriteResponseBody(args.Client.ClientStream, args.WebSession.Response.ResponseBody, isChunked); await WriteResponseBody(args.Client.ClientStream, args.WebSession.Response.ResponseBody, isChunked).ConfigureAwait(false);
} }
else else
{ {
WriteResponseHeaders(args.Client.ClientStreamWriter, args.WebSession.Response.ResponseHeaders); WriteResponseHeaders(args.Client.ClientStreamWriter, args.WebSession.Response.ResponseHeaders);
if (args.WebSession.Response.IsChunked || args.WebSession.Response.ContentLength > 0) if (args.WebSession.Response.IsChunked || args.WebSession.Response.ContentLength > 0)
WriteResponseBody(args.WebSession.ProxyClient.ServerStreamReader, args.Client.ClientStream, args.WebSession.Response.IsChunked, args.WebSession.Response.ContentLength); await WriteResponseBody(args.WebSession.ProxyClient.ServerStreamReader, args.Client.ClientStream, args.WebSession.Response.IsChunked, args.WebSession.Response.ContentLength).ConfigureAwait(false);
} }
args.Client.ClientStream.Flush(); args.Client.ClientStream.Flush();
...@@ -84,11 +93,11 @@ namespace Titanium.Web.Proxy ...@@ -84,11 +93,11 @@ namespace Titanium.Web.Proxy
} }
} }
private static byte[] GetCompressedResponseBody(string encodingType, byte[] responseBodyStream) private static async Task<byte[]> GetCompressedResponseBody(string encodingType, byte[] responseBodyStream)
{ {
var compressionFactory = new CompressionFactory(); var compressionFactory = new CompressionFactory();
var compressor = compressionFactory.Create(encodingType); var compressor = compressionFactory.Create(encodingType);
return compressor.Compress(responseBodyStream); return await compressor.Compress(responseBodyStream).ConfigureAwait(false);
} }
...@@ -132,7 +141,7 @@ namespace Titanium.Web.Proxy ...@@ -132,7 +141,7 @@ namespace Titanium.Web.Proxy
headers.RemoveAll(x => x.Name.ToLower() == "proxy-connection"); headers.RemoveAll(x => x.Name.ToLower() == "proxy-connection");
} }
private static void WriteResponseHeaders(StreamWriter responseWriter, List<HttpHeader> headers, int length, private static async Task WriteResponseHeaders(StreamWriter responseWriter, List<HttpHeader> headers, int length,
bool isChunked) bool isChunked)
{ {
FixResponseProxyHeaders(headers); FixResponseProxyHeaders(headers);
...@@ -152,25 +161,25 @@ namespace Titanium.Web.Proxy ...@@ -152,25 +161,25 @@ namespace Titanium.Web.Proxy
if (!isChunked && header.Name.ToLower() == "content-length") if (!isChunked && header.Name.ToLower() == "content-length")
header.Value = length.ToString(); header.Value = length.ToString();
responseWriter.WriteLine(header.ToString()); await responseWriter.WriteLineAsync(header.ToString()).ConfigureAwait(false);
} }
} }
responseWriter.WriteLine(); await responseWriter.WriteLineAsync().ConfigureAwait(false);
responseWriter.Flush(); await responseWriter.FlushAsync().ConfigureAwait(false);
} }
private static void WriteResponseBody(Stream clientStream, byte[] data, bool isChunked) private static async Task WriteResponseBody(Stream clientStream, byte[] data, bool isChunked)
{ {
if (!isChunked) if (!isChunked)
{ {
clientStream.Write(data, 0, data.Length); await clientStream.WriteAsync(data, 0, data.Length).ConfigureAwait(false);
} }
else else
WriteResponseBodyChunked(data, clientStream); await WriteResponseBodyChunked(data, clientStream).ConfigureAwait(false);
} }
private static void WriteResponseBody(CustomBinaryReader inStreamReader, Stream outStream, bool isChunked, long ContentLength) private static async Task WriteResponseBody(CustomBinaryReader inStreamReader, Stream outStream, bool isChunked, long ContentLength)
{ {
if (!isChunked) if (!isChunked)
{ {
...@@ -184,9 +193,9 @@ namespace Titanium.Web.Proxy ...@@ -184,9 +193,9 @@ namespace Titanium.Web.Proxy
var bytesRead = 0; var bytesRead = 0;
var totalBytesRead = 0; var totalBytesRead = 0;
while ((bytesRead += inStreamReader.BaseStream.Read(buffer, 0, bytesToRead)) > 0) while ((bytesRead += await inStreamReader.BaseStream.ReadAsync(buffer, 0, bytesToRead).ConfigureAwait(false)) > 0)
{ {
outStream.Write(buffer, 0, bytesRead); await outStream.WriteAsync(buffer, 0, bytesRead).ConfigureAwait(false);
totalBytesRead += bytesRead; totalBytesRead += bytesRead;
if (totalBytesRead == ContentLength) if (totalBytesRead == ContentLength)
...@@ -198,50 +207,50 @@ namespace Titanium.Web.Proxy ...@@ -198,50 +207,50 @@ namespace Titanium.Web.Proxy
} }
} }
else else
WriteResponseBodyChunked(inStreamReader, outStream); await WriteResponseBodyChunked(inStreamReader, outStream).ConfigureAwait(false);
} }
//Send chunked response //Send chunked response
private static void WriteResponseBodyChunked(CustomBinaryReader inStreamReader, Stream outStream) private static async Task WriteResponseBodyChunked(CustomBinaryReader inStreamReader, Stream outStream)
{ {
while (true) while (true)
{ {
var chuchkHead = inStreamReader.ReadLine(); var chunkHead = await inStreamReader.ReadLineAsync().ConfigureAwait(false);
var chunkSize = int.Parse(chuchkHead, NumberStyles.HexNumber); var chunkSize = int.Parse(chunkHead, NumberStyles.HexNumber);
if (chunkSize != 0) if (chunkSize != 0)
{ {
var buffer = inStreamReader.ReadBytes(chunkSize); var buffer = await inStreamReader.ReadBytesAsync(chunkSize).ConfigureAwait(false);
var chunkHead = Encoding.ASCII.GetBytes(chunkSize.ToString("x2")); var chunkHeadBytes = Encoding.ASCII.GetBytes(chunkSize.ToString("x2"));
outStream.Write(chunkHead, 0, chunkHead.Length); await outStream.WriteAsync(chunkHeadBytes, 0, chunkHeadBytes.Length).ConfigureAwait(false);
outStream.Write(Constants.NewLineBytes, 0, Constants.NewLineBytes.Length); await outStream.WriteAsync(Constants.NewLineBytes, 0, Constants.NewLineBytes.Length).ConfigureAwait(false);
outStream.Write(buffer, 0, chunkSize); await outStream.WriteAsync(buffer, 0, chunkSize).ConfigureAwait(false);
outStream.Write(Constants.NewLineBytes, 0, Constants.NewLineBytes.Length); await outStream.WriteAsync(Constants.NewLineBytes, 0, Constants.NewLineBytes.Length).ConfigureAwait(false);
inStreamReader.ReadLine(); await inStreamReader.ReadLineAsync().ConfigureAwait(false);
} }
else else
{ {
inStreamReader.ReadLine(); await inStreamReader.ReadLineAsync().ConfigureAwait(false);
outStream.Write(Constants.ChunkEnd, 0, Constants.ChunkEnd.Length); await outStream.WriteAsync(Constants.ChunkEnd, 0, Constants.ChunkEnd.Length).ConfigureAwait(false);
break; break;
} }
} }
} }
private static void WriteResponseBodyChunked(byte[] data, Stream outStream) private static async Task WriteResponseBodyChunked(byte[] data, Stream outStream)
{ {
var chunkHead = Encoding.ASCII.GetBytes(data.Length.ToString("x2")); var chunkHead = Encoding.ASCII.GetBytes(data.Length.ToString("x2"));
outStream.Write(chunkHead, 0, chunkHead.Length); await outStream.WriteAsync(chunkHead, 0, chunkHead.Length).ConfigureAwait(false);
outStream.Write(Constants.NewLineBytes, 0, Constants.NewLineBytes.Length); await outStream.WriteAsync(Constants.NewLineBytes, 0, Constants.NewLineBytes.Length).ConfigureAwait(false);
outStream.Write(data, 0, data.Length); await outStream.WriteAsync(data, 0, data.Length).ConfigureAwait(false);
outStream.Write(Constants.NewLineBytes, 0, Constants.NewLineBytes.Length); await outStream.WriteAsync(Constants.NewLineBytes, 0, Constants.NewLineBytes.Length).ConfigureAwait(false);
outStream.Write(Constants.ChunkEnd, 0, Constants.ChunkEnd.Length); await outStream.WriteAsync(Constants.ChunkEnd, 0, Constants.ChunkEnd.Length).ConfigureAwait(false);
} }
......
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