diff options
Diffstat (limited to 'netlib/http/http2')
-rw-r--r-- | netlib/http/http2/__init__.py | 8 | ||||
-rw-r--r-- | netlib/http/http2/connections.py (renamed from netlib/http/http2/protocol.py) | 30 | ||||
-rw-r--r-- | netlib/http/http2/frame.py | 39 |
3 files changed, 55 insertions, 22 deletions
diff --git a/netlib/http/http2/__init__.py b/netlib/http/http2/__init__.py index 5acf7696..7043d36f 100644 --- a/netlib/http/http2/__init__.py +++ b/netlib/http/http2/__init__.py @@ -1,2 +1,6 @@ -from frame import * -from protocol import * +from __future__ import absolute_import, print_function, division +from .connections import HTTP2Protocol + +__all__ = [ + "HTTP2Protocol" +] diff --git a/netlib/http/http2/protocol.py b/netlib/http/http2/connections.py index b6d376d3..5220d5d2 100644 --- a/netlib/http/http2/protocol.py +++ b/netlib/http/http2/connections.py @@ -3,8 +3,8 @@ import itertools import time from hpack.hpack import Encoder, Decoder -from netlib import http, utils -from netlib.http import semantics +from ... import utils +from .. import Headers, Response, Request, ALPN_PROTO_H2 from . import frame @@ -15,7 +15,7 @@ class TCPHandler(object): self.wfile = wfile -class HTTP2Protocol(semantics.ProtocolMixin): +class HTTP2Protocol(object): ERROR_CODES = utils.BiDi( NO_ERROR=0x0, @@ -36,8 +36,6 @@ class HTTP2Protocol(semantics.ProtocolMixin): CLIENT_CONNECTION_PREFACE = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" - ALPN_PROTO_H2 = 'h2' - def __init__( self, tcp_handler=None, @@ -62,6 +60,7 @@ class HTTP2Protocol(semantics.ProtocolMixin): def read_request( self, + __rfile, include_body=True, body_size_limit=None, allow_empty=False, @@ -111,7 +110,7 @@ class HTTP2Protocol(semantics.ProtocolMixin): port = 80 if scheme == 'http' else 443 port = int(port) - request = http.Request( + request = Request( form_in, method, scheme, @@ -131,6 +130,7 @@ class HTTP2Protocol(semantics.ProtocolMixin): def read_response( self, + __rfile, request_method='', body_size_limit=None, include_body=True, @@ -159,7 +159,7 @@ class HTTP2Protocol(semantics.ProtocolMixin): else: timestamp_end = None - response = http.Response( + response = Response( (2, 0), int(headers.get(':status', 502)), "", @@ -172,8 +172,16 @@ class HTTP2Protocol(semantics.ProtocolMixin): return response + def assemble(self, message): + if isinstance(message, Request): + return self.assemble_request(message) + elif isinstance(message, Response): + return self.assemble_response(message) + else: + raise ValueError("HTTP message not supported.") + def assemble_request(self, request): - assert isinstance(request, semantics.Request) + assert isinstance(request, Request) authority = self.tcp_handler.sni if self.tcp_handler.sni else self.tcp_handler.address.host if self.tcp_handler.address.port != 443: @@ -200,7 +208,7 @@ class HTTP2Protocol(semantics.ProtocolMixin): self._create_body(request.body, stream_id))) def assemble_response(self, response): - assert isinstance(response, semantics.Response) + assert isinstance(response, Response) headers = response.headers.copy() @@ -275,7 +283,7 @@ class HTTP2Protocol(semantics.ProtocolMixin): def check_alpn(self): alp = self.tcp_handler.get_alpn_proto_negotiated() - if alp != self.ALPN_PROTO_H2: + if alp != ALPN_PROTO_H2: raise NotImplementedError( "HTTP2Protocol can not handle unknown ALP: %s" % alp) return True @@ -405,7 +413,7 @@ class HTTP2Protocol(semantics.ProtocolMixin): else: self._handle_unexpected_frame(frm) - headers = http.Headers( + headers = Headers( [[str(k), str(v)] for k, v in self.decoder.decode(header_block_fragment)] ) diff --git a/netlib/http/http2/frame.py b/netlib/http/http2/frame.py index b36b3adf..cb2cde99 100644 --- a/netlib/http/http2/frame.py +++ b/netlib/http/http2/frame.py @@ -1,12 +1,31 @@ -import sys +from __future__ import absolute_import, print_function, division import struct from hpack.hpack import Encoder, Decoder -from .. import utils +from ...utils import BiDi +from ...exceptions import HttpSyntaxException -class FrameSizeError(Exception): - pass +ERROR_CODES = BiDi( + NO_ERROR=0x0, + PROTOCOL_ERROR=0x1, + INTERNAL_ERROR=0x2, + FLOW_CONTROL_ERROR=0x3, + SETTINGS_TIMEOUT=0x4, + STREAM_CLOSED=0x5, + FRAME_SIZE_ERROR=0x6, + REFUSED_STREAM=0x7, + CANCEL=0x8, + COMPRESSION_ERROR=0x9, + CONNECT_ERROR=0xa, + ENHANCE_YOUR_CALM=0xb, + INADEQUATE_SECURITY=0xc, + HTTP_1_1_REQUIRED=0xd +) + +CLIENT_CONNECTION_PREFACE = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" + +ALPN_PROTO_H2 = b'h2' class Frame(object): @@ -30,7 +49,9 @@ class Frame(object): length=0, flags=FLAG_NO_FLAGS, stream_id=0x0): - valid_flags = reduce(lambda x, y: x | y, self.VALID_FLAGS, 0x0) + valid_flags = 0 + for flag in self.VALID_FLAGS: + valid_flags |= flag if flags | valid_flags != valid_flags: raise ValueError('invalid flags detected.') @@ -61,7 +82,7 @@ class Frame(object): SettingsFrame.SETTINGS.SETTINGS_MAX_FRAME_SIZE] if length > max_frame_size: - raise FrameSizeError( + raise HttpSyntaxException( "Frame size exceeded: %d, but only %d allowed." % ( length, max_frame_size)) @@ -80,7 +101,7 @@ class Frame(object): stream_id = fields[4] if raw_header[:4] == b'HTTP': # pragma no cover - print >> sys.stderr, "WARNING: This looks like an HTTP/1 connection!" + raise HttpSyntaxException("Expected HTTP2 Frame, got HTTP/1 connection") cls._check_frame_size(length, state) @@ -339,7 +360,7 @@ class SettingsFrame(Frame): TYPE = 0x4 VALID_FLAGS = [Frame.FLAG_ACK] - SETTINGS = utils.BiDi( + SETTINGS = BiDi( SETTINGS_HEADER_TABLE_SIZE=0x1, SETTINGS_ENABLE_PUSH=0x2, SETTINGS_MAX_CONCURRENT_STREAMS=0x3, @@ -366,7 +387,7 @@ class SettingsFrame(Frame): def from_bytes(cls, state, length, flags, stream_id, payload): f = cls(state=state, length=length, flags=flags, stream_id=stream_id) - for i in xrange(0, len(payload), 6): + for i in range(0, len(payload), 6): identifier, value = struct.unpack("!HL", payload[i:i + 6]) f.settings[identifier] = value |