diff options
author | Loïc Hoguin <[email protected]> | 2020-03-30 17:30:01 +0200 |
---|---|---|
committer | Loïc Hoguin <[email protected]> | 2020-03-30 17:30:01 +0200 |
commit | 4b369969ce0a3dc2a2ac10b31a6ce844926faac4 (patch) | |
tree | b601e0ce10270498e549dfa57d460b87f387a273 /src/cow_hpack.erl | |
parent | b34155f725245848dca3a505398e262b1d50f25b (diff) | |
download | cowlib-4b369969ce0a3dc2a2ac10b31a6ce844926faac4.tar.gz cowlib-4b369969ce0a3dc2a2ac10b31a6ce844926faac4.tar.bz2 cowlib-4b369969ce0a3dc2a2ac10b31a6ce844926faac4.zip |
Fix some HPACK Huffman decoding failure cases
When EOS is found within the string the decoding must fail.
When the final padding is > 7 bit in length the decoding must
fail as well.
Diffstat (limited to 'src/cow_hpack.erl')
-rw-r--r-- | src/cow_hpack.erl | 38 |
1 files changed, 28 insertions, 10 deletions
diff --git a/src/cow_hpack.erl b/src/cow_hpack.erl index 4c27a75..3089d16 100644 --- a/src/cow_hpack.erl +++ b/src/cow_hpack.erl @@ -209,9 +209,9 @@ dec_str(<<0:1, Length:7, Rest0/bits>>) -> {Str, Rest}; dec_str(<<1:1, 2#1111111:7, Rest0/bits>>) -> {Length, Rest} = dec_big_int(Rest0, 127, 0), - dec_huffman(Rest, Length, 0, ok, <<>>); + dec_huffman(Rest, Length, 0, <<>>); dec_str(<<1:1, Length:7, Rest/bits>>) -> - dec_huffman(Rest, Length, 0, ok, <<>>). + dec_huffman(Rest, Length, 0, <<>>). %% We use a lookup table that allows us to benefit from %% the binary match context optimization. A more naive @@ -221,21 +221,39 @@ dec_str(<<1:1, Length:7, Rest/bits>>) -> %% %% See cow_hpack_dec_huffman_lookup.hrl for more details. -dec_huffman(<<A:4, B:4, R/bits>>, Len, Huff0, _, Acc) when Len > 0 -> +dec_huffman(<<A:4, B:4, R/bits>>, Len, Huff0, Acc) when Len > 1 -> {_, CharA, Huff1} = dec_huffman_lookup(Huff0, A), - {Result, CharB, Huff} = dec_huffman_lookup(Huff1, B), + {_, CharB, Huff} = dec_huffman_lookup(Huff1, B), case {CharA, CharB} of - {undefined, undefined} -> dec_huffman(R, Len - 1, Huff, Result, Acc); - {CharA, undefined} -> dec_huffman(R, Len - 1, Huff, Result, <<Acc/binary, CharA>>); - {undefined, CharB} -> dec_huffman(R, Len - 1, Huff, Result, <<Acc/binary, CharB>>); - {CharA, CharB} -> dec_huffman(R, Len - 1, Huff, Result, <<Acc/binary, CharA, CharB>>) + {undefined, undefined} -> dec_huffman(R, Len - 1, Huff, Acc); + {CharA, undefined} -> dec_huffman(R, Len - 1, Huff, <<Acc/binary, CharA>>); + {undefined, CharB} -> dec_huffman(R, Len - 1, Huff, <<Acc/binary, CharB>>); + {CharA, CharB} -> dec_huffman(R, Len - 1, Huff, <<Acc/binary, CharA, CharB>>) end; -dec_huffman(Rest, 0, _, ok, Acc) -> - {Acc, Rest}. +dec_huffman(<<A:4, B:4, Rest/bits>>, 1, Huff0, Acc) -> + {_, CharA, Huff} = dec_huffman_lookup(Huff0, A), + {ok, CharB, _} = dec_huffman_lookup(Huff, B), + case {CharA, CharB} of + %% {undefined, undefined} (> 7-bit final padding) is rejected with a crash. + {CharA, undefined} -> + {<<Acc/binary, CharA>>, Rest}; + {undefined, CharB} -> + {<<Acc/binary, CharB>>, Rest}; + _ -> + {<<Acc/binary, CharA, CharB>>, Rest} + end; +%% Can only be reached when the string length to decode is 0. +dec_huffman(Rest, 0, _, <<>>) -> + {<<>>, Rest}. -include("cow_hpack_dec_huffman_lookup.hrl"). -ifdef(TEST). +%% Test case extracted from h2spec. +decode_reject_eos_test() -> + {'EXIT', _} = (catch decode(<<16#0085f2b24a84ff874951fffffffa7f:120>>)), + ok. + req_decode_test() -> %% First request (raw then huffman). {Headers1, State1} = decode(<< 16#828684410f7777772e6578616d706c652e636f6d:160 >>), |