using System; using System.Threading; #if NETFX_CORE using System.Threading.Tasks; //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 //Disable warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. #pragma warning disable 1998 #endif namespace BestHTTP { internal delegate void HTTPConnectionRecycledDelegate(ConnectionBase conn); internal abstract class ConnectionBase : IDisposable { #region Public Properties /// /// The address of the server that this connection is bound to. /// public string ServerAddress { get; protected set; } /// /// The state of this connection. /// public HTTPConnectionStates State { get; protected set; } /// /// It's true if this connection is available to process a HTTPRequest. /// public bool IsFree { get { return State == HTTPConnectionStates.Initial || State == HTTPConnectionStates.Free; } } /// /// Returns true if it's an active connection. /// public bool IsActive { get { return State > HTTPConnectionStates.Initial && State < HTTPConnectionStates.Free; } } /// /// If the State is HTTPConnectionStates.Processing, then it holds a HTTPRequest instance. Otherwise it's null. /// public HTTPRequest CurrentRequest { get; protected set; } public virtual bool IsRemovable { get { return IsFree && (DateTime.UtcNow - LastProcessTime) > HTTPManager.MaxConnectionIdleTime; } } /// /// When we start to process the current request. It's set after the connection is established. /// public DateTime StartTime { get; protected set; } /// /// When this connection timed out. /// public DateTime TimedOutStart { get; protected set; } #if !BESTHTTP_DISABLE_PROXY protected HTTPProxy Proxy { get; set; } public bool HasProxy { get { return Proxy != null; } } #endif public Uri LastProcessedUri { get; protected set; } #endregion #region Protected Fields protected DateTime LastProcessTime; protected HTTPConnectionRecycledDelegate OnConnectionRecycled = null; #endregion #region Privates private bool IsThreaded; #endregion public ConnectionBase(string serverAddress) :this(serverAddress, true) {} public ConnectionBase(string serverAddress, bool threaded) { this.ServerAddress = serverAddress; this.State = HTTPConnectionStates.Initial; this.LastProcessTime = DateTime.UtcNow; this.IsThreaded = threaded; } internal abstract void Abort(HTTPConnectionStates hTTPConnectionStates); internal void Process(HTTPRequest request) { if (State == HTTPConnectionStates.Processing) throw new Exception("Connection already processing a request!"); StartTime = DateTime.MaxValue; State = HTTPConnectionStates.Processing; CurrentRequest = request; if (IsThreaded) { #if NETFX_CORE #pragma warning disable 4014 Windows.System.Threading.ThreadPool.RunAsync(ThreadFunc); #pragma warning restore 4014 #else ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadFunc)); //new Thread(ThreadFunc) // .Start(); #endif } else ThreadFunc(null); } protected virtual #if NETFX_CORE async #endif void ThreadFunc(object param) { } internal void HandleProgressCallback() { if (CurrentRequest.OnProgress != null && CurrentRequest.DownloadProgressChanged) { try { CurrentRequest.OnProgress(CurrentRequest, CurrentRequest.Downloaded, CurrentRequest.DownloadLength); } catch (Exception ex) { HTTPManager.Logger.Exception("ConnectionBase", "HandleProgressCallback - OnProgress", ex); } CurrentRequest.DownloadProgressChanged = false; } if (CurrentRequest.OnUploadProgress != null && CurrentRequest.UploadProgressChanged) { try { CurrentRequest.OnUploadProgress(CurrentRequest, CurrentRequest.Uploaded, CurrentRequest.UploadLength); } catch (Exception ex) { HTTPManager.Logger.Exception("ConnectionBase", "HandleProgressCallback - OnUploadProgress", ex); } CurrentRequest.UploadProgressChanged = false; } } internal void HandleCallback() { try { HandleProgressCallback(); if (State == HTTPConnectionStates.Upgraded) { if (CurrentRequest != null && CurrentRequest.Response != null && CurrentRequest.Response.IsUpgraded) CurrentRequest.UpgradeCallback(); State = HTTPConnectionStates.WaitForProtocolShutdown; } else CurrentRequest.CallCallback(); } catch (Exception ex) { HTTPManager.Logger.Exception("ConnectionBase", "HandleCallback", ex); } } internal void Recycle(HTTPConnectionRecycledDelegate onConnectionRecycled) { OnConnectionRecycled = onConnectionRecycled; if (!(State > HTTPConnectionStates.Initial && State < HTTPConnectionStates.WaitForProtocolShutdown) || State == HTTPConnectionStates.Redirected) RecycleNow(); } protected void RecycleNow() { if (State == HTTPConnectionStates.TimedOut || State == HTTPConnectionStates.Closed) LastProcessTime = DateTime.MinValue; State = HTTPConnectionStates.Free; CurrentRequest = null; if (OnConnectionRecycled != null) { OnConnectionRecycled(this); OnConnectionRecycled = null; } } #region Dispose Pattern protected bool IsDisposed { get; private set; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { IsDisposed = true; } #endregion } }