181 lines
6.4 KiB
C#
181 lines
6.4 KiB
C#
#if !UNITY_WEBGL || UNITY_EDITOR
|
|
|
|
using System;
|
|
|
|
using BestHTTP.Core;
|
|
|
|
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)
|
|
return this.requestHandler.KeepAlive.TimeOut;
|
|
|
|
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)
|
|
{}
|
|
|
|
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.connector != null && !this.connector.IsConnected)
|
|
{
|
|
// this will semd 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.CurrentRequest.State = HTTPRequestStates.ConnectionTimedOut;
|
|
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 + "'");
|
|
|
|
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);
|
|
RequestEventHelper.EnqueueRequestEvent(new RequestEventInfo(CurrentRequest, RequestEvents.Resend));
|
|
ConnectionEventHelper.EnqueueConnectionEvent(new ConnectionEventInfo(this, HTTPConnectionStates.Closed));
|
|
return;
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
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 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 resposibility (as always had)
|
|
// to close the stream and TCP connection properly.
|
|
if (this.connector != null)
|
|
this.connector.LeaveOpen = true;
|
|
}
|
|
|
|
base.Dispose(disposing);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|