Commit 36be993a authored by Honfika's avatar Honfika

more cancellationtokens

parent 3aa4f2fd
...@@ -86,7 +86,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -86,7 +86,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary> /// <summary>
/// Read request body content as bytes[] for current session /// Read request body content as bytes[] for current session
/// </summary> /// </summary>
private async Task ReadRequestBodyAsync() private async Task ReadRequestBodyAsync(CancellationToken cancellationToken)
{ {
WebSession.Request.EnsureBodyAvailable(false); WebSession.Request.EnsureBodyAvailable(false);
...@@ -95,7 +95,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -95,7 +95,7 @@ namespace Titanium.Web.Proxy.EventArguments
//If not already read (not cached yet) //If not already read (not cached yet)
if (!request.IsBodyRead) if (!request.IsBodyRead)
{ {
var body = await ReadBodyAsync(true); var body = await ReadBodyAsync(true, cancellationToken);
request.Body = body; request.Body = body;
//Now set the flag to true //Now set the flag to true
...@@ -108,10 +108,10 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -108,10 +108,10 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary> /// <summary>
/// reinit response object /// reinit response object
/// </summary> /// </summary>
internal async Task ClearResponse() internal async Task ClearResponse(CancellationToken cancellationToken)
{ {
//syphon out the response body from server //syphon out the response body from server
await SyphonOutBodyAsync(false); await SyphonOutBodyAsync(false, cancellationToken);
WebSession.Response = new Response(); WebSession.Response = new Response();
} }
...@@ -130,7 +130,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -130,7 +130,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary> /// <summary>
/// Read response body as byte[] for current response /// Read response body as byte[] for current response
/// </summary> /// </summary>
private async Task ReadResponseBodyAsync() private async Task ReadResponseBodyAsync(CancellationToken cancellationToken)
{ {
if (!WebSession.Request.Locked) if (!WebSession.Request.Locked)
{ {
...@@ -146,7 +146,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -146,7 +146,7 @@ namespace Titanium.Web.Proxy.EventArguments
//If not already read (not cached yet) //If not already read (not cached yet)
if (!response.IsBodyRead) if (!response.IsBodyRead)
{ {
var body = await ReadBodyAsync(false); var body = await ReadBodyAsync(false, cancellationToken);
response.Body = body; response.Body = body;
//Now set the flag to true //Now set the flag to true
...@@ -156,7 +156,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -156,7 +156,7 @@ namespace Titanium.Web.Proxy.EventArguments
} }
} }
private async Task<byte[]> ReadBodyAsync(bool isRequest) private async Task<byte[]> ReadBodyAsync(bool isRequest, CancellationToken cancellationToken)
{ {
using (var bodyStream = new MemoryStream()) using (var bodyStream = new MemoryStream())
{ {
...@@ -164,18 +164,18 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -164,18 +164,18 @@ namespace Titanium.Web.Proxy.EventArguments
if (isRequest) if (isRequest)
{ {
await CopyRequestBodyAsync(writer, TransformationMode.Uncompress); await CopyRequestBodyAsync(writer, TransformationMode.Uncompress, cancellationToken);
} }
else else
{ {
await CopyResponseBodyAsync(writer, TransformationMode.Uncompress); await CopyResponseBodyAsync(writer, TransformationMode.Uncompress, cancellationToken);
} }
return bodyStream.ToArray(); return bodyStream.ToArray();
} }
} }
internal async Task SyphonOutBodyAsync(bool isRequest) internal async Task SyphonOutBodyAsync(bool isRequest, CancellationToken cancellationToken)
{ {
var requestResponse = isRequest ? (RequestResponseBase)WebSession.Request : WebSession.Response; var requestResponse = isRequest ? (RequestResponseBase)WebSession.Request : WebSession.Response;
if (requestResponse.IsBodyRead || !requestResponse.OriginalHasBody) if (requestResponse.IsBodyRead || !requestResponse.OriginalHasBody)
...@@ -186,7 +186,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -186,7 +186,7 @@ namespace Titanium.Web.Proxy.EventArguments
using (var bodyStream = new MemoryStream()) using (var bodyStream = new MemoryStream())
{ {
var writer = new HttpWriter(bodyStream, BufferSize); var writer = new HttpWriter(bodyStream, BufferSize);
await CopyBodyAsync(isRequest, writer, TransformationMode.None, null); await CopyBodyAsync(isRequest, writer, TransformationMode.None, null, cancellationToken);
} }
} }
...@@ -194,7 +194,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -194,7 +194,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// This is called when the request is PUT/POST/PATCH to read the body /// This is called when the request is PUT/POST/PATCH to read the body
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
internal async Task CopyRequestBodyAsync(HttpWriter writer, TransformationMode transformation) internal async Task CopyRequestBodyAsync(HttpWriter writer, TransformationMode transformation, CancellationToken cancellationToken)
{ {
var request = WebSession.Request; var request = WebSession.Request;
...@@ -220,26 +220,26 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -220,26 +220,26 @@ namespace Titanium.Web.Proxy.EventArguments
if (contentLength > copyStream.ReadBytes) if (contentLength > copyStream.ReadBytes)
{ {
var headers = new HeaderCollection(); var headers = new HeaderCollection();
await HeaderParser.ReadHeaders(copyStreamReader, headers); await HeaderParser.ReadHeaders(copyStreamReader, headers, cancellationToken);
OnMultipartRequestPartSent(boundary, headers); OnMultipartRequestPartSent(boundary, headers);
} }
} }
await copyStream.FlushAsync(); await copyStream.FlushAsync(cancellationToken);
} }
} }
else else
{ {
await CopyBodyAsync(true, writer, transformation, OnDataSent); await CopyBodyAsync(true, writer, transformation, OnDataSent, cancellationToken);
} }
} }
internal async Task CopyResponseBodyAsync(HttpWriter writer, TransformationMode transformation) internal async Task CopyResponseBodyAsync(HttpWriter writer, TransformationMode transformation, CancellationToken cancellationToken)
{ {
await CopyBodyAsync(false, writer, transformation, OnDataReceived); await CopyBodyAsync(false, writer, transformation, OnDataReceived, cancellationToken);
} }
private async Task CopyBodyAsync(bool isRequest, HttpWriter writer, TransformationMode transformation, Action<byte[], int, int> onCopy) private async Task CopyBodyAsync(bool isRequest, HttpWriter writer, TransformationMode transformation, Action<byte[], int, int> onCopy, CancellationToken cancellationToken)
{ {
var stream = GetStream(isRequest); var stream = GetStream(isRequest);
var reader = GetStreamReader(isRequest); var reader = GetStreamReader(isRequest);
...@@ -250,7 +250,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -250,7 +250,7 @@ namespace Titanium.Web.Proxy.EventArguments
long contentLength = requestResponse.ContentLength; long contentLength = requestResponse.ContentLength;
if (transformation == TransformationMode.None) if (transformation == TransformationMode.None)
{ {
await writer.CopyBodyAsync(reader, isChunked, contentLength, onCopy); await writer.CopyBodyAsync(reader, isChunked, contentLength, onCopy, cancellationToken);
return; return;
} }
...@@ -271,7 +271,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -271,7 +271,7 @@ namespace Titanium.Web.Proxy.EventArguments
var bufStream = new CustomBufferedStream(s, BufferSize, true); var bufStream = new CustomBufferedStream(s, BufferSize, true);
reader = new CustomBinaryReader(bufStream, BufferSize); reader = new CustomBinaryReader(bufStream, BufferSize);
await writer.CopyBodyAsync(reader, false, -1, onCopy); await writer.CopyBodyAsync(reader, false, -1, onCopy, cancellationToken);
} }
finally finally
{ {
...@@ -349,11 +349,11 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -349,11 +349,11 @@ namespace Titanium.Web.Proxy.EventArguments
/// Gets the request body as bytes /// Gets the request body as bytes
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public async Task<byte[]> GetRequestBody() public async Task<byte[]> GetRequestBody(CancellationToken cancellationToken = default (CancellationToken))
{ {
if (!WebSession.Request.IsBodyRead) if (!WebSession.Request.IsBodyRead)
{ {
await ReadRequestBodyAsync(); await ReadRequestBodyAsync(cancellationToken);
} }
return WebSession.Request.Body; return WebSession.Request.Body;
...@@ -363,11 +363,11 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -363,11 +363,11 @@ namespace Titanium.Web.Proxy.EventArguments
/// Gets the request body as string /// Gets the request body as string
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public async Task<string> GetRequestBodyAsString() public async Task<string> GetRequestBodyAsString(CancellationToken cancellationToken = default(CancellationToken))
{ {
if (!WebSession.Request.IsBodyRead) if (!WebSession.Request.IsBodyRead)
{ {
await ReadRequestBodyAsync(); await ReadRequestBodyAsync(cancellationToken);
} }
return WebSession.Request.BodyString; return WebSession.Request.BodyString;
...@@ -406,11 +406,11 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -406,11 +406,11 @@ namespace Titanium.Web.Proxy.EventArguments
/// Gets the response body as byte array /// Gets the response body as byte array
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public async Task<byte[]> GetResponseBody() public async Task<byte[]> GetResponseBody(CancellationToken cancellationToken = default(CancellationToken))
{ {
if (!WebSession.Response.IsBodyRead) if (!WebSession.Response.IsBodyRead)
{ {
await ReadResponseBodyAsync(); await ReadResponseBodyAsync(cancellationToken);
} }
return WebSession.Response.Body; return WebSession.Response.Body;
...@@ -420,11 +420,11 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -420,11 +420,11 @@ namespace Titanium.Web.Proxy.EventArguments
/// Gets the response body as string /// Gets the response body as string
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public async Task<string> GetResponseBodyAsString() public async Task<string> GetResponseBodyAsString(CancellationToken cancellationToken = default(CancellationToken))
{ {
if (!WebSession.Response.IsBodyRead) if (!WebSession.Response.IsBodyRead)
{ {
await ReadResponseBodyAsync(); await ReadResponseBodyAsync(cancellationToken);
} }
return WebSession.Response.BodyString; return WebSession.Response.BodyString;
......
...@@ -62,7 +62,7 @@ namespace Titanium.Web.Proxy ...@@ -62,7 +62,7 @@ namespace Titanium.Web.Proxy
HttpVersion = version HttpVersion = version
}; };
await HeaderParser.ReadHeaders(clientStreamReader, connectRequest.Headers); await HeaderParser.ReadHeaders(clientStreamReader, connectRequest.Headers, cancellationTokenSource.Token);
var connectArgs = new TunnelConnectSessionEventArgs(BufferSize, endPoint, connectRequest, var connectArgs = new TunnelConnectSessionEventArgs(BufferSize, endPoint, connectRequest,
cancellationTokenSource, ExceptionFunc); cancellationTokenSource, ExceptionFunc);
......
...@@ -29,17 +29,17 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -29,17 +29,17 @@ namespace Titanium.Web.Proxy.Helpers
public int BufferSize { get; } public int BufferSize { get; }
public Task WriteLineAsync() public Task WriteLineAsync(CancellationToken cancellationToken = default(CancellationToken))
{ {
return WriteAsync(newLine); return WriteAsync(newLine, cancellationToken: cancellationToken);
} }
public Task WriteAsync(string value) public Task WriteAsync(string value, CancellationToken cancellationToken = default (CancellationToken))
{ {
return WriteAsyncInternal(value, false); return WriteAsyncInternal(value, false, cancellationToken);
} }
private Task WriteAsyncInternal(string value, bool addNewLine) private Task WriteAsyncInternal(string value, bool addNewLine, CancellationToken cancellationToken)
{ {
int newLineChars = addNewLine ? newLine.Length : 0; int newLineChars = addNewLine ? newLine.Length : 0;
int charCount = value.Length; int charCount = value.Length;
...@@ -57,7 +57,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -57,7 +57,7 @@ namespace Titanium.Web.Proxy.Helpers
idx += newLineChars; idx += newLineChars;
} }
return WriteAsync(buffer, 0, idx); return WriteAsync(buffer, 0, idx, cancellationToken);
} }
finally finally
{ {
...@@ -77,13 +77,13 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -77,13 +77,13 @@ namespace Titanium.Web.Proxy.Helpers
idx += newLineChars; idx += newLineChars;
} }
return WriteAsync(buffer, 0, idx); return WriteAsync(buffer, 0, idx, cancellationToken);
} }
} }
public Task WriteLineAsync(string value) public Task WriteLineAsync(string value, CancellationToken cancellationToken = default (CancellationToken))
{ {
return WriteAsyncInternal(value, true); return WriteAsyncInternal(value, true, cancellationToken);
} }
/// <summary> /// <summary>
...@@ -91,31 +91,32 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -91,31 +91,32 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary> /// </summary>
/// <param name="headers"></param> /// <param name="headers"></param>
/// <param name="flush"></param> /// <param name="flush"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
public async Task WriteHeadersAsync(HeaderCollection headers, bool flush = true) public async Task WriteHeadersAsync(HeaderCollection headers, bool flush = true, CancellationToken cancellationToken = default(CancellationToken))
{ {
foreach (var header in headers) foreach (var header in headers)
{ {
await header.WriteToStreamAsync(this); await header.WriteToStreamAsync(this);
} }
await WriteLineAsync(); await WriteLineAsync(cancellationToken);
if (flush) if (flush)
{ {
await FlushAsync(); await FlushAsync(cancellationToken);
} }
} }
public async Task WriteAsync(byte[] data, bool flush = false) public async Task WriteAsync(byte[] data, bool flush = false, CancellationToken cancellationToken = default(CancellationToken))
{ {
await WriteAsync(data, 0, data.Length); await WriteAsync(data, 0, data.Length, cancellationToken);
if (flush) if (flush)
{ {
await FlushAsync(); await FlushAsync(cancellationToken);
} }
} }
public async Task WriteAsync(byte[] data, int offset, int count, bool flush, CancellationToken cancellationToken) public async Task WriteAsync(byte[] data, int offset, int count, bool flush, CancellationToken cancellationToken = default (CancellationToken))
{ {
await WriteAsync(data, offset, count, cancellationToken); await WriteAsync(data, offset, count, cancellationToken);
if (flush) if (flush)
...@@ -129,15 +130,16 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -129,15 +130,16 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary> /// </summary>
/// <param name="data"></param> /// <param name="data"></param>
/// <param name="isChunked"></param> /// <param name="isChunked"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
internal Task WriteBodyAsync(byte[] data, bool isChunked) internal Task WriteBodyAsync(byte[] data, bool isChunked, CancellationToken cancellationToken)
{ {
if (isChunked) if (isChunked)
{ {
return WriteBodyChunkedAsync(data); return WriteBodyChunkedAsync(data, cancellationToken);
} }
return WriteAsync(data); return WriteAsync(data, cancellationToken: cancellationToken);
} }
/// <summary> /// <summary>
...@@ -148,14 +150,15 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -148,14 +150,15 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="isChunked"></param> /// <param name="isChunked"></param>
/// <param name="contentLength"></param> /// <param name="contentLength"></param>
/// <param name="onCopy"></param> /// <param name="onCopy"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
internal Task CopyBodyAsync(CustomBinaryReader streamReader, bool isChunked, long contentLength, internal Task CopyBodyAsync(CustomBinaryReader streamReader, bool isChunked, long contentLength,
Action<byte[], int, int> onCopy) Action<byte[], int, int> onCopy, CancellationToken cancellationToken)
{ {
//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 (isChunked) if (isChunked)
{ {
return CopyBodyChunkedAsync(streamReader, onCopy); return CopyBodyChunkedAsync(streamReader, onCopy, cancellationToken);
} }
//http 1.0 or the stream reader limits the stream //http 1.0 or the stream reader limits the stream
...@@ -172,18 +175,19 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -172,18 +175,19 @@ namespace Titanium.Web.Proxy.Helpers
/// Copies the given input bytes to output stream chunked /// Copies the given input bytes to output stream chunked
/// </summary> /// </summary>
/// <param name="data"></param> /// <param name="data"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
private async Task WriteBodyChunkedAsync(byte[] data) private async Task WriteBodyChunkedAsync(byte[] data, CancellationToken cancellationToken)
{ {
var chunkHead = Encoding.ASCII.GetBytes(data.Length.ToString("x2")); var chunkHead = Encoding.ASCII.GetBytes(data.Length.ToString("x2"));
await WriteAsync(chunkHead); await WriteAsync(chunkHead, cancellationToken: cancellationToken);
await WriteLineAsync(); await WriteLineAsync(cancellationToken);
await WriteAsync(data); await WriteAsync(data, cancellationToken: cancellationToken);
await WriteLineAsync(); await WriteLineAsync(cancellationToken);
await WriteLineAsync("0"); await WriteLineAsync("0", cancellationToken);
await WriteLineAsync(); await WriteLineAsync(cancellationToken);
} }
/// <summary> /// <summary>
...@@ -191,12 +195,13 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -191,12 +195,13 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary> /// </summary>
/// <param name="reader"></param> /// <param name="reader"></param>
/// <param name="onCopy"></param> /// <param name="onCopy"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
private async Task CopyBodyChunkedAsync(CustomBinaryReader reader, Action<byte[], int, int> onCopy) private async Task CopyBodyChunkedAsync(CustomBinaryReader reader, Action<byte[], int, int> onCopy, CancellationToken cancellationToken)
{ {
while (true) while (true)
{ {
string chunkHead = await reader.ReadLineAsync(); string chunkHead = await reader.ReadLineAsync(cancellationToken);
int idx = chunkHead.IndexOf(";"); int idx = chunkHead.IndexOf(";");
if (idx >= 0) if (idx >= 0)
{ {
...@@ -205,17 +210,17 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -205,17 +210,17 @@ namespace Titanium.Web.Proxy.Helpers
int chunkSize = int.Parse(chunkHead, NumberStyles.HexNumber); int chunkSize = int.Parse(chunkHead, NumberStyles.HexNumber);
await WriteLineAsync(chunkHead); await WriteLineAsync(chunkHead, cancellationToken);
if (chunkSize != 0) if (chunkSize != 0)
{ {
await CopyBytesFromStream(reader, chunkSize, onCopy); await CopyBytesFromStream(reader, chunkSize, onCopy);
} }
await WriteLineAsync(); await WriteLineAsync(cancellationToken);
//chunk trail //chunk trail
await reader.ReadLineAsync(); await reader.ReadLineAsync(cancellationToken);
if (chunkSize == 0) if (chunkSize == 0)
{ {
...@@ -263,15 +268,16 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -263,15 +268,16 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary> /// </summary>
/// <param name="requestResponse"></param> /// <param name="requestResponse"></param>
/// <param name="flush"></param> /// <param name="flush"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
protected async Task WriteAsync(RequestResponseBase requestResponse, bool flush = true) protected async Task WriteAsync(RequestResponseBase requestResponse, bool flush = true, CancellationToken cancellationToken = default (CancellationToken))
{ {
var body = requestResponse.CompressBodyAndUpdateContentLength(); var body = requestResponse.CompressBodyAndUpdateContentLength();
await WriteHeadersAsync(requestResponse.Headers, flush); await WriteHeadersAsync(requestResponse.Headers, flush, cancellationToken);
if (body != null) if (body != null)
{ {
await WriteBodyAsync(body, requestResponse.IsChunked); await WriteBodyAsync(body, requestResponse.IsChunked, cancellationToken);
} }
} }
} }
......
using System; using System;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using StreamExtended.Network; using StreamExtended.Network;
using Titanium.Web.Proxy.Shared; using Titanium.Web.Proxy.Shared;
...@@ -7,10 +8,10 @@ namespace Titanium.Web.Proxy.Http ...@@ -7,10 +8,10 @@ namespace Titanium.Web.Proxy.Http
{ {
internal static class HeaderParser internal static class HeaderParser
{ {
internal static async Task ReadHeaders(CustomBinaryReader reader, HeaderCollection headerCollection) internal static async Task ReadHeaders(CustomBinaryReader reader, HeaderCollection headerCollection, CancellationToken cancellationToken)
{ {
string tmpLine; string tmpLine;
while (!string.IsNullOrEmpty(tmpLine = await reader.ReadLineAsync())) while (!string.IsNullOrEmpty(tmpLine = await reader.ReadLineAsync(cancellationToken)))
{ {
var header = tmpLine.Split(ProxyConstants.ColonSplit, 2); var header = tmpLine.Split(ProxyConstants.ColonSplit, 2);
headerCollection.AddHeader(header[0], header[1]); headerCollection.AddHeader(header[0], header[1]);
......
using System; using System;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
...@@ -79,7 +80,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -79,7 +80,7 @@ namespace Titanium.Web.Proxy.Http
/// Prepare and send the http(s) request /// Prepare and send the http(s) request
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
internal async Task SendRequest(bool enable100ContinueBehaviour, bool isTransparent) internal async Task SendRequest(bool enable100ContinueBehaviour, bool isTransparent, CancellationToken cancellationToken)
{ {
var upstreamProxy = ServerConnection.UpStreamProxy; var upstreamProxy = ServerConnection.UpStreamProxy;
...@@ -90,7 +91,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -90,7 +91,7 @@ namespace Titanium.Web.Proxy.Http
//prepare the request & headers //prepare the request & headers
await writer.WriteLineAsync(Request.CreateRequestLine(Request.Method, await writer.WriteLineAsync(Request.CreateRequestLine(Request.Method,
useUpstreamProxy || isTransparent ? Request.OriginalUrl : Request.RequestUri.PathAndQuery, useUpstreamProxy || isTransparent ? Request.OriginalUrl : Request.RequestUri.PathAndQuery,
Request.HttpVersion)); Request.HttpVersion), cancellationToken);
//Send Authentication to Upstream proxy if needed //Send Authentication to Upstream proxy if needed
...@@ -113,13 +114,13 @@ namespace Titanium.Web.Proxy.Http ...@@ -113,13 +114,13 @@ namespace Titanium.Web.Proxy.Http
} }
} }
await writer.WriteLineAsync(); await writer.WriteLineAsync(cancellationToken);
if (enable100ContinueBehaviour) if (enable100ContinueBehaviour)
{ {
if (Request.ExpectContinue) if (Request.ExpectContinue)
{ {
string httpStatus = await ServerConnection.StreamReader.ReadLineAsync(); string httpStatus = await ServerConnection.StreamReader.ReadLineAsync(cancellationToken);
Response.ParseResponseLine(httpStatus, out _, out int responseStatusCode, Response.ParseResponseLine(httpStatus, out _, out int responseStatusCode,
out string responseStatusDescription); out string responseStatusDescription);
...@@ -129,13 +130,13 @@ namespace Titanium.Web.Proxy.Http ...@@ -129,13 +130,13 @@ namespace Titanium.Web.Proxy.Http
&& responseStatusDescription.EqualsIgnoreCase("continue")) && responseStatusDescription.EqualsIgnoreCase("continue"))
{ {
Request.Is100Continue = true; Request.Is100Continue = true;
await ServerConnection.StreamReader.ReadLineAsync(); await ServerConnection.StreamReader.ReadLineAsync(cancellationToken);
} }
else if (responseStatusCode == (int)HttpStatusCode.ExpectationFailed else if (responseStatusCode == (int)HttpStatusCode.ExpectationFailed
&& responseStatusDescription.EqualsIgnoreCase("expectation failed")) && responseStatusDescription.EqualsIgnoreCase("expectation failed"))
{ {
Request.ExpectationFailed = true; Request.ExpectationFailed = true;
await ServerConnection.StreamReader.ReadLineAsync(); await ServerConnection.StreamReader.ReadLineAsync(cancellationToken);
} }
} }
} }
...@@ -145,7 +146,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -145,7 +146,7 @@ namespace Titanium.Web.Proxy.Http
/// Receive and parse the http response from server /// Receive and parse the http response from server
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
internal async Task ReceiveResponse() internal async Task ReceiveResponse(CancellationToken cancellationToken)
{ {
//return if this is already read //return if this is already read
if (Response.StatusCode != 0) if (Response.StatusCode != 0)
...@@ -153,7 +154,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -153,7 +154,7 @@ namespace Titanium.Web.Proxy.Http
return; return;
} }
string httpStatus = await ServerConnection.StreamReader.ReadLineAsync(); string httpStatus = await ServerConnection.StreamReader.ReadLineAsync(cancellationToken);
if (httpStatus == null) if (httpStatus == null)
{ {
throw new IOException(); throw new IOException();
...@@ -161,7 +162,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -161,7 +162,7 @@ namespace Titanium.Web.Proxy.Http
if (httpStatus == string.Empty) if (httpStatus == string.Empty)
{ {
httpStatus = await ServerConnection.StreamReader.ReadLineAsync(); httpStatus = await ServerConnection.StreamReader.ReadLineAsync(cancellationToken);
} }
Response.ParseResponseLine(httpStatus, out var version, out int statusCode, out string statusDescription); Response.ParseResponseLine(httpStatus, out var version, out int statusCode, out string statusDescription);
...@@ -177,10 +178,10 @@ namespace Titanium.Web.Proxy.Http ...@@ -177,10 +178,10 @@ namespace Titanium.Web.Proxy.Http
//Read the next line after 100-continue //Read the next line after 100-continue
Response.Is100Continue = true; Response.Is100Continue = true;
Response.StatusCode = 0; Response.StatusCode = 0;
await ServerConnection.StreamReader.ReadLineAsync(); await ServerConnection.StreamReader.ReadLineAsync(cancellationToken);
//now receive response //now receive response
await ReceiveResponse(); await ReceiveResponse(cancellationToken);
return; return;
} }
...@@ -190,15 +191,15 @@ namespace Titanium.Web.Proxy.Http ...@@ -190,15 +191,15 @@ namespace Titanium.Web.Proxy.Http
//read next line after expectation failed response //read next line after expectation failed response
Response.ExpectationFailed = true; Response.ExpectationFailed = true;
Response.StatusCode = 0; Response.StatusCode = 0;
await ServerConnection.StreamReader.ReadLineAsync(); await ServerConnection.StreamReader.ReadLineAsync(cancellationToken);
//now receive response //now receive response
await ReceiveResponse(); await ReceiveResponse(cancellationToken);
return; return;
} }
//Read the response headers in to unique and non-unique header collections //Read the response headers in to unique and non-unique header collections
await HeaderParser.ReadHeaders(ServerConnection.StreamReader, Response.Headers); await HeaderParser.ReadHeaders(ServerConnection.StreamReader, Response.Headers, cancellationToken);
} }
/// <summary> /// <summary>
......
using System.Net; using System.Net;
using System.Web;
namespace Titanium.Web.Proxy.Http.Responses namespace Titanium.Web.Proxy.Http.Responses
{ {
...@@ -15,9 +16,13 @@ namespace Titanium.Web.Proxy.Http.Responses ...@@ -15,9 +16,13 @@ namespace Titanium.Web.Proxy.Http.Responses
{ {
StatusCode = (int)status; StatusCode = (int)status;
#if NET45
StatusDescription = HttpWorkerRequest.GetStatusDescription(StatusCode);
#else
//todo: this is not really correct, status description should contain spaces, too //todo: this is not really correct, status description should contain spaces, too
//see: https://tools.ietf.org/html/rfc7231#section-6.1 //see: https://tools.ietf.org/html/rfc7231#section-6.1
StatusDescription = status.ToString(); StatusDescription = status.ToString();
#endif
} }
/// <summary> /// <summary>
......
...@@ -74,19 +74,19 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -74,19 +74,19 @@ namespace Titanium.Web.Proxy.Network.Tcp
if (useUpstreamProxy && (isConnect || isHttps)) if (useUpstreamProxy && (isConnect || isHttps))
{ {
var writer = new HttpRequestWriter(stream, proxyServer.BufferSize); var writer = new HttpRequestWriter(stream, proxyServer.BufferSize);
await writer.WriteLineAsync($"CONNECT {remoteHostName}:{remotePort} HTTP/{httpVersion}"); await writer.WriteLineAsync($"CONNECT {remoteHostName}:{remotePort} HTTP/{httpVersion}", cancellationToken);
await writer.WriteLineAsync($"Host: {remoteHostName}:{remotePort}"); await writer.WriteLineAsync($"Host: {remoteHostName}:{remotePort}", cancellationToken);
await writer.WriteLineAsync($"{KnownHeaders.Connection}: {KnownHeaders.ConnectionKeepAlive}"); await writer.WriteLineAsync($"{KnownHeaders.Connection}: {KnownHeaders.ConnectionKeepAlive}", cancellationToken);
if (!string.IsNullOrEmpty(externalProxy.UserName) && externalProxy.Password != null) if (!string.IsNullOrEmpty(externalProxy.UserName) && externalProxy.Password != null)
{ {
await HttpHeader.ProxyConnectionKeepAlive.WriteToStreamAsync(writer); await HttpHeader.ProxyConnectionKeepAlive.WriteToStreamAsync(writer);
await writer.WriteLineAsync(KnownHeaders.ProxyAuthorization + ": Basic " + await writer.WriteLineAsync(KnownHeaders.ProxyAuthorization + ": Basic " +
Convert.ToBase64String(Encoding.UTF8.GetBytes( Convert.ToBase64String(Encoding.UTF8.GetBytes(
externalProxy.UserName + ":" + externalProxy.Password))); externalProxy.UserName + ":" + externalProxy.Password)), cancellationToken);
} }
await writer.WriteLineAsync(); await writer.WriteLineAsync(cancellationToken);
using (var reader = new CustomBinaryReader(stream, proxyServer.BufferSize)) using (var reader = new CustomBinaryReader(stream, proxyServer.BufferSize))
{ {
......
...@@ -56,20 +56,22 @@ namespace Titanium.Web.Proxy ...@@ -56,20 +56,22 @@ namespace Titanium.Web.Proxy
while (true) while (true)
{ {
// read the request line // read the request line
string httpCmd = await clientStreamReader.ReadLineAsync(); string httpCmd = await clientStreamReader.ReadLineAsync(cancellationTokenSource.Token);
if (httpCmd == "PRI * HTTP/2.0") if (httpCmd == "PRI * HTTP/2.0")
{ {
// HTTP/2 Connection Preface // HTTP/2 Connection Preface
string line = await clientStreamReader.ReadLineAsync(); string line = await clientStreamReader.ReadLineAsync(cancellationTokenSource.Token);
if (line != string.Empty) throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received"); if (line != string.Empty) throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received");
line = await clientStreamReader.ReadLineAsync(); line = await clientStreamReader.ReadLineAsync(cancellationTokenSource.Token);
if (line != "SM") throw new Exception($"HTTP/2 Protocol violation. 'SM' expected, '{line}' received"); if (line != "SM") throw new Exception($"HTTP/2 Protocol violation. 'SM' expected, '{line}' received");
line = await clientStreamReader.ReadLineAsync(); line = await clientStreamReader.ReadLineAsync(cancellationTokenSource.Token);
if (line != string.Empty) throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received"); if (line != string.Empty) throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received");
// todo // todo
var buffer = new byte[1024];
await clientStreamReader.ReadBytesAsync(buffer, 0, 3, cancellationTokenSource.Token);
} }
if (string.IsNullOrEmpty(httpCmd)) if (string.IsNullOrEmpty(httpCmd))
...@@ -91,7 +93,7 @@ namespace Titanium.Web.Proxy ...@@ -91,7 +93,7 @@ namespace Titanium.Web.Proxy
out var version); out var version);
//Read the request headers in to unique and non-unique header collections //Read the request headers in to unique and non-unique header collections
await HeaderParser.ReadHeaders(clientStreamReader, args.WebSession.Request.Headers); await HeaderParser.ReadHeaders(clientStreamReader, args.WebSession.Request.Headers, cancellationTokenSource.Token);
Uri httpRemoteUri; Uri httpRemoteUri;
if (uriSchemeRegex.IsMatch(httpUrl)) if (uriSchemeRegex.IsMatch(httpUrl))
...@@ -171,7 +173,7 @@ namespace Titanium.Web.Proxy ...@@ -171,7 +173,7 @@ namespace Titanium.Web.Proxy
if (request.CancelRequest) if (request.CancelRequest)
{ {
//syphon out the request body from client before setting the new body //syphon out the request body from client before setting the new body
await args.SyphonOutBodyAsync(true); await args.SyphonOutBodyAsync(true, cancellationTokenSource.Token);
await HandleHttpSessionResponse(args); await HandleHttpSessionResponse(args);
...@@ -205,7 +207,7 @@ namespace Titanium.Web.Proxy ...@@ -205,7 +207,7 @@ namespace Titanium.Web.Proxy
//prepare the prefix content //prepare the prefix content
await connection.StreamWriter.WriteLineAsync(httpCmd); await connection.StreamWriter.WriteLineAsync(httpCmd);
await connection.StreamWriter.WriteHeadersAsync(request.Headers); await connection.StreamWriter.WriteHeadersAsync(request.Headers);
string httpStatus = await connection.StreamReader.ReadLineAsync(); string httpStatus = await connection.StreamReader.ReadLineAsync(cancellationTokenSource.Token);
Response.ParseResponseLine(httpStatus, out var responseVersion, Response.ParseResponseLine(httpStatus, out var responseVersion,
out int responseStatusCode, out int responseStatusCode,
...@@ -214,7 +216,7 @@ namespace Titanium.Web.Proxy ...@@ -214,7 +216,7 @@ namespace Titanium.Web.Proxy
response.StatusCode = responseStatusCode; response.StatusCode = responseStatusCode;
response.StatusDescription = responseStatusDescription; response.StatusDescription = responseStatusDescription;
await HeaderParser.ReadHeaders(connection.StreamReader, response.Headers); await HeaderParser.ReadHeaders(connection.StreamReader, response.Headers, cancellationTokenSource.Token);
if (!args.IsTransparent) if (!args.IsTransparent)
{ {
...@@ -287,6 +289,7 @@ namespace Titanium.Web.Proxy ...@@ -287,6 +289,7 @@ namespace Titanium.Web.Proxy
{ {
try try
{ {
var cancellationToken = args.CancellationTokenSource.Token;
var request = args.WebSession.Request; var request = args.WebSession.Request;
request.Locked = true; request.Locked = true;
...@@ -297,7 +300,7 @@ namespace Titanium.Web.Proxy ...@@ -297,7 +300,7 @@ namespace Titanium.Web.Proxy
if (request.ExpectContinue) if (request.ExpectContinue)
{ {
args.WebSession.SetConnection(connection); args.WebSession.SetConnection(connection);
await args.WebSession.SendRequest(Enable100ContinueBehaviour, args.IsTransparent); await args.WebSession.SendRequest(Enable100ContinueBehaviour, args.IsTransparent, cancellationToken);
} }
//If 100 continue was the response inform that to the client //If 100 continue was the response inform that to the client
...@@ -309,13 +312,13 @@ namespace Titanium.Web.Proxy ...@@ -309,13 +312,13 @@ namespace Titanium.Web.Proxy
{ {
await clientStreamWriter.WriteResponseStatusAsync(args.WebSession.Response.HttpVersion, await clientStreamWriter.WriteResponseStatusAsync(args.WebSession.Response.HttpVersion,
(int)HttpStatusCode.Continue, "Continue"); (int)HttpStatusCode.Continue, "Continue");
await clientStreamWriter.WriteLineAsync(); await clientStreamWriter.WriteLineAsync(cancellationToken);
} }
else if (request.ExpectationFailed) else if (request.ExpectationFailed)
{ {
await clientStreamWriter.WriteResponseStatusAsync(args.WebSession.Response.HttpVersion, await clientStreamWriter.WriteResponseStatusAsync(args.WebSession.Response.HttpVersion,
(int)HttpStatusCode.ExpectationFailed, "Expectation Failed"); (int)HttpStatusCode.ExpectationFailed, "Expectation Failed");
await clientStreamWriter.WriteLineAsync(); await clientStreamWriter.WriteLineAsync(cancellationToken);
} }
} }
...@@ -323,7 +326,7 @@ namespace Titanium.Web.Proxy ...@@ -323,7 +326,7 @@ namespace Titanium.Web.Proxy
if (!request.ExpectContinue) if (!request.ExpectContinue)
{ {
args.WebSession.SetConnection(connection); args.WebSession.SetConnection(connection);
await args.WebSession.SendRequest(Enable100ContinueBehaviour, args.IsTransparent); await args.WebSession.SendRequest(Enable100ContinueBehaviour, args.IsTransparent, cancellationToken);
} }
//check if content-length is > 0 //check if content-length is > 0
...@@ -332,7 +335,7 @@ namespace Titanium.Web.Proxy ...@@ -332,7 +335,7 @@ namespace Titanium.Web.Proxy
if (request.IsBodyRead) if (request.IsBodyRead)
{ {
var writer = args.WebSession.ServerConnection.StreamWriter; var writer = args.WebSession.ServerConnection.StreamWriter;
await writer.WriteBodyAsync(body, request.IsChunked); await writer.WriteBodyAsync(body, request.IsChunked, cancellationToken);
} }
else else
{ {
...@@ -341,7 +344,7 @@ namespace Titanium.Web.Proxy ...@@ -341,7 +344,7 @@ namespace Titanium.Web.Proxy
if (request.HasBody) if (request.HasBody)
{ {
HttpWriter writer = args.WebSession.ServerConnection.StreamWriter; HttpWriter writer = args.WebSession.ServerConnection.StreamWriter;
await args.CopyRequestBodyAsync(writer, TransformationMode.None); await args.CopyRequestBodyAsync(writer, TransformationMode.None, cancellationToken);
} }
} }
} }
......
...@@ -22,8 +22,9 @@ namespace Titanium.Web.Proxy ...@@ -22,8 +22,9 @@ namespace Titanium.Web.Proxy
{ {
try try
{ {
var cancellationToken = args.CancellationTokenSource.Token;
//read response & headers from server //read response & headers from server
await args.WebSession.ReceiveResponse(); await args.WebSession.ReceiveResponse(cancellationToken);
var response = args.WebSession.Response; var response = args.WebSession.Response;
args.ReRequest = false; args.ReRequest = false;
...@@ -61,7 +62,7 @@ namespace Titanium.Web.Proxy ...@@ -61,7 +62,7 @@ namespace Titanium.Web.Proxy
if (!response.TerminateResponse) if (!response.TerminateResponse)
{ {
//syphon out the response body from server before setting the new body //syphon out the response body from server before setting the new body
await args.SyphonOutBodyAsync(false); await args.SyphonOutBodyAsync(false, cancellationToken);
} }
else else
{ {
...@@ -77,7 +78,7 @@ namespace Titanium.Web.Proxy ...@@ -77,7 +78,7 @@ namespace Titanium.Web.Proxy
if (args.ReRequest) if (args.ReRequest)
{ {
//clear current response //clear current response
await args.ClearResponse(); await args.ClearResponse(cancellationToken);
await HandleHttpSessionRequestInternal(args.WebSession.ServerConnection, args); await HandleHttpSessionRequestInternal(args.WebSession.ServerConnection, args);
return; return;
} }
...@@ -89,13 +90,13 @@ namespace Titanium.Web.Proxy ...@@ -89,13 +90,13 @@ namespace Titanium.Web.Proxy
{ {
await clientStreamWriter.WriteResponseStatusAsync(response.HttpVersion, await clientStreamWriter.WriteResponseStatusAsync(response.HttpVersion,
(int)HttpStatusCode.Continue, "Continue"); (int)HttpStatusCode.Continue, "Continue");
await clientStreamWriter.WriteLineAsync(); await clientStreamWriter.WriteLineAsync(cancellationToken);
} }
else if (response.ExpectationFailed) else if (response.ExpectationFailed)
{ {
await clientStreamWriter.WriteResponseStatusAsync(response.HttpVersion, await clientStreamWriter.WriteResponseStatusAsync(response.HttpVersion,
(int)HttpStatusCode.ExpectationFailed, "Expectation Failed"); (int)HttpStatusCode.ExpectationFailed, "Expectation Failed");
await clientStreamWriter.WriteLineAsync(); await clientStreamWriter.WriteLineAsync(cancellationToken);
} }
if (!args.IsTransparent) if (!args.IsTransparent)
...@@ -112,12 +113,12 @@ namespace Titanium.Web.Proxy ...@@ -112,12 +113,12 @@ namespace Titanium.Web.Proxy
//Write back response status to client //Write back response status to client
await clientStreamWriter.WriteResponseStatusAsync(response.HttpVersion, response.StatusCode, await clientStreamWriter.WriteResponseStatusAsync(response.HttpVersion, response.StatusCode,
response.StatusDescription); response.StatusDescription);
await clientStreamWriter.WriteHeadersAsync(response.Headers); await clientStreamWriter.WriteHeadersAsync(response.Headers, cancellationToken: cancellationToken);
//Write body if exists //Write body if exists
if (response.HasBody) if (response.HasBody)
{ {
await args.CopyResponseBodyAsync(clientStreamWriter, TransformationMode.None); await args.CopyResponseBodyAsync(clientStreamWriter, TransformationMode.None, cancellationToken);
} }
} }
} }
......
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net45;netstandard2.0</TargetFrameworks> <TargetFrameworks>net45;netstandard2.0</TargetFrameworks>
<RootNamespace>Titanium.Web.Proxy</RootNamespace> <RootNamespace>Titanium.Web.Proxy</RootNamespace>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<SignAssembly>True</SignAssembly> <SignAssembly>True</SignAssembly>
<AssemblyOriginatorKeyFile>StrongNameKey.snk</AssemblyOriginatorKeyFile> <AssemblyOriginatorKeyFile>StrongNameKey.snk</AssemblyOriginatorKeyFile>
<DelaySign>False</DelaySign> <DelaySign>False</DelaySign>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks> <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<LangVersion>7.1</LangVersion> <LangVersion>7.1</LangVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Portable.BouncyCastle" Version="1.8.2" /> <PackageReference Include="Portable.BouncyCastle" Version="1.8.2" />
<PackageReference Include="StreamExtended" Version="1.0.147-beta" /> <PackageReference Include="StreamExtended" Version="1.0.147-beta" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'"> <ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<PackageReference Include="Microsoft.Win32.Registry"> <PackageReference Include="Microsoft.Win32.Registry">
<Version>4.4.0</Version> <Version>4.4.0</Version>
</PackageReference> </PackageReference>
<PackageReference Include="System.Security.Principal.Windows"> <PackageReference Include="System.Security.Principal.Windows">
<Version>4.4.1</Version> <Version>4.4.1</Version>
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp2.1'"> <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp2.1'">
<PackageReference Include="Microsoft.Win32.Registry"> <PackageReference Include="Microsoft.Win32.Registry">
<Version>4.4.0</Version> <Version>4.4.0</Version>
</PackageReference> </PackageReference>
<PackageReference Include="System.Security.Principal.Windows"> <PackageReference Include="System.Security.Principal.Windows">
<Version>4.4.1</Version> <Version>4.4.1</Version>
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Reference Include="System.Web" />
</ItemGroup>
</Project> </Project>
\ No newline at end of file
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