cow_hpack.erl (72419B)
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 %% The current implementation is not suitable for use in 16 %% intermediaries as the information about headers that 17 %% should never be indexed is currently lost. 18 19 -module(cow_hpack). 20 -dialyzer(no_improper_lists). 21 22 -export([init/0]). 23 -export([init/1]). 24 -export([set_max_size/2]). 25 26 -export([decode/1]). 27 -export([decode/2]). 28 29 -export([encode/1]). 30 -export([encode/2]). 31 -export([encode/3]). 32 33 -record(state, { 34 size = 0 :: non_neg_integer(), 35 max_size = 4096 :: non_neg_integer(), 36 configured_max_size = 4096 :: non_neg_integer(), 37 dyn_table = [] :: [{pos_integer(), {binary(), binary()}}] 38 }). 39 40 -opaque state() :: #state{}. 41 -export_type([state/0]). 42 43 -type opts() :: map(). 44 -export_type([opts/0]). 45 46 -ifdef(TEST). 47 -include_lib("proper/include/proper.hrl"). 48 -endif. 49 50 %% State initialization. 51 52 -spec init() -> state(). 53 init() -> 54 #state{}. 55 56 -spec init(non_neg_integer()) -> state(). 57 init(MaxSize) -> 58 #state{max_size=MaxSize, configured_max_size=MaxSize}. 59 60 %% Update the configured max size. 61 %% 62 %% When decoding, the local endpoint also needs to send a SETTINGS 63 %% frame with this value and it is then up to the remote endpoint 64 %% to decide what actual limit it will use. The actual limit is 65 %% signaled via dynamic table size updates in the encoded data. 66 %% 67 %% When encoding, the local endpoint will call this function after 68 %% receiving a SETTINGS frame with this value. The encoder will 69 %% then use this value as the new max after signaling via a dynamic 70 %% table size update. The value given as argument may be lower 71 %% than the one received in the SETTINGS. 72 73 -spec set_max_size(non_neg_integer(), State) -> State when State::state(). 74 set_max_size(MaxSize, State) -> 75 State#state{configured_max_size=MaxSize}. 76 77 %% Decoding. 78 79 -spec decode(binary()) -> {cow_http:headers(), state()}. 80 decode(Data) -> 81 decode(Data, init()). 82 83 -spec decode(binary(), State) -> {cow_http:headers(), State} when State::state(). 84 %% Dynamic table size update is only allowed at the beginning of a HEADERS block. 85 decode(<< 0:2, 1:1, Rest/bits >>, State=#state{configured_max_size=ConfigMaxSize}) -> 86 {MaxSize, Rest2} = dec_int5(Rest), 87 if 88 MaxSize =< ConfigMaxSize -> 89 State2 = table_update_size(MaxSize, State), 90 decode(Rest2, State2) 91 end; 92 decode(Data, State) -> 93 decode(Data, State, []). 94 95 decode(<<>>, State, Acc) -> 96 {lists:reverse(Acc), State}; 97 %% Indexed header field representation. 98 decode(<< 1:1, Rest/bits >>, State, Acc) -> 99 dec_indexed(Rest, State, Acc); 100 %% Literal header field with incremental indexing: new name. 101 decode(<< 0:1, 1:1, 0:6, Rest/bits >>, State, Acc) -> 102 dec_lit_index_new_name(Rest, State, Acc); 103 %% Literal header field with incremental indexing: indexed name. 104 decode(<< 0:1, 1:1, Rest/bits >>, State, Acc) -> 105 dec_lit_index_indexed_name(Rest, State, Acc); 106 %% Literal header field without indexing: new name. 107 decode(<< 0:8, Rest/bits >>, State, Acc) -> 108 dec_lit_no_index_new_name(Rest, State, Acc); 109 %% Literal header field without indexing: indexed name. 110 decode(<< 0:4, Rest/bits >>, State, Acc) -> 111 dec_lit_no_index_indexed_name(Rest, State, Acc); 112 %% Literal header field never indexed: new name. 113 %% @todo Keep track of "never indexed" headers. 114 decode(<< 0:3, 1:1, 0:4, Rest/bits >>, State, Acc) -> 115 dec_lit_no_index_new_name(Rest, State, Acc); 116 %% Literal header field never indexed: indexed name. 117 %% @todo Keep track of "never indexed" headers. 118 decode(<< 0:3, 1:1, Rest/bits >>, State, Acc) -> 119 dec_lit_no_index_indexed_name(Rest, State, Acc). 120 121 %% Indexed header field representation. 122 123 %% We do the integer decoding inline where appropriate, falling 124 %% back to dec_big_int for larger values. 125 dec_indexed(<<2#1111111:7, 0:1, Int:7, Rest/bits>>, State, Acc) -> 126 {Name, Value} = table_get(127 + Int, State), 127 decode(Rest, State, [{Name, Value}|Acc]); 128 dec_indexed(<<2#1111111:7, Rest0/bits>>, State, Acc) -> 129 {Index, Rest} = dec_big_int(Rest0, 127, 0), 130 {Name, Value} = table_get(Index, State), 131 decode(Rest, State, [{Name, Value}|Acc]); 132 dec_indexed(<<Index:7, Rest/bits>>, State, Acc) -> 133 {Name, Value} = table_get(Index, State), 134 decode(Rest, State, [{Name, Value}|Acc]). 135 136 %% Literal header field with incremental indexing. 137 138 dec_lit_index_new_name(Rest, State, Acc) -> 139 {Name, Rest2} = dec_str(Rest), 140 dec_lit_index(Rest2, State, Acc, Name). 141 142 %% We do the integer decoding inline where appropriate, falling 143 %% back to dec_big_int for larger values. 144 dec_lit_index_indexed_name(<<2#111111:6, 0:1, Int:7, Rest/bits>>, State, Acc) -> 145 Name = table_get_name(63 + Int, State), 146 dec_lit_index(Rest, State, Acc, Name); 147 dec_lit_index_indexed_name(<<2#111111:6, Rest0/bits>>, State, Acc) -> 148 {Index, Rest} = dec_big_int(Rest0, 63, 0), 149 Name = table_get_name(Index, State), 150 dec_lit_index(Rest, State, Acc, Name); 151 dec_lit_index_indexed_name(<<Index:6, Rest/bits>>, State, Acc) -> 152 Name = table_get_name(Index, State), 153 dec_lit_index(Rest, State, Acc, Name). 154 155 dec_lit_index(Rest, State, Acc, Name) -> 156 {Value, Rest2} = dec_str(Rest), 157 State2 = table_insert({Name, Value}, State), 158 decode(Rest2, State2, [{Name, Value}|Acc]). 159 160 %% Literal header field without indexing. 161 162 dec_lit_no_index_new_name(Rest, State, Acc) -> 163 {Name, Rest2} = dec_str(Rest), 164 dec_lit_no_index(Rest2, State, Acc, Name). 165 166 %% We do the integer decoding inline where appropriate, falling 167 %% back to dec_big_int for larger values. 168 dec_lit_no_index_indexed_name(<<2#1111:4, 0:1, Int:7, Rest/bits>>, State, Acc) -> 169 Name = table_get_name(15 + Int, State), 170 dec_lit_no_index(Rest, State, Acc, Name); 171 dec_lit_no_index_indexed_name(<<2#1111:4, Rest0/bits>>, State, Acc) -> 172 {Index, Rest} = dec_big_int(Rest0, 15, 0), 173 Name = table_get_name(Index, State), 174 dec_lit_no_index(Rest, State, Acc, Name); 175 dec_lit_no_index_indexed_name(<<Index:4, Rest/bits>>, State, Acc) -> 176 Name = table_get_name(Index, State), 177 dec_lit_no_index(Rest, State, Acc, Name). 178 179 dec_lit_no_index(Rest, State, Acc, Name) -> 180 {Value, Rest2} = dec_str(Rest), 181 decode(Rest2, State, [{Name, Value}|Acc]). 182 183 %% @todo Literal header field never indexed. 184 185 %% Decode an integer. 186 187 %% The HPACK format has 4 different integer prefixes length (from 4 to 7) 188 %% and each can be used to create an indefinite length integer if all bits 189 %% of the prefix are set to 1. 190 191 dec_int5(<< 2#11111:5, Rest/bits >>) -> 192 dec_big_int(Rest, 31, 0); 193 dec_int5(<< Int:5, Rest/bits >>) -> 194 {Int, Rest}. 195 196 dec_big_int(<< 0:1, Value:7, Rest/bits >>, Int, M) -> 197 {Int + (Value bsl M), Rest}; 198 dec_big_int(<< 1:1, Value:7, Rest/bits >>, Int, M) -> 199 dec_big_int(Rest, Int + (Value bsl M), M + 7). 200 201 %% Decode a string. 202 203 dec_str(<<0:1, 2#1111111:7, Rest0/bits>>) -> 204 {Length, Rest1} = dec_big_int(Rest0, 127, 0), 205 <<Str:Length/binary, Rest/bits>> = Rest1, 206 {Str, Rest}; 207 dec_str(<<0:1, Length:7, Rest0/bits>>) -> 208 <<Str:Length/binary, Rest/bits>> = Rest0, 209 {Str, Rest}; 210 dec_str(<<1:1, 2#1111111:7, Rest0/bits>>) -> 211 {Length, Rest} = dec_big_int(Rest0, 127, 0), 212 dec_huffman(Rest, Length, 0, <<>>); 213 dec_str(<<1:1, Length:7, Rest/bits>>) -> 214 dec_huffman(Rest, Length, 0, <<>>). 215 216 %% We use a lookup table that allows us to benefit from 217 %% the binary match context optimization. A more naive 218 %% implementation using bit pattern matching cannot reuse 219 %% a match context because it wouldn't always match on 220 %% byte boundaries. 221 %% 222 %% See cow_hpack_dec_huffman_lookup.hrl for more details. 223 224 dec_huffman(<<A:4, B:4, R/bits>>, Len, Huff0, Acc) when Len > 1 -> 225 {_, CharA, Huff1} = dec_huffman_lookup(Huff0, A), 226 {_, CharB, Huff} = dec_huffman_lookup(Huff1, B), 227 case {CharA, CharB} of 228 {undefined, undefined} -> dec_huffman(R, Len - 1, Huff, Acc); 229 {CharA, undefined} -> dec_huffman(R, Len - 1, Huff, <<Acc/binary, CharA>>); 230 {undefined, CharB} -> dec_huffman(R, Len - 1, Huff, <<Acc/binary, CharB>>); 231 {CharA, CharB} -> dec_huffman(R, Len - 1, Huff, <<Acc/binary, CharA, CharB>>) 232 end; 233 dec_huffman(<<A:4, B:4, Rest/bits>>, 1, Huff0, Acc) -> 234 {_, CharA, Huff} = dec_huffman_lookup(Huff0, A), 235 {ok, CharB, _} = dec_huffman_lookup(Huff, B), 236 case {CharA, CharB} of 237 %% {undefined, undefined} (> 7-bit final padding) is rejected with a crash. 238 {CharA, undefined} -> 239 {<<Acc/binary, CharA>>, Rest}; 240 {undefined, CharB} -> 241 {<<Acc/binary, CharB>>, Rest}; 242 _ -> 243 {<<Acc/binary, CharA, CharB>>, Rest} 244 end; 245 %% Can only be reached when the string length to decode is 0. 246 dec_huffman(Rest, 0, _, <<>>) -> 247 {<<>>, Rest}. 248 249 -include("cow_hpack_dec_huffman_lookup.hrl"). 250 251 -ifdef(TEST). 252 %% Test case extracted from h2spec. 253 decode_reject_eos_test() -> 254 {'EXIT', _} = (catch decode(<<16#0085f2b24a84ff874951fffffffa7f:120>>)), 255 ok. 256 257 req_decode_test() -> 258 %% First request (raw then huffman). 259 {Headers1, State1} = decode(<< 16#828684410f7777772e6578616d706c652e636f6d:160 >>), 260 {Headers1, State1} = decode(<< 16#828684418cf1e3c2e5f23a6ba0ab90f4ff:136 >>), 261 Headers1 = [ 262 {<<":method">>, <<"GET">>}, 263 {<<":scheme">>, <<"http">>}, 264 {<<":path">>, <<"/">>}, 265 {<<":authority">>, <<"www.example.com">>} 266 ], 267 #state{size=57, dyn_table=[{57,{<<":authority">>, <<"www.example.com">>}}]} = State1, 268 %% Second request (raw then huffman). 269 {Headers2, State2} = decode(<< 16#828684be58086e6f2d6361636865:112 >>, State1), 270 {Headers2, State2} = decode(<< 16#828684be5886a8eb10649cbf:96 >>, State1), 271 Headers2 = [ 272 {<<":method">>, <<"GET">>}, 273 {<<":scheme">>, <<"http">>}, 274 {<<":path">>, <<"/">>}, 275 {<<":authority">>, <<"www.example.com">>}, 276 {<<"cache-control">>, <<"no-cache">>} 277 ], 278 #state{size=110, dyn_table=[ 279 {53,{<<"cache-control">>, <<"no-cache">>}}, 280 {57,{<<":authority">>, <<"www.example.com">>}}]} = State2, 281 %% Third request (raw then huffman). 282 {Headers3, State3} = decode(<< 16#828785bf400a637573746f6d2d6b65790c637573746f6d2d76616c7565:232 >>, State2), 283 {Headers3, State3} = decode(<< 16#828785bf408825a849e95ba97d7f8925a849e95bb8e8b4bf:192 >>, State2), 284 Headers3 = [ 285 {<<":method">>, <<"GET">>}, 286 {<<":scheme">>, <<"https">>}, 287 {<<":path">>, <<"/index.html">>}, 288 {<<":authority">>, <<"www.example.com">>}, 289 {<<"custom-key">>, <<"custom-value">>} 290 ], 291 #state{size=164, dyn_table=[ 292 {54,{<<"custom-key">>, <<"custom-value">>}}, 293 {53,{<<"cache-control">>, <<"no-cache">>}}, 294 {57,{<<":authority">>, <<"www.example.com">>}}]} = State3, 295 ok. 296 297 resp_decode_test() -> 298 %% Use a max_size of 256 to trigger header evictions. 299 State0 = init(256), 300 %% First response (raw then huffman). 301 {Headers1, State1} = decode(<< 16#4803333032580770726976617465611d4d6f6e2c203231204f637420323031332032303a31333a323120474d546e1768747470733a2f2f7777772e6578616d706c652e636f6d:560 >>, State0), 302 {Headers1, State1} = decode(<< 16#488264025885aec3771a4b6196d07abe941054d444a8200595040b8166e082a62d1bff6e919d29ad171863c78f0b97c8e9ae82ae43d3:432 >>, State0), 303 Headers1 = [ 304 {<<":status">>, <<"302">>}, 305 {<<"cache-control">>, <<"private">>}, 306 {<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}, 307 {<<"location">>, <<"https://www.example.com">>} 308 ], 309 #state{size=222, dyn_table=[ 310 {63,{<<"location">>, <<"https://www.example.com">>}}, 311 {65,{<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}}, 312 {52,{<<"cache-control">>, <<"private">>}}, 313 {42,{<<":status">>, <<"302">>}}]} = State1, 314 %% Second response (raw then huffman). 315 {Headers2, State2} = decode(<< 16#4803333037c1c0bf:64 >>, State1), 316 {Headers2, State2} = decode(<< 16#4883640effc1c0bf:64 >>, State1), 317 Headers2 = [ 318 {<<":status">>, <<"307">>}, 319 {<<"cache-control">>, <<"private">>}, 320 {<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}, 321 {<<"location">>, <<"https://www.example.com">>} 322 ], 323 #state{size=222, dyn_table=[ 324 {42,{<<":status">>, <<"307">>}}, 325 {63,{<<"location">>, <<"https://www.example.com">>}}, 326 {65,{<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}}, 327 {52,{<<"cache-control">>, <<"private">>}}]} = State2, 328 %% Third response (raw then huffman). 329 {Headers3, State3} = decode(<< 16#88c1611d4d6f6e2c203231204f637420323031332032303a31333a323220474d54c05a04677a69707738666f6f3d4153444a4b48514b425a584f5157454f50495541585157454f49553b206d61782d6167653d333630303b2076657273696f6e3d31:784 >>, State2), 330 {Headers3, State3} = decode(<< 16#88c16196d07abe941054d444a8200595040b8166e084a62d1bffc05a839bd9ab77ad94e7821dd7f2e6c7b335dfdfcd5b3960d5af27087f3672c1ab270fb5291f9587316065c003ed4ee5b1063d5007:632 >>, State2), 331 Headers3 = [ 332 {<<":status">>, <<"200">>}, 333 {<<"cache-control">>, <<"private">>}, 334 {<<"date">>, <<"Mon, 21 Oct 2013 20:13:22 GMT">>}, 335 {<<"location">>, <<"https://www.example.com">>}, 336 {<<"content-encoding">>, <<"gzip">>}, 337 {<<"set-cookie">>, <<"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1">>} 338 ], 339 #state{size=215, dyn_table=[ 340 {98,{<<"set-cookie">>, <<"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1">>}}, 341 {52,{<<"content-encoding">>, <<"gzip">>}}, 342 {65,{<<"date">>, <<"Mon, 21 Oct 2013 20:13:22 GMT">>}}]} = State3, 343 ok. 344 345 table_update_decode_test() -> 346 %% Use a max_size of 256 to trigger header evictions 347 %% when the code is not updating the max size. 348 State0 = init(256), 349 %% First response (raw then huffman). 350 {Headers1, State1} = decode(<< 16#4803333032580770726976617465611d4d6f6e2c203231204f637420323031332032303a31333a323120474d546e1768747470733a2f2f7777772e6578616d706c652e636f6d:560 >>, State0), 351 {Headers1, State1} = decode(<< 16#488264025885aec3771a4b6196d07abe941054d444a8200595040b8166e082a62d1bff6e919d29ad171863c78f0b97c8e9ae82ae43d3:432 >>, State0), 352 Headers1 = [ 353 {<<":status">>, <<"302">>}, 354 {<<"cache-control">>, <<"private">>}, 355 {<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}, 356 {<<"location">>, <<"https://www.example.com">>} 357 ], 358 #state{size=222, configured_max_size=256, dyn_table=[ 359 {63,{<<"location">>, <<"https://www.example.com">>}}, 360 {65,{<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}}, 361 {52,{<<"cache-control">>, <<"private">>}}, 362 {42,{<<":status">>, <<"302">>}}]} = State1, 363 %% Set a new configured max_size to avoid header evictions. 364 State2 = set_max_size(512, State1), 365 %% Second response with the table size update (raw then huffman). 366 MaxSize = enc_big_int(512 - 31, <<>>), 367 {Headers2, State3} = decode( 368 iolist_to_binary([<< 2#00111111>>, MaxSize, <<16#4803333037c1c0bf:64>>]), 369 State2), 370 {Headers2, State3} = decode( 371 iolist_to_binary([<< 2#00111111>>, MaxSize, <<16#4883640effc1c0bf:64>>]), 372 State2), 373 Headers2 = [ 374 {<<":status">>, <<"307">>}, 375 {<<"cache-control">>, <<"private">>}, 376 {<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}, 377 {<<"location">>, <<"https://www.example.com">>} 378 ], 379 #state{size=264, configured_max_size=512, dyn_table=[ 380 {42,{<<":status">>, <<"307">>}}, 381 {63,{<<"location">>, <<"https://www.example.com">>}}, 382 {65,{<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}}, 383 {52,{<<"cache-control">>, <<"private">>}}, 384 {42,{<<":status">>, <<"302">>}}]} = State3, 385 ok. 386 387 table_update_decode_smaller_test() -> 388 %% Use a max_size of 256 to trigger header evictions 389 %% when the code is not updating the max size. 390 State0 = init(256), 391 %% First response (raw then huffman). 392 {Headers1, State1} = decode(<< 16#4803333032580770726976617465611d4d6f6e2c203231204f637420323031332032303a31333a323120474d546e1768747470733a2f2f7777772e6578616d706c652e636f6d:560 >>, State0), 393 {Headers1, State1} = decode(<< 16#488264025885aec3771a4b6196d07abe941054d444a8200595040b8166e082a62d1bff6e919d29ad171863c78f0b97c8e9ae82ae43d3:432 >>, State0), 394 Headers1 = [ 395 {<<":status">>, <<"302">>}, 396 {<<"cache-control">>, <<"private">>}, 397 {<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}, 398 {<<"location">>, <<"https://www.example.com">>} 399 ], 400 #state{size=222, configured_max_size=256, dyn_table=[ 401 {63,{<<"location">>, <<"https://www.example.com">>}}, 402 {65,{<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}}, 403 {52,{<<"cache-control">>, <<"private">>}}, 404 {42,{<<":status">>, <<"302">>}}]} = State1, 405 %% Set a new configured max_size to avoid header evictions. 406 State2 = set_max_size(512, State1), 407 %% Second response with the table size update smaller than the limit (raw then huffman). 408 MaxSize = enc_big_int(400 - 31, <<>>), 409 {Headers2, State3} = decode( 410 iolist_to_binary([<< 2#00111111>>, MaxSize, <<16#4803333037c1c0bf:64>>]), 411 State2), 412 {Headers2, State3} = decode( 413 iolist_to_binary([<< 2#00111111>>, MaxSize, <<16#4883640effc1c0bf:64>>]), 414 State2), 415 Headers2 = [ 416 {<<":status">>, <<"307">>}, 417 {<<"cache-control">>, <<"private">>}, 418 {<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}, 419 {<<"location">>, <<"https://www.example.com">>} 420 ], 421 #state{size=264, configured_max_size=512, dyn_table=[ 422 {42,{<<":status">>, <<"307">>}}, 423 {63,{<<"location">>, <<"https://www.example.com">>}}, 424 {65,{<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}}, 425 {52,{<<"cache-control">>, <<"private">>}}, 426 {42,{<<":status">>, <<"302">>}}]} = State3, 427 ok. 428 429 table_update_decode_too_large_test() -> 430 %% Use a max_size of 256 to trigger header evictions 431 %% when the code is not updating the max size. 432 State0 = init(256), 433 %% First response (raw then huffman). 434 {Headers1, State1} = decode(<< 16#4803333032580770726976617465611d4d6f6e2c203231204f637420323031332032303a31333a323120474d546e1768747470733a2f2f7777772e6578616d706c652e636f6d:560 >>, State0), 435 {Headers1, State1} = decode(<< 16#488264025885aec3771a4b6196d07abe941054d444a8200595040b8166e082a62d1bff6e919d29ad171863c78f0b97c8e9ae82ae43d3:432 >>, State0), 436 Headers1 = [ 437 {<<":status">>, <<"302">>}, 438 {<<"cache-control">>, <<"private">>}, 439 {<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}, 440 {<<"location">>, <<"https://www.example.com">>} 441 ], 442 #state{size=222, configured_max_size=256, dyn_table=[ 443 {63,{<<"location">>, <<"https://www.example.com">>}}, 444 {65,{<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}}, 445 {52,{<<"cache-control">>, <<"private">>}}, 446 {42,{<<":status">>, <<"302">>}}]} = State1, 447 %% Set a new configured max_size to avoid header evictions. 448 State2 = set_max_size(512, State1), 449 %% Second response with the table size update (raw then huffman). 450 MaxSize = enc_big_int(1024 - 31, <<>>), 451 {'EXIT', _} = (catch decode( 452 iolist_to_binary([<< 2#00111111>>, MaxSize, <<16#4803333037c1c0bf:64>>]), 453 State2)), 454 {'EXIT', _} = (catch decode( 455 iolist_to_binary([<< 2#00111111>>, MaxSize, <<16#4883640effc1c0bf:64>>]), 456 State2)), 457 ok. 458 459 table_update_decode_zero_test() -> 460 State0 = init(256), 461 %% First response (raw then huffman). 462 {Headers1, State1} = decode(<< 16#4803333032580770726976617465611d4d6f6e2c203231204f637420323031332032303a31333a323120474d546e1768747470733a2f2f7777772e6578616d706c652e636f6d:560 >>, State0), 463 {Headers1, State1} = decode(<< 16#488264025885aec3771a4b6196d07abe941054d444a8200595040b8166e082a62d1bff6e919d29ad171863c78f0b97c8e9ae82ae43d3:432 >>, State0), 464 Headers1 = [ 465 {<<":status">>, <<"302">>}, 466 {<<"cache-control">>, <<"private">>}, 467 {<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}, 468 {<<"location">>, <<"https://www.example.com">>} 469 ], 470 #state{size=222, configured_max_size=256, dyn_table=[ 471 {63,{<<"location">>, <<"https://www.example.com">>}}, 472 {65,{<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}}, 473 {52,{<<"cache-control">>, <<"private">>}}, 474 {42,{<<":status">>, <<"302">>}}]} = State1, 475 %% Set a new configured max_size to avoid header evictions. 476 State2 = set_max_size(512, State1), 477 %% Second response with the table size update (raw then huffman). 478 %% We set the table size to 0 to evict all values before setting 479 %% it to 512 so we only get the second request indexed. 480 MaxSize = enc_big_int(512 - 31, <<>>), 481 {Headers1, State3} = decode(iolist_to_binary([ 482 <<2#00100000, 2#00111111>>, MaxSize, 483 <<16#4803333032580770726976617465611d4d6f6e2c203231204f637420323031332032303a31333a323120474d546e1768747470733a2f2f7777772e6578616d706c652e636f6d:560>>]), 484 State2), 485 {Headers1, State3} = decode(iolist_to_binary([ 486 <<2#00100000, 2#00111111>>, MaxSize, 487 <<16#488264025885aec3771a4b6196d07abe941054d444a8200595040b8166e082a62d1bff6e919d29ad171863c78f0b97c8e9ae82ae43d3:432>>]), 488 State2), 489 #state{size=222, configured_max_size=512, dyn_table=[ 490 {63,{<<"location">>, <<"https://www.example.com">>}}, 491 {65,{<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}}, 492 {52,{<<"cache-control">>, <<"private">>}}, 493 {42,{<<":status">>, <<"302">>}}]} = State3, 494 ok. 495 496 horse_decode_raw() -> 497 horse:repeat(20000, 498 do_horse_decode_raw() 499 ). 500 501 do_horse_decode_raw() -> 502 {_, State1} = decode(<<16#828684410f7777772e6578616d706c652e636f6d:160>>), 503 {_, State2} = decode(<<16#828684be58086e6f2d6361636865:112>>, State1), 504 {_, _} = decode(<<16#828785bf400a637573746f6d2d6b65790c637573746f6d2d76616c7565:232>>, State2), 505 ok. 506 507 horse_decode_huffman() -> 508 horse:repeat(20000, 509 do_horse_decode_huffman() 510 ). 511 512 do_horse_decode_huffman() -> 513 {_, State1} = decode(<<16#828684418cf1e3c2e5f23a6ba0ab90f4ff:136>>), 514 {_, State2} = decode(<<16#828684be5886a8eb10649cbf:96>>, State1), 515 {_, _} = decode(<<16#828785bf408825a849e95ba97d7f8925a849e95bb8e8b4bf:192>>, State2), 516 ok. 517 -endif. 518 519 %% Encoding. 520 521 -spec encode(cow_http:headers()) -> {iodata(), state()}. 522 encode(Headers) -> 523 encode(Headers, init(), huffman, []). 524 525 -spec encode(cow_http:headers(), State) -> {iodata(), State} when State::state(). 526 encode(Headers, State=#state{max_size=MaxSize, configured_max_size=MaxSize}) -> 527 encode(Headers, State, huffman, []); 528 encode(Headers, State0=#state{configured_max_size=MaxSize}) -> 529 State1 = table_update_size(MaxSize, State0), 530 {Data, State} = encode(Headers, State1, huffman, []), 531 {[enc_int5(MaxSize, 2#001)|Data], State}. 532 533 -spec encode(cow_http:headers(), State, opts()) -> {iodata(), State} when State::state(). 534 encode(Headers, State=#state{max_size=MaxSize, configured_max_size=MaxSize}, Opts) -> 535 encode(Headers, State, huffman_opt(Opts), []); 536 encode(Headers, State0=#state{configured_max_size=MaxSize}, Opts) -> 537 State1 = table_update_size(MaxSize, State0), 538 {Data, State} = encode(Headers, State1, huffman_opt(Opts), []), 539 {[enc_int5(MaxSize, 2#001)|Data], State}. 540 541 huffman_opt(#{huffman := false}) -> no_huffman; 542 huffman_opt(_) -> huffman. 543 544 %% @todo Handle cases where no/never indexing is expected. 545 encode([], State, _, Acc) -> 546 {lists:reverse(Acc), State}; 547 encode([{Name, Value0}|Tail], State, HuffmanOpt, Acc) -> 548 %% We conditionally call iolist_to_binary/1 because a small 549 %% but noticeable speed improvement happens when we do this. 550 Value = if 551 is_binary(Value0) -> Value0; 552 true -> iolist_to_binary(Value0) 553 end, 554 Header = {Name, Value}, 555 case table_find(Header, State) of 556 %% Indexed header field representation. 557 {field, Index} -> 558 encode(Tail, State, HuffmanOpt, 559 [enc_int7(Index, 2#1)|Acc]); 560 %% Literal header field representation: indexed name. 561 {name, Index} -> 562 State2 = table_insert(Header, State), 563 encode(Tail, State2, HuffmanOpt, 564 [[enc_int6(Index, 2#01)|enc_str(Value, HuffmanOpt)]|Acc]); 565 %% Literal header field representation: new name. 566 not_found -> 567 State2 = table_insert(Header, State), 568 encode(Tail, State2, HuffmanOpt, 569 [[<< 0:1, 1:1, 0:6 >>|[enc_str(Name, HuffmanOpt)|enc_str(Value, HuffmanOpt)]]|Acc]) 570 end. 571 572 %% Encode an integer. 573 574 enc_int5(Int, Prefix) when Int < 31 -> 575 << Prefix:3, Int:5 >>; 576 enc_int5(Int, Prefix) -> 577 enc_big_int(Int - 31, << Prefix:3, 2#11111:5 >>). 578 579 enc_int6(Int, Prefix) when Int < 63 -> 580 << Prefix:2, Int:6 >>; 581 enc_int6(Int, Prefix) -> 582 enc_big_int(Int - 63, << Prefix:2, 2#111111:6 >>). 583 584 enc_int7(Int, Prefix) when Int < 127 -> 585 << Prefix:1, Int:7 >>; 586 enc_int7(Int, Prefix) -> 587 enc_big_int(Int - 127, << Prefix:1, 2#1111111:7 >>). 588 589 enc_big_int(Int, Acc) when Int < 128 -> 590 <<Acc/binary, Int:8>>; 591 enc_big_int(Int, Acc) -> 592 enc_big_int(Int bsr 7, <<Acc/binary, 1:1, Int:7>>). 593 594 %% Encode a string. 595 596 enc_str(Str, huffman) -> 597 Str2 = enc_huffman(Str, <<>>), 598 [enc_int7(byte_size(Str2), 2#1)|Str2]; 599 enc_str(Str, no_huffman) -> 600 [enc_int7(byte_size(Str), 2#0)|Str]. 601 602 enc_huffman(<<>>, Acc) -> 603 case bit_size(Acc) rem 8 of 604 1 -> << Acc/bits, 2#1111111:7 >>; 605 2 -> << Acc/bits, 2#111111:6 >>; 606 3 -> << Acc/bits, 2#11111:5 >>; 607 4 -> << Acc/bits, 2#1111:4 >>; 608 5 -> << Acc/bits, 2#111:3 >>; 609 6 -> << Acc/bits, 2#11:2 >>; 610 7 -> << Acc/bits, 2#1:1 >>; 611 0 -> Acc 612 end; 613 enc_huffman(<< 0, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111000:13 >>); 614 enc_huffman(<< 1, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111011000:23 >>); 615 enc_huffman(<< 2, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111100010:28 >>); 616 enc_huffman(<< 3, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111100011:28 >>); 617 enc_huffman(<< 4, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111100100:28 >>); 618 enc_huffman(<< 5, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111100101:28 >>); 619 enc_huffman(<< 6, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111100110:28 >>); 620 enc_huffman(<< 7, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111100111:28 >>); 621 enc_huffman(<< 8, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111101000:28 >>); 622 enc_huffman(<< 9, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111101010:24 >>); 623 enc_huffman(<< 10, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111111111100:30 >>); 624 enc_huffman(<< 11, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111101001:28 >>); 625 enc_huffman(<< 12, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111101010:28 >>); 626 enc_huffman(<< 13, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111111111101:30 >>); 627 enc_huffman(<< 14, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111101011:28 >>); 628 enc_huffman(<< 15, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111101100:28 >>); 629 enc_huffman(<< 16, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111101101:28 >>); 630 enc_huffman(<< 17, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111101110:28 >>); 631 enc_huffman(<< 18, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111101111:28 >>); 632 enc_huffman(<< 19, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111110000:28 >>); 633 enc_huffman(<< 20, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111110001:28 >>); 634 enc_huffman(<< 21, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111110010:28 >>); 635 enc_huffman(<< 22, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111111111110:30 >>); 636 enc_huffman(<< 23, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111110011:28 >>); 637 enc_huffman(<< 24, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111110100:28 >>); 638 enc_huffman(<< 25, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111110101:28 >>); 639 enc_huffman(<< 26, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111110110:28 >>); 640 enc_huffman(<< 27, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111110111:28 >>); 641 enc_huffman(<< 28, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111111000:28 >>); 642 enc_huffman(<< 29, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111111001:28 >>); 643 enc_huffman(<< 30, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111111010:28 >>); 644 enc_huffman(<< 31, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111111011:28 >>); 645 enc_huffman(<< 32, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#010100:6 >>); 646 enc_huffman(<< 33, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111000:10 >>); 647 enc_huffman(<< 34, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111001:10 >>); 648 enc_huffman(<< 35, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111010:12 >>); 649 enc_huffman(<< 36, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111001:13 >>); 650 enc_huffman(<< 37, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#010101:6 >>); 651 enc_huffman(<< 38, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111000:8 >>); 652 enc_huffman(<< 39, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111010:11 >>); 653 enc_huffman(<< 40, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111010:10 >>); 654 enc_huffman(<< 41, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111011:10 >>); 655 enc_huffman(<< 42, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111001:8 >>); 656 enc_huffman(<< 43, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111011:11 >>); 657 enc_huffman(<< 44, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111010:8 >>); 658 enc_huffman(<< 45, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#010110:6 >>); 659 enc_huffman(<< 46, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#010111:6 >>); 660 enc_huffman(<< 47, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#011000:6 >>); 661 enc_huffman(<< 48, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#00000:5 >>); 662 enc_huffman(<< 49, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#00001:5 >>); 663 enc_huffman(<< 50, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#00010:5 >>); 664 enc_huffman(<< 51, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#011001:6 >>); 665 enc_huffman(<< 52, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#011010:6 >>); 666 enc_huffman(<< 53, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#011011:6 >>); 667 enc_huffman(<< 54, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#011100:6 >>); 668 enc_huffman(<< 55, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#011101:6 >>); 669 enc_huffman(<< 56, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#011110:6 >>); 670 enc_huffman(<< 57, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#011111:6 >>); 671 enc_huffman(<< 58, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1011100:7 >>); 672 enc_huffman(<< 59, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111011:8 >>); 673 enc_huffman(<< 60, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111100:15 >>); 674 enc_huffman(<< 61, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#100000:6 >>); 675 enc_huffman(<< 62, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111011:12 >>); 676 enc_huffman(<< 63, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111100:10 >>); 677 enc_huffman(<< 64, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111010:13 >>); 678 enc_huffman(<< 65, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#100001:6 >>); 679 enc_huffman(<< 66, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1011101:7 >>); 680 enc_huffman(<< 67, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1011110:7 >>); 681 enc_huffman(<< 68, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1011111:7 >>); 682 enc_huffman(<< 69, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1100000:7 >>); 683 enc_huffman(<< 70, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1100001:7 >>); 684 enc_huffman(<< 71, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1100010:7 >>); 685 enc_huffman(<< 72, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1100011:7 >>); 686 enc_huffman(<< 73, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1100100:7 >>); 687 enc_huffman(<< 74, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1100101:7 >>); 688 enc_huffman(<< 75, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1100110:7 >>); 689 enc_huffman(<< 76, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1100111:7 >>); 690 enc_huffman(<< 77, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1101000:7 >>); 691 enc_huffman(<< 78, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1101001:7 >>); 692 enc_huffman(<< 79, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1101010:7 >>); 693 enc_huffman(<< 80, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1101011:7 >>); 694 enc_huffman(<< 81, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1101100:7 >>); 695 enc_huffman(<< 82, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1101101:7 >>); 696 enc_huffman(<< 83, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1101110:7 >>); 697 enc_huffman(<< 84, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1101111:7 >>); 698 enc_huffman(<< 85, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1110000:7 >>); 699 enc_huffman(<< 86, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1110001:7 >>); 700 enc_huffman(<< 87, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1110010:7 >>); 701 enc_huffman(<< 88, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111100:8 >>); 702 enc_huffman(<< 89, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1110011:7 >>); 703 enc_huffman(<< 90, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111101:8 >>); 704 enc_huffman(<< 91, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111011:13 >>); 705 enc_huffman(<< 92, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111110000:19 >>); 706 enc_huffman(<< 93, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111100:13 >>); 707 enc_huffman(<< 94, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111100:14 >>); 708 enc_huffman(<< 95, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#100010:6 >>); 709 enc_huffman(<< 96, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111101:15 >>); 710 enc_huffman(<< 97, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#00011:5 >>); 711 enc_huffman(<< 98, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#100011:6 >>); 712 enc_huffman(<< 99, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#00100:5 >>); 713 enc_huffman(<< 100, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#100100:6 >>); 714 enc_huffman(<< 101, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#00101:5 >>); 715 enc_huffman(<< 102, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#100101:6 >>); 716 enc_huffman(<< 103, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#100110:6 >>); 717 enc_huffman(<< 104, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#100111:6 >>); 718 enc_huffman(<< 105, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#00110:5 >>); 719 enc_huffman(<< 106, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1110100:7 >>); 720 enc_huffman(<< 107, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1110101:7 >>); 721 enc_huffman(<< 108, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#101000:6 >>); 722 enc_huffman(<< 109, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#101001:6 >>); 723 enc_huffman(<< 110, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#101010:6 >>); 724 enc_huffman(<< 111, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#00111:5 >>); 725 enc_huffman(<< 112, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#101011:6 >>); 726 enc_huffman(<< 113, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1110110:7 >>); 727 enc_huffman(<< 114, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#101100:6 >>); 728 enc_huffman(<< 115, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#01000:5 >>); 729 enc_huffman(<< 116, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#01001:5 >>); 730 enc_huffman(<< 117, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#101101:6 >>); 731 enc_huffman(<< 118, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1110111:7 >>); 732 enc_huffman(<< 119, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111000:7 >>); 733 enc_huffman(<< 120, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111001:7 >>); 734 enc_huffman(<< 121, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111010:7 >>); 735 enc_huffman(<< 122, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111011:7 >>); 736 enc_huffman(<< 123, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111110:15 >>); 737 enc_huffman(<< 124, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111100:11 >>); 738 enc_huffman(<< 125, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111101:14 >>); 739 enc_huffman(<< 126, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111101:13 >>); 740 enc_huffman(<< 127, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111111100:28 >>); 741 enc_huffman(<< 128, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111100110:20 >>); 742 enc_huffman(<< 129, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111010010:22 >>); 743 enc_huffman(<< 130, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111100111:20 >>); 744 enc_huffman(<< 131, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111101000:20 >>); 745 enc_huffman(<< 132, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111010011:22 >>); 746 enc_huffman(<< 133, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111010100:22 >>); 747 enc_huffman(<< 134, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111010101:22 >>); 748 enc_huffman(<< 135, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111011001:23 >>); 749 enc_huffman(<< 136, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111010110:22 >>); 750 enc_huffman(<< 137, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111011010:23 >>); 751 enc_huffman(<< 138, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111011011:23 >>); 752 enc_huffman(<< 139, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111011100:23 >>); 753 enc_huffman(<< 140, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111011101:23 >>); 754 enc_huffman(<< 141, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111011110:23 >>); 755 enc_huffman(<< 142, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111101011:24 >>); 756 enc_huffman(<< 143, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111011111:23 >>); 757 enc_huffman(<< 144, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111101100:24 >>); 758 enc_huffman(<< 145, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111101101:24 >>); 759 enc_huffman(<< 146, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111010111:22 >>); 760 enc_huffman(<< 147, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111100000:23 >>); 761 enc_huffman(<< 148, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111101110:24 >>); 762 enc_huffman(<< 149, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111100001:23 >>); 763 enc_huffman(<< 150, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111100010:23 >>); 764 enc_huffman(<< 151, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111100011:23 >>); 765 enc_huffman(<< 152, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111100100:23 >>); 766 enc_huffman(<< 153, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111011100:21 >>); 767 enc_huffman(<< 154, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111011000:22 >>); 768 enc_huffman(<< 155, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111100101:23 >>); 769 enc_huffman(<< 156, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111011001:22 >>); 770 enc_huffman(<< 157, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111100110:23 >>); 771 enc_huffman(<< 158, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111100111:23 >>); 772 enc_huffman(<< 159, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111101111:24 >>); 773 enc_huffman(<< 160, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111011010:22 >>); 774 enc_huffman(<< 161, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111011101:21 >>); 775 enc_huffman(<< 162, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111101001:20 >>); 776 enc_huffman(<< 163, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111011011:22 >>); 777 enc_huffman(<< 164, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111011100:22 >>); 778 enc_huffman(<< 165, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111101000:23 >>); 779 enc_huffman(<< 166, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111101001:23 >>); 780 enc_huffman(<< 167, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111011110:21 >>); 781 enc_huffman(<< 168, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111101010:23 >>); 782 enc_huffman(<< 169, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111011101:22 >>); 783 enc_huffman(<< 170, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111011110:22 >>); 784 enc_huffman(<< 171, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111110000:24 >>); 785 enc_huffman(<< 172, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111011111:21 >>); 786 enc_huffman(<< 173, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111011111:22 >>); 787 enc_huffman(<< 174, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111101011:23 >>); 788 enc_huffman(<< 175, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111101100:23 >>); 789 enc_huffman(<< 176, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111100000:21 >>); 790 enc_huffman(<< 177, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111100001:21 >>); 791 enc_huffman(<< 178, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111100000:22 >>); 792 enc_huffman(<< 179, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111100010:21 >>); 793 enc_huffman(<< 180, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111101101:23 >>); 794 enc_huffman(<< 181, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111100001:22 >>); 795 enc_huffman(<< 182, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111101110:23 >>); 796 enc_huffman(<< 183, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111101111:23 >>); 797 enc_huffman(<< 184, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111101010:20 >>); 798 enc_huffman(<< 185, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111100010:22 >>); 799 enc_huffman(<< 186, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111100011:22 >>); 800 enc_huffman(<< 187, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111100100:22 >>); 801 enc_huffman(<< 188, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111110000:23 >>); 802 enc_huffman(<< 189, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111100101:22 >>); 803 enc_huffman(<< 190, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111100110:22 >>); 804 enc_huffman(<< 191, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111110001:23 >>); 805 enc_huffman(<< 192, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111111100000:26 >>); 806 enc_huffman(<< 193, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111111100001:26 >>); 807 enc_huffman(<< 194, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111101011:20 >>); 808 enc_huffman(<< 195, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111110001:19 >>); 809 enc_huffman(<< 196, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111100111:22 >>); 810 enc_huffman(<< 197, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111110010:23 >>); 811 enc_huffman(<< 198, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111101000:22 >>); 812 enc_huffman(<< 199, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111101100:25 >>); 813 enc_huffman(<< 200, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111111100010:26 >>); 814 enc_huffman(<< 201, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111111100011:26 >>); 815 enc_huffman(<< 202, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111111100100:26 >>); 816 enc_huffman(<< 203, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111011110:27 >>); 817 enc_huffman(<< 204, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111011111:27 >>); 818 enc_huffman(<< 205, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111111100101:26 >>); 819 enc_huffman(<< 206, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111110001:24 >>); 820 enc_huffman(<< 207, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111101101:25 >>); 821 enc_huffman(<< 208, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111110010:19 >>); 822 enc_huffman(<< 209, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111100011:21 >>); 823 enc_huffman(<< 210, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111111100110:26 >>); 824 enc_huffman(<< 211, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111100000:27 >>); 825 enc_huffman(<< 212, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111100001:27 >>); 826 enc_huffman(<< 213, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111111100111:26 >>); 827 enc_huffman(<< 214, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111100010:27 >>); 828 enc_huffman(<< 215, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111110010:24 >>); 829 enc_huffman(<< 216, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111100100:21 >>); 830 enc_huffman(<< 217, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111100101:21 >>); 831 enc_huffman(<< 218, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111111101000:26 >>); 832 enc_huffman(<< 219, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111111101001:26 >>); 833 enc_huffman(<< 220, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111111101:28 >>); 834 enc_huffman(<< 221, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111100011:27 >>); 835 enc_huffman(<< 222, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111100100:27 >>); 836 enc_huffman(<< 223, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111100101:27 >>); 837 enc_huffman(<< 224, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111101100:20 >>); 838 enc_huffman(<< 225, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111110011:24 >>); 839 enc_huffman(<< 226, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111101101:20 >>); 840 enc_huffman(<< 227, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111100110:21 >>); 841 enc_huffman(<< 228, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111101001:22 >>); 842 enc_huffman(<< 229, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111100111:21 >>); 843 enc_huffman(<< 230, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111101000:21 >>); 844 enc_huffman(<< 231, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111110011:23 >>); 845 enc_huffman(<< 232, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111101010:22 >>); 846 enc_huffman(<< 233, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111101011:22 >>); 847 enc_huffman(<< 234, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111101110:25 >>); 848 enc_huffman(<< 235, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111101111:25 >>); 849 enc_huffman(<< 236, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111110100:24 >>); 850 enc_huffman(<< 237, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111110101:24 >>); 851 enc_huffman(<< 238, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111111101010:26 >>); 852 enc_huffman(<< 239, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111110100:23 >>); 853 enc_huffman(<< 240, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111111101011:26 >>); 854 enc_huffman(<< 241, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111100110:27 >>); 855 enc_huffman(<< 242, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111111101100:26 >>); 856 enc_huffman(<< 243, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111111101101:26 >>); 857 enc_huffman(<< 244, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111100111:27 >>); 858 enc_huffman(<< 245, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111101000:27 >>); 859 enc_huffman(<< 246, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111101001:27 >>); 860 enc_huffman(<< 247, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111101010:27 >>); 861 enc_huffman(<< 248, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111101011:27 >>); 862 enc_huffman(<< 249, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#1111111111111111111111111110:28 >>); 863 enc_huffman(<< 250, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111101100:27 >>); 864 enc_huffman(<< 251, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111101101:27 >>); 865 enc_huffman(<< 252, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111101110:27 >>); 866 enc_huffman(<< 253, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111101111:27 >>); 867 enc_huffman(<< 254, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#111111111111111111111110000:27 >>); 868 enc_huffman(<< 255, R/bits >>, A) -> enc_huffman(R, << A/bits, 2#11111111111111111111101110:26 >>). 869 870 -ifdef(TEST). 871 req_encode_test() -> 872 %% First request (raw then huffman). 873 Headers1 = [ 874 {<<":method">>, <<"GET">>}, 875 {<<":scheme">>, <<"http">>}, 876 {<<":path">>, <<"/">>}, 877 {<<":authority">>, <<"www.example.com">>} 878 ], 879 {Raw1, State1} = encode(Headers1, init(), #{huffman => false}), 880 << 16#828684410f7777772e6578616d706c652e636f6d:160 >> = iolist_to_binary(Raw1), 881 {Huff1, State1} = encode(Headers1), 882 << 16#828684418cf1e3c2e5f23a6ba0ab90f4ff:136 >> = iolist_to_binary(Huff1), 883 #state{size=57, dyn_table=[{57,{<<":authority">>, <<"www.example.com">>}}]} = State1, 884 %% Second request (raw then huffman). 885 Headers2 = [ 886 {<<":method">>, <<"GET">>}, 887 {<<":scheme">>, <<"http">>}, 888 {<<":path">>, <<"/">>}, 889 {<<":authority">>, <<"www.example.com">>}, 890 {<<"cache-control">>, <<"no-cache">>} 891 ], 892 {Raw2, State2} = encode(Headers2, State1, #{huffman => false}), 893 << 16#828684be58086e6f2d6361636865:112 >> = iolist_to_binary(Raw2), 894 {Huff2, State2} = encode(Headers2, State1), 895 << 16#828684be5886a8eb10649cbf:96 >> = iolist_to_binary(Huff2), 896 #state{size=110, dyn_table=[ 897 {53,{<<"cache-control">>, <<"no-cache">>}}, 898 {57,{<<":authority">>, <<"www.example.com">>}}]} = State2, 899 %% Third request (raw then huffman). 900 Headers3 = [ 901 {<<":method">>, <<"GET">>}, 902 {<<":scheme">>, <<"https">>}, 903 {<<":path">>, <<"/index.html">>}, 904 {<<":authority">>, <<"www.example.com">>}, 905 {<<"custom-key">>, <<"custom-value">>} 906 ], 907 {Raw3, State3} = encode(Headers3, State2, #{huffman => false}), 908 << 16#828785bf400a637573746f6d2d6b65790c637573746f6d2d76616c7565:232 >> = iolist_to_binary(Raw3), 909 {Huff3, State3} = encode(Headers3, State2), 910 << 16#828785bf408825a849e95ba97d7f8925a849e95bb8e8b4bf:192 >> = iolist_to_binary(Huff3), 911 #state{size=164, dyn_table=[ 912 {54,{<<"custom-key">>, <<"custom-value">>}}, 913 {53,{<<"cache-control">>, <<"no-cache">>}}, 914 {57,{<<":authority">>, <<"www.example.com">>}}]} = State3, 915 ok. 916 917 resp_encode_test() -> 918 %% Use a max_size of 256 to trigger header evictions. 919 State0 = init(256), 920 %% First response (raw then huffman). 921 Headers1 = [ 922 {<<":status">>, <<"302">>}, 923 {<<"cache-control">>, <<"private">>}, 924 {<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}, 925 {<<"location">>, <<"https://www.example.com">>} 926 ], 927 {Raw1, State1} = encode(Headers1, State0, #{huffman => false}), 928 << 16#4803333032580770726976617465611d4d6f6e2c203231204f637420323031332032303a31333a323120474d546e1768747470733a2f2f7777772e6578616d706c652e636f6d:560 >> = iolist_to_binary(Raw1), 929 {Huff1, State1} = encode(Headers1, State0), 930 << 16#488264025885aec3771a4b6196d07abe941054d444a8200595040b8166e082a62d1bff6e919d29ad171863c78f0b97c8e9ae82ae43d3:432 >> = iolist_to_binary(Huff1), 931 #state{size=222, dyn_table=[ 932 {63,{<<"location">>, <<"https://www.example.com">>}}, 933 {65,{<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}}, 934 {52,{<<"cache-control">>, <<"private">>}}, 935 {42,{<<":status">>, <<"302">>}}]} = State1, 936 %% Second response (raw then huffman). 937 Headers2 = [ 938 {<<":status">>, <<"307">>}, 939 {<<"cache-control">>, <<"private">>}, 940 {<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}, 941 {<<"location">>, <<"https://www.example.com">>} 942 ], 943 {Raw2, State2} = encode(Headers2, State1, #{huffman => false}), 944 << 16#4803333037c1c0bf:64 >> = iolist_to_binary(Raw2), 945 {Huff2, State2} = encode(Headers2, State1), 946 << 16#4883640effc1c0bf:64 >> = iolist_to_binary(Huff2), 947 #state{size=222, dyn_table=[ 948 {42,{<<":status">>, <<"307">>}}, 949 {63,{<<"location">>, <<"https://www.example.com">>}}, 950 {65,{<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}}, 951 {52,{<<"cache-control">>, <<"private">>}}]} = State2, 952 %% Third response (raw then huffman). 953 Headers3 = [ 954 {<<":status">>, <<"200">>}, 955 {<<"cache-control">>, <<"private">>}, 956 {<<"date">>, <<"Mon, 21 Oct 2013 20:13:22 GMT">>}, 957 {<<"location">>, <<"https://www.example.com">>}, 958 {<<"content-encoding">>, <<"gzip">>}, 959 {<<"set-cookie">>, <<"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1">>} 960 ], 961 {Raw3, State3} = encode(Headers3, State2, #{huffman => false}), 962 << 16#88c1611d4d6f6e2c203231204f637420323031332032303a31333a323220474d54c05a04677a69707738666f6f3d4153444a4b48514b425a584f5157454f50495541585157454f49553b206d61782d6167653d333630303b2076657273696f6e3d31:784 >> = iolist_to_binary(Raw3), 963 {Huff3, State3} = encode(Headers3, State2), 964 << 16#88c16196d07abe941054d444a8200595040b8166e084a62d1bffc05a839bd9ab77ad94e7821dd7f2e6c7b335dfdfcd5b3960d5af27087f3672c1ab270fb5291f9587316065c003ed4ee5b1063d5007:632 >> = iolist_to_binary(Huff3), 965 #state{size=215, dyn_table=[ 966 {98,{<<"set-cookie">>, <<"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1">>}}, 967 {52,{<<"content-encoding">>, <<"gzip">>}}, 968 {65,{<<"date">>, <<"Mon, 21 Oct 2013 20:13:22 GMT">>}}]} = State3, 969 ok. 970 971 %% This test assumes that table updates work correctly when decoding. 972 table_update_encode_test() -> 973 %% Use a max_size of 256 to trigger header evictions 974 %% when the code is not updating the max size. 975 DecState0 = EncState0 = init(256), 976 %% First response. 977 Headers1 = [ 978 {<<":status">>, <<"302">>}, 979 {<<"cache-control">>, <<"private">>}, 980 {<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}, 981 {<<"location">>, <<"https://www.example.com">>} 982 ], 983 {Encoded1, EncState1} = encode(Headers1, EncState0), 984 {Headers1, DecState1} = decode(iolist_to_binary(Encoded1), DecState0), 985 #state{size=222, configured_max_size=256, dyn_table=[ 986 {63,{<<"location">>, <<"https://www.example.com">>}}, 987 {65,{<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}}, 988 {52,{<<"cache-control">>, <<"private">>}}, 989 {42,{<<":status">>, <<"302">>}}]} = DecState1, 990 #state{size=222, configured_max_size=256, dyn_table=[ 991 {63,{<<"location">>, <<"https://www.example.com">>}}, 992 {65,{<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}}, 993 {52,{<<"cache-control">>, <<"private">>}}, 994 {42,{<<":status">>, <<"302">>}}]} = EncState1, 995 %% Set a new configured max_size to avoid header evictions. 996 DecState2 = set_max_size(512, DecState1), 997 EncState2 = set_max_size(512, EncState1), 998 %% Second response. 999 Headers2 = [ 1000 {<<":status">>, <<"307">>}, 1001 {<<"cache-control">>, <<"private">>}, 1002 {<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}, 1003 {<<"location">>, <<"https://www.example.com">>} 1004 ], 1005 {Encoded2, EncState3} = encode(Headers2, EncState2), 1006 {Headers2, DecState3} = decode(iolist_to_binary(Encoded2), DecState2), 1007 #state{size=264, max_size=512, dyn_table=[ 1008 {42,{<<":status">>, <<"307">>}}, 1009 {63,{<<"location">>, <<"https://www.example.com">>}}, 1010 {65,{<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}}, 1011 {52,{<<"cache-control">>, <<"private">>}}, 1012 {42,{<<":status">>, <<"302">>}}]} = DecState3, 1013 #state{size=264, max_size=512, dyn_table=[ 1014 {42,{<<":status">>, <<"307">>}}, 1015 {63,{<<"location">>, <<"https://www.example.com">>}}, 1016 {65,{<<"date">>, <<"Mon, 21 Oct 2013 20:13:21 GMT">>}}, 1017 {52,{<<"cache-control">>, <<"private">>}}, 1018 {42,{<<":status">>, <<"302">>}}]} = EncState3, 1019 ok. 1020 1021 %% Check that encode/2 is using the new table size after calling 1022 %% set_max_size/1 and that adding entries larger than the max size 1023 %% results in an empty table. 1024 table_update_encode_max_size_0_test() -> 1025 %% Encoding starts with default max size 1026 EncState0 = init(), 1027 %% Decoding starts with max size of 0 1028 DecState0 = init(0), 1029 %% First request. 1030 Headers1 = [ 1031 {<<":method">>, <<"GET">>}, 1032 {<<":scheme">>, <<"http">>}, 1033 {<<":path">>, <<"/">>}, 1034 {<<":authority">>, <<"www.example.com">>} 1035 ], 1036 {Encoded1, EncState1} = encode(Headers1, EncState0), 1037 {Headers1, DecState1} = decode(iolist_to_binary(Encoded1), DecState0), 1038 #state{size=57, dyn_table=[{57,{<<":authority">>, <<"www.example.com">>}}]} = EncState1, 1039 #state{size=0, dyn_table=[]} = DecState1, 1040 %% Settings received after the first request. 1041 EncState2 = set_max_size(0, EncState1), 1042 #state{configured_max_size=0, max_size=4096, 1043 size=57, dyn_table=[{57,{<<":authority">>, <<"www.example.com">>}}]} = EncState2, 1044 %% Second request. 1045 Headers2 = [ 1046 {<<":method">>, <<"GET">>}, 1047 {<<":scheme">>, <<"http">>}, 1048 {<<":path">>, <<"/">>}, 1049 {<<":authority">>, <<"www.example.com">>}, 1050 {<<"cache-control">>, <<"no-cache">>} 1051 ], 1052 {Encoded2, EncState3} = encode(Headers2, EncState2), 1053 {Headers2, DecState2} = decode(iolist_to_binary(Encoded2), DecState1), 1054 #state{configured_max_size=0, max_size=0, size=0, dyn_table=[]} = EncState3, 1055 #state{size=0, dyn_table=[]} = DecState2, 1056 ok. 1057 1058 encode_iolist_test() -> 1059 Headers = [ 1060 {<<":method">>, <<"GET">>}, 1061 {<<":scheme">>, <<"http">>}, 1062 {<<":path">>, <<"/">>}, 1063 {<<":authority">>, <<"www.example.com">>}, 1064 {<<"content-type">>, [<<"image">>,<<"/">>,<<"png">>,<<>>]} 1065 ], 1066 {_, _} = encode(Headers), 1067 ok. 1068 1069 horse_encode_raw() -> 1070 horse:repeat(20000, 1071 do_horse_encode_raw() 1072 ). 1073 1074 do_horse_encode_raw() -> 1075 Headers1 = [ 1076 {<<":method">>, <<"GET">>}, 1077 {<<":scheme">>, <<"http">>}, 1078 {<<":path">>, <<"/">>}, 1079 {<<":authority">>, <<"www.example.com">>} 1080 ], 1081 {_, State1} = encode(Headers1, init(), #{huffman => false}), 1082 Headers2 = [ 1083 {<<":method">>, <<"GET">>}, 1084 {<<":scheme">>, <<"http">>}, 1085 {<<":path">>, <<"/">>}, 1086 {<<":authority">>, <<"www.example.com">>}, 1087 {<<"cache-control">>, <<"no-cache">>} 1088 ], 1089 {_, State2} = encode(Headers2, State1, #{huffman => false}), 1090 Headers3 = [ 1091 {<<":method">>, <<"GET">>}, 1092 {<<":scheme">>, <<"https">>}, 1093 {<<":path">>, <<"/index.html">>}, 1094 {<<":authority">>, <<"www.example.com">>}, 1095 {<<"custom-key">>, <<"custom-value">>} 1096 ], 1097 {_, _} = encode(Headers3, State2, #{huffman => false}), 1098 ok. 1099 1100 horse_encode_huffman() -> 1101 horse:repeat(20000, 1102 do_horse_encode_huffman() 1103 ). 1104 1105 do_horse_encode_huffman() -> 1106 Headers1 = [ 1107 {<<":method">>, <<"GET">>}, 1108 {<<":scheme">>, <<"http">>}, 1109 {<<":path">>, <<"/">>}, 1110 {<<":authority">>, <<"www.example.com">>} 1111 ], 1112 {_, State1} = encode(Headers1), 1113 Headers2 = [ 1114 {<<":method">>, <<"GET">>}, 1115 {<<":scheme">>, <<"http">>}, 1116 {<<":path">>, <<"/">>}, 1117 {<<":authority">>, <<"www.example.com">>}, 1118 {<<"cache-control">>, <<"no-cache">>} 1119 ], 1120 {_, State2} = encode(Headers2, State1), 1121 Headers3 = [ 1122 {<<":method">>, <<"GET">>}, 1123 {<<":scheme">>, <<"https">>}, 1124 {<<":path">>, <<"/index.html">>}, 1125 {<<":authority">>, <<"www.example.com">>}, 1126 {<<"custom-key">>, <<"custom-value">>} 1127 ], 1128 {_, _} = encode(Headers3, State2), 1129 ok. 1130 -endif. 1131 1132 %% Static and dynamic tables. 1133 1134 %% @todo There must be a more efficient way. 1135 table_find(Header = {Name, _}, State) -> 1136 case table_find_field(Header, State) of 1137 not_found -> 1138 case table_find_name(Name, State) of 1139 NotFound = not_found -> 1140 NotFound; 1141 Found -> 1142 {name, Found} 1143 end; 1144 Found -> 1145 {field, Found} 1146 end. 1147 1148 table_find_field({<<":authority">>, <<>>}, _) -> 1; 1149 table_find_field({<<":method">>, <<"GET">>}, _) -> 2; 1150 table_find_field({<<":method">>, <<"POST">>}, _) -> 3; 1151 table_find_field({<<":path">>, <<"/">>}, _) -> 4; 1152 table_find_field({<<":path">>, <<"/index.html">>}, _) -> 5; 1153 table_find_field({<<":scheme">>, <<"http">>}, _) -> 6; 1154 table_find_field({<<":scheme">>, <<"https">>}, _) -> 7; 1155 table_find_field({<<":status">>, <<"200">>}, _) -> 8; 1156 table_find_field({<<":status">>, <<"204">>}, _) -> 9; 1157 table_find_field({<<":status">>, <<"206">>}, _) -> 10; 1158 table_find_field({<<":status">>, <<"304">>}, _) -> 11; 1159 table_find_field({<<":status">>, <<"400">>}, _) -> 12; 1160 table_find_field({<<":status">>, <<"404">>}, _) -> 13; 1161 table_find_field({<<":status">>, <<"500">>}, _) -> 14; 1162 table_find_field({<<"accept-charset">>, <<>>}, _) -> 15; 1163 table_find_field({<<"accept-encoding">>, <<"gzip, deflate">>}, _) -> 16; 1164 table_find_field({<<"accept-language">>, <<>>}, _) -> 17; 1165 table_find_field({<<"accept-ranges">>, <<>>}, _) -> 18; 1166 table_find_field({<<"accept">>, <<>>}, _) -> 19; 1167 table_find_field({<<"access-control-allow-origin">>, <<>>}, _) -> 20; 1168 table_find_field({<<"age">>, <<>>}, _) -> 21; 1169 table_find_field({<<"allow">>, <<>>}, _) -> 22; 1170 table_find_field({<<"authorization">>, <<>>}, _) -> 23; 1171 table_find_field({<<"cache-control">>, <<>>}, _) -> 24; 1172 table_find_field({<<"content-disposition">>, <<>>}, _) -> 25; 1173 table_find_field({<<"content-encoding">>, <<>>}, _) -> 26; 1174 table_find_field({<<"content-language">>, <<>>}, _) -> 27; 1175 table_find_field({<<"content-length">>, <<>>}, _) -> 28; 1176 table_find_field({<<"content-location">>, <<>>}, _) -> 29; 1177 table_find_field({<<"content-range">>, <<>>}, _) -> 30; 1178 table_find_field({<<"content-type">>, <<>>}, _) -> 31; 1179 table_find_field({<<"cookie">>, <<>>}, _) -> 32; 1180 table_find_field({<<"date">>, <<>>}, _) -> 33; 1181 table_find_field({<<"etag">>, <<>>}, _) -> 34; 1182 table_find_field({<<"expect">>, <<>>}, _) -> 35; 1183 table_find_field({<<"expires">>, <<>>}, _) -> 36; 1184 table_find_field({<<"from">>, <<>>}, _) -> 37; 1185 table_find_field({<<"host">>, <<>>}, _) -> 38; 1186 table_find_field({<<"if-match">>, <<>>}, _) -> 39; 1187 table_find_field({<<"if-modified-since">>, <<>>}, _) -> 40; 1188 table_find_field({<<"if-none-match">>, <<>>}, _) -> 41; 1189 table_find_field({<<"if-range">>, <<>>}, _) -> 42; 1190 table_find_field({<<"if-unmodified-since">>, <<>>}, _) -> 43; 1191 table_find_field({<<"last-modified">>, <<>>}, _) -> 44; 1192 table_find_field({<<"link">>, <<>>}, _) -> 45; 1193 table_find_field({<<"location">>, <<>>}, _) -> 46; 1194 table_find_field({<<"max-forwards">>, <<>>}, _) -> 47; 1195 table_find_field({<<"proxy-authenticate">>, <<>>}, _) -> 48; 1196 table_find_field({<<"proxy-authorization">>, <<>>}, _) -> 49; 1197 table_find_field({<<"range">>, <<>>}, _) -> 50; 1198 table_find_field({<<"referer">>, <<>>}, _) -> 51; 1199 table_find_field({<<"refresh">>, <<>>}, _) -> 52; 1200 table_find_field({<<"retry-after">>, <<>>}, _) -> 53; 1201 table_find_field({<<"server">>, <<>>}, _) -> 54; 1202 table_find_field({<<"set-cookie">>, <<>>}, _) -> 55; 1203 table_find_field({<<"strict-transport-security">>, <<>>}, _) -> 56; 1204 table_find_field({<<"transfer-encoding">>, <<>>}, _) -> 57; 1205 table_find_field({<<"user-agent">>, <<>>}, _) -> 58; 1206 table_find_field({<<"vary">>, <<>>}, _) -> 59; 1207 table_find_field({<<"via">>, <<>>}, _) -> 60; 1208 table_find_field({<<"www-authenticate">>, <<>>}, _) -> 61; 1209 table_find_field(Header, #state{dyn_table=DynamicTable}) -> 1210 table_find_field_dyn(Header, DynamicTable, 62). 1211 1212 table_find_field_dyn(_, [], _) -> not_found; 1213 table_find_field_dyn(Header, [{_, Header}|_], Index) -> Index; 1214 table_find_field_dyn(Header, [_|Tail], Index) -> table_find_field_dyn(Header, Tail, Index + 1). 1215 1216 table_find_name(<<":authority">>, _) -> 1; 1217 table_find_name(<<":method">>, _) -> 2; 1218 table_find_name(<<":path">>, _) -> 4; 1219 table_find_name(<<":scheme">>, _) -> 6; 1220 table_find_name(<<":status">>, _) -> 8; 1221 table_find_name(<<"accept-charset">>, _) -> 15; 1222 table_find_name(<<"accept-encoding">>, _) -> 16; 1223 table_find_name(<<"accept-language">>, _) -> 17; 1224 table_find_name(<<"accept-ranges">>, _) -> 18; 1225 table_find_name(<<"accept">>, _) -> 19; 1226 table_find_name(<<"access-control-allow-origin">>, _) -> 20; 1227 table_find_name(<<"age">>, _) -> 21; 1228 table_find_name(<<"allow">>, _) -> 22; 1229 table_find_name(<<"authorization">>, _) -> 23; 1230 table_find_name(<<"cache-control">>, _) -> 24; 1231 table_find_name(<<"content-disposition">>, _) -> 25; 1232 table_find_name(<<"content-encoding">>, _) -> 26; 1233 table_find_name(<<"content-language">>, _) -> 27; 1234 table_find_name(<<"content-length">>, _) -> 28; 1235 table_find_name(<<"content-location">>, _) -> 29; 1236 table_find_name(<<"content-range">>, _) -> 30; 1237 table_find_name(<<"content-type">>, _) -> 31; 1238 table_find_name(<<"cookie">>, _) -> 32; 1239 table_find_name(<<"date">>, _) -> 33; 1240 table_find_name(<<"etag">>, _) -> 34; 1241 table_find_name(<<"expect">>, _) -> 35; 1242 table_find_name(<<"expires">>, _) -> 36; 1243 table_find_name(<<"from">>, _) -> 37; 1244 table_find_name(<<"host">>, _) -> 38; 1245 table_find_name(<<"if-match">>, _) -> 39; 1246 table_find_name(<<"if-modified-since">>, _) -> 40; 1247 table_find_name(<<"if-none-match">>, _) -> 41; 1248 table_find_name(<<"if-range">>, _) -> 42; 1249 table_find_name(<<"if-unmodified-since">>, _) -> 43; 1250 table_find_name(<<"last-modified">>, _) -> 44; 1251 table_find_name(<<"link">>, _) -> 45; 1252 table_find_name(<<"location">>, _) -> 46; 1253 table_find_name(<<"max-forwards">>, _) -> 47; 1254 table_find_name(<<"proxy-authenticate">>, _) -> 48; 1255 table_find_name(<<"proxy-authorization">>, _) -> 49; 1256 table_find_name(<<"range">>, _) -> 50; 1257 table_find_name(<<"referer">>, _) -> 51; 1258 table_find_name(<<"refresh">>, _) -> 52; 1259 table_find_name(<<"retry-after">>, _) -> 53; 1260 table_find_name(<<"server">>, _) -> 54; 1261 table_find_name(<<"set-cookie">>, _) -> 55; 1262 table_find_name(<<"strict-transport-security">>, _) -> 56; 1263 table_find_name(<<"transfer-encoding">>, _) -> 57; 1264 table_find_name(<<"user-agent">>, _) -> 58; 1265 table_find_name(<<"vary">>, _) -> 59; 1266 table_find_name(<<"via">>, _) -> 60; 1267 table_find_name(<<"www-authenticate">>, _) -> 61; 1268 table_find_name(Name, #state{dyn_table=DynamicTable}) -> 1269 table_find_name_dyn(Name, DynamicTable, 62). 1270 1271 table_find_name_dyn(_, [], _) -> not_found; 1272 table_find_name_dyn(Name, [{Name, _}|_], Index) -> Index; 1273 table_find_name_dyn(Name, [_|Tail], Index) -> table_find_name_dyn(Name, Tail, Index + 1). 1274 1275 table_get(1, _) -> {<<":authority">>, <<>>}; 1276 table_get(2, _) -> {<<":method">>, <<"GET">>}; 1277 table_get(3, _) -> {<<":method">>, <<"POST">>}; 1278 table_get(4, _) -> {<<":path">>, <<"/">>}; 1279 table_get(5, _) -> {<<":path">>, <<"/index.html">>}; 1280 table_get(6, _) -> {<<":scheme">>, <<"http">>}; 1281 table_get(7, _) -> {<<":scheme">>, <<"https">>}; 1282 table_get(8, _) -> {<<":status">>, <<"200">>}; 1283 table_get(9, _) -> {<<":status">>, <<"204">>}; 1284 table_get(10, _) -> {<<":status">>, <<"206">>}; 1285 table_get(11, _) -> {<<":status">>, <<"304">>}; 1286 table_get(12, _) -> {<<":status">>, <<"400">>}; 1287 table_get(13, _) -> {<<":status">>, <<"404">>}; 1288 table_get(14, _) -> {<<":status">>, <<"500">>}; 1289 table_get(15, _) -> {<<"accept-charset">>, <<>>}; 1290 table_get(16, _) -> {<<"accept-encoding">>, <<"gzip, deflate">>}; 1291 table_get(17, _) -> {<<"accept-language">>, <<>>}; 1292 table_get(18, _) -> {<<"accept-ranges">>, <<>>}; 1293 table_get(19, _) -> {<<"accept">>, <<>>}; 1294 table_get(20, _) -> {<<"access-control-allow-origin">>, <<>>}; 1295 table_get(21, _) -> {<<"age">>, <<>>}; 1296 table_get(22, _) -> {<<"allow">>, <<>>}; 1297 table_get(23, _) -> {<<"authorization">>, <<>>}; 1298 table_get(24, _) -> {<<"cache-control">>, <<>>}; 1299 table_get(25, _) -> {<<"content-disposition">>, <<>>}; 1300 table_get(26, _) -> {<<"content-encoding">>, <<>>}; 1301 table_get(27, _) -> {<<"content-language">>, <<>>}; 1302 table_get(28, _) -> {<<"content-length">>, <<>>}; 1303 table_get(29, _) -> {<<"content-location">>, <<>>}; 1304 table_get(30, _) -> {<<"content-range">>, <<>>}; 1305 table_get(31, _) -> {<<"content-type">>, <<>>}; 1306 table_get(32, _) -> {<<"cookie">>, <<>>}; 1307 table_get(33, _) -> {<<"date">>, <<>>}; 1308 table_get(34, _) -> {<<"etag">>, <<>>}; 1309 table_get(35, _) -> {<<"expect">>, <<>>}; 1310 table_get(36, _) -> {<<"expires">>, <<>>}; 1311 table_get(37, _) -> {<<"from">>, <<>>}; 1312 table_get(38, _) -> {<<"host">>, <<>>}; 1313 table_get(39, _) -> {<<"if-match">>, <<>>}; 1314 table_get(40, _) -> {<<"if-modified-since">>, <<>>}; 1315 table_get(41, _) -> {<<"if-none-match">>, <<>>}; 1316 table_get(42, _) -> {<<"if-range">>, <<>>}; 1317 table_get(43, _) -> {<<"if-unmodified-since">>, <<>>}; 1318 table_get(44, _) -> {<<"last-modified">>, <<>>}; 1319 table_get(45, _) -> {<<"link">>, <<>>}; 1320 table_get(46, _) -> {<<"location">>, <<>>}; 1321 table_get(47, _) -> {<<"max-forwards">>, <<>>}; 1322 table_get(48, _) -> {<<"proxy-authenticate">>, <<>>}; 1323 table_get(49, _) -> {<<"proxy-authorization">>, <<>>}; 1324 table_get(50, _) -> {<<"range">>, <<>>}; 1325 table_get(51, _) -> {<<"referer">>, <<>>}; 1326 table_get(52, _) -> {<<"refresh">>, <<>>}; 1327 table_get(53, _) -> {<<"retry-after">>, <<>>}; 1328 table_get(54, _) -> {<<"server">>, <<>>}; 1329 table_get(55, _) -> {<<"set-cookie">>, <<>>}; 1330 table_get(56, _) -> {<<"strict-transport-security">>, <<>>}; 1331 table_get(57, _) -> {<<"transfer-encoding">>, <<>>}; 1332 table_get(58, _) -> {<<"user-agent">>, <<>>}; 1333 table_get(59, _) -> {<<"vary">>, <<>>}; 1334 table_get(60, _) -> {<<"via">>, <<>>}; 1335 table_get(61, _) -> {<<"www-authenticate">>, <<>>}; 1336 table_get(Index, #state{dyn_table=DynamicTable}) -> 1337 {_, Header} = lists:nth(Index - 61, DynamicTable), 1338 Header. 1339 1340 table_get_name(1, _) -> <<":authority">>; 1341 table_get_name(2, _) -> <<":method">>; 1342 table_get_name(3, _) -> <<":method">>; 1343 table_get_name(4, _) -> <<":path">>; 1344 table_get_name(5, _) -> <<":path">>; 1345 table_get_name(6, _) -> <<":scheme">>; 1346 table_get_name(7, _) -> <<":scheme">>; 1347 table_get_name(8, _) -> <<":status">>; 1348 table_get_name(9, _) -> <<":status">>; 1349 table_get_name(10, _) -> <<":status">>; 1350 table_get_name(11, _) -> <<":status">>; 1351 table_get_name(12, _) -> <<":status">>; 1352 table_get_name(13, _) -> <<":status">>; 1353 table_get_name(14, _) -> <<":status">>; 1354 table_get_name(15, _) -> <<"accept-charset">>; 1355 table_get_name(16, _) -> <<"accept-encoding">>; 1356 table_get_name(17, _) -> <<"accept-language">>; 1357 table_get_name(18, _) -> <<"accept-ranges">>; 1358 table_get_name(19, _) -> <<"accept">>; 1359 table_get_name(20, _) -> <<"access-control-allow-origin">>; 1360 table_get_name(21, _) -> <<"age">>; 1361 table_get_name(22, _) -> <<"allow">>; 1362 table_get_name(23, _) -> <<"authorization">>; 1363 table_get_name(24, _) -> <<"cache-control">>; 1364 table_get_name(25, _) -> <<"content-disposition">>; 1365 table_get_name(26, _) -> <<"content-encoding">>; 1366 table_get_name(27, _) -> <<"content-language">>; 1367 table_get_name(28, _) -> <<"content-length">>; 1368 table_get_name(29, _) -> <<"content-location">>; 1369 table_get_name(30, _) -> <<"content-range">>; 1370 table_get_name(31, _) -> <<"content-type">>; 1371 table_get_name(32, _) -> <<"cookie">>; 1372 table_get_name(33, _) -> <<"date">>; 1373 table_get_name(34, _) -> <<"etag">>; 1374 table_get_name(35, _) -> <<"expect">>; 1375 table_get_name(36, _) -> <<"expires">>; 1376 table_get_name(37, _) -> <<"from">>; 1377 table_get_name(38, _) -> <<"host">>; 1378 table_get_name(39, _) -> <<"if-match">>; 1379 table_get_name(40, _) -> <<"if-modified-since">>; 1380 table_get_name(41, _) -> <<"if-none-match">>; 1381 table_get_name(42, _) -> <<"if-range">>; 1382 table_get_name(43, _) -> <<"if-unmodified-since">>; 1383 table_get_name(44, _) -> <<"last-modified">>; 1384 table_get_name(45, _) -> <<"link">>; 1385 table_get_name(46, _) -> <<"location">>; 1386 table_get_name(47, _) -> <<"max-forwards">>; 1387 table_get_name(48, _) -> <<"proxy-authenticate">>; 1388 table_get_name(49, _) -> <<"proxy-authorization">>; 1389 table_get_name(50, _) -> <<"range">>; 1390 table_get_name(51, _) -> <<"referer">>; 1391 table_get_name(52, _) -> <<"refresh">>; 1392 table_get_name(53, _) -> <<"retry-after">>; 1393 table_get_name(54, _) -> <<"server">>; 1394 table_get_name(55, _) -> <<"set-cookie">>; 1395 table_get_name(56, _) -> <<"strict-transport-security">>; 1396 table_get_name(57, _) -> <<"transfer-encoding">>; 1397 table_get_name(58, _) -> <<"user-agent">>; 1398 table_get_name(59, _) -> <<"vary">>; 1399 table_get_name(60, _) -> <<"via">>; 1400 table_get_name(61, _) -> <<"www-authenticate">>; 1401 table_get_name(Index, #state{dyn_table=DynamicTable}) -> 1402 {_, {Name, _}} = lists:nth(Index - 61, DynamicTable), 1403 Name. 1404 1405 table_insert(Entry = {Name, Value}, State=#state{size=Size, max_size=MaxSize, dyn_table=DynamicTable}) -> 1406 EntrySize = byte_size(Name) + byte_size(Value) + 32, 1407 if 1408 EntrySize + Size =< MaxSize -> 1409 %% Add entry without eviction 1410 State#state{size=Size + EntrySize, dyn_table=[{EntrySize, Entry}|DynamicTable]}; 1411 EntrySize =< MaxSize -> 1412 %% Evict, then add entry 1413 {DynamicTable2, Size2} = table_resize(DynamicTable, MaxSize - EntrySize, 0, []), 1414 State#state{size=Size2 + EntrySize, dyn_table=[{EntrySize, Entry}|DynamicTable2]}; 1415 EntrySize > MaxSize -> 1416 %% "an attempt to add an entry larger than the 1417 %% maximum size causes the table to be emptied 1418 %% of all existing entries and results in an 1419 %% empty table" (RFC 7541, 4.4) 1420 State#state{size=0, dyn_table=[]} 1421 end. 1422 1423 table_resize([], _, Size, Acc) -> 1424 {lists:reverse(Acc), Size}; 1425 table_resize([{EntrySize, _}|_], MaxSize, Size, Acc) when Size + EntrySize > MaxSize -> 1426 {lists:reverse(Acc), Size}; 1427 table_resize([Entry = {EntrySize, _}|Tail], MaxSize, Size, Acc) -> 1428 table_resize(Tail, MaxSize, Size + EntrySize, [Entry|Acc]). 1429 1430 table_update_size(0, State) -> 1431 State#state{size=0, max_size=0, dyn_table=[]}; 1432 table_update_size(MaxSize, State=#state{size=CurrentSize}) 1433 when CurrentSize =< MaxSize -> 1434 State#state{max_size=MaxSize}; 1435 table_update_size(MaxSize, State=#state{dyn_table=DynTable}) -> 1436 {DynTable2, Size} = table_resize(DynTable, MaxSize, 0, []), 1437 State#state{size=Size, max_size=MaxSize, dyn_table=DynTable2}. 1438 1439 -ifdef(TEST). 1440 prop_str_raw() -> 1441 ?FORALL(Str, binary(), begin 1442 {Str, <<>>} =:= dec_str(iolist_to_binary(enc_str(Str, no_huffman))) 1443 end). 1444 1445 prop_str_huffman() -> 1446 ?FORALL(Str, binary(), begin 1447 {Str, <<>>} =:= dec_str(iolist_to_binary(enc_str(Str, huffman))) 1448 end). 1449 -endif.