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

Fix request body modification

parent 3c1c351e
......@@ -64,30 +64,49 @@ Sample request and response event handlers
```csharp
public void OnRequest(object sender, SessionEventArgs e)
//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)
{
//To cancel a request with a custom HTML content
//Filter URL
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
//Filter URL
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)
{
if (e.ServerResponse.StatusCode == HttpStatusCode.OK)
{
if (e.ServerResponse.ContentType.Trim().ToLower().Contains("text/html"))
{
//Get response body
string responseHtmlBody = e.GetResponseHtmlBody();
//Modify e.ServerResponse
responseHtmlBody = "<html><head></head><body>Response is modified!</body></html>";
//Set modifed response Html Body
e.SetResponseHtmlBody(responseHtmlBody);
}
}
if (e.ServerResponse.StatusCode == HttpStatusCode.OK)
{
if (e.ServerResponse.ContentType.Trim().ToLower().Contains("text/html"))
{
//Get response body
string responseBody = e.GetResponseBody();
//Modify e.ServerResponse
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
e.SetResponseBody(modified);
}
}
}
```
Future updates
......
......@@ -24,23 +24,24 @@ namespace Titanium.Web.Proxy.Test
public void StartProxy()
{
ProxyServer.BeforeRequest += OnRequest;
ProxyServer.BeforeResponse += OnResponse;
ProxyServer.EnableSSL = EnableSSL;
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();
ListeningPort = ProxyServer.ListeningPort;
ProxyServer.ListeningPort = ProxyServer.ListeningPort;
Console.WriteLine(String.Format("Proxy listening on local machine port: {0} ", ProxyServer.ListeningPort));
}
public void Stop()
{
......@@ -59,14 +60,23 @@ namespace Titanium.Web.Proxy.Test
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
//Filter URL
//if (e.RequestURL.Contains("somewebsite.com"))
//{
// e.Ok("<!DOCTYPE html><html><body><h1>Blocked</h1><p>website blocked.</p></body></html>");
//}
if (e.RequestURL.Contains("somewebsite.com"))
{
e.Ok("<!DOCTYPE html><html><body><h1>Blocked</h1><p>Website blocked.</p></body></html>");
}
}
//Test script injection
......@@ -75,18 +85,21 @@ namespace Titanium.Web.Proxy.Test
{
//To modify a response
//if (e.ServerResponse.StatusCode == HttpStatusCode.OK)
//{
// if (e.ServerResponse.ContentType.Trim().ToLower().Contains("text/html"))
// {
// //Get response body
// string responseHtmlBody = e.GetResponseHtmlBody();
// //Modify e.ServerResponse
// responseHtmlBody = "<html><head></head><body>Response is modified!</body></html>";
// //Set modifed response Html Body
// e.SetResponseHtmlBody(responseHtmlBody);
// }
//}
if (e.ServerResponse.StatusCode == HttpStatusCode.OK)
{
if (e.ServerResponse.ContentType.Trim().ToLower().Contains("text/html"))
{
//Get response body
string responseBody = e.GetResponseBody();
//Modify e.ServerResponse
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
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
Task sendRelay = Task.Factory.StartNew(() => StreamHelper.CopyTo(clientStream, tunnelStream, BUFFER_SIZE));
Task receiveRelay = Task.Factory.StartNew(() => StreamHelper.CopyTo(tunnelStream, clientStream, BUFFER_SIZE));
sendRelay.Start();
receiveRelay.Start();
Task.WaitAll(sendRelay, receiveRelay);
}
catch
......@@ -118,9 +115,6 @@ namespace Titanium.Web.Proxy.Helpers
var sendRelay = new Task(() => StreamHelper.CopyTo(sb.ToString(), clientStream, tunnelStream, BUFFER_SIZE));
var receiveRelay = new Task(() => StreamHelper.CopyTo(tunnelStream, clientStream, BUFFER_SIZE));
sendRelay.Start();
receiveRelay.Start();
Task.WaitAll(sendRelay, receiveRelay);
}
catch
......
......@@ -4,6 +4,7 @@ using System.IO;
using System.Net;
using Titanium.Web.Proxy.Helpers;
using System.Net.Sockets;
using Titanium.Web.Proxy.Exceptions;
namespace Titanium.Web.Proxy.Models
......@@ -18,25 +19,25 @@ namespace Titanium.Web.Proxy.Models
internal CustomBinaryReader ClientStreamReader { get; set; }
internal StreamWriter ClientStreamWriter { get; set; }
internal string UpgradeProtocol { get; set; }
internal Encoding Encoding { get; set; }
internal int RequestLength { get; set; }
internal string HttpsHostName { get; set; }
internal string HttpsDecoratedHostName { get; set; }
internal int RequestContentLength { get; set; }
internal Encoding RequestEncoding { get; set; }
internal Version RequestHttpVersion { get; set; }
internal bool RequestIsAlive { get; set; }
internal bool CancelRequest { get; set; }
internal string RequestHtmlBody { get; set; }
internal bool RequestWasModified { get; set; }
internal string RequestBody { 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 IPAddress ClientIpAddress { get; set; }
public string tunnelHostName { get; set; }
public string securehost { get; set; }
public bool IsSSLRequest { get; set; }
public bool IsHttps { get; set; }
public string RequestURL { get; set; }
public string RequestHostname { get; set; }
......@@ -48,8 +49,8 @@ namespace Titanium.Web.Proxy.Models
if (this.ProxyRequest != null)
this.ProxyRequest.Abort();
if (this.ServerResponseStream != null)
this.ServerResponseStream.Dispose();
if (this.ResponseStream != null)
this.ResponseStream.Dispose();
if (this.ServerResponse != null)
this.ServerResponse.Close();
......@@ -60,70 +61,66 @@ namespace Titanium.Web.Proxy.Models
{
BUFFER_SIZE = bufferSize;
}
public string GetRequestHtmlBody()
public string GetRequestBody()
{
if (RequestHtmlBody == null)
if ((ProxyRequest.Method.ToUpper() == "POST" || ProxyRequest.Method.ToUpper() == "PUT") && RequestContentLength > 0)
{
int bytesRead;
int totalBytesRead = 0;
MemoryStream mw = new MemoryStream();
var buffer = ClientStreamReader.ReadBytes(RequestLength);
while (totalBytesRead < RequestLength && (bytesRead = buffer.Length) > 0)
if (RequestBody == null)
{
totalBytesRead += bytesRead;
mw.Write(buffer, 0, bytesRead);
var buffer = ClientStreamReader.ReadBytes(RequestContentLength);
RequestBody = RequestEncoding.GetString(buffer);
}
mw.Close();
RequestHtmlBody = Encoding.Default.GetString(mw.ToArray());
RequestBodyRead = true;
return RequestBody;
}
RequestWasModified = true;
return RequestHtmlBody;
else
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;
RequestWasModified = true;
this.RequestBody = body;
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)
{
case "gzip":
ResponseHtmlBody = CompressionHelper.DecompressGzip(ServerResponseStream, Encoding);
ResponseBody = CompressionHelper.DecompressGzip(ResponseStream, ResponseEncoding);
break;
case "deflate":
ResponseHtmlBody = CompressionHelper.DecompressDeflate(ServerResponseStream, Encoding);
ResponseBody = CompressionHelper.DecompressDeflate(ResponseStream, ResponseEncoding);
break;
case "zlib":
ResponseHtmlBody = CompressionHelper.DecompressZlib(ServerResponseStream, Encoding);
ResponseBody = CompressionHelper.DecompressZlib(ResponseStream, ResponseEncoding);
break;
default:
ResponseHtmlBody = DecodeData(ServerResponseStream, Encoding);
ResponseBody = DecodeData(ResponseStream, ResponseEncoding);
break;
}
ResponseWasModified = true;
ResponseBodyRead = true;
}
return ResponseHtmlBody;
return ResponseBody;
}
public void SetResponseHtmlBody(string body)
public void SetResponseBody(string body)
{
this.ResponseHtmlBody = body;
ResponseWasModified = true;
if (ResponseEncoding == null) ResponseEncoding = Encoding.GetEncoding(ServerResponse.CharacterSet);
if (ResponseEncoding == null) ResponseEncoding = Encoding.Default;
this.ResponseBody = body;
ResponseBodyRead = true;
}
//stream reader not recomended for images
private string DecodeData(Stream responseStream, Encoding e)
......
......@@ -31,29 +31,23 @@ namespace Titanium.Web.Proxy
private static readonly Regex cookieSplitRegEx = new Regex(@",(?! )");
private static object certificateAccessLock = new object();
private static List<string> pinnedCertificateClients = new List<string>();
private static TcpListener listener;
private static Thread listenerThread;
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> BeforeResponse;
public static IPAddress ListeningIPInterface { get; set; }
public static string RootCertificateName { get; set; }
public static bool EnableSSL { get; set; }
public static bool SetAsSystemProxy { get; set; }
public static Int32 ListeningPort
{
get
{
return ((IPEndPoint)listener.LocalEndpoint).Port;
}
}
public static Int32 ListeningPort { get; set; }
public static IPAddress ListeningIpAddress { get; set; }
public static CertificateManager CertManager { get; set; }
......@@ -61,12 +55,14 @@ namespace Titanium.Web.Proxy
{
CertManager = new CertificateManager("Titanium",
"Titanium Root Certificate Authority");
ListeningIpAddress = IPAddress.Any;
ListeningPort = 0;
}
public ProxyServer()
{
System.Net.ServicePointManager.Expect100Continue = false;
System.Net.WebRequest.DefaultWebProxy = null;
System.Net.ServicePointManager.DefaultConnectionLimit = 10;
......@@ -111,13 +107,16 @@ namespace Titanium.Web.Proxy
public static bool Start()
{
listener = new TcpListener(IPAddress.Any, 0);
listener = new TcpListener(ListeningIpAddress, ListeningPort);
listener.Start();
listenerThread = new Thread(new ParameterizedThreadStart(Listen));
listenerThread.IsBackground = true;
ShouldListen = true;
listenerThread.Start(listener);
ListeningPort = ((IPEndPoint)listener.LocalEndpoint).Port;
if (SetAsSystemProxy)
{
SystemProxyHelper.EnableProxyHTTP("localhost", ListeningPort);
......
This diff is collapsed.
......@@ -38,41 +38,39 @@ namespace Titanium.Web.Proxy
if (args.ServerResponse != null)
{
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;
args.UpgradeProtocol = args.ServerResponse.GetResponseHeader("upgrade") == null ? null : args.ServerResponse.GetResponseHeader("upgrade");
if (BeforeResponse != null)
BeforeResponse(null, args);
if (args.ResponseWasModified)
if (args.ResponseBodyRead)
{
byte[] data;
switch (args.ServerResponse.ContentEncoding)
{
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);
WriteResponseHeaders(args.ClientStreamWriter, responseHeaders, data.Length);
SendData(args.ClientStream, data, isChunked);
break;
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);
WriteResponseHeaders(args.ClientStreamWriter, responseHeaders, data.Length);
SendData(args.ClientStream, data, isChunked);
break;
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);
WriteResponseHeaders(args.ClientStreamWriter, responseHeaders, data.Length);
SendData(args.ClientStream, data, isChunked);
break;
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);
WriteResponseHeaders(args.ClientStreamWriter, responseHeaders, data.Length);
SendData(args.ClientStream, data, isChunked);
......@@ -86,9 +84,9 @@ namespace Titanium.Web.Proxy
WriteResponseHeaders(args.ClientStreamWriter, responseHeaders);
if (isChunked)
SendChunked(args.ServerResponseStream, args.ClientStream);
SendChunked(args.ResponseStream, args.ClientStream);
else
SendNormal(args.ServerResponseStream, args.ClientStream);
SendNormal(args.ResponseStream, args.ClientStream);
}
......
......@@ -76,6 +76,8 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Exceptions\BodyNotFoundException.cs" />
<Compile Include="Extensions\HttpWebRequestExtensions.cs" />
<Compile Include="Helpers\CertificateManager.cs" />
<Compile Include="Helpers\Firefox.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