Commit fe4d5ee9 authored by titanium007's avatar titanium007

Expose only properties that are safer to user

parent 214be692
......@@ -76,11 +76,11 @@ namespace Titanium.Web.Proxy.Test
if (index >= 0)
{
string URL = e.Decode();
string URL = e.GetRequestHtmlBody();
if (_lastURL != URL)
{
OnChanged(new VisitedEventArgs() { hostname = e.Hostname, URL = URL, remoteIP = e.ipAddress, remotePort = e.Port });
OnChanged(new VisitedEventArgs() { hostname = e.RequestHostname, URL = URL, remoteIP = e.ClientIpAddress, remotePort = e.ClientPort });
}
......@@ -106,7 +106,7 @@ namespace Titanium.Web.Proxy.Test
string c = e.ServerResponse.GetResponseHeader("X-Requested-With");
if (e.ServerResponse.GetResponseHeader("X-Requested-With") == "")
{
e.GetResponseBody();
string responseHtmlBody = e.GetResponseHtmlBody();
string functioname = "fr" + RandomString(10);
string VisitedURL = RandomString(5);
......@@ -116,10 +116,10 @@ namespace Titanium.Web.Proxy.Test
string RandomLastRequest = RandomString(10);
string LocalRequest;
if (e.IsSecure)
LocalRequest = "https://" + e.Hostname + "/" + RandomURLEnding;
if (e.IsSSLRequest)
LocalRequest = "https://" + e.RequestHostname + "/" + RandomURLEnding;
else
LocalRequest = "http://" + e.Hostname + "/" + RandomURLEnding;
LocalRequest = "http://" + e.RequestHostname + "/" + RandomURLEnding;
string script = "var " + RandomLastRequest + " = null;" +
"if(window.top==self) { " + "\n" +
......@@ -135,13 +135,13 @@ namespace Titanium.Web.Proxy.Test
RequestVariable + ".open(\"POST\",\"" + LocalRequest + "\", true); " + "\n" +
RequestVariable + ".send(" + VisitedURL + ");} " + RandomLastRequest + " = " + VisitedURL + "}";
string response = e.ResponseString;
Regex RE = new Regex("</body>", RegexOptions.RightToLeft | RegexOptions.IgnoreCase | RegexOptions.Multiline);
string replaced = RE.Replace(response, "<script type =\"text/javascript\">" + script + "</script></body>", 1);
if (replaced.Length != response.Length)
string modifiedResponseHtmlBody = RE.Replace(responseHtmlBody, "<script type =\"text/javascript\">" + script + "</script></body>", 1);
if (modifiedResponseHtmlBody.Length != responseHtmlBody.Length)
{
e.ResponseString = replaced;
e.SetRequestHtmlBody(modifiedResponseHtmlBody);
_URLList.Add(RandomURLEnding);
}
......
......@@ -9,84 +9,70 @@ namespace Titanium.Web.Proxy.Models
{
public class SessionEventArgs : EventArgs
{
public string RequestURL { get; set; }
public string Hostname { get; set; }
public CustomBinaryReader ClientStreamReader { get; set; }
public string ResponseString { get; set; }
public int RequestLength { get; set; }
public Stream ClientStream { get; set; }
public Version HttpVersion { get; set; }
public bool IsAlive { get; set; }
public bool Cancel { get; set; }
public bool IsSecure { get; set; }
public int Port { get; set; }
private int BUFFER_SIZE;
public HttpWebResponse ServerResponse { get; set; }
public Stream ServerResponseStream { get; set; }
public string RequestHostname { get; set; }
public bool IsSSLRequest { get; set; }
public int ClientPort { get; set; }
public IPAddress ClientIpAddress { get; set; }
public HttpWebRequest ProxyRequest { get; set; }
public Encoding Encoding { get; set; }
public bool WasModified { get; set; }
public System.Threading.ManualResetEvent FinishedRequestEvent { get; set; }
public string UpgradeProtocol { get; set; }
public HttpWebResponse ServerResponse { get; set; }
internal int BUFFER_SIZE;
internal int RequestLength { get; set; }
internal Version RequestHttpVersion { get; set; }
internal bool RequestIsAlive { get; set; }
internal bool CancelRequest { get; set; }
internal CustomBinaryReader ClientStreamReader { get; set; }
internal Stream ClientStream { get; set; }
internal Stream ServerResponseStream { get; set; }
internal Encoding Encoding { get; set; }
internal bool WasModified { get; set; }
internal System.Threading.ManualResetEvent FinishedRequestEvent { get; set; }
internal string UpgradeProtocol { get; set; }
internal string RequestHtmlBody { get; set; }
internal string ResponseHtmlBody { get; set; }
public SessionEventArgs(int BufferSize)
{
BUFFER_SIZE = BufferSize;
}
public string Decode()
public string GetRequestHtmlBody()
{
if (RequestHtmlBody == null)
{
int bytesRead;
int totalBytesRead = 0;
MemoryStream mw = new MemoryStream();
var buffer = ClientStreamReader.ReadBytes(RequestLength);
while (totalBytesRead < RequestLength && (bytesRead = buffer.Length) > 0)
{
totalBytesRead += bytesRead;
mw.Write(buffer, 0, bytesRead);
int bytesRead;
int totalBytesRead = 0;
MemoryStream mw = new MemoryStream();
var buffer = ClientStreamReader.ReadBytes(RequestLength);
while (totalBytesRead < RequestLength && (bytesRead = buffer.Length) > 0)
{
totalBytesRead += bytesRead;
mw.Write(buffer, 0, bytesRead);
}
mw.Close();
RequestHtmlBody = Encoding.Default.GetString(mw.ToArray());
}
mw.Close();
return Encoding.Default.GetString(mw.ToArray());
return RequestHtmlBody;
}
public void Ok(string Html)
public void SetRequestHtmlBody(string Body)
{
if (Html == null)
Html = string.Empty;
var result = Encoding.Default.GetBytes(Html);
StreamWriter connectStreamWriter = new StreamWriter(ClientStream);
var s = String.Format("HTTP/{0}.{1} {2} {3}", HttpVersion.Major, HttpVersion.Minor, 200, "Ok");
connectStreamWriter.WriteLine(s);
connectStreamWriter.WriteLine(String.Format("Timestamp: {0}", DateTime.Now.ToString()));
connectStreamWriter.WriteLine("content-length: " + result.Length);
connectStreamWriter.WriteLine("Cache-Control: no-cache, no-store, must-revalidate");
connectStreamWriter.WriteLine("Pragma: no-cache");
connectStreamWriter.WriteLine("Expires: 0");
if (IsAlive)
{
connectStreamWriter.WriteLine("Connection: Keep-Alive");
}
else
connectStreamWriter.WriteLine("Connection: close");
connectStreamWriter.WriteLine();
connectStreamWriter.Flush();
ClientStream.Write(result, 0, result.Length);
Cancel = true;
this.RequestHtmlBody = Body;
}
public void GetResponseBody()
public string GetResponseHtmlBody()
{
if (ResponseString == null)
if (ResponseHtmlBody == null)
{
Encoding = Encoding.GetEncoding(ServerResponse.CharacterSet);
......@@ -110,9 +96,16 @@ namespace Titanium.Web.Proxy.Models
ResponseData = DecodeData(ServerResponseStream, Encoding);
break;
}
ResponseString = ResponseData;
ResponseHtmlBody = ResponseData;
WasModified = true;
}
return ResponseHtmlBody;
}
public void SetResponseHtmlBody(string Body)
{
this.ResponseHtmlBody = Body;
}
//stream reader not recomended for images
private string DecodeData(Stream ResponseStream, Encoding e)
......@@ -122,12 +115,45 @@ namespace Titanium.Web.Proxy.Models
}
public void Ok(string Html)
{
if (Html == null)
Html = string.Empty;
var result = Encoding.Default.GetBytes(Html);
StreamWriter connectStreamWriter = new StreamWriter(ClientStream);
var s = String.Format("HTTP/{0}.{1} {2} {3}", RequestHttpVersion.Major, RequestHttpVersion.Minor, 200, "Ok");
connectStreamWriter.WriteLine(s);
connectStreamWriter.WriteLine(String.Format("Timestamp: {0}", DateTime.Now.ToString()));
connectStreamWriter.WriteLine("content-length: " + result.Length);
connectStreamWriter.WriteLine("Cache-Control: no-cache, no-store, must-revalidate");
connectStreamWriter.WriteLine("Pragma: no-cache");
connectStreamWriter.WriteLine("Expires: 0");
if (RequestIsAlive)
{
connectStreamWriter.WriteLine("Connection: Keep-Alive");
}
else
connectStreamWriter.WriteLine("Connection: close");
connectStreamWriter.WriteLine();
connectStreamWriter.Flush();
ClientStream.Write(result, 0, result.Length);
CancelRequest = true;
}
public IPAddress ipAddress { get; set; }
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Authentication;
using System.Net.Sockets;
using System.Diagnostics;
using System.Security.Cryptography.X509Certificates;
using System.Reflection;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy
{
partial class ProxyServer
{
private static void HandleClientRequest(TcpClient Client)
{
string connectionGroup = null;
Stream clientStream = null;
CustomBinaryReader clientStreamReader = null;
StreamWriter connectStreamWriter = null;
string tunnelHostName = null;
int tunnelPort = 0;
try
{
connectionGroup = Dns.GetHostEntry(((IPEndPoint)Client.Client.RemoteEndPoint).Address).HostName;
clientStream = Client.GetStream();
clientStreamReader = new CustomBinaryReader(clientStream, Encoding.ASCII);
string securehost = null;
List<string> requestLines = new List<string>();
string tmpLine;
while (!String.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine()))
{
requestLines.Add(tmpLine);
}
//read the first line HTTP command
String httpCmd = requestLines.Count > 0 ? requestLines[0] : null;
if (String.IsNullOrEmpty(httpCmd))
{
throw new EndOfStreamException();
}
//break up the line into three components
String[] splitBuffer = httpCmd.Split(spaceSplit, 3);
String method = splitBuffer[0];
String remoteUri = splitBuffer[1];
Version version;
string RequestVersion;
if (splitBuffer[2] == "HTTP/1.1")
{
version = new Version(1, 1);
RequestVersion = "HTTP/1.1";
}
else
{
version = new Version(1, 0);
RequestVersion = "HTTP/1.0";
}
if (splitBuffer[0].ToUpper() == "CONNECT")
{
//Browser wants to create a secure tunnel
//instead = we are going to perform a man in the middle "attack"
//the user's browser should warn them of the certification errors,
//so we need to install our root certficate in users machine as Certificate Authority.
remoteUri = "https://" + splitBuffer[1];
tunnelHostName = splitBuffer[1].Split(':')[0];
int.TryParse(splitBuffer[1].Split(':')[1], out tunnelPort);
if (tunnelPort == 0) tunnelPort = 80;
var isSecure = true;
for (int i = 1; i < requestLines.Count; i++)
{
var rawHeader = requestLines[i];
String[] header = rawHeader.ToLower().Trim().Split(colonSpaceSplit, 2, StringSplitOptions.None);
if ((header[0] == "host"))
{
var hostDetails = header[1].ToLower().Trim().Split(':');
if (hostDetails.Length > 1)
{
isSecure = false;
}
}
}
requestLines.Clear();
connectStreamWriter = new StreamWriter(clientStream);
connectStreamWriter.WriteLine(RequestVersion + " 200 Connection established");
connectStreamWriter.WriteLine(String.Format("Timestamp: {0}", DateTime.Now.ToString()));
connectStreamWriter.WriteLine(String.Format("connection:close"));
connectStreamWriter.WriteLine();
connectStreamWriter.Flush();
if (tunnelPort != 443)
{
TcpHelper.SendRaw(tunnelHostName, tunnelPort, clientStreamReader.BaseStream);
if (clientStream != null)
clientStream.Close();
return;
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Authentication;
using System.Net.Sockets;
using System.Diagnostics;
using System.Security.Cryptography.X509Certificates;
using System.Reflection;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy
{
partial class ProxyServer
{
private static void HandleClientRequest(TcpClient Client)
{
string connectionGroup = null;
Stream clientStream = null;
CustomBinaryReader clientStreamReader = null;
StreamWriter connectStreamWriter = null;
string tunnelHostName = null;
int tunnelPort = 0;
try
{
connectionGroup = Dns.GetHostEntry(((IPEndPoint)Client.Client.RemoteEndPoint).Address).HostName;
clientStream = Client.GetStream();
clientStreamReader = new CustomBinaryReader(clientStream, Encoding.ASCII);
string securehost = null;
List<string> requestLines = new List<string>();
string tmpLine;
while (!String.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine()))
{
requestLines.Add(tmpLine);
}
//read the first line HTTP command
String httpCmd = requestLines.Count > 0 ? requestLines[0] : null;
if (String.IsNullOrEmpty(httpCmd))
{
throw new EndOfStreamException();
}
//break up the line into three components
String[] splitBuffer = httpCmd.Split(spaceSplit, 3);
String method = splitBuffer[0];
String remoteUri = splitBuffer[1];
Version version;
string RequestVersion;
if (splitBuffer[2] == "HTTP/1.1")
{
version = new Version(1, 1);
RequestVersion = "HTTP/1.1";
}
else
{
version = new Version(1, 0);
RequestVersion = "HTTP/1.0";
}
if (splitBuffer[0].ToUpper() == "CONNECT")
{
//Browser wants to create a secure tunnel
//instead = we are going to perform a man in the middle "attack"
//the user's browser should warn them of the certification errors,
//so we need to install our root certficate in users machine as Certificate Authority.
remoteUri = "https://" + splitBuffer[1];
tunnelHostName = splitBuffer[1].Split(':')[0];
int.TryParse(splitBuffer[1].Split(':')[1], out tunnelPort);
if (tunnelPort == 0) tunnelPort = 80;
var isSecure = true;
for (int i = 1; i < requestLines.Count; i++)
{
var rawHeader = requestLines[i];
String[] header = rawHeader.ToLower().Trim().Split(colonSpaceSplit, 2, StringSplitOptions.None);
if ((header[0] == "host"))
{
var hostDetails = header[1].ToLower().Trim().Split(':');
if (hostDetails.Length > 1)
{
isSecure = false;
}
}
}
requestLines.Clear();
connectStreamWriter = new StreamWriter(clientStream);
connectStreamWriter.WriteLine(RequestVersion + " 200 Connection established");
connectStreamWriter.WriteLine(String.Format("Timestamp: {0}", DateTime.Now.ToString()));
connectStreamWriter.WriteLine(String.Format("connection:close"));
connectStreamWriter.WriteLine();
connectStreamWriter.Flush();
if (tunnelPort != 443)
{
TcpHelper.SendRaw(tunnelHostName, tunnelPort, clientStreamReader.BaseStream);
if (clientStream != null)
clientStream.Close();
return;
}
Monitor.Enter(certificateAccessLock);
var _certificate = ProxyServer.CertManager.CreateCertificate(tunnelHostName); //CertificateHelper.GetCertificate(RootCertificateName, tunnelHostName);
Monitor.Exit(certificateAccessLock);
SslStream sslStream = null;
if (!pinnedCertificateClients.Contains(tunnelHostName) && isSecure)
{
sslStream = new SslStream(clientStream, true);
try
{
sslStream.AuthenticateAsServer(_certificate, false, SslProtocols.Tls | SslProtocols.Ssl3 | SslProtocols.Ssl2, false);
}
catch (AuthenticationException ex)
{
if (pinnedCertificateClients.Contains(tunnelHostName) == false)
{
pinnedCertificateClients.Add(tunnelHostName);
}
throw ex;
}
}
else
{
TcpHelper.SendRaw(tunnelHostName, tunnelPort, clientStreamReader.BaseStream);
if (clientStream != null)
clientStream.Close();
return;
}
clientStreamReader = new CustomBinaryReader(sslStream, Encoding.ASCII);
//HTTPS server created - we can now decrypt the client's traffic
clientStream = sslStream;
while (!String.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine()))
{
requestLines.Add(tmpLine);
}
//read the new http command.
httpCmd = requestLines.Count > 0 ? requestLines[0] : null;
if (String.IsNullOrEmpty(httpCmd))
{
throw new EndOfStreamException();
}
securehost = remoteUri;
}
int count = 0;
SessionEventArgs args = new SessionEventArgs(BUFFER_SIZE);
while (!String.IsNullOrEmpty(httpCmd))
{
count++;
MemoryStream mw = null;
StreamWriter sw = null;
args = new SessionEventArgs(BUFFER_SIZE);
try
{
splitBuffer = httpCmd.Split(spaceSplit, 3);
if (splitBuffer.Length != 3)
{
TcpHelper.SendRaw(httpCmd, tunnelHostName, ref requestLines, args.IsSecure, clientStreamReader.BaseStream);
if (clientStream != null)
clientStream.Close();
return;
}
method = splitBuffer[0];
remoteUri = splitBuffer[1];
if (splitBuffer[2] == "HTTP/1.1")
{
version = new Version(1, 1);
}
else
{
version = new Version(1, 0);
}
if (securehost != null)
{
remoteUri = securehost + remoteUri;
args.IsSecure = true;
}
//construct the web request that we are going to issue on behalf of the client.
args.ProxyRequest = (HttpWebRequest)HttpWebRequest.Create(remoteUri.Trim());
args.ProxyRequest.Proxy = null;
args.ProxyRequest.UseDefaultCredentials = true;
args.ProxyRequest.Method = method;
args.ProxyRequest.ProtocolVersion = version;
args.ClientStream = clientStream;
args.ClientStreamReader = clientStreamReader;
for (int i = 1; i < requestLines.Count; i++)
{
var rawHeader = requestLines[i];
String[] header = rawHeader.ToLower().Trim().Split(colonSpaceSplit, 2, StringSplitOptions.None);
if ((header[0] == "upgrade") && (header[1] == "websocket"))
{
TcpHelper.SendRaw(httpCmd, tunnelHostName, ref requestLines, args.IsSecure, clientStreamReader.BaseStream);
if (clientStream != null)
clientStream.Close();
return;
}
}
ReadRequestHeaders(ref requestLines, args.ProxyRequest);
int contentLen = (int)args.ProxyRequest.ContentLength;
args.ProxyRequest.AllowAutoRedirect = false;
args.ProxyRequest.AutomaticDecompression = DecompressionMethods.None;
if (BeforeRequest != null)
{
args.Hostname = args.ProxyRequest.RequestUri.Host;
args.RequestURL = args.ProxyRequest.RequestUri.OriginalString;
args.RequestLength = contentLen;
args.HttpVersion = version;
args.Port = ((IPEndPoint)Client.Client.RemoteEndPoint).Port;
args.ipAddress = ((IPEndPoint)Client.Client.RemoteEndPoint).Address;
args.IsAlive = args.ProxyRequest.KeepAlive;
BeforeRequest(null, args);
}
if (args.Cancel)
{
if (args.IsAlive)
{
requestLines.Clear();
while (!String.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine()))
{
requestLines.Add(tmpLine);
}
httpCmd = requestLines.Count > 0 ? requestLines[0] : null;
continue;
}
else
break;
}
args.ProxyRequest.ConnectionGroupName = connectionGroup;
args.ProxyRequest.AllowWriteStreamBuffering = true;
args.FinishedRequestEvent = new ManualResetEvent(false);
if (method.ToUpper() == "POST" || method.ToUpper() == "PUT")
{
args.ProxyRequest.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), args);
}
else
{
args.ProxyRequest.BeginGetResponse(new AsyncCallback(HandleServerResponse), args);
}
if (args.IsSecure)
{
if (args.ProxyRequest.Method == "POST" || args.ProxyRequest.Method == "PUT")
args.FinishedRequestEvent.WaitOne();
else
args.FinishedRequestEvent.Set();
}
else
args.FinishedRequestEvent.WaitOne();
httpCmd = null;
if (args.ProxyRequest.KeepAlive)
{
requestLines.Clear();
while (!String.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine()))
{
requestLines.Add(tmpLine);
}
httpCmd = requestLines.Count() > 0 ? requestLines[0] : null;
}
if (args.ServerResponse != null)
args.ServerResponse.Close();
}
catch (IOException ex)
{
throw ex;
}
catch (UriFormatException ex)
{
throw ex;
}
catch (WebException ex)
{
throw ex;
}
finally
{
if (sw != null) sw.Close();
if (mw != null) mw.Close();
if (args.ProxyRequest != null) args.ProxyRequest.Abort();
if (args.ServerResponseStream != null) args.ServerResponseStream.Close();
}
}
}
catch (AuthenticationException ex)
{
Debug.WriteLine(ex.Message);
}
catch (EndOfStreamException ex)
{
Debug.WriteLine(ex.Message);
}
catch (IOException ex)
{
Debug.WriteLine(ex.Message);
}
catch (UriFormatException ex)
{
Debug.WriteLine(ex.Message);
}
catch (WebException ex)
{
Debug.WriteLine(ex.Message);
}
finally
{
if (connectStreamWriter != null)
connectStreamWriter.Close();
if (clientStreamReader != null)
clientStreamReader.Close();
if (clientStream != null)
clientStream.Close();
}
}
private static void ReadRequestHeaders(ref List<string> RequestLines, HttpWebRequest WebRequest)
{
for (int i = 1; i < RequestLines.Count; i++)
{
String httpCmd = RequestLines[i];
String[] header = httpCmd.Split(colonSpaceSplit, 2, StringSplitOptions.None);
if (!String.IsNullOrEmpty(header[0].Trim()))
switch (header[0].ToLower())
{
case "accept":
WebRequest.Accept = header[1];
break;
case "accept-encoding":
WebRequest.Headers.Add(header[0], "gzip,deflate,zlib");
break;
case "cookie":
WebRequest.Headers["Cookie"] = header[1];
break;
case "connection":
if (header[1].ToLower() == "keep-alive")
WebRequest.KeepAlive = true;
break;
case "content-length":
int contentLen;
int.TryParse(header[1], out contentLen);
if (contentLen != 0)
WebRequest.ContentLength = contentLen;
break;
case "content-type":
WebRequest.ContentType = header[1];
break;
case "expect":
if (header[1].ToLower() == "100-continue")
WebRequest.ServicePoint.Expect100Continue = true;
else
WebRequest.Expect = header[1];
break;
case "host":
WebRequest.Host = header[1];
break;
case "if-modified-since":
String[] sb = header[1].Trim().Split(semiSplit);
DateTime d;
if (DateTime.TryParse(sb[0], out d))
WebRequest.IfModifiedSince = d;
break;
case "proxy-connection":
break;
case "range":
var startEnd = header[1].Replace(Environment.NewLine, "").Remove(0, 6).Split('-');
if (startEnd.Length > 1) { if (!String.IsNullOrEmpty(startEnd[1])) WebRequest.AddRange(int.Parse(startEnd[0]), int.Parse(startEnd[1])); else WebRequest.AddRange(int.Parse(startEnd[0])); }
else
WebRequest.AddRange(int.Parse(startEnd[0]));
break;
case "referer":
WebRequest.Referer = header[1];
break;
case "user-agent":
WebRequest.UserAgent = header[1];
break;
case "transfer-encoding":
if (header[1].ToLower() == "chunked")
WebRequest.SendChunked = true;
else
WebRequest.SendChunked = false;
break;
case "upgrade":
if (header[1].ToLower() == "http/1.1")
WebRequest.Headers.Add(header[0], header[1]);
break;
default:
if (header.Length > 0)
WebRequest.Headers.Add(header[0], header[1]);
else
WebRequest.Headers.Add(header[0], "");
break;
}
}
}
private static void GetRequestStreamCallback(IAsyncResult AsynchronousResult)
{
var args = (SessionEventArgs)AsynchronousResult.AsyncState;
// End the operation
Stream postStream = args.ProxyRequest.EndGetRequestStream(AsynchronousResult);
if (args.ProxyRequest.ContentLength > 0)
{
args.ProxyRequest.AllowWriteStreamBuffering = true;
try
{
int totalbytesRead = 0;
int bytesToRead;
if (args.ProxyRequest.ContentLength < BUFFER_SIZE)
{
bytesToRead = (int)args.ProxyRequest.ContentLength;
}
else
bytesToRead = BUFFER_SIZE;
while (totalbytesRead < (int)args.ProxyRequest.ContentLength)
{
var buffer = args.ClientStreamReader.ReadBytes(bytesToRead);
totalbytesRead += buffer.Length;
int RemainingBytes = (int)args.ProxyRequest.ContentLength - totalbytesRead;
if (RemainingBytes < bytesToRead)
{
bytesToRead = RemainingBytes;
}
postStream.Write(buffer, 0, buffer.Length);
}
postStream.Close();
}
catch (IOException ex)
{
args.ProxyRequest.KeepAlive = false;
args.FinishedRequestEvent.Set();
Debug.WriteLine(ex.Message);
return;
}
catch (WebException ex)
{
args.ProxyRequest.KeepAlive = false;
args.FinishedRequestEvent.Set();
Debug.WriteLine(ex.Message);
return;
}
}
else if (args.ProxyRequest.SendChunked)
{
args.ProxyRequest.AllowWriteStreamBuffering = true;
try
{
StringBuilder sb = new StringBuilder();
byte[] byteRead = new byte[1];
while (true)
{
args.ClientStream.Read(byteRead, 0, 1);
sb.Append(Encoding.ASCII.GetString(byteRead));
if (sb.ToString().EndsWith(Environment.NewLine))
{
var chunkSizeInHex = sb.ToString().Replace(Environment.NewLine, String.Empty);
var chunckSize = int.Parse(chunkSizeInHex, System.Globalization.NumberStyles.HexNumber);
if (chunckSize == 0)
{
for (int i = 0; i < Encoding.ASCII.GetByteCount(Environment.NewLine); i++)
{
args.ClientStream.ReadByte();
}
break;
}
var totalbytesRead = 0;
int bytesToRead;
if (chunckSize < BUFFER_SIZE)
{
bytesToRead = chunckSize;
}
else
bytesToRead = BUFFER_SIZE;
while (totalbytesRead < chunckSize)
{
var buffer = args.ClientStreamReader.ReadBytes(bytesToRead);
totalbytesRead += buffer.Length;
int RemainingBytes = chunckSize - totalbytesRead;
if (RemainingBytes < bytesToRead)
{
bytesToRead = RemainingBytes;
}
postStream.Write(buffer, 0, buffer.Length);
}
for (int i = 0; i < Encoding.ASCII.GetByteCount(Environment.NewLine); i++)
{
args.ClientStream.ReadByte();
}
sb.Clear();
}
}
postStream.Close();
}
catch (IOException ex)
{
if (postStream != null)
postStream.Close();
args.ProxyRequest.KeepAlive = false;
args.FinishedRequestEvent.Set();
Debug.WriteLine(ex.Message);
return;
}
catch (WebException ex)
{
if (postStream != null)
postStream.Close();
args.ProxyRequest.KeepAlive = false;
args.FinishedRequestEvent.Set();
Debug.WriteLine(ex.Message);
return;
}
}
args.ProxyRequest.BeginGetResponse(new AsyncCallback(HandleServerResponse), args);
}
}
var _certificate = ProxyServer.CertManager.CreateCertificate(tunnelHostName); //CertificateHelper.GetCertificate(RootCertificateName, tunnelHostName);
Monitor.Exit(certificateAccessLock);
SslStream sslStream = null;
if (!pinnedCertificateClients.Contains(tunnelHostName) && isSecure)
{
sslStream = new SslStream(clientStream, true);
try
{
sslStream.AuthenticateAsServer(_certificate, false, SslProtocols.Tls | SslProtocols.Ssl3 | SslProtocols.Ssl2, false);
}
catch (AuthenticationException ex)
{
if (pinnedCertificateClients.Contains(tunnelHostName) == false)
{
pinnedCertificateClients.Add(tunnelHostName);
}
throw ex;
}
}
else
{
TcpHelper.SendRaw(tunnelHostName, tunnelPort, clientStreamReader.BaseStream);
if (clientStream != null)
clientStream.Close();
return;
}
clientStreamReader = new CustomBinaryReader(sslStream, Encoding.ASCII);
//HTTPS server created - we can now decrypt the client's traffic
clientStream = sslStream;
while (!String.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine()))
{
requestLines.Add(tmpLine);
}
//read the new http command.
httpCmd = requestLines.Count > 0 ? requestLines[0] : null;
if (String.IsNullOrEmpty(httpCmd))
{
throw new EndOfStreamException();
}
securehost = remoteUri;
}
int count = 0;
SessionEventArgs args = new SessionEventArgs(BUFFER_SIZE);
while (!String.IsNullOrEmpty(httpCmd))
{
count++;
MemoryStream mw = null;
StreamWriter sw = null;
args = new SessionEventArgs(BUFFER_SIZE);
try
{
splitBuffer = httpCmd.Split(spaceSplit, 3);
if (splitBuffer.Length != 3)
{
TcpHelper.SendRaw(httpCmd, tunnelHostName, ref requestLines, args.IsSSLRequest, clientStreamReader.BaseStream);
if (clientStream != null)
clientStream.Close();
return;
}
method = splitBuffer[0];
remoteUri = splitBuffer[1];
if (splitBuffer[2] == "HTTP/1.1")
{
version = new Version(1, 1);
}
else
{
version = new Version(1, 0);
}
if (securehost != null)
{
remoteUri = securehost + remoteUri;
args.IsSSLRequest = true;
}
//construct the web request that we are going to issue on behalf of the client.
args.ProxyRequest = (HttpWebRequest)HttpWebRequest.Create(remoteUri.Trim());
args.ProxyRequest.Proxy = null;
args.ProxyRequest.UseDefaultCredentials = true;
args.ProxyRequest.Method = method;
args.ProxyRequest.ProtocolVersion = version;
args.ClientStream = clientStream;
args.ClientStreamReader = clientStreamReader;
for (int i = 1; i < requestLines.Count; i++)
{
var rawHeader = requestLines[i];
String[] header = rawHeader.ToLower().Trim().Split(colonSpaceSplit, 2, StringSplitOptions.None);
if ((header[0] == "upgrade") && (header[1] == "websocket"))
{
TcpHelper.SendRaw(httpCmd, tunnelHostName, ref requestLines, args.IsSSLRequest, clientStreamReader.BaseStream);
if (clientStream != null)
clientStream.Close();
return;
}
}
ReadRequestHeaders(ref requestLines, args.ProxyRequest);
int contentLen = (int)args.ProxyRequest.ContentLength;
args.ProxyRequest.AllowAutoRedirect = false;
args.ProxyRequest.AutomaticDecompression = DecompressionMethods.None;
if (BeforeRequest != null)
{
args.RequestHostname = args.ProxyRequest.RequestUri.Host;
args.RequestURL = args.ProxyRequest.RequestUri.OriginalString;
args.RequestLength = contentLen;
args.RequestHttpVersion = version;
args.ClientPort = ((IPEndPoint)Client.Client.RemoteEndPoint).Port;
args.ClientIpAddress = ((IPEndPoint)Client.Client.RemoteEndPoint).Address;
args.RequestIsAlive = args.ProxyRequest.KeepAlive;
BeforeRequest(null, args);
}
if (args.CancelRequest)
{
if (args.RequestIsAlive)
{
requestLines.Clear();
while (!String.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine()))
{
requestLines.Add(tmpLine);
}
httpCmd = requestLines.Count > 0 ? requestLines[0] : null;
continue;
}
else
break;
}
args.ProxyRequest.ConnectionGroupName = connectionGroup;
args.ProxyRequest.AllowWriteStreamBuffering = true;
args.FinishedRequestEvent = new ManualResetEvent(false);
if (method.ToUpper() == "POST" || method.ToUpper() == "PUT")
{
args.ProxyRequest.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), args);
}
else
{
args.ProxyRequest.BeginGetResponse(new AsyncCallback(HandleServerResponse), args);
}
if (args.IsSSLRequest)
{
if (args.ProxyRequest.Method == "POST" || args.ProxyRequest.Method == "PUT")
args.FinishedRequestEvent.WaitOne();
else
args.FinishedRequestEvent.Set();
}
else
args.FinishedRequestEvent.WaitOne();
httpCmd = null;
if (args.ProxyRequest.KeepAlive)
{
requestLines.Clear();
while (!String.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine()))
{
requestLines.Add(tmpLine);
}
httpCmd = requestLines.Count() > 0 ? requestLines[0] : null;
}
if (args.ServerResponse != null)
args.ServerResponse.Close();
}
catch (IOException ex)
{
throw ex;
}
catch (UriFormatException ex)
{
throw ex;
}
catch (WebException ex)
{
throw ex;
}
finally
{
if (sw != null) sw.Close();
if (mw != null) mw.Close();
if (args.ProxyRequest != null) args.ProxyRequest.Abort();
if (args.ServerResponseStream != null) args.ServerResponseStream.Close();
}
}
}
catch (AuthenticationException ex)
{
Debug.WriteLine(ex.Message);
}
catch (EndOfStreamException ex)
{
Debug.WriteLine(ex.Message);
}
catch (IOException ex)
{
Debug.WriteLine(ex.Message);
}
catch (UriFormatException ex)
{
Debug.WriteLine(ex.Message);
}
catch (WebException ex)
{
Debug.WriteLine(ex.Message);
}
finally
{
if (connectStreamWriter != null)
connectStreamWriter.Close();
if (clientStreamReader != null)
clientStreamReader.Close();
if (clientStream != null)
clientStream.Close();
}
}
private static void ReadRequestHeaders(ref List<string> RequestLines, HttpWebRequest WebRequest)
{
for (int i = 1; i < RequestLines.Count; i++)
{
String httpCmd = RequestLines[i];
String[] header = httpCmd.Split(colonSpaceSplit, 2, StringSplitOptions.None);
if (!String.IsNullOrEmpty(header[0].Trim()))
switch (header[0].ToLower())
{
case "accept":
WebRequest.Accept = header[1];
break;
case "accept-encoding":
WebRequest.Headers.Add(header[0], "gzip,deflate,zlib");
break;
case "cookie":
WebRequest.Headers["Cookie"] = header[1];
break;
case "connection":
if (header[1].ToLower() == "keep-alive")
WebRequest.KeepAlive = true;
break;
case "content-length":
int contentLen;
int.TryParse(header[1], out contentLen);
if (contentLen != 0)
WebRequest.ContentLength = contentLen;
break;
case "content-type":
WebRequest.ContentType = header[1];
break;
case "expect":
if (header[1].ToLower() == "100-continue")
WebRequest.ServicePoint.Expect100Continue = true;
else
WebRequest.Expect = header[1];
break;
case "host":
WebRequest.Host = header[1];
break;
case "if-modified-since":
String[] sb = header[1].Trim().Split(semiSplit);
DateTime d;
if (DateTime.TryParse(sb[0], out d))
WebRequest.IfModifiedSince = d;
break;
case "proxy-connection":
break;
case "range":
var startEnd = header[1].Replace(Environment.NewLine, "").Remove(0, 6).Split('-');
if (startEnd.Length > 1) { if (!String.IsNullOrEmpty(startEnd[1])) WebRequest.AddRange(int.Parse(startEnd[0]), int.Parse(startEnd[1])); else WebRequest.AddRange(int.Parse(startEnd[0])); }
else
WebRequest.AddRange(int.Parse(startEnd[0]));
break;
case "referer":
WebRequest.Referer = header[1];
break;
case "user-agent":
WebRequest.UserAgent = header[1];
break;
case "transfer-encoding":
if (header[1].ToLower() == "chunked")
WebRequest.SendChunked = true;
else
WebRequest.SendChunked = false;
break;
case "upgrade":
if (header[1].ToLower() == "http/1.1")
WebRequest.Headers.Add(header[0], header[1]);
break;
default:
if (header.Length > 0)
WebRequest.Headers.Add(header[0], header[1]);
else
WebRequest.Headers.Add(header[0], "");
break;
}
}
}
private static void GetRequestStreamCallback(IAsyncResult AsynchronousResult)
{
var args = (SessionEventArgs)AsynchronousResult.AsyncState;
// End the operation
Stream postStream = args.ProxyRequest.EndGetRequestStream(AsynchronousResult);
if (args.ProxyRequest.ContentLength > 0)
{
args.ProxyRequest.AllowWriteStreamBuffering = true;
try
{
int totalbytesRead = 0;
int bytesToRead;
if (args.ProxyRequest.ContentLength < BUFFER_SIZE)
{
bytesToRead = (int)args.ProxyRequest.ContentLength;
}
else
bytesToRead = BUFFER_SIZE;
while (totalbytesRead < (int)args.ProxyRequest.ContentLength)
{
var buffer = args.ClientStreamReader.ReadBytes(bytesToRead);
totalbytesRead += buffer.Length;
int RemainingBytes = (int)args.ProxyRequest.ContentLength - totalbytesRead;
if (RemainingBytes < bytesToRead)
{
bytesToRead = RemainingBytes;
}
postStream.Write(buffer, 0, buffer.Length);
}
postStream.Close();
}
catch (IOException ex)
{
args.ProxyRequest.KeepAlive = false;
args.FinishedRequestEvent.Set();
Debug.WriteLine(ex.Message);
return;
}
catch (WebException ex)
{
args.ProxyRequest.KeepAlive = false;
args.FinishedRequestEvent.Set();
Debug.WriteLine(ex.Message);
return;
}
}
else if (args.ProxyRequest.SendChunked)
{
args.ProxyRequest.AllowWriteStreamBuffering = true;
try
{
StringBuilder sb = new StringBuilder();
byte[] byteRead = new byte[1];
while (true)
{
args.ClientStream.Read(byteRead, 0, 1);
sb.Append(Encoding.ASCII.GetString(byteRead));
if (sb.ToString().EndsWith(Environment.NewLine))
{
var chunkSizeInHex = sb.ToString().Replace(Environment.NewLine, String.Empty);
var chunckSize = int.Parse(chunkSizeInHex, System.Globalization.NumberStyles.HexNumber);
if (chunckSize == 0)
{
for (int i = 0; i < Encoding.ASCII.GetByteCount(Environment.NewLine); i++)
{
args.ClientStream.ReadByte();
}
break;
}
var totalbytesRead = 0;
int bytesToRead;
if (chunckSize < BUFFER_SIZE)
{
bytesToRead = chunckSize;
}
else
bytesToRead = BUFFER_SIZE;
while (totalbytesRead < chunckSize)
{
var buffer = args.ClientStreamReader.ReadBytes(bytesToRead);
totalbytesRead += buffer.Length;
int RemainingBytes = chunckSize - totalbytesRead;
if (RemainingBytes < bytesToRead)
{
bytesToRead = RemainingBytes;
}
postStream.Write(buffer, 0, buffer.Length);
}
for (int i = 0; i < Encoding.ASCII.GetByteCount(Environment.NewLine); i++)
{
args.ClientStream.ReadByte();
}
sb.Clear();
}
}
postStream.Close();
}
catch (IOException ex)
{
if (postStream != null)
postStream.Close();
args.ProxyRequest.KeepAlive = false;
args.FinishedRequestEvent.Set();
Debug.WriteLine(ex.Message);
return;
}
catch (WebException ex)
{
if (postStream != null)
postStream.Close();
args.ProxyRequest.KeepAlive = false;
args.FinishedRequestEvent.Set();
Debug.WriteLine(ex.Message);
return;
}
}
args.ProxyRequest.BeginGetResponse(new AsyncCallback(HandleServerResponse), args);
}
}
}
\ No newline at end of file
......@@ -62,25 +62,25 @@ namespace Titanium.Web.Proxy
switch (args.ServerResponse.ContentEncoding)
{
case "gzip":
data = CompressionHelper.CompressGzip(args.ResponseString, args.Encoding);
data = CompressionHelper.CompressGzip(args.ResponseHtmlBody, args.Encoding);
WriteResponseStatus(args.ServerResponse.ProtocolVersion, args.ServerResponse.StatusCode, args.ServerResponse.StatusDescription, responseWriter);
WriteResponseHeaders(responseWriter, responseHeaders, data.Length);
SendData(clientWriteStream, data, isChunked);
break;
case "deflate":
data = CompressionHelper.CompressDeflate(args.ResponseString, args.Encoding);
data = CompressionHelper.CompressDeflate(args.ResponseHtmlBody, args.Encoding);
WriteResponseStatus(args.ServerResponse.ProtocolVersion, args.ServerResponse.StatusCode, args.ServerResponse.StatusDescription, responseWriter);
WriteResponseHeaders(responseWriter, responseHeaders, data.Length);
SendData(clientWriteStream, data, isChunked);
break;
case "zlib":
data = CompressionHelper.CompressZlib(args.ResponseString, args.Encoding);
data = CompressionHelper.CompressZlib(args.ResponseHtmlBody, args.Encoding);
WriteResponseStatus(args.ServerResponse.ProtocolVersion, args.ServerResponse.StatusCode, args.ServerResponse.StatusDescription, responseWriter);
WriteResponseHeaders(responseWriter, responseHeaders, data.Length);
SendData(clientWriteStream, data, isChunked);
break;
default:
data = EncodeData(args.ResponseString, args.Encoding);
data = EncodeData(args.ResponseHtmlBody, args.Encoding);
WriteResponseStatus(args.ServerResponse.ProtocolVersion, args.ServerResponse.StatusCode, args.ServerResponse.StatusDescription, responseWriter);
WriteResponseHeaders(responseWriter, responseHeaders, data.Length);
SendData(clientWriteStream, data, isChunked);
......
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