Commit 49d94058 authored by justcoding121's avatar justcoding121

refactor connection factory

parent db6a0291
...@@ -151,7 +151,7 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -151,7 +151,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
private Task OnBeforeTunnelConnectResponse(object sender, TunnelConnectSessionEventArgs e) private Task OnBeforeTunnelConnectResponse(object sender, TunnelConnectSessionEventArgs e)
{ {
return default; return Task.FromResult(false);
} }
// intecept & cancel redirect or update requests // intecept & cancel redirect or update requests
......
...@@ -140,7 +140,7 @@ namespace Titanium.Web.Proxy ...@@ -140,7 +140,7 @@ namespace Titanium.Web.Proxy
{ {
// test server HTTP/2 support // test server HTTP/2 support
// todo: this is a hack, because Titanium does not support HTTP protocol changing currently // todo: this is a hack, because Titanium does not support HTTP protocol changing currently
var connection = await getServerConnection(connectArgs, true, var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs, true,
SslExtensions.Http2ProtocolAsList, true, cancellationToken); SslExtensions.Http2ProtocolAsList, true, cancellationToken);
http2Supported = connection.NegotiatedApplicationProtocol == SslApplicationProtocol.Http2; http2Supported = connection.NegotiatedApplicationProtocol == SslApplicationProtocol.Http2;
...@@ -153,7 +153,7 @@ namespace Titanium.Web.Proxy ...@@ -153,7 +153,7 @@ namespace Titanium.Web.Proxy
//don't pass cancellation token here //don't pass cancellation token here
//it could cause floating server connections when client exits //it could cause floating server connections when client exits
prefetchConnectionTask = getServerConnection(connectArgs, true, prefetchConnectionTask = tcpConnectionFactory.GetServerConnection(this, connectArgs, true,
null, false, CancellationToken.None); null, false, CancellationToken.None);
try try
...@@ -214,7 +214,7 @@ namespace Titanium.Web.Proxy ...@@ -214,7 +214,7 @@ namespace Titanium.Web.Proxy
// create new connection to server. // create new connection to server.
// If we detected that client tunnel CONNECTs without SSL by checking for empty client hello then // If we detected that client tunnel CONNECTs without SSL by checking for empty client hello then
// this connection should not be HTTPS. // this connection should not be HTTPS.
var connection = await getServerConnection(connectArgs, var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs,
true, SslExtensions.Http2ProtocolAsList, true, cancellationToken); true, SslExtensions.Http2ProtocolAsList, true, cancellationToken);
try try
...@@ -284,7 +284,7 @@ namespace Titanium.Web.Proxy ...@@ -284,7 +284,7 @@ namespace Titanium.Web.Proxy
throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received"); throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received");
} }
var connection = await getServerConnection(connectArgs, true, var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs, true,
SslExtensions.Http2ProtocolAsList, true, SslExtensions.Http2ProtocolAsList, true,
cancellationToken); cancellationToken);
try try
......
...@@ -196,7 +196,7 @@ namespace Titanium.Web.Proxy ...@@ -196,7 +196,7 @@ namespace Titanium.Web.Proxy
// only gets hit when connection pool is disabled. // only gets hit when connection pool is disabled.
// or when prefetch task has a unexpectedly different connection. // or when prefetch task has a unexpectedly different connection.
if (connection != null if (connection != null
&& (await getConnectionCacheKey(args, && (await tcpConnectionFactory.GetConnectionCacheKey(this, args,
clientConnection.NegotiatedApplicationProtocol) clientConnection.NegotiatedApplicationProtocol)
!= connection.CacheKey)) != connection.CacheKey))
{ {
...@@ -205,9 +205,10 @@ namespace Titanium.Web.Proxy ...@@ -205,9 +205,10 @@ namespace Titanium.Web.Proxy
} }
//a connection generator task with captured parameters via closure. //a connection generator task with captured parameters via closure.
Func<Task<TcpServerConnection>> generator = () => getServerConnection(args, false, Func<Task<TcpServerConnection>> generator = () =>
clientConnection.NegotiatedApplicationProtocol, tcpConnectionFactory.GetServerConnection(this, args, false,
false, cancellationToken); clientConnection.NegotiatedApplicationProtocol,
false, cancellationToken);
//for connection pool, retry fails until cache is exhausted. //for connection pool, retry fails until cache is exhausted.
await retryPolicy<ServerConnectionException>().ExecuteAsync(async (serverConnection) => await retryPolicy<ServerConnectionException>().ExecuteAsync(async (serverConnection) =>
...@@ -373,62 +374,6 @@ namespace Titanium.Web.Proxy ...@@ -373,62 +374,6 @@ namespace Titanium.Web.Proxy
} }
} }
/// <summary>
/// Handle upgrade to websocket
/// </summary>
private async Task handleWebSocketUpgrade(string httpCmd,
SessionEventArgs args, Request request, Response response,
CustomBufferedStream clientStream, HttpResponseWriter clientStreamWriter,
TcpServerConnection serverConnection,
CancellationTokenSource cancellationTokenSource, CancellationToken cancellationToken)
{
// prepare the prefix content
await serverConnection.StreamWriter.WriteLineAsync(httpCmd, cancellationToken);
await serverConnection.StreamWriter.WriteHeadersAsync(request.Headers,
cancellationToken: cancellationToken);
string httpStatus;
try
{
httpStatus = await serverConnection.Stream.ReadLineAsync(cancellationToken);
if (httpStatus == null)
{
throw new ServerConnectionException("Server connection was closed.");
}
}
catch (Exception e) when (!(e is ServerConnectionException))
{
throw new ServerConnectionException("Server connection was closed.", e);
}
Response.ParseResponseLine(httpStatus, out var responseVersion,
out int responseStatusCode,
out string responseStatusDescription);
response.HttpVersion = responseVersion;
response.StatusCode = responseStatusCode;
response.StatusDescription = responseStatusDescription;
await HeaderParser.ReadHeaders(serverConnection.Stream, response.Headers,
cancellationToken);
if (!args.IsTransparent)
{
await clientStreamWriter.WriteResponseAsync(response,
cancellationToken: cancellationToken);
}
// If user requested call back then do it
if (!args.WebSession.Response.Locked)
{
await invokeBeforeResponse(args);
}
await TcpHelper.SendRaw(clientStream, serverConnection.Stream, BufferPool, BufferSize,
(buffer, offset, count) => { args.OnDataSent(buffer, offset, count); },
(buffer, offset, count) => { args.OnDataReceived(buffer, offset, count); },
cancellationTokenSource, ExceptionFunc);
}
/// <summary> /// <summary>
/// Prepare the request headers so that we can avoid encodings not parsable by this proxy /// Prepare the request headers so that we can avoid encodings not parsable by this proxy
/// </summary> /// </summary>
...@@ -455,92 +400,6 @@ namespace Titanium.Web.Proxy ...@@ -455,92 +400,6 @@ namespace Titanium.Web.Proxy
requestHeaders.FixProxyHeaders(); requestHeaders.FixProxyHeaders();
} }
/// <summary>
/// Gets the connection cache key.
/// </summary>
/// <param name="args">The session event arguments.</param>
/// <param name="applicationProtocol"></param>
/// <returns></returns>
private async Task<string> getConnectionCacheKey(SessionEventArgsBase args,
SslApplicationProtocol applicationProtocol)
{
List<SslApplicationProtocol> applicationProtocols = null;
if (applicationProtocol != default)
{
applicationProtocols = new List<SslApplicationProtocol> { applicationProtocol };
}
ExternalProxy customUpStreamProxy = null;
bool isHttps = args.IsHttps;
if (GetCustomUpStreamProxyFunc != null)
{
customUpStreamProxy = await GetCustomUpStreamProxyFunc(args);
}
args.CustomUpStreamProxyUsed = customUpStreamProxy;
return tcpConnectionFactory.GetConnectionCacheKey(
args.WebSession.Request.RequestUri.Host,
args.WebSession.Request.RequestUri.Port,
isHttps, applicationProtocols,
this, args.WebSession.UpStreamEndPoint ?? UpStreamEndPoint,
customUpStreamProxy ?? (isHttps ? UpStreamHttpsProxy : UpStreamHttpProxy));
}
/// <summary>
/// Create a server connection.
/// </summary>
/// <param name="args">The session event arguments.</param>
/// <param name="isConnect">Is this a CONNECT request.</param>
/// <param name="applicationProtocol"></param>
/// <param name="cancellationToken">The cancellation token for this async task.</param>
/// <returns></returns>
private Task<TcpServerConnection> getServerConnection(SessionEventArgsBase args, bool isConnect,
SslApplicationProtocol applicationProtocol, bool noCache, CancellationToken cancellationToken)
{
List<SslApplicationProtocol> applicationProtocols = null;
if (applicationProtocol != default)
{
applicationProtocols = new List<SslApplicationProtocol> { applicationProtocol };
}
return getServerConnection(args, isConnect, applicationProtocols, noCache, cancellationToken);
}
/// <summary>
/// Create a server connection.
/// </summary>
/// <param name="args">The session event arguments.</param>
/// <param name="isConnect">Is this a CONNECT request.</param>
/// <param name="applicationProtocols"></param>
/// <param name="cancellationToken">The cancellation token for this async task.</param>
/// <returns></returns>
private async Task<TcpServerConnection> getServerConnection(SessionEventArgsBase args, bool isConnect,
List<SslApplicationProtocol> applicationProtocols, bool noCache, CancellationToken cancellationToken)
{
ExternalProxy customUpStreamProxy = null;
bool isHttps = args.IsHttps;
if (GetCustomUpStreamProxyFunc != null)
{
customUpStreamProxy = await GetCustomUpStreamProxyFunc(args);
}
args.CustomUpStreamProxyUsed = customUpStreamProxy;
return await tcpConnectionFactory.GetClient(
args.WebSession.Request.RequestUri.Host,
args.WebSession.Request.RequestUri.Port,
args.WebSession.Request.HttpVersion,
isHttps, applicationProtocols, isConnect,
this, args.WebSession.UpStreamEndPoint ?? UpStreamEndPoint,
customUpStreamProxy ?? (isHttps ? UpStreamHttpsProxy : UpStreamHttpProxy),
noCache, cancellationToken);
}
/// <summary> /// <summary>
/// Invoke before request handler if it is set. /// Invoke before request handler if it is set.
/// </summary> /// </summary>
......
...@@ -65,7 +65,7 @@ namespace Titanium.Web.Proxy ...@@ -65,7 +65,7 @@ namespace Titanium.Web.Proxy
{ {
//don't pass cancellation token here //don't pass cancellation token here
//it could cause floating server connections when client exits //it could cause floating server connections when client exits
prefetchConnectionTask = tcpConnectionFactory.GetClient(httpsHostName, endPoint.Port, prefetchConnectionTask = tcpConnectionFactory.GetServerConnection(httpsHostName, endPoint.Port,
null, true, null, false, this, null, true, null, false, this,
UpStreamEndPoint, UpStreamHttpsProxy, false, CancellationToken.None); UpStreamEndPoint, UpStreamHttpsProxy, false, CancellationToken.None);
...@@ -96,7 +96,7 @@ namespace Titanium.Web.Proxy ...@@ -96,7 +96,7 @@ namespace Titanium.Web.Proxy
} }
else else
{ {
var connection = await tcpConnectionFactory.GetClient(httpsHostName, endPoint.Port, var connection = await tcpConnectionFactory.GetServerConnection(httpsHostName, endPoint.Port,
null, false, null, null, false, null,
true, this, UpStreamEndPoint, UpStreamHttpsProxy, true, cancellationToken); true, this, UpStreamEndPoint, UpStreamHttpsProxy, true, cancellationToken);
......
using StreamExtended.Network;
using System;
using System.Threading;
using System.Threading.Tasks;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Exceptions;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Network.Tcp;
namespace Titanium.Web.Proxy
{
public partial class ProxyServer
{
/// <summary>
/// Handle upgrade to websocket
/// </summary>
private async Task handleWebSocketUpgrade(string httpCmd,
SessionEventArgs args, Request request, Response response,
CustomBufferedStream clientStream, HttpResponseWriter clientStreamWriter,
TcpServerConnection serverConnection,
CancellationTokenSource cancellationTokenSource, CancellationToken cancellationToken)
{
// prepare the prefix content
await serverConnection.StreamWriter.WriteLineAsync(httpCmd, cancellationToken);
await serverConnection.StreamWriter.WriteHeadersAsync(request.Headers,
cancellationToken: cancellationToken);
string httpStatus;
try
{
httpStatus = await serverConnection.Stream.ReadLineAsync(cancellationToken);
if (httpStatus == null)
{
throw new ServerConnectionException("Server connection was closed.");
}
}
catch (Exception e) when (!(e is ServerConnectionException))
{
throw new ServerConnectionException("Server connection was closed.", e);
}
Response.ParseResponseLine(httpStatus, out var responseVersion,
out int responseStatusCode,
out string responseStatusDescription);
response.HttpVersion = responseVersion;
response.StatusCode = responseStatusCode;
response.StatusDescription = responseStatusDescription;
await HeaderParser.ReadHeaders(serverConnection.Stream, response.Headers,
cancellationToken);
if (!args.IsTransparent)
{
await clientStreamWriter.WriteResponseAsync(response,
cancellationToken: cancellationToken);
}
// If user requested call back then do it
if (!args.WebSession.Response.Locked)
{
await invokeBeforeResponse(args);
}
await TcpHelper.SendRaw(clientStream, serverConnection.Stream, BufferPool, BufferSize,
(buffer, offset, count) => { args.OnDataSent(buffer, offset, count); },
(buffer, offset, count) => { args.OnDataReceived(buffer, offset, count); },
cancellationTokenSource, ExceptionFunc);
}
}
}
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