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

Commit

Permalink
Allow trailing HEADERS frames.
Browse files Browse the repository at this point in the history
  • Loading branch information
Lukasa committed Jun 25, 2014
1 parent 260b4f9 commit 6620630
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 3 deletions.
9 changes: 9 additions & 0 deletions hyper/http20/response.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ def getheaders(self):
def items(self):
return self._headers.items()

def merge(self, headers):
for n, v in headers:
self._headers[n] = v
self._strip_headers()

def _strip_headers(self):
"""
Strips the headers attached to the instance of any header beginning
Expand Down Expand Up @@ -162,6 +167,10 @@ def read(self, amt=None, decode_content=True):
if decode_content and self._decompressobj:
data += self._decompressobj.flush()

if self._stream.response_headers:
self._headers.merge(self._stream.response_headers)

# We're at the end. Close the connection.
if not data:
self.close()

Expand Down
2 changes: 2 additions & 0 deletions hyper/http20/stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,8 @@ def receive_frame(self, frame):
else:
self.promised_headers[self.promised_stream_id] = headers

self.header_data = None

def open(self, end):
"""
Open the stream. Does this by encoding and sending the headers: no more
Expand Down
6 changes: 6 additions & 0 deletions test/test_hyper.py
Original file line number Diff line number Diff line change
Expand Up @@ -1945,6 +1945,8 @@ class DummyStream(object):
def __init__(self, data):
self.data = data
self.closed = False
self.response_headers = {}
self._remote_closed = False

def _read(self, *args, **kwargs):
try:
Expand All @@ -1954,6 +1956,10 @@ def _read(self, *args, **kwargs):

d = self.data[:read_len]
self.data = self.data[read_len:]

if not self.data:
self._remote_closed = True

return d

def close(self):
Expand Down
66 changes: 63 additions & 3 deletions test/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,12 @@ def decode_frame(frame_data):
return f


def build_headers_frame(headers):
def build_headers_frame(headers, encoder=None):
f = HeadersFrame(1)
e = Encoder()
e.huffman_coder = HuffmanEncoder(REQUEST_CODES, REQUEST_CODES_LENGTH)
e = encoder
if e is None:
e = Encoder()
e.huffman_coder = HuffmanEncoder(REQUEST_CODES, REQUEST_CODES_LENGTH)
f.data = e.encode(headers)
f.flags.add('END_HEADERS')
return f
Expand Down Expand Up @@ -310,6 +312,64 @@ def socket_handler(listener):

self.tear_down()

def test_receiving_trailers(self):
self.set_up()

recv_event = threading.Event()

def socket_handler(listener):
sock = listener.accept()[0]

e = Encoder()
e.huffman_coder = HuffmanEncoder(REQUEST_CODES, REQUEST_CODES_LENGTH)

# We get two messages for the connection open and then a HEADERS
# frame.
receive_preamble(sock)

# Now, send the headers for the response. This response has no body.
f = build_headers_frame([(':status', '200'), ('content-length', '0')], e)
f.stream_id = 1
sock.send(f.serialize())

# Also send a data frame.
f = DataFrame(1)
f.data = b'have some data'
sock.send(f.serialize())

# Now, send a headers frame again, containing trailing headers.
f = build_headers_frame([('trailing', 'sure'), (':res', 'no')], e)
f.flags.add('END_STREAM')
f.stream_id = 1
sock.send(f.serialize())

# Wait for the message from the main thread.
recv_event.wait()
sock.close()

self._start_server(socket_handler)
conn = self.get_connection()
conn.request('GET', '/')
resp = conn.getresponse()

# Confirm the status code.
assert resp.status == 200

# Confirm that we can read this, but it has no body.
assert resp.read() == b'have some data'
assert resp._stream._in_window_manager.document_size == 0

# Confirm that we got the trailing headers, and that they don't contain
# reserved headers.
assert resp.getheader('trailing') == 'sure'
assert resp.getheader(':res') is None
assert len(resp.getheaders()) == 2

# Awesome, we're done now.
recv_event.set()

self.tear_down()

def test_clean_shut_down(self):
self.set_up()

Expand Down

0 comments on commit 6620630

Please sign in to comment.