Skip to content
This repository was archived by the owner on Jan 13, 2021. It is now read-only.

Commit ce3f39b

Browse files
committed
Don't succeed on invalid HPACK input.
If given a Huffman-encoded string that we can't decode, rather than quietly returning an empty string we should throw an exception.
1 parent 798b5b9 commit ce3f39b

File tree

3 files changed

+42
-7
lines changed

3 files changed

+42
-7
lines changed

hyper/http20/exceptions.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# -*- coding: utf-8 -*-
2+
"""
3+
hyper/http20/exceptions
4+
~~~~~~~~~~~~~~~~~~~~~~~
5+
6+
This defines exceptions used in the HTTP/2.0 portion of hyper.
7+
"""
8+
class HTTP20Error(Exception):
9+
"""
10+
The base class for all of ``hyper``'s HTTP/2.0-related exceptions.
11+
"""
12+
pass
13+
14+
15+
class HPACKDecodingError(HTTP20Error):
16+
"""
17+
An error has been encountered while performing HPACK decoding.
18+
"""
19+
pass

hyper/http20/huffman.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
An implementation of a bitwise prefix tree specially built for decoding
77
Huffman-coded content where we already know the Huffman table.
88
"""
9+
from .exceptions import HPACKDecodingError
10+
911

1012
def _pad_binary(bin_str, req_len=8):
1113
"""
@@ -59,13 +61,17 @@ def decode(self, encoded_string):
5961
number = _hex_to_bin_str(encoded_string)
6062
cur_node = self.root
6163
decoded_message = []
62-
for digit in number:
63-
if digit not in cur_node.mapping:
64-
break
65-
cur_node = cur_node.mapping[digit]
66-
if cur_node.data is not None:
67-
decoded_message.append(cur_node.data)
68-
cur_node = self.root
64+
65+
try:
66+
for digit in number:
67+
cur_node = cur_node.mapping[digit]
68+
if cur_node.data is not None:
69+
decoded_message.append(cur_node.data)
70+
cur_node = self.root
71+
except KeyError:
72+
# We have a Huffman-coded string that doesn't match our trie. This
73+
# is pretty bad: raise a useful exception.
74+
raise HPACKDecodingError("Invalid Huffman-coded string received.")
6975
return bytes(decoded_message)
7076

7177

test/test_hyper.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
Stream, STATE_HALF_CLOSED_LOCAL, STATE_OPEN, MAX_CHUNK, STATE_CLOSED
1313
)
1414
from hyper.http20.response import HTTP20Response
15+
from hyper.http20.exceptions import HPACKDecodingError
1516
from hyper.contrib import HTTP20Adapter
1617
import pytest
1718
import zlib
@@ -329,6 +330,15 @@ def test_continuation_frame_parses_properly(self):
329330
assert f.data == b'hello world'
330331

331332

333+
class TestHuffmanDecoder(object):
334+
def test_huffman_decoder_throws_useful_exceptions(self):
335+
# Specify a HuffmanDecoder with no values in it, then attempt to decode
336+
# using it.
337+
d = HuffmanDecoder([], [])
338+
with pytest.raises(HPACKDecodingError):
339+
d.decode(b'test')
340+
341+
332342
class TestHPACKEncoder(object):
333343
# These tests are stolen entirely from the IETF specification examples.
334344
def test_literal_header_field_with_indexing(self):

0 commit comments

Comments
 (0)