cow_http2.erl 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. %% Copyright (c) 2015, Loïc Hoguin <essen@ninenines.eu>
  2. %%
  3. %% Permission to use, copy, modify, and/or distribute this software for any
  4. %% purpose with or without fee is hereby granted, provided that the above
  5. %% copyright notice and this permission notice appear in all copies.
  6. %%
  7. %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  8. %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  9. %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  10. %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  11. %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  12. %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  13. %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  14. -module(cow_http2).
  15. %% Parsing.
  16. -export([parse/1]).
  17. -export([parse/2]).
  18. -export([parse_settings_payload/1]).
  19. %% Building.
  20. -export([data/3]).
  21. -export([data_header/3]).
  22. -export([headers/3]).
  23. -export([rst_stream/2]).
  24. -export([settings/1]).
  25. -export([settings_payload/1]).
  26. -export([settings_ack/0]).
  27. -export([push_promise/3]).
  28. -export([ping/1]).
  29. -export([ping_ack/1]).
  30. -export([goaway/3]).
  31. -type streamid() :: pos_integer().
  32. -type fin() :: fin | nofin.
  33. -type head_fin() :: head_fin | head_nofin.
  34. -type exclusive() :: exclusive | shared.
  35. -type weight() :: 1..256.
  36. -type settings() :: map().
  37. -type error() :: no_error
  38. | protocol_error
  39. | internal_error
  40. | flow_control_error
  41. | settings_timeout
  42. | stream_closed
  43. | frame_size_error
  44. | refused_stream
  45. | cancel
  46. | compression_error
  47. | connect_error
  48. | enhance_your_calm
  49. | inadequate_security
  50. | http_1_1_required
  51. | unknown_error.
  52. -export_type([error/0]).
  53. -type frame() :: {data, streamid(), fin(), binary()}
  54. | {headers, streamid(), fin(), head_fin(), binary()}
  55. | {headers, streamid(), fin(), head_fin(), exclusive(), streamid(), weight(), binary()}
  56. | {priority, streamid(), exclusive(), streamid(), weight()}
  57. | {rst_stream, streamid(), error()}
  58. | {settings, settings()}
  59. | settings_ack
  60. | {push_promise, streamid(), head_fin(), streamid(), binary()}
  61. | {ping, integer()}
  62. | {ping_ack, integer()}
  63. | {goaway, streamid(), error(), binary()}
  64. | {window_update, non_neg_integer()}
  65. | {window_update, streamid(), non_neg_integer()}
  66. | {continuation, streamid(), head_fin(), binary()}.
  67. -export_type([frame/0]).
  68. %% Parsing.
  69. parse(<< Len:24, _/bits >>, MaxFrameSize) when Len > MaxFrameSize ->
  70. {connection_error, frame_size_error, 'The frame size exceeded SETTINGS_MAX_FRAME_SIZE. (RFC7540 4.2)'};
  71. parse(Data, _) ->
  72. parse(Data).
  73. %%
  74. %% DATA frames.
  75. %%
  76. parse(<< _:24, 0:8, _:9, 0:31, _/bits >>) ->
  77. {connection_error, protocol_error, 'DATA frames MUST be associated with a stream. (RFC7540 6.1)'};
  78. parse(<< 0:24, 0:8, _:4, 1:1, _:35, _/bits >>) ->
  79. {connection_error, frame_size_error, 'DATA frames with padding flag MUST have a length > 0. (RFC7540 6.1)'};
  80. parse(<< Len0:24, 0:8, _:4, 1:1, _:35, PadLen:8, _/bits >>) when PadLen >= Len0 ->
  81. {connection_error, protocol_error, 'Length of padding MUST be less than length of payload. (RFC7540 6.1)'};
  82. %% No padding.
  83. parse(<< Len:24, 0:8, _:4, 0:1, _:2, FlagEndStream:1, _:1, StreamID:31, Data:Len/binary, Rest/bits >>) ->
  84. {ok, {data, StreamID, parse_fin(FlagEndStream), Data}, Rest};
  85. %% Padding.
  86. parse(<< Len0:24, 0:8, _:4, 1:1, _:2, FlagEndStream:1, _:1, StreamID:31, PadLen:8, Rest0/bits >>)
  87. when byte_size(Rest0) >= Len0 - 1 ->
  88. Len = Len0 - PadLen,
  89. case Rest0 of
  90. << Data:Len/binary, 0:PadLen/unit:8, Rest/bits >> ->
  91. {ok, {data, StreamID, parse_fin(FlagEndStream), Data}, Rest};
  92. _ ->
  93. {connection_error, protocol_error, 'Padding octets MUST be set to zero. (RFC7540 6.1)'}
  94. end;
  95. %%
  96. %% HEADERS frames.
  97. %%
  98. parse(<< _:24, 1:8, _:9, 0:31, _/bits >>) ->
  99. {connection_error, protocol_error, 'HEADERS frames MUST be associated with a stream. (RFC7540 6.2)'};
  100. parse(<< 0:24, 1:8, _:4, 1:1, _:35, _/bits >>) ->
  101. {connection_error, frame_size_error, 'HEADERS frames with padding flag MUST have a length > 0. (RFC7540 6.1)'};
  102. parse(<< Len:24, 1:8, _:2, 1:1, _:37, _/bits >>) when Len < 5 ->
  103. {connection_error, frame_size_error, 'HEADERS frames with priority flag MUST have a length >= 5. (RFC7540 6.1)'};
  104. parse(<< Len:24, 1:8, _:2, 1:1, _:37, _/bits >>) when Len < 6 ->
  105. {connection_error, frame_size_error, 'HEADERS frames with padding and priority flags MUST have a length >= 6. (RFC7540 6.1)'};
  106. parse(<< Len0:24, 1:8, _:4, 1:1, _:35, PadLen:8, _/bits >>) when PadLen >= Len0 ->
  107. {connection_error, protocol_error, 'Length of padding MUST be less than length of payload. (RFC7540 6.2)'};
  108. parse(<< Len0:24, 1:8, _:2, 1:1, _:1, 1:1, _:35, PadLen:8, _/bits >>) when PadLen >= Len0 - 5 ->
  109. {connection_error, protocol_error, 'Length of padding MUST be less than length of payload. (RFC7540 6.2)'};
  110. %% No padding, no priority.
  111. parse(<< Len:24, 1:8, _:2, 0:1, _:1, 0:1, FlagEndHeaders:1, _:1, FlagEndStream:1, _:1, StreamID:31,
  112. HeaderBlockFragment:Len/binary, Rest/bits >>) ->
  113. {ok, {headers, StreamID, parse_fin(FlagEndStream), parse_head_fin(FlagEndHeaders), HeaderBlockFragment}, Rest};
  114. %% Padding, no priority.
  115. parse(<< Len0:24, 1:8, _:2, 0:1, _:1, 1:1, FlagEndHeaders:1, _:1, FlagEndStream:1, _:1, StreamID:31,
  116. PadLen:8, Rest0/bits >>) when byte_size(Rest0) >= Len0 - 1 ->
  117. Len = Len0 - PadLen - 1,
  118. case Rest0 of
  119. << HeaderBlockFragment:Len/binary, 0:PadLen/unit:8, Rest/bits >> ->
  120. {ok, {headers, StreamID, parse_fin(FlagEndStream), parse_head_fin(FlagEndHeaders), HeaderBlockFragment}, Rest};
  121. _ ->
  122. {connection_error, protocol_error, 'Padding octets MUST be set to zero. (RFC7540 6.2)'}
  123. end;
  124. %% No padding, priority.
  125. parse(<< Len0:24, 1:8, _:2, 1:1, _:1, 0:1, FlagEndHeaders:1, _:1, FlagEndStream:1, _:1, StreamID:31,
  126. E:1, DepStreamID:31, Weight:8, Rest0/bits >>) when byte_size(Rest0) >= Len0 - 5 ->
  127. Len = Len0 - 5,
  128. << HeaderBlockFragment:Len/binary, Rest/bits >> = Rest0,
  129. {ok, {headers, StreamID, parse_fin(FlagEndStream), parse_head_fin(FlagEndHeaders),
  130. parse_exclusive(E), DepStreamID, Weight + 1, HeaderBlockFragment}, Rest};
  131. %% Padding, priority.
  132. parse(<< Len0:24, 1:8, _:2, 1:1, _:1, 1:1, FlagEndHeaders:1, _:1, FlagEndStream:1, _:1, StreamID:31,
  133. PadLen:8, E:1, DepStreamID:31, Weight:8, Rest0/bits >>) when byte_size(Rest0) >= Len0 - 6 ->
  134. Len = Len0 - PadLen - 6,
  135. case Rest0 of
  136. << HeaderBlockFragment:Len/binary, 0:PadLen/unit:8, Rest/bits >> ->
  137. {ok, {headers, StreamID, parse_fin(FlagEndStream), parse_head_fin(FlagEndHeaders),
  138. parse_exclusive(E), DepStreamID, Weight + 1, HeaderBlockFragment}, Rest};
  139. _ ->
  140. {connection_error, protocol_error, 'Padding octets MUST be set to zero. (RFC7540 6.2)'}
  141. end;
  142. %%
  143. %% PRIORITY frames.
  144. %%
  145. parse(<< 5:24, 2:8, _:9, 0:31, _/bits >>) ->
  146. {connection_error, protocol_error, 'PRIORITY frames MUST be associated with a stream. (RFC7540 6.3)'};
  147. parse(<< 5:24, 2:8, _:9, StreamID:31, E:1, DepStreamID:31, Weight:8, Rest/bits >>) ->
  148. {ok, {priority, StreamID, parse_exclusive(E), DepStreamID, Weight + 1}, Rest};
  149. %% @todo figure out how to best deal with frame size errors; if we have everything fine
  150. %% if not we might want to inform the caller how much he should expect so that it can
  151. %% decide if it should just close the connection
  152. parse(<< BadLen:24, 2:8, _:9, StreamID:31, _:BadLen/binary, Rest/bits >>) ->
  153. {stream_error, StreamID, frame_size_error, 'PRIORITY frames MUST be 5 bytes wide. (RFC7540 6.3)', Rest};
  154. %%
  155. %% RST_STREAM frames.
  156. %%
  157. parse(<< 4:24, 3:8, _:9, 0:31, _/bits >>) ->
  158. {connection_error, protocol_error, 'RST_STREAM frames MUST be associated with a stream. (RFC7540 6.4)'};
  159. parse(<< 4:24, 3:8, _:9, StreamID:31, ErrorCode:32, Rest/bits >>) ->
  160. {ok, {rst_stream, StreamID, parse_error_code(ErrorCode)}, Rest};
  161. %% @todo same as priority
  162. parse(<< _:24, 3:8, _:9, _:31, _/bits >>) ->
  163. {connection_error, frame_size_error, 'RST_STREAM frames MUST be 4 bytes wide. (RFC7540 6.4)'};
  164. %%
  165. %% SETTINGS frames.
  166. %%
  167. parse(<< 0:24, 4:8, _:7, 1:1, _:1, 0:31, Rest/bits >>) ->
  168. {ok, settings_ack, Rest};
  169. parse(<< _:24, 4:8, _:7, 1:1, _:1, 0:31, _/bits >>) ->
  170. {connection_error, frame_size_error, 'SETTINGS frames with the ACK flag set MUST have a length of 0. (RFC7540 6.5)'};
  171. parse(<< Len:24, 4:8, _:7, 0:1, _:1, 0:31, _/bits >>) when Len rem 6 =/= 0 ->
  172. {connection_error, frame_size_error, 'SETTINGS frames MUST have a length multiple of 6. (RFC7540 6.5)'};
  173. parse(<< Len:24, 4:8, _:7, 0:1, _:1, 0:31, Rest/bits >>) when byte_size(Rest) >= Len ->
  174. parse_settings_payload(Rest, Len, #{});
  175. parse(<< _:24, 4:8, _/bits >>) ->
  176. {connection_error, protocol_error, 'SETTINGS frames MUST NOT be associated with a stream. (RFC7540 6.5)'};
  177. %%
  178. %% PUSH_PROMISE frames.
  179. %%
  180. parse(<< Len:24, 5:8, _:40, _/bits >>) when Len < 4 ->
  181. {connection_error, frame_size_error, 'PUSH_PROMISE frames MUST have a length >= 4. (RFC7540 4.2, RFC7540 6.6)'};
  182. parse(<< Len:24, 5:8, _:4, 1:1, _:35, _/bits >>) when Len < 5 ->
  183. {connection_error, frame_size_error, 'PUSH_PROMISE frames with padding flag MUST have a length >= 5. (RFC7540 4.2, RFC7540 6.6)'};
  184. parse(<< _:24, 5:8, _:9, 0:31, _/bits >>) ->
  185. {connection_error, protocol_error, 'PUSH_PROMISE frames MUST be associated with a stream. (RFC7540 6.6)'};
  186. parse(<< Len0:24, 5:8, _:4, 1:1, _:35, PadLen:8, _/bits >>) when PadLen >= Len0 - 4 ->
  187. {connection_error, protocol_error, 'Length of padding MUST be less than length of payload. (RFC7540 6.6)'};
  188. parse(<< Len0:24, 5:8, _:4, 0:1, FlagEndHeaders:1, _:3, StreamID:31, _:1, PromisedStreamID:31, Rest0/bits >>)
  189. when byte_size(Rest0) >= Len0 - 4 ->
  190. Len = Len0 - 4,
  191. << HeaderBlockFragment:Len/binary, Rest/bits >> = Rest0,
  192. {ok, {push_promise, StreamID, parse_head_fin(FlagEndHeaders), PromisedStreamID, HeaderBlockFragment}, Rest};
  193. parse(<< Len0:24, 5:8, _:4, 1:1, FlagEndHeaders:1, _:2, StreamID:31, PadLen:8, _:1, PromisedStreamID:31, Rest0/bits >>)
  194. when byte_size(Rest0) >= Len0 - 5 ->
  195. Len = Len0 - 5,
  196. case Rest0 of
  197. << HeaderBlockFragment:Len/binary, 0:PadLen/unit:8, Rest/bits >> ->
  198. {ok, {push_promise, StreamID, parse_head_fin(FlagEndHeaders), PromisedStreamID, HeaderBlockFragment}, Rest};
  199. _ ->
  200. {connection_error, protocol_error, 'Padding octets MUST be set to zero. (RFC7540 6.6)'}
  201. end;
  202. %%
  203. %% PING frames.
  204. %%
  205. parse(<< 8:24, 6:8, _:7, 1:1, _:1, 0:31, Opaque:64, Rest/bits >>) ->
  206. {ok, {ping_ack, Opaque}, Rest};
  207. parse(<< 8:24, 6:8, _:7, 0:1, _:1, 0:31, Opaque:64, Rest/bits >>) ->
  208. {ok, {ping, Opaque}, Rest};
  209. parse(<< 8:24, 6:8, _:104, _/bits >>) ->
  210. {connection_error, protocol_error, 'PING frames MUST NOT be associated with a stream. (RFC7540 6.7)'};
  211. parse(<< Len:24, 6:8, _/bits >>) when Len =/= 8 ->
  212. {connection_error, frame_size_error, 'PING frames MUST be 8 bytes wide. (RFC7540 6.7)'};
  213. %%
  214. %% GOAWAY frames.
  215. %%
  216. parse(<< Len0:24, 7:8, _:9, 0:31, _:1, LastStreamID:31, ErrorCode:32, Rest0/bits >>) when byte_size(Rest0) >= Len0 - 8 ->
  217. Len = Len0 - 8,
  218. << DebugData:Len/binary, Rest/bits >> = Rest0,
  219. {ok, {goaway, LastStreamID, parse_error_code(ErrorCode), DebugData}, Rest};
  220. parse(<< Len:24, 7:8, _:40, _/bits >>) when Len < 8 ->
  221. {connection_error, frame_size_error, 'GOAWAY frames MUST have a length >= 8. (RFC7540 4.2, RFC7540 6.8)'};
  222. parse(<< _:24, 7:8, _:40, _/bits >>) ->
  223. {connection_error, protocol_error, 'GOAWAY frames MUST NOT be associated with a stream. (RFC7540 6.8)'};
  224. %%
  225. %% WINDOW_UPDATE frames.
  226. %%
  227. parse(<< 4:24, 8:8, _:9, 0:31, _:1, 0:31, _/bits >>) ->
  228. {connection_error, protocol_error, 'WINDOW_UPDATE frames MUST have a non-zero increment. (RFC7540 6.9)'};
  229. parse(<< 4:24, 8:8, _:9, 0:31, _:1, Increment:31, Rest/bits >>) ->
  230. {ok, {window_update, Increment}, Rest};
  231. parse(<< 4:24, 8:8, _:9, StreamID:31, _:1, 0:31, _/bits >>) ->
  232. {stream_error, StreamID, protocol_error, 'WINDOW_UPDATE frames MUST have a non-zero increment. (RFC7540 6.9)'};
  233. parse(<< 4:24, 8:8, _:9, StreamID:31, _:1, Increment:31, Rest/bits >>) ->
  234. {ok, {window_update, StreamID, Increment}, Rest};
  235. parse(<< Len:24, 8:8, _/bits >>) when Len =/= 4->
  236. {connection_error, frame_size_error, 'WINDOW_UPDATE frames MUST be 4 bytes wide. (RFC7540 6.9)'};
  237. %%
  238. %% CONTINUATION frames.
  239. %%
  240. parse(<< _:24, 9:8, _:9, 0:31, _/bits >>) ->
  241. {connection_error, protocol_error, 'CONTINUATION frames MUST be associated with a stream. (RFC7540 6.10)'};
  242. parse(<< Len:24, 9:8, _:5, FlagEndHeaders:1, _:3, StreamID:31, HeaderBlockFragment:Len/binary, Rest/bits >>) ->
  243. {ok, {continuation, StreamID, parse_head_fin(FlagEndHeaders), HeaderBlockFragment}, Rest};
  244. %%
  245. %% Incomplete frames.
  246. %%
  247. parse(_) ->
  248. more.
  249. -ifdef(TEST).
  250. parse_ping_test() ->
  251. Ping = ping(1234567890),
  252. _ = [more = parse(binary:part(Ping, 0, I)) || I <- lists:seq(1, byte_size(Ping) - 1)],
  253. {ok, {ping, 1234567890}, <<>>} = parse(Ping),
  254. {ok, {ping, 1234567890}, << 42 >>} = parse(<< Ping/binary, 42 >>),
  255. ok.
  256. parse_windows_update_test() ->
  257. WindowUpdate = << 4:24, 8:8, 0:9, 0:31, 0:1, 12345:31 >>,
  258. _ = [more = parse(binary:part(WindowUpdate, 0, I)) || I <- lists:seq(1, byte_size(WindowUpdate) - 1)],
  259. {ok, {window_update, 12345}, <<>>} = parse(WindowUpdate),
  260. {ok, {window_update, 12345}, << 42 >>} = parse(<< WindowUpdate/binary, 42 >>),
  261. ok.
  262. -endif.
  263. parse_fin(0) -> nofin;
  264. parse_fin(1) -> fin.
  265. parse_head_fin(0) -> head_nofin;
  266. parse_head_fin(1) -> head_fin.
  267. parse_exclusive(0) -> shared;
  268. parse_exclusive(1) -> exclusive.
  269. parse_error_code( 0) -> no_error;
  270. parse_error_code( 1) -> protocol_error;
  271. parse_error_code( 2) -> internal_error;
  272. parse_error_code( 3) -> flow_control_error;
  273. parse_error_code( 4) -> settings_timeout;
  274. parse_error_code( 5) -> stream_closed;
  275. parse_error_code( 6) -> frame_size_error;
  276. parse_error_code( 7) -> refused_stream;
  277. parse_error_code( 8) -> cancel;
  278. parse_error_code( 9) -> compression_error;
  279. parse_error_code(10) -> connect_error;
  280. parse_error_code(11) -> enhance_your_calm;
  281. parse_error_code(12) -> inadequate_security;
  282. parse_error_code(13) -> http_1_1_required;
  283. parse_error_code(_) -> unknown_error.
  284. parse_settings_payload(SettingsPayload) ->
  285. {ok, {settings, Settings}, <<>>}
  286. = parse_settings_payload(SettingsPayload, byte_size(SettingsPayload), #{}),
  287. Settings.
  288. parse_settings_payload(Rest, 0, Settings) ->
  289. {ok, {settings, Settings}, Rest};
  290. %% SETTINGS_HEADER_TABLE_SIZE.
  291. parse_settings_payload(<< 1:16, Value:32, Rest/bits >>, Len, Settings) ->
  292. parse_settings_payload(Rest, Len - 6, Settings#{header_table_size => Value});
  293. %% SETTINGS_ENABLE_PUSH.
  294. parse_settings_payload(<< 2:16, 0:32, Rest/bits >>, Len, Settings) ->
  295. parse_settings_payload(Rest, Len - 6, Settings#{enable_push => false});
  296. parse_settings_payload(<< 2:16, 1:32, Rest/bits >>, Len, Settings) ->
  297. parse_settings_payload(Rest, Len - 6, Settings#{enable_push => true});
  298. parse_settings_payload(<< 2:16, _:32, _/bits >>, _, _) ->
  299. {connection_error, protocol_error, 'The SETTINGS_ENABLE_PUSH value MUST be 0 or 1. (RFC7540 6.5.2)'};
  300. %% SETTINGS_MAX_CONCURRENT_STREAMS.
  301. parse_settings_payload(<< 3:16, Value:32, Rest/bits >>, Len, Settings) ->
  302. parse_settings_payload(Rest, Len - 6, Settings#{max_concurrent_streams => Value});
  303. %% SETTINGS_INITIAL_WINDOW_SIZE.
  304. parse_settings_payload(<< 4:16, Value:32, _/bits >>, _, _) when Value > 16#7fffffff ->
  305. {connection_error, flow_control_error, 'The maximum SETTINGS_INITIAL_WINDOW_SIZE value is 0x7fffffff. (RFC7540 6.5.2)'};
  306. parse_settings_payload(<< 4:16, Value:32, Rest/bits >>, Len, Settings) ->
  307. parse_settings_payload(Rest, Len - 6, Settings#{initial_window_size => Value});
  308. %% SETTINGS_MAX_FRAME_SIZE.
  309. parse_settings_payload(<< 5:16, Value:32, _/bits >>, _, _) when Value =< 16#3fff ->
  310. {connection_error, protocol_error, 'The SETTINGS_MAX_FRAME_SIZE value must be > 0x3fff. (RFC7540 6.5.2)'};
  311. parse_settings_payload(<< 5:16, Value:32, Rest/bits >>, Len, Settings) when Value =< 16#ffffff ->
  312. parse_settings_payload(Rest, Len - 6, Settings#{max_frame_size => Value});
  313. parse_settings_payload(<< 5:16, _:32, _/bits >>, _, _) ->
  314. {connection_error, protocol_error, 'The SETTINGS_MAX_FRAME_SIZE value must be =< 0xffffff. (RFC7540 6.5.2)'};
  315. %% SETTINGS_MAX_HEADER_LIST_SIZE.
  316. parse_settings_payload(<< 6:16, Value:32, Rest/bits >>, Len, Settings) ->
  317. parse_settings_payload(Rest, Len - 6, Settings#{max_header_list_size => Value});
  318. parse_settings_payload(<< _:48, Rest/bits >>, Len, Settings) ->
  319. parse_settings_payload(Rest, Len - 6, Settings).
  320. %% Building.
  321. %% @todo Check size and create multiple frames if needed.
  322. data(StreamID, IsFin, Data) ->
  323. [data_header(StreamID, IsFin, iolist_size(Data)), Data].
  324. data_header(StreamID, IsFin, Len) ->
  325. FlagEndStream = flag_fin(IsFin),
  326. << Len:24, 0:15, FlagEndStream:1, 0:1, StreamID:31 >>.
  327. %% @todo Check size of HeaderBlock and use CONTINUATION frames if needed.
  328. headers(StreamID, IsFin, HeaderBlock) ->
  329. Len = iolist_size(HeaderBlock),
  330. FlagEndStream = flag_fin(IsFin),
  331. FlagEndHeaders = 1,
  332. [<< Len:24, 1:8, 0:5, FlagEndHeaders:1, 0:1, FlagEndStream:1, 0:1, StreamID:31 >>, HeaderBlock].
  333. rst_stream(StreamID, Reason) ->
  334. ErrorCode = error_code(Reason),
  335. << 4:24, 3:8, 0:9, StreamID:31, ErrorCode:32 >>.
  336. %% @todo Actually implement it. :-)
  337. settings(#{}) ->
  338. << 0:24, 4:8, 0:40 >>.
  339. %% @todo Actually implement it. :-)
  340. settings_payload(#{}) ->
  341. <<>>.
  342. settings_ack() ->
  343. << 0:24, 4:8, 1:8, 0:32 >>.
  344. %% @todo Check size of HeaderBlock and use CONTINUATION frames if needed.
  345. push_promise(StreamID, PromisedStreamID, HeaderBlock) ->
  346. Len = iolist_size(HeaderBlock) + 4,
  347. FlagEndHeaders = 1,
  348. [<< Len:24, 5:8, 0:5, FlagEndHeaders:1, 0:3, StreamID:31, 0:1, PromisedStreamID:31 >>, HeaderBlock].
  349. ping(Opaque) ->
  350. << 8:24, 6:8, 0:40, Opaque:64 >>.
  351. ping_ack(Opaque) ->
  352. << 8:24, 6:8, 0:7, 1:1, 0:32, Opaque:64 >>.
  353. goaway(LastStreamID, Reason, DebugData) ->
  354. ErrorCode = error_code(Reason),
  355. Len = iolist_size(DebugData) + 8,
  356. [<< Len:24, 7:8, 0:41, LastStreamID:31, ErrorCode:32 >>, DebugData].
  357. flag_fin(nofin) -> 0;
  358. flag_fin(fin) -> 1.
  359. error_code(no_error) -> 0;
  360. error_code(protocol_error) -> 1;
  361. error_code(internal_error) -> 2;
  362. error_code(flow_control_error) -> 3;
  363. error_code(settings_timeout) -> 4;
  364. error_code(stream_closed) -> 5;
  365. error_code(frame_size_error) -> 6;
  366. error_code(refused_stream) -> 7;
  367. error_code(cancel) -> 8;
  368. error_code(compression_error) -> 9;
  369. error_code(connect_error) -> 10;
  370. error_code(enhance_your_calm) -> 11;
  371. error_code(inadequate_security) -> 12;
  372. error_code(http_1_1_required) -> 13.