zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

cow_http2.erl (21529B)


      1 %% Copyright (c) 2015-2018, 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 
     15 -module(cow_http2).
     16 
     17 %% Parsing.
     18 -export([parse_sequence/1]).
     19 -export([parse/1]).
     20 -export([parse/2]).
     21 -export([parse_settings_payload/1]).
     22 
     23 %% Building.
     24 -export([data/3]).
     25 -export([data_header/3]).
     26 -export([headers/3]).
     27 -export([priority/4]).
     28 -export([rst_stream/2]).
     29 -export([settings/1]).
     30 -export([settings_payload/1]).
     31 -export([settings_ack/0]).
     32 -export([push_promise/3]).
     33 -export([ping/1]).
     34 -export([ping_ack/1]).
     35 -export([goaway/3]).
     36 -export([window_update/1]).
     37 -export([window_update/2]).
     38 
     39 -type streamid() :: pos_integer().
     40 -export_type([streamid/0]).
     41 
     42 -type fin() :: fin | nofin.
     43 -export_type([fin/0]).
     44 
     45 -type head_fin() :: head_fin | head_nofin.
     46 -export_type([head_fin/0]).
     47 
     48 -type exclusive() :: exclusive | shared.
     49 -type weight() :: 1..256.
     50 -type settings() :: map().
     51 
     52 -type error() :: no_error
     53 	| protocol_error
     54 	| internal_error
     55 	| flow_control_error
     56 	| settings_timeout
     57 	| stream_closed
     58 	| frame_size_error
     59 	| refused_stream
     60 	| cancel
     61 	| compression_error
     62 	| connect_error
     63 	| enhance_your_calm
     64 	| inadequate_security
     65 	| http_1_1_required
     66 	| unknown_error.
     67 -export_type([error/0]).
     68 
     69 -type frame() :: {data, streamid(), fin(), binary()}
     70 	| {headers, streamid(), fin(), head_fin(), binary()}
     71 	| {headers, streamid(), fin(), head_fin(), exclusive(), streamid(), weight(), binary()}
     72 	| {priority, streamid(), exclusive(), streamid(), weight()}
     73 	| {rst_stream, streamid(), error()}
     74 	| {settings, settings()}
     75 	| settings_ack
     76 	| {push_promise, streamid(), head_fin(), streamid(), binary()}
     77 	| {ping, integer()}
     78 	| {ping_ack, integer()}
     79 	| {goaway, streamid(), error(), binary()}
     80 	| {window_update, non_neg_integer()}
     81 	| {window_update, streamid(), non_neg_integer()}
     82 	| {continuation, streamid(), head_fin(), binary()}.
     83 -export_type([frame/0]).
     84 
     85 %% Parsing.
     86 
     87 -spec parse_sequence(binary())
     88 	-> {ok, binary()} | more | {connection_error, error(), atom()}.
     89 parse_sequence(<<"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n", Rest/bits>>) ->
     90 	{ok, Rest};
     91 parse_sequence(Data) when byte_size(Data) >= 24 ->
     92 	{connection_error, protocol_error,
     93 		'The connection preface was invalid. (RFC7540 3.5)'};
     94 parse_sequence(Data) ->
     95 	Len = byte_size(Data),
     96 	<<Preface:Len/binary, _/bits>> = <<"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n">>,
     97 	case Data of
     98 		Preface ->
     99 			more;
    100 		_ ->
    101 			{connection_error, protocol_error,
    102 				'The connection preface was invalid. (RFC7540 3.5)'}
    103 	end.
    104 
    105 parse(<< Len:24, _/bits >>, MaxFrameSize) when Len > MaxFrameSize ->
    106 	{connection_error, frame_size_error, 'The frame size exceeded SETTINGS_MAX_FRAME_SIZE. (RFC7540 4.2)'};
    107 parse(Data, _) ->
    108 	parse(Data).
    109 
    110 %%
    111 %% DATA frames.
    112 %%
    113 parse(<< _:24, 0:8, _:9, 0:31, _/bits >>) ->
    114 	{connection_error, protocol_error, 'DATA frames MUST be associated with a stream. (RFC7540 6.1)'};
    115 parse(<< 0:24, 0:8, _:4, 1:1, _:35, _/bits >>) ->
    116 	{connection_error, frame_size_error, 'DATA frames with padding flag MUST have a length > 0. (RFC7540 6.1)'};
    117 parse(<< Len0:24, 0:8, _:4, 1:1, _:35, PadLen:8, _/bits >>) when PadLen >= Len0 ->
    118 	{connection_error, protocol_error, 'Length of padding MUST be less than length of payload. (RFC7540 6.1)'};
    119 %% No padding.
    120 parse(<< Len:24, 0:8, _:4, 0:1, _:2, FlagEndStream:1, _:1, StreamID:31, Data:Len/binary, Rest/bits >>) ->
    121 	{ok, {data, StreamID, parse_fin(FlagEndStream), Data}, Rest};
    122 %% Padding.
    123 parse(<< Len0:24, 0:8, _:4, 1:1, _:2, FlagEndStream:1, _:1, StreamID:31, PadLen:8, Rest0/bits >>)
    124 		when byte_size(Rest0) >= Len0 - 1 ->
    125 	Len = Len0 - PadLen - 1,
    126 	case Rest0 of
    127 		<< Data:Len/binary, 0:PadLen/unit:8, Rest/bits >> ->
    128 			{ok, {data, StreamID, parse_fin(FlagEndStream), Data}, Rest};
    129 		_ ->
    130 			{connection_error, protocol_error, 'Padding octets MUST be set to zero. (RFC7540 6.1)'}
    131 	end;
    132 %%
    133 %% HEADERS frames.
    134 %%
    135 parse(<< _:24, 1:8, _:9, 0:31, _/bits >>) ->
    136 	{connection_error, protocol_error, 'HEADERS frames MUST be associated with a stream. (RFC7540 6.2)'};
    137 parse(<< 0:24, 1:8, _:4, 1:1, _:35, _/bits >>) ->
    138 	{connection_error, frame_size_error, 'HEADERS frames with padding flag MUST have a length > 0. (RFC7540 6.1)'};
    139 parse(<< Len:24, 1:8, _:2, 1:1, _:37, _/bits >>) when Len < 5 ->
    140 	{connection_error, frame_size_error, 'HEADERS frames with priority flag MUST have a length >= 5. (RFC7540 6.1)'};
    141 parse(<< Len:24, 1:8, _:2, 1:1, _:1, 1:1, _:35, _/bits >>) when Len < 6 ->
    142 	{connection_error, frame_size_error, 'HEADERS frames with padding and priority flags MUST have a length >= 6. (RFC7540 6.1)'};
    143 parse(<< Len0:24, 1:8, _:4, 1:1, _:35, PadLen:8, _/bits >>) when PadLen >= Len0 ->
    144 	{connection_error, protocol_error, 'Length of padding MUST be less than length of payload. (RFC7540 6.2)'};
    145 parse(<< Len0:24, 1:8, _:2, 1:1, _:1, 1:1, _:35, PadLen:8, _/bits >>) when PadLen >= Len0 - 5 ->
    146 	{connection_error, protocol_error, 'Length of padding MUST be less than length of payload. (RFC7540 6.2)'};
    147 %% No padding, no priority.
    148 parse(<< Len:24, 1:8, _:2, 0:1, _:1, 0:1, FlagEndHeaders:1, _:1, FlagEndStream:1, _:1, StreamID:31,
    149 		HeaderBlockFragment:Len/binary, Rest/bits >>) ->
    150 	{ok, {headers, StreamID, parse_fin(FlagEndStream), parse_head_fin(FlagEndHeaders), HeaderBlockFragment}, Rest};
    151 %% Padding, no priority.
    152 parse(<< Len0:24, 1:8, _:2, 0:1, _:1, 1:1, FlagEndHeaders:1, _:1, FlagEndStream:1, _:1, StreamID:31,
    153 		PadLen:8, Rest0/bits >>) when byte_size(Rest0) >= Len0 - 1 ->
    154 	Len = Len0 - PadLen - 1,
    155 	case Rest0 of
    156 		<< HeaderBlockFragment:Len/binary, 0:PadLen/unit:8, Rest/bits >> ->
    157 			{ok, {headers, StreamID, parse_fin(FlagEndStream), parse_head_fin(FlagEndHeaders), HeaderBlockFragment}, Rest};
    158 		_ ->
    159 			{connection_error, protocol_error, 'Padding octets MUST be set to zero. (RFC7540 6.2)'}
    160 	end;
    161 %% No padding, priority.
    162 parse(<< _:24, 1:8, _:2, 1:1, _:1, 0:1, _:4, StreamID:31, _:1, StreamID:31, _/bits >>) ->
    163 	{connection_error, protocol_error,
    164 		'HEADERS frames cannot define a stream that depends on itself. (RFC7540 5.3.1)'};
    165 parse(<< Len0:24, 1:8, _:2, 1:1, _:1, 0:1, FlagEndHeaders:1, _:1, FlagEndStream:1, _:1, StreamID:31,
    166 		E:1, DepStreamID:31, Weight:8, Rest0/bits >>) when byte_size(Rest0) >= Len0 - 5 ->
    167 	Len = Len0 - 5,
    168 	<< HeaderBlockFragment:Len/binary, Rest/bits >> = Rest0,
    169 	{ok, {headers, StreamID, parse_fin(FlagEndStream), parse_head_fin(FlagEndHeaders),
    170 		parse_exclusive(E), DepStreamID, Weight + 1, HeaderBlockFragment}, Rest};
    171 %% Padding, priority.
    172 parse(<< _:24, 1:8, _:2, 1:1, _:1, 1:1, _:4, StreamID:31, _:9, StreamID:31, _/bits >>) ->
    173 	{connection_error, protocol_error,
    174 		'HEADERS frames cannot define a stream that depends on itself. (RFC7540 5.3.1)'};
    175 parse(<< Len0:24, 1:8, _:2, 1:1, _:1, 1:1, FlagEndHeaders:1, _:1, FlagEndStream:1, _:1, StreamID:31,
    176 		PadLen:8, E:1, DepStreamID:31, Weight:8, Rest0/bits >>) when byte_size(Rest0) >= Len0 - 6 ->
    177 	Len = Len0 - PadLen - 6,
    178 	case Rest0 of
    179 		<< HeaderBlockFragment:Len/binary, 0:PadLen/unit:8, Rest/bits >> ->
    180 			{ok, {headers, StreamID, parse_fin(FlagEndStream), parse_head_fin(FlagEndHeaders),
    181 				parse_exclusive(E), DepStreamID, Weight + 1, HeaderBlockFragment}, Rest};
    182 		_ ->
    183 			{connection_error, protocol_error, 'Padding octets MUST be set to zero. (RFC7540 6.2)'}
    184 	end;
    185 %%
    186 %% PRIORITY frames.
    187 %%
    188 parse(<< 5:24, 2:8, _:9, 0:31, _/bits >>) ->
    189 	{connection_error, protocol_error, 'PRIORITY frames MUST be associated with a stream. (RFC7540 6.3)'};
    190 parse(<< 5:24, 2:8, _:9, StreamID:31, _:1, StreamID:31, _:8, Rest/bits >>) ->
    191 	{stream_error, StreamID, protocol_error,
    192 		'PRIORITY frames cannot make a stream depend on itself. (RFC7540 5.3.1)', Rest};
    193 parse(<< 5:24, 2:8, _:9, StreamID:31, E:1, DepStreamID:31, Weight:8, Rest/bits >>) ->
    194 	{ok, {priority, StreamID, parse_exclusive(E), DepStreamID, Weight + 1}, Rest};
    195 %% @todo figure out how to best deal with frame size errors; if we have everything fine
    196 %% if not we might want to inform the caller how much he should expect so that it can
    197 %% decide if it should just close the connection
    198 parse(<< BadLen:24, 2:8, _:9, StreamID:31, _:BadLen/binary, Rest/bits >>) ->
    199 	{stream_error, StreamID, frame_size_error, 'PRIORITY frames MUST be 5 bytes wide. (RFC7540 6.3)', Rest};
    200 %%
    201 %% RST_STREAM frames.
    202 %%
    203 parse(<< 4:24, 3:8, _:9, 0:31, _/bits >>) ->
    204 	{connection_error, protocol_error, 'RST_STREAM frames MUST be associated with a stream. (RFC7540 6.4)'};
    205 parse(<< 4:24, 3:8, _:9, StreamID:31, ErrorCode:32, Rest/bits >>) ->
    206 	{ok, {rst_stream, StreamID, parse_error_code(ErrorCode)}, Rest};
    207 %% @todo same as priority
    208 parse(<< _:24, 3:8, _:9, _:31, _/bits >>) ->
    209 	{connection_error, frame_size_error, 'RST_STREAM frames MUST be 4 bytes wide. (RFC7540 6.4)'};
    210 %%
    211 %% SETTINGS frames.
    212 %%
    213 parse(<< 0:24, 4:8, _:7, 1:1, _:1, 0:31, Rest/bits >>) ->
    214 	{ok, settings_ack, Rest};
    215 parse(<< _:24, 4:8, _:7, 1:1, _:1, 0:31, _/bits >>) ->
    216 	{connection_error, frame_size_error, 'SETTINGS frames with the ACK flag set MUST have a length of 0. (RFC7540 6.5)'};
    217 parse(<< Len:24, 4:8, _:7, 0:1, _:1, 0:31, _/bits >>) when Len rem 6 =/= 0 ->
    218 	{connection_error, frame_size_error, 'SETTINGS frames MUST have a length multiple of 6. (RFC7540 6.5)'};
    219 parse(<< Len:24, 4:8, _:7, 0:1, _:1, 0:31, Rest/bits >>) when byte_size(Rest) >= Len ->
    220 	parse_settings_payload(Rest, Len, #{});
    221 parse(<< _:24, 4:8, _:8, _:1, StreamID:31, _/bits >>) when StreamID =/= 0 ->
    222 	{connection_error, protocol_error, 'SETTINGS frames MUST NOT be associated with a stream. (RFC7540 6.5)'};
    223 %%
    224 %% PUSH_PROMISE frames.
    225 %%
    226 parse(<< Len:24, 5:8, _:40, _/bits >>) when Len < 4 ->
    227 	{connection_error, frame_size_error, 'PUSH_PROMISE frames MUST have a length >= 4. (RFC7540 4.2, RFC7540 6.6)'};
    228 parse(<< Len:24, 5:8, _:4, 1:1, _:35, _/bits >>) when Len < 5 ->
    229 	{connection_error, frame_size_error, 'PUSH_PROMISE frames with padding flag MUST have a length >= 5. (RFC7540 4.2, RFC7540 6.6)'};
    230 parse(<< _:24, 5:8, _:9, 0:31, _/bits >>) ->
    231 	{connection_error, protocol_error, 'PUSH_PROMISE frames MUST be associated with a stream. (RFC7540 6.6)'};
    232 parse(<< Len0:24, 5:8, _:4, 1:1, _:35, PadLen:8, _/bits >>) when PadLen >= Len0 - 4 ->
    233 	{connection_error, protocol_error, 'Length of padding MUST be less than length of payload. (RFC7540 6.6)'};
    234 parse(<< Len0:24, 5:8, _:4, 0:1, FlagEndHeaders:1, _:3, StreamID:31, _:1, PromisedStreamID:31, Rest0/bits >>)
    235 		when byte_size(Rest0) >= Len0 - 4 ->
    236 	Len = Len0 - 4,
    237 	<< HeaderBlockFragment:Len/binary, Rest/bits >> = Rest0,
    238 	{ok, {push_promise, StreamID, parse_head_fin(FlagEndHeaders), PromisedStreamID, HeaderBlockFragment}, Rest};
    239 parse(<< Len0:24, 5:8, _:4, 1:1, FlagEndHeaders:1, _:2, StreamID:31, PadLen:8, _:1, PromisedStreamID:31, Rest0/bits >>)
    240 		when byte_size(Rest0) >= Len0 - 5 ->
    241 	Len = Len0 - 5,
    242 	case Rest0 of
    243 		<< HeaderBlockFragment:Len/binary, 0:PadLen/unit:8, Rest/bits >> ->
    244 			{ok, {push_promise, StreamID, parse_head_fin(FlagEndHeaders), PromisedStreamID, HeaderBlockFragment}, Rest};
    245 		_ ->
    246 			{connection_error, protocol_error, 'Padding octets MUST be set to zero. (RFC7540 6.6)'}
    247 	end;
    248 %%
    249 %% PING frames.
    250 %%
    251 parse(<< 8:24, 6:8, _:7, 1:1, _:1, 0:31, Opaque:64, Rest/bits >>) ->
    252 	{ok, {ping_ack, Opaque}, Rest};
    253 parse(<< 8:24, 6:8, _:7, 0:1, _:1, 0:31, Opaque:64, Rest/bits >>) ->
    254 	{ok, {ping, Opaque}, Rest};
    255 parse(<< 8:24, 6:8, _:104, _/bits >>) ->
    256 	{connection_error, protocol_error, 'PING frames MUST NOT be associated with a stream. (RFC7540 6.7)'};
    257 parse(<< Len:24, 6:8, _/bits >>) when Len =/= 8 ->
    258 	{connection_error, frame_size_error, 'PING frames MUST be 8 bytes wide. (RFC7540 6.7)'};
    259 %%
    260 %% GOAWAY frames.
    261 %%
    262 parse(<< Len0:24, 7:8, _:9, 0:31, _:1, LastStreamID:31, ErrorCode:32, Rest0/bits >>) when byte_size(Rest0) >= Len0 - 8 ->
    263 	Len = Len0 - 8,
    264 	<< DebugData:Len/binary, Rest/bits >> = Rest0,
    265 	{ok, {goaway, LastStreamID, parse_error_code(ErrorCode), DebugData}, Rest};
    266 parse(<< Len:24, 7:8, _:40, _/bits >>) when Len < 8 ->
    267 	{connection_error, frame_size_error, 'GOAWAY frames MUST have a length >= 8. (RFC7540 4.2, RFC7540 6.8)'};
    268 parse(<< _:24, 7:8, _:40, _/bits >>) ->
    269 	{connection_error, protocol_error, 'GOAWAY frames MUST NOT be associated with a stream. (RFC7540 6.8)'};
    270 %%
    271 %% WINDOW_UPDATE frames.
    272 %%
    273 parse(<< 4:24, 8:8, _:9, 0:31, _:1, 0:31, _/bits >>) ->
    274 	{connection_error, protocol_error, 'WINDOW_UPDATE frames MUST have a non-zero increment. (RFC7540 6.9)'};
    275 parse(<< 4:24, 8:8, _:9, 0:31, _:1, Increment:31, Rest/bits >>) ->
    276 	{ok, {window_update, Increment}, Rest};
    277 parse(<< 4:24, 8:8, _:9, StreamID:31, _:1, 0:31, Rest/bits >>) ->
    278 	{stream_error, StreamID, protocol_error, 'WINDOW_UPDATE frames MUST have a non-zero increment. (RFC7540 6.9)', Rest};
    279 parse(<< 4:24, 8:8, _:9, StreamID:31, _:1, Increment:31, Rest/bits >>) ->
    280 	{ok, {window_update, StreamID, Increment}, Rest};
    281 parse(<< Len:24, 8:8, _/bits >>) when Len =/= 4->
    282 	{connection_error, frame_size_error, 'WINDOW_UPDATE frames MUST be 4 bytes wide. (RFC7540 6.9)'};
    283 %%
    284 %% CONTINUATION frames.
    285 %%
    286 parse(<< _:24, 9:8, _:9, 0:31, _/bits >>) ->
    287 	{connection_error, protocol_error, 'CONTINUATION frames MUST be associated with a stream. (RFC7540 6.10)'};
    288 parse(<< Len:24, 9:8, _:5, FlagEndHeaders:1, _:3, StreamID:31, HeaderBlockFragment:Len/binary, Rest/bits >>) ->
    289 	{ok, {continuation, StreamID, parse_head_fin(FlagEndHeaders), HeaderBlockFragment}, Rest};
    290 %%
    291 %% Unknown frames are ignored.
    292 %%
    293 parse(<< Len:24, Type:8, _:40, _:Len/binary, Rest/bits >>) when Type > 9 ->
    294 	{ignore, Rest};
    295 %%
    296 %% Incomplete frames.
    297 %%
    298 parse(_) ->
    299 	more.
    300 
    301 -ifdef(TEST).
    302 parse_ping_test() ->
    303 	Ping = ping(1234567890),
    304 	_ = [more = parse(binary:part(Ping, 0, I)) || I <- lists:seq(1, byte_size(Ping) - 1)],
    305 	{ok, {ping, 1234567890}, <<>>} = parse(Ping),
    306 	{ok, {ping, 1234567890}, << 42 >>} = parse(<< Ping/binary, 42 >>),
    307 	ok.
    308 
    309 parse_windows_update_test() ->
    310 	WindowUpdate = << 4:24, 8:8, 0:9, 0:31, 0:1, 12345:31 >>,
    311 	_ = [more = parse(binary:part(WindowUpdate, 0, I)) || I <- lists:seq(1, byte_size(WindowUpdate) - 1)],
    312 	{ok, {window_update, 12345}, <<>>} = parse(WindowUpdate),
    313 	{ok, {window_update, 12345}, << 42 >>} = parse(<< WindowUpdate/binary, 42 >>),
    314 	ok.
    315 
    316 parse_settings_test() ->
    317 	more = parse(<< 0:24, 4:8, 1:8, 0:8 >>),
    318 	{ok, settings_ack, <<>>} = parse(<< 0:24, 4:8, 1:8, 0:32 >>),
    319 	{connection_error, protocol_error, _} = parse(<< 0:24, 4:8, 1:8, 0:1, 1:31 >>),
    320 	ok.
    321 -endif.
    322 
    323 parse_fin(0) -> nofin;
    324 parse_fin(1) -> fin.
    325 
    326 parse_head_fin(0) -> head_nofin;
    327 parse_head_fin(1) -> head_fin.
    328 
    329 parse_exclusive(0) -> shared;
    330 parse_exclusive(1) -> exclusive.
    331 
    332 parse_error_code( 0) -> no_error;
    333 parse_error_code( 1) -> protocol_error;
    334 parse_error_code( 2) -> internal_error;
    335 parse_error_code( 3) -> flow_control_error;
    336 parse_error_code( 4) -> settings_timeout;
    337 parse_error_code( 5) -> stream_closed;
    338 parse_error_code( 6) -> frame_size_error;
    339 parse_error_code( 7) -> refused_stream;
    340 parse_error_code( 8) -> cancel;
    341 parse_error_code( 9) -> compression_error;
    342 parse_error_code(10) -> connect_error;
    343 parse_error_code(11) -> enhance_your_calm;
    344 parse_error_code(12) -> inadequate_security;
    345 parse_error_code(13) -> http_1_1_required;
    346 parse_error_code(_) -> unknown_error.
    347 
    348 parse_settings_payload(SettingsPayload) ->
    349 	{ok, {settings, Settings}, <<>>}
    350 		= parse_settings_payload(SettingsPayload, byte_size(SettingsPayload), #{}),
    351 	Settings.
    352 
    353 parse_settings_payload(Rest, 0, Settings) ->
    354 	{ok, {settings, Settings}, Rest};
    355 %% SETTINGS_HEADER_TABLE_SIZE.
    356 parse_settings_payload(<< 1:16, Value:32, Rest/bits >>, Len, Settings) ->
    357 	parse_settings_payload(Rest, Len - 6, Settings#{header_table_size => Value});
    358 %% SETTINGS_ENABLE_PUSH.
    359 parse_settings_payload(<< 2:16, 0:32, Rest/bits >>, Len, Settings) ->
    360 	parse_settings_payload(Rest, Len - 6, Settings#{enable_push => false});
    361 parse_settings_payload(<< 2:16, 1:32, Rest/bits >>, Len, Settings) ->
    362 	parse_settings_payload(Rest, Len - 6, Settings#{enable_push => true});
    363 parse_settings_payload(<< 2:16, _:32, _/bits >>, _, _) ->
    364 	{connection_error, protocol_error, 'The SETTINGS_ENABLE_PUSH value MUST be 0 or 1. (RFC7540 6.5.2)'};
    365 %% SETTINGS_MAX_CONCURRENT_STREAMS.
    366 parse_settings_payload(<< 3:16, Value:32, Rest/bits >>, Len, Settings) ->
    367 	parse_settings_payload(Rest, Len - 6, Settings#{max_concurrent_streams => Value});
    368 %% SETTINGS_INITIAL_WINDOW_SIZE.
    369 parse_settings_payload(<< 4:16, Value:32, _/bits >>, _, _) when Value > 16#7fffffff ->
    370 	{connection_error, flow_control_error, 'The maximum SETTINGS_INITIAL_WINDOW_SIZE value is 0x7fffffff. (RFC7540 6.5.2)'};
    371 parse_settings_payload(<< 4:16, Value:32, Rest/bits >>, Len, Settings) ->
    372 	parse_settings_payload(Rest, Len - 6, Settings#{initial_window_size => Value});
    373 %% SETTINGS_MAX_FRAME_SIZE.
    374 parse_settings_payload(<< 5:16, Value:32, _/bits >>, _, _) when Value =< 16#3fff ->
    375 	{connection_error, protocol_error, 'The SETTINGS_MAX_FRAME_SIZE value must be > 0x3fff. (RFC7540 6.5.2)'};
    376 parse_settings_payload(<< 5:16, Value:32, Rest/bits >>, Len, Settings) when Value =< 16#ffffff ->
    377 	parse_settings_payload(Rest, Len - 6, Settings#{max_frame_size => Value});
    378 parse_settings_payload(<< 5:16, _:32, _/bits >>, _, _) ->
    379 	{connection_error, protocol_error, 'The SETTINGS_MAX_FRAME_SIZE value must be =< 0xffffff. (RFC7540 6.5.2)'};
    380 %% SETTINGS_MAX_HEADER_LIST_SIZE.
    381 parse_settings_payload(<< 6:16, Value:32, Rest/bits >>, Len, Settings) ->
    382 	parse_settings_payload(Rest, Len - 6, Settings#{max_header_list_size => Value});
    383 %% SETTINGS_ENABLE_CONNECT_PROTOCOL.
    384 parse_settings_payload(<< 8:16, 0:32, Rest/bits >>, Len, Settings) ->
    385 	parse_settings_payload(Rest, Len - 6, Settings#{enable_connect_protocol => false});
    386 parse_settings_payload(<< 8:16, 1:32, Rest/bits >>, Len, Settings) ->
    387 	parse_settings_payload(Rest, Len - 6, Settings#{enable_connect_protocol => true});
    388 parse_settings_payload(<< 8:16, _:32, _/bits >>, _, _) ->
    389 	{connection_error, protocol_error, 'The SETTINGS_ENABLE_CONNECT_PROTOCOL value MUST be 0 or 1. (draft-h2-websockets-01 3)'};
    390 %% Ignore unknown settings.
    391 parse_settings_payload(<< _:48, Rest/bits >>, Len, Settings) ->
    392 	parse_settings_payload(Rest, Len - 6, Settings).
    393 
    394 %% Building.
    395 
    396 data(StreamID, IsFin, Data) ->
    397 	[data_header(StreamID, IsFin, iolist_size(Data)), Data].
    398 
    399 data_header(StreamID, IsFin, Len) ->
    400 	FlagEndStream = flag_fin(IsFin),
    401 	<< Len:24, 0:15, FlagEndStream:1, 0:1, StreamID:31 >>.
    402 
    403 %% @todo Check size of HeaderBlock and use CONTINUATION frames if needed.
    404 headers(StreamID, IsFin, HeaderBlock) ->
    405 	Len = iolist_size(HeaderBlock),
    406 	FlagEndStream = flag_fin(IsFin),
    407 	FlagEndHeaders = 1,
    408 	[<< Len:24, 1:8, 0:5, FlagEndHeaders:1, 0:1, FlagEndStream:1, 0:1, StreamID:31 >>, HeaderBlock].
    409 
    410 priority(StreamID, E, DepStreamID, Weight) ->
    411 	FlagExclusive = exclusive(E),
    412 	<< 5:24, 2:8, 0:9, StreamID:31, FlagExclusive:1, DepStreamID:31, Weight:8 >>.
    413 
    414 rst_stream(StreamID, Reason) ->
    415 	ErrorCode = error_code(Reason),
    416 	<< 4:24, 3:8, 0:9, StreamID:31, ErrorCode:32 >>.
    417 
    418 settings(Settings) ->
    419 	Payload = settings_payload(Settings),
    420 	Len = iolist_size(Payload),
    421 	[<< Len:24, 4:8, 0:40 >>, Payload].
    422 
    423 settings_payload(Settings) ->
    424 	[case Key of
    425 		header_table_size -> <<1:16, Value:32>>;
    426 		enable_push when Value -> <<2:16, 1:32>>;
    427 		enable_push -> <<2:16, 0:32>>;
    428 		max_concurrent_streams when Value =:= infinity -> <<>>;
    429 		max_concurrent_streams -> <<3:16, Value:32>>;
    430 		initial_window_size -> <<4:16, Value:32>>;
    431 		max_frame_size -> <<5:16, Value:32>>;
    432 		max_header_list_size when Value =:= infinity -> <<>>;
    433 		max_header_list_size -> <<6:16, Value:32>>;
    434 		enable_connect_protocol when Value -> <<8:16, 1:32>>;
    435 		enable_connect_protocol -> <<8:16, 0:32>>
    436 	end || {Key, Value} <- maps:to_list(Settings)].
    437 
    438 settings_ack() ->
    439 	<< 0:24, 4:8, 1:8, 0:32 >>.
    440 
    441 %% @todo Check size of HeaderBlock and use CONTINUATION frames if needed.
    442 push_promise(StreamID, PromisedStreamID, HeaderBlock) ->
    443 	Len = iolist_size(HeaderBlock) + 4,
    444 	FlagEndHeaders = 1,
    445 	[<< Len:24, 5:8, 0:5, FlagEndHeaders:1, 0:3, StreamID:31, 0:1, PromisedStreamID:31 >>, HeaderBlock].
    446 
    447 ping(Opaque) ->
    448 	<< 8:24, 6:8, 0:40, Opaque:64 >>.
    449 
    450 ping_ack(Opaque) ->
    451 	<< 8:24, 6:8, 0:7, 1:1, 0:32, Opaque:64 >>.
    452 
    453 goaway(LastStreamID, Reason, DebugData) ->
    454 	ErrorCode = error_code(Reason),
    455 	Len = iolist_size(DebugData) + 8,
    456 	[<< Len:24, 7:8, 0:41, LastStreamID:31, ErrorCode:32 >>, DebugData].
    457 
    458 window_update(Increment) ->
    459 	window_update(0, Increment).
    460 
    461 window_update(StreamID, Increment) when Increment =< 16#7fffffff ->
    462 	<< 4:24, 8:8, 0:8, StreamID:32, 0:1, Increment:31 >>.
    463 
    464 flag_fin(nofin) -> 0;
    465 flag_fin(fin) -> 1.
    466 
    467 exclusive(shared) -> 0;
    468 exclusive(exclusive) -> 1.
    469 
    470 error_code(no_error) -> 0;
    471 error_code(protocol_error) -> 1;
    472 error_code(internal_error) -> 2;
    473 error_code(flow_control_error) -> 3;
    474 error_code(settings_timeout) -> 4;
    475 error_code(stream_closed) -> 5;
    476 error_code(frame_size_error) -> 6;
    477 error_code(refused_stream) -> 7;
    478 error_code(cancel) -> 8;
    479 error_code(compression_error) -> 9;
    480 error_code(connect_error) -> 10;
    481 error_code(enhance_your_calm) -> 11;
    482 error_code(inadequate_security) -> 12;
    483 error_code(http_1_1_required) -> 13.