ConnectionBase.cs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. using System;
  2. using System.Threading;
  3. #if NETFX_CORE
  4. using System.Threading.Tasks;
  5. //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.
  6. #pragma warning disable 4014
  7. //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.
  8. #pragma warning disable 1998
  9. #endif
  10. namespace BestHTTP
  11. {
  12. internal delegate void HTTPConnectionRecycledDelegate(ConnectionBase conn);
  13. internal abstract class ConnectionBase : IDisposable
  14. {
  15. #region Public Properties
  16. /// <summary>
  17. /// The address of the server that this connection is bound to.
  18. /// </summary>
  19. public string ServerAddress { get; protected set; }
  20. /// <summary>
  21. /// The state of this connection.
  22. /// </summary>
  23. public HTTPConnectionStates State { get; protected set; }
  24. /// <summary>
  25. /// It's true if this connection is available to process a HTTPRequest.
  26. /// </summary>
  27. public bool IsFree { get { return State == HTTPConnectionStates.Initial || State == HTTPConnectionStates.Free; } }
  28. /// <summary>
  29. /// Returns true if it's an active connection.
  30. /// </summary>
  31. public bool IsActive { get { return State > HTTPConnectionStates.Initial && State < HTTPConnectionStates.Free; } }
  32. /// <summary>
  33. /// If the State is HTTPConnectionStates.Processing, then it holds a HTTPRequest instance. Otherwise it's null.
  34. /// </summary>
  35. public HTTPRequest CurrentRequest { get; protected set; }
  36. public virtual bool IsRemovable { get { return IsFree && (DateTime.UtcNow - LastProcessTime) > HTTPManager.MaxConnectionIdleTime; } }
  37. /// <summary>
  38. /// When we start to process the current request. It's set after the connection is established.
  39. /// </summary>
  40. public DateTime StartTime { get; protected set; }
  41. /// <summary>
  42. /// When this connection timed out.
  43. /// </summary>
  44. public DateTime TimedOutStart { get; protected set; }
  45. #if !BESTHTTP_DISABLE_PROXY
  46. protected HTTPProxy Proxy { get; set; }
  47. public bool HasProxy { get { return Proxy != null; } }
  48. #endif
  49. public Uri LastProcessedUri { get; protected set; }
  50. #endregion
  51. #region Protected Fields
  52. protected DateTime LastProcessTime;
  53. protected HTTPConnectionRecycledDelegate OnConnectionRecycled = null;
  54. #endregion
  55. #region Privates
  56. private bool IsThreaded;
  57. #endregion
  58. public ConnectionBase(string serverAddress)
  59. :this(serverAddress, true)
  60. {}
  61. public ConnectionBase(string serverAddress, bool threaded)
  62. {
  63. this.ServerAddress = serverAddress;
  64. this.State = HTTPConnectionStates.Initial;
  65. this.LastProcessTime = DateTime.UtcNow;
  66. this.IsThreaded = threaded;
  67. }
  68. internal abstract void Abort(HTTPConnectionStates hTTPConnectionStates);
  69. internal void Process(HTTPRequest request)
  70. {
  71. if (State == HTTPConnectionStates.Processing)
  72. throw new Exception("Connection already processing a request!");
  73. StartTime = DateTime.MaxValue;
  74. State = HTTPConnectionStates.Processing;
  75. CurrentRequest = request;
  76. if (IsThreaded)
  77. {
  78. #if NETFX_CORE
  79. #pragma warning disable 4014
  80. Windows.System.Threading.ThreadPool.RunAsync(ThreadFunc);
  81. #pragma warning restore 4014
  82. #else
  83. ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadFunc));
  84. //new Thread(ThreadFunc)
  85. // .Start();
  86. #endif
  87. }
  88. else
  89. ThreadFunc(null);
  90. }
  91. protected virtual
  92. #if NETFX_CORE
  93. async
  94. #endif
  95. void ThreadFunc(object param)
  96. {
  97. }
  98. internal void HandleProgressCallback()
  99. {
  100. if (CurrentRequest.OnProgress != null && CurrentRequest.DownloadProgressChanged)
  101. {
  102. try
  103. {
  104. CurrentRequest.OnProgress(CurrentRequest, CurrentRequest.Downloaded, CurrentRequest.DownloadLength);
  105. }
  106. catch (Exception ex)
  107. {
  108. HTTPManager.Logger.Exception("ConnectionBase", "HandleProgressCallback - OnProgress", ex);
  109. }
  110. CurrentRequest.DownloadProgressChanged = false;
  111. }
  112. if (CurrentRequest.OnUploadProgress != null && CurrentRequest.UploadProgressChanged)
  113. {
  114. try
  115. {
  116. CurrentRequest.OnUploadProgress(CurrentRequest, CurrentRequest.Uploaded, CurrentRequest.UploadLength);
  117. }
  118. catch (Exception ex)
  119. {
  120. HTTPManager.Logger.Exception("ConnectionBase", "HandleProgressCallback - OnUploadProgress", ex);
  121. }
  122. CurrentRequest.UploadProgressChanged = false;
  123. }
  124. }
  125. internal void HandleCallback()
  126. {
  127. try
  128. {
  129. HandleProgressCallback();
  130. if (State == HTTPConnectionStates.Upgraded)
  131. {
  132. if (CurrentRequest != null && CurrentRequest.Response != null && CurrentRequest.Response.IsUpgraded)
  133. CurrentRequest.UpgradeCallback();
  134. State = HTTPConnectionStates.WaitForProtocolShutdown;
  135. }
  136. else
  137. CurrentRequest.CallCallback();
  138. }
  139. catch (Exception ex)
  140. {
  141. HTTPManager.Logger.Exception("ConnectionBase", "HandleCallback", ex);
  142. }
  143. }
  144. internal void Recycle(HTTPConnectionRecycledDelegate onConnectionRecycled)
  145. {
  146. OnConnectionRecycled = onConnectionRecycled;
  147. if (!(State > HTTPConnectionStates.Initial && State < HTTPConnectionStates.WaitForProtocolShutdown) || State == HTTPConnectionStates.Redirected)
  148. RecycleNow();
  149. }
  150. protected void RecycleNow()
  151. {
  152. if (State == HTTPConnectionStates.TimedOut ||
  153. State == HTTPConnectionStates.Closed)
  154. LastProcessTime = DateTime.MinValue;
  155. State = HTTPConnectionStates.Free;
  156. CurrentRequest = null;
  157. if (OnConnectionRecycled != null)
  158. {
  159. OnConnectionRecycled(this);
  160. OnConnectionRecycled = null;
  161. }
  162. }
  163. #region Dispose Pattern
  164. protected bool IsDisposed { get; private set; }
  165. public void Dispose()
  166. {
  167. Dispose(true);
  168. GC.SuppressFinalize(this);
  169. }
  170. protected virtual void Dispose(bool disposing)
  171. {
  172. IsDisposed = true;
  173. }
  174. #endregion
  175. }
  176. }