Skip to content

Commit

Permalink
Port becomes optional (#92)
Browse files Browse the repository at this point in the history
* Port becomes optional

* Update docstring

Co-authored-by: Florimond Manca <[email protected]>
  • Loading branch information
tomchristie and florimondmanca authored May 21, 2020
1 parent 7cfb2d5 commit 875daba
Show file tree
Hide file tree
Showing 12 changed files with 61 additions and 31 deletions.
2 changes: 1 addition & 1 deletion httpcore/_async/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ async def request(
**Parameters:**
* **method** - `bytes` - The HTTP method, such as `b'GET'`.
* **url** - `Tuple[bytes, bytes, int, bytes]` - The URL as a 4-tuple of
* **url** - `Tuple[bytes, bytes, Optional[int], bytes]` - The URL as a 4-tuple of
(scheme, host, port, path).
* **headers** - `Optional[List[Tuple[bytes, bytes]]]` - Any HTTP headers
to send with the request.
Expand Down
4 changes: 2 additions & 2 deletions httpcore/_async/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from .._backends.auto import AsyncLock, AsyncSocketStream, AutoBackend
from .._types import URL, Headers, Origin, TimeoutDict
from .._utils import get_logger
from .._utils import get_logger, url_to_origin
from .base import (
AsyncByteStream,
AsyncHTTPTransport,
Expand Down Expand Up @@ -55,7 +55,7 @@ async def request(
stream: AsyncByteStream = None,
timeout: TimeoutDict = None,
) -> Tuple[bytes, int, bytes, List[Tuple[bytes, bytes]], AsyncByteStream]:
assert url[:3] == self.origin
assert url_to_origin(url) == self.origin
async with self.request_lock:
if self.state == ConnectionState.PENDING:
if not self.socket:
Expand Down
6 changes: 3 additions & 3 deletions httpcore/_async/connection_pool.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from .._exceptions import PoolTimeout
from .._threadlock import ThreadLock
from .._types import URL, Headers, Origin, TimeoutDict
from .._utils import get_logger
from .._utils import get_logger, url_to_origin
from .base import (
AsyncByteStream,
AsyncHTTPTransport,
Expand Down Expand Up @@ -124,8 +124,8 @@ async def request(
stream: AsyncByteStream = None,
timeout: TimeoutDict = None,
) -> Tuple[bytes, int, bytes, Headers, AsyncByteStream]:
timeout = {} if timeout is None else timeout
origin = url[:3]
assert url[0] in (b'http', b'https')
origin = url_to_origin(url)

if self._keepalive_expiry is not None:
await self._keepalive_sweep()
Expand Down
5 changes: 4 additions & 1 deletion httpcore/_async/http2.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,10 @@ async def send_headers(
) -> None:
scheme, hostname, port, path = url
default_port = {b"http": 80, b"https": 443}.get(scheme)
authority = b"%s:%d" % (hostname, port) if port != default_port else hostname
if port is None or port == default_port:
authority = hostname
else:
authority = b"%s:%d" % (hostname, port)

headers = [
(b":method", method),
Expand Down
24 changes: 16 additions & 8 deletions httpcore/_async/http_proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from .._exceptions import ProxyError
from .._types import URL, Headers, Origin, TimeoutDict
from .._utils import get_logger
from .._utils import get_logger, url_to_origin
from .base import AsyncByteStream
from .connection import AsyncHTTPConnection
from .connection_pool import AsyncConnectionPool, ResponseByteStream
Expand Down Expand Up @@ -34,8 +34,8 @@ class AsyncHTTPProxy(AsyncConnectionPool):
**Parameters:**
* **proxy_origin** - `Tuple[bytes, bytes, int]` - The address of the proxy
service as a 3-tuple of (scheme, host, port).
* **proxy_url** - `Tuple[bytes, bytes, Optional[int], bytes]` - The URL of
the proxy service as a 4-tuple of (scheme, host, port, path).
* **proxy_headers** - `Optional[List[Tuple[bytes, bytes]]]` - A list of
proxy headers to include.
* **proxy_mode** - `str` - A proxy mode to operate in. May be "DEFAULT",
Expand All @@ -51,7 +51,7 @@ class AsyncHTTPProxy(AsyncConnectionPool):

def __init__(
self,
proxy_origin: Origin,
proxy_url: URL,
proxy_headers: Headers = None,
proxy_mode: str = "DEFAULT",
ssl_context: SSLContext = None,
Expand All @@ -62,7 +62,7 @@ def __init__(
):
assert proxy_mode in ("DEFAULT", "FORWARD_ONLY", "TUNNEL_ONLY")

self.proxy_origin = proxy_origin
self.proxy_origin = url_to_origin(proxy_url)
self.proxy_headers = [] if proxy_headers is None else proxy_headers
self.proxy_mode = proxy_mode
super().__init__(
Expand Down Expand Up @@ -137,7 +137,12 @@ async def _forward_request(
# GET https://www.example.org/path HTTP/1.1
# [proxy headers]
# [headers]
target = b"%b://%b:%d%b" % url
scheme, host, port, path = url
if port is None:
target = b"%b://%b%b" % (scheme, host, path)
else:
target = b"%b://%b:%d%b" % (scheme, host, port, path)

url = self.proxy_origin + (target,)
headers = merge_headers(self.proxy_headers, headers)

Expand All @@ -161,7 +166,7 @@ async def _tunnel_request(
Tunnelled proxy requests require an initial CONNECT request to
establish the connection, and then send regular requests.
"""
origin = url[:3]
origin = url_to_origin(url)
connection = await self._get_connection_from_pool(origin)

if connection is None:
Expand All @@ -176,7 +181,10 @@ async def _tunnel_request(

# CONNECT www.example.org:80 HTTP/1.1
# [proxy-headers]
target = b"%b:%d" % (url[1], url[2])
if url[2] is None:
target = url[1]
else:
target = b"%b:%d" % (url[1], url[2])
connect_url = self.proxy_origin + (target,)
connect_headers = [(b"Host", target), (b"Accept", b"*/*")]
connect_headers = merge_headers(connect_headers, self.proxy_headers)
Expand Down
2 changes: 1 addition & 1 deletion httpcore/_sync/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def request(
**Parameters:**
* **method** - `bytes` - The HTTP method, such as `b'GET'`.
* **url** - `Tuple[bytes, bytes, int, bytes]` - The URL as a 4-tuple of
* **url** - `Tuple[bytes, bytes, Optional[int], bytes]` - The URL as a 4-tuple of
(scheme, host, port, path).
* **headers** - `Optional[List[Tuple[bytes, bytes]]]` - Any HTTP headers
to send with the request.
Expand Down
4 changes: 2 additions & 2 deletions httpcore/_sync/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from .._backends.auto import SyncLock, SyncSocketStream, SyncBackend
from .._types import URL, Headers, Origin, TimeoutDict
from .._utils import get_logger
from .._utils import get_logger, url_to_origin
from .base import (
SyncByteStream,
SyncHTTPTransport,
Expand Down Expand Up @@ -55,7 +55,7 @@ def request(
stream: SyncByteStream = None,
timeout: TimeoutDict = None,
) -> Tuple[bytes, int, bytes, List[Tuple[bytes, bytes]], SyncByteStream]:
assert url[:3] == self.origin
assert url_to_origin(url) == self.origin
with self.request_lock:
if self.state == ConnectionState.PENDING:
if not self.socket:
Expand Down
6 changes: 3 additions & 3 deletions httpcore/_sync/connection_pool.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from .._exceptions import PoolTimeout
from .._threadlock import ThreadLock
from .._types import URL, Headers, Origin, TimeoutDict
from .._utils import get_logger
from .._utils import get_logger, url_to_origin
from .base import (
SyncByteStream,
SyncHTTPTransport,
Expand Down Expand Up @@ -124,8 +124,8 @@ def request(
stream: SyncByteStream = None,
timeout: TimeoutDict = None,
) -> Tuple[bytes, int, bytes, Headers, SyncByteStream]:
timeout = {} if timeout is None else timeout
origin = url[:3]
assert url[0] in (b'http', b'https')
origin = url_to_origin(url)

if self._keepalive_expiry is not None:
self._keepalive_sweep()
Expand Down
5 changes: 4 additions & 1 deletion httpcore/_sync/http2.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,10 @@ def send_headers(
) -> None:
scheme, hostname, port, path = url
default_port = {b"http": 80, b"https": 443}.get(scheme)
authority = b"%s:%d" % (hostname, port) if port != default_port else hostname
if port is None or port == default_port:
authority = hostname
else:
authority = b"%s:%d" % (hostname, port)

headers = [
(b":method", method),
Expand Down
24 changes: 16 additions & 8 deletions httpcore/_sync/http_proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from .._exceptions import ProxyError
from .._types import URL, Headers, Origin, TimeoutDict
from .._utils import get_logger
from .._utils import get_logger, url_to_origin
from .base import SyncByteStream
from .connection import SyncHTTPConnection
from .connection_pool import SyncConnectionPool, ResponseByteStream
Expand Down Expand Up @@ -34,8 +34,8 @@ class SyncHTTPProxy(SyncConnectionPool):
**Parameters:**
* **proxy_origin** - `Tuple[bytes, bytes, int]` - The address of the proxy
service as a 3-tuple of (scheme, host, port).
* **proxy_url** - `Tuple[bytes, bytes, Optional[int], bytes]` - The URL of
the proxy service as a 4-tuple of (scheme, host, port, path).
* **proxy_headers** - `Optional[List[Tuple[bytes, bytes]]]` - A list of
proxy headers to include.
* **proxy_mode** - `str` - A proxy mode to operate in. May be "DEFAULT",
Expand All @@ -51,7 +51,7 @@ class SyncHTTPProxy(SyncConnectionPool):

def __init__(
self,
proxy_origin: Origin,
proxy_url: URL,
proxy_headers: Headers = None,
proxy_mode: str = "DEFAULT",
ssl_context: SSLContext = None,
Expand All @@ -62,7 +62,7 @@ def __init__(
):
assert proxy_mode in ("DEFAULT", "FORWARD_ONLY", "TUNNEL_ONLY")

self.proxy_origin = proxy_origin
self.proxy_origin = url_to_origin(proxy_url)
self.proxy_headers = [] if proxy_headers is None else proxy_headers
self.proxy_mode = proxy_mode
super().__init__(
Expand Down Expand Up @@ -137,7 +137,12 @@ def _forward_request(
# GET https://www.example.org/path HTTP/1.1
# [proxy headers]
# [headers]
target = b"%b://%b:%d%b" % url
scheme, host, port, path = url
if port is None:
target = b"%b://%b%b" % (scheme, host, path)
else:
target = b"%b://%b:%d%b" % (scheme, host, port, path)

url = self.proxy_origin + (target,)
headers = merge_headers(self.proxy_headers, headers)

Expand All @@ -161,7 +166,7 @@ def _tunnel_request(
Tunnelled proxy requests require an initial CONNECT request to
establish the connection, and then send regular requests.
"""
origin = url[:3]
origin = url_to_origin(url)
connection = self._get_connection_from_pool(origin)

if connection is None:
Expand All @@ -176,7 +181,10 @@ def _tunnel_request(

# CONNECT www.example.org:80 HTTP/1.1
# [proxy-headers]
target = b"%b:%d" % (url[1], url[2])
if url[2] is None:
target = url[1]
else:
target = b"%b:%d" % (url[1], url[2])
connect_url = self.proxy_origin + (target,)
connect_headers = [(b"Host", target), (b"Accept", b"*/*")]
connect_headers = merge_headers(connect_headers, self.proxy_headers)
Expand Down
2 changes: 1 addition & 1 deletion httpcore/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@

StrOrBytes = Union[str, bytes]
Origin = Tuple[bytes, bytes, int]
URL = Tuple[bytes, bytes, int, bytes]
URL = Tuple[bytes, bytes, Optional[int], bytes]
Headers = List[Tuple[bytes, bytes]]
TimeoutDict = Dict[str, Optional[float]]
8 changes: 8 additions & 0 deletions httpcore/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import os
import sys
import typing
from ._types import URL, Origin

_LOGGER_INITIALIZED = False
TRACE_LOG_LEVEL = 5
Expand Down Expand Up @@ -47,3 +48,10 @@ def trace(message: str, *args: typing.Any, **kwargs: typing.Any) -> None:
logger.trace = trace # type: ignore

return typing.cast(Logger, logger)


def url_to_origin(url: URL) -> Origin:
scheme, host, explicit_port = url[:3]
default_port = {b'http': 80, b'https': 443}[scheme]
port = default_port if explicit_port is None else explicit_port
return scheme, host, port

0 comments on commit 875daba

Please sign in to comment.