Commit c16e1c20 authored by John Reese's avatar John Reese

Add Redirect method and refactor out compression/decompression logic for reuse

parent a4d42abf
namespace Titanium.Web.Proxy.Compression
{
class CompressionFactory
{
public ICompression Create(string type)
{
switch (type)
{
case "gzip":
return new GZipCompression();
case "deflate":
return new DeflateCompression();
case "zlib":
return new ZlibCompression();
default:
return null;
}
}
}
}
using System.IO;
using System.IO.Compression;
namespace Titanium.Web.Proxy.Compression
{
class DeflateCompression : ICompression
{
public byte[] Compress(byte[] responseBody)
{
using (var ms = new MemoryStream())
{
using (var zip = new DeflateStream(ms, CompressionMode.Compress, true))
{
zip.Write(responseBody, 0, responseBody.Length);
}
return ms.ToArray();
}
}
}
}
using Ionic.Zlib;
using System.IO;
namespace Titanium.Web.Proxy.Compression
{
class GZipCompression : ICompression
{
public byte[] Compress(byte[] responseBody)
{
using (var ms = new MemoryStream())
{
using (var zip = new GZipStream(ms, CompressionMode.Compress, true))
{
zip.Write(responseBody, 0, responseBody.Length);
}
return ms.ToArray();
}
}
}
}
namespace Titanium.Web.Proxy.Compression
{
interface ICompression
{
byte[] Compress(byte[] responseBody);
}
}
using Ionic.Zlib;
using System.IO;
namespace Titanium.Web.Proxy.Compression
{
class ZlibCompression : ICompression
{
public byte[] Compress(byte[] responseBody)
{
using (var ms = new MemoryStream())
{
using (var zip = new ZlibStream(ms, CompressionMode.Compress, true))
{
zip.Write(responseBody, 0, responseBody.Length);
}
return ms.ToArray();
}
}
}
}
namespace Titanium.Web.Proxy.Decompression
{
class DecompressionFactory
{
public IDecompression Create(string type)
{
switch(type)
{
case "gzip":
return new GZipDecompression();
case "deflate":
return new DeflateDecompression();
case "zlib":
return new ZlibDecompression();
default:
return new DefaultDecompression();
}
}
}
}
namespace Titanium.Web.Proxy.Decompression
{
class DefaultDecompression : IDecompression
{
public byte[] Decompress(byte[] compressedArray)
{
return compressedArray;
}
}
}
using Ionic.Zlib;
using System.IO;
namespace Titanium.Web.Proxy.Decompression
{
class DeflateDecompression : IDecompression
{
public byte[] Decompress(byte[] compressedArray)
{
var stream = new MemoryStream(compressedArray);
using (var decompressor = new DeflateStream(stream, 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();
}
}
}
}
}
using System.IO;
using System.IO.Compression;
namespace Titanium.Web.Proxy.Decompression
{
class GZipDecompression : IDecompression
{
public byte[] Decompress(byte[] compressedArray)
{
using (var decompressor = new GZipStream(new MemoryStream(compressedArray), 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();
}
}
}
}
}
using System.IO;
namespace Titanium.Web.Proxy.Decompression
{
interface IDecompression
{
byte[] Decompress(byte[] compressedArray);
}
}
using Ionic.Zlib;
using System.IO;
namespace Titanium.Web.Proxy.Decompression
{
class ZlibDecompression : IDecompression
{
public byte[] Decompress(byte[] compressedArray)
{
var memoryStream = new MemoryStream(compressedArray);
using (var decompressor = new ZlibStream(memoryStream, 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();
}
}
}
}
}
using System; using System;
using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text; using System.Text;
using Titanium.Web.Proxy.Exceptions; using Titanium.Web.Proxy.Exceptions;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Network; using Titanium.Web.Proxy.Network;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Responses;
using Titanium.Web.Proxy.Decompression;
namespace Titanium.Web.Proxy.EventArguments namespace Titanium.Web.Proxy.EventArguments
{ {
/// <summary> /// <summary>
/// Holds info related to a single proxy session (single request/response sequence) /// Holds info related to a single proxy session (single request/response sequence)
/// A proxy session is bounded to a single connection from client /// A proxy session is bounded to a single connection from client
...@@ -22,13 +18,11 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -22,13 +18,11 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary> /// </summary>
public class SessionEventArgs : EventArgs, IDisposable public class SessionEventArgs : EventArgs, IDisposable
{ {
/// <summary> /// <summary>
/// Constructor to initialize the proxy /// Constructor to initialize the proxy
/// </summary> /// </summary>
internal SessionEventArgs() internal SessionEventArgs()
{ {
Client = new ProxyClient(); Client = new ProxyClient();
ProxySession = new HttpWebSession(); ProxySession = new HttpWebSession();
} }
...@@ -38,7 +32,6 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -38,7 +32,6 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary> /// </summary>
internal ProxyClient Client { get; set; } internal ProxyClient Client { get; set; }
/// <summary> /// <summary>
/// Does this session uses SSL /// Does this session uses SSL
/// </summary> /// </summary>
...@@ -50,7 +43,6 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -50,7 +43,6 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary> /// </summary>
public HttpWebSession ProxySession { get; set; } public HttpWebSession ProxySession { get; set; }
/// <summary> /// <summary>
/// A shortcut to get the request content length /// A shortcut to get the request content length
/// </summary> /// </summary>
...@@ -165,22 +157,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -165,22 +157,7 @@ namespace Titanium.Web.Proxy.EventArguments
try try
{ {
//decompress ProxySession.Request.RequestBody = GetDecompressedResponseBody(requestContentEncoding, requestBodyStream.ToArray());
switch (requestContentEncoding)
{
case "gzip":
ProxySession.Request.RequestBody = CompressionHelper.DecompressGzip(requestBodyStream.ToArray());
break;
case "deflate":
ProxySession.Request.RequestBody = CompressionHelper.DecompressDeflate(requestBodyStream);
break;
case "zlib":
ProxySession.Request.RequestBody = CompressionHelper.DecompressZlib(requestBodyStream);
break;
default:
ProxySession.Request.RequestBody = requestBodyStream.ToArray();
break;
}
} }
catch catch
{ {
...@@ -235,22 +212,9 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -235,22 +212,9 @@ namespace Titanium.Web.Proxy.EventArguments
var buffer = ProxySession.ProxyClient.ServerStreamReader.ReadBytes(ProxySession.Response.ContentLength); var buffer = ProxySession.ProxyClient.ServerStreamReader.ReadBytes(ProxySession.Response.ContentLength);
responseBodyStream.Write(buffer, 0, buffer.Length); responseBodyStream.Write(buffer, 0, buffer.Length);
} }
//decompress
switch (ProxySession.Response.ContentEncoding) ProxySession.Response.ResponseBody = GetDecompressedResponseBody(ProxySession.Response.ContentEncoding, responseBodyStream.ToArray());
{
case "gzip":
ProxySession.Response.ResponseBody = CompressionHelper.DecompressGzip(responseBodyStream.ToArray());
break;
case "deflate":
ProxySession.Response.ResponseBody = CompressionHelper.DecompressDeflate(responseBodyStream);
break;
case "zlib":
ProxySession.Response.ResponseBody = CompressionHelper.DecompressZlib(responseBodyStream);
break;
default:
ProxySession.Response.ResponseBody = responseBodyStream.ToArray();
break;
}
} }
//set this to true for caching //set this to true for caching
ProxySession.Response.ResponseBodyRead = true; ProxySession.Response.ResponseBodyRead = true;
...@@ -379,6 +343,14 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -379,6 +343,14 @@ namespace Titanium.Web.Proxy.EventArguments
SetResponseBody(bodyBytes); SetResponseBody(bodyBytes);
} }
private byte[] GetDecompressedResponseBody(string encodingType, byte[] responseBodyStream)
{
var decompressionFactory = new DecompressionFactory();
var decompressor = decompressionFactory.Create(encodingType);
return decompressor.Decompress(responseBodyStream);
}
/// <summary> /// <summary>
/// Before request is made to server /// Before request is made to server
...@@ -406,20 +378,22 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -406,20 +378,22 @@ namespace Titanium.Web.Proxy.EventArguments
/// <param name="body"></param> /// <param name="body"></param>
public void Ok(byte[] result) public void Ok(byte[] result)
{ {
var response = new Response(); var response = new OkResponse();
response.HttpVersion = ProxySession.Request.HttpVersion; response.HttpVersion = ProxySession.Request.HttpVersion;
response.ResponseStatusCode = "200"; response.ResponseBody = result;
response.ResponseStatusDescription = "Ok";
response.ResponseHeaders.Add(new HttpHeader("Timestamp", DateTime.Now.ToString())); Respond(response);
response.ResponseHeaders.Add(new HttpHeader("content-length", DateTime.Now.ToString())); ProxySession.Request.CancelRequest = true;
response.ResponseHeaders.Add(new HttpHeader("Cache-Control", "no-cache, no-store, must-revalidate")); }
response.ResponseHeaders.Add(new HttpHeader("Pragma", "no-cache"));
response.ResponseHeaders.Add(new HttpHeader("Expires", "0"));
response.ResponseBody = result; public void Redirect(string url)
{
var response = new RedirectResponse();
response.HttpVersion = ProxySession.Request.HttpVersion;
response.ResponseBody = Encoding.ASCII.GetBytes(string.Empty);
Respond(response); Respond(response);
...@@ -430,6 +404,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -430,6 +404,7 @@ namespace Titanium.Web.Proxy.EventArguments
public void Respond(Response response) public void Respond(Response response)
{ {
ProxySession.Request.RequestLocked = true; ProxySession.Request.RequestLocked = true;
ProxySession.Response.ResponseLocked = true;
response.ResponseLocked = true; response.ResponseLocked = true;
response.ResponseBodyRead = true; response.ResponseBodyRead = true;
......
...@@ -12,6 +12,7 @@ using Titanium.Web.Proxy.Extensions; ...@@ -12,6 +12,7 @@ using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Network; using Titanium.Web.Proxy.Network;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Compression;
namespace Titanium.Web.Proxy namespace Titanium.Web.Proxy
{ {
...@@ -40,18 +41,9 @@ namespace Titanium.Web.Proxy ...@@ -40,18 +41,9 @@ namespace Titanium.Web.Proxy
var isChunked = args.ProxySession.Response.IsChunked; var isChunked = args.ProxySession.Response.IsChunked;
var contentEncoding = args.ProxySession.Response.ContentEncoding; var contentEncoding = args.ProxySession.Response.ContentEncoding;
if(contentEncoding!=null) if (contentEncoding != null)
switch (contentEncoding)
{ {
case "gzip": args.ProxySession.Response.ResponseBody = GetCompressedResponseBody(contentEncoding, args.ProxySession.Response.ResponseBody);
args.ProxySession.Response.ResponseBody = CompressionHelper.CompressGzip(args.ProxySession.Response.ResponseBody);
break;
case "deflate":
args.ProxySession.Response.ResponseBody = CompressionHelper.CompressDeflate(args.ProxySession.Response.ResponseBody);
break;
case "zlib":
args.ProxySession.Response.ResponseBody = CompressionHelper.CompressZlib(args.ProxySession.Response.ResponseBody);
break;
} }
WriteResponseStatus(args.ProxySession.Response.HttpVersion, args.ProxySession.Response.ResponseStatusCode, WriteResponseStatus(args.ProxySession.Response.HttpVersion, args.ProxySession.Response.ResponseStatusCode,
...@@ -83,6 +75,13 @@ namespace Titanium.Web.Proxy ...@@ -83,6 +75,13 @@ namespace Titanium.Web.Proxy
} }
} }
private static byte[] GetCompressedResponseBody(string encodingType, byte[] responseBodyStream)
{
var compressionFactory = new CompressionFactory();
var compressor = compressionFactory.Create(encodingType);
return compressor.Compress(responseBodyStream);
}
private static void WriteResponseStatus(string version, string code, string description, private static void WriteResponseStatus(string version, string code, string description,
StreamWriter responseWriter) StreamWriter responseWriter)
......
using System;
using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Network;
namespace Titanium.Web.Proxy.Responses
{
public class OkResponse : Response
{
public OkResponse()
{
ResponseStatusCode = "200";
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"));
}
}
}
using System;
using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Network;
namespace Titanium.Web.Proxy.Responses
{
public class RedirectResponse : Response
{
public RedirectResponse()
{
ResponseStatusCode = "302";
ResponseStatusDescription = "Found";
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"));
}
}
}
...@@ -80,6 +80,17 @@ ...@@ -80,6 +80,17 @@
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Compression\CompressionFactory.cs" />
<Compile Include="Compression\DeflateCompression.cs" />
<Compile Include="Compression\GZipCompression.cs" />
<Compile Include="Compression\ICompression.cs" />
<Compile Include="Compression\ZlibCompression.cs" />
<Compile Include="Decompression\DecompressionFactory.cs" />
<Compile Include="Decompression\DefaultDecompression.cs" />
<Compile Include="Decompression\DeflateDecompression.cs" />
<Compile Include="Decompression\GZipDecompression.cs" />
<Compile Include="Decompression\IDecompression.cs" />
<Compile Include="Decompression\ZlibDecompression.cs" />
<Compile Include="EventArguments\ProxyClient.cs" /> <Compile Include="EventArguments\ProxyClient.cs" />
<Compile Include="Exceptions\BodyNotFoundException.cs" /> <Compile Include="Exceptions\BodyNotFoundException.cs" />
<Compile Include="Extensions\HttpWebResponseExtensions.cs" /> <Compile Include="Extensions\HttpWebResponseExtensions.cs" />
...@@ -101,6 +112,8 @@ ...@@ -101,6 +112,8 @@
<Compile Include="EventArguments\SessionEventArgs.cs" /> <Compile Include="EventArguments\SessionEventArgs.cs" />
<Compile Include="Helpers\Tcp.cs" /> <Compile Include="Helpers\Tcp.cs" />
<Compile Include="Extensions\StreamExtensions.cs" /> <Compile Include="Extensions\StreamExtensions.cs" />
<Compile Include="Responses\OkResponse.cs" />
<Compile Include="Responses\RedirectResponse.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup /> <ItemGroup />
<ItemGroup> <ItemGroup>
......
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