boring-http 2.2.1__tar.gz → 2.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {boring_http-2.2.1 → boring_http-2.3.0}/PKG-INFO +4 -4
- {boring_http-2.2.1 → boring_http-2.3.0}/README.md +1 -1
- {boring_http-2.2.1 → boring_http-2.3.0}/pyproject.toml +3 -3
- {boring_http-2.2.1 → boring_http-2.3.0}/pyproject.toml.orig +3 -3
- {boring_http-2.2.1 → boring_http-2.3.0}/src/boring_http/client.py +16 -4
- {boring_http-2.2.1 → boring_http-2.3.0}/src/boring_http/__init__.py +0 -0
- {boring_http-2.2.1 → boring_http-2.3.0}/src/boring_http/codings.py +0 -0
- {boring_http-2.2.1 → boring_http-2.3.0}/src/boring_http/cookies.py +0 -0
- {boring_http-2.2.1 → boring_http-2.3.0}/src/boring_http/errors.py +0 -0
- {boring_http-2.2.1 → boring_http-2.3.0}/src/boring_http/hpack.py +0 -0
- {boring_http-2.2.1 → boring_http-2.3.0}/src/boring_http/hpack_tables.py +0 -0
- {boring_http-2.2.1 → boring_http-2.3.0}/src/boring_http/http1.py +0 -0
- {boring_http-2.2.1 → boring_http-2.3.0}/src/boring_http/http2.py +0 -0
- {boring_http-2.2.1 → boring_http-2.3.0}/src/boring_http/http3.py +0 -0
- {boring_http-2.2.1 → boring_http-2.3.0}/src/boring_http/message.py +0 -0
- {boring_http-2.2.1 → boring_http-2.3.0}/src/boring_http/pool.py +0 -0
- {boring_http-2.2.1 → boring_http-2.3.0}/src/boring_http/public_suffixes.py +0 -0
- {boring_http-2.2.1 → boring_http-2.3.0}/src/boring_http/py.typed +0 -0
- {boring_http-2.2.1 → boring_http-2.3.0}/src/boring_http/qpack.py +0 -0
- {boring_http-2.2.1 → boring_http-2.3.0}/src/boring_http/qpack_tables.py +0 -0
- {boring_http-2.2.1 → boring_http-2.3.0}/src/boring_http/quic/__init__.py +0 -0
- {boring_http-2.2.1 → boring_http-2.3.0}/src/boring_http/quic/connection.py +0 -0
- {boring_http-2.2.1 → boring_http-2.3.0}/src/boring_http/quic/packet.py +0 -0
- {boring_http-2.2.1 → boring_http-2.3.0}/src/boring_http/quic/protocol.py +0 -0
- {boring_http-2.2.1 → boring_http-2.3.0}/src/boring_http/quic/recovery.py +0 -0
- {boring_http-2.2.1 → boring_http-2.3.0}/src/boring_http/quic/streams.py +0 -0
- {boring_http-2.2.1 → boring_http-2.3.0}/src/boring_http/revocation.py +0 -0
- {boring_http-2.2.1 → boring_http-2.3.0}/src/boring_http/timing.py +0 -0
- {boring_http-2.2.1 → boring_http-2.3.0}/src/boring_http/websocket.py +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: boring-http
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.0
|
|
4
4
|
Summary: Asyncio HTTP client on BoringSSL: HTTP/1.1, HTTP/2 and HTTP/3 over QUIC v1 and v2, WebSocket on all three, HTTP and SOCKS proxies, headers in your order
|
|
5
|
-
Requires-Dist: boring-ssl2>=1.
|
|
6
|
-
Requires-Dist: ssl2>=2.0
|
|
5
|
+
Requires-Dist: boring-ssl2>=1.3.0
|
|
6
|
+
Requires-Dist: ssl2>=2.1.0
|
|
7
7
|
Requires-Python: >=3.14
|
|
8
8
|
Project-URL: Repository, https://github.com/baobien-dev/boring-http
|
|
9
9
|
Description-Content-Type: text/markdown
|
|
@@ -42,7 +42,7 @@ async def main() -> None:
|
|
|
42
42
|
asyncio.run(main())
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
Certificates are checked against the system trust store, or against `trust_store=TrustStore.from_file(...)` from `ssl2`; `verify=False` turns the check off for a test server. Revocation is checked against the CRL the certificate names: fetched over HTTP, verified with the issuer from the chain, cached until its next update, and a listed certificate is refused with `RevocationError`. `revocation=Revocation.STRICT` also refuses when no valid CRL can be had, `Revocation.NONE` skips the check, and the default `Revocation.SOFT` lets such a connection through, as browsers do. The check covers the origin's certificate and an HTTPS proxy's own certificate on a plain-HTTP request through it; the proxy's certificate on a TLS tunnel is verified but not checked for revocation. `certificate_chain=SigningChain(...)` from `ssl2` presents a client certificate over TCP and QUIC. `check_peer=` is awaited with the peer's chain in DER, leaf first, and its authority after the same checks; raising from it refuses the connection, which is where a key pin goes. Connections are pooled per origin and proxy under `max_connections` and `max_connections_per_host`; one that has served nothing for `max_idle_time` seconds, 90 by default, is closed instead of reused, and `None` keeps it until the server closes it. Headers go on the wire in the order given, client headers first and then the request's own. `Host` leads an HTTP/1.1 request; HTTP/2 and HTTP/3 lowercase the names and drop the connection-specific ones, nothing else changes. `params`, `json`, `data`, `content`, `files`, `auth` and `cookies` are accepted by `get`, `post`, `put`, `patch`, `delete`, `head`, `options` and `request`.
|
|
45
|
+
Certificates are checked against the system trust store, or against `trust_store=TrustStore.from_file(...)` from `ssl2`; `verify=False` turns the check off for a test server. Revocation is checked against the CRL the certificate names: fetched over HTTP, verified with the issuer from the chain, cached until its next update, and a listed certificate is refused with `RevocationError`. `revocation=Revocation.STRICT` also refuses when no valid CRL can be had, `Revocation.NONE` skips the check, and the default `Revocation.SOFT` lets such a connection through, as browsers do. The check covers the origin's certificate and an HTTPS proxy's own certificate on a plain-HTTP request through it; the proxy's certificate on a TLS tunnel is verified but not checked for revocation. `certificate_chain=SigningChain(...)` from `ssl2` presents a client certificate over TCP and QUIC. `check_peer=` is awaited with the peer's chain in DER, leaf first, and its authority after the same checks; raising from it refuses the connection, which is where a key pin goes. `key_log="keys.txt"` appends the secrets of every TLS and QUIC handshake in the NSS key log format, for Wireshark. `resolve={("example.com", 443): ("203.0.113.7", 443)}` sends a connection without a proxy to that address instead of resolving the name, while SNI and certificate verification keep the name from the URL. Connections are pooled per origin and proxy under `max_connections` and `max_connections_per_host`; one that has served nothing for `max_idle_time` seconds, 90 by default, is closed instead of reused, and `None` keeps it until the server closes it. Headers go on the wire in the order given, client headers first and then the request's own. `Host` leads an HTTP/1.1 request; HTTP/2 and HTTP/3 lowercase the names and drop the connection-specific ones, nothing else changes. `params`, `json`, `data`, `content`, `files`, `auth` and `cookies` are accepted by `get`, `post`, `put`, `patch`, `delete`, `head`, `options` and `request`.
|
|
46
46
|
|
|
47
47
|
## Responses
|
|
48
48
|
|
|
@@ -32,7 +32,7 @@ async def main() -> None:
|
|
|
32
32
|
asyncio.run(main())
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
Certificates are checked against the system trust store, or against `trust_store=TrustStore.from_file(...)` from `ssl2`; `verify=False` turns the check off for a test server. Revocation is checked against the CRL the certificate names: fetched over HTTP, verified with the issuer from the chain, cached until its next update, and a listed certificate is refused with `RevocationError`. `revocation=Revocation.STRICT` also refuses when no valid CRL can be had, `Revocation.NONE` skips the check, and the default `Revocation.SOFT` lets such a connection through, as browsers do. The check covers the origin's certificate and an HTTPS proxy's own certificate on a plain-HTTP request through it; the proxy's certificate on a TLS tunnel is verified but not checked for revocation. `certificate_chain=SigningChain(...)` from `ssl2` presents a client certificate over TCP and QUIC. `check_peer=` is awaited with the peer's chain in DER, leaf first, and its authority after the same checks; raising from it refuses the connection, which is where a key pin goes. Connections are pooled per origin and proxy under `max_connections` and `max_connections_per_host`; one that has served nothing for `max_idle_time` seconds, 90 by default, is closed instead of reused, and `None` keeps it until the server closes it. Headers go on the wire in the order given, client headers first and then the request's own. `Host` leads an HTTP/1.1 request; HTTP/2 and HTTP/3 lowercase the names and drop the connection-specific ones, nothing else changes. `params`, `json`, `data`, `content`, `files`, `auth` and `cookies` are accepted by `get`, `post`, `put`, `patch`, `delete`, `head`, `options` and `request`.
|
|
35
|
+
Certificates are checked against the system trust store, or against `trust_store=TrustStore.from_file(...)` from `ssl2`; `verify=False` turns the check off for a test server. Revocation is checked against the CRL the certificate names: fetched over HTTP, verified with the issuer from the chain, cached until its next update, and a listed certificate is refused with `RevocationError`. `revocation=Revocation.STRICT` also refuses when no valid CRL can be had, `Revocation.NONE` skips the check, and the default `Revocation.SOFT` lets such a connection through, as browsers do. The check covers the origin's certificate and an HTTPS proxy's own certificate on a plain-HTTP request through it; the proxy's certificate on a TLS tunnel is verified but not checked for revocation. `certificate_chain=SigningChain(...)` from `ssl2` presents a client certificate over TCP and QUIC. `check_peer=` is awaited with the peer's chain in DER, leaf first, and its authority after the same checks; raising from it refuses the connection, which is where a key pin goes. `key_log="keys.txt"` appends the secrets of every TLS and QUIC handshake in the NSS key log format, for Wireshark. `resolve={("example.com", 443): ("203.0.113.7", 443)}` sends a connection without a proxy to that address instead of resolving the name, while SNI and certificate verification keep the name from the URL. Connections are pooled per origin and proxy under `max_connections` and `max_connections_per_host`; one that has served nothing for `max_idle_time` seconds, 90 by default, is closed instead of reused, and `None` keeps it until the server closes it. Headers go on the wire in the order given, client headers first and then the request's own. `Host` leads an HTTP/1.1 request; HTTP/2 and HTTP/3 lowercase the names and drop the connection-specific ones, nothing else changes. `params`, `json`, `data`, `content`, `files`, `auth` and `cookies` are accepted by `get`, `post`, `put`, `patch`, `delete`, `head`, `options` and `request`.
|
|
36
36
|
|
|
37
37
|
## Responses
|
|
38
38
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "boring-http"
|
|
3
|
-
version = "2.
|
|
3
|
+
version = "2.3.0"
|
|
4
4
|
description = "Asyncio HTTP client on BoringSSL: HTTP/1.1, HTTP/2 and HTTP/3 over QUIC v1 and v2, WebSocket on all three, HTTP and SOCKS proxies, headers in your order"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.14"
|
|
7
7
|
dependencies = [
|
|
8
|
-
"boring-ssl2>=1.
|
|
9
|
-
"ssl2>=2.0
|
|
8
|
+
"boring-ssl2>=1.3.0",
|
|
9
|
+
"ssl2>=2.1.0",
|
|
10
10
|
]
|
|
11
11
|
|
|
12
12
|
[project.urls]
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "boring-http"
|
|
3
|
-
version = "2.
|
|
3
|
+
version = "2.3.0"
|
|
4
4
|
description = "Asyncio HTTP client on BoringSSL: HTTP/1.1, HTTP/2 and HTTP/3 over QUIC v1 and v2, WebSocket on all three, HTTP and SOCKS proxies, headers in your order"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.14"
|
|
7
7
|
dependencies = [
|
|
8
|
-
"boring-ssl2>=1.
|
|
9
|
-
"ssl2>=2.0
|
|
8
|
+
"boring-ssl2>=1.3.0",
|
|
9
|
+
"ssl2>=2.1.0",
|
|
10
10
|
]
|
|
11
11
|
|
|
12
12
|
[project.urls]
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import base64
|
|
2
|
+
import os
|
|
2
3
|
from collections.abc import (
|
|
3
4
|
AsyncGenerator,
|
|
4
5
|
AsyncIterable,
|
|
@@ -117,6 +118,8 @@ class Client:
|
|
|
117
118
|
revocation: Revocation = Revocation.SOFT,
|
|
118
119
|
certificate_chain: SigningChain | None = None,
|
|
119
120
|
check_peer: Callable[[tuple[bytes, ...], str], Awaitable[None]] | None = None,
|
|
121
|
+
key_log: str | os.PathLike[str] | None = None,
|
|
122
|
+
resolve: Mapping[tuple[str, int], tuple[str, int]] | None = None,
|
|
120
123
|
cookies: CookieJar | None = None,
|
|
121
124
|
base_url: str | None = None,
|
|
122
125
|
max_connections: int = 100,
|
|
@@ -151,6 +154,8 @@ class Client:
|
|
|
151
154
|
self._revocations = Revocations(revocation, self._fetch_crl)
|
|
152
155
|
self._certificate_chain = certificate_chain
|
|
153
156
|
self._check_peer = check_peer
|
|
157
|
+
self._key_log = key_log
|
|
158
|
+
self._resolve = {} if resolve is None else dict(resolve)
|
|
154
159
|
self._base_url = base_url
|
|
155
160
|
self._max_redirects = max_redirects
|
|
156
161
|
self._max_message_size = max_message_size
|
|
@@ -475,7 +480,7 @@ class Client:
|
|
|
475
480
|
else None
|
|
476
481
|
)
|
|
477
482
|
self._contexts[protocols] = ClientContext(
|
|
478
|
-
configuration, session_cache=cache
|
|
483
|
+
configuration, session_cache=cache, key_log=self._key_log
|
|
479
484
|
)
|
|
480
485
|
return self._contexts[protocols]
|
|
481
486
|
|
|
@@ -528,13 +533,19 @@ class Client:
|
|
|
528
533
|
*,
|
|
529
534
|
http1_only: bool = False,
|
|
530
535
|
) -> Connection:
|
|
536
|
+
# a resolve= entry sends a direct connection elsewhere, while the URL's host stays the name sent and verified
|
|
537
|
+
address = (
|
|
538
|
+
self._resolve.get(url.address, url.address)
|
|
539
|
+
if proxy is None
|
|
540
|
+
else url.address
|
|
541
|
+
)
|
|
531
542
|
try:
|
|
532
543
|
if quic and self._http3 is not None:
|
|
533
544
|
memory = self._memory.setdefault(url.address, OriginMemory())
|
|
534
545
|
client = await QuicClient.connect(
|
|
535
546
|
self._context((NextProtocol.H3,)),
|
|
536
547
|
url.host,
|
|
537
|
-
|
|
548
|
+
address,
|
|
538
549
|
self._http3.transport,
|
|
539
550
|
version=self._http3.quic_version,
|
|
540
551
|
proxy=proxy,
|
|
@@ -551,11 +562,12 @@ class Client:
|
|
|
551
562
|
if url.secure:
|
|
552
563
|
stream = await TLSStream.connect(
|
|
553
564
|
self._context((NextProtocol.HTTP1,) if http1_only else None),
|
|
554
|
-
|
|
565
|
+
address,
|
|
555
566
|
proxy=proxy,
|
|
556
567
|
proxy_context=self._context((NextProtocol.HTTP1,))
|
|
557
568
|
if proxy is not None and proxy.scheme is ProxyScheme.HTTPS
|
|
558
569
|
else None,
|
|
570
|
+
server_hostname=url.host,
|
|
559
571
|
)
|
|
560
572
|
await self._checked(stream, url.authority)
|
|
561
573
|
if (
|
|
@@ -587,7 +599,7 @@ class Client:
|
|
|
587
599
|
return Http1Connection(
|
|
588
600
|
transport, absolute_form=True, proxy_authorization=authorization
|
|
589
601
|
)
|
|
590
|
-
tunnel = await TLSStream.tunnel(self._context(),
|
|
602
|
+
tunnel = await TLSStream.tunnel(self._context(), address, proxy)
|
|
591
603
|
return Http1Connection(tunnel.transport, leftover=tunnel.leftover)
|
|
592
604
|
except ProxyError, ConfigurationError, RevocationError:
|
|
593
605
|
raise
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|