Commit ffe306c2 authored by titanium007's avatar titanium007

Separate request & response

parent f69bed23
...@@ -43,7 +43,7 @@ namespace Titanium.Web.Proxy.Test ...@@ -43,7 +43,7 @@ namespace Titanium.Web.Proxy.Test
//Read browser URL send back to proxy by the injection script in OnResponse event //Read browser URL send back to proxy by the injection script in OnResponse event
public void OnRequest(object sender, SessionEventArgs e) public void OnRequest(object sender, SessionEventArgs e)
{ {
Console.WriteLine(e.RequestUrl); Console.WriteLine(e.ProxySession.Request.RequestUrl);
////read request headers ////read request headers
//var requestHeaders = e.RequestHeaders; //var requestHeaders = e.RequestHeaders;
......
...@@ -13,6 +13,17 @@ using Titanium.Web.Proxy.Models; ...@@ -13,6 +13,17 @@ using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.EventArguments namespace Titanium.Web.Proxy.EventArguments
{ {
public class Client
{
internal TcpClient TcpClient { get; set; }
internal Stream ClientStream { get; set; }
internal CustomBinaryReader ClientStreamReader { get; set; }
internal StreamWriter ClientStreamWriter { get; set; }
public int ClientPort { get; internal set; }
public IPAddress ClientIpAddress { get; internal set; }
}
public class SessionEventArgs : EventArgs, IDisposable public class SessionEventArgs : EventArgs, IDisposable
{ {
readonly int _bufferSize; readonly int _bufferSize;
...@@ -20,47 +31,25 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -20,47 +31,25 @@ namespace Titanium.Web.Proxy.EventArguments
internal SessionEventArgs(int bufferSize) internal SessionEventArgs(int bufferSize)
{ {
_bufferSize = bufferSize; _bufferSize = bufferSize;
Client = new Client();
ProxySession = new Http.HttpWebSession();
} }
internal TcpClient Client { get; set; } public Client Client { get; set; }
internal Stream ClientStream { get; set; }
internal CustomBinaryReader ClientStreamReader { get; set; }
internal StreamWriter ClientStreamWriter { get; set; }
public bool IsHttps { get; internal set; } public bool IsHttps { get; internal set; }
public string RequestUrl { get; internal set; }
public string RequestHostname { get; internal set; }
public int ClientPort { get; internal set; } public HttpWebSession ProxySession { get; set; }
public IPAddress ClientIpAddress { get; internal set; }
internal Encoding RequestEncoding { get; set; }
internal Version RequestHttpVersion { get; set; }
internal bool RequestIsAlive { get; set; }
internal bool CancelRequest { get; set; }
internal byte[] RequestBody { get; set; }
internal string RequestBodyString { get; set; }
internal bool RequestBodyRead { get; set; }
public List<HttpHeader> RequestHeaders { get; internal set; }
internal bool RequestLocked { get; set; }
internal HttpWebSession ProxySession { get; set; }
internal Encoding ResponseEncoding { get; set; }
internal Stream ResponseStream { get; set; }
internal byte[] ResponseBody { get; set; }
internal string ResponseBodyString { get; set; }
internal bool ResponseBodyRead { get; set; }
public List<HttpHeader> ResponseHeaders { get; internal set; }
internal bool ResponseLocked { get; set; }
public int RequestContentLength public int RequestContentLength
{ {
get get
{ {
if (RequestHeaders.All(x => x.Name.ToLower() != "content-length")) return -1; if (ProxySession.Request.RequestHeaders.All(x => x.Name.ToLower() != "content-length")) return -1;
int contentLen; int contentLen;
int.TryParse(RequestHeaders.First(x => x.Name.ToLower() == "content-length").Value, out contentLen); int.TryParse(ProxySession.Request.RequestHeaders.First(x => x.Name.ToLower() == "content-length").Value, out contentLen);
if (contentLen != 0) if (contentLen != 0)
return contentLen; return contentLen;
return -1; return -1;
...@@ -82,8 +71,8 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -82,8 +71,8 @@ namespace Titanium.Web.Proxy.EventArguments
{ {
get get
{ {
return ResponseHeaders.Any(x => x.Name.ToLower() == "content-type") return ProxySession.Response.ResponseHeaders.Any(x => x.Name.ToLower() == "content-type")
? ResponseHeaders.First(x => x.Name.ToLower() == "content-type").Value ? ProxySession.Response.ResponseHeaders.First(x => x.Name.ToLower() == "content-type").Value
: null; : null;
} }
} }
...@@ -108,21 +97,21 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -108,21 +97,21 @@ namespace Titanium.Web.Proxy.EventArguments
"Please verify that this request is a Http POST/PUT and request content length is greater than zero before accessing the body."); "Please verify that this request is a Http POST/PUT and request content length is greater than zero before accessing the body.");
} }
if (RequestBody == null) if (ProxySession.Request.RequestBody == null)
{ {
var isChunked = false; var isChunked = false;
string requestContentEncoding = null; string requestContentEncoding = null;
if (RequestHeaders.Any(x => x.Name.ToLower() == "content-encoding")) if (ProxySession.Request.RequestHeaders.Any(x => x.Name.ToLower() == "content-encoding"))
{ {
requestContentEncoding = RequestHeaders.First(x => x.Name.ToLower() == "content-encoding").Value; requestContentEncoding = ProxySession.Request.RequestHeaders.First(x => x.Name.ToLower() == "content-encoding").Value;
} }
if (RequestHeaders.Any(x => x.Name.ToLower() == "transfer-encoding")) if (ProxySession.Request.RequestHeaders.Any(x => x.Name.ToLower() == "transfer-encoding"))
{ {
var transferEncoding = var transferEncoding =
RequestHeaders.First(x => x.Name.ToLower() == "transfer-encoding").Value.ToLower(); ProxySession.Request.RequestHeaders.First(x => x.Name.ToLower() == "transfer-encoding").Value.ToLower();
if (transferEncoding.Contains("chunked")) if (transferEncoding.Contains("chunked"))
{ {
isChunked = true; isChunked = true;
...@@ -131,7 +120,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -131,7 +120,7 @@ namespace Titanium.Web.Proxy.EventArguments
if (requestContentEncoding == null && !isChunked) if (requestContentEncoding == null && !isChunked)
RequestBody = ClientStreamReader.ReadBytes(RequestContentLength); ProxySession.Request.RequestBody = this.Client.ClientStreamReader.ReadBytes(RequestContentLength);
else else
{ {
using (var requestBodyStream = new MemoryStream()) using (var requestBodyStream = new MemoryStream())
...@@ -140,19 +129,19 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -140,19 +129,19 @@ namespace Titanium.Web.Proxy.EventArguments
{ {
while (true) while (true)
{ {
var chuchkHead = ClientStreamReader.ReadLine(); var chuchkHead = this.Client.ClientStreamReader.ReadLine();
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 = this.Client.ClientStreamReader.ReadBytes(chunkSize);
requestBodyStream.Write(buffer, 0, buffer.Length); requestBodyStream.Write(buffer, 0, buffer.Length);
//chunk trail //chunk trail
ClientStreamReader.ReadLine(); this.Client.ClientStreamReader.ReadLine();
} }
else else
{ {
ClientStreamReader.ReadLine(); this.Client.ClientStreamReader.ReadLine();
break; break;
} }
} }
...@@ -162,50 +151,50 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -162,50 +151,50 @@ namespace Titanium.Web.Proxy.EventArguments
switch (requestContentEncoding) switch (requestContentEncoding)
{ {
case "gzip": case "gzip":
RequestBody = CompressionHelper.DecompressGzip(requestBodyStream); ProxySession.Request.RequestBody = CompressionHelper.DecompressGzip(requestBodyStream);
break; break;
case "deflate": case "deflate":
RequestBody = CompressionHelper.DecompressDeflate(requestBodyStream); ProxySession.Request.RequestBody = CompressionHelper.DecompressDeflate(requestBodyStream);
break; break;
case "zlib": case "zlib":
RequestBody = CompressionHelper.DecompressZlib(requestBodyStream); ProxySession.Request.RequestBody = CompressionHelper.DecompressZlib(requestBodyStream);
break; break;
default: default:
RequestBody = requestBodyStream.ToArray(); ProxySession.Request.RequestBody = requestBodyStream.ToArray();
break; break;
} }
} }
catch catch
{ {
RequestBody = requestBodyStream.ToArray(); ProxySession.Request.RequestBody = requestBodyStream.ToArray();
} }
} }
} }
} }
RequestBodyRead = true; ProxySession.Request.RequestBodyRead = true;
} }
private void ReadResponseBody() private void ReadResponseBody()
{ {
if (ResponseBody == null) if (ProxySession.Response.ResponseBody == null)
{ {
switch ( ProxySession.Response.ResponseContentEncoding) switch (ProxySession.Response.ResponseContentEncoding)
{ {
case "gzip": case "gzip":
ResponseBody = CompressionHelper.DecompressGzip(ResponseStream); ProxySession.Response.ResponseBody = CompressionHelper.DecompressGzip(ProxySession.Response.ResponseStream);
break; break;
case "deflate": case "deflate":
ResponseBody = CompressionHelper.DecompressDeflate(ResponseStream); ProxySession.Response.ResponseBody = CompressionHelper.DecompressDeflate(ProxySession.Response.ResponseStream);
break; break;
case "zlib": case "zlib":
ResponseBody = CompressionHelper.DecompressZlib(ResponseStream); ProxySession.Response.ResponseBody = CompressionHelper.DecompressZlib(ProxySession.Response.ResponseStream);
break; break;
default: default:
ResponseBody = DecodeData(ResponseStream); ProxySession.Response.ResponseBody = DecodeData(ProxySession.Response.ResponseStream);
break; break;
} }
ResponseBodyRead = true; ProxySession.Response.ResponseBodyRead = true;
} }
} }
...@@ -227,116 +216,116 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -227,116 +216,116 @@ namespace Titanium.Web.Proxy.EventArguments
public Encoding GetRequestBodyEncoding() public Encoding GetRequestBodyEncoding()
{ {
if (RequestLocked) throw new Exception("You cannot call this function after request is made to server."); if (ProxySession.Request.RequestLocked) throw new Exception("You cannot call this function after request is made to server.");
return RequestEncoding; return ProxySession.Request.RequestEncoding;
} }
public byte[] GetRequestBody() public byte[] GetRequestBody()
{ {
if (RequestLocked) throw new Exception("You cannot call this function after request is made to server."); if (ProxySession.Request.RequestLocked) throw new Exception("You cannot call this function after request is made to server.");
ReadRequestBody(); ReadRequestBody();
return RequestBody; return ProxySession.Request.RequestBody;
} }
public string GetRequestBodyAsString() public string GetRequestBodyAsString()
{ {
if (RequestLocked) throw new Exception("You cannot call this function after request is made to server."); if (ProxySession.Request.RequestLocked) throw new Exception("You cannot call this function after request is made to server.");
ReadRequestBody(); ReadRequestBody();
return RequestBodyString ?? (RequestBodyString = RequestEncoding.GetString(RequestBody)); return ProxySession.Request.RequestBodyString ?? (ProxySession.Request.RequestBodyString = ProxySession.Request.RequestEncoding.GetString(ProxySession.Request.RequestBody));
} }
public void SetRequestBody(byte[] body) public void SetRequestBody(byte[] body)
{ {
if (RequestLocked) throw new Exception("You cannot call this function after request is made to server."); if (ProxySession.Request.RequestLocked) throw new Exception("You cannot call this function after request is made to server.");
if (!RequestBodyRead) if (!ProxySession.Request.RequestBodyRead)
{ {
ReadRequestBody(); ReadRequestBody();
} }
RequestBody = body; ProxySession.Request.RequestBody = body;
RequestBodyRead = true; ProxySession.Request.RequestBodyRead = true;
} }
public void SetRequestBodyString(string body) public void SetRequestBodyString(string body)
{ {
if (RequestLocked) throw new Exception("You cannot call this function after request is made to server."); if (ProxySession.Request.RequestLocked) throw new Exception("You cannot call this function after request is made to server.");
if (!RequestBodyRead) if (!ProxySession.Request.RequestBodyRead)
{ {
ReadRequestBody(); ReadRequestBody();
} }
RequestBody = RequestEncoding.GetBytes(body); ProxySession.Request.RequestBody = ProxySession.Request.RequestEncoding.GetBytes(body);
RequestBodyRead = true; ProxySession.Request.RequestBodyRead = true;
} }
public Encoding GetResponseBodyEncoding() public Encoding GetResponseBodyEncoding()
{ {
if (!RequestLocked) throw new Exception("You cannot call this function before request is made to server."); if (!ProxySession.Request.RequestLocked) throw new Exception("You cannot call this function before request is made to server.");
return ResponseEncoding; return ProxySession.Response.ResponseEncoding;
} }
public byte[] GetResponseBody() public byte[] GetResponseBody()
{ {
if (!RequestLocked) throw new Exception("You cannot call this function before request is made to server."); if (!ProxySession.Request.RequestLocked) throw new Exception("You cannot call this function before request is made to server.");
ReadResponseBody(); ReadResponseBody();
return ResponseBody; return ProxySession.Response.ResponseBody;
} }
public string GetResponseBodyAsString() public string GetResponseBodyAsString()
{ {
if (!RequestLocked) throw new Exception("You cannot call this function before request is made to server."); if (!ProxySession.Request.RequestLocked) throw new Exception("You cannot call this function before request is made to server.");
GetResponseBody(); GetResponseBody();
return ResponseBodyString ?? (ResponseBodyString = ResponseEncoding.GetString(ResponseBody)); return ProxySession.Response.ResponseBodyString ?? (ProxySession.Response.ResponseBodyString = ProxySession.Response.ResponseEncoding.GetString(ProxySession.Response.ResponseBody));
} }
public void SetResponseBody(byte[] body) public void SetResponseBody(byte[] body)
{ {
if (!RequestLocked) throw new Exception("You cannot call this function before request is made to server."); if (!ProxySession.Request.RequestLocked) throw new Exception("You cannot call this function before request is made to server.");
if (ResponseBody == null) if (ProxySession.Response.ResponseBody == null)
{ {
GetResponseBody(); GetResponseBody();
} }
ResponseBody = body; ProxySession.Response.ResponseBody = body;
} }
public void SetResponseBodyString(string body) public void SetResponseBodyString(string body)
{ {
if (!RequestLocked) throw new Exception("You cannot call this function before request is made to server."); if (!ProxySession.Request.RequestLocked) throw new Exception("You cannot call this function before request is made to server.");
if (ResponseBody == null) if (ProxySession.Response.ResponseBody == null)
{ {
GetResponseBody(); GetResponseBody();
} }
var bodyBytes = ResponseEncoding.GetBytes(body); var bodyBytes = ProxySession.Response.ResponseEncoding.GetBytes(body);
SetResponseBody(bodyBytes); SetResponseBody(bodyBytes);
} }
public void Ok(string html) public void Ok(string html)
{ {
if (RequestLocked) throw new Exception("You cannot call this function after request is made to server."); if (ProxySession.Request.RequestLocked) throw new Exception("You cannot call this function after request is made to server.");
if (html == null) if (html == null)
html = string.Empty; html = string.Empty;
var result = Encoding.Default.GetBytes(html); var result = Encoding.Default.GetBytes(html);
var connectStreamWriter = new StreamWriter(ClientStream); var connectStreamWriter = new StreamWriter(this.Client.ClientStream);
var s = string.Format("HTTP/{0}.{1} {2} {3}", RequestHttpVersion.Major, RequestHttpVersion.Minor, 200, "Ok"); var s = string.Format("HTTP/{0}.{1} {2} {3}", ProxySession.Request.RequestHttpVersion.Major, ProxySession.Request.RequestHttpVersion.Minor, 200, "Ok");
connectStreamWriter.WriteLine(s); connectStreamWriter.WriteLine(s);
connectStreamWriter.WriteLine("Timestamp: {0}", DateTime.Now); connectStreamWriter.WriteLine("Timestamp: {0}", DateTime.Now);
connectStreamWriter.WriteLine("content-length: " + result.Length); connectStreamWriter.WriteLine("content-length: " + result.Length);
...@@ -344,15 +333,15 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -344,15 +333,15 @@ namespace Titanium.Web.Proxy.EventArguments
connectStreamWriter.WriteLine("Pragma: no-cache"); connectStreamWriter.WriteLine("Pragma: no-cache");
connectStreamWriter.WriteLine("Expires: 0"); connectStreamWriter.WriteLine("Expires: 0");
connectStreamWriter.WriteLine(RequestIsAlive ? "Connection: Keep-Alive" : "Connection: close"); connectStreamWriter.WriteLine(ProxySession.Request.RequestIsAlive ? "Connection: Keep-Alive" : "Connection: close");
connectStreamWriter.WriteLine(); connectStreamWriter.WriteLine();
connectStreamWriter.Flush(); connectStreamWriter.Flush();
ClientStream.Write(result, 0, result.Length); this.Client.ClientStream.Write(result, 0, result.Length);
CancelRequest = true; ProxySession.Request.CancelRequest = true;
} }
} }
} }
\ No newline at end of file
...@@ -15,25 +15,29 @@ namespace Titanium.Web.Proxy.Http ...@@ -15,25 +15,29 @@ namespace Titanium.Web.Proxy.Http
public class Request public class Request
{ {
public string Method { get; set; } public string Method { get; set; }
public Uri RequestUri { get; set; } public Uri RequestUri { get; set; }
public string Version { get; set; } public string Version { get; set; }
public List<HttpHeader> RequestHeaders { get; set; }
public string RequestStatus { get; set; } public string RequestStatus { get; set; }
public int RequestContentLength { get; set; } public int RequestContentLength { get; set; }
public bool RequestSendChunked { get; set; } public bool RequestSendChunked { get; set; }
public string RequestContentType { get; set; } public string RequestContentType { get; set; }
public bool RequestKeepAlive { get; set; } public bool RequestKeepAlive { get; set; }
public string RequestHost { get; set; } public string RequestHost { get; set; }
public string RequestUrl { get; internal set; }
public string RequestHostname { get; internal set; }
internal Encoding RequestEncoding { get; set; }
internal Version RequestHttpVersion { get; set; }
internal bool RequestIsAlive { get; set; }
internal bool CancelRequest { get; set; }
internal byte[] RequestBody { get; set; }
internal string RequestBodyString { get; set; }
internal bool RequestBodyRead { get; set; }
public List<HttpHeader> RequestHeaders { get; internal set; }
internal bool RequestLocked { get; set; }
public Request() public Request()
{ {
this.RequestHeaders = new List<HttpHeader>(); this.RequestHeaders = new List<HttpHeader>();
...@@ -43,28 +47,28 @@ namespace Titanium.Web.Proxy.Http ...@@ -43,28 +47,28 @@ namespace Titanium.Web.Proxy.Http
public class Response public class Response
{ {
public List<HttpHeader> ResponseHeaders { get; set; } internal Encoding ResponseEncoding { get; set; }
internal Stream ResponseStream { get; set; }
internal byte[] ResponseBody { get; set; }
internal string ResponseBodyString { get; set; }
internal bool ResponseBodyRead { get; set; }
internal bool ResponseLocked { get; set; }
public List<HttpHeader> ResponseHeaders { get; internal set; }
public string ResponseCharacterSet { get; set; } public string ResponseCharacterSet { get; set; }
public string ResponseContentEncoding { get; set; } public string ResponseContentEncoding { get; set; }
public System.Version ResponseProtocolVersion { get; set; } public System.Version ResponseProtocolVersion { get; set; }
public string ResponseStatusCode { get; set; } public string ResponseStatusCode { get; set; }
public string ResponseStatusDescription { get; set; } public string ResponseStatusDescription { get; set; }
public bool ResponseKeepAlive { get; set; } public bool ResponseKeepAlive { get; set; }
public string ResponseContentType { get; set; } public string ResponseContentType { get; set; }
public int ContentLength { get; set; }
public Response() public Response()
{ {
this.ResponseHeaders = new List<HttpHeader>(); this.ResponseHeaders = new List<HttpHeader>();
} }
public int ContentLength { get; set; }
} }
public class HttpWebSession public class HttpWebSession
...@@ -81,12 +85,11 @@ namespace Titanium.Web.Proxy.Http ...@@ -81,12 +85,11 @@ namespace Titanium.Web.Proxy.Http
public Request Request { get; set; } public Request Request { get; set; }
public Response Response { get; set; } public Response Response { get; set; }
public TcpConnection Client { get; set; } public TcpConnection ProxyClient { get; set; }
public void SetConnection(TcpConnection Connection) public void SetConnection(TcpConnection Connection)
{ {
Client = Connection; ProxyClient = Connection;
ServerStreamReader = Client.ServerStreamReader;
} }
public HttpWebSession() public HttpWebSession()
...@@ -97,11 +100,11 @@ namespace Titanium.Web.Proxy.Http ...@@ -97,11 +100,11 @@ namespace Titanium.Web.Proxy.Http
} }
public CustomBinaryReader ServerStreamReader { get; set; }
public async Task SendRequest()
public void SendRequest()
{ {
Stream stream = Client.Stream; Stream stream = ProxyClient.Stream;
StringBuilder requestLines = new StringBuilder(); StringBuilder requestLines = new StringBuilder();
...@@ -122,13 +125,13 @@ namespace Titanium.Web.Proxy.Http ...@@ -122,13 +125,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);
await AsyncExtensions.WriteAsync((Stream)stream, requestBytes, 0, requestBytes.Length); stream.Write(requestBytes, 0, requestBytes.Length);
await AsyncExtensions.FlushAsync((Stream)stream); stream.Flush();
} }
public void ReceiveResponse() public void ReceiveResponse()
{ {
var httpResult = ServerStreamReader.ReadLine().Split(new char[] { ' ' }, 3); var httpResult = ProxyClient.ServerStreamReader.ReadLine().Split(new char[] { ' ' }, 3);
var httpVersion = httpResult[0]; var httpVersion = httpResult[0];
...@@ -148,7 +151,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -148,7 +151,7 @@ namespace Titanium.Web.Proxy.Http
this.Response.ResponseStatusDescription = status; this.Response.ResponseStatusDescription = status;
List<string> responseLines = ServerStreamReader.ReadAllLines(); List<string> responseLines = ProxyClient.ServerStreamReader.ReadAllLines();
for (int index = 0; index < responseLines.Count; ++index) for (int index = 0; index < responseLines.Count; ++index)
{ {
......
...@@ -22,25 +22,28 @@ namespace Titanium.Web.Proxy.Http ...@@ -22,25 +22,28 @@ namespace Titanium.Web.Proxy.Http
{ {
static ConcurrentDictionary<string, ConcurrentStack<TcpConnection>> ConnectionCache = new ConcurrentDictionary<string, ConcurrentStack<TcpConnection>>(); static ConcurrentDictionary<string, ConcurrentStack<TcpConnection>> ConnectionCache = new ConcurrentDictionary<string, ConcurrentStack<TcpConnection>>();
public static async Task<TcpConnection> GetClient(string Hostname, int port, bool IsSecure) public static TcpConnection GetClient(string Hostname, int port, bool IsSecure)
{ {
var key = string.Concat(Hostname, ":", port, ":", IsSecure); var key = string.Concat(Hostname, ":", port, ":", IsSecure);
TcpConnection client;
lock (ConnectionCache)
{
ConcurrentStack<TcpConnection> connections; ConcurrentStack<TcpConnection> connections;
if (!ConnectionCache.TryGetValue(key, out connections)) if (!ConnectionCache.TryGetValue(key, out connections))
{ {
return await CreateClient(Hostname, port, IsSecure); return CreateClient(Hostname, port, IsSecure);
} }
TcpConnection client;
if (!connections.TryPop(out client)) if (!connections.TryPop(out client))
{ {
return await CreateClient(Hostname, port, IsSecure); return CreateClient(Hostname, port, IsSecure);
}
} }
return client; return client;
} }
private static async Task<TcpConnection> CreateClient(string Hostname, int port, bool IsSecure) private static TcpConnection CreateClient(string Hostname, int port, bool IsSecure)
{ {
var client = new TcpClient(Hostname, port); var client = new TcpClient(Hostname, port);
var stream = (Stream)client.GetStream(); var stream = (Stream)client.GetStream();
...@@ -51,7 +54,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -51,7 +54,7 @@ namespace Titanium.Web.Proxy.Http
try try
{ {
sslStream = new SslStream(stream); sslStream = new SslStream(stream);
await AsyncPlatformExtensions.AuthenticateAsClientAsync(sslStream, Hostname); sslStream.AuthenticateAsClient(Hostname);
stream = (Stream)sslStream; stream = (Stream)sslStream;
} }
catch catch
...@@ -68,6 +71,8 @@ namespace Titanium.Web.Proxy.Http ...@@ -68,6 +71,8 @@ namespace Titanium.Web.Proxy.Http
public static void AddClient(string Hostname, int port, bool IsSecure, TcpConnection Client) public static void AddClient(string Hostname, int port, bool IsSecure, TcpConnection Client)
{ {
var key = string.Concat(Hostname, ":", port, ":", IsSecure); var key = string.Concat(Hostname, ":", port, ":", IsSecure);
lock (ConnectionCache)
{
ConcurrentStack<TcpConnection> connections; ConcurrentStack<TcpConnection> connections;
if (!ConnectionCache.TryGetValue(key, out connections)) if (!ConnectionCache.TryGetValue(key, out connections))
...@@ -78,6 +83,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -78,6 +83,7 @@ namespace Titanium.Web.Proxy.Http
} }
connections.Push(Client); connections.Push(Client);
}
} }
......
...@@ -112,7 +112,7 @@ namespace Titanium.Web.Proxy ...@@ -112,7 +112,7 @@ namespace Titanium.Web.Proxy
} }
private static async void HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream, private static void HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream,
CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, string secureTunnelHostName) CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, string secureTunnelHostName)
{ {
while (true) while (true)
...@@ -124,7 +124,7 @@ namespace Titanium.Web.Proxy ...@@ -124,7 +124,7 @@ namespace Titanium.Web.Proxy
} }
var args = new SessionEventArgs(BUFFER_SIZE); var args = new SessionEventArgs(BUFFER_SIZE);
args.Client = client; args.Client.TcpClient = client;
try try
{ {
...@@ -151,25 +151,26 @@ namespace Titanium.Web.Proxy ...@@ -151,25 +151,26 @@ namespace Titanium.Web.Proxy
args.IsHttps = true; args.IsHttps = true;
} }
args.RequestHeaders = new List<HttpHeader>();
args.ProxySession.Request.RequestHeaders = new List<HttpHeader>();
string tmpLine; string tmpLine;
while (!string.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine())) while (!string.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine()))
{ {
var header = tmpLine.Split(new char[] { ':' }, 2); var header = tmpLine.Split(new char[] { ':' }, 2);
args.RequestHeaders.Add(new HttpHeader(header[0], header[1])); args.ProxySession.Request.RequestHeaders.Add(new HttpHeader(header[0], header[1]));
} }
for (var i = 0; i < args.RequestHeaders.Count; i++) for (var i = 0; i < args.ProxySession.Request.RequestHeaders.Count; i++)
{ {
var rawHeader = args.RequestHeaders[i]; var rawHeader = args.ProxySession.Request.RequestHeaders[i];
//if request was upgrade to web-socket protocol then relay the request without proxying //if request was upgrade to web-socket protocol then relay the request without proxying
if ((rawHeader.Name.ToLower() == "upgrade") && (rawHeader.Value.ToLower() == "websocket")) if ((rawHeader.Name.ToLower() == "upgrade") && (rawHeader.Value.ToLower() == "websocket"))
{ {
TcpHelper.SendRaw(clientStreamReader.BaseStream, httpCmd, args.RequestHeaders, TcpHelper.SendRaw(clientStreamReader.BaseStream, httpCmd, args.ProxySession.Request.RequestHeaders,
httpRemoteUri.Host, httpRemoteUri.Port, httpRemoteUri.Scheme == Uri.UriSchemeHttps); httpRemoteUri.Host, httpRemoteUri.Port, httpRemoteUri.Scheme == Uri.UriSchemeHttps);
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args); Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
return; return;
...@@ -177,7 +178,7 @@ namespace Titanium.Web.Proxy ...@@ -177,7 +178,7 @@ namespace Titanium.Web.Proxy
} }
args.ProxySession = new Http.HttpWebSession();
args.ProxySession.Request.RequestUri = httpRemoteUri; args.ProxySession.Request.RequestUri = httpRemoteUri;
...@@ -186,16 +187,16 @@ namespace Titanium.Web.Proxy ...@@ -186,16 +187,16 @@ namespace Titanium.Web.Proxy
args.ProxySession.Request.Method = httpMethod; args.ProxySession.Request.Method = httpMethod;
args.ProxySession.Request.Version = httpVersion; args.ProxySession.Request.Version = httpVersion;
// args.ProxyRequest.ProtocolVersion = version; // args.ProxyRequest.ProtocolVersion = version;
args.ClientStream = clientStream; args.Client.ClientStream = clientStream;
args.ClientStreamReader = clientStreamReader; args.Client.ClientStreamReader = clientStreamReader;
args.ClientStreamWriter = clientStreamWriter; args.Client.ClientStreamWriter = clientStreamWriter;
// args.ProxyRequest.AllowAutoRedirect = false; // args.ProxyRequest.AllowAutoRedirect = false;
// args.ProxyRequest.AutomaticDecompression = DecompressionMethods.None; // args.ProxyRequest.AutomaticDecompression = DecompressionMethods.None;
args.RequestHostname = args.ProxySession.Request.RequestUri.Host; args.ProxySession.Request.RequestHostname = args.ProxySession.Request.RequestUri.Host;
args.RequestUrl = args.ProxySession.Request.RequestUri.OriginalString; args.ProxySession.Request.RequestUrl = args.ProxySession.Request.RequestUri.OriginalString;
args.ClientPort = ((IPEndPoint)client.Client.RemoteEndPoint).Port; args.Client.ClientPort = ((IPEndPoint)client.Client.RemoteEndPoint).Port;
args.ClientIpAddress = ((IPEndPoint)client.Client.RemoteEndPoint).Address; args.Client.ClientIpAddress = ((IPEndPoint)client.Client.RemoteEndPoint).Address;
args.RequestHttpVersion = version; args.ProxySession.Request.RequestHttpVersion = version;
//args.RequestIsAlive = args.ProxyRequest.KeepAlive; //args.RequestIsAlive = args.ProxyRequest.KeepAlive;
//args.ProxyRequest.AllowWriteStreamBuffering = true; //args.ProxyRequest.AllowWriteStreamBuffering = true;
...@@ -204,30 +205,30 @@ namespace Titanium.Web.Proxy ...@@ -204,30 +205,30 @@ namespace Titanium.Web.Proxy
//If requested interception //If requested interception
if (BeforeRequest != null) if (BeforeRequest != null)
{ {
args.RequestEncoding = args.ProxySession.GetEncoding(); args.ProxySession.Request.RequestEncoding = args.ProxySession.GetEncoding();
BeforeRequest(null, args); BeforeRequest(null, args);
} }
args.RequestLocked = true; args.ProxySession.Request.RequestLocked = true;
if (args.CancelRequest) if (args.ProxySession.Request.CancelRequest)
{ {
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args); Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
return; return;
} }
SetRequestHeaders(args.RequestHeaders, args.ProxySession); SetRequestHeaders(args.ProxySession.Request.RequestHeaders, args.ProxySession);
//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.
var connection = await TcpConnectionManager.GetClient(args.ProxySession.Request.RequestUri.Host, args.ProxySession.Request.RequestUri.Port, args.IsHttps); var connection = TcpConnectionManager.GetClient(args.ProxySession.Request.RequestUri.Host, args.ProxySession.Request.RequestUri.Port, args.IsHttps);
args.ProxySession.SetConnection(connection); args.ProxySession.SetConnection(connection);
await args.ProxySession.SendRequest(); args.ProxySession.SendRequest();
//If request was modified by user //If request was modified by user
if (args.RequestBodyRead) if (args.ProxySession.Request.RequestBodyRead)
{ {
args.ProxySession.Request.RequestContentLength = args.RequestBody.Length; args.ProxySession.Request.RequestContentLength = args.ProxySession.Request.RequestBody.Length;
var newStream = args.ProxySession.ServerStreamReader.BaseStream; var newStream = args.ProxySession.ProxyClient.ServerStreamReader.BaseStream;
newStream.Write(args.RequestBody, 0, args.RequestBody.Length); newStream.Write(args.ProxySession.Request.RequestBody, 0, args.ProxySession.Request.RequestBody.Length);
} }
else else
{ {
...@@ -241,14 +242,15 @@ namespace Titanium.Web.Proxy ...@@ -241,14 +242,15 @@ namespace Titanium.Web.Proxy
HandleHttpSessionResponse(args); HandleHttpSessionResponse(args);
//if connection is closing exit //if connection is closing exit
if (args.ResponseHeaders.Any(x => x.Name.ToLower() == "connection" && x.Value.ToLower() == "close")) if (args.ProxySession.Response.ResponseHeaders.Any(x => x.Name.ToLower() == "connection" && x.Value.ToLower() == "close"))
{ {
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args); Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
return; return;
} }
TcpConnectionManager.AddClient(args.ProxySession.Request.RequestUri.Host, args.ProxySession.Request.RequestUri.Port, args.IsHttps, args.ProxySession.Client); //if (args.ProxySession.ProxyClient.Client.Connected)
// read the next request // TcpConnectionManager.AddClient(args.ProxySession.Request.RequestUri.Host, args.ProxySession.Request.RequestUri.Port, args.IsHttps, args.ProxySession.ProxyClient);
// // read the next request
httpCmd = clientStreamReader.ReadLine(); httpCmd = clientStreamReader.ReadLine();
} }
...@@ -380,7 +382,7 @@ namespace Titanium.Web.Proxy ...@@ -380,7 +382,7 @@ namespace Titanium.Web.Proxy
private static void SendClientRequestBody(SessionEventArgs args) private static void SendClientRequestBody(SessionEventArgs args)
{ {
// End the operation // End the operation
var postStream = args.ProxySession.ServerStreamReader; var postStream = args.ProxySession.ProxyClient.ServerStreamReader;
if (args.ProxySession.Request.RequestContentLength > 0) if (args.ProxySession.Request.RequestContentLength > 0)
...@@ -401,7 +403,7 @@ namespace Titanium.Web.Proxy ...@@ -401,7 +403,7 @@ namespace Titanium.Web.Proxy
while (totalbytesRead < (int)args.ProxySession.Request.RequestContentLength) while (totalbytesRead < (int)args.ProxySession.Request.RequestContentLength)
{ {
var buffer = args.ClientStreamReader.ReadBytes(bytesToRead); var buffer = args.Client.ClientStreamReader.ReadBytes(bytesToRead);
totalbytesRead += buffer.Length; totalbytesRead += buffer.Length;
var remainingBytes = (int)args.ProxySession.Request.RequestContentLength - totalbytesRead; var remainingBytes = (int)args.ProxySession.Request.RequestContentLength - totalbytesRead;
...@@ -412,12 +414,12 @@ namespace Titanium.Web.Proxy ...@@ -412,12 +414,12 @@ namespace Titanium.Web.Proxy
postStream.BaseStream.Write(buffer, 0, buffer.Length); postStream.BaseStream.Write(buffer, 0, buffer.Length);
} }
postStream.Close(); //postStream.Close();
} }
catch catch
{ {
postStream.Close(); // postStream.Close();
postStream.Dispose(); // postStream.Dispose();
throw; throw;
} }
} }
...@@ -430,30 +432,30 @@ namespace Titanium.Web.Proxy ...@@ -430,30 +432,30 @@ namespace Titanium.Web.Proxy
{ {
while (true) while (true)
{ {
var chuchkHead = args.ClientStreamReader.ReadLine(); var chuchkHead = args.Client.ClientStreamReader.ReadLine();
var chunkSize = int.Parse(chuchkHead, NumberStyles.HexNumber); var chunkSize = int.Parse(chuchkHead, NumberStyles.HexNumber);
if (chunkSize != 0) if (chunkSize != 0)
{ {
var buffer = args.ClientStreamReader.ReadBytes(chunkSize); var buffer = args.Client.ClientStreamReader.ReadBytes(chunkSize);
postStream.BaseStream.Write(buffer, 0, buffer.Length); postStream.BaseStream.Write(buffer, 0, buffer.Length);
//chunk trail //chunk trail
args.ClientStreamReader.ReadLine(); args.Client.ClientStreamReader.ReadLine();
} }
else else
{ {
args.ClientStreamReader.ReadLine(); args.Client.ClientStreamReader.ReadLine();
break; break;
} }
} }
postStream.Close(); //postStream.Close();
} }
catch catch
{ {
postStream.Close(); // postStream.Close();
postStream.Dispose(); // postStream.Dispose();
throw; throw;
} }
......
...@@ -26,19 +26,19 @@ namespace Titanium.Web.Proxy ...@@ -26,19 +26,19 @@ namespace Titanium.Web.Proxy
try try
{ {
args.ResponseHeaders = ReadResponseHeaders(args.ProxySession); args.ProxySession.Response.ResponseHeaders = ReadResponseHeaders(args.ProxySession);
args.ResponseStream = args.ProxySession.ServerStreamReader.BaseStream; args.ProxySession.Response.ResponseStream = args.ProxySession.ProxyClient.ServerStreamReader.BaseStream;
if (BeforeResponse != null) if (BeforeResponse != null)
{ {
args.ResponseEncoding = args.ProxySession.GetResponseEncoding(); args.ProxySession.Response.ResponseEncoding = args.ProxySession.GetResponseEncoding();
BeforeResponse(null, args); BeforeResponse(null, args);
} }
args.ResponseLocked = true; args.ProxySession.Response.ResponseLocked = true;
if (args.ResponseBodyRead) if (args.ProxySession.Response.ResponseBodyRead)
{ {
var isChunked = args.ProxySession.Response.ResponseHeaders.Any(x => x.Name.ToLower() == "transfer-encoding" && x.Value.ToLower().Contains("chunked")); var isChunked = args.ProxySession.Response.ResponseHeaders.Any(x => x.Name.ToLower() == "transfer-encoding" && x.Value.ToLower().Contains("chunked"));
var contentEncoding = args.ProxySession.Response.ResponseContentEncoding; var contentEncoding = args.ProxySession.Response.ResponseContentEncoding;
...@@ -46,40 +46,40 @@ namespace Titanium.Web.Proxy ...@@ -46,40 +46,40 @@ namespace Titanium.Web.Proxy
switch (contentEncoding.ToLower()) switch (contentEncoding.ToLower())
{ {
case "gzip": case "gzip":
args.ResponseBody = CompressionHelper.CompressGzip(args.ResponseBody); args.ProxySession.Response.ResponseBody = CompressionHelper.CompressGzip(args.ProxySession.Response.ResponseBody);
break; break;
case "deflate": case "deflate":
args.ResponseBody = CompressionHelper.CompressDeflate(args.ResponseBody); args.ProxySession.Response.ResponseBody = CompressionHelper.CompressDeflate(args.ProxySession.Response.ResponseBody);
break; break;
case "zlib": case "zlib":
args.ResponseBody = CompressionHelper.CompressZlib(args.ResponseBody); args.ProxySession.Response.ResponseBody = CompressionHelper.CompressZlib(args.ProxySession.Response.ResponseBody);
break; break;
} }
WriteResponseStatus(args.ProxySession.Response.ResponseProtocolVersion, args.ProxySession.Response.ResponseStatusCode, WriteResponseStatus(args.ProxySession.Response.ResponseProtocolVersion, args.ProxySession.Response.ResponseStatusCode,
args.ProxySession.Response.ResponseStatusDescription, args.ClientStreamWriter); args.ProxySession.Response.ResponseStatusDescription, args.Client.ClientStreamWriter);
WriteResponseHeaders(args.ClientStreamWriter, args.ResponseHeaders, args.ResponseBody.Length, WriteResponseHeaders(args.Client.ClientStreamWriter, args.ProxySession.Response.ResponseHeaders, args.ProxySession.Response.ResponseBody.Length,
isChunked); isChunked);
WriteResponseBody(args.ClientStream, args.ResponseBody, isChunked); WriteResponseBody(args.Client.ClientStream, args.ProxySession.Response.ResponseBody, isChunked);
} }
else else
{ {
var isChunked = args.ProxySession.Response.ResponseHeaders.Any(x => x.Name.ToLower() == "transfer-encoding" && x.Value.ToLower().Contains("chunked")); var isChunked = args.ProxySession.Response.ResponseHeaders.Any(x => x.Name.ToLower() == "transfer-encoding" && x.Value.ToLower().Contains("chunked"));
WriteResponseStatus(args.ProxySession.Response.ResponseProtocolVersion, args.ProxySession.Response.ResponseStatusCode, WriteResponseStatus(args.ProxySession.Response.ResponseProtocolVersion, args.ProxySession.Response.ResponseStatusCode,
args.ProxySession.Response.ResponseStatusDescription, args.ClientStreamWriter); args.ProxySession.Response.ResponseStatusDescription, args.Client.ClientStreamWriter);
WriteResponseHeaders(args.ClientStreamWriter, args.ResponseHeaders); WriteResponseHeaders(args.Client.ClientStreamWriter, args.ProxySession.Response.ResponseHeaders);
if (isChunked || args.ProxySession.Response.ContentLength > 0) if (isChunked || args.ProxySession.Response.ContentLength > 0)
WriteResponseBody(args.ResponseStream, args.ClientStream, isChunked, args.ProxySession.Response.ContentLength); WriteResponseBody(args.ProxySession.ProxyClient.ServerStreamReader, args.Client.ClientStream, isChunked, args.ProxySession.Response.ContentLength);
} }
args.ClientStream.Flush(); args.Client.ClientStream.Flush();
} }
catch catch
{ {
Dispose(args.Client, args.ClientStream, args.ClientStreamReader, args.ClientStreamWriter, args); Dispose(args.Client.TcpClient, args.Client.ClientStream, args.Client.ClientStreamReader, args.Client.ClientStreamWriter, args);
} }
finally finally
{ {
...@@ -199,7 +199,7 @@ namespace Titanium.Web.Proxy ...@@ -199,7 +199,7 @@ namespace Titanium.Web.Proxy
WriteResponseBodyChunked(data, clientStream); WriteResponseBodyChunked(data, clientStream);
} }
private static void WriteResponseBody(Stream inStream, Stream outStream, bool isChunked, int BodyLength) private static void WriteResponseBody(CustomBinaryReader inStreamReader, Stream outStream, bool isChunked, int BodyLength)
{ {
if (!isChunked) if (!isChunked)
{ {
...@@ -213,7 +213,7 @@ namespace Titanium.Web.Proxy ...@@ -213,7 +213,7 @@ namespace Titanium.Web.Proxy
var bytesRead = 0; var bytesRead = 0;
var totalBytesRead = 0; var totalBytesRead = 0;
while ((bytesRead += inStream.Read(buffer, 0, bytesToRead)) > 0) while ((bytesRead += inStreamReader.BaseStream.Read(buffer, 0, bytesToRead)) > 0)
{ {
outStream.Write(buffer, 0, bytesRead); outStream.Write(buffer, 0, bytesRead);
totalBytesRead += bytesRead; totalBytesRead += bytesRead;
...@@ -227,13 +227,12 @@ namespace Titanium.Web.Proxy ...@@ -227,13 +227,12 @@ namespace Titanium.Web.Proxy
} }
} }
else else
WriteResponseBodyChunked(inStream, outStream); WriteResponseBodyChunked(inStreamReader, outStream);
} }
//Send chunked response //Send chunked response
private static void WriteResponseBodyChunked(Stream inStream, Stream outStream) private static void WriteResponseBodyChunked(CustomBinaryReader inStreamReader, Stream outStream)
{ {
var inStreamReader = new CustomBinaryReader(inStream, Encoding.ASCII);
while (true) while (true)
{ {
var chuchkHead = inStreamReader.ReadLine(); var chuchkHead = inStreamReader.ReadLine();
......
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