Commit 23f1d181 authored by justcoding121's avatar justcoding121 Committed by justcoding121

Fix request body modification

parent 3c1c351e
...@@ -64,14 +64,30 @@ Sample request and response event handlers ...@@ -64,14 +64,30 @@ Sample request and response event handlers
```csharp ```csharp
//Test On Request, intecept requests
//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);
if (e.RequestURL.Contains("somewebsite.com"))
if ((e.ProxyRequest.Method.ToUpper() == "POST" || e.ProxyRequest.Method.ToUpper() == "PUT") && e.ProxyRequest.ContentLength > 0)
{
var m = e.GetRequestBody().Replace("a", "b");
e.SetRequestBody(m);
}
//To cancel a request with a custom HTML content //To cancel a request with a custom HTML content
//Filter URL //Filter URL
if (e.RequestURL.Contains("somewebsite.com")) if (e.RequestURL.Contains("somewebsite.com"))
{ {
e.Ok("<!DOCTYPE html><html><body><h1>Blocked</h1><p>website blocked.</p></body></html>"); e.Ok("<!DOCTYPE html><html><body><h1>Blocked</h1><p>Website blocked.</p></body></html>");
} }
} }
public void OnResponse(object sender, SessionEventArgs e) public void OnResponse(object sender, SessionEventArgs e)
...@@ -81,11 +97,14 @@ Sample request and response event handlers ...@@ -81,11 +97,14 @@ Sample request and response event handlers
if (e.ServerResponse.ContentType.Trim().ToLower().Contains("text/html")) if (e.ServerResponse.ContentType.Trim().ToLower().Contains("text/html"))
{ {
//Get response body //Get response body
string responseHtmlBody = e.GetResponseHtmlBody(); string responseBody = e.GetResponseBody();
//Modify e.ServerResponse //Modify e.ServerResponse
responseHtmlBody = "<html><head></head><body>Response is modified!</body></html>"; Regex rex = new Regex("</body>", RegexOptions.RightToLeft | RegexOptions.IgnoreCase | RegexOptions.Multiline);
string modified = rex.Replace(responseBody, "<script type =\"text/javascript\">alert('Response was modified by this script!');</script></body>", 1);
//Set modifed response Html Body //Set modifed response Html Body
e.SetResponseHtmlBody(responseHtmlBody); e.SetResponseBody(modified);
} }
} }
} }
......
...@@ -24,20 +24,21 @@ namespace Titanium.Web.Proxy.Test ...@@ -24,20 +24,21 @@ namespace Titanium.Web.Proxy.Test
public void StartProxy() public void StartProxy()
{ {
ProxyServer.BeforeRequest += OnRequest; ProxyServer.BeforeRequest += OnRequest;
ProxyServer.BeforeResponse += OnResponse; ProxyServer.BeforeResponse += OnResponse;
ProxyServer.EnableSSL = EnableSSL; ProxyServer.EnableSSL = EnableSSL;
ProxyServer.SetAsSystemProxy = SetAsSystemProxy; ProxyServer.SetAsSystemProxy = SetAsSystemProxy;
//Exclude Https addresses you don't want to proxy
//Usefull for clients that use certificate pinning
//for example dropbox.com
ProxyServer.ExcludedHttpsHostNameRegex.Add(".dropbox.com");
ProxyServer.Start(); ProxyServer.Start();
ProxyServer.ListeningPort = ProxyServer.ListeningPort;
ListeningPort = ProxyServer.ListeningPort;
Console.WriteLine(String.Format("Proxy listening on local machine port: {0} ", ProxyServer.ListeningPort)); Console.WriteLine(String.Format("Proxy listening on local machine port: {0} ", ProxyServer.ListeningPort));
...@@ -59,13 +60,22 @@ namespace Titanium.Web.Proxy.Test ...@@ -59,13 +60,22 @@ namespace Titanium.Web.Proxy.Test
Console.WriteLine(e.RequestURL); Console.WriteLine(e.RequestURL);
if (e.RequestURL.Contains("somewebsite.com"))
if ((e.ProxyRequest.Method.ToUpper() == "POST" || e.ProxyRequest.Method.ToUpper() == "PUT") && e.ProxyRequest.ContentLength > 0)
{
var m = e.GetRequestBody().Replace("a", "b");
e.SetRequestBody(m);
}
//To cancel a request with a custom HTML content //To cancel a request with a custom HTML content
//Filter URL //Filter URL
//if (e.RequestURL.Contains("somewebsite.com")) if (e.RequestURL.Contains("somewebsite.com"))
//{ {
// e.Ok("<!DOCTYPE html><html><body><h1>Blocked</h1><p>website blocked.</p></body></html>"); e.Ok("<!DOCTYPE html><html><body><h1>Blocked</h1><p>Website blocked.</p></body></html>");
//} }
} }
...@@ -75,18 +85,21 @@ namespace Titanium.Web.Proxy.Test ...@@ -75,18 +85,21 @@ namespace Titanium.Web.Proxy.Test
{ {
//To modify a response //To modify a response
//if (e.ServerResponse.StatusCode == HttpStatusCode.OK) if (e.ServerResponse.StatusCode == HttpStatusCode.OK)
//{ {
// if (e.ServerResponse.ContentType.Trim().ToLower().Contains("text/html")) if (e.ServerResponse.ContentType.Trim().ToLower().Contains("text/html"))
// { {
// //Get response body //Get response body
// string responseHtmlBody = e.GetResponseHtmlBody(); string responseBody = e.GetResponseBody();
// //Modify e.ServerResponse
// responseHtmlBody = "<html><head></head><body>Response is modified!</body></html>"; //Modify e.ServerResponse
// //Set modifed response Html Body Regex rex = new Regex("</body>", RegexOptions.RightToLeft | RegexOptions.IgnoreCase | RegexOptions.Multiline);
// e.SetResponseHtmlBody(responseHtmlBody); string modified = rex.Replace(responseBody, "<script type =\"text/javascript\">alert('Response was modified by this script!');</script></body>", 1);
// }
//} //Set modifed response Html Body
e.SetResponseBody(modified);
}
}
} }
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Titanium.Web.Proxy.Exceptions
{
public class BodyNotFoundException : Exception
{
public BodyNotFoundException(string message)
:base(message)
{
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
namespace Titanium.Web.Proxy.Extensions
{
public static class HttpWebRequestExtensions
{
public static Encoding GetEncoding(this HttpWebRequest request)
{
try
{
if (request.ContentType == null) return Encoding.GetEncoding("ISO-8859-1");
var contentTypes = request.ContentType.Split(';');
foreach (var contentType in contentTypes)
{
var encodingSplit = contentType.Split('=');
if (encodingSplit.Length == 2 && encodingSplit[0].ToLower().Trim() == "charset")
{
return Encoding.GetEncoding(encodingSplit[1]);
}
}
}
catch { }
return Encoding.GetEncoding("ISO-8859-1");
}
}
}
...@@ -31,9 +31,6 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -31,9 +31,6 @@ namespace Titanium.Web.Proxy.Helpers
Task sendRelay = Task.Factory.StartNew(() => StreamHelper.CopyTo(clientStream, tunnelStream, BUFFER_SIZE)); Task sendRelay = Task.Factory.StartNew(() => StreamHelper.CopyTo(clientStream, tunnelStream, BUFFER_SIZE));
Task receiveRelay = Task.Factory.StartNew(() => StreamHelper.CopyTo(tunnelStream, clientStream, BUFFER_SIZE)); Task receiveRelay = Task.Factory.StartNew(() => StreamHelper.CopyTo(tunnelStream, clientStream, BUFFER_SIZE));
sendRelay.Start();
receiveRelay.Start();
Task.WaitAll(sendRelay, receiveRelay); Task.WaitAll(sendRelay, receiveRelay);
} }
catch catch
...@@ -118,9 +115,6 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -118,9 +115,6 @@ namespace Titanium.Web.Proxy.Helpers
var sendRelay = new Task(() => StreamHelper.CopyTo(sb.ToString(), clientStream, tunnelStream, BUFFER_SIZE)); var sendRelay = new Task(() => StreamHelper.CopyTo(sb.ToString(), clientStream, tunnelStream, BUFFER_SIZE));
var receiveRelay = new Task(() => StreamHelper.CopyTo(tunnelStream, clientStream, BUFFER_SIZE)); var receiveRelay = new Task(() => StreamHelper.CopyTo(tunnelStream, clientStream, BUFFER_SIZE));
sendRelay.Start();
receiveRelay.Start();
Task.WaitAll(sendRelay, receiveRelay); Task.WaitAll(sendRelay, receiveRelay);
} }
catch catch
......
...@@ -4,6 +4,7 @@ using System.IO; ...@@ -4,6 +4,7 @@ using System.IO;
using System.Net; using System.Net;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
using System.Net.Sockets; using System.Net.Sockets;
using Titanium.Web.Proxy.Exceptions;
namespace Titanium.Web.Proxy.Models namespace Titanium.Web.Proxy.Models
...@@ -18,25 +19,25 @@ namespace Titanium.Web.Proxy.Models ...@@ -18,25 +19,25 @@ namespace Titanium.Web.Proxy.Models
internal CustomBinaryReader ClientStreamReader { get; set; } internal CustomBinaryReader ClientStreamReader { get; set; }
internal StreamWriter ClientStreamWriter { get; set; } internal StreamWriter ClientStreamWriter { get; set; }
internal string UpgradeProtocol { get; set; } internal string HttpsHostName { get; set; }
internal Encoding Encoding { get; set; } internal string HttpsDecoratedHostName { get; set; }
internal int RequestLength { get; set; } internal int RequestContentLength { get; set; }
internal Encoding RequestEncoding { get; set; }
internal Version RequestHttpVersion { get; set; } internal Version RequestHttpVersion { get; set; }
internal bool RequestIsAlive { get; set; } internal bool RequestIsAlive { get; set; }
internal bool CancelRequest { get; set; } internal bool CancelRequest { get; set; }
internal string RequestHtmlBody { get; set; } internal string RequestBody { get; set; }
internal bool RequestWasModified { get; set; } internal bool RequestBodyRead { get; set; }
internal Stream ServerResponseStream { get; set; }
internal string ResponseHtmlBody { get; set; }
internal bool ResponseWasModified { get; set; }
internal Encoding ResponseEncoding { get; set; }
internal Stream ResponseStream { get; set; }
internal string ResponseBody { get; set; }
internal bool ResponseBodyRead { get; set; }
public int ClientPort { get; set; } public int ClientPort { get; set; }
public IPAddress ClientIpAddress { get; set; } public IPAddress ClientIpAddress { get; set; }
public string tunnelHostName { get; set; }
public string securehost { get; set; } public bool IsHttps { get; set; }
public bool IsSSLRequest { get; set; }
public string RequestURL { get; set; } public string RequestURL { get; set; }
public string RequestHostname { get; set; } public string RequestHostname { get; set; }
...@@ -48,8 +49,8 @@ namespace Titanium.Web.Proxy.Models ...@@ -48,8 +49,8 @@ namespace Titanium.Web.Proxy.Models
if (this.ProxyRequest != null) if (this.ProxyRequest != null)
this.ProxyRequest.Abort(); this.ProxyRequest.Abort();
if (this.ServerResponseStream != null) if (this.ResponseStream != null)
this.ServerResponseStream.Dispose(); this.ResponseStream.Dispose();
if (this.ServerResponse != null) if (this.ServerResponse != null)
this.ServerResponse.Close(); this.ServerResponse.Close();
...@@ -60,70 +61,66 @@ namespace Titanium.Web.Proxy.Models ...@@ -60,70 +61,66 @@ namespace Titanium.Web.Proxy.Models
{ {
BUFFER_SIZE = bufferSize; BUFFER_SIZE = bufferSize;
} }
public string GetRequestHtmlBody() public string GetRequestBody()
{ {
if (RequestHtmlBody == null) if ((ProxyRequest.Method.ToUpper() == "POST" || ProxyRequest.Method.ToUpper() == "PUT") && RequestContentLength > 0)
{ {
if (RequestBody == null)
int bytesRead;
int totalBytesRead = 0;
MemoryStream mw = new MemoryStream();
var buffer = ClientStreamReader.ReadBytes(RequestLength);
while (totalBytesRead < RequestLength && (bytesRead = buffer.Length) > 0)
{ {
totalBytesRead += bytesRead; var buffer = ClientStreamReader.ReadBytes(RequestContentLength);
mw.Write(buffer, 0, bytesRead); RequestBody = RequestEncoding.GetString(buffer);
} }
RequestBodyRead = true;
mw.Close(); return RequestBody;
RequestHtmlBody = Encoding.Default.GetString(mw.ToArray());
} }
RequestWasModified = true; else
return RequestHtmlBody; throw new BodyNotFoundException("Request don't have a body." +
"Please verify that this request is a Http POST/PUT and request content length is greater than zero before accessing the body.");
} }
public void SetRequestHtmlBody(string body) public void SetRequestBody(string body)
{ {
this.RequestHtmlBody = body; this.RequestBody = body;
RequestWasModified = true; RequestBodyRead = true;
} }
public string GetResponseHtmlBody() public string GetResponseBody()
{ {
if (ResponseHtmlBody == null) if (ResponseBody == null)
{ {
Encoding = Encoding.GetEncoding(ServerResponse.CharacterSet); if (ResponseEncoding == null) ResponseEncoding = Encoding.GetEncoding(ServerResponse.CharacterSet);
if (ResponseEncoding == null) ResponseEncoding = Encoding.Default;
if (Encoding == null) Encoding = Encoding.Default;
switch (ServerResponse.ContentEncoding) switch (ServerResponse.ContentEncoding)
{ {
case "gzip": case "gzip":
ResponseHtmlBody = CompressionHelper.DecompressGzip(ServerResponseStream, Encoding); ResponseBody = CompressionHelper.DecompressGzip(ResponseStream, ResponseEncoding);
break; break;
case "deflate": case "deflate":
ResponseHtmlBody = CompressionHelper.DecompressDeflate(ServerResponseStream, Encoding); ResponseBody = CompressionHelper.DecompressDeflate(ResponseStream, ResponseEncoding);
break; break;
case "zlib": case "zlib":
ResponseHtmlBody = CompressionHelper.DecompressZlib(ServerResponseStream, Encoding); ResponseBody = CompressionHelper.DecompressZlib(ResponseStream, ResponseEncoding);
break; break;
default: default:
ResponseHtmlBody = DecodeData(ServerResponseStream, Encoding); ResponseBody = DecodeData(ResponseStream, ResponseEncoding);
break; break;
} }
ResponseWasModified = true; ResponseBodyRead = true;
} }
return ResponseHtmlBody; return ResponseBody;
} }
public void SetResponseHtmlBody(string body) public void SetResponseBody(string body)
{ {
this.ResponseHtmlBody = body; if (ResponseEncoding == null) ResponseEncoding = Encoding.GetEncoding(ServerResponse.CharacterSet);
ResponseWasModified = true; if (ResponseEncoding == null) ResponseEncoding = Encoding.Default;
this.ResponseBody = body;
ResponseBodyRead = true;
} }
//stream reader not recomended for images //stream reader not recomended for images
private string DecodeData(Stream responseStream, Encoding e) private string DecodeData(Stream responseStream, Encoding e)
......
...@@ -31,29 +31,23 @@ namespace Titanium.Web.Proxy ...@@ -31,29 +31,23 @@ namespace Titanium.Web.Proxy
private static readonly Regex cookieSplitRegEx = new Regex(@",(?! )"); private static readonly Regex cookieSplitRegEx = new Regex(@",(?! )");
private static object certificateAccessLock = new object(); private static object certificateAccessLock = new object();
private static List<string> pinnedCertificateClients = new List<string>();
private static TcpListener listener; private static TcpListener listener;
private static Thread listenerThread; private static Thread listenerThread;
private static bool ShouldListen { get; set; } private static bool ShouldListen { get; set; }
public static List<string> ExcludedHttpsHostNameRegex = new List<string>();
public static event EventHandler<SessionEventArgs> BeforeRequest; public static event EventHandler<SessionEventArgs> BeforeRequest;
public static event EventHandler<SessionEventArgs> BeforeResponse; public static event EventHandler<SessionEventArgs> BeforeResponse;
public static IPAddress ListeningIPInterface { get; set; }
public static string RootCertificateName { get; set; } public static string RootCertificateName { get; set; }
public static bool EnableSSL { get; set; } public static bool EnableSSL { get; set; }
public static bool SetAsSystemProxy { get; set; } public static bool SetAsSystemProxy { get; set; }
public static Int32 ListeningPort public static Int32 ListeningPort { get; set; }
{ public static IPAddress ListeningIpAddress { get; set; }
get
{
return ((IPEndPoint)listener.LocalEndpoint).Port;
}
}
public static CertificateManager CertManager { get; set; } public static CertificateManager CertManager { get; set; }
...@@ -61,12 +55,14 @@ namespace Titanium.Web.Proxy ...@@ -61,12 +55,14 @@ namespace Titanium.Web.Proxy
{ {
CertManager = new CertificateManager("Titanium", CertManager = new CertificateManager("Titanium",
"Titanium Root Certificate Authority"); "Titanium Root Certificate Authority");
ListeningIpAddress = IPAddress.Any;
ListeningPort = 0;
} }
public ProxyServer() public ProxyServer()
{ {
System.Net.ServicePointManager.Expect100Continue = false; System.Net.ServicePointManager.Expect100Continue = false;
System.Net.WebRequest.DefaultWebProxy = null; System.Net.WebRequest.DefaultWebProxy = null;
System.Net.ServicePointManager.DefaultConnectionLimit = 10; System.Net.ServicePointManager.DefaultConnectionLimit = 10;
...@@ -111,13 +107,16 @@ namespace Titanium.Web.Proxy ...@@ -111,13 +107,16 @@ namespace Titanium.Web.Proxy
public static bool Start() public static bool Start()
{ {
listener = new TcpListener(IPAddress.Any, 0); listener = new TcpListener(ListeningIpAddress, ListeningPort);
listener.Start(); listener.Start();
listenerThread = new Thread(new ParameterizedThreadStart(Listen)); listenerThread = new Thread(new ParameterizedThreadStart(Listen));
listenerThread.IsBackground = true; listenerThread.IsBackground = true;
ShouldListen = true; ShouldListen = true;
listenerThread.Start(listener); listenerThread.Start(listener);
ListeningPort = ((IPEndPoint)listener.LocalEndpoint).Port;
if (SetAsSystemProxy) if (SetAsSystemProxy)
{ {
SystemProxyHelper.EnableProxyHTTP("localhost", ListeningPort); SystemProxyHelper.EnableProxyHTTP("localhost", ListeningPort);
......
...@@ -14,7 +14,8 @@ using System.Reflection; ...@@ -14,7 +14,8 @@ using System.Reflection;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
using System.Threading.Tasks; using System.Threading.Tasks;
using Titanium.Web.Proxy.Extensions;
using System.Text.RegularExpressions;
namespace Titanium.Web.Proxy namespace Titanium.Web.Proxy
{ {
...@@ -30,17 +31,14 @@ namespace Titanium.Web.Proxy ...@@ -30,17 +31,14 @@ namespace Titanium.Web.Proxy
CustomBinaryReader clientStreamReader = new CustomBinaryReader(clientStream, Encoding.ASCII); CustomBinaryReader clientStreamReader = new CustomBinaryReader(clientStream, Encoding.ASCII);
StreamWriter clientStreamWriter = new StreamWriter(clientStream); StreamWriter clientStreamWriter = new StreamWriter(clientStream);
string tunnelHostName = null; string HttpsHostName = null;
int httpsPort = 443;
int tunnelPort = 0;
try try
{ {
string httpsDecoratedHostName = null, tmpLine = null;
string securehost = null;
List<string> requestLines = new List<string>(); List<string> requestLines = new List<string>();
string tmpLine;
while (!String.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine())) while (!String.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine()))
{ {
requestLines.Add(tmpLine); requestLines.Add(tmpLine);
...@@ -79,11 +77,9 @@ namespace Titanium.Web.Proxy ...@@ -79,11 +77,9 @@ namespace Titanium.Web.Proxy
//to avoid that we need to install our root certficate in users machine as Certificate Authority. //to avoid that we need to install our root certficate in users machine as Certificate Authority.
remoteUri = "https://" + splitBuffer[1]; remoteUri = "https://" + splitBuffer[1];
tunnelHostName = splitBuffer[1].Split(':')[0]; HttpsHostName = splitBuffer[1].Split(':')[0];
int.TryParse(splitBuffer[1].Split(':')[1], out tunnelPort);
if (tunnelPort == 0) tunnelPort = 443; int.TryParse(splitBuffer[1].Split(':')[1], out httpsPort);
requestLines.Clear(); requestLines.Clear();
...@@ -94,10 +90,10 @@ namespace Titanium.Web.Proxy ...@@ -94,10 +90,10 @@ namespace Titanium.Web.Proxy
clientStreamWriter.Flush(); clientStreamWriter.Flush();
//If port is not 443 its not a HTTP request, so just relay //If port is not 443 its not a HTTP request (may be tcp), so just relay
if (tunnelPort != 443) if (httpsPort != 443)
{ {
TcpHelper.SendRaw(tunnelHostName, tunnelPort, clientStreamReader.BaseStream); TcpHelper.SendRaw(HttpsHostName, httpsPort, clientStreamReader.BaseStream);
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null); Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null);
...@@ -106,16 +102,16 @@ namespace Titanium.Web.Proxy ...@@ -106,16 +102,16 @@ namespace Titanium.Web.Proxy
//Create the fake certificate signed using our fake certificate authority //Create the fake certificate signed using our fake certificate authority
Monitor.Enter(certificateAccessLock); Monitor.Enter(certificateAccessLock);
var certificate = ProxyServer.CertManager.CreateCertificate(tunnelHostName); var certificate = ProxyServer.CertManager.CreateCertificate(HttpsHostName);
Monitor.Exit(certificateAccessLock); Monitor.Exit(certificateAccessLock);
SslStream sslStream = null; SslStream sslStream = null;
//Pinned certificate clients cannot be proxied //Pinned certificate clients cannot be proxied
//Example dropbox.com uses certificate pinning //For example dropbox clients use certificate pinning
//So just relay the request after identifying it by first failure //So just relay the request
if (!pinnedCertificateClients.Contains(tunnelHostName)) if (!ExcludedHttpsHostNameRegex.Any(x=> Regex.IsMatch(HttpsHostName,x)))
{ {
try try
{ {
sslStream = new SslStream(clientStream, true); sslStream = new SslStream(clientStream, true);
...@@ -130,13 +126,6 @@ namespace Titanium.Web.Proxy ...@@ -130,13 +126,6 @@ namespace Titanium.Web.Proxy
catch catch
{ {
//if authentication failed it could be because client uses pinned certificates
//So add the hostname to this list so that next time we can relay without touching it (tunnel the request)
if (pinnedCertificateClients.Contains(tunnelHostName) == false)
{
pinnedCertificateClients.Add(tunnelHostName);
}
if (sslStream != null) if (sslStream != null)
sslStream.Dispose(); sslStream.Dispose();
...@@ -147,14 +136,11 @@ namespace Titanium.Web.Proxy ...@@ -147,14 +136,11 @@ namespace Titanium.Web.Proxy
else else
{ {
//Hostname was a previously failed request due to certificate pinning, just relay (tunnel the request) //Hostname was a previously failed request due to certificate pinning, just relay (tunnel the request)
TcpHelper.SendRaw(tunnelHostName, tunnelPort, clientStreamReader.BaseStream); TcpHelper.SendRaw(HttpsHostName, httpsPort, clientStreamReader.BaseStream);
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null); Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null);
return; return;
} }
while (!String.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine())) while (!String.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine()))
{ {
requestLines.Add(tmpLine); requestLines.Add(tmpLine);
...@@ -167,13 +153,11 @@ namespace Titanium.Web.Proxy ...@@ -167,13 +153,11 @@ namespace Titanium.Web.Proxy
throw new EndOfStreamException(); throw new EndOfStreamException();
} }
securehost = remoteUri; httpsDecoratedHostName = remoteUri;
} }
//Now create the request //Now create the request
Task.Factory.StartNew(() => HandleHttpSessionRequest(client, httpCmd, clientStream, tunnelHostName, requestLines, clientStreamReader, clientStreamWriter, securehost)); Task.Factory.StartNew(() => HandleHttpSessionRequest(client, httpCmd, clientStream, HttpsHostName, requestLines, clientStreamReader, clientStreamWriter, httpsDecoratedHostName));
} }
catch catch
...@@ -183,7 +167,7 @@ namespace Titanium.Web.Proxy ...@@ -183,7 +167,7 @@ namespace Titanium.Web.Proxy
} }
private static void HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream, string tunnelHostName, List<string> requestLines, CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, string securehost) private static void HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream, string httpsHostName, List<string> requestLines, CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, string httpsDecoratedHostName)
{ {
...@@ -197,8 +181,8 @@ namespace Titanium.Web.Proxy ...@@ -197,8 +181,8 @@ namespace Titanium.Web.Proxy
var args = new SessionEventArgs(BUFFER_SIZE); var args = new SessionEventArgs(BUFFER_SIZE);
args.Client = client; args.Client = client;
args.tunnelHostName = tunnelHostName; args.HttpsHostName = httpsHostName;
args.securehost = securehost; args.HttpsDecoratedHostName = httpsDecoratedHostName;
try try
{ {
...@@ -207,7 +191,7 @@ namespace Titanium.Web.Proxy ...@@ -207,7 +191,7 @@ namespace Titanium.Web.Proxy
if (splitBuffer.Length != 3) if (splitBuffer.Length != 3)
{ {
TcpHelper.SendRaw(httpCmd, tunnelHostName, requestLines, args.IsSSLRequest, clientStreamReader.BaseStream); TcpHelper.SendRaw(httpCmd, httpsHostName, requestLines, args.IsHttps, clientStreamReader.BaseStream);
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args); Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
...@@ -225,10 +209,10 @@ namespace Titanium.Web.Proxy ...@@ -225,10 +209,10 @@ namespace Titanium.Web.Proxy
version = new Version(1, 0); version = new Version(1, 0);
} }
if (securehost != null) if (httpsDecoratedHostName != null)
{ {
remoteUri = securehost + remoteUri; remoteUri = httpsDecoratedHostName + remoteUri;
args.IsSSLRequest = true; args.IsHttps = true;
} }
//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.
...@@ -250,7 +234,7 @@ namespace Titanium.Web.Proxy ...@@ -250,7 +234,7 @@ namespace Titanium.Web.Proxy
if ((header[0] == "upgrade") && (header[1] == "websocket")) if ((header[0] == "upgrade") && (header[1] == "websocket"))
{ {
TcpHelper.SendRaw(httpCmd, tunnelHostName, requestLines, args.IsSSLRequest, clientStreamReader.BaseStream); TcpHelper.SendRaw(httpCmd, httpsHostName, requestLines, args.IsHttps, clientStreamReader.BaseStream);
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args); Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
...@@ -260,25 +244,21 @@ namespace Titanium.Web.Proxy ...@@ -260,25 +244,21 @@ namespace Titanium.Web.Proxy
SetClientRequestHeaders(requestLines, args.ProxyRequest); SetClientRequestHeaders(requestLines, args.ProxyRequest);
int contentLen = (int)args.ProxyRequest.ContentLength;
args.ProxyRequest.AllowAutoRedirect = false; args.ProxyRequest.AllowAutoRedirect = false;
args.ProxyRequest.AutomaticDecompression = DecompressionMethods.None; args.ProxyRequest.AutomaticDecompression = DecompressionMethods.None;
//If requested interception
if (BeforeRequest != null)
{
args.RequestHostname = args.ProxyRequest.RequestUri.Host; args.RequestHostname = args.ProxyRequest.RequestUri.Host;
args.RequestURL = args.ProxyRequest.RequestUri.OriginalString; args.RequestURL = args.ProxyRequest.RequestUri.OriginalString;
args.RequestLength = contentLen;
args.RequestHttpVersion = version;
args.ClientPort = ((IPEndPoint)client.Client.RemoteEndPoint).Port; args.ClientPort = ((IPEndPoint)client.Client.RemoteEndPoint).Port;
args.ClientIpAddress = ((IPEndPoint)client.Client.RemoteEndPoint).Address; args.ClientIpAddress = ((IPEndPoint)client.Client.RemoteEndPoint).Address;
args.RequestHttpVersion = version;
args.RequestIsAlive = args.ProxyRequest.KeepAlive; args.RequestIsAlive = args.ProxyRequest.KeepAlive;
//If requested interception
if (BeforeRequest != null)
{
args.RequestContentLength = (int)args.ProxyRequest.ContentLength;
args.RequestEncoding = args.ProxyRequest.GetEncoding();
BeforeRequest(null, args); BeforeRequest(null, args);
} }
...@@ -294,13 +274,13 @@ namespace Titanium.Web.Proxy ...@@ -294,13 +274,13 @@ namespace Titanium.Web.Proxy
args.ProxyRequest.AllowWriteStreamBuffering = true; args.ProxyRequest.AllowWriteStreamBuffering = true;
//If request was modified by user //If request was modified by user
if (args.RequestWasModified) if (args.RequestBodyRead)
{ {
ASCIIEncoding encoding = new ASCIIEncoding(); byte[] requestBytes = args.RequestEncoding.GetBytes(args.RequestBody);
byte[] requestBytes = encoding.GetBytes(args.RequestHtmlBody);
args.ProxyRequest.ContentLength = requestBytes.Length; args.ProxyRequest.ContentLength = requestBytes.Length;
Stream newStream = args.ProxyRequest.GetRequestStream(); Stream newStream = args.ProxyRequest.GetRequestStream();
newStream.Write(requestBytes, 0, requestBytes.Length); newStream.Write(requestBytes, 0, requestBytes.Length);
args.ProxyRequest.BeginGetResponse(new AsyncCallback(HandleHttpSessionResponse), args); args.ProxyRequest.BeginGetResponse(new AsyncCallback(HandleHttpSessionResponse), args);
} }
...@@ -331,7 +311,7 @@ namespace Titanium.Web.Proxy ...@@ -331,7 +311,7 @@ namespace Titanium.Web.Proxy
TcpClient Client = args.Client; TcpClient Client = args.Client;
//Http request body sent, now wait for next request //Http request body sent, now wait for next request
Task.Factory.StartNew(() => HandleHttpSessionRequest(Client, httpCmd, args.ClientStream, args.tunnelHostName, requestLines, args.ClientStreamReader, args.ClientStreamWriter, args.securehost)); Task.Factory.StartNew(() => HandleHttpSessionRequest(Client, httpCmd, args.ClientStream, args.HttpsHostName, requestLines, args.ClientStreamReader, args.ClientStreamWriter, args.HttpsDecoratedHostName));
} }
catch catch
...@@ -491,7 +471,7 @@ namespace Titanium.Web.Proxy ...@@ -491,7 +471,7 @@ namespace Titanium.Web.Proxy
} }
postStream.Close(); postStream.Close();
postStream.Dispose();
} }
catch catch
{ {
......
...@@ -38,41 +38,39 @@ namespace Titanium.Web.Proxy ...@@ -38,41 +38,39 @@ namespace Titanium.Web.Proxy
if (args.ServerResponse != null) if (args.ServerResponse != null)
{ {
List<Tuple<String, String>> responseHeaders = ProcessResponse(args.ServerResponse); List<Tuple<String, String>> responseHeaders = ProcessResponse(args.ServerResponse);
args.ServerResponseStream = args.ServerResponse.GetResponseStream(); args.ResponseStream = args.ServerResponse.GetResponseStream();
bool isChunked = args.ServerResponse.GetResponseHeader("transfer-encoding") == null ? false : args.ServerResponse.GetResponseHeader("transfer-encoding").ToLower() == "chunked" ? true : false; bool isChunked = args.ServerResponse.GetResponseHeader("transfer-encoding") == null ? false : args.ServerResponse.GetResponseHeader("transfer-encoding").ToLower() == "chunked" ? true : false;
args.UpgradeProtocol = args.ServerResponse.GetResponseHeader("upgrade") == null ? null : args.ServerResponse.GetResponseHeader("upgrade");
if (BeforeResponse != null) if (BeforeResponse != null)
BeforeResponse(null, args); BeforeResponse(null, args);
if (args.ResponseWasModified) if (args.ResponseBodyRead)
{ {
byte[] data; byte[] data;
switch (args.ServerResponse.ContentEncoding) switch (args.ServerResponse.ContentEncoding)
{ {
case "gzip": case "gzip":
data = CompressionHelper.CompressGzip(args.ResponseHtmlBody, args.Encoding); data = CompressionHelper.CompressGzip(args.ResponseBody, args.ResponseEncoding);
WriteResponseStatus(args.ServerResponse.ProtocolVersion, args.ServerResponse.StatusCode, args.ServerResponse.StatusDescription, args.ClientStreamWriter); WriteResponseStatus(args.ServerResponse.ProtocolVersion, args.ServerResponse.StatusCode, args.ServerResponse.StatusDescription, args.ClientStreamWriter);
WriteResponseHeaders(args.ClientStreamWriter, responseHeaders, data.Length); WriteResponseHeaders(args.ClientStreamWriter, responseHeaders, data.Length);
SendData(args.ClientStream, data, isChunked); SendData(args.ClientStream, data, isChunked);
break; break;
case "deflate": case "deflate":
data = CompressionHelper.CompressDeflate(args.ResponseHtmlBody, args.Encoding); data = CompressionHelper.CompressDeflate(args.ResponseBody, args.ResponseEncoding);
WriteResponseStatus(args.ServerResponse.ProtocolVersion, args.ServerResponse.StatusCode, args.ServerResponse.StatusDescription, args.ClientStreamWriter); WriteResponseStatus(args.ServerResponse.ProtocolVersion, args.ServerResponse.StatusCode, args.ServerResponse.StatusDescription, args.ClientStreamWriter);
WriteResponseHeaders(args.ClientStreamWriter, responseHeaders, data.Length); WriteResponseHeaders(args.ClientStreamWriter, responseHeaders, data.Length);
SendData(args.ClientStream, data, isChunked); SendData(args.ClientStream, data, isChunked);
break; break;
case "zlib": case "zlib":
data = CompressionHelper.CompressZlib(args.ResponseHtmlBody, args.Encoding); data = CompressionHelper.CompressZlib(args.ResponseBody, args.ResponseEncoding);
WriteResponseStatus(args.ServerResponse.ProtocolVersion, args.ServerResponse.StatusCode, args.ServerResponse.StatusDescription, args.ClientStreamWriter); WriteResponseStatus(args.ServerResponse.ProtocolVersion, args.ServerResponse.StatusCode, args.ServerResponse.StatusDescription, args.ClientStreamWriter);
WriteResponseHeaders(args.ClientStreamWriter, responseHeaders, data.Length); WriteResponseHeaders(args.ClientStreamWriter, responseHeaders, data.Length);
SendData(args.ClientStream, data, isChunked); SendData(args.ClientStream, data, isChunked);
break; break;
default: default:
data = EncodeData(args.ResponseHtmlBody, args.Encoding); data = EncodeData(args.ResponseBody, args.ResponseEncoding);
WriteResponseStatus(args.ServerResponse.ProtocolVersion, args.ServerResponse.StatusCode, args.ServerResponse.StatusDescription, args.ClientStreamWriter); WriteResponseStatus(args.ServerResponse.ProtocolVersion, args.ServerResponse.StatusCode, args.ServerResponse.StatusDescription, args.ClientStreamWriter);
WriteResponseHeaders(args.ClientStreamWriter, responseHeaders, data.Length); WriteResponseHeaders(args.ClientStreamWriter, responseHeaders, data.Length);
SendData(args.ClientStream, data, isChunked); SendData(args.ClientStream, data, isChunked);
...@@ -86,9 +84,9 @@ namespace Titanium.Web.Proxy ...@@ -86,9 +84,9 @@ namespace Titanium.Web.Proxy
WriteResponseHeaders(args.ClientStreamWriter, responseHeaders); WriteResponseHeaders(args.ClientStreamWriter, responseHeaders);
if (isChunked) if (isChunked)
SendChunked(args.ServerResponseStream, args.ClientStream); SendChunked(args.ResponseStream, args.ClientStream);
else else
SendNormal(args.ServerResponseStream, args.ClientStream); SendNormal(args.ResponseStream, args.ClientStream);
} }
......
...@@ -76,6 +76,8 @@ ...@@ -76,6 +76,8 @@
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Exceptions\BodyNotFoundException.cs" />
<Compile Include="Extensions\HttpWebRequestExtensions.cs" />
<Compile Include="Helpers\CertificateManager.cs" /> <Compile Include="Helpers\CertificateManager.cs" />
<Compile Include="Helpers\Firefox.cs" /> <Compile Include="Helpers\Firefox.cs" />
<Compile Include="Helpers\SystemProxy.cs" /> <Compile Include="Helpers\SystemProxy.cs" />
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment