Commit 4dd7f91f authored by Honfika's avatar Honfika

cancellation tokens

parent 912826ee
......@@ -349,7 +349,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// Gets the request body as bytes
/// </summary>
/// <returns></returns>
public async Task<byte[]> GetRequestBody(CancellationToken cancellationToken = default (CancellationToken))
public async Task<byte[]> GetRequestBody(CancellationToken cancellationToken = default)
{
if (!WebSession.Request.IsBodyRead)
{
......@@ -363,7 +363,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// Gets the request body as string
/// </summary>
/// <returns></returns>
public async Task<string> GetRequestBodyAsString(CancellationToken cancellationToken = default(CancellationToken))
public async Task<string> GetRequestBodyAsString(CancellationToken cancellationToken = default)
{
if (!WebSession.Request.IsBodyRead)
{
......@@ -406,7 +406,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// Gets the response body as byte array
/// </summary>
/// <returns></returns>
public async Task<byte[]> GetResponseBody(CancellationToken cancellationToken = default(CancellationToken))
public async Task<byte[]> GetResponseBody(CancellationToken cancellationToken = default)
{
if (!WebSession.Response.IsBodyRead)
{
......@@ -420,7 +420,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// Gets the response body as string
/// </summary>
/// <returns></returns>
public async Task<string> GetResponseBodyAsString(CancellationToken cancellationToken = default(CancellationToken))
public async Task<string> GetResponseBodyAsString(CancellationToken cancellationToken = default)
{
if (!WebSession.Response.IsBodyRead)
{
......
......@@ -14,7 +14,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// A proxy session ends when client terminates connection to proxy
/// or when server terminates connection from proxy
/// </summary>
public class SessionEventArgsBase : EventArgs, IDisposable
public abstract class SessionEventArgsBase : EventArgs, IDisposable
{
/// <summary>
/// Size of Buffers used by this object
......
using System.Threading;
using System;
using System.Threading;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Models;
......@@ -6,6 +7,8 @@ namespace Titanium.Web.Proxy.EventArguments
{
public class TunnelConnectSessionEventArgs : SessionEventArgsBase
{
private bool? isHttpsConnect;
internal TunnelConnectSessionEventArgs(int bufferSize, ProxyEndPoint endPoint, ConnectRequest connectRequest,
CancellationTokenSource cancellationTokenSource, ExceptionHandler exceptionFunc)
: base(bufferSize, endPoint, cancellationTokenSource, connectRequest, exceptionFunc)
......@@ -19,6 +22,10 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
public bool DenyConnect { get; set; }
public bool IsHttpsConnect { get; internal set; }
public bool IsHttpsConnect
{
get => isHttpsConnect ?? throw new Exception("The value of this property is known in the BeforeTunnectConnectResponse event");
internal set => isHttpsConnect = value;
}
}
}
......@@ -30,6 +30,8 @@ namespace Titanium.Web.Proxy
private async Task HandleClient(ExplicitProxyEndPoint endPoint, TcpClient tcpClient)
{
var cancellationTokenSource = new CancellationTokenSource();
var cancellationToken = cancellationTokenSource.Token;
var clientStream = new CustomBufferedStream(tcpClient.GetStream(), BufferSize);
var clientStreamReader = new CustomBinaryReader(clientStream, BufferSize);
......@@ -44,7 +46,7 @@ namespace Titanium.Web.Proxy
if (await HttpHelper.IsConnectMethod(clientStream) == 1)
{
//read the first line HTTP command
string httpCmd = await clientStreamReader.ReadLineAsync(cancellationTokenSource.Token);
string httpCmd = await clientStreamReader.ReadLineAsync(cancellationToken);
if (string.IsNullOrEmpty(httpCmd))
{
return;
......@@ -62,7 +64,7 @@ namespace Titanium.Web.Proxy
HttpVersion = version
};
await HeaderParser.ReadHeaders(clientStreamReader, connectRequest.Headers, cancellationTokenSource.Token);
await HeaderParser.ReadHeaders(clientStreamReader, connectRequest.Headers, cancellationToken);
var connectArgs = new TunnelConnectSessionEventArgs(BufferSize, endPoint, connectRequest,
cancellationTokenSource, ExceptionFunc);
......@@ -87,7 +89,7 @@ namespace Titanium.Web.Proxy
}
//send the response
await clientStreamWriter.WriteResponseAsync(connectArgs.WebSession.Response);
await clientStreamWriter.WriteResponseAsync(connectArgs.WebSession.Response, cancellationToken: cancellationToken);
return;
}
......@@ -96,7 +98,7 @@ namespace Titanium.Web.Proxy
await endPoint.InvokeBeforeTunnectConnectResponse(this, connectArgs, ExceptionFunc);
//send the response
await clientStreamWriter.WriteResponseAsync(connectArgs.WebSession.Response);
await clientStreamWriter.WriteResponseAsync(connectArgs.WebSession.Response, cancellationToken: cancellationToken);
return;
}
......@@ -108,9 +110,9 @@ namespace Titanium.Web.Proxy
response.Headers.FixProxyHeaders();
connectArgs.WebSession.Response = response;
await clientStreamWriter.WriteResponseAsync(response);
await clientStreamWriter.WriteResponseAsync(response, cancellationToken: cancellationToken);
var clientHelloInfo = await SslTools.PeekClientHello(clientStream, cancellationTokenSource.Token);
var clientHelloInfo = await SslTools.PeekClientHello(clientStream, cancellationToken);
bool isClientHello = clientHelloInfo != null;
if (isClientHello)
......@@ -144,13 +146,13 @@ namespace Titanium.Web.Proxy
}
// client connection is always HTTP 1.x, todo
options.ApplicationProtocols = SslExtensions.Http11ProtocolAsList;
//options.ApplicationProtocols = SslExtensions.Http11ProtocolAsList;
options.ServerCertificate = certificate;
options.ClientCertificateRequired = false;
options.EnabledSslProtocols = SupportedSslProtocols;
options.CertificateRevocationCheckMode = X509RevocationMode.NoCheck;
await sslStream.AuthenticateAsServerAsync(options, cancellationTokenSource.Token);
await sslStream.AuthenticateAsServerAsync(options, cancellationToken);
//HTTPS server created - we can now decrypt the client's traffic
clientStream = new CustomBufferedStream(sslStream, BufferSize);
......@@ -182,7 +184,7 @@ namespace Titanium.Web.Proxy
if (!decryptSsl || !isClientHello)
{
//create new connection
using (var connection = await GetServerConnection(connectArgs, true, cancellationTokenSource.Token))
using (var connection = await GetServerConnection(connectArgs, true, cancellationToken))
{
if (isClientHello)
{
......@@ -195,8 +197,8 @@ namespace Titanium.Web.Proxy
try
{
// clientStream.Available sbould be at most BufferSize because it is using the same buffer size
await clientStream.ReadAsync(data, 0, available, cancellationTokenSource.Token);
await connection.StreamWriter.WriteAsync(data, 0, available, true, cancellationTokenSource.Token);
await clientStream.ReadAsync(data, 0, available, cancellationToken);
await connection.StreamWriter.WriteAsync(data, 0, available, true, cancellationToken);
}
finally
{
......@@ -204,7 +206,7 @@ namespace Titanium.Web.Proxy
}
}
var serverHelloInfo = await SslTools.PeekServerHello(connection.Stream, cancellationTokenSource.Token);
var serverHelloInfo = await SslTools.PeekServerHello(connection.Stream, cancellationToken);
((ConnectResponse)connectArgs.WebSession.Response).ServerHelloInfo = serverHelloInfo;
}
......
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Titanium.Web.Proxy.Http;
......@@ -16,11 +17,14 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary>
/// <param name="response"></param>
/// <param name="flush"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task WriteResponseAsync(Response response, bool flush = true)
public async Task WriteResponseAsync(Response response, bool flush = true,
CancellationToken cancellationToken = default)
{
await WriteResponseStatusAsync(response.HttpVersion, response.StatusCode, response.StatusDescription);
await WriteAsync(response, flush);
await WriteResponseStatusAsync(response.HttpVersion, response.StatusCode, response.StatusDescription,
cancellationToken);
await WriteAsync(response, flush, cancellationToken);
}
/// <summary>
......@@ -29,10 +33,11 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="version"></param>
/// <param name="code"></param>
/// <param name="description"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public Task WriteResponseStatusAsync(Version version, int code, string description)
public Task WriteResponseStatusAsync(Version version, int code, string description, CancellationToken cancellationToken)
{
return WriteLineAsync(Response.CreateResponseLine(version, code, description));
return WriteLineAsync(Response.CreateResponseLine(version, code, description), cancellationToken);
}
}
}
......@@ -29,12 +29,12 @@ namespace Titanium.Web.Proxy.Helpers
public int BufferSize { get; }
public Task WriteLineAsync(CancellationToken cancellationToken = default(CancellationToken))
public Task WriteLineAsync(CancellationToken cancellationToken = default)
{
return WriteAsync(newLine, cancellationToken: cancellationToken);
}
public Task WriteAsync(string value, CancellationToken cancellationToken = default (CancellationToken))
public Task WriteAsync(string value, CancellationToken cancellationToken = default)
{
return WriteAsyncInternal(value, false, cancellationToken);
}
......@@ -81,7 +81,7 @@ namespace Titanium.Web.Proxy.Helpers
}
}
public Task WriteLineAsync(string value, CancellationToken cancellationToken = default (CancellationToken))
public Task WriteLineAsync(string value, CancellationToken cancellationToken = default)
{
return WriteAsyncInternal(value, true, cancellationToken);
}
......@@ -93,7 +93,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="flush"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task WriteHeadersAsync(HeaderCollection headers, bool flush = true, CancellationToken cancellationToken = default(CancellationToken))
public async Task WriteHeadersAsync(HeaderCollection headers, bool flush = true, CancellationToken cancellationToken = default)
{
foreach (var header in headers)
{
......@@ -107,7 +107,7 @@ namespace Titanium.Web.Proxy.Helpers
}
}
public async Task WriteAsync(byte[] data, bool flush = false, CancellationToken cancellationToken = default(CancellationToken))
public async Task WriteAsync(byte[] data, bool flush = false, CancellationToken cancellationToken = default)
{
await WriteAsync(data, 0, data.Length, cancellationToken);
if (flush)
......@@ -116,7 +116,7 @@ namespace Titanium.Web.Proxy.Helpers
}
}
public async Task WriteAsync(byte[] data, int offset, int count, bool flush, CancellationToken cancellationToken = default (CancellationToken))
public async Task WriteAsync(byte[] data, int offset, int count, bool flush, CancellationToken cancellationToken = default)
{
await WriteAsync(data, offset, count, cancellationToken);
if (flush)
......@@ -271,7 +271,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="flush"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
protected async Task WriteAsync(RequestResponseBase requestResponse, bool flush = true, CancellationToken cancellationToken = default (CancellationToken))
protected async Task WriteAsync(RequestResponseBase requestResponse, bool flush = true, CancellationToken cancellationToken = default)
{
var body = requestResponse.CompressBodyAndUpdateContentLength();
await WriteHeadersAsync(requestResponse.Headers, flush, cancellationToken);
......
......@@ -104,11 +104,6 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
public bool ExpectationFailed { get; internal set; }
/// <summary>
/// Gets the resposne status.
/// </summary>
public string Status => CreateResponseLine(HttpVersion, StatusCode, StatusDescription);
/// <summary>
/// Gets the header text.
/// </summary>
......@@ -117,7 +112,7 @@ namespace Titanium.Web.Proxy.Http
get
{
var sb = new StringBuilder();
sb.AppendLine(Status);
sb.AppendLine(CreateResponseLine(HttpVersion, StatusCode, StatusDescription));
foreach (var header in Headers)
{
sb.AppendLine(header.ToString());
......
......@@ -47,6 +47,7 @@ namespace Titanium.Web.Proxy
CancellationTokenSource cancellationTokenSource, string httpsConnectHostname, ConnectRequest connectRequest,
bool isTransparentEndPoint = false)
{
var cancellationToken = cancellationTokenSource.Token;
TcpConnection connection = null;
try
......@@ -56,22 +57,29 @@ namespace Titanium.Web.Proxy
while (true)
{
// read the request line
string httpCmd = await clientStreamReader.ReadLineAsync(cancellationTokenSource.Token);
string httpCmd = await clientStreamReader.ReadLineAsync(cancellationToken);
if (httpCmd == "PRI * HTTP/2.0")
{
// HTTP/2 Connection Preface
string line = await clientStreamReader.ReadLineAsync(cancellationTokenSource.Token);
string line = await clientStreamReader.ReadLineAsync(cancellationToken);
if (line != string.Empty) throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received");
line = await clientStreamReader.ReadLineAsync(cancellationTokenSource.Token);
line = await clientStreamReader.ReadLineAsync(cancellationToken);
if (line != "SM") throw new Exception($"HTTP/2 Protocol violation. 'SM' expected, '{line}' received");
line = await clientStreamReader.ReadLineAsync(cancellationTokenSource.Token);
line = await clientStreamReader.ReadLineAsync(cancellationToken);
if (line != string.Empty) throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received");
// todo
var buffer = new byte[1024];
await clientStreamReader.ReadBytesAsync(buffer, 0, 3, cancellationTokenSource.Token);
await clientStreamReader.ReadBytesAsync(buffer, 0, 3, cancellationToken);
int length = (buffer[0] << 16) + (buffer[1] << 8) + buffer[2];
await clientStreamReader.ReadBytesAsync(buffer, 0, length, cancellationToken);
byte type = buffer[0];
byte flags = buffer[1];
}
if (string.IsNullOrEmpty(httpCmd))
......@@ -93,7 +101,7 @@ namespace Titanium.Web.Proxy
out var version);
//Read the request headers in to unique and non-unique header collections
await HeaderParser.ReadHeaders(clientStreamReader, args.WebSession.Request.Headers, cancellationTokenSource.Token);
await HeaderParser.ReadHeaders(clientStreamReader, args.WebSession.Request.Headers, cancellationToken);
Uri httpRemoteUri;
if (uriSchemeRegex.IsMatch(httpUrl))
......@@ -145,7 +153,7 @@ namespace Titanium.Web.Proxy
await InvokeBeforeResponse(args);
//send the response
await clientStreamWriter.WriteResponseAsync(args.WebSession.Response);
await clientStreamWriter.WriteResponseAsync(args.WebSession.Response, cancellationToken: cancellationToken);
return;
}
......@@ -160,7 +168,7 @@ namespace Titanium.Web.Proxy
//so that we can send it after authentication in WinAuthHandler.cs
if (isWindowsAuthenticationEnabledAndSupported && request.HasBody)
{
await args.GetRequestBody();
await args.GetRequestBody(cancellationToken);
}
request.OriginalHasBody = request.HasBody;
......@@ -173,7 +181,7 @@ namespace Titanium.Web.Proxy
if (request.CancelRequest)
{
//syphon out the request body from client before setting the new body
await args.SyphonOutBodyAsync(true, cancellationTokenSource.Token);
await args.SyphonOutBodyAsync(true, cancellationToken);
await HandleHttpSessionResponse(args);
......@@ -198,16 +206,16 @@ namespace Titanium.Web.Proxy
if (connection == null)
{
connection = await GetServerConnection(args, false, cancellationTokenSource.Token);
connection = await GetServerConnection(args, false, cancellationToken);
}
//if upgrading to websocket then relay the requet without reading the contents
if (request.UpgradeToWebSocket)
{
//prepare the prefix content
await connection.StreamWriter.WriteLineAsync(httpCmd);
await connection.StreamWriter.WriteHeadersAsync(request.Headers);
string httpStatus = await connection.StreamReader.ReadLineAsync(cancellationTokenSource.Token);
await connection.StreamWriter.WriteLineAsync(httpCmd, cancellationToken);
await connection.StreamWriter.WriteHeadersAsync(request.Headers, cancellationToken: cancellationToken);
string httpStatus = await connection.StreamReader.ReadLineAsync(cancellationToken);
Response.ParseResponseLine(httpStatus, out var responseVersion,
out int responseStatusCode,
......@@ -216,11 +224,11 @@ namespace Titanium.Web.Proxy
response.StatusCode = responseStatusCode;
response.StatusDescription = responseStatusDescription;
await HeaderParser.ReadHeaders(connection.StreamReader, response.Headers, cancellationTokenSource.Token);
await HeaderParser.ReadHeaders(connection.StreamReader, response.Headers, cancellationToken);
if (!args.IsTransparent)
{
await clientStreamWriter.WriteResponseAsync(response);
await clientStreamWriter.WriteResponseAsync(response, cancellationToken: cancellationToken);
}
//If user requested call back then do it
......@@ -311,13 +319,13 @@ namespace Titanium.Web.Proxy
if (request.Is100Continue)
{
await clientStreamWriter.WriteResponseStatusAsync(args.WebSession.Response.HttpVersion,
(int)HttpStatusCode.Continue, "Continue");
(int)HttpStatusCode.Continue, "Continue", cancellationToken);
await clientStreamWriter.WriteLineAsync(cancellationToken);
}
else if (request.ExpectationFailed)
{
await clientStreamWriter.WriteResponseStatusAsync(args.WebSession.Response.HttpVersion,
(int)HttpStatusCode.ExpectationFailed, "Expectation Failed");
(int)HttpStatusCode.ExpectationFailed, "Expectation Failed", cancellationToken);
await clientStreamWriter.WriteLineAsync(cancellationToken);
}
}
......
......@@ -57,7 +57,7 @@ namespace Titanium.Web.Proxy
if (response.TerminateResponse || response.Locked)
{
await clientStreamWriter.WriteResponseAsync(response);
await clientStreamWriter.WriteResponseAsync(response, cancellationToken: cancellationToken);
if (!response.TerminateResponse)
{
......@@ -89,13 +89,13 @@ namespace Titanium.Web.Proxy
if (response.Is100Continue)
{
await clientStreamWriter.WriteResponseStatusAsync(response.HttpVersion,
(int)HttpStatusCode.Continue, "Continue");
(int)HttpStatusCode.Continue, "Continue", cancellationToken);
await clientStreamWriter.WriteLineAsync(cancellationToken);
}
else if (response.ExpectationFailed)
{
await clientStreamWriter.WriteResponseStatusAsync(response.HttpVersion,
(int)HttpStatusCode.ExpectationFailed, "Expectation Failed");
(int)HttpStatusCode.ExpectationFailed, "Expectation Failed", cancellationToken);
await clientStreamWriter.WriteLineAsync(cancellationToken);
}
......@@ -106,13 +106,13 @@ namespace Titanium.Web.Proxy
if (response.IsBodyRead)
{
await clientStreamWriter.WriteResponseAsync(response);
await clientStreamWriter.WriteResponseAsync(response, cancellationToken: cancellationToken);
}
else
{
//Write back response status to client
await clientStreamWriter.WriteResponseStatusAsync(response.HttpVersion, response.StatusCode,
response.StatusDescription);
response.StatusDescription, cancellationToken);
await clientStreamWriter.WriteHeadersAsync(response.Headers, cancellationToken: cancellationToken);
//Write body if exists
......
......@@ -26,6 +26,7 @@ namespace Titanium.Web.Proxy
private async Task HandleClient(TransparentProxyEndPoint endPoint, TcpClient tcpClient)
{
var cancellationTokenSource = new CancellationTokenSource();
var cancellationToken = cancellationTokenSource.Token;
var clientStream = new CustomBufferedStream(tcpClient.GetStream(), BufferSize);
......@@ -34,7 +35,7 @@ namespace Titanium.Web.Proxy
try
{
var clientHelloInfo = await SslTools.PeekClientHello(clientStream, cancellationTokenSource.Token);
var clientHelloInfo = await SslTools.PeekClientHello(clientStream, cancellationToken);
bool isHttps = clientHelloInfo != null;
string httpsHostName = null;
......@@ -102,9 +103,9 @@ namespace Titanium.Web.Proxy
try
{
// clientStream.Available sbould be at most BufferSize because it is using the same buffer size
await clientStream.ReadAsync(data, 0, available, cancellationTokenSource.Token);
await serverStream.WriteAsync(data, 0, available, cancellationTokenSource.Token);
await serverStream.FlushAsync(cancellationTokenSource.Token);
await clientStream.ReadAsync(data, 0, available, cancellationToken);
await serverStream.WriteAsync(data, 0, available, cancellationToken);
await serverStream.FlushAsync(cancellationToken);
}
finally
{
......
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