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

Commit

Permalink
Resizing header table causes context updates.
Browse files Browse the repository at this point in the history
  • Loading branch information
Lukasa committed Jun 26, 2014
1 parent 111051e commit e2b23b0
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 0 deletions.
22 changes: 22 additions & 0 deletions hyper/http20/hpack.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,11 @@ def __init__(self):
# test for presence.
self.reference_set = {}

# We need to keep track of whether the header table size has been
# changed since we last encoded anything. If it has, we need to signal
# that change in the HPACK block.
self._table_size_changed = False

@property
def header_table_size(self):
return self._header_table_size
Expand Down Expand Up @@ -220,6 +225,9 @@ def header_table_size(self, value):
"Removed %s: %s from the encoder header table", n, v
)

if value != self._header_table_size:
self._table_size_changed = True

self._header_table_size = value

def encode(self, headers, huffman=True):
Expand Down Expand Up @@ -259,6 +267,12 @@ def encode(self, headers, huffman=True):
# Next, walk across the headers and turn them all into bytestrings.
headers = [(_to_bytes(n), _to_bytes(v)) for n, v in headers]

# Before we begin, if the header table size has been changed we need
# to signal that appropriately.
if self._table_size_changed:
header_block.append(self._encode_table_size_change())
self._table_size_changed = False

# We can now encode each header in the block. The logic here roughly
# goes as follows:
# 1. Check whether the header is in the reference set. If it is and
Expand Down Expand Up @@ -515,6 +529,14 @@ def _encode_indexed_literal(self, index, value, huffman=False):

return b''.join([bytes(name), bytes(value_len), value])

def _encode_table_size_change(self):
"""
Produces the encoded form of a header table size change context update.
"""
size_bytes = encode_integer(self.header_table_size, 4)
size_bytes[0] |= 0x20
return bytes(size_bytes)


class Decoder(object):
"""
Expand Down
29 changes: 29 additions & 0 deletions test/test_hyper.py
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,9 @@ def test_indexed_header_field_from_static_table(self):
header_set = {':method': 'GET'}
result = b'\x82'

# Make sure we don't emit an encoding context update.
e._table_size_changed = False

assert e.encode(header_set, huffman=False) == result
assert list(e.header_table) == []

Expand Down Expand Up @@ -770,6 +773,32 @@ def test_removing_header_not_in_table_at_all(self):
with pytest.raises(HPACKEncodingError):
e.remove((b'not', b'present'))

def test_resizing_header_table_sends_context_update(self):
e = Encoder()

# Resize the header table to a size so small that nothing can be in it.
e.header_table_size = 40

# Now, encode a header set. Just a small one, with a well-defined
# output.
header_set = [(':method', 'GET')]
out = e.encode(header_set, huffman=True)

assert out == b'\x2f\x19\x82'

def test_setting_table_size_to_the_same_does_nothing(self):
e = Encoder()

# Set the header table size to the default.
e.header_table_size = 4096

# Now encode a header set. Just a small one, with a well-defined
# output.
header_set = [(':method', 'GET')]
out = e.encode(header_set, huffman=True)

assert out == b'\x82'


class TestHPACKDecoder(object):
# These tests are stolen entirely from the IETF specification examples.
Expand Down

0 comments on commit e2b23b0

Please sign in to comment.