HTTP2Frames.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. #if (!UNITY_WEBGL || UNITY_EDITOR) && !BESTHTTP_DISABLE_ALTERNATE_SSL && !BESTHTTP_DISABLE_HTTP2
  2. using BestHTTP.Extensions;
  3. using BestHTTP.PlatformSupport.Memory;
  4. using System;
  5. using System.Collections.Generic;
  6. namespace BestHTTP.Connections.HTTP2
  7. {
  8. // https://httpwg.org/specs/rfc7540.html#iana-frames
  9. public enum HTTP2FrameTypes : byte
  10. {
  11. DATA = 0x00,
  12. HEADERS = 0x01,
  13. PRIORITY = 0x02,
  14. RST_STREAM = 0x03,
  15. SETTINGS = 0x04,
  16. PUSH_PROMISE = 0x05,
  17. PING = 0x06,
  18. GOAWAY = 0x07,
  19. WINDOW_UPDATE = 0x08,
  20. CONTINUATION = 0x09,
  21. // https://tools.ietf.org/html/rfc7838#section-4
  22. ALT_SVC = 0x0A
  23. }
  24. [Flags]
  25. public enum HTTP2DataFlags : byte
  26. {
  27. None = 0x00,
  28. END_STREAM = 0x01,
  29. PADDED = 0x08,
  30. }
  31. [Flags]
  32. public enum HTTP2HeadersFlags : byte
  33. {
  34. None = 0x00,
  35. END_STREAM = 0x01,
  36. END_HEADERS = 0x04,
  37. PADDED = 0x08,
  38. PRIORITY = 0x20,
  39. }
  40. [Flags]
  41. public enum HTTP2SettingsFlags : byte
  42. {
  43. None = 0x00,
  44. ACK = 0x01,
  45. }
  46. [Flags]
  47. public enum HTTP2PushPromiseFlags : byte
  48. {
  49. None = 0x00,
  50. END_HEADERS = 0x04,
  51. PADDED = 0x08,
  52. }
  53. [Flags]
  54. public enum HTTP2PingFlags : byte
  55. {
  56. None = 0x00,
  57. ACK = 0x01,
  58. }
  59. [Flags]
  60. public enum HTTP2ContinuationFlags : byte
  61. {
  62. None = 0x00,
  63. END_HEADERS = 0x04,
  64. }
  65. public struct HTTP2FrameHeaderAndPayload
  66. {
  67. public UInt32 PayloadLength;
  68. public HTTP2FrameTypes Type;
  69. public byte Flags;
  70. public UInt32 StreamId;
  71. public byte[] Payload;
  72. public UInt32 PayloadOffset;
  73. public bool DontUseMemPool;
  74. public override string ToString()
  75. {
  76. return string.Format("[HTTP2FrameHeaderAndPayload Length: {0}, Type: {1}, Flags: {2}, StreamId: {3}, PayloadOffset: {4}, DontUseMemPool: {5}, Payload: {6}]",
  77. this.PayloadLength, this.Type, this.Flags.ToBinaryStr(), this.StreamId, this.PayloadOffset, this.DontUseMemPool,
  78. this.Payload == null ? BufferSegment.Empty : new BufferSegment(this.Payload, (int)this.PayloadOffset, (int)this.PayloadLength));
  79. }
  80. public string PayloadAsHex()
  81. {
  82. System.Text.StringBuilder sb = PlatformSupport.Text.StringBuilderPool.Get((int)this.PayloadLength + 2);
  83. sb.Append("[");
  84. if (this.Payload != null && this.PayloadLength > 0)
  85. {
  86. uint idx = this.PayloadOffset;
  87. sb.Append(this.Payload[idx++]);
  88. for (int i = 1; i < this.PayloadLength; i++)
  89. sb.AppendFormat(", {0:X2}", this.Payload[idx++]);
  90. }
  91. sb.Append("]");
  92. return PlatformSupport.Text.StringBuilderPool.ReleaseAndGrab(sb);
  93. }
  94. }
  95. public struct HTTP2SettingsFrame
  96. {
  97. public readonly HTTP2FrameHeaderAndPayload Header;
  98. public HTTP2SettingsFlags Flags { get { return (HTTP2SettingsFlags)this.Header.Flags; } }
  99. public List<KeyValuePair<HTTP2Settings, UInt32>> Settings;
  100. public HTTP2SettingsFrame(HTTP2FrameHeaderAndPayload header)
  101. {
  102. this.Header = header;
  103. this.Settings = null;
  104. }
  105. public override string ToString()
  106. {
  107. string settings = null;
  108. if (this.Settings != null)
  109. {
  110. System.Text.StringBuilder sb = PlatformSupport.Text.StringBuilderPool.Get(this.Settings.Count + 2);
  111. sb.Append("[");
  112. foreach (var kvp in this.Settings)
  113. sb.AppendFormat("[{0}: {1}]", kvp.Key, kvp.Value);
  114. sb.Append("]");
  115. settings = PlatformSupport.Text.StringBuilderPool.ReleaseAndGrab(sb);
  116. }
  117. return string.Format("[HTTP2SettingsFrame Header: {0}, Flags: {1}, Settings: {2}]", this.Header.ToString(), this.Flags, settings ?? "Empty");
  118. }
  119. }
  120. public struct HTTP2DataFrame
  121. {
  122. public readonly HTTP2FrameHeaderAndPayload Header;
  123. public HTTP2DataFlags Flags { get { return (HTTP2DataFlags)this.Header.Flags; } }
  124. public byte? PadLength;
  125. public UInt32 DataIdx;
  126. public byte[] Data;
  127. public uint DataLength;
  128. public HTTP2DataFrame(HTTP2FrameHeaderAndPayload header)
  129. {
  130. this.Header = header;
  131. this.PadLength = null;
  132. this.DataIdx = 0;
  133. this.Data = null;
  134. this.DataLength = 0;
  135. }
  136. public override string ToString()
  137. {
  138. return string.Format("[HTTP2DataFrame Header: {0}, Flags: {1}, PadLength: {2}, DataLength: {3}]",
  139. this.Header.ToString(),
  140. this.Flags,
  141. this.PadLength == null ? ":Empty" : this.PadLength.Value.ToString(),
  142. this.DataLength);
  143. }
  144. }
  145. public struct HTTP2HeadersFrame
  146. {
  147. public readonly HTTP2FrameHeaderAndPayload Header;
  148. public HTTP2HeadersFlags Flags { get { return (HTTP2HeadersFlags)this.Header.Flags; } }
  149. public byte? PadLength;
  150. public byte? IsExclusive;
  151. public UInt32? StreamDependency;
  152. public byte? Weight;
  153. public UInt32 HeaderBlockFragmentIdx;
  154. public byte[] HeaderBlockFragment;
  155. public UInt32 HeaderBlockFragmentLength;
  156. public HTTP2HeadersFrame(HTTP2FrameHeaderAndPayload header)
  157. {
  158. this.Header = header;
  159. this.PadLength = null;
  160. this.IsExclusive = null;
  161. this.StreamDependency = null;
  162. this.Weight = null;
  163. this.HeaderBlockFragmentIdx = 0;
  164. this.HeaderBlockFragment = null;
  165. this.HeaderBlockFragmentLength = 0;
  166. }
  167. public override string ToString()
  168. {
  169. return string.Format("[HTTP2HeadersFrame Header: {0}, Flags: {1}, PadLength: {2}, IsExclusive: {3}, StreamDependency: {4}, Weight: {5}, HeaderBlockFragmentLength: {6}]",
  170. this.Header.ToString(),
  171. this.Flags,
  172. this.PadLength == null ? ":Empty" : this.PadLength.Value.ToString(),
  173. this.IsExclusive == null ? "Empty" : this.IsExclusive.Value.ToString(),
  174. this.StreamDependency == null ? "Empty" : this.StreamDependency.Value.ToString(),
  175. this.Weight == null ? "Empty" : this.Weight.Value.ToString(),
  176. this.HeaderBlockFragmentLength);
  177. }
  178. }
  179. public struct HTTP2PriorityFrame
  180. {
  181. public readonly HTTP2FrameHeaderAndPayload Header;
  182. public byte IsExclusive;
  183. public UInt32 StreamDependency;
  184. public byte Weight;
  185. public HTTP2PriorityFrame(HTTP2FrameHeaderAndPayload header)
  186. {
  187. this.Header = header;
  188. this.IsExclusive = 0;
  189. this.StreamDependency = 0;
  190. this.Weight = 0;
  191. }
  192. public override string ToString()
  193. {
  194. return string.Format("[HTTP2PriorityFrame Header: {0}, IsExclusive: {1}, StreamDependency: {2}, Weight: {3}]",
  195. this.Header.ToString(), this.IsExclusive, this.StreamDependency, this.Weight);
  196. }
  197. }
  198. public struct HTTP2RSTStreamFrame
  199. {
  200. public readonly HTTP2FrameHeaderAndPayload Header;
  201. public UInt32 ErrorCode;
  202. public HTTP2ErrorCodes Error { get { return (HTTP2ErrorCodes)this.ErrorCode; } }
  203. public HTTP2RSTStreamFrame(HTTP2FrameHeaderAndPayload header)
  204. {
  205. this.Header = header;
  206. this.ErrorCode = 0;
  207. }
  208. public override string ToString()
  209. {
  210. return string.Format("[HTTP2RST_StreamFrame Header: {0}, Error: {1}({2})]", this.Header.ToString(), this.Error, this.ErrorCode);
  211. }
  212. }
  213. public struct HTTP2PushPromiseFrame
  214. {
  215. public readonly HTTP2FrameHeaderAndPayload Header;
  216. public HTTP2PushPromiseFlags Flags { get { return (HTTP2PushPromiseFlags)this.Header.Flags; } }
  217. public byte? PadLength;
  218. public byte ReservedBit;
  219. public UInt32 PromisedStreamId;
  220. public UInt32 HeaderBlockFragmentIdx;
  221. public byte[] HeaderBlockFragment;
  222. public UInt32 HeaderBlockFragmentLength;
  223. public HTTP2PushPromiseFrame(HTTP2FrameHeaderAndPayload header)
  224. {
  225. this.Header = header;
  226. this.PadLength = null;
  227. this.ReservedBit = 0;
  228. this.PromisedStreamId = 0;
  229. this.HeaderBlockFragmentIdx = 0;
  230. this.HeaderBlockFragment = null;
  231. this.HeaderBlockFragmentLength = 0;
  232. }
  233. public override string ToString()
  234. {
  235. return string.Format("[HTTP2Push_PromiseFrame Header: {0}, Flags: {1}, PadLength: {2}, ReservedBit: {3}, PromisedStreamId: {4}, HeaderBlockFragmentLength: {5}]",
  236. this.Header.ToString(),
  237. this.Flags,
  238. this.PadLength == null ? "Empty" : this.PadLength.Value.ToString(),
  239. this.ReservedBit,
  240. this.PromisedStreamId,
  241. this.HeaderBlockFragmentLength);
  242. }
  243. }
  244. public struct HTTP2PingFrame
  245. {
  246. public readonly HTTP2FrameHeaderAndPayload Header;
  247. public HTTP2PingFlags Flags { get { return (HTTP2PingFlags)this.Header.Flags; } }
  248. public readonly byte[] OpaqueData;
  249. public readonly byte OpaqueDataLength;
  250. public HTTP2PingFrame(HTTP2FrameHeaderAndPayload header)
  251. {
  252. this.Header = header;
  253. this.OpaqueData = BufferPool.Get(8, true);
  254. this.OpaqueDataLength = 8;
  255. }
  256. public override string ToString()
  257. {
  258. return string.Format("[HTTP2PingFrame Header: {0}, Flags: {1}, OpaqueData: {2}]",
  259. this.Header.ToString(),
  260. this.Flags,
  261. SecureProtocol.Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(this.OpaqueData, 0, this.OpaqueDataLength));
  262. }
  263. }
  264. public struct HTTP2GoAwayFrame
  265. {
  266. public readonly HTTP2FrameHeaderAndPayload Header;
  267. public HTTP2ErrorCodes Error { get { return (HTTP2ErrorCodes)this.ErrorCode; } }
  268. public byte ReservedBit;
  269. public UInt32 LastStreamId;
  270. public UInt32 ErrorCode;
  271. public byte[] AdditionalDebugData;
  272. public UInt32 AdditionalDebugDataLength;
  273. public HTTP2GoAwayFrame(HTTP2FrameHeaderAndPayload header)
  274. {
  275. this.Header = header;
  276. this.ReservedBit = 0;
  277. this.LastStreamId = 0;
  278. this.ErrorCode = 0;
  279. this.AdditionalDebugData = null;
  280. this.AdditionalDebugDataLength = 0;
  281. }
  282. public override string ToString()
  283. {
  284. return string.Format("[HTTP2GoAwayFrame Header: {0}, ReservedBit: {1}, LastStreamId: {2}, Error: {3}({4}), AdditionalDebugData({5}): {6}]",
  285. this.Header.ToString(),
  286. this.ReservedBit,
  287. this.LastStreamId,
  288. this.Error,
  289. this.ErrorCode,
  290. this.AdditionalDebugDataLength,
  291. this.AdditionalDebugData == null ? "Empty" : SecureProtocol.Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(this.AdditionalDebugData, 0, (int)this.AdditionalDebugDataLength));
  292. }
  293. }
  294. public struct HTTP2WindowUpdateFrame
  295. {
  296. public readonly HTTP2FrameHeaderAndPayload Header;
  297. public byte ReservedBit;
  298. public UInt32 WindowSizeIncrement;
  299. public HTTP2WindowUpdateFrame(HTTP2FrameHeaderAndPayload header)
  300. {
  301. this.Header = header;
  302. this.ReservedBit = 0;
  303. this.WindowSizeIncrement = 0;
  304. }
  305. public override string ToString()
  306. {
  307. return string.Format("[HTTP2WindowUpdateFrame Header: {0}, ReservedBit: {1}, WindowSizeIncrement: {2}]",
  308. this.Header.ToString(), this.ReservedBit, this.WindowSizeIncrement);
  309. }
  310. }
  311. public struct HTTP2ContinuationFrame
  312. {
  313. public readonly HTTP2FrameHeaderAndPayload Header;
  314. public HTTP2ContinuationFlags Flags { get { return (HTTP2ContinuationFlags)this.Header.Flags; } }
  315. public byte[] HeaderBlockFragment;
  316. public UInt32 HeaderBlockFragmentLength { get { return this.Header.PayloadLength; } }
  317. public HTTP2ContinuationFrame(HTTP2FrameHeaderAndPayload header)
  318. {
  319. this.Header = header;
  320. this.HeaderBlockFragment = null;
  321. }
  322. public override string ToString()
  323. {
  324. return string.Format("[HTTP2ContinuationFrame Header: {0}, Flags: {1}, HeaderBlockFragmentLength: {2}]",
  325. this.Header.ToString(),
  326. this.Flags,
  327. this.HeaderBlockFragmentLength);
  328. }
  329. }
  330. /// <summary>
  331. /// https://tools.ietf.org/html/rfc7838#section-4
  332. /// </summary>
  333. public struct HTTP2AltSVCFrame
  334. {
  335. public readonly HTTP2FrameHeaderAndPayload Header;
  336. public string Origin;
  337. public string AltSvcFieldValue;
  338. public HTTP2AltSVCFrame(HTTP2FrameHeaderAndPayload header)
  339. {
  340. this.Header = header;
  341. this.Origin = null;
  342. this.AltSvcFieldValue = null;
  343. }
  344. }
  345. }
  346. #endif