Unverified Commit 08167b4d authored by Jehonathan Thomas's avatar Jehonathan Thomas Committed by GitHub

Merge pull request #496 from justcoding121/master

Dns resolve from code
parents c3fc1d35 fb33defa
......@@ -15,7 +15,7 @@
"**/*.Basic.csproj/": true,
"**/*.Docs.csproj/": true,
"**/*.Proxy.csproj/": true,
"**/*.Proxy.csproj" : true
"**/*.Mono.csproj" : true
},
"search.exclude": {
"**/.build": true,
......@@ -32,6 +32,6 @@
"**/*.Basic.csproj/": true,
"**/*.Docs.csproj/": true,
"**/*.Proxy.csproj/": true,
"**/*.Proxy.csproj" : true
"**/*.Mono.csproj" : true
}
}
\ No newline at end of file
{
"fileOptions": {
"excludeSearchPatterns": [
"**/*.sln",
"**/*.Docs.csproj",
"**/tests/",
"**/Titanium.Web.Proxy.Examples.Wpf/",
......
......@@ -22,6 +22,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// </summary>
internal class TcpConnectionFactory : IDisposable
{
//Tcp server connection pool cache
private readonly ConcurrentDictionary<string, ConcurrentQueue<TcpServerConnection>> cache
= new ConcurrentDictionary<string, ConcurrentQueue<TcpServerConnection>>();
......@@ -74,10 +75,10 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <summary>
/// Gets the connection cache key.
/// </summary>
/// <param name="args">The session event arguments.</param>
/// <param name="session">The session event arguments.</param>
/// <param name="applicationProtocol"></param>
/// <returns></returns>
internal async Task<string> GetConnectionCacheKey(ProxyServer server, SessionEventArgsBase args,
internal async Task<string> GetConnectionCacheKey(ProxyServer server, SessionEventArgsBase session,
SslApplicationProtocol applicationProtocol)
{
List<SslApplicationProtocol> applicationProtocols = null;
......@@ -88,19 +89,19 @@ namespace Titanium.Web.Proxy.Network.Tcp
ExternalProxy customUpStreamProxy = null;
bool isHttps = args.IsHttps;
bool isHttps = session.IsHttps;
if (server.GetCustomUpStreamProxyFunc != null)
{
customUpStreamProxy = await server.GetCustomUpStreamProxyFunc(args);
customUpStreamProxy = await server.GetCustomUpStreamProxyFunc(session);
}
args.CustomUpStreamProxyUsed = customUpStreamProxy;
session.CustomUpStreamProxyUsed = customUpStreamProxy;
return GetConnectionCacheKey(
args.WebSession.Request.RequestUri.Host,
args.WebSession.Request.RequestUri.Port,
session.WebSession.Request.RequestUri.Host,
session.WebSession.Request.RequestUri.Port,
isHttps, applicationProtocols,
server, args.WebSession.UpStreamEndPoint ?? server.UpStreamEndPoint,
server, session.WebSession.UpStreamEndPoint ?? server.UpStreamEndPoint,
customUpStreamProxy ?? (isHttps ? server.UpStreamHttpsProxy : server.UpStreamHttpProxy));
}
......@@ -108,12 +109,12 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <summary>
/// Create a server connection.
/// </summary>
/// <param name="args">The session event arguments.</param>
/// <param name="session">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>
internal Task<TcpServerConnection> GetServerConnection(ProxyServer server, SessionEventArgsBase args, bool isConnect,
internal Task<TcpServerConnection> GetServerConnection(ProxyServer server, SessionEventArgsBase session, bool isConnect,
SslApplicationProtocol applicationProtocol, bool noCache, CancellationToken cancellationToken)
{
List<SslApplicationProtocol> applicationProtocols = null;
......@@ -122,36 +123,36 @@ namespace Titanium.Web.Proxy.Network.Tcp
applicationProtocols = new List<SslApplicationProtocol> { applicationProtocol };
}
return GetServerConnection(server, args, isConnect, applicationProtocols, noCache, cancellationToken);
return GetServerConnection(server, session, isConnect, applicationProtocols, noCache, cancellationToken);
}
/// <summary>
/// Create a server connection.
/// </summary>
/// <param name="args">The session event arguments.</param>
/// <param name="session">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>
internal async Task<TcpServerConnection> GetServerConnection(ProxyServer server, SessionEventArgsBase args, bool isConnect,
internal async Task<TcpServerConnection> GetServerConnection(ProxyServer server, SessionEventArgsBase session, bool isConnect,
List<SslApplicationProtocol> applicationProtocols, bool noCache, CancellationToken cancellationToken)
{
ExternalProxy customUpStreamProxy = null;
bool isHttps = args.IsHttps;
bool isHttps = session.IsHttps;
if (server.GetCustomUpStreamProxyFunc != null)
{
customUpStreamProxy = await server.GetCustomUpStreamProxyFunc(args);
customUpStreamProxy = await server.GetCustomUpStreamProxyFunc(session);
}
args.CustomUpStreamProxyUsed = customUpStreamProxy;
session.CustomUpStreamProxyUsed = customUpStreamProxy;
return await GetServerConnection(
args.WebSession.Request.RequestUri.Host,
args.WebSession.Request.RequestUri.Port,
args.WebSession.Request.HttpVersion,
session.WebSession.Request.RequestUri.Host,
session.WebSession.Request.RequestUri.Port,
session.WebSession.Request.HttpVersion,
isHttps, applicationProtocols, isConnect,
server, args.WebSession.UpStreamEndPoint ?? server.UpStreamEndPoint,
server, session, session.WebSession.UpStreamEndPoint ?? server.UpStreamEndPoint,
customUpStreamProxy ?? (isHttps ? server.UpStreamHttpsProxy : server.UpStreamHttpProxy),
noCache, cancellationToken);
}
......@@ -172,7 +173,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <returns></returns>
internal async Task<TcpServerConnection> GetServerConnection(string remoteHostName, int remotePort,
Version httpVersion, bool isHttps, List<SslApplicationProtocol> applicationProtocols, bool isConnect,
ProxyServer proxyServer, IPEndPoint upStreamEndPoint, ExternalProxy externalProxy,
ProxyServer proxyServer, SessionEventArgsBase session, IPEndPoint upStreamEndPoint, ExternalProxy externalProxy,
bool noCache, CancellationToken cancellationToken)
{
var cacheKey = GetConnectionCacheKey(remoteHostName, remotePort,
......@@ -203,7 +204,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
}
var connection = await createServerConnection(remoteHostName, remotePort, httpVersion, isHttps,
applicationProtocols, isConnect, proxyServer, upStreamEndPoint, externalProxy, cancellationToken);
applicationProtocols, isConnect, proxyServer, session, upStreamEndPoint, externalProxy, cancellationToken);
connection.CacheKey = cacheKey;
......@@ -220,13 +221,14 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <param name="applicationProtocols">The list of HTTPS application level protocol to negotiate if needed.</param>
/// <param name="isConnect">Is this a CONNECT request.</param>
/// <param name="proxyServer">The current ProxyServer instance.</param>
/// <param name="session">The http session.</param>
/// <param name="upStreamEndPoint">The local upstream endpoint to make request via.</param>
/// <param name="externalProxy">The external proxy to make request via.</param>
/// <param name="cancellationToken">The cancellation token for this async task.</param>
/// <returns></returns>
private async Task<TcpServerConnection> createServerConnection(string remoteHostName, int remotePort,
Version httpVersion, bool isHttps, List<SslApplicationProtocol> applicationProtocols, bool isConnect,
ProxyServer proxyServer, IPEndPoint upStreamEndPoint, ExternalProxy externalProxy,
ProxyServer proxyServer, SessionEventArgsBase session, IPEndPoint upStreamEndPoint, ExternalProxy externalProxy,
CancellationToken cancellationToken)
{
//deny connection to proxy end points to avoid infinite connection loop.
......@@ -282,16 +284,37 @@ namespace Titanium.Web.Proxy.Network.Tcp
tcpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
}
// If this proxy uses another external proxy then create a tunnel request for HTTP/HTTPS connections
if (useUpstreamProxy)
var hostname = useUpstreamProxy ? externalProxy.HostName : remoteHostName;
var port = useUpstreamProxy ? externalProxy.Port : remotePort;
var ipHostEntry = await Dns.GetHostEntryAsync(hostname);
if (ipHostEntry == null || ipHostEntry.AddressList.Length == 0)
{
await tcpClient.ConnectAsync(externalProxy.HostName, externalProxy.Port);
throw new Exception($"Could not resolve the hostname {hostname}");
}
else
session.TimeLine["Dns Resolved"] = DateTime.Now;
var ipAddresses = ipHostEntry.AddressList;
for (int i = 0; i < ipAddresses.Length; i++)
{
await tcpClient.ConnectAsync(remoteHostName, remotePort);
try
{
await tcpClient.ConnectAsync(ipAddresses[i], port);
break;
}
catch (Exception e)
{
if (i == ipAddresses.Length - 1)
{
throw new Exception($"Could not establish connection to {hostname}", e);
}
}
}
session.TimeLine["Connection Established"] = DateTime.Now;
await proxyServer.InvokeConnectionCreateEvent(tcpClient, false);
stream = new CustomBufferedStream(tcpClient.GetStream(), proxyServer.BufferPool, proxyServer.BufferSize);
......@@ -347,6 +370,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
#if NETCOREAPP2_1
negotiatedApplicationProtocol = sslStream.NegotiatedApplicationProtocol;
#endif
session.TimeLine["HTTPS Established"] = DateTime.Now;
}
}
catch (Exception)
......
......@@ -94,8 +94,6 @@ namespace Titanium.Web.Proxy
bool userTrustRootCertificate = true, bool machineTrustRootCertificate = false,
bool trustRootCertificateAsAdmin = false)
{
// default values
ConnectionTimeOutSeconds = 60;
if (BufferPool == null)
{
......@@ -186,7 +184,7 @@ namespace Titanium.Web.Proxy
/// This will also determine the pool eviction time when connection pool is enabled.
/// Default value is 60 seconds.
/// </summary>
public int ConnectionTimeOutSeconds { get; set; }
public int ConnectionTimeOutSeconds { get; set; } = 60;
/// <summary>
/// Maximum number of concurrent connections per remote host in cache.
......
......@@ -207,7 +207,7 @@ namespace Titanium.Web.Proxy
//for connection pool, retry fails until cache is exhausted.
var result = await retryPolicy<ServerConnectionException>().ExecuteAsync(async (serverConnection) =>
{
args.TimeLine["Server Connection Created"] = DateTime.Now;
args.TimeLine["Connection Ready"] = DateTime.Now;
// if upgrading to websocket then relay the request without reading the contents
if (request.UpgradeToWebSocket)
......@@ -369,6 +369,8 @@ namespace Titanium.Web.Proxy
}
}
args.TimeLine["Request Sent"] = DateTime.Now;
// If not expectation failed response was returned by server then parse response
if (!request.ExpectationFailed)
{
......
......@@ -69,7 +69,7 @@ namespace Titanium.Web.Proxy
//it could cause floating server connections when client exits
prefetchConnectionTask = tcpConnectionFactory.GetServerConnection(httpsHostName, endPoint.Port,
httpVersion: null, isHttps: true, applicationProtocols: null, isConnect: false,
proxyServer: this, upStreamEndPoint: UpStreamEndPoint, externalProxy: UpStreamHttpsProxy,
proxyServer: this, session: null, upStreamEndPoint: UpStreamEndPoint, externalProxy: UpStreamHttpsProxy,
noCache: false, cancellationToken: CancellationToken.None);
}
......@@ -102,7 +102,7 @@ namespace Titanium.Web.Proxy
{
var connection = await tcpConnectionFactory.GetServerConnection(httpsHostName, endPoint.Port,
httpVersion: null, isHttps: false, applicationProtocols: null,
isConnect: true, proxyServer: this, upStreamEndPoint: UpStreamEndPoint,
isConnect: true, proxyServer: this, session:null, upStreamEndPoint: UpStreamEndPoint,
externalProxy: UpStreamHttpsProxy, noCache: true, cancellationToken: cancellationToken);
try
......
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