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

Commit a2d4637

Browse files
committed
Basic HTTP abstraction layer.
1 parent d09c017 commit a2d4637

File tree

1 file changed

+108
-0
lines changed

1 file changed

+108
-0
lines changed

hyper/common/connection.py

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# -*- coding: utf-8 -*-
2+
"""
3+
hyper/common/connection
4+
~~~~~~~~~~~~~~~~~~~~~~~
5+
6+
Hyper's HTTP/1.1 and HTTP/2 abstraction layer.
7+
"""
8+
from .exceptions import TLSUpgrade
9+
from ..http11.connection import HTTP11Connection
10+
from ..http20.connection import HTTP20Connection
11+
from ..tls import H2_NPN_PROTOCOLS
12+
13+
14+
class HTTPConnection(object):
15+
"""
16+
An object representing a single HTTP connection to a server.
17+
18+
This object behaves similarly to the Python standard library's
19+
``HTTPConnection`` object, with a few critical differences.
20+
21+
Most of the standard library's arguments to the constructor are not
22+
supported by hyper. Most optional parameters apply to *either* HTTP/1.1 or
23+
HTTP/2.
24+
25+
:param host: The host to connect to. This may be an IP address or a
26+
hostname, and optionally may include a port: for example,
27+
``'http2bin.org'``, ``'http2bin.org:443'`` or ``'127.0.0.1'``.
28+
:param port: (optional) The port to connect to. If not provided and one also
29+
isn't provided in the ``host`` parameter, defaults to 443.
30+
:param secure: (optional, HTTP/1.1 only) Whether the request should use
31+
TLS. Defaults to ``False`` for most requests, but to ``True`` for any
32+
request issued to port 443.
33+
:param window_manager: (optional) The class to use to manage flow control
34+
windows. This needs to be a subclass of the
35+
:class:`BaseFlowControlManager <hyper.http20.window.BaseFlowControlManager>`.
36+
If not provided,
37+
:class:`FlowControlManager <hyper.http20.window.FlowControlManager>`
38+
will be used.
39+
:param enable_push: (optional) Whether the server is allowed to push
40+
resources to the client (see
41+
:meth:`get_pushes() <hyper.HTTP20Connection.get_pushes>`).
42+
"""
43+
def __init__(self,
44+
host,
45+
port=None,
46+
secure=None,
47+
window_manager=None,
48+
enable_push=False,
49+
**kwargs):
50+
51+
self._host = host
52+
self._port = port
53+
self._h1_kwargs = {'secure': secure}
54+
self._h2_kwargs = {
55+
'window_manager': window_manager, 'enable_push': enable_push
56+
}
57+
58+
# Add any unexpected kwargs to both dictionaries.
59+
self._h1_kwargs.update(kwargs)
60+
self._h2_kwargs.update(kwargs)
61+
62+
self._conn = HTTP11Connection(
63+
self._host, self._port, **self._h1_kwargs
64+
)
65+
66+
def request(self, method, url, body=None, headers={}):
67+
"""
68+
This will send a request to the server using the HTTP request method
69+
``method`` and the selector ``url``. If the ``body`` argument is
70+
present, it should be string or bytes object of data to send after the
71+
headers are finished. Strings are encoded as UTF-8. To use other
72+
encodings, pass a bytes object. The Content-Length header is set to the
73+
length of the body field.
74+
75+
:param method: The request method, e.g. ``'GET'``.
76+
:param url: The URL to contact, e.g. ``'/path/segment'``.
77+
:param body: (optional) The request body to send. Must be a bytestring
78+
or a file-like object.
79+
:param headers: (optional) The headers to send on the request.
80+
:returns: A stream ID for the request, or ``None`` if the request is
81+
made over HTTP/1.1.
82+
"""
83+
try:
84+
return self._conn.request(
85+
method=method, url=url, body=body, headers=headers
86+
)
87+
except TLSUpgrade as e:
88+
# We upgraded in the NPN/ALPN handshake. We can just go straight to
89+
# the world of HTTP/2. Replace the backing object and insert the
90+
# socket into it.
91+
assert e.negotiated in H2_NPN_PROTOCOLS
92+
93+
self._conn = HTTP20Connection(
94+
self._host, self._port, **self._h2_kwargs
95+
)
96+
self._conn._sock = e.sock
97+
98+
# Because we skipped the connecting logic, we need to send the
99+
# HTTP/2 preamble.
100+
self._conn._send_preamble()
101+
102+
return self._conn.request(
103+
method=method, url=url, body=body, headers=headers
104+
)
105+
106+
# Can anyone say 'proxy object pattern'?
107+
def __getattr__(self, name):
108+
return getattr(self._conn, name)

0 commit comments

Comments
 (0)