Repository navigation
Connection #127
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Connection #127
Changes from all commits
14d1c0d
2469089
e0ee823
b264732
caa69d3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,7 +19,6 @@ | |
| "Connection", | ||
| "ResponseStream", | ||
| "Transport", | ||
| "open_connection", | ||
| ] | ||
|
|
||
|
|
||
|
|
@@ -80,11 +79,30 @@ def stream( | |
|
|
||
|
|
||
| class Connection(Transport): | ||
| def __init__(self, stream: Stream, origin: URL | str): | ||
| self._stream = stream | ||
| def __init__(self, origin: URL | str, stream: Stream | None = None): | ||
| self._stream = Stream() if (stream is None) else stream | ||
| self._origin = URL(origin) if not isinstance(origin, URL) else origin | ||
| self._request_lock = Lock() | ||
| self._parser = HTTPParser(stream, mode="CLIENT") | ||
| self._parser = HTTPParser(self._stream, mode="CLIENT") | ||
|
|
||
| # Ensure valid URL | ||
| if self._origin.scheme not in ("http", "https"): | ||
| raise ValueError( | ||
| f"Invalid URL. Expected http:// or https://, got {self._origin.scheme}://" | ||
| ) | ||
|
|
||
| def open(self, backend: NetworkBackend | None = None) -> None: | ||
| backend = NetworkBackend() if (backend is None) else backend | ||
|
|
||
| scheme = self._origin.scheme | ||
| host = self._origin.host | ||
| port = self._origin.port or {"http": 80, "https": 443}[scheme] | ||
|
|
||
| if scheme == "https": | ||
| self._stream = backend.connect_tls(host, port) | ||
| else: | ||
| self._stream = backend.connect(host, port) | ||
| self._parser = HTTPParser(self._stream, mode="CLIENT") | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This repeats the parser initialisation in the constructor. Maybe we can postpone the parser creation until after connection is opened. |
||
|
|
||
| # API for connection pool management... | ||
| def origin(self) -> URL: | ||
|
|
@@ -180,6 +198,7 @@ def __repr__(self) -> str: | |
| return f"<Connection [{self._origin} {self.description()}]>" | ||
|
|
||
| def __enter__(self) -> "Self": | ||
| self.open() | ||
| return self | ||
|
|
||
| def __exit__( | ||
|
|
@@ -189,28 +208,3 @@ def __exit__( | |
| traceback: types.TracebackType | None = None, | ||
| ): | ||
| self.close() | ||
|
|
||
|
|
||
| def open_connection( | ||
| url: URL | str, | ||
| hostname: str = "", | ||
| backend: NetworkBackend | None = None, | ||
| ) -> Connection: | ||
|
|
||
| if isinstance(url, str): | ||
| url = URL(url) | ||
|
|
||
| if url.scheme not in ("http", "https"): | ||
| raise ValueError("URL scheme must be 'http://' or 'https://'.") | ||
| if backend is None: | ||
| backend = NetworkBackend() | ||
|
|
||
| host = url.host | ||
| port = url.port or {"http": 80, "https": 443}[url.scheme] | ||
|
|
||
| if url.scheme == "https": | ||
| stream = backend.connect_tls(host, port, hostname) | ||
| else: | ||
| stream = backend.connect(host, port) | ||
|
|
||
| return Connection(stream, url) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,9 @@ | ||
| from ._connection import Connection, ResponseStream, Transport, open_connection | ||
| from ._connection import Connection, ResponseStream, Transport | ||
| from ._pool import ConnectionPool | ||
|
|
||
| __all__ = [ | ||
| "Connection", | ||
| "ConnectionPool", | ||
| "ResponseStream", | ||
| "Transport", | ||
| "open_connection", | ||
| ] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -80,7 +80,7 @@ def test_connection_pool_should_have_managed_lifespan(server): | |
|
|
||
|
|
||
| def test_connection_request(server): | ||
| with hip.transports.open_connection(server.url) as conn: | ||
| with hip.transports.Connection(server.url) as conn: | ||
| assert repr(conn) == f"<Connection [{server.url} idle]>" | ||
|
|
||
| r = conn.request("GET", "/") | ||
|
|
@@ -90,7 +90,7 @@ def test_connection_request(server): | |
|
|
||
|
|
||
| def test_connection_stream(server): | ||
| with hip.transports.open_connection(server.url) as conn: | ||
| with hip.transports.Connection(server.url) as conn: | ||
| assert repr(conn) == f"<Connection [{server.url} idle]>" | ||
| with conn.stream("GET", "/") as r: | ||
| assert r.status_code == 200 | ||
|
|
@@ -101,7 +101,7 @@ def test_connection_stream(server): | |
|
|
||
| def test_connection_stream_read_in_chunks(server): | ||
| with ( | ||
| hip.transports.open_connection(server.url) as conn, | ||
| hip.transports.Connection(server.url) as conn, | ||
| conn.stream("GET", "/") as response, | ||
| ): | ||
| assert response.read(5) == b"Hello" | ||
|
|
@@ -110,19 +110,17 @@ def test_connection_stream_read_in_chunks(server): | |
|
|
||
|
|
||
| class TLSBackend: | ||
| def connect_tls(self, host, port, hostname): | ||
| self.connect_tls_args = (host, port, hostname) | ||
| def connect_tls(self, host, port): | ||
| self.connect_tls_args = (host, port) | ||
| return hip.Binary(b"").open() | ||
|
|
||
|
|
||
| def test_open_https_connection(): | ||
| backend = TLSBackend() | ||
|
|
||
| with hip.transports.open_connection( | ||
| "https://example.com", | ||
| hostname="example.com", | ||
| backend=backend, | ||
| ): | ||
| pass | ||
|
|
||
| assert backend.connect_tls_args == ("example.com", 443, "example.com") | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. def test_context_manager_uses_supplied_stream(server):
backend = hip.backends.NetworkBackend()
network_stream = backend.connect(server.host, server.port)
try:
with hip.transports.Connection(
server.url, stream=network_stream
) as connection:
assert connection._stream is network_stream
assert connection.request("GET", "/").status_code == 200
assert network_stream._is_closed
finally:
network_stream.close()Can we add a regression test like this? |
||
| conn = hip.transports.Connection("https://example.com") | ||
| conn.open(backend=backend) | ||
| try: | ||
| assert backend.connect_tls_args == ("example.com", 443) | ||
| finally: | ||
| conn.close() | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These lines works ok well when no stream is supplied, but otherwise they create a second connection and overwrite
self._stream, leaving the supplied stream open.