Commit e0bdf695 authored by justcoding121's avatar justcoding121 Committed by justcoding121

clean up;add comments

parent 99141b28
...@@ -12,7 +12,7 @@ namespace Titanium.Web.Proxy.Compression ...@@ -12,7 +12,7 @@ namespace Titanium.Web.Proxy.Compression
{ {
using (var zip = new DeflateStream(ms, CompressionMode.Compress, true)) using (var zip = new DeflateStream(ms, CompressionMode.Compress, true))
{ {
await zip.WriteAsync(responseBody, 0, responseBody.Length).ConfigureAwait(false); await zip.WriteAsync(responseBody, 0, responseBody.Length);
} }
return ms.ToArray(); return ms.ToArray();
......
...@@ -12,7 +12,7 @@ namespace Titanium.Web.Proxy.Compression ...@@ -12,7 +12,7 @@ namespace Titanium.Web.Proxy.Compression
{ {
using (var zip = new GZipStream(ms, CompressionMode.Compress, true)) using (var zip = new GZipStream(ms, CompressionMode.Compress, true))
{ {
await zip.WriteAsync(responseBody, 0, responseBody.Length).ConfigureAwait(false); await zip.WriteAsync(responseBody, 0, responseBody.Length);
} }
return ms.ToArray(); return ms.ToArray();
......
...@@ -12,7 +12,7 @@ namespace Titanium.Web.Proxy.Compression ...@@ -12,7 +12,7 @@ namespace Titanium.Web.Proxy.Compression
{ {
using (var zip = new ZlibStream(ms, CompressionMode.Compress, true)) using (var zip = new ZlibStream(ms, CompressionMode.Compress, true))
{ {
await zip.WriteAsync(responseBody, 0, responseBody.Length).ConfigureAwait(false); await zip.WriteAsync(responseBody, 0, responseBody.Length);
} }
return ms.ToArray(); return ms.ToArray();
......
...@@ -20,7 +20,7 @@ namespace Titanium.Web.Proxy.Decompression ...@@ -20,7 +20,7 @@ namespace Titanium.Web.Proxy.Decompression
int read; int read;
while ((read = await decompressor.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false)) > 0) while ((read = await decompressor.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false)) > 0)
{ {
await output.WriteAsync(buffer, 0, read).ConfigureAwait(false); await output.WriteAsync(buffer, 0, read);
} }
return output.ToArray(); return output.ToArray();
......
...@@ -17,7 +17,7 @@ namespace Titanium.Web.Proxy.Decompression ...@@ -17,7 +17,7 @@ namespace Titanium.Web.Proxy.Decompression
int read; int read;
while ((read = await decompressor.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false)) > 0) while ((read = await decompressor.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false)) > 0)
{ {
await output.WriteAsync(buffer, 0, read).ConfigureAwait(false); await output.WriteAsync(buffer, 0, read);
} }
return output.ToArray(); return output.ToArray();
} }
......
...@@ -19,7 +19,7 @@ namespace Titanium.Web.Proxy.Decompression ...@@ -19,7 +19,7 @@ namespace Titanium.Web.Proxy.Decompression
int read; int read;
while ((read = await decompressor.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false)) > 0) while ((read = await decompressor.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false)) > 0)
{ {
await output.WriteAsync(buffer, 0, read).ConfigureAwait(false); await output.WriteAsync(buffer, 0, read);
} }
return output.ToArray(); return output.ToArray();
} }
......
...@@ -81,7 +81,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -81,7 +81,7 @@ namespace Titanium.Web.Proxy.EventArguments
//For chunked request we need to read data as they arrive, until we reach a chunk end symbol //For chunked request we need to read data as they arrive, until we reach a chunk end symbol
if (WebSession.Request.IsChunked) if (WebSession.Request.IsChunked)
{ {
await this.ProxyClient.ClientStreamReader.CopyBytesToStreamChunked(requestBodyStream).ConfigureAwait(false); await this.ProxyClient.ClientStreamReader.CopyBytesToStreamChunked(requestBodyStream);
} }
else else
{ {
...@@ -89,13 +89,13 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -89,13 +89,13 @@ namespace Titanium.Web.Proxy.EventArguments
if (WebSession.Request.ContentLength > 0) if (WebSession.Request.ContentLength > 0)
{ {
//If not chunked then its easy just read the amount of bytes mentioned in content length header of response //If not chunked then its easy just read the amount of bytes mentioned in content length header of response
await this.ProxyClient.ClientStreamReader.CopyBytesToStream(requestBodyStream, WebSession.Request.ContentLength).ConfigureAwait(false); await this.ProxyClient.ClientStreamReader.CopyBytesToStream(requestBodyStream, WebSession.Request.ContentLength);
} }
else if(WebSession.Request.HttpVersion.Major == 1 && WebSession.Request.HttpVersion.Minor == 0) else if(WebSession.Request.HttpVersion.Major == 1 && WebSession.Request.HttpVersion.Minor == 0)
await WebSession.ServerConnection.StreamReader.CopyBytesToStream(requestBodyStream, long.MaxValue).ConfigureAwait(false); await WebSession.ServerConnection.StreamReader.CopyBytesToStream(requestBodyStream, long.MaxValue);
} }
WebSession.Request.RequestBody = await GetDecompressedResponseBody(WebSession.Request.ContentEncoding, requestBodyStream.ToArray()).ConfigureAwait(false); WebSession.Request.RequestBody = await GetDecompressedResponseBody(WebSession.Request.ContentEncoding, requestBodyStream.ToArray());
} }
//Now set the flag to true //Now set the flag to true
...@@ -118,21 +118,21 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -118,21 +118,21 @@ namespace Titanium.Web.Proxy.EventArguments
//If chuncked the read chunk by chunk until we hit chunk end symbol //If chuncked the read chunk by chunk until we hit chunk end symbol
if (WebSession.Response.IsChunked) if (WebSession.Response.IsChunked)
{ {
await WebSession.ServerConnection.StreamReader.CopyBytesToStreamChunked(responseBodyStream).ConfigureAwait(false); await WebSession.ServerConnection.StreamReader.CopyBytesToStreamChunked(responseBodyStream);
} }
else else
{ {
if (WebSession.Response.ContentLength > 0) if (WebSession.Response.ContentLength > 0)
{ {
//If not chunked then its easy just read the amount of bytes mentioned in content length header of response //If not chunked then its easy just read the amount of bytes mentioned in content length header of response
await WebSession.ServerConnection.StreamReader.CopyBytesToStream(responseBodyStream, WebSession.Response.ContentLength).ConfigureAwait(false); await WebSession.ServerConnection.StreamReader.CopyBytesToStream(responseBodyStream, WebSession.Response.ContentLength);
} }
else if(WebSession.Response.HttpVersion.Major == 1 && WebSession.Response.HttpVersion.Minor == 0) else if(WebSession.Response.HttpVersion.Major == 1 && WebSession.Response.HttpVersion.Minor == 0)
await WebSession.ServerConnection.StreamReader.CopyBytesToStream(responseBodyStream, long.MaxValue).ConfigureAwait(false); await WebSession.ServerConnection.StreamReader.CopyBytesToStream(responseBodyStream, long.MaxValue);
} }
WebSession.Response.ResponseBody = await GetDecompressedResponseBody(WebSession.Response.ContentEncoding, responseBodyStream.ToArray()).ConfigureAwait(false); WebSession.Response.ResponseBody = await GetDecompressedResponseBody(WebSession.Response.ContentEncoding, responseBodyStream.ToArray());
} }
//set this to true for caching //set this to true for caching
...@@ -149,7 +149,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -149,7 +149,7 @@ namespace Titanium.Web.Proxy.EventArguments
if (WebSession.Request.RequestLocked) if (WebSession.Request.RequestLocked)
throw new Exception("You cannot call this function after request is made to server."); throw new Exception("You cannot call this function after request is made to server.");
await ReadRequestBody().ConfigureAwait(false); await ReadRequestBody();
return WebSession.Request.RequestBody; return WebSession.Request.RequestBody;
} }
/// <summary> /// <summary>
...@@ -162,7 +162,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -162,7 +162,7 @@ namespace Titanium.Web.Proxy.EventArguments
throw new Exception("You cannot call this function after request is made to server."); throw new Exception("You cannot call this function after request is made to server.");
await ReadRequestBody().ConfigureAwait(false); await ReadRequestBody();
//Use the encoding specified in request to decode the byte[] data to string //Use the encoding specified in request to decode the byte[] data to string
return WebSession.Request.RequestBodyString ?? (WebSession.Request.RequestBodyString = WebSession.Request.Encoding.GetString(WebSession.Request.RequestBody)); return WebSession.Request.RequestBodyString ?? (WebSession.Request.RequestBodyString = WebSession.Request.Encoding.GetString(WebSession.Request.RequestBody));
...@@ -180,7 +180,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -180,7 +180,7 @@ namespace Titanium.Web.Proxy.EventArguments
//syphon out the request body from client before setting the new body //syphon out the request body from client before setting the new body
if (!WebSession.Request.RequestBodyRead) if (!WebSession.Request.RequestBodyRead)
{ {
await ReadRequestBody().ConfigureAwait(false); await ReadRequestBody();
} }
WebSession.Request.RequestBody = body; WebSession.Request.RequestBody = body;
...@@ -203,7 +203,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -203,7 +203,7 @@ namespace Titanium.Web.Proxy.EventArguments
//syphon out the request body from client before setting the new body //syphon out the request body from client before setting the new body
if (!WebSession.Request.RequestBodyRead) if (!WebSession.Request.RequestBodyRead)
{ {
await ReadRequestBody().ConfigureAwait(false); await ReadRequestBody();
} }
await SetRequestBody(WebSession.Request.Encoding.GetBytes(body)); await SetRequestBody(WebSession.Request.Encoding.GetBytes(body));
...@@ -219,7 +219,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -219,7 +219,7 @@ namespace Titanium.Web.Proxy.EventArguments
if (!WebSession.Request.RequestLocked) if (!WebSession.Request.RequestLocked)
throw new Exception("You cannot call this function before request is made to server."); throw new Exception("You cannot call this function before request is made to server.");
await ReadResponseBody().ConfigureAwait(false); await ReadResponseBody();
return WebSession.Response.ResponseBody; return WebSession.Response.ResponseBody;
} }
...@@ -232,7 +232,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -232,7 +232,7 @@ namespace Titanium.Web.Proxy.EventArguments
if (!WebSession.Request.RequestLocked) if (!WebSession.Request.RequestLocked)
throw new Exception("You cannot call this function before request is made to server."); throw new Exception("You cannot call this function before request is made to server.");
await GetResponseBody().ConfigureAwait(false); await GetResponseBody();
return WebSession.Response.ResponseBodyString ?? (WebSession.Response.ResponseBodyString = WebSession.Response.Encoding.GetString(WebSession.Response.ResponseBody)); return WebSession.Response.ResponseBodyString ?? (WebSession.Response.ResponseBodyString = WebSession.Response.Encoding.GetString(WebSession.Response.ResponseBody));
} }
...@@ -249,7 +249,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -249,7 +249,7 @@ namespace Titanium.Web.Proxy.EventArguments
//syphon out the response body from server before setting the new body //syphon out the response body from server before setting the new body
if (WebSession.Response.ResponseBody == null) if (WebSession.Response.ResponseBody == null)
{ {
await GetResponseBody().ConfigureAwait(false); await GetResponseBody();
} }
WebSession.Response.ResponseBody = body; WebSession.Response.ResponseBody = body;
...@@ -273,12 +273,12 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -273,12 +273,12 @@ namespace Titanium.Web.Proxy.EventArguments
//syphon out the response body from server before setting the new body //syphon out the response body from server before setting the new body
if (WebSession.Response.ResponseBody == null) if (WebSession.Response.ResponseBody == null)
{ {
await GetResponseBody().ConfigureAwait(false); await GetResponseBody();
} }
var bodyBytes = WebSession.Response.Encoding.GetBytes(body); var bodyBytes = WebSession.Response.Encoding.GetBytes(body);
await SetResponseBody(bodyBytes).ConfigureAwait(false); await SetResponseBody(bodyBytes);
} }
private async Task<byte[]> GetDecompressedResponseBody(string encodingType, byte[] responseBodyStream) private async Task<byte[]> GetDecompressedResponseBody(string encodingType, byte[] responseBodyStream)
...@@ -286,7 +286,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -286,7 +286,7 @@ namespace Titanium.Web.Proxy.EventArguments
var decompressionFactory = new DecompressionFactory(); var decompressionFactory = new DecompressionFactory();
var decompressor = decompressionFactory.Create(encodingType); var decompressor = decompressionFactory.Create(encodingType);
return await decompressor.Decompress(responseBodyStream).ConfigureAwait(false); return await decompressor.Decompress(responseBodyStream);
} }
...@@ -306,7 +306,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -306,7 +306,7 @@ namespace Titanium.Web.Proxy.EventArguments
var result = Encoding.Default.GetBytes(html); var result = Encoding.Default.GetBytes(html);
await Ok(result).ConfigureAwait(false); await Ok(result);
} }
/// <summary> /// <summary>
...@@ -322,7 +322,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -322,7 +322,7 @@ namespace Titanium.Web.Proxy.EventArguments
response.HttpVersion = WebSession.Request.HttpVersion; response.HttpVersion = WebSession.Request.HttpVersion;
response.ResponseBody = result; response.ResponseBody = result;
await Respond(response).ConfigureAwait(false); await Respond(response);
WebSession.Request.CancelRequest = true; WebSession.Request.CancelRequest = true;
} }
...@@ -335,7 +335,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -335,7 +335,7 @@ namespace Titanium.Web.Proxy.EventArguments
response.ResponseHeaders.Add(new Models.HttpHeader("Location", url)); response.ResponseHeaders.Add(new Models.HttpHeader("Location", url));
response.ResponseBody = Encoding.ASCII.GetBytes(string.Empty); response.ResponseBody = Encoding.ASCII.GetBytes(string.Empty);
await Respond(response).ConfigureAwait(false); await Respond(response);
WebSession.Request.CancelRequest = true; WebSession.Request.CancelRequest = true;
} }
...@@ -350,7 +350,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -350,7 +350,7 @@ namespace Titanium.Web.Proxy.EventArguments
WebSession.Response = response; WebSession.Response = response;
await ProxyServer.HandleHttpSessionResponse(this).ConfigureAwait(false); await ProxyServer.HandleHttpSessionResponse(this);
} }
} }
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Extensions
{
public static class ByteArrayExtensions
{
/// <summary>
/// Get the sub array from byte of data
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="data"></param>
/// <param name="index"></param>
/// <param name="length"></param>
/// <returns></returns>
public static T[] SubArray<T>(this T[] data, int index, int length)
{
T[] result = new T[length];
Array.Copy(data, index, result, 0, length);
return result;
}
}
}
...@@ -9,7 +9,11 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -9,7 +9,11 @@ namespace Titanium.Web.Proxy.Extensions
/// </summary> /// </summary>
internal static class HttpWebRequestExtensions internal static class HttpWebRequestExtensions
{ {
//Get encoding of the HTTP request /// <summary>
/// parse the character encoding of request from request headers
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
internal static Encoding GetEncoding(this Request request) internal static Encoding GetEncoding(this Request request)
{ {
try try
......
...@@ -6,6 +6,11 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -6,6 +6,11 @@ namespace Titanium.Web.Proxy.Extensions
{ {
internal static class HttpWebResponseExtensions internal static class HttpWebResponseExtensions
{ {
/// <summary>
/// Gets the character encoding of response from response headers
/// </summary>
/// <param name="response"></param>
/// <returns></returns>
internal static Encoding GetResponseCharacterEncoding(this Response response) internal static Encoding GetResponseCharacterEncoding(this Response response)
{ {
try try
......
...@@ -8,8 +8,15 @@ using Titanium.Web.Proxy.Shared; ...@@ -8,8 +8,15 @@ using Titanium.Web.Proxy.Shared;
namespace Titanium.Web.Proxy.Extensions namespace Titanium.Web.Proxy.Extensions
{ {
internal static class StreamHelper internal static class StreamExtensions
{ {
/// <summary>
/// Copy streams asynchronously with an initial data inserted to the beginning of stream
/// </summary>
/// <param name="input"></param>
/// <param name="initialData"></param>
/// <param name="output"></param>
/// <returns></returns>
internal static async Task CopyToAsync(this Stream input, string initialData, Stream output) internal static async Task CopyToAsync(this Stream input, string initialData, Stream output)
{ {
if (!string.IsNullOrEmpty(initialData)) if (!string.IsNullOrEmpty(initialData))
...@@ -19,7 +26,13 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -19,7 +26,13 @@ namespace Titanium.Web.Proxy.Extensions
} }
await input.CopyToAsync(output); await input.CopyToAsync(output);
} }
/// <summary>
/// copies the specified bytes to the stream from the input stream
/// </summary>
/// <param name="streamReader"></param>
/// <param name="stream"></param>
/// <param name="totalBytesToRead"></param>
/// <returns></returns>
internal static async Task CopyBytesToStream(this CustomBinaryReader streamReader, Stream stream, long totalBytesToRead) internal static async Task CopyBytesToStream(this CustomBinaryReader streamReader, Stream stream, long totalBytesToRead)
{ {
var totalbytesRead = 0; var totalbytesRead = 0;
...@@ -50,11 +63,18 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -50,11 +63,18 @@ namespace Titanium.Web.Proxy.Extensions
await stream.WriteAsync(buffer, 0, buffer.Length); await stream.WriteAsync(buffer, 0, buffer.Length);
} }
} }
/// <summary>
/// Copies the stream chunked
/// </summary>
/// <param name="clientStreamReader"></param>
/// <param name="stream"></param>
/// <returns></returns>
internal static async Task CopyBytesToStreamChunked(this CustomBinaryReader clientStreamReader, Stream stream) internal static async Task CopyBytesToStreamChunked(this CustomBinaryReader clientStreamReader, Stream stream)
{ {
while (true) while (true)
{ {
var chuchkHead = await clientStreamReader.ReadLineAsync().ConfigureAwait(false); var chuchkHead = await clientStreamReader.ReadLineAsync();
var chunkSize = int.Parse(chuchkHead, NumberStyles.HexNumber); var chunkSize = int.Parse(chuchkHead, NumberStyles.HexNumber);
if (chunkSize != 0) if (chunkSize != 0)
...@@ -62,14 +82,127 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -62,14 +82,127 @@ namespace Titanium.Web.Proxy.Extensions
var buffer = await clientStreamReader.ReadBytesAsync(chunkSize); var buffer = await clientStreamReader.ReadBytesAsync(chunkSize);
await stream.WriteAsync(buffer, 0, buffer.Length); await stream.WriteAsync(buffer, 0, buffer.Length);
//chunk trail //chunk trail
await clientStreamReader.ReadLineAsync().ConfigureAwait(false); await clientStreamReader.ReadLineAsync();
} }
else else
{ {
await clientStreamReader.ReadLineAsync().ConfigureAwait(false); await clientStreamReader.ReadLineAsync();
break; break;
} }
} }
} }
/// <summary>
/// Writes the byte array body to the given stream; optionally chunked
/// </summary>
/// <param name="clientStream"></param>
/// <param name="data"></param>
/// <param name="isChunked"></param>
/// <returns></returns>
internal static async Task WriteResponseBody(this Stream clientStream, byte[] data, bool isChunked)
{
if (!isChunked)
{
await clientStream.WriteAsync(data, 0, data.Length);
}
else
await WriteResponseBodyChunked(data, clientStream);
}
/// <summary>
/// Copies the specified content length number of bytes to the output stream from the given inputs stream
/// optionally chunked
/// </summary>
/// <param name="inStreamReader"></param>
/// <param name="outStream"></param>
/// <param name="isChunked"></param>
/// <param name="ContentLength"></param>
/// <returns></returns>
internal static async Task WriteResponseBody(this CustomBinaryReader inStreamReader, Stream outStream, bool isChunked, long ContentLength)
{
if (!isChunked)
{
//http 1.0
if (ContentLength == -1)
ContentLength = long.MaxValue;
int bytesToRead = ProxyConstants.BUFFER_SIZE;
if (ContentLength < ProxyConstants.BUFFER_SIZE)
bytesToRead = (int)ContentLength;
var buffer = new byte[ProxyConstants.BUFFER_SIZE];
var bytesRead = 0;
var totalBytesRead = 0;
while ((bytesRead += await inStreamReader.BaseStream.ReadAsync(buffer, 0, bytesToRead).ConfigureAwait(false)) > 0)
{
await outStream.WriteAsync(buffer, 0, bytesRead);
totalBytesRead += bytesRead;
if (totalBytesRead == ContentLength)
break;
bytesRead = 0;
var remainingBytes = (ContentLength - totalBytesRead);
bytesToRead = remainingBytes > (long)ProxyConstants.BUFFER_SIZE ? ProxyConstants.BUFFER_SIZE : (int)remainingBytes;
}
}
else
await WriteResponseBodyChunked(inStreamReader, outStream);
}
/// <summary>
/// Copies the streams chunked
/// </summary>
/// <param name="inStreamReader"></param>
/// <param name="outStream"></param>
/// <returns></returns>
internal static async Task WriteResponseBodyChunked(this CustomBinaryReader inStreamReader, Stream outStream)
{
while (true)
{
var chunkHead = await inStreamReader.ReadLineAsync();
var chunkSize = int.Parse(chunkHead, NumberStyles.HexNumber);
if (chunkSize != 0)
{
var buffer = await inStreamReader.ReadBytesAsync(chunkSize);
var chunkHeadBytes = Encoding.ASCII.GetBytes(chunkSize.ToString("x2"));
await outStream.WriteAsync(chunkHeadBytes, 0, chunkHeadBytes.Length);
await outStream.WriteAsync(ProxyConstants.NewLineBytes, 0, ProxyConstants.NewLineBytes.Length);
await outStream.WriteAsync(buffer, 0, chunkSize);
await outStream.WriteAsync(ProxyConstants.NewLineBytes, 0, ProxyConstants.NewLineBytes.Length);
await inStreamReader.ReadLineAsync();
}
else
{
await inStreamReader.ReadLineAsync();
await outStream.WriteAsync(ProxyConstants.ChunkEnd, 0, ProxyConstants.ChunkEnd.Length);
break;
}
}
}
/// <summary>
/// Copies the given input bytes to output stream chunked
/// </summary>
/// <param name="data"></param>
/// <param name="outStream"></param>
/// <returns></returns>
internal static async Task WriteResponseBodyChunked(this byte[] data, Stream outStream)
{
var chunkHead = Encoding.ASCII.GetBytes(data.Length.ToString("x2"));
await outStream.WriteAsync(chunkHead, 0, chunkHead.Length);
await outStream.WriteAsync(ProxyConstants.NewLineBytes, 0, ProxyConstants.NewLineBytes.Length);
await outStream.WriteAsync(data, 0, data.Length);
await outStream.WriteAsync(ProxyConstants.NewLineBytes, 0, ProxyConstants.NewLineBytes.Length);
await outStream.WriteAsync(ProxyConstants.ChunkEnd, 0, ProxyConstants.ChunkEnd.Length);
}
} }
} }
\ No newline at end of file
...@@ -4,6 +4,11 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -4,6 +4,11 @@ namespace Titanium.Web.Proxy.Extensions
{ {
internal static class TcpExtensions internal static class TcpExtensions
{ {
/// <summary>
/// verifies if the underlying socket is connected before using a TcpClient connection
/// </summary>
/// <param name="client"></param>
/// <returns></returns>
internal static bool IsConnected(this Socket client) internal static bool IsConnected(this Socket client)
{ {
// This is how you can determine whether a socket is still connected. // This is how you can determine whether a socket is still connected.
......
...@@ -248,7 +248,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -248,7 +248,7 @@ namespace Titanium.Web.Proxy.Helpers
} }
finally { semaphoreLock.Release(); } finally { semaphoreLock.Release(); }
await Task.Delay(1000 * 60 * 3).ConfigureAwait(false); await Task.Delay(1000 * 60 * 3);
} }
} }
......
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Net.Security;
using System.Net.Sockets;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Titanium.Web.Proxy.Network; using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Shared; using Titanium.Web.Proxy.Shared;
namespace Titanium.Web.Proxy.Helpers namespace Titanium.Web.Proxy.Helpers
{ {
/// <summary> /// <summary>
/// A custom binary reader that would allo us to read string line by line /// A custom binary reader that would allo us to read string line by line
/// using the specified encoding /// using the specified encoding
...@@ -18,10 +17,11 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -18,10 +17,11 @@ namespace Titanium.Web.Proxy.Helpers
internal class CustomBinaryReader : IDisposable internal class CustomBinaryReader : IDisposable
{ {
private Stream stream; private Stream stream;
private Encoding encoding;
internal CustomBinaryReader(Stream stream) internal CustomBinaryReader(Stream stream)
{ {
this.stream = stream; this.stream = stream;
this.encoding = Encoding.UTF8;
} }
internal Stream BaseStream => stream; internal Stream BaseStream => stream;
...@@ -32,8 +32,8 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -32,8 +32,8 @@ namespace Titanium.Web.Proxy.Helpers
/// <returns></returns> /// <returns></returns>
internal async Task<string> ReadLineAsync() internal async Task<string> ReadLineAsync()
{ {
var readBuffer = new StringBuilder(); using (var readBuffer = new MemoryStream())
{
try try
{ {
var lastChar = default(char); var lastChar = default(char);
...@@ -43,21 +43,23 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -43,21 +43,23 @@ namespace Titanium.Web.Proxy.Helpers
{ {
if (lastChar == '\r' && buffer[0] == '\n') if (lastChar == '\r' && buffer[0] == '\n')
{ {
return await Task.FromResult(readBuffer.Remove(readBuffer.Length - 1, 1).ToString()); var result = readBuffer.ToArray();
return encoding.GetString(result.SubArray(0, result.Length - 1));
} }
if (buffer[0] == '\0') if (buffer[0] == '\0')
{ {
return await Task.FromResult(readBuffer.ToString()); return encoding.GetString(readBuffer.ToArray());
} }
readBuffer.Append((char)buffer[0]); await readBuffer.WriteAsync(buffer,0,1);
lastChar = (char)buffer[0]; lastChar = (char)buffer[0];
} }
return await Task.FromResult(readBuffer.ToString()); return encoding.GetString(readBuffer.ToArray());
} }
catch (IOException) catch (IOException)
{ {
return await Task.FromResult(readBuffer.ToString()); return encoding.GetString(readBuffer.ToArray());
}
} }
} }
...@@ -92,7 +94,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -92,7 +94,7 @@ namespace Titanium.Web.Proxy.Helpers
{ {
while ((bytesRead += await this.stream.ReadAsync(buffer, 0, bytesToRead).ConfigureAwait(false)) > 0) while ((bytesRead += await this.stream.ReadAsync(buffer, 0, bytesToRead).ConfigureAwait(false)) > 0)
{ {
await outStream.WriteAsync(buffer, 0, bytesRead).ConfigureAwait(false); await outStream.WriteAsync(buffer, 0, bytesRead);
totalBytesRead += bytesRead; totalBytesRead += bytesRead;
if (totalBytesRead == totalBytesToRead) if (totalBytesRead == totalBytesToRead)
......
...@@ -72,7 +72,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -72,7 +72,7 @@ namespace Titanium.Web.Proxy.Helpers
var receiveRelay = tunnelStream.CopyToAsync(string.Empty, clientStream); var receiveRelay = tunnelStream.CopyToAsync(string.Empty, clientStream);
await Task.WhenAll(sendRelay, receiveRelay).ConfigureAwait(false); await Task.WhenAll(sendRelay, receiveRelay);
} }
catch catch
{ {
......
...@@ -76,13 +76,13 @@ namespace Titanium.Web.Proxy.Http ...@@ -76,13 +76,13 @@ namespace Titanium.Web.Proxy.Http
&& responseStatusDescription.ToLower().Equals("continue")) && responseStatusDescription.ToLower().Equals("continue"))
{ {
this.Request.Is100Continue = true; this.Request.Is100Continue = true;
await ServerConnection.StreamReader.ReadLineAsync().ConfigureAwait(false); await ServerConnection.StreamReader.ReadLineAsync();
} }
else if (responseStatusCode.Equals("417") else if (responseStatusCode.Equals("417")
&& responseStatusDescription.ToLower().Equals("expectation failed")) && responseStatusDescription.ToLower().Equals("expectation failed"))
{ {
this.Request.ExpectationFailed = true; this.Request.ExpectationFailed = true;
await ServerConnection.StreamReader.ReadLineAsync().ConfigureAwait(false); await ServerConnection.StreamReader.ReadLineAsync();
} }
} }
} }
...@@ -96,7 +96,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -96,7 +96,7 @@ namespace Titanium.Web.Proxy.Http
if (string.IsNullOrEmpty(httpResult[0])) if (string.IsNullOrEmpty(httpResult[0]))
{ {
await ServerConnection.StreamReader.ReadLineAsync().ConfigureAwait(false); await ServerConnection.StreamReader.ReadLineAsync();
} }
var httpVersion = httpResult[0].Trim().ToLower(); var httpVersion = httpResult[0].Trim().ToLower();
...@@ -116,7 +116,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -116,7 +116,7 @@ namespace Titanium.Web.Proxy.Http
{ {
this.Response.Is100Continue = true; this.Response.Is100Continue = true;
this.Response.ResponseStatusCode = null; this.Response.ResponseStatusCode = null;
await ServerConnection.StreamReader.ReadLineAsync().ConfigureAwait(false); await ServerConnection.StreamReader.ReadLineAsync();
await ReceiveResponse(); await ReceiveResponse();
return; return;
} }
...@@ -125,12 +125,12 @@ namespace Titanium.Web.Proxy.Http ...@@ -125,12 +125,12 @@ namespace Titanium.Web.Proxy.Http
{ {
this.Response.ExpectationFailed = true; this.Response.ExpectationFailed = true;
this.Response.ResponseStatusCode = null; this.Response.ResponseStatusCode = null;
await ServerConnection.StreamReader.ReadLineAsync().ConfigureAwait(false); await ServerConnection.StreamReader.ReadLineAsync();
await ReceiveResponse(); await ReceiveResponse();
return; return;
} }
List<string> responseLines = await ServerConnection.StreamReader.ReadAllLinesAsync().ConfigureAwait(false); List<string> responseLines = await ServerConnection.StreamReader.ReadAllLinesAsync();
for (int index = 0; index < responseLines.Count; ++index) for (int index = 0; index < responseLines.Count; ++index)
{ {
......
...@@ -79,7 +79,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -79,7 +79,7 @@ namespace Titanium.Web.Proxy.Network
} }
if (cached == null) if (cached == null)
cached = await CreateClient(hostname, port, isHttps, version).ConfigureAwait(false); cached = await CreateClient(hostname, port, isHttps, version);
if (cachedConnections == null || cachedConnections.Count() <= 2) if (cachedConnections == null || cachedConnections.Count() <= 2)
{ {
...@@ -111,22 +111,22 @@ namespace Titanium.Web.Proxy.Network ...@@ -111,22 +111,22 @@ namespace Titanium.Web.Proxy.Network
using (var writer = new StreamWriter(stream, Encoding.ASCII, ProxyConstants.BUFFER_SIZE, true)) using (var writer = new StreamWriter(stream, Encoding.ASCII, ProxyConstants.BUFFER_SIZE, true))
{ {
await writer.WriteLineAsync(string.Format("CONNECT {0}:{1} {2}", hostname, port, version)).ConfigureAwait(false); await writer.WriteLineAsync(string.Format("CONNECT {0}:{1} {2}", hostname, port, version));
await writer.WriteLineAsync(string.Format("Host: {0}:{1}", hostname, port)).ConfigureAwait(false); await writer.WriteLineAsync(string.Format("Host: {0}:{1}", hostname, port));
await writer.WriteLineAsync("Connection: Keep-Alive").ConfigureAwait(false); await writer.WriteLineAsync("Connection: Keep-Alive");
await writer.WriteLineAsync().ConfigureAwait(false); await writer.WriteLineAsync();
await writer.FlushAsync().ConfigureAwait(false); await writer.FlushAsync();
writer.Close(); writer.Close();
} }
using (var reader = new CustomBinaryReader(stream)) using (var reader = new CustomBinaryReader(stream))
{ {
var result = await reader.ReadLineAsync().ConfigureAwait(false); var result = await reader.ReadLineAsync();
if (!result.ToLower().Contains("200 connection established")) if (!result.ToLower().Contains("200 connection established"))
throw new Exception("Upstream proxy failed to create a secure tunnel"); throw new Exception("Upstream proxy failed to create a secure tunnel");
await reader.ReadAllLinesAsync().ConfigureAwait(false); await reader.ReadAllLinesAsync();
} }
} }
else else
...@@ -139,7 +139,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -139,7 +139,7 @@ namespace Titanium.Web.Proxy.Network
{ {
sslStream = new SslStream(stream, true, new RemoteCertificateValidationCallback(ProxyServer.ValidateServerCertificate), sslStream = new SslStream(stream, true, new RemoteCertificateValidationCallback(ProxyServer.ValidateServerCertificate),
new LocalCertificateSelectionCallback(ProxyServer.SelectClientCertificate)); new LocalCertificateSelectionCallback(ProxyServer.SelectClientCertificate));
await sslStream.AuthenticateAsClientAsync(hostname, null, ProxyConstants.SupportedSslProtocols, false).ConfigureAwait(false); await sslStream.AuthenticateAsClientAsync(hostname, null, ProxyConstants.SupportedSslProtocols, false);
stream = (Stream)sslStream; stream = (Stream)sslStream;
} }
catch catch
...@@ -224,7 +224,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -224,7 +224,7 @@ namespace Titanium.Web.Proxy.Network
} }
finally { connectionAccessLock.Release(); } finally { connectionAccessLock.Release(); }
await Task.Delay(1000 * 60 * 3).ConfigureAwait(false); await Task.Delay(1000 * 60);
} }
} }
......
...@@ -32,7 +32,7 @@ namespace Titanium.Web.Proxy ...@@ -32,7 +32,7 @@ namespace Titanium.Web.Proxy
try try
{ {
//read the first line HTTP command //read the first line HTTP command
var httpCmd = await clientStreamReader.ReadLineAsync().ConfigureAwait(false); var httpCmd = await clientStreamReader.ReadLineAsync();
if (string.IsNullOrEmpty(httpCmd)) if (string.IsNullOrEmpty(httpCmd))
{ {
...@@ -68,25 +68,23 @@ namespace Titanium.Web.Proxy ...@@ -68,25 +68,23 @@ namespace Titanium.Web.Proxy
if (httpVerb.ToUpper() == "CONNECT" && !excluded && httpRemoteUri.Port != 80) if (httpVerb.ToUpper() == "CONNECT" && !excluded && httpRemoteUri.Port != 80)
{ {
httpRemoteUri = new Uri("https://" + httpCmdSplit[1]); httpRemoteUri = new Uri("https://" + httpCmdSplit[1]);
await clientStreamReader.ReadAllLinesAsync().ConfigureAwait(false); await clientStreamReader.ReadAllLinesAsync();
await WriteConnectResponse(clientStreamWriter, version).ConfigureAwait(false);
await WriteConnectResponse(clientStreamWriter, version);
SslStream sslStream = null; SslStream sslStream = null;
try try
{ {
var tunnelClient = await TcpConnectionManager.GetClient(httpRemoteUri.Host, httpRemoteUri.Port, true, version).ConfigureAwait(false); var tunnelClient = await TcpConnectionManager.GetClient(httpRemoteUri.Host, httpRemoteUri.Port, true, version);
await TcpConnectionManager.ReleaseClient(tunnelClient); await TcpConnectionManager.ReleaseClient(tunnelClient);
sslStream = new SslStream(clientStream, true); sslStream = new SslStream(clientStream, true);
var certificate = await CertManager.CreateCertificate(httpRemoteUri.Host, false); var certificate = await CertManager.CreateCertificate(httpRemoteUri.Host, false);
//Successfully managed to authenticate the client using the fake certificate //Successfully managed to authenticate the client using the fake certificate
await sslStream.AuthenticateAsServerAsync(certificate, false, await sslStream.AuthenticateAsServerAsync(certificate, false,
ProxyConstants.SupportedSslProtocols, false).ConfigureAwait(false); ProxyConstants.SupportedSslProtocols, false);
//HTTPS server created - we can now decrypt the client's traffic //HTTPS server created - we can now decrypt the client's traffic
clientStream = sslStream; clientStream = sslStream;
...@@ -104,26 +102,24 @@ namespace Titanium.Web.Proxy ...@@ -104,26 +102,24 @@ namespace Titanium.Web.Proxy
return; return;
} }
httpCmd = await clientStreamReader.ReadLineAsync();
httpCmd = await clientStreamReader.ReadLineAsync().ConfigureAwait(false);
} }
else if (httpVerb.ToUpper() == "CONNECT") else if (httpVerb.ToUpper() == "CONNECT")
{ {
await clientStreamReader.ReadAllLinesAsync().ConfigureAwait(false); await clientStreamReader.ReadAllLinesAsync();
await WriteConnectResponse(clientStreamWriter, version).ConfigureAwait(false); await WriteConnectResponse(clientStreamWriter, version);
await TcpHelper.SendRaw(clientStream, null, null, httpRemoteUri.Host, httpRemoteUri.Port, await TcpHelper.SendRaw(clientStream, null, null, httpRemoteUri.Host, httpRemoteUri.Port,
false).ConfigureAwait(false); false);
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null); Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null);
return; return;
} }
//Now create the request //Now create the request
await HandleHttpSessionRequest(client, httpCmd, clientStream, clientStreamReader, clientStreamWriter, await HandleHttpSessionRequest(client, httpCmd, clientStream, clientStreamReader, clientStreamWriter,
httpRemoteUri.Scheme == Uri.UriSchemeHttps ? true : false).ConfigureAwait(false); httpRemoteUri.Scheme == Uri.UriSchemeHttps ? true : false);
} }
catch catch
{ {
...@@ -155,7 +151,7 @@ namespace Titanium.Web.Proxy ...@@ -155,7 +151,7 @@ namespace Titanium.Web.Proxy
{ {
//Successfully managed to authenticate the client using the fake certificate //Successfully managed to authenticate the client using the fake certificate
await sslStream.AuthenticateAsServerAsync(certificate, false, await sslStream.AuthenticateAsServerAsync(certificate, false,
SslProtocols.Tls, false).ConfigureAwait(false); SslProtocols.Tls, false);
clientStreamReader = new CustomBinaryReader(sslStream); clientStreamReader = new CustomBinaryReader(sslStream);
clientStreamWriter = new StreamWriter(sslStream); clientStreamWriter = new StreamWriter(sslStream);
...@@ -177,11 +173,11 @@ namespace Titanium.Web.Proxy ...@@ -177,11 +173,11 @@ namespace Titanium.Web.Proxy
clientStreamReader = new CustomBinaryReader(clientStream); clientStreamReader = new CustomBinaryReader(clientStream);
} }
var httpCmd = await clientStreamReader.ReadLineAsync().ConfigureAwait(false); var httpCmd = await clientStreamReader.ReadLineAsync();
//Now create the request //Now create the request
await HandleHttpSessionRequest(tcpClient, httpCmd, clientStream, clientStreamReader, clientStreamWriter, await HandleHttpSessionRequest(tcpClient, httpCmd, clientStream, clientStreamReader, clientStreamWriter,
true).ConfigureAwait(false); true);
} }
private static async Task HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream, private static async Task HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream,
...@@ -234,7 +230,6 @@ namespace Titanium.Web.Proxy ...@@ -234,7 +230,6 @@ namespace Titanium.Web.Proxy
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null); Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null);
break; break;
} }
#endif #endif
args.WebSession.Request.RequestUri = httpRemoteUri; args.WebSession.Request.RequestUri = httpRemoteUri;
...@@ -244,7 +239,6 @@ namespace Titanium.Web.Proxy ...@@ -244,7 +239,6 @@ namespace Titanium.Web.Proxy
args.ProxyClient.ClientStreamReader = clientStreamReader; args.ProxyClient.ClientStreamReader = clientStreamReader;
args.ProxyClient.ClientStreamWriter = clientStreamWriter; args.ProxyClient.ClientStreamWriter = clientStreamWriter;
PrepareRequestHeaders(args.WebSession.Request.RequestHeaders, args.WebSession); PrepareRequestHeaders(args.WebSession.Request.RequestHeaders, args.WebSession);
args.WebSession.Request.Host = args.WebSession.Request.RequestUri.Authority; args.WebSession.Request.Host = args.WebSession.Request.RequestUri.Authority;
...@@ -259,19 +253,19 @@ namespace Titanium.Web.Proxy ...@@ -259,19 +253,19 @@ namespace Titanium.Web.Proxy
handlerTasks[i] = ((Func<object, SessionEventArgs, Task>)invocationList[i])(null, args); handlerTasks[i] = ((Func<object, SessionEventArgs, Task>)invocationList[i])(null, args);
} }
await Task.WhenAll(handlerTasks).ConfigureAwait(false); await Task.WhenAll(handlerTasks);
} }
if (args.WebSession.Request.UpgradeToWebSocket) if (args.WebSession.Request.UpgradeToWebSocket)
{ {
await TcpHelper.SendRaw(clientStream, httpCmd, args.WebSession.Request.RequestHeaders, await TcpHelper.SendRaw(clientStream, httpCmd, args.WebSession.Request.RequestHeaders,
httpRemoteUri.Host, httpRemoteUri.Port, args.IsHttps).ConfigureAwait(false); httpRemoteUri.Host, httpRemoteUri.Port, args.IsHttps);
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args); Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
return; return;
} }
//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.
connection = await TcpConnectionManager.GetClient(args.WebSession.Request.RequestUri.Host, args.WebSession.Request.RequestUri.Port, args.IsHttps, version).ConfigureAwait(false); connection = await TcpConnectionManager.GetClient(args.WebSession.Request.RequestUri.Host, args.WebSession.Request.RequestUri.Port, args.IsHttps, version);
args.WebSession.Request.RequestLocked = true; args.WebSession.Request.RequestLocked = true;
...@@ -285,7 +279,7 @@ namespace Titanium.Web.Proxy ...@@ -285,7 +279,7 @@ namespace Titanium.Web.Proxy
if (args.WebSession.Request.ExpectContinue) if (args.WebSession.Request.ExpectContinue)
{ {
args.WebSession.SetConnection(connection); args.WebSession.SetConnection(connection);
await args.WebSession.SendRequest().ConfigureAwait(false); await args.WebSession.SendRequest();
} }
if (Enable100ContinueBehaviour) if (Enable100ContinueBehaviour)
...@@ -305,7 +299,7 @@ namespace Titanium.Web.Proxy ...@@ -305,7 +299,7 @@ namespace Titanium.Web.Proxy
if (!args.WebSession.Request.ExpectContinue) if (!args.WebSession.Request.ExpectContinue)
{ {
args.WebSession.SetConnection(connection); args.WebSession.SetConnection(connection);
await args.WebSession.SendRequest().ConfigureAwait(false); await args.WebSession.SendRequest();
} }
//If request was modified by user //If request was modified by user
...@@ -319,7 +313,7 @@ namespace Titanium.Web.Proxy ...@@ -319,7 +313,7 @@ namespace Titanium.Web.Proxy
args.WebSession.Request.ContentLength = args.WebSession.Request.RequestBody.Length; args.WebSession.Request.ContentLength = args.WebSession.Request.RequestBody.Length;
var newStream = args.WebSession.ServerConnection.Stream; var newStream = args.WebSession.ServerConnection.Stream;
await newStream.WriteAsync(args.WebSession.Request.RequestBody, 0, args.WebSession.Request.RequestBody.Length).ConfigureAwait(false); await newStream.WriteAsync(args.WebSession.Request.RequestBody, 0, args.WebSession.Request.RequestBody.Length);
} }
else else
{ {
...@@ -328,14 +322,14 @@ namespace Titanium.Web.Proxy ...@@ -328,14 +322,14 @@ namespace Titanium.Web.Proxy
//If its a post/put request, then read the client html body and send it to server //If its a post/put request, then read the client html body and send it to server
if (httpMethod.ToUpper() == "POST" || httpMethod.ToUpper() == "PUT") if (httpMethod.ToUpper() == "POST" || httpMethod.ToUpper() == "PUT")
{ {
await SendClientRequestBody(args).ConfigureAwait(false); await SendClientRequestBody(args);
} }
} }
} }
if (!args.WebSession.Request.ExpectationFailed) if (!args.WebSession.Request.ExpectationFailed)
{ {
await HandleHttpSessionResponse(args).ConfigureAwait(false); await HandleHttpSessionResponse(args);
} }
//if connection is closing exit //if connection is closing exit
...@@ -348,7 +342,7 @@ namespace Titanium.Web.Proxy ...@@ -348,7 +342,7 @@ namespace Titanium.Web.Proxy
await TcpConnectionManager.ReleaseClient(connection); await TcpConnectionManager.ReleaseClient(connection);
// read the next request // read the next request
httpCmd = await clientStreamReader.ReadLineAsync().ConfigureAwait(false); httpCmd = await clientStreamReader.ReadLineAsync();
} }
catch catch
...@@ -363,10 +357,10 @@ namespace Titanium.Web.Proxy ...@@ -363,10 +357,10 @@ namespace Titanium.Web.Proxy
private static async Task WriteConnectResponse(StreamWriter clientStreamWriter, Version httpVersion) private static async Task WriteConnectResponse(StreamWriter clientStreamWriter, Version httpVersion)
{ {
await clientStreamWriter.WriteLineAsync(string.Format("HTTP/{0}.{1} {2}", httpVersion.Major, httpVersion.Minor, "200 Connection established")).ConfigureAwait(false); await clientStreamWriter.WriteLineAsync(string.Format("HTTP/{0}.{1} {2}", httpVersion.Major, httpVersion.Minor, "200 Connection established"));
await clientStreamWriter.WriteLineAsync(string.Format("Timestamp: {0}", DateTime.Now)).ConfigureAwait(false); await clientStreamWriter.WriteLineAsync(string.Format("Timestamp: {0}", DateTime.Now));
await clientStreamWriter.WriteLineAsync().ConfigureAwait(false); await clientStreamWriter.WriteLineAsync();
await clientStreamWriter.FlushAsync().ConfigureAwait(false); await clientStreamWriter.FlushAsync();
} }
private static void PrepareRequestHeaders(List<HttpHeader> requestHeaders, HttpWebClient webRequest) private static void PrepareRequestHeaders(List<HttpHeader> requestHeaders, HttpWebClient webRequest)
...@@ -405,6 +399,7 @@ namespace Titanium.Web.Proxy ...@@ -405,6 +399,7 @@ namespace Titanium.Web.Proxy
headers.RemoveAll(x => x.Name.ToLower() == "proxy-connection"); headers.RemoveAll(x => x.Name.ToLower() == "proxy-connection");
} }
//This is called when the request is PUT/POST to read the body //This is called when the request is PUT/POST to read the body
private static async Task SendClientRequestBody(SessionEventArgs args) private static async Task SendClientRequestBody(SessionEventArgs args)
{ {
...@@ -415,7 +410,7 @@ namespace Titanium.Web.Proxy ...@@ -415,7 +410,7 @@ namespace Titanium.Web.Proxy
{ {
try try
{ {
await args.ProxyClient.ClientStreamReader.CopyBytesToStream(postStream, args.WebSession.Request.ContentLength).ConfigureAwait(false); await args.ProxyClient.ClientStreamReader.CopyBytesToStream(postStream, args.WebSession.Request.ContentLength);
} }
catch catch
{ {
...@@ -427,7 +422,7 @@ namespace Titanium.Web.Proxy ...@@ -427,7 +422,7 @@ namespace Titanium.Web.Proxy
{ {
try try
{ {
await args.ProxyClient.ClientStreamReader.CopyBytesToStreamChunked(postStream).ConfigureAwait(false); await args.ProxyClient.ClientStreamReader.CopyBytesToStreamChunked(postStream);
} }
catch catch
{ {
......
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text;
using Titanium.Web.Proxy.EventArguments; using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Compression; using Titanium.Web.Proxy.Compression;
using Titanium.Web.Proxy.Shared;
using System.Threading.Tasks; using System.Threading.Tasks;
using Titanium.Web.Proxy.Extensions;
namespace Titanium.Web.Proxy namespace Titanium.Web.Proxy
{ {
...@@ -19,7 +16,7 @@ namespace Titanium.Web.Proxy ...@@ -19,7 +16,7 @@ namespace Titanium.Web.Proxy
//Called asynchronously when a request was successfully and we received the response //Called asynchronously when a request was successfully and we received the response
public static async Task HandleHttpSessionResponse(SessionEventArgs args) public static async Task HandleHttpSessionResponse(SessionEventArgs args)
{ {
await args.WebSession.ReceiveResponse().ConfigureAwait(false); await args.WebSession.ReceiveResponse();
try try
{ {
...@@ -37,7 +34,7 @@ namespace Titanium.Web.Proxy ...@@ -37,7 +34,7 @@ namespace Titanium.Web.Proxy
handlerTasks[i] = ((Func<object, SessionEventArgs, Task>)invocationList[i])(null, args); handlerTasks[i] = ((Func<object, SessionEventArgs, Task>)invocationList[i])(null, args);
} }
await Task.WhenAll(handlerTasks).ConfigureAwait(false); await Task.WhenAll(handlerTasks);
} }
args.WebSession.Response.ResponseLocked = true; args.WebSession.Response.ResponseLocked = true;
...@@ -65,7 +62,7 @@ namespace Titanium.Web.Proxy ...@@ -65,7 +62,7 @@ namespace Titanium.Web.Proxy
if (contentEncoding != null) if (contentEncoding != null)
{ {
args.WebSession.Response.ResponseBody = await GetCompressedResponseBody(contentEncoding, args.WebSession.Response.ResponseBody).ConfigureAwait(false); args.WebSession.Response.ResponseBody = await GetCompressedResponseBody(contentEncoding, args.WebSession.Response.ResponseBody);
if (isChunked == false) if (isChunked == false)
args.WebSession.Response.ContentLength = args.WebSession.Response.ResponseBody.Length; args.WebSession.Response.ContentLength = args.WebSession.Response.ResponseBody.Length;
...@@ -73,8 +70,8 @@ namespace Titanium.Web.Proxy ...@@ -73,8 +70,8 @@ namespace Titanium.Web.Proxy
args.WebSession.Response.ContentLength = -1; args.WebSession.Response.ContentLength = -1;
} }
await WriteResponseHeaders(args.ProxyClient.ClientStreamWriter, args.WebSession.Response.ResponseHeaders).ConfigureAwait(false); await WriteResponseHeaders(args.ProxyClient.ClientStreamWriter, args.WebSession.Response.ResponseHeaders);
await WriteResponseBody(args.ProxyClient.ClientStream, args.WebSession.Response.ResponseBody, isChunked).ConfigureAwait(false); await args.ProxyClient.ClientStream.WriteResponseBody(args.WebSession.Response.ResponseBody, isChunked);
} }
else else
{ {
...@@ -82,7 +79,7 @@ namespace Titanium.Web.Proxy ...@@ -82,7 +79,7 @@ namespace Titanium.Web.Proxy
if (args.WebSession.Response.IsChunked || args.WebSession.Response.ContentLength > 0 || if (args.WebSession.Response.IsChunked || args.WebSession.Response.ContentLength > 0 ||
(args.WebSession.Response.HttpVersion.Major == 1 && args.WebSession.Response.HttpVersion.Minor == 0)) (args.WebSession.Response.HttpVersion.Major == 1 && args.WebSession.Response.HttpVersion.Minor == 0))
await WriteResponseBody(args.WebSession.ServerConnection.StreamReader, args.ProxyClient.ClientStream, args.WebSession.Response.IsChunked, args.WebSession.Response.ContentLength).ConfigureAwait(false); await args.WebSession.ServerConnection.StreamReader.WriteResponseBody(args.ProxyClient.ClientStream, args.WebSession.Response.IsChunked, args.WebSession.Response.ContentLength);
} }
await args.ProxyClient.ClientStream.FlushAsync(); await args.ProxyClient.ClientStream.FlushAsync();
...@@ -102,7 +99,7 @@ namespace Titanium.Web.Proxy ...@@ -102,7 +99,7 @@ namespace Titanium.Web.Proxy
{ {
var compressionFactory = new CompressionFactory(); var compressionFactory = new CompressionFactory();
var compressor = compressionFactory.Create(encodingType); var compressor = compressionFactory.Create(encodingType);
return await compressor.Compress(responseBodyStream).ConfigureAwait(false); return await compressor.Compress(responseBodyStream);
} }
...@@ -146,94 +143,6 @@ namespace Titanium.Web.Proxy ...@@ -146,94 +143,6 @@ namespace Titanium.Web.Proxy
headers.RemoveAll(x => x.Name.ToLower() == "proxy-connection"); headers.RemoveAll(x => x.Name.ToLower() == "proxy-connection");
} }
private static async Task WriteResponseBody(Stream clientStream, byte[] data, bool isChunked)
{
if (!isChunked)
{
await clientStream.WriteAsync(data, 0, data.Length).ConfigureAwait(false);
}
else
await WriteResponseBodyChunked(data, clientStream).ConfigureAwait(false);
}
private static async Task WriteResponseBody(CustomBinaryReader inStreamReader, Stream outStream, bool isChunked, long ContentLength)
{
if (!isChunked)
{
//http 1.0
if (ContentLength == -1)
ContentLength = long.MaxValue;
int bytesToRead = ProxyConstants.BUFFER_SIZE;
if (ContentLength < ProxyConstants.BUFFER_SIZE)
bytesToRead = (int)ContentLength;
var buffer = new byte[ProxyConstants.BUFFER_SIZE];
var bytesRead = 0;
var totalBytesRead = 0;
while ((bytesRead += await inStreamReader.BaseStream.ReadAsync(buffer, 0, bytesToRead).ConfigureAwait(false)) > 0)
{
await outStream.WriteAsync(buffer, 0, bytesRead).ConfigureAwait(false);
totalBytesRead += bytesRead;
if (totalBytesRead == ContentLength)
break;
bytesRead = 0;
var remainingBytes = (ContentLength - totalBytesRead);
bytesToRead = remainingBytes > (long)ProxyConstants.BUFFER_SIZE ? ProxyConstants.BUFFER_SIZE : (int)remainingBytes;
}
}
else
await WriteResponseBodyChunked(inStreamReader, outStream).ConfigureAwait(false);
}
//Send chunked response
private static async Task WriteResponseBodyChunked(CustomBinaryReader inStreamReader, Stream outStream)
{
while (true)
{
var chunkHead = await inStreamReader.ReadLineAsync().ConfigureAwait(false);
var chunkSize = int.Parse(chunkHead, NumberStyles.HexNumber);
if (chunkSize != 0)
{
var buffer = await inStreamReader.ReadBytesAsync(chunkSize).ConfigureAwait(false);
var chunkHeadBytes = Encoding.ASCII.GetBytes(chunkSize.ToString("x2"));
await outStream.WriteAsync(chunkHeadBytes, 0, chunkHeadBytes.Length).ConfigureAwait(false);
await outStream.WriteAsync(ProxyConstants.NewLineBytes, 0, ProxyConstants.NewLineBytes.Length).ConfigureAwait(false);
await outStream.WriteAsync(buffer, 0, chunkSize).ConfigureAwait(false);
await outStream.WriteAsync(ProxyConstants.NewLineBytes, 0, ProxyConstants.NewLineBytes.Length).ConfigureAwait(false);
await inStreamReader.ReadLineAsync().ConfigureAwait(false);
}
else
{
await inStreamReader.ReadLineAsync().ConfigureAwait(false);
await outStream.WriteAsync(ProxyConstants.ChunkEnd, 0, ProxyConstants.ChunkEnd.Length).ConfigureAwait(false);
break;
}
}
}
private static async Task WriteResponseBodyChunked(byte[] data, Stream outStream)
{
var chunkHead = Encoding.ASCII.GetBytes(data.Length.ToString("x2"));
await outStream.WriteAsync(chunkHead, 0, chunkHead.Length).ConfigureAwait(false);
await outStream.WriteAsync(ProxyConstants.NewLineBytes, 0, ProxyConstants.NewLineBytes.Length).ConfigureAwait(false);
await outStream.WriteAsync(data, 0, data.Length).ConfigureAwait(false);
await outStream.WriteAsync(ProxyConstants.NewLineBytes, 0, ProxyConstants.NewLineBytes.Length).ConfigureAwait(false);
await outStream.WriteAsync(ProxyConstants.ChunkEnd, 0, ProxyConstants.ChunkEnd.Length).ConfigureAwait(false);
}
private static void Dispose(TcpClient client, IDisposable clientStream, IDisposable clientStreamReader, private static void Dispose(TcpClient client, IDisposable clientStream, IDisposable clientStreamReader,
IDisposable clientStreamWriter, IDisposable args) IDisposable clientStreamWriter, IDisposable args)
......
...@@ -62,6 +62,7 @@ ...@@ -62,6 +62,7 @@
<Compile Include="Decompression\ZlibDecompression.cs" /> <Compile Include="Decompression\ZlibDecompression.cs" />
<Compile Include="EventArguments\CertificateSelectionEventArgs.cs" /> <Compile Include="EventArguments\CertificateSelectionEventArgs.cs" />
<Compile Include="EventArguments\CertificateValidationEventArgs.cs" /> <Compile Include="EventArguments\CertificateValidationEventArgs.cs" />
<Compile Include="Extensions\ByteArrayExtensions.cs" />
<Compile Include="Network\ProxyClient.cs" /> <Compile Include="Network\ProxyClient.cs" />
<Compile Include="Exceptions\BodyNotFoundException.cs" /> <Compile Include="Exceptions\BodyNotFoundException.cs" />
<Compile Include="Extensions\HttpWebResponseExtensions.cs" /> <Compile Include="Extensions\HttpWebResponseExtensions.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