Commit 0c997fd7 authored by justcoding121's avatar justcoding121

Add Expect100Continue disable option

For servers/clients having buggy implementation
parent 1f129b04
using System.Diagnostics.CodeAnalysis;
using System.IO;
using Ionic.Zlib;
namespace Titanium.Web.Proxy.Helpers
{
/// <summary>
/// A helper to handle compression/decompression (gzip, zlib & deflate)
/// </summary>
public class CompressionHelper
{
/// <summary>
/// compress the given bytes using zlib compression
/// </summary>
/// <param name="bytes"></param>
/// <returns></returns>
[SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
public static byte[] CompressZlib(byte[] bytes)
{
using (var ms = new MemoryStream())
{
using (var zip = new ZlibStream(ms, CompressionMode.Compress, true))
{
zip.Write(bytes, 0, bytes.Length);
}
return ms.ToArray();
}
}
/// <summary>
/// compress the given bytes using deflate compression
/// </summary>
/// <param name="bytes"></param>
/// <returns></returns>
[SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
public static byte[] CompressDeflate(byte[] bytes)
{
using (var ms = new MemoryStream())
{
using (var zip = new DeflateStream(ms, CompressionMode.Compress, true))
{
zip.Write(bytes, 0, bytes.Length);
}
return ms.ToArray();
}
}
/// <summary>
/// compress the given bytes using gzip compression
/// </summary>
/// <param name="bytes"></param>
/// <returns></returns>
[SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
public static byte[] CompressGzip(byte[] bytes)
{
using (var ms = new MemoryStream())
{
using (var zip = new GZipStream(ms, CompressionMode.Compress, true))
{
zip.Write(bytes, 0, bytes.Length);
}
return ms.ToArray();
}
}
/// <summary>
/// decompression the gzip compressed byte array
/// </summary>
/// <param name="gzip"></param>
/// <returns></returns>
//identify why passing stream instead of bytes returns empty result
public static byte[] DecompressGzip(byte[] gzip)
{
using (var decompressor = new System.IO.Compression.GZipStream(new MemoryStream(gzip), System.IO.Compression.CompressionMode.Decompress))
{
var buffer = new byte[ProxyServer.BUFFER_SIZE];
using (var output = new MemoryStream())
{
int read;
while ((read = decompressor.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, read);
}
return output.ToArray();
}
}
}
/// <summary>
/// decompress the deflate byte stream
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static byte[] DecompressDeflate(Stream input)
{
using (var decompressor = new DeflateStream(input, CompressionMode.Decompress))
{
var buffer = new byte[ProxyServer.BUFFER_SIZE];
using (var output = new MemoryStream())
{
int read;
while ((read = decompressor.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, read);
}
return output.ToArray();
}
}
}
/// <summary>
/// decompress the zlib byte stream
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static byte[] DecompressZlib(Stream input)
{
using (var decompressor = new ZlibStream(input, CompressionMode.Decompress))
{
var buffer = new byte[ProxyServer.BUFFER_SIZE];
using (var output = new MemoryStream())
{
int read;
while ((read = decompressor.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, read);
}
return output.ToArray();
}
}
}
}
}
\ No newline at end of file
...@@ -97,6 +97,16 @@ namespace Titanium.Web.Proxy.Network ...@@ -97,6 +97,16 @@ namespace Titanium.Web.Proxy.Network
} }
} }
public bool ExpectContinue
{
get
{
var header = RequestHeaders.FirstOrDefault(x => x.Name.ToLower() == "expect");
if (header != null) return header.Value.Equals("100-continue");
return false;
}
}
public string Url { get { return RequestUri.OriginalString; } } public string Url { get { return RequestUri.OriginalString; } }
internal Encoding Encoding { get { return this.GetEncoding(); } } internal Encoding Encoding { get { return this.GetEncoding(); } }
...@@ -127,7 +137,8 @@ namespace Titanium.Web.Proxy.Network ...@@ -127,7 +137,8 @@ namespace Titanium.Web.Proxy.Network
} }
public List<HttpHeader> RequestHeaders { get; set; } public List<HttpHeader> RequestHeaders { get; set; }
public bool Is100Continue { get; internal set; }
public bool ExpectationFailed { get; internal set; }
public Request() public Request()
{ {
...@@ -251,6 +262,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -251,6 +262,7 @@ namespace Titanium.Web.Proxy.Network
internal bool ResponseBodyRead { get; set; } internal bool ResponseBodyRead { get; set; }
internal bool ResponseLocked { get; set; } internal bool ResponseLocked { get; set; }
public bool Is100Continue { get; internal set; } public bool Is100Continue { get; internal set; }
public bool ExpectationFailed { get; internal set; }
public Response() public Response()
{ {
...@@ -311,6 +323,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -311,6 +323,7 @@ namespace Titanium.Web.Proxy.Network
byte[] requestBytes = Encoding.ASCII.GetBytes(request); byte[] requestBytes = Encoding.ASCII.GetBytes(request);
stream.Write(requestBytes, 0, requestBytes.Length); stream.Write(requestBytes, 0, requestBytes.Length);
stream.Flush(); stream.Flush();
} }
public void ReceiveResponse() public void ReceiveResponse()
...@@ -329,7 +342,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -329,7 +342,7 @@ namespace Titanium.Web.Proxy.Network
this.Response.ResponseStatusCode = httpResult[1].Trim(); this.Response.ResponseStatusCode = httpResult[1].Trim();
this.Response.ResponseStatusDescription = httpResult[2].Trim(); this.Response.ResponseStatusDescription = httpResult[2].Trim();
if (this.Response.ResponseStatusCode.Equals("100") if (this.Response.ResponseStatusCode.Equals("100")
&& this.Response.ResponseStatusDescription.ToLower().Equals("continue")) && this.Response.ResponseStatusDescription.ToLower().Equals("continue"))
{ {
this.Response.Is100Continue = true; this.Response.Is100Continue = true;
...@@ -338,6 +351,13 @@ namespace Titanium.Web.Proxy.Network ...@@ -338,6 +351,13 @@ namespace Titanium.Web.Proxy.Network
ReceiveResponse(); ReceiveResponse();
return; return;
} }
{
this.Response.ExpectationFailed = true;
this.Response.ResponseStatusCode = null;
ProxyClient.ServerStreamReader.ReadLine();
ReceiveResponse();
return;
}
List<string> responseLines = ProxyClient.ServerStreamReader.ReadAllLines(); List<string> responseLines = ProxyClient.ServerStreamReader.ReadAllLines();
......
...@@ -40,7 +40,7 @@ namespace Titanium.Web.Proxy ...@@ -40,7 +40,7 @@ namespace Titanium.Web.Proxy
#else #else
internal static SslProtocols SupportedProtocols = SslProtocols.Tls | SslProtocols.Ssl3; internal static SslProtocols SupportedProtocols = SslProtocols.Tls | SslProtocols.Ssl3;
#endif #endif
static ProxyServer() static ProxyServer()
{ {
...@@ -56,6 +56,7 @@ namespace Titanium.Web.Proxy ...@@ -56,6 +56,7 @@ namespace Titanium.Web.Proxy
public static string RootCertificateIssuerName { get; set; } public static string RootCertificateIssuerName { get; set; }
public static string RootCertificateName { get; set; } public static string RootCertificateName { get; set; }
public static bool Enable100ContinueBehaviour { get; set; }
public static event EventHandler<SessionEventArgs> BeforeRequest; public static event EventHandler<SessionEventArgs> BeforeRequest;
public static event EventHandler<SessionEventArgs> BeforeResponse; public static event EventHandler<SessionEventArgs> BeforeResponse;
......
...@@ -266,6 +266,21 @@ namespace Titanium.Web.Proxy ...@@ -266,6 +266,21 @@ namespace Titanium.Web.Proxy
args.ProxySession.SetConnection(connection); args.ProxySession.SetConnection(connection);
args.ProxySession.SendRequest(); args.ProxySession.SendRequest();
if(Enable100ContinueBehaviour)
if (args.ProxySession.Request.Is100Continue)
{
WriteResponseStatus(args.ProxySession.Response.HttpVersion, "100",
"Continue", args.Client.ClientStreamWriter);
args.Client.ClientStreamWriter.WriteLine();
}
else if (args.ProxySession.Request.ExpectationFailed)
{
WriteResponseStatus(args.ProxySession.Response.HttpVersion, "417",
"Expectation Failed", args.Client.ClientStreamWriter);
args.Client.ClientStreamWriter.WriteLine();
}
//If request was modified by user //If request was modified by user
if (args.ProxySession.Request.RequestBodyRead) if (args.ProxySession.Request.RequestBodyRead)
{ {
...@@ -275,14 +290,20 @@ namespace Titanium.Web.Proxy ...@@ -275,14 +290,20 @@ namespace Titanium.Web.Proxy
} }
else else
{ {
//If its a post/put request, then read the client html body and send it to server if (!args.ProxySession.Request.ExpectationFailed)
if (httpMethod.ToUpper() == "POST" || httpMethod.ToUpper() == "PUT")
{ {
SendClientRequestBody(args); //If its a post/put request, then read the client html body and send it to server
if (httpMethod.ToUpper() == "POST" || httpMethod.ToUpper() == "PUT")
{
SendClientRequestBody(args);
}
} }
} }
HandleHttpSessionResponse(args); if (!args.ProxySession.Request.ExpectationFailed)
{
HandleHttpSessionResponse(args);
}
//if connection is closing exit //if connection is closing exit
if (args.ProxySession.Response.ResponseKeepAlive == false) if (args.ProxySession.Response.ResponseKeepAlive == false)
......
...@@ -42,6 +42,12 @@ namespace Titanium.Web.Proxy ...@@ -42,6 +42,12 @@ namespace Titanium.Web.Proxy
"Continue", args.Client.ClientStreamWriter); "Continue", args.Client.ClientStreamWriter);
args.Client.ClientStreamWriter.WriteLine(); args.Client.ClientStreamWriter.WriteLine();
} }
else if (args.ProxySession.Response.ExpectationFailed)
{
WriteResponseStatus(args.ProxySession.Response.HttpVersion, "417",
"Expectation Failed", args.Client.ClientStreamWriter);
args.Client.ClientStreamWriter.WriteLine();
}
WriteResponseStatus(args.ProxySession.Response.HttpVersion, args.ProxySession.Response.ResponseStatusCode, WriteResponseStatus(args.ProxySession.Response.HttpVersion, args.ProxySession.Response.ResponseStatusCode,
args.ProxySession.Response.ResponseStatusDescription, args.Client.ClientStreamWriter); args.ProxySession.Response.ResponseStatusDescription, args.Client.ClientStreamWriter);
......
...@@ -10,12 +10,6 @@ namespace Titanium.Web.Proxy.Responses ...@@ -10,12 +10,6 @@ namespace Titanium.Web.Proxy.Responses
{ {
ResponseStatusCode = "200"; ResponseStatusCode = "200";
ResponseStatusDescription = "Ok"; ResponseStatusDescription = "Ok";
ResponseHeaders.Add(new HttpHeader("Timestamp", DateTime.Now.ToString()));
ResponseHeaders.Add(new HttpHeader("content-length", DateTime.Now.ToString()));
ResponseHeaders.Add(new HttpHeader("Cache-Control", "no-cache, no-store, must-revalidate"));
ResponseHeaders.Add(new HttpHeader("Pragma", "no-cache"));
ResponseHeaders.Add(new HttpHeader("Expires", "0"));
} }
} }
} }
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