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

269 lines
11 KiB

#if !UNITY_WEBGL || UNITY_EDITOR
using System;
using BestHTTP.Core;
using BestHTTP.Logger;
using BestHTTP.PlatformSupport.Threading;
#if !BESTHTTP_DISABLE_CACHING
using BestHTTP.Caching;
#endif
using BestHTTP.Timings;
namespace BestHTTP.Connections
{
public sealed class HTTP1Handler : IHTTPRequestHandler
{
public bool HasCustomRequestProcessor { get { return false; } }
public KeepAliveHeader KeepAlive { get { return this._keepAlive; } }
private KeepAliveHeader _keepAlive;
public bool CanProcessMultiple { get { return false; } }
private readonly HTTPConnection conn;
public LoggingContext Context { get; private set; }
public HTTP1Handler(HTTPConnection conn)
{
this.Context = new LoggingContext(this);
this.conn = conn;
}
public void Process(HTTPRequest request)
{
}
public void RunHandler()
{
HTTPManager.Logger.Information("HTTP1Handler", string.Format("[{0}] started processing request '{1}'", this, this.conn.CurrentRequest.CurrentUri.ToString()), this.Context, this.conn.CurrentRequest.Context);
ThreadedRunner.SetThreadName("BestHTTP.HTTP1 R&W");
HTTPConnectionStates proposedConnectionState = HTTPConnectionStates.Processing;
bool resendRequest = false;
try
{
if (this.conn.CurrentRequest.IsCancellationRequested)
return;
#if !BESTHTTP_DISABLE_CACHING
// Setup cache control headers before we send out the request
if (!this.conn.CurrentRequest.DisableCache)
HTTPCacheService.SetHeaders(this.conn.CurrentRequest);
#endif
// Write the request to the stream
this.conn.CurrentRequest.QueuedAt = DateTime.MinValue;
this.conn.CurrentRequest.ProcessingStarted = DateTime.UtcNow;
this.conn.CurrentRequest.SendOutTo(this.conn.connector.Stream);
this.conn.CurrentRequest.Timing.Add(TimingEventNames.Request_Sent);
if (this.conn.CurrentRequest.IsCancellationRequested)
return;
this.conn.CurrentRequest.OnCancellationRequested += OnCancellationRequested;
// Receive response from the server
bool received = Receive(this.conn.CurrentRequest);
this.conn.CurrentRequest.Timing.Add(TimingEventNames.Response_Received);
if (this.conn.CurrentRequest.IsCancellationRequested)
return;
if (!received && this.conn.CurrentRequest.Retries < this.conn.CurrentRequest.MaxRetries)
{
proposedConnectionState = HTTPConnectionStates.Closed;
this.conn.CurrentRequest.Retries++;
resendRequest = true;
return;
}
ConnectionHelper.HandleResponse(this.conn.ToString(), this.conn.CurrentRequest, out resendRequest, out proposedConnectionState, ref this._keepAlive, this.conn.Context, this.conn.CurrentRequest.Context);
}
catch (TimeoutException e)
{
this.conn.CurrentRequest.Response = null;
// Do nothing here if Abort() got called on the request, its State is already set.
if (!this.conn.CurrentRequest.IsTimedOut)
{
// We will try again only once
if (this.conn.CurrentRequest.Retries < this.conn.CurrentRequest.MaxRetries)
{
this.conn.CurrentRequest.Retries++;
resendRequest = true;
}
else
{
this.conn.CurrentRequest.Exception = e;
this.conn.CurrentRequest.State = HTTPRequestStates.ConnectionTimedOut;
}
}
proposedConnectionState = HTTPConnectionStates.Closed;
}
catch (Exception e)
{
if (this.ShutdownType == ShutdownTypes.Immediate)
return;
string exceptionMessage = string.Empty;
if (e == null)
exceptionMessage = "null";
else
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
Exception exception = e;
int counter = 1;
while (exception != null)
{
sb.AppendFormat("{0}: {1} {2}", counter++.ToString(), exception.Message, exception.StackTrace);
exception = exception.InnerException;
if (exception != null)
sb.AppendLine();
}
exceptionMessage = sb.ToString();
}
HTTPManager.Logger.Verbose("HTTP1Handler", exceptionMessage, this.Context, this.conn.CurrentRequest.Context);
#if !BESTHTTP_DISABLE_CACHING
if (this.conn.CurrentRequest.UseStreaming)
HTTPCacheService.DeleteEntity(this.conn.CurrentRequest.CurrentUri);
#endif
// Something gone bad, Response must be null!
this.conn.CurrentRequest.Response = null;
// Do nothing here if Abort() got called on the request, its State is already set.
if (!this.conn.CurrentRequest.IsCancellationRequested)
{
this.conn.CurrentRequest.Exception = e;
this.conn.CurrentRequest.State = HTTPRequestStates.Error;
}
proposedConnectionState = HTTPConnectionStates.Closed;
}
finally
{
this.conn.CurrentRequest.OnCancellationRequested -= OnCancellationRequested;
// Exit ASAP
if (this.ShutdownType != ShutdownTypes.Immediate)
{
if (this.conn.CurrentRequest.IsCancellationRequested)
{
// we don't know what stage the request is canceled, we can't safely reuse the tcp channel.
proposedConnectionState = HTTPConnectionStates.Closed;
this.conn.CurrentRequest.Response = null;
// The request's State already set, or going to be set soon in RequestEvents.cs.
//this.conn.CurrentRequest.State = this.conn.CurrentRequest.IsTimedOut ? HTTPRequestStates.TimedOut : HTTPRequestStates.Aborted;
}
else if (resendRequest)
{
// Here introducing a ClosedResendRequest connection state, where we have to process the connection's state change to Closed
// than we have to resend the request.
// If we would send the Resend request here, than a few lines below the Closed connection state change,
// request events are processed before connection events (just switching the EnqueueRequestEvent and EnqueueConnectionEvent wouldn't work
// see order of ProcessQueues in HTTPManager.OnUpdate!) and it would pick this very same closing/closed connection!
if (proposedConnectionState == HTTPConnectionStates.Closed || proposedConnectionState == HTTPConnectionStates.ClosedResendRequest)
ConnectionEventHelper.EnqueueConnectionEvent(new ConnectionEventInfo(this.conn, this.conn.CurrentRequest));
else
RequestEventHelper.EnqueueRequestEvent(new RequestEventInfo(this.conn.CurrentRequest, RequestEvents.Resend));
}
else if (this.conn.CurrentRequest.Response != null && this.conn.CurrentRequest.Response.IsUpgraded)
{
proposedConnectionState = HTTPConnectionStates.WaitForProtocolShutdown;
}
else if (this.conn.CurrentRequest.State == HTTPRequestStates.Processing)
{
if (this.conn.CurrentRequest.Response != null)
this.conn.CurrentRequest.State = HTTPRequestStates.Finished;
else
{
this.conn.CurrentRequest.Exception = new Exception(string.Format("[{0}] Remote server closed the connection before sending response header! Previous request state: {1}. Connection state: {2}",
this.ToString(),
this.conn.CurrentRequest.State.ToString(),
this.conn.State.ToString()));
this.conn.CurrentRequest.State = HTTPRequestStates.Error;
proposedConnectionState = HTTPConnectionStates.Closed;
}
}
this.conn.CurrentRequest = null;
if (proposedConnectionState == HTTPConnectionStates.Processing)
proposedConnectionState = HTTPConnectionStates.Recycle;
if (proposedConnectionState != HTTPConnectionStates.ClosedResendRequest)
ConnectionEventHelper.EnqueueConnectionEvent(new ConnectionEventInfo(this.conn, proposedConnectionState));
}
}
}
private void OnCancellationRequested(HTTPRequest obj)
{
if (this.conn != null && this.conn.connector != null)
this.conn.connector.Dispose();
}
private bool Receive(HTTPRequest request)
{
SupportedProtocols protocol = HTTPProtocolFactory.GetProtocolFromUri(request.CurrentUri);
if (HTTPManager.Logger.Level == Logger.Loglevels.All)
HTTPManager.Logger.Verbose("HTTPConnection", string.Format("[{0}] - Receive - protocol: {1}", this.ToString(), protocol.ToString()), this.Context, request.Context);
request.Response = HTTPProtocolFactory.Get(protocol, request, this.conn.connector.Stream, request.UseStreaming, false);
if (!request.Response.Receive())
{
if (HTTPManager.Logger.Level == Logger.Loglevels.All)
HTTPManager.Logger.Verbose("HTTP1Handler", string.Format("[{0}] - Receive - Failed! Response will be null, returning with false.", this.ToString()), this.Context, request.Context);
request.Response = null;
return false;
}
if (HTTPManager.Logger.Level == Logger.Loglevels.All)
HTTPManager.Logger.Verbose("HTTP1Handler", string.Format("[{0}] - Receive - Finished Successfully!", this.ToString()), this.Context, request.Context);
return true;
}
public ShutdownTypes ShutdownType { get; private set; }
public void Shutdown(ShutdownTypes type)
{
this.ShutdownType = type;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
}
~HTTP1Handler()
{
Dispose(false);
}
}
}
#endif