培训考核三期,新版培训,网页版培训登录器
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.

262 lines
9.4 KiB

#if !UNITY_WEBGL || UNITY_EDITOR
using System;
#if !BESTHTTP_DISABLE_ALTERNATE_SSL
using BestHTTP.SecureProtocol.Org.BouncyCastle.Tls;
#endif
using BestHTTP.Core;
using BestHTTP.Timings;
namespace BestHTTP.Connections
{
/// <summary>
/// Represents and manages a connection to a server.
/// </summary>
public sealed class HTTPConnection : ConnectionBase
{
public TCPConnector connector;
public IHTTPRequestHandler requestHandler;
public override TimeSpan KeepAliveTime {
get {
if (this.requestHandler != null && this.requestHandler.KeepAlive != null)
{
if (this.requestHandler.KeepAlive.MaxRequests > 0)
{
if (base.KeepAliveTime < this.requestHandler.KeepAlive.TimeOut)
return base.KeepAliveTime;
else
return this.requestHandler.KeepAlive.TimeOut;
}
else
return TimeSpan.Zero;
}
return base.KeepAliveTime;
}
protected set
{
base.KeepAliveTime = value;
}
}
public override bool CanProcessMultiple
{
get
{
if (this.requestHandler != null)
return this.requestHandler.CanProcessMultiple;
return base.CanProcessMultiple;
}
}
internal HTTPConnection(string serverAddress)
:base(serverAddress)
{}
public override bool TestConnection()
{
#if !NETFX_CORE
try
{
#if !BESTHTTP_DISABLE_ALTERNATE_SSL
TlsStream stream = (this.connector?.Stream as TlsStream);
if (stream != null && stream.Protocol != null)
{
bool locked = stream.Protocol.TryEnterApplicationDataLock(0);
try
{
if (locked && this.connector.Client.Available > 0)
{
try
{
var available = stream.Protocol.TestApplicationData();
return !stream.Protocol.IsClosed;
}
catch
{
return false;
}
}
}
finally
{
if (locked)
stream.Protocol.ExitApplicationDataLock();
}
}
#endif
bool connected = this.connector.Client.Connected;
return connected;
}
catch
{
return false;
}
#else
return base.TestConnection();
#endif
}
internal override void Process(HTTPRequest request)
{
this.LastProcessedUri = request.CurrentUri;
if (this.requestHandler == null || !this.requestHandler.HasCustomRequestProcessor)
base.Process(request);
else
{
this.requestHandler.Process(request);
LastProcessTime = DateTime.Now;
}
}
protected override void ThreadFunc()
{
if (this.CurrentRequest.IsRedirected)
this.CurrentRequest.Timing.Add(TimingEventNames.Queued_For_Redirection);
else
this.CurrentRequest.Timing.Add(TimingEventNames.Queued);
if (this.connector != null && !this.connector.IsConnected)
{
// this will send the request back to the queue
RequestEventHelper.EnqueueRequestEvent(new RequestEventInfo(CurrentRequest, RequestEvents.Resend));
ConnectionEventHelper.EnqueueConnectionEvent(new ConnectionEventInfo(this, HTTPConnectionStates.Closed));
return;
}
if (this.connector == null)
{
this.connector = new Connections.TCPConnector();
try
{
this.connector.Connect(this.CurrentRequest);
}
catch(Exception ex)
{
if (HTTPManager.Logger.Level == Logger.Loglevels.All)
HTTPManager.Logger.Exception("HTTPConnection", "Connector.Connect", ex, this.Context, this.CurrentRequest.Context);
if (ex is TimeoutException)
this.CurrentRequest.State = HTTPRequestStates.ConnectionTimedOut;
else if (!this.CurrentRequest.IsTimedOut) // Do nothing here if Abort() got called on the request, its State is already set.
{
this.CurrentRequest.Exception = ex;
this.CurrentRequest.State = HTTPRequestStates.Error;
}
ConnectionEventHelper.EnqueueConnectionEvent(new ConnectionEventInfo(this, HTTPConnectionStates.Closed));
return;
}
#if !NETFX_CORE
// data sending is buffered for all protocols, so when we put data into the socket we want to send them asap
this.connector.Client.NoDelay = true;
#endif
StartTime = DateTime.UtcNow;
HTTPManager.Logger.Information("HTTPConnection", "Negotiated protocol through ALPN: '" + this.connector.NegotiatedProtocol + "'", this.Context, this.CurrentRequest.Context);
switch (this.connector.NegotiatedProtocol)
{
case HTTPProtocolFactory.W3C_HTTP1:
this.requestHandler = new Connections.HTTP1Handler(this);
ConnectionEventHelper.EnqueueConnectionEvent(new ConnectionEventInfo(this, HostProtocolSupport.HTTP1));
break;
#if (!UNITY_WEBGL || UNITY_EDITOR) && !BESTHTTP_DISABLE_ALTERNATE_SSL && !BESTHTTP_DISABLE_HTTP2
case HTTPProtocolFactory.W3C_HTTP2:
this.requestHandler = new Connections.HTTP2.HTTP2Handler(this);
this.CurrentRequest = null;
ConnectionEventHelper.EnqueueConnectionEvent(new ConnectionEventInfo(this, HostProtocolSupport.HTTP2));
break;
#endif
default:
HTTPManager.Logger.Error("HTTPConnection", "Unknown negotiated protocol: " + this.connector.NegotiatedProtocol, this.Context, this.CurrentRequest.Context);
RequestEventHelper.EnqueueRequestEvent(new RequestEventInfo(CurrentRequest, RequestEvents.Resend));
ConnectionEventHelper.EnqueueConnectionEvent(new ConnectionEventInfo(this, HTTPConnectionStates.Closed));
return;
}
}
this.requestHandler.Context.Add("Connection", this.GetHashCode());
this.Context.Add("RequestHandler", this.requestHandler.GetHashCode());
this.requestHandler.RunHandler();
LastProcessTime = DateTime.Now;
}
public override void Shutdown(ShutdownTypes type)
{
base.Shutdown(type);
if (this.requestHandler != null)
this.requestHandler.Shutdown(type);
switch(this.ShutdownType)
{
case ShutdownTypes.Immediate:
this.connector.Dispose();
break;
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
LastProcessedUri = null;
if (this.State != HTTPConnectionStates.WaitForProtocolShutdown)
{
if (this.connector != null)
{
try
{
this.connector.Close();
}
catch
{ }
this.connector = null;
}
if (this.requestHandler != null)
{
try
{
this.requestHandler.Dispose();
}
catch
{ }
this.requestHandler = null;
}
}
else
{
// We have to connector to do not close its stream at any cost while disposing.
// All references to this connection will be removed, so this and the connector may be finalized after some time.
// But, finalizing (and disposing) the connector while the protocol is still active would be fatal,
// so we have to make sure that it will not happen. This also means that the protocol has the responsibility (as always had)
// to close the stream and TCP connection properly.
if (this.connector != null)
this.connector.LeaveOpen = true;
}
}
base.Dispose(disposing);
}
}
}
#endif