培训考核三期,新版培训,网页版培训登录器
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

377 lines
16 KiB

#if !UNITY_WEBGL || UNITY_EDITOR
using System;
using System.Collections.Generic;
using System.IO;
#if !NETFX_CORE || UNITY_EDITOR
using System.Net.Security;
#endif
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
using BestHTTP.SecureProtocol.Org.BouncyCastle.Tls;
using BestHTTP.Connections.TLS;
using System.Threading;
#endif
#if NETFX_CORE
using System.Threading.Tasks;
using Windows.Networking.Sockets;
using TcpClient = BestHTTP.PlatformSupport.TcpClient.WinRT.TcpClient;
//Disable CD4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.
#pragma warning disable 4014
#else
using TcpClient = BestHTTP.PlatformSupport.TcpClient.General.TcpClient;
using System.Security.Cryptography.X509Certificates;
#endif
using BestHTTP.Timings;
namespace BestHTTP.Connections
{
public sealed class TCPConnector : IDisposable
{
public bool IsConnected { get { return this.Client != null && this.Client.Connected; } }
public string NegotiatedProtocol { get; private set; }
public TcpClient Client { get; private set; }
public Stream TopmostStream { get; private set; }
public Stream Stream { get; private set; }
public bool LeaveOpen { get; set; }
public void Connect(HTTPRequest request)
{
string negotiatedProtocol = HTTPProtocolFactory.W3C_HTTP1;
Uri uri =
#if !BESTHTTP_DISABLE_PROXY
request.HasProxy ? request.Proxy.Address :
#endif
request.CurrentUri;
#region TCP Connection
if (Client == null)
Client = new TcpClient();
if (!Client.Connected)
{
Client.ConnectTimeout = request.ConnectTimeout;
#if NETFX_CORE
Client.UseHTTPSProtocol =
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
!Request.UseAlternateSSL &&
#endif
HTTPProtocolFactory.IsSecureProtocol(uri);
#endif
if (HTTPManager.Logger.Level == Logger.Loglevels.All)
HTTPManager.Logger.Verbose("TCPConnector", string.Format("'{0}' - Connecting to {1}:{2}", request.CurrentUri.ToString(), uri.Host, uri.Port.ToString()), request.Context);
#if !NETFX_CORE && (!UNITY_WEBGL || UNITY_EDITOR)
bool changed = false;
int? sendBufferSize = null, receiveBufferSize = null;
if (HTTPManager.SendBufferSize.HasValue)
{
sendBufferSize = Client.SendBufferSize;
Client.SendBufferSize = HTTPManager.SendBufferSize.Value;
changed = true;
}
if (HTTPManager.ReceiveBufferSize.HasValue)
{
receiveBufferSize = Client.ReceiveBufferSize;
Client.ReceiveBufferSize = HTTPManager.ReceiveBufferSize.Value;
changed = true;
}
if (HTTPManager.Logger.Level == Logger.Loglevels.All)
{
if (changed)
HTTPManager.Logger.Verbose("TCPConnector", string.Format("'{0}' - Buffer sizes changed - Send from: {1} to: {2}, Receive from: {3} to: {4}, Blocking: {5}",
request.CurrentUri.ToString(),
sendBufferSize,
Client.SendBufferSize,
receiveBufferSize,
Client.ReceiveBufferSize,
Client.Client.Blocking),
request.Context);
else
HTTPManager.Logger.Verbose("TCPConnector", string.Format("'{0}' - Buffer sizes - Send: {1} Receive: {2} Blocking: {3}", request.CurrentUri.ToString(), Client.SendBufferSize, Client.ReceiveBufferSize, Client.Client.Blocking), request.Context);
}
#endif
#if NETFX_CORE && !UNITY_EDITOR && !ENABLE_IL2CPP
try
{
Client.Connect(uri.Host, uri.Port);
}
finally
{
request.Timing.Add(TimingEventNames.TCP_Connection);
}
#else
System.Net.IPAddress[] addresses = null;
try
{
if (Client.ConnectTimeout > TimeSpan.Zero)
{
// https://forum.unity3d.com/threads/best-http-released.200006/page-37#post-3150972
using (System.Threading.ManualResetEvent mre = new System.Threading.ManualResetEvent(false))
{
IAsyncResult result = System.Net.Dns.BeginGetHostAddresses(uri.Host, (res) => { try { mre.Set(); } catch { } }, null);
bool success = mre.WaitOne(Client.ConnectTimeout);
if (success)
{
addresses = System.Net.Dns.EndGetHostAddresses(result);
}
else
{
throw new TimeoutException("DNS resolve timed out!");
}
}
}
else
{
addresses = System.Net.Dns.GetHostAddresses(uri.Host);
}
}
finally
{
request.Timing.Add(TimingEventNames.DNS_Lookup);
}
if (HTTPManager.Logger.Level == Logger.Loglevels.All)
HTTPManager.Logger.Verbose("TCPConnector", string.Format("'{0}' - DNS Query returned with addresses: {1}", request.CurrentUri.ToString(), addresses != null ? addresses.Length : -1), request.Context);
if (request.IsCancellationRequested)
throw new Exception("IsCancellationRequested");
try
{
Client.Connect(addresses, uri.Port, request);
}
finally
{
request.Timing.Add(TimingEventNames.TCP_Connection);
}
if (request.IsCancellationRequested)
throw new Exception("IsCancellationRequested");
#endif
if (HTTPManager.Logger.Level <= Logger.Loglevels.Information)
HTTPManager.Logger.Information("TCPConnector", "Connected to " + uri.Host + ":" + uri.Port.ToString(), request.Context);
}
else if (HTTPManager.Logger.Level <= Logger.Loglevels.Information)
HTTPManager.Logger.Information("TCPConnector", "Already connected to " + uri.Host + ":" + uri.Port.ToString(), request.Context);
#endregion
if (Stream == null)
{
bool isSecure = HTTPProtocolFactory.IsSecureProtocol(request.CurrentUri);
// set the stream to Client.GetStream() so the proxy, if there's any can use it directly.
this.Stream = this.TopmostStream = Client.GetStream();
/*if (Stream.CanTimeout)
Stream.ReadTimeout = Stream.WriteTimeout = (int)Request.Timeout.TotalMilliseconds;*/
#if !BESTHTTP_DISABLE_PROXY
if (request.HasProxy)
{
try
{
request.Proxy.Connect(this.Stream, request);
}
finally
{
request.Timing.Add(TimingEventNames.Proxy_Negotiation);
}
}
if (request.IsCancellationRequested)
throw new Exception("IsCancellationRequested");
#endif
// proxy connect is done, we can set the stream to a buffered one. HTTPProxy requires the raw NetworkStream for HTTPResponse's ReadUnknownSize!
this.Stream = this.TopmostStream = new BufferedReadNetworkStream(Client.GetStream(), Math.Max(8 * 1024, HTTPManager.ReceiveBufferSize ?? Client.ReceiveBufferSize));
// We have to use Request.CurrentUri here, because uri can be a proxy uri with a different protocol
if (isSecure)
{
DateTime tlsNegotiationStartedAt = DateTime.Now;
#region SSL Upgrade
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
if (HTTPManager.UseAlternateSSLDefaultValue)
{
var handler = new TlsClientProtocol(this.Stream);
List<ProtocolName> protocols = new List<ProtocolName>();
#if !BESTHTTP_DISABLE_HTTP2
SupportedProtocols protocol = HTTPProtocolFactory.GetProtocolFromUri(request.CurrentUri);
if (protocol == SupportedProtocols.HTTP && request.IsKeepAlive)
{
// http/2 over tls (https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids)
protocols.Add(ProtocolName.AsUtf8Encoding(HTTPProtocolFactory.W3C_HTTP2));
}
#endif
protocols.Add(ProtocolName.AsUtf8Encoding(HTTPProtocolFactory.W3C_HTTP1));
AbstractTls13Client tlsClient = null;
if (HTTPManager.TlsClientFactory == null)
{
tlsClient = HTTPManager.DefaultTlsClientFactory(request, protocols);
}
else
{
try
{
tlsClient = HTTPManager.TlsClientFactory(request, protocols);
}
catch (Exception ex)
{
HTTPManager.Logger.Exception(nameof(TCPConnector), nameof(HTTPManager.TlsClientFactory), ex, request.Context);
}
if (tlsClient == null)
tlsClient = HTTPManager.DefaultTlsClientFactory(request, protocols);
}
//tlsClient.LoggingContext = request.Context;
handler.Connect(tlsClient);
var applicationProtocol = tlsClient.GetNegotiatedApplicationProtocol();
if (!string.IsNullOrEmpty(applicationProtocol))
negotiatedProtocol = applicationProtocol;
Stream = handler.Stream;
}
else
#endif
{
#if !NETFX_CORE
SslStream sslStream = null;
if (HTTPManager.ClientCertificationProvider == null)
sslStream = new SslStream(Client.GetStream(), false, (sender, cert, chain, errors) =>
{
if (HTTPManager.DefaultCertificationValidator != null)
return HTTPManager.DefaultCertificationValidator(request, cert, chain, errors);
else
return true;
});
else
sslStream = new SslStream(Client.GetStream(), false, (sender, cert, chain, errors) =>
{
if (HTTPManager.DefaultCertificationValidator != null)
return HTTPManager.DefaultCertificationValidator(request, cert, chain, errors);
else
return true;
},
(object sender, string targetHost, X509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers) =>
{
return HTTPManager.ClientCertificationProvider(request, targetHost, localCertificates, remoteCertificate, acceptableIssuers);
});
if (!sslStream.IsAuthenticated)
{
#if !BESTHTTP_DISABLE_HTTP2 && !BESTHTTP_DISABLE_ALTERNATE_SSL && false
List<SslApplicationProtocol> protocols = new List<SslApplicationProtocol>();
SupportedProtocols protocol = HTTPProtocolFactory.GetProtocolFromUri(request.CurrentUri);
if (protocol == SupportedProtocols.HTTP && request.IsKeepAlive)
{
// http/2 over tls (https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids)
protocols.Add(new SslApplicationProtocol(HTTPProtocolFactory.W3C_HTTP2));
}
protocols.Add(new SslApplicationProtocol(HTTPProtocolFactory.W3C_HTTP1));
SslClientAuthenticationOptions options = new SslClientAuthenticationOptions();
options.ApplicationProtocols = protocols;
options.TargetHost = request.CurrentUri.Host;
var task = sslStream.AuthenticateAsClientAsync(options, default(System.Threading.CancellationToken));
task.Wait();
try
{
negotiatedProtocol = System.Text.Encoding.UTF8.GetString(sslStream.NegotiatedApplicationProtocol.Protocol.Span);
}
catch (Exception ex)
{
HTTPManager.Logger.Exception(nameof(TCPConnector), "Accessing SslStream's NegotiatedApplicationProtocol throwed an exception, falling back using HTTP/1.1", ex, request.Context);
negotiatedProtocol = HTTPProtocolFactory.W3C_HTTP1;
}
#else
sslStream.AuthenticateAsClient(request.CurrentUri.Host);
#endif
}
Stream = sslStream;
#else
Stream = Client.GetStream();
#endif
}
#endregion
request.Timing.Add(TimingEventNames.TLS_Negotiation, DateTime.Now - tlsNegotiationStartedAt);
}
}
this.NegotiatedProtocol = negotiatedProtocol;
}
public void Close()
{
if (Client != null && !this.LeaveOpen)
{
try
{
if (Stream != null)
Stream.Close();
}
catch { }
finally
{
Stream = null;
}
try
{
if (TopmostStream != null)
TopmostStream.Close();
}
catch { }
finally
{
TopmostStream = null;
}
try
{
Client.Close();
}
catch { }
finally
{
Client = null;
}
}
}
public void Dispose()
{
Close();
}
}
}
#endif