Commit f59fb6a3 authored by justcoding121's avatar justcoding121

clean up;add comments

parent a4e2e3ed
......@@ -12,7 +12,7 @@ namespace Titanium.Web.Proxy.Compression
{
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();
......
......@@ -12,7 +12,7 @@ namespace Titanium.Web.Proxy.Compression
{
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();
......
......@@ -12,7 +12,7 @@ namespace Titanium.Web.Proxy.Compression
{
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();
......
......@@ -20,7 +20,7 @@ namespace Titanium.Web.Proxy.Decompression
int read;
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();
......
......@@ -17,7 +17,7 @@ namespace Titanium.Web.Proxy.Decompression
int read;
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();
}
......
......@@ -19,7 +19,7 @@ namespace Titanium.Web.Proxy.Decompression
int read;
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();
}
......
......@@ -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
if (WebSession.Request.IsChunked)
{
await this.ProxyClient.ClientStreamReader.CopyBytesToStreamChunked(requestBodyStream).ConfigureAwait(false);
await this.ProxyClient.ClientStreamReader.CopyBytesToStreamChunked(requestBodyStream);
}
else
{
......@@ -89,13 +89,13 @@ namespace Titanium.Web.Proxy.EventArguments
if (WebSession.Request.ContentLength > 0)
{
//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)
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
......@@ -118,21 +118,21 @@ namespace Titanium.Web.Proxy.EventArguments
//If chuncked the read chunk by chunk until we hit chunk end symbol
if (WebSession.Response.IsChunked)
{
await WebSession.ServerConnection.StreamReader.CopyBytesToStreamChunked(responseBodyStream).ConfigureAwait(false);
await WebSession.ServerConnection.StreamReader.CopyBytesToStreamChunked(responseBodyStream);
}
else
{
if (WebSession.Response.ContentLength > 0)
{
//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)
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
......@@ -149,7 +149,7 @@ namespace Titanium.Web.Proxy.EventArguments
if (WebSession.Request.RequestLocked)
throw new Exception("You cannot call this function after request is made to server.");
await ReadRequestBody().ConfigureAwait(false);
await ReadRequestBody();
return WebSession.Request.RequestBody;
}
/// <summary>
......@@ -162,7 +162,7 @@ namespace Titanium.Web.Proxy.EventArguments
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
return WebSession.Request.RequestBodyString ?? (WebSession.Request.RequestBodyString = WebSession.Request.Encoding.GetString(WebSession.Request.RequestBody));
......@@ -180,7 +180,7 @@ namespace Titanium.Web.Proxy.EventArguments
//syphon out the request body from client before setting the new body
if (!WebSession.Request.RequestBodyRead)
{
await ReadRequestBody().ConfigureAwait(false);
await ReadRequestBody();
}
WebSession.Request.RequestBody = body;
......@@ -203,7 +203,7 @@ namespace Titanium.Web.Proxy.EventArguments
//syphon out the request body from client before setting the new body
if (!WebSession.Request.RequestBodyRead)
{
await ReadRequestBody().ConfigureAwait(false);
await ReadRequestBody();
}
await SetRequestBody(WebSession.Request.Encoding.GetBytes(body));
......@@ -219,7 +219,7 @@ namespace Titanium.Web.Proxy.EventArguments
if (!WebSession.Request.RequestLocked)
throw new Exception("You cannot call this function before request is made to server.");
await ReadResponseBody().ConfigureAwait(false);
await ReadResponseBody();
return WebSession.Response.ResponseBody;
}
......@@ -232,7 +232,7 @@ namespace Titanium.Web.Proxy.EventArguments
if (!WebSession.Request.RequestLocked)
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));
}
......@@ -249,7 +249,7 @@ namespace Titanium.Web.Proxy.EventArguments
//syphon out the response body from server before setting the new body
if (WebSession.Response.ResponseBody == null)
{
await GetResponseBody().ConfigureAwait(false);
await GetResponseBody();
}
WebSession.Response.ResponseBody = body;
......@@ -273,12 +273,12 @@ namespace Titanium.Web.Proxy.EventArguments
//syphon out the response body from server before setting the new body
if (WebSession.Response.ResponseBody == null)
{
await GetResponseBody().ConfigureAwait(false);
await GetResponseBody();
}
var bodyBytes = WebSession.Response.Encoding.GetBytes(body);
await SetResponseBody(bodyBytes).ConfigureAwait(false);
await SetResponseBody(bodyBytes);
}
private async Task<byte[]> GetDecompressedResponseBody(string encodingType, byte[] responseBodyStream)
......@@ -286,7 +286,7 @@ namespace Titanium.Web.Proxy.EventArguments
var decompressionFactory = new DecompressionFactory();
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
var result = Encoding.Default.GetBytes(html);
await Ok(result).ConfigureAwait(false);
await Ok(result);
}
/// <summary>
......@@ -322,7 +322,7 @@ namespace Titanium.Web.Proxy.EventArguments
response.HttpVersion = WebSession.Request.HttpVersion;
response.ResponseBody = result;
await Respond(response).ConfigureAwait(false);
await Respond(response);
WebSession.Request.CancelRequest = true;
}
......@@ -335,7 +335,7 @@ namespace Titanium.Web.Proxy.EventArguments
response.ResponseHeaders.Add(new Models.HttpHeader("Location", url));
response.ResponseBody = Encoding.ASCII.GetBytes(string.Empty);
await Respond(response).ConfigureAwait(false);
await Respond(response);
WebSession.Request.CancelRequest = true;
}
......@@ -350,7 +350,7 @@ namespace Titanium.Web.Proxy.EventArguments
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
/// </summary>
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)
{
try
......
......@@ -6,6 +6,11 @@ namespace Titanium.Web.Proxy.Extensions
{
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)
{
try
......
......@@ -8,8 +8,15 @@ using Titanium.Web.Proxy.Shared;
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)
{
if (!string.IsNullOrEmpty(initialData))
......@@ -19,7 +26,13 @@ namespace Titanium.Web.Proxy.Extensions
}
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)
{
var totalbytesRead = 0;
......@@ -50,11 +63,18 @@ namespace Titanium.Web.Proxy.Extensions
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)
{
while (true)
{
var chuchkHead = await clientStreamReader.ReadLineAsync().ConfigureAwait(false);
var chuchkHead = await clientStreamReader.ReadLineAsync();
var chunkSize = int.Parse(chuchkHead, NumberStyles.HexNumber);
if (chunkSize != 0)
......@@ -62,14 +82,127 @@ namespace Titanium.Web.Proxy.Extensions
var buffer = await clientStreamReader.ReadBytesAsync(chunkSize);
await stream.WriteAsync(buffer, 0, buffer.Length);
//chunk trail
await clientStreamReader.ReadLineAsync().ConfigureAwait(false);
await clientStreamReader.ReadLineAsync();
}
else
{
await clientStreamReader.ReadLineAsync();
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 clientStreamReader.ReadLineAsync().ConfigureAwait(false);
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
{
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)
{
// This is how you can determine whether a socket is still connected.
......
......@@ -248,7 +248,7 @@ namespace Titanium.Web.Proxy.Helpers
}
finally { semaphoreLock.Release(); }
await Task.Delay(1000 * 60 * 3).ConfigureAwait(false);
await Task.Delay(1000 * 60 * 3);
}
}
......
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Security;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using Titanium.Web.Proxy.Network;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Shared;
namespace Titanium.Web.Proxy.Helpers
{
/// <summary>
/// A custom binary reader that would allo us to read string line by line
/// using the specified encoding
......@@ -18,10 +17,11 @@ namespace Titanium.Web.Proxy.Helpers
internal class CustomBinaryReader : IDisposable
{
private Stream stream;
private Encoding encoding;
internal CustomBinaryReader(Stream stream)
{
this.stream = stream;
this.encoding = Encoding.UTF8;
}
internal Stream BaseStream => stream;
......@@ -32,32 +32,34 @@ namespace Titanium.Web.Proxy.Helpers
/// <returns></returns>
internal async Task<string> ReadLineAsync()
{
var readBuffer = new StringBuilder();
try
using (var readBuffer = new MemoryStream())
{
var lastChar = default(char);
var buffer = new byte[1];
while ((await this.stream.ReadAsync(buffer, 0, 1)) > 0)
try
{
if (lastChar == '\r' && buffer[0] == '\n')
{
return await Task.FromResult(readBuffer.Remove(readBuffer.Length - 1, 1).ToString());
}
if (buffer[0] == '\0')
var lastChar = default(char);
var buffer = new byte[1];
while ((await this.stream.ReadAsync(buffer, 0, 1)) > 0)
{
return await Task.FromResult(readBuffer.ToString());
if (lastChar == '\r' && buffer[0] == '\n')
{
var result = readBuffer.ToArray();
return encoding.GetString(result.SubArray(0, result.Length - 1));
}
if (buffer[0] == '\0')
{
return encoding.GetString(readBuffer.ToArray());
}
await readBuffer.WriteAsync(buffer,0,1);
lastChar = (char)buffer[0];
}
readBuffer.Append((char)buffer[0]);
lastChar = (char)buffer[0];
}
return await Task.FromResult(readBuffer.ToString());
}
catch (IOException)
{
return await Task.FromResult(readBuffer.ToString());
return encoding.GetString(readBuffer.ToArray());
}
catch (IOException)
{
return encoding.GetString(readBuffer.ToArray());
}
}
}
......@@ -92,7 +94,7 @@ namespace Titanium.Web.Proxy.Helpers
{
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;
if (totalBytesRead == totalBytesToRead)
......
......@@ -72,7 +72,7 @@ namespace Titanium.Web.Proxy.Helpers
var receiveRelay = tunnelStream.CopyToAsync(string.Empty, clientStream);
await Task.WhenAll(sendRelay, receiveRelay).ConfigureAwait(false);
await Task.WhenAll(sendRelay, receiveRelay);
}
catch
{
......
......@@ -76,13 +76,13 @@ namespace Titanium.Web.Proxy.Http
&& responseStatusDescription.ToLower().Equals("continue"))
{
this.Request.Is100Continue = true;
await ServerConnection.StreamReader.ReadLineAsync().ConfigureAwait(false);
await ServerConnection.StreamReader.ReadLineAsync();
}
else if (responseStatusCode.Equals("417")
&& responseStatusDescription.ToLower().Equals("expectation failed"))
{
this.Request.ExpectationFailed = true;
await ServerConnection.StreamReader.ReadLineAsync().ConfigureAwait(false);
await ServerConnection.StreamReader.ReadLineAsync();
}
}
}
......@@ -96,7 +96,7 @@ namespace Titanium.Web.Proxy.Http
if (string.IsNullOrEmpty(httpResult[0]))
{
await ServerConnection.StreamReader.ReadLineAsync().ConfigureAwait(false);
await ServerConnection.StreamReader.ReadLineAsync();
}
var httpVersion = httpResult[0].Trim().ToLower();
......@@ -116,7 +116,7 @@ namespace Titanium.Web.Proxy.Http
{
this.Response.Is100Continue = true;
this.Response.ResponseStatusCode = null;
await ServerConnection.StreamReader.ReadLineAsync().ConfigureAwait(false);
await ServerConnection.StreamReader.ReadLineAsync();
await ReceiveResponse();
return;
}
......@@ -125,12 +125,12 @@ namespace Titanium.Web.Proxy.Http
{
this.Response.ExpectationFailed = true;
this.Response.ResponseStatusCode = null;
await ServerConnection.StreamReader.ReadLineAsync().ConfigureAwait(false);
await ServerConnection.StreamReader.ReadLineAsync();
await ReceiveResponse();
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)
{
......
......@@ -79,7 +79,7 @@ namespace Titanium.Web.Proxy.Network
}
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)
{
......@@ -111,22 +111,22 @@ namespace Titanium.Web.Proxy.Network
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("Host: {0}:{1}", hostname, port)).ConfigureAwait(false);
await writer.WriteLineAsync("Connection: Keep-Alive").ConfigureAwait(false);
await writer.WriteLineAsync().ConfigureAwait(false);
await writer.FlushAsync().ConfigureAwait(false);
await writer.WriteLineAsync(string.Format("CONNECT {0}:{1} {2}", hostname, port, version));
await writer.WriteLineAsync(string.Format("Host: {0}:{1}", hostname, port));
await writer.WriteLineAsync("Connection: Keep-Alive");
await writer.WriteLineAsync();
await writer.FlushAsync();
writer.Close();
}
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"))
throw new Exception("Upstream proxy failed to create a secure tunnel");
await reader.ReadAllLinesAsync().ConfigureAwait(false);
await reader.ReadAllLinesAsync();
}
}
else
......@@ -139,7 +139,7 @@ namespace Titanium.Web.Proxy.Network
{
sslStream = new SslStream(stream, true, new RemoteCertificateValidationCallback(ProxyServer.ValidateServerCertificate),
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;
}
catch
......@@ -224,7 +224,7 @@ namespace Titanium.Web.Proxy.Network
}
finally { connectionAccessLock.Release(); }
await Task.Delay(1000 * 60 * 3).ConfigureAwait(false);
await Task.Delay(1000 * 60);
}
}
......
......@@ -32,7 +32,7 @@ namespace Titanium.Web.Proxy
try
{
//read the first line HTTP command
var httpCmd = await clientStreamReader.ReadLineAsync().ConfigureAwait(false);
var httpCmd = await clientStreamReader.ReadLineAsync();
if (string.IsNullOrEmpty(httpCmd))
{
......@@ -68,25 +68,23 @@ namespace Titanium.Web.Proxy
if (httpVerb.ToUpper() == "CONNECT" && !excluded && httpRemoteUri.Port != 80)
{
httpRemoteUri = new Uri("https://" + httpCmdSplit[1]);
await clientStreamReader.ReadAllLinesAsync().ConfigureAwait(false);
await WriteConnectResponse(clientStreamWriter, version).ConfigureAwait(false);
await clientStreamReader.ReadAllLinesAsync();
await WriteConnectResponse(clientStreamWriter, version);
SslStream sslStream = null;
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);
sslStream = new SslStream(clientStream, true);
var certificate = await CertManager.CreateCertificate(httpRemoteUri.Host, false);
//Successfully managed to authenticate the client using the fake certificate
await sslStream.AuthenticateAsServerAsync(certificate, false,
ProxyConstants.SupportedSslProtocols, false).ConfigureAwait(false);
ProxyConstants.SupportedSslProtocols, false);
//HTTPS server created - we can now decrypt the client's traffic
clientStream = sslStream;
......@@ -104,26 +102,24 @@ namespace Titanium.Web.Proxy
return;
}
httpCmd = await clientStreamReader.ReadLineAsync().ConfigureAwait(false);
httpCmd = await clientStreamReader.ReadLineAsync();
}
else if (httpVerb.ToUpper() == "CONNECT")
{
await clientStreamReader.ReadAllLinesAsync().ConfigureAwait(false);
await WriteConnectResponse(clientStreamWriter, version).ConfigureAwait(false);
await clientStreamReader.ReadAllLinesAsync();
await WriteConnectResponse(clientStreamWriter, version);
await TcpHelper.SendRaw(clientStream, null, null, httpRemoteUri.Host, httpRemoteUri.Port,
false).ConfigureAwait(false);
false);
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null);
return;
}
//Now create the request
await HandleHttpSessionRequest(client, httpCmd, clientStream, clientStreamReader, clientStreamWriter,
httpRemoteUri.Scheme == Uri.UriSchemeHttps ? true : false).ConfigureAwait(false);
httpRemoteUri.Scheme == Uri.UriSchemeHttps ? true : false);
}
catch
{
......@@ -155,7 +151,7 @@ namespace Titanium.Web.Proxy
{
//Successfully managed to authenticate the client using the fake certificate
await sslStream.AuthenticateAsServerAsync(certificate, false,
SslProtocols.Tls, false).ConfigureAwait(false);
SslProtocols.Tls, false);
clientStreamReader = new CustomBinaryReader(sslStream);
clientStreamWriter = new StreamWriter(sslStream);
......@@ -177,11 +173,11 @@ namespace Titanium.Web.Proxy
clientStreamReader = new CustomBinaryReader(clientStream);
}
var httpCmd = await clientStreamReader.ReadLineAsync().ConfigureAwait(false);
var httpCmd = await clientStreamReader.ReadLineAsync();
//Now create the request
await HandleHttpSessionRequest(tcpClient, httpCmd, clientStream, clientStreamReader, clientStreamWriter,
true).ConfigureAwait(false);
true);
}
private static async Task HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream,
......@@ -234,7 +230,6 @@ namespace Titanium.Web.Proxy
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null);
break;
}
#endif
args.WebSession.Request.RequestUri = httpRemoteUri;
......@@ -244,7 +239,6 @@ namespace Titanium.Web.Proxy
args.ProxyClient.ClientStreamReader = clientStreamReader;
args.ProxyClient.ClientStreamWriter = clientStreamWriter;
PrepareRequestHeaders(args.WebSession.Request.RequestHeaders, args.WebSession);
args.WebSession.Request.Host = args.WebSession.Request.RequestUri.Authority;
......@@ -259,19 +253,19 @@ namespace Titanium.Web.Proxy
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)
{
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);
return;
}
//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;
......@@ -285,7 +279,7 @@ namespace Titanium.Web.Proxy
if (args.WebSession.Request.ExpectContinue)
{
args.WebSession.SetConnection(connection);
await args.WebSession.SendRequest().ConfigureAwait(false);
await args.WebSession.SendRequest();
}
if (Enable100ContinueBehaviour)
......@@ -305,7 +299,7 @@ namespace Titanium.Web.Proxy
if (!args.WebSession.Request.ExpectContinue)
{
args.WebSession.SetConnection(connection);
await args.WebSession.SendRequest().ConfigureAwait(false);
await args.WebSession.SendRequest();
}
//If request was modified by user
......@@ -319,7 +313,7 @@ namespace Titanium.Web.Proxy
args.WebSession.Request.ContentLength = args.WebSession.Request.RequestBody.Length;
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
{
......@@ -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 (httpMethod.ToUpper() == "POST" || httpMethod.ToUpper() == "PUT")
{
await SendClientRequestBody(args).ConfigureAwait(false);
await SendClientRequestBody(args);
}
}
}
if (!args.WebSession.Request.ExpectationFailed)
{
await HandleHttpSessionResponse(args).ConfigureAwait(false);
await HandleHttpSessionResponse(args);
}
//if connection is closing exit
......@@ -348,7 +342,7 @@ namespace Titanium.Web.Proxy
await TcpConnectionManager.ReleaseClient(connection);
// read the next request
httpCmd = await clientStreamReader.ReadLineAsync().ConfigureAwait(false);
httpCmd = await clientStreamReader.ReadLineAsync();
}
catch
......@@ -363,10 +357,10 @@ namespace Titanium.Web.Proxy
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("Timestamp: {0}", DateTime.Now)).ConfigureAwait(false);
await clientStreamWriter.WriteLineAsync().ConfigureAwait(false);
await clientStreamWriter.FlushAsync().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));
await clientStreamWriter.WriteLineAsync();
await clientStreamWriter.FlushAsync();
}
private static void PrepareRequestHeaders(List<HttpHeader> requestHeaders, HttpWebClient webRequest)
......@@ -405,6 +399,7 @@ namespace Titanium.Web.Proxy
headers.RemoveAll(x => x.Name.ToLower() == "proxy-connection");
}
//This is called when the request is PUT/POST to read the body
private static async Task SendClientRequestBody(SessionEventArgs args)
{
......@@ -415,7 +410,7 @@ namespace Titanium.Web.Proxy
{
try
{
await args.ProxyClient.ClientStreamReader.CopyBytesToStream(postStream, args.WebSession.Request.ContentLength).ConfigureAwait(false);
await args.ProxyClient.ClientStreamReader.CopyBytesToStream(postStream, args.WebSession.Request.ContentLength);
}
catch
{
......@@ -427,7 +422,7 @@ namespace Titanium.Web.Proxy
{
try
{
await args.ProxyClient.ClientStreamReader.CopyBytesToStreamChunked(postStream).ConfigureAwait(false);
await args.ProxyClient.ClientStreamReader.CopyBytesToStreamChunked(postStream);
}
catch
{
......
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Compression;
using Titanium.Web.Proxy.Shared;
using System.Threading.Tasks;
using Titanium.Web.Proxy.Extensions;
namespace Titanium.Web.Proxy
{
......@@ -19,7 +16,7 @@ namespace Titanium.Web.Proxy
//Called asynchronously when a request was successfully and we received the response
public static async Task HandleHttpSessionResponse(SessionEventArgs args)
{
await args.WebSession.ReceiveResponse().ConfigureAwait(false);
await args.WebSession.ReceiveResponse();
try
{
......@@ -37,7 +34,7 @@ namespace Titanium.Web.Proxy
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;
......@@ -65,7 +62,7 @@ namespace Titanium.Web.Proxy
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)
args.WebSession.Response.ContentLength = args.WebSession.Response.ResponseBody.Length;
......@@ -73,8 +70,8 @@ namespace Titanium.Web.Proxy
args.WebSession.Response.ContentLength = -1;
}
await WriteResponseHeaders(args.ProxyClient.ClientStreamWriter, args.WebSession.Response.ResponseHeaders).ConfigureAwait(false);
await WriteResponseBody(args.ProxyClient.ClientStream, args.WebSession.Response.ResponseBody, isChunked).ConfigureAwait(false);
await WriteResponseHeaders(args.ProxyClient.ClientStreamWriter, args.WebSession.Response.ResponseHeaders);
await args.ProxyClient.ClientStream.WriteResponseBody(args.WebSession.Response.ResponseBody, isChunked);
}
else
{
......@@ -82,7 +79,7 @@ namespace Titanium.Web.Proxy
if (args.WebSession.Response.IsChunked || args.WebSession.Response.ContentLength > 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();
......@@ -102,7 +99,7 @@ namespace Titanium.Web.Proxy
{
var compressionFactory = new CompressionFactory();
var compressor = compressionFactory.Create(encodingType);
return await compressor.Compress(responseBodyStream).ConfigureAwait(false);
return await compressor.Compress(responseBodyStream);
}
......@@ -145,95 +142,7 @@ namespace Titanium.Web.Proxy
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,
IDisposable clientStreamWriter, IDisposable args)
......
......@@ -62,6 +62,7 @@
<Compile Include="Decompression\ZlibDecompression.cs" />
<Compile Include="EventArguments\CertificateSelectionEventArgs.cs" />
<Compile Include="EventArguments\CertificateValidationEventArgs.cs" />
<Compile Include="Extensions\ByteArrayExtensions.cs" />
<Compile Include="Network\ProxyClient.cs" />
<Compile Include="Exceptions\BodyNotFoundException.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