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

Fixup HTTPHeaderMap replacing. #204

Merged
merged 2 commits into from
Feb 20, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
Release History
===============

dev
---

*Bugfixes*

- Overriding HTTP/2 special headers no longer leads to ill-formed header blocks
with special headers at the end.

0.5.0 (2015-10-11)
------------------

Expand Down
27 changes: 20 additions & 7 deletions hyper/common/headers.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,15 +184,28 @@ def iter_raw(self):
def replace(self, key, value):
"""
Replace existing header with new value. If header doesn't exist this
method work like ``__setitem__``. Replacing leads to deletion of all
exsiting headers with the same name.
method work like ``__setitem__``. Replacing leads to deletion of all
existing headers with the same name.
"""
try:
del self[key]
except KeyError:
pass
key = to_bytestring(key)
indices = []
for (i, (k, v)) in enumerate(self._items):
if _keys_equal(k, key):
indices.append(i)

# If the key isn't present, this is easy: just append and abort early.
if not indices:
self._items.append((key, value))
return

# Delete all but the first. I swear, this is the correct slicing
# syntax!
base_index = indices[0]
for i in indices[:0:-1]:
self._items.pop(i)

self[key] = value
del self._items[base_index]
self._items.insert(base_index, (key, value))

def merge(self, other):
"""
Expand Down
2 changes: 1 addition & 1 deletion test/test_headers.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,8 @@ def test_replacing(self):

assert list(h.items()) == [
(b'name', b'value'),
(b'name3', b'value3'),
(b'name2', b'42'),
(b'name3', b'value3'),
(b'name4', b'other_value'),
]

10 changes: 5 additions & 5 deletions test/test_hyper.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,8 @@ def test_putheader_replaces_headers(self):
assert list(s.headers.items()) == [
(b':method', b'GET'),
(b':scheme', b'https'),
(b':path', b'/'),
(b':authority', b'www.example.org'),
(b':path', b'/'),
(b'name', b'value2'),
]

Expand Down Expand Up @@ -581,7 +581,7 @@ def test_recv_cb_n_times(self):

def consume_single_frame():
mutable['counter'] += 1

c._consume_single_frame = consume_single_frame
c._recv_cb()

Expand Down Expand Up @@ -779,7 +779,7 @@ def test_streams_can_replace_none_headers(self):
(b"name", b"value"),
(b"other_name", b"other_value")
]

def test_stream_opening_sends_headers(self):
def data_callback(frame):
assert isinstance(frame, HeadersFrame)
Expand Down Expand Up @@ -1548,7 +1548,7 @@ def test_connection_error_when_send_out_of_range_frame(self):
class NullEncoder(object):
@staticmethod
def encode(headers):

def to_str(v):
if is_py2:
return str(v)
Expand All @@ -1557,7 +1557,7 @@ def to_str(v):
v = str(v, 'utf-8')
return v

return '\n'.join("%s%s" % (to_str(name), to_str(val))
return '\n'.join("%s%s" % (to_str(name), to_str(val))
for name, val in headers)


Expand Down