HostDefinition.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. using System;
  2. using System.Collections.Generic;
  3. namespace BestHTTP.Core
  4. {
  5. public sealed class HostDefinition
  6. {
  7. public string Host { get; private set; }
  8. // alt-svc support:
  9. // 1. When a request receives an alt-svc header send a plugin msg to the manager with all the details to route to the proper hostDefinition.
  10. // 2. HostDefinition parses the header value
  11. // 3. If there's at least one supported protocol found, start open a connection to that said alternate
  12. // 4. If the new connection is open, route new requests to that connection
  13. public List<HostConnection> Alternates;
  14. /// <summary>
  15. /// Requests to the same host can require different connections: http, https, http + proxy, https + proxy, http2, http2 + proxy
  16. /// </summary>
  17. public Dictionary<string, HostConnection> hostConnectionVariant = new Dictionary<string, HostConnection>();
  18. public HostDefinition(string host)
  19. {
  20. this.Host = host;
  21. }
  22. public HostConnection HasBetterAlternate(HTTPRequest request)
  23. {
  24. return null;
  25. }
  26. public HostConnection GetHostDefinition(HTTPRequest request)
  27. {
  28. string key = GetKeyForRequest(request);
  29. return GetHostDefinition(key);
  30. }
  31. public HostConnection GetHostDefinition(string key)
  32. {
  33. HostConnection host = null;
  34. if (!this.hostConnectionVariant.TryGetValue(key, out host))
  35. this.hostConnectionVariant.Add(key, host = new HostConnection(this, key));
  36. return host;
  37. }
  38. public void Send(HTTPRequest request)
  39. {
  40. GetHostDefinition(request)
  41. .Send(request);
  42. }
  43. public void TryToSendQueuedRequests()
  44. {
  45. foreach (var kvp in hostConnectionVariant)
  46. kvp.Value.TryToSendQueuedRequests();
  47. }
  48. public void HandleAltSvcHeader(HTTPResponse response)
  49. {
  50. var headerValues = response.GetHeaderValues("alt-svc");
  51. if (headerValues == null)
  52. HTTPManager.Logger.Warning(typeof(HostDefinition).Name, "Received HandleAltSvcHeader message, but no Alt-Svc header found!", response.Context);
  53. }
  54. public void HandleConnectProtocol(HTTP2ConnectProtocolInfo info)
  55. {
  56. HTTPManager.Logger.Information(typeof(HostDefinition).Name, string.Format("Received HandleConnectProtocol message. Connect protocol for host {0}. Enabled: {1}", info.Host, info.Enabled));
  57. }
  58. internal void Shutdown()
  59. {
  60. foreach (var kvp in this.hostConnectionVariant)
  61. {
  62. kvp.Value.Shutdown();
  63. }
  64. }
  65. internal void SaveTo(System.IO.BinaryWriter bw)
  66. {
  67. bw.Write(this.hostConnectionVariant.Count);
  68. foreach (var kvp in this.hostConnectionVariant)
  69. {
  70. bw.Write(kvp.Key.ToString());
  71. kvp.Value.SaveTo(bw);
  72. }
  73. }
  74. internal void LoadFrom(int version, System.IO.BinaryReader br)
  75. {
  76. int count = br.ReadInt32();
  77. for (int i = 0; i < count; ++i)
  78. {
  79. GetHostDefinition(br.ReadString())
  80. .LoadFrom(version, br);
  81. }
  82. }
  83. private static System.Text.StringBuilder keyBuilder = new System.Text.StringBuilder(11);
  84. // While a ReaderWriterLockSlim would be best with read and write locking and we use only WriteLock, it's still a lightweight locking mechanism instead of the lock statement.
  85. private static System.Threading.ReaderWriterLockSlim keyBuilderLock = new System.Threading.ReaderWriterLockSlim(System.Threading.LockRecursionPolicy.NoRecursion);
  86. public static string GetKeyForRequest(HTTPRequest request)
  87. {
  88. return GetKeyFor(request.CurrentUri
  89. #if !BESTHTTP_DISABLE_PROXY
  90. , request.Proxy
  91. #endif
  92. );
  93. }
  94. public static string GetKeyFor(Uri uri
  95. #if !BESTHTTP_DISABLE_PROXY
  96. , Proxy proxy
  97. #endif
  98. )
  99. {
  100. if (uri.IsFile)
  101. return uri.ToString();
  102. keyBuilderLock.EnterWriteLock();
  103. try
  104. {
  105. keyBuilder.Length = 0;
  106. #if !BESTHTTP_DISABLE_PROXY
  107. if (proxy != null && proxy.UseProxyForAddress(uri))
  108. {
  109. keyBuilder.Append(proxy.Address.Scheme);
  110. keyBuilder.Append("://");
  111. keyBuilder.Append(proxy.Address.Host);
  112. keyBuilder.Append(":");
  113. keyBuilder.Append(proxy.Address.Port);
  114. keyBuilder.Append(" @ ");
  115. }
  116. #endif
  117. keyBuilder.Append(uri.Scheme);
  118. keyBuilder.Append("://");
  119. keyBuilder.Append(uri.Host);
  120. keyBuilder.Append(":");
  121. keyBuilder.Append(uri.Port);
  122. return keyBuilder.ToString();
  123. }
  124. finally
  125. {
  126. keyBuilderLock.ExitWriteLock();
  127. }
  128. }
  129. }
  130. }