diff options
author | Thomas Kriechbaumer <thomas@kriechbaumer.name> | 2016-01-31 12:15:44 +0100 |
---|---|---|
committer | Thomas Kriechbaumer <thomas@kriechbaumer.name> | 2016-01-31 20:03:25 +0100 |
commit | 280b491ab2b743f75483e2916e5344b22d4136e1 (patch) | |
tree | 8fd4aaa0934ec9abe21d2a652857fbd77fd131a7 /netlib/http/http2/connections.py | |
parent | d253ebc142d80708a1bdc065d3db05d1394e3819 (diff) | |
download | mitmproxy-280b491ab2b743f75483e2916e5344b22d4136e1.tar.gz mitmproxy-280b491ab2b743f75483e2916e5344b22d4136e1.tar.bz2 mitmproxy-280b491ab2b743f75483e2916e5344b22d4136e1.zip |
migrate to hyperframe
Diffstat (limited to 'netlib/http/http2/connections.py')
-rw-r--r-- | netlib/http/http2/connections.py | 81 |
1 files changed, 43 insertions, 38 deletions
diff --git a/netlib/http/http2/connections.py b/netlib/http/http2/connections.py index c493abe6..c963f7c4 100644 --- a/netlib/http/http2/connections.py +++ b/netlib/http/http2/connections.py @@ -5,7 +5,8 @@ import time from hpack.hpack import Encoder, Decoder from ... import utils from .. import Headers, Response, Request -from . import frame + +from hyperframe import frame class TCPHandler(object): @@ -36,6 +37,15 @@ class HTTP2Protocol(object): CLIENT_CONNECTION_PREFACE = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" + HTTP2_DEFAULT_SETTINGS = { + frame.SettingsFrame.HEADER_TABLE_SIZE: 4096, + frame.SettingsFrame.ENABLE_PUSH: 1, + frame.SettingsFrame.MAX_CONCURRENT_STREAMS: None, + frame.SettingsFrame.INITIAL_WINDOW_SIZE: 2 ** 16 - 1, + frame.SettingsFrame.MAX_FRAME_SIZE: 2 ** 14, + frame.SettingsFrame.MAX_HEADER_LIST_SIZE: None, + } + def __init__( self, tcp_handler=None, @@ -54,7 +64,7 @@ class HTTP2Protocol(object): self.decoder = decoder or Decoder() self.unhandled_frame_cb = unhandled_frame_cb - self.http2_settings = frame.HTTP2_DEFAULT_SETTINGS.copy() + self.http2_settings = self.HTTP2_DEFAULT_SETTINGS.copy() self.current_stream_id = None self.connection_preface_performed = False @@ -240,9 +250,9 @@ class HTTP2Protocol(object): magic = self.tcp_handler.rfile.safe_read(magic_length) assert magic == self.CLIENT_CONNECTION_PREFACE - frm = frame.SettingsFrame(state=self, settings={ - frame.SettingsFrame.SETTINGS.SETTINGS_ENABLE_PUSH: 0, - frame.SettingsFrame.SETTINGS.SETTINGS_MAX_CONCURRENT_STREAMS: 1, + frm = frame.SettingsFrame(settings={ + frame.SettingsFrame.ENABLE_PUSH: 0, + frame.SettingsFrame.MAX_CONCURRENT_STREAMS: 1, }) self.send_frame(frm, hide=True) self._receive_settings(hide=True) @@ -253,12 +263,12 @@ class HTTP2Protocol(object): self.tcp_handler.wfile.write(self.CLIENT_CONNECTION_PREFACE) - self.send_frame(frame.SettingsFrame(state=self), hide=True) + self.send_frame(frame.SettingsFrame(), hide=True) self._receive_settings(hide=True) # server announces own settings self._receive_settings(hide=True) # server acks my settings def send_frame(self, frm, hide=False): - raw_bytes = frm.to_bytes() + raw_bytes = frm.serialize() self.tcp_handler.wfile.write(raw_bytes) self.tcp_handler.wfile.flush() if not hide and self.dump_frames: # pragma no cover @@ -266,19 +276,19 @@ class HTTP2Protocol(object): def read_frame(self, hide=False): while True: - frm = frame.Frame.from_file(self.tcp_handler.rfile, self) + frm = utils.http2_read_frame(self.tcp_handler.rfile) if not hide and self.dump_frames: # pragma no cover print(frm.human_readable("<<")) if isinstance(frm, frame.PingFrame): - raw_bytes = frame.PingFrame(flags=frame.Frame.FLAG_ACK, payload=frm.payload).to_bytes() + raw_bytes = frame.PingFrame(flags=['ACK'], payload=frm.payload).serialize() self.tcp_handler.wfile.write(raw_bytes) self.tcp_handler.wfile.flush() continue - if isinstance(frm, frame.SettingsFrame) and not frm.flags & frame.Frame.FLAG_ACK: + if isinstance(frm, frame.SettingsFrame) and 'ACK' not in frm.flags: self._apply_settings(frm.settings, hide) - if isinstance(frm, frame.DataFrame) and frm.length > 0: - self._update_flow_control_window(frm.stream_id, frm.length) + if isinstance(frm, frame.DataFrame) and frm.flow_controlled_length > 0: + self._update_flow_control_window(frm.stream_id, frm.flow_controlled_length) return frm def check_alpn(self): @@ -321,15 +331,13 @@ class HTTP2Protocol(object): old_value = '-' self.http2_settings[setting] = value - frm = frame.SettingsFrame( - state=self, - flags=frame.Frame.FLAG_ACK) + frm = frame.SettingsFrame(flags=['ACK']) self.send_frame(frm, hide) def _update_flow_control_window(self, stream_id, increment): - frm = frame.WindowUpdateFrame(stream_id=0, window_size_increment=increment) + frm = frame.WindowUpdateFrame(stream_id=0, window_increment=increment) self.send_frame(frm) - frm = frame.WindowUpdateFrame(stream_id=stream_id, window_size_increment=increment) + frm = frame.WindowUpdateFrame(stream_id=stream_id, window_increment=increment) self.send_frame(frm) def _create_headers(self, headers, stream_id, end_stream=True): @@ -342,43 +350,40 @@ class HTTP2Protocol(object): header_block_fragment = self.encoder.encode(headers.fields) - chunk_size = self.http2_settings[frame.SettingsFrame.SETTINGS.SETTINGS_MAX_FRAME_SIZE] + chunk_size = self.http2_settings[frame.SettingsFrame.MAX_FRAME_SIZE] chunks = range(0, len(header_block_fragment), chunk_size) frms = [frm_cls( - state=self, - flags=frame.Frame.FLAG_NO_FLAGS, + flags=[], stream_id=stream_id, - header_block_fragment=header_block_fragment[i:i+chunk_size]) for frm_cls, i in frame_cls(chunks)] + data=header_block_fragment[i:i+chunk_size]) for frm_cls, i in frame_cls(chunks)] - last_flags = frame.Frame.FLAG_END_HEADERS + frms[-1].flags.add('END_HEADERS') if end_stream: - last_flags |= frame.Frame.FLAG_END_STREAM - frms[-1].flags = last_flags + frms[0].flags.add('END_STREAM') if self.dump_frames: # pragma no cover for frm in frms: print(frm.human_readable(">>")) - return [frm.to_bytes() for frm in frms] + return [frm.serialize() for frm in frms] def _create_body(self, body, stream_id): if body is None or len(body) == 0: return b'' - chunk_size = self.http2_settings[frame.SettingsFrame.SETTINGS.SETTINGS_MAX_FRAME_SIZE] + chunk_size = self.http2_settings[frame.SettingsFrame.MAX_FRAME_SIZE] chunks = range(0, len(body), chunk_size) frms = [frame.DataFrame( - state=self, - flags=frame.Frame.FLAG_NO_FLAGS, + flags=[], stream_id=stream_id, - payload=body[i:i+chunk_size]) for i in chunks] - frms[-1].flags = frame.Frame.FLAG_END_STREAM + data=body[i:i+chunk_size]) for i in chunks] + frms[-1].flags.add('END_STREAM') if self.dump_frames: # pragma no cover for frm in frms: print(frm.human_readable(">>")) - return [frm.to_bytes() for frm in frms] + return [frm.serialize() for frm in frms] def _receive_transmission(self, stream_id=None, include_body=True): if not include_body: @@ -386,7 +391,7 @@ class HTTP2Protocol(object): body_expected = True - header_block_fragment = b'' + header_blocks = b'' body = b'' while True: @@ -396,10 +401,10 @@ class HTTP2Protocol(object): (stream_id is None or frm.stream_id == stream_id) ): stream_id = frm.stream_id - header_block_fragment += frm.header_block_fragment - if frm.flags & frame.Frame.FLAG_END_STREAM: + header_blocks += frm.data + if 'END_STREAM' in frm.flags: body_expected = False - if frm.flags & frame.Frame.FLAG_END_HEADERS: + if 'END_HEADERS' in frm.flags: break else: self._handle_unexpected_frame(frm) @@ -407,14 +412,14 @@ class HTTP2Protocol(object): while body_expected: frm = self.read_frame() if isinstance(frm, frame.DataFrame) and frm.stream_id == stream_id: - body += frm.payload - if frm.flags & frame.Frame.FLAG_END_STREAM: + body += frm.data + if 'END_STREAM' in frm.flags: break else: self._handle_unexpected_frame(frm) headers = Headers( - [[str(k), str(v)] for k, v in self.decoder.decode(header_block_fragment)] + [[str(k), str(v)] for k, v in self.decoder.decode(header_blocks)] ) return stream_id, headers, body |