Commit 0fe5a400 authored by Honfika's avatar Honfika

HTTP/2 => HTTP/2 support in "readonly" mode without user events (HTTP 1.x <=>...

HTTP/2 => HTTP/2 support in "readonly" mode without user events (HTTP 1.x <=> HTTP/2 fails currently)
parent 4dd7f91f
...@@ -13,6 +13,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -13,6 +13,7 @@ namespace Titanium.Web.Proxy.EventArguments
CancellationTokenSource cancellationTokenSource, ExceptionHandler exceptionFunc) CancellationTokenSource cancellationTokenSource, ExceptionHandler exceptionFunc)
: base(bufferSize, endPoint, cancellationTokenSource, connectRequest, exceptionFunc) : base(bufferSize, endPoint, cancellationTokenSource, connectRequest, exceptionFunc)
{ {
WebSession.ConnectRequest = connectRequest;
} }
public bool DecryptSsl { get; set; } = true; public bool DecryptSsl { get; set; } = true;
......
using System; using System;
using System.IO; using System.IO;
using System.Linq;
using System.Net; using System.Net;
using System.Net.Security; using System.Net.Security;
using System.Net.Sockets; using System.Net.Sockets;
...@@ -40,7 +41,7 @@ namespace Titanium.Web.Proxy ...@@ -40,7 +41,7 @@ namespace Titanium.Web.Proxy
try try
{ {
string connectHostname = null; string connectHostname = null;
ConnectRequest connectRequest = null; TunnelConnectSessionEventArgs connectArgs = null;
//Client wants to create a secure tcp tunnel (probably its a HTTPS or Websocket request) //Client wants to create a secure tcp tunnel (probably its a HTTPS or Websocket request)
if (await HttpHelper.IsConnectMethod(clientStream) == 1) if (await HttpHelper.IsConnectMethod(clientStream) == 1)
...@@ -57,7 +58,7 @@ namespace Titanium.Web.Proxy ...@@ -57,7 +58,7 @@ namespace Titanium.Web.Proxy
var httpRemoteUri = new Uri("http://" + httpUrl); var httpRemoteUri = new Uri("http://" + httpUrl);
connectHostname = httpRemoteUri.Host; connectHostname = httpRemoteUri.Host;
connectRequest = new ConnectRequest var connectRequest = new ConnectRequest
{ {
RequestUri = httpRemoteUri, RequestUri = httpRemoteUri,
OriginalUrl = httpUrl, OriginalUrl = httpUrl,
...@@ -66,7 +67,7 @@ namespace Titanium.Web.Proxy ...@@ -66,7 +67,7 @@ namespace Titanium.Web.Proxy
await HeaderParser.ReadHeaders(clientStreamReader, connectRequest.Headers, cancellationToken); await HeaderParser.ReadHeaders(clientStreamReader, connectRequest.Headers, cancellationToken);
var connectArgs = new TunnelConnectSessionEventArgs(BufferSize, endPoint, connectRequest, connectArgs = new TunnelConnectSessionEventArgs(BufferSize, endPoint, connectRequest,
cancellationTokenSource, ExceptionFunc); cancellationTokenSource, ExceptionFunc);
connectArgs.ProxyClient.TcpClient = tcpClient; connectArgs.ProxyClient.TcpClient = tcpClient;
connectArgs.ProxyClient.ClientStream = clientStream; connectArgs.ProxyClient.ClientStream = clientStream;
...@@ -220,9 +221,41 @@ namespace Titanium.Web.Proxy ...@@ -220,9 +221,41 @@ namespace Titanium.Web.Proxy
} }
} }
if (connectArgs != null && await HttpHelper.IsPriMethod(clientStream) == 1)
{
// todo
string httpCmd = await clientStreamReader.ReadLineAsync(cancellationToken);
if (httpCmd == "PRI * HTTP/2.0")
{
// HTTP/2 Connection Preface
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(cancellationToken);
if (line != "SM") throw new Exception($"HTTP/2 Protocol violation. 'SM' expected, '{line}' received");
line = await clientStreamReader.ReadLineAsync(cancellationToken);
if (line != string.Empty) throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received");
//create new connection
using (var connection = await GetServerConnection(connectArgs, true, cancellationToken))
{
await connection.StreamWriter.WriteLineAsync("PRI * HTTP/2.0", cancellationToken);
await connection.StreamWriter.WriteLineAsync(cancellationToken);
await connection.StreamWriter.WriteLineAsync("SM", cancellationToken);
await connection.StreamWriter.WriteLineAsync(cancellationToken);
await TcpHelper.SendHttp2(clientStream, connection.Stream, BufferSize,
(buffer, offset, count) => { connectArgs.OnDataSent(buffer, offset, count); },
(buffer, offset, count) => { connectArgs.OnDataReceived(buffer, offset, count); },
connectArgs.CancellationTokenSource, ExceptionFunc);
}
}
}
//Now create the request //Now create the request
await HandleHttpSessionRequest(endPoint, tcpClient, clientStream, clientStreamReader, await HandleHttpSessionRequest(endPoint, tcpClient, clientStream, clientStreamReader,
clientStreamWriter, cancellationTokenSource, connectHostname, connectRequest); clientStreamWriter, cancellationTokenSource, connectHostname, connectArgs?.WebSession.ConnectRequest);
} }
catch (ProxyHttpException e) catch (ProxyHttpException e)
{ {
......
...@@ -120,9 +120,32 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -120,9 +120,32 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary> /// </summary>
/// <param name="clientStream">The client stream.</param> /// <param name="clientStream">The client stream.</param>
/// <returns>1: when CONNECT, 0: when valid HTTP method, -1: otherwise</returns> /// <returns>1: when CONNECT, 0: when valid HTTP method, -1: otherwise</returns>
internal static async Task<int> IsConnectMethod(CustomBufferedStream clientStream) internal static Task<int> IsConnectMethod(CustomBufferedStream clientStream)
{ {
bool isConnect = true; return StartsWith(clientStream, "CONNECT");
}
/// <summary>
/// Determines whether is pri method (HTTP/2).
/// </summary>
/// <param name="clientStream">The client stream.</param>
/// <returns>1: when PRI, 0: when valid HTTP method, -1: otherwise</returns>
internal static Task<int> IsPriMethod(CustomBufferedStream clientStream)
{
return StartsWith(clientStream, "PRI");
}
/// <summary>
/// Determines whether the stream starts with the given string.
/// </summary>
/// <param name="clientStream">The client stream.</param>
/// <param name="expectedStart">The expected start.</param>
/// <returns>
/// 1: when starts with the given string, 0: when valid HTTP method, -1: otherwise
/// </returns>
private static async Task<int> StartsWith(CustomBufferedStream clientStream, string expectedStart)
{
bool isExpected = true;
int legthToCheck = 10; int legthToCheck = 10;
for (int i = 0; i < legthToCheck; i++) for (int i = 0; i < legthToCheck; i++)
{ {
...@@ -134,7 +157,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -134,7 +157,7 @@ namespace Titanium.Web.Proxy.Helpers
if (b == ' ' && i > 2) if (b == ' ' && i > 2)
{ {
return isConnect ? 1 : 0; return isExpected ? 1 : 0;
} }
char ch = (char)b; char ch = (char)b;
...@@ -143,14 +166,14 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -143,14 +166,14 @@ namespace Titanium.Web.Proxy.Helpers
return -1; return -1;
} }
if (i > 6 || ch != "CONNECT"[i]) if (i >= expectedStart.Length || ch != expectedStart[i])
{ {
isConnect = false; isExpected = false;
} }
} }
// only letters // only letters
return isConnect ? 1 : 0; return isExpected ? 1 : 0;
} }
} }
} }
using System.IO; using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Titanium.Web.Proxy.Http;
namespace Titanium.Web.Proxy.Helpers namespace Titanium.Web.Proxy.Helpers
{ {
...@@ -7,5 +10,20 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -7,5 +10,20 @@ namespace Titanium.Web.Proxy.Helpers
public HttpRequestWriter(Stream stream, int bufferSize) : base(stream, bufferSize) public HttpRequestWriter(Stream stream, int bufferSize) : base(stream, bufferSize)
{ {
} }
/// <summary>
/// Writes the request.
/// </summary>
/// <param name="request"></param>
/// <param name="flush"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task WriteRequestAsync(Request request, bool flush = true,
CancellationToken cancellationToken = default)
{
await WriteLineAsync(Request.CreateRequestLine(request.Method, request.OriginalUrl, request.HttpVersion),
cancellationToken);
await WriteAsync(request, flush, cancellationToken);
}
} }
} }
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Helpers
{
public class Ref<T>
{
public Ref()
{
}
public Ref(T value)
{
Value = value;
}
public T Value { get; set; }
public override string ToString()
{
T value = Value;
return value == null ? string.Empty : value.ToString();
}
public static implicit operator T(Ref<T> r)
{
return r.Value;
}
public static implicit operator Ref<T>(T value)
{
return new Ref<T>(value);
}
}
}
...@@ -130,7 +130,8 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -130,7 +130,8 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="exceptionFunc"></param> /// <param name="exceptionFunc"></param>
/// <returns></returns> /// <returns></returns>
internal static async Task SendRawApm(Stream clientStream, Stream serverStream, int bufferSize, internal static async Task SendRawApm(Stream clientStream, Stream serverStream, int bufferSize,
Action<byte[], int, int> onDataSend, Action<byte[], int, int> onDataReceive, CancellationTokenSource cancellationTokenSource, Action<byte[], int, int> onDataSend, Action<byte[], int, int> onDataReceive,
CancellationTokenSource cancellationTokenSource,
ExceptionHandler exceptionFunc) ExceptionHandler exceptionFunc)
{ {
var taskCompletionSource = new TaskCompletionSource<bool>(); var taskCompletionSource = new TaskCompletionSource<bool>();
...@@ -234,7 +235,8 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -234,7 +235,8 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="exceptionFunc"></param> /// <param name="exceptionFunc"></param>
/// <returns></returns> /// <returns></returns>
private static async Task SendRawTap(Stream clientStream, Stream serverStream, int bufferSize, private static async Task SendRawTap(Stream clientStream, Stream serverStream, int bufferSize,
Action<byte[], int, int> onDataSend, Action<byte[], int, int> onDataReceive, CancellationTokenSource cancellationTokenSource, Action<byte[], int, int> onDataSend, Action<byte[], int, int> onDataReceive,
CancellationTokenSource cancellationTokenSource,
ExceptionHandler exceptionFunc) ExceptionHandler exceptionFunc)
{ {
//Now async relay all server=>client & client=>server data //Now async relay all server=>client & client=>server data
...@@ -263,12 +265,101 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -263,12 +265,101 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="exceptionFunc"></param> /// <param name="exceptionFunc"></param>
/// <returns></returns> /// <returns></returns>
internal static Task SendRaw(Stream clientStream, Stream serverStream, int bufferSize, internal static Task SendRaw(Stream clientStream, Stream serverStream, int bufferSize,
Action<byte[], int, int> onDataSend, Action<byte[], int, int> onDataReceive, CancellationTokenSource cancellationTokenSource, Action<byte[], int, int> onDataSend, Action<byte[], int, int> onDataReceive,
CancellationTokenSource cancellationTokenSource,
ExceptionHandler exceptionFunc) ExceptionHandler exceptionFunc)
{ {
// todo: fix APM mode // todo: fix APM mode
return SendRawTap(clientStream, serverStream, bufferSize, onDataSend, onDataReceive, cancellationTokenSource, return SendRawTap(clientStream, serverStream, bufferSize, onDataSend, onDataReceive,
cancellationTokenSource,
exceptionFunc); exceptionFunc);
} }
/// <summary>
/// relays the input clientStream to the server at the specified host name and port with the given httpCmd and headers
/// as prefix
/// Usefull for websocket requests
/// Task-based Asynchronous Pattern
/// </summary>
/// <param name="clientStream"></param>
/// <param name="serverStream"></param>
/// <param name="bufferSize"></param>
/// <param name="onDataSend"></param>
/// <param name="onDataReceive"></param>
/// <param name="cancellationTokenSource"></param>
/// <param name="exceptionFunc"></param>
/// <returns></returns>
internal static async Task SendHttp2(Stream clientStream, Stream serverStream, int bufferSize,
Action<byte[], int, int> onDataSend, Action<byte[], int, int> onDataReceive,
CancellationTokenSource cancellationTokenSource,
ExceptionHandler exceptionFunc)
{
var connectionId = Guid.NewGuid();
//Now async relay all server=>client & client=>server data
var sendRelay =
CopyHttp2FrameAsync(clientStream, serverStream, onDataSend, bufferSize, connectionId, cancellationTokenSource.Token);
var receiveRelay =
CopyHttp2FrameAsync(serverStream, clientStream, onDataReceive, bufferSize, connectionId, cancellationTokenSource.Token);
await Task.WhenAny(sendRelay, receiveRelay);
cancellationTokenSource.Cancel();
await Task.WhenAll(sendRelay, receiveRelay);
}
private static async Task CopyHttp2FrameAsync(Stream input, Stream output, Action<byte[], int, int> onCopy,
int bufferSize, Guid connectionId, CancellationToken cancellationToken)
{
var headerBuffer = new byte[9];
var buffer = new byte[32768];
while (true)
{
int read = await ForceRead(input, headerBuffer, 0, 9, cancellationToken);
if (read != 9)
{
return;
}
int length = (headerBuffer[0] << 16) + (headerBuffer[1] << 8) + headerBuffer[2];
byte type = headerBuffer[3];
byte flags = headerBuffer[4];
int streamId = ((headerBuffer[5] & 0x7f) << 24) + (headerBuffer[6] << 16) + (headerBuffer[7] << 8) + headerBuffer[8];
read = await ForceRead(input, buffer, 0, length, cancellationToken);
if (read != length)
{
return;
}
await output.WriteAsync(headerBuffer, 0, headerBuffer.Length, cancellationToken);
await output.WriteAsync(buffer, 0, length, cancellationToken);
/*using (var fs = new System.IO.FileStream($@"c:\11\{connectionId}.{streamId}.dat", FileMode.Append))
{
fs.Write(headerBuffer, 0, headerBuffer.Length);
fs.Write(buffer, 0, length);
}*/
}
}
private static async Task<int> ForceRead(Stream input, byte[] buffer, int offset, int bytesToRead, CancellationToken cancellationToken)
{
int totalRead = 0;
while (bytesToRead > 0)
{
int read = await input.ReadAsync(buffer, offset, bytesToRead, cancellationToken);
if (read == -1)
{
break;
}
totalRead += read;
bytesToRead -= read;
offset += read;
}
return totalRead;
}
} }
} }
...@@ -26,7 +26,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -26,7 +26,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <param name="remotePort"></param> /// <param name="remotePort"></param>
/// <param name="applicationProtocols"></param> /// <param name="applicationProtocols"></param>
/// <param name="httpVersion"></param> /// <param name="httpVersion"></param>
/// <param name="isHttps"></param> /// <param name="decryptSsl"></param>
/// <param name="isConnect"></param> /// <param name="isConnect"></param>
/// <param name="proxyServer"></param> /// <param name="proxyServer"></param>
/// <param name="upStreamEndPoint"></param> /// <param name="upStreamEndPoint"></param>
...@@ -34,7 +34,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -34,7 +34,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
internal async Task<TcpConnection> CreateClient(string remoteHostName, int remotePort, internal async Task<TcpConnection> CreateClient(string remoteHostName, int remotePort,
List<SslApplicationProtocol> applicationProtocols, Version httpVersion, bool isHttps, bool isConnect, List<SslApplicationProtocol> applicationProtocols, Version httpVersion, bool decryptSsl, bool isConnect,
ProxyServer proxyServer, IPEndPoint upStreamEndPoint, ExternalProxy externalProxy, CancellationToken cancellationToken) ProxyServer proxyServer, IPEndPoint upStreamEndPoint, ExternalProxy externalProxy, CancellationToken cancellationToken)
{ {
bool useUpstreamProxy = false; bool useUpstreamProxy = false;
...@@ -71,22 +71,24 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -71,22 +71,24 @@ namespace Titanium.Web.Proxy.Network.Tcp
stream = new CustomBufferedStream(client.GetStream(), proxyServer.BufferSize); stream = new CustomBufferedStream(client.GetStream(), proxyServer.BufferSize);
if (useUpstreamProxy && (isConnect || isHttps)) if (useUpstreamProxy && (isConnect || decryptSsl))
{ {
var writer = new HttpRequestWriter(stream, proxyServer.BufferSize); var writer = new HttpRequestWriter(stream, proxyServer.BufferSize);
await writer.WriteLineAsync($"CONNECT {remoteHostName}:{remotePort} HTTP/{httpVersion}", cancellationToken); var connectRequest = new ConnectRequest
await writer.WriteLineAsync($"Host: {remoteHostName}:{remotePort}", cancellationToken); {
await writer.WriteLineAsync($"{KnownHeaders.Connection}: {KnownHeaders.ConnectionKeepAlive}", cancellationToken); OriginalUrl = $"{remoteHostName}:{remotePort}",
HttpVersion = httpVersion,
};
connectRequest.Headers.AddHeader(KnownHeaders.Connection, KnownHeaders.ConnectionKeepAlive);
if (!string.IsNullOrEmpty(externalProxy.UserName) && externalProxy.Password != null) if (!string.IsNullOrEmpty(externalProxy.UserName) && externalProxy.Password != null)
{ {
await HttpHeader.ProxyConnectionKeepAlive.WriteToStreamAsync(writer, cancellationToken); connectRequest.Headers.AddHeader(HttpHeader.ProxyConnectionKeepAlive);
await writer.WriteLineAsync(KnownHeaders.ProxyAuthorization + ": Basic " + connectRequest.Headers.AddHeader(HttpHeader.GetProxyAuthorizationHeader(externalProxy.UserName, externalProxy.Password));
Convert.ToBase64String(Encoding.UTF8.GetBytes(
externalProxy.UserName + ":" + externalProxy.Password)), cancellationToken);
} }
await writer.WriteLineAsync(cancellationToken); await writer.WriteRequestAsync(connectRequest, cancellationToken: cancellationToken);
using (var reader = new CustomBinaryReader(stream, proxyServer.BufferSize)) using (var reader = new CustomBinaryReader(stream, proxyServer.BufferSize))
{ {
...@@ -104,7 +106,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -104,7 +106,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
} }
} }
if (isHttps) if (decryptSsl)
{ {
var sslStream = new SslStream(stream, false, proxyServer.ValidateServerCertificate, var sslStream = new SslStream(stream, false, proxyServer.ValidateServerCertificate,
proxyServer.SelectClientCertificate); proxyServer.SelectClientCertificate);
...@@ -118,7 +120,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -118,7 +120,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
} }
// server connection is always HTTP 1.x, todo // server connection is always HTTP 1.x, todo
options.ApplicationProtocols = SslExtensions.Http11ProtocolAsList; //options.ApplicationProtocols = SslExtensions.Http11ProtocolAsList;
options.TargetHost = remoteHostName; options.TargetHost = remoteHostName;
options.ClientCertificates = null; options.ClientCertificates = null;
...@@ -143,7 +145,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -143,7 +145,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
UpStreamEndPoint = upStreamEndPoint, UpStreamEndPoint = upStreamEndPoint,
HostName = remoteHostName, HostName = remoteHostName,
Port = remotePort, Port = remotePort,
IsHttps = isHttps, IsHttps = decryptSsl,
UseUpstreamProxy = useUpstreamProxy, UseUpstreamProxy = useUpstreamProxy,
TcpClient = client, TcpClient = client,
StreamReader = new CustomBinaryReader(stream, proxyServer.BufferSize), StreamReader = new CustomBinaryReader(stream, proxyServer.BufferSize),
......
...@@ -58,29 +58,6 @@ namespace Titanium.Web.Proxy ...@@ -58,29 +58,6 @@ namespace Titanium.Web.Proxy
{ {
// read the request line // read the request line
string httpCmd = await clientStreamReader.ReadLineAsync(cancellationToken); string httpCmd = await clientStreamReader.ReadLineAsync(cancellationToken);
if (httpCmd == "PRI * HTTP/2.0")
{
// HTTP/2 Connection Preface
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(cancellationToken);
if (line != "SM") throw new Exception($"HTTP/2 Protocol violation. 'SM' expected, '{line}' received");
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, 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)) if (string.IsNullOrEmpty(httpCmd))
{ {
...@@ -101,7 +78,8 @@ namespace Titanium.Web.Proxy ...@@ -101,7 +78,8 @@ 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, cancellationToken); await HeaderParser.ReadHeaders(clientStreamReader, args.WebSession.Request.Headers,
cancellationToken);
Uri httpRemoteUri; Uri httpRemoteUri;
if (uriSchemeRegex.IsMatch(httpUrl)) if (uriSchemeRegex.IsMatch(httpUrl))
...@@ -153,7 +131,8 @@ namespace Titanium.Web.Proxy ...@@ -153,7 +131,8 @@ namespace Titanium.Web.Proxy
await InvokeBeforeResponse(args); await InvokeBeforeResponse(args);
//send the response //send the response
await clientStreamWriter.WriteResponseAsync(args.WebSession.Response, cancellationToken: cancellationToken); await clientStreamWriter.WriteResponseAsync(args.WebSession.Response,
cancellationToken: cancellationToken);
return; return;
} }
...@@ -214,7 +193,8 @@ namespace Titanium.Web.Proxy ...@@ -214,7 +193,8 @@ namespace Titanium.Web.Proxy
{ {
//prepare the prefix content //prepare the prefix content
await connection.StreamWriter.WriteLineAsync(httpCmd, cancellationToken); await connection.StreamWriter.WriteLineAsync(httpCmd, cancellationToken);
await connection.StreamWriter.WriteHeadersAsync(request.Headers, cancellationToken: cancellationToken); await connection.StreamWriter.WriteHeadersAsync(request.Headers,
cancellationToken: cancellationToken);
string httpStatus = await connection.StreamReader.ReadLineAsync(cancellationToken); string httpStatus = await connection.StreamReader.ReadLineAsync(cancellationToken);
Response.ParseResponseLine(httpStatus, out var responseVersion, Response.ParseResponseLine(httpStatus, out var responseVersion,
...@@ -224,11 +204,13 @@ namespace Titanium.Web.Proxy ...@@ -224,11 +204,13 @@ namespace Titanium.Web.Proxy
response.StatusCode = responseStatusCode; response.StatusCode = responseStatusCode;
response.StatusDescription = responseStatusDescription; response.StatusDescription = responseStatusDescription;
await HeaderParser.ReadHeaders(connection.StreamReader, response.Headers, cancellationToken); await HeaderParser.ReadHeaders(connection.StreamReader, response.Headers,
cancellationToken);
if (!args.IsTransparent) if (!args.IsTransparent)
{ {
await clientStreamWriter.WriteResponseAsync(response, cancellationToken: cancellationToken); await clientStreamWriter.WriteResponseAsync(response,
cancellationToken: cancellationToken);
} }
//If user requested call back then do it //If user requested call back then do it
......
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