wsbuilder 1.2.5__tar.gz → 1.2.7__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.
- {wsbuilder-1.2.5/src/wsbuilder.egg-info → wsbuilder-1.2.7}/PKG-INFO +1 -1
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/pyproject.toml +1 -1
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/__init__.py +1 -1
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/proxyi.py +3 -1
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/server.py +6 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7/src/wsbuilder.egg-info}/PKG-INFO +1 -1
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_proxyi.py +16 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_server.py +37 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/LICENSE +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/MANIFEST.in +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/README.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/404.html +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/CNAME +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/advanced.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/ai-predict.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/api-map.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/app-http.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/architecture.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/assets/wsbuilder-mark.svg +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/beginners.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/cache-security.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/cache.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/capabilities.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/data-orm.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/dns.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/full-project.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/getting-started.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/help/index.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/http-versions.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/http.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/ia.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/index.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/install.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/intermediate.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/mdns.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/network-edge.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/observability-tasks.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/observability.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/persistence.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/proxy.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/reference/index.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/security.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/stylesheets/extra.css +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/tasks.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/tls-certificates.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/docs/websocket.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/examples/full-project/.gitignore +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/examples/full-project/README.md +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/examples/full-project/app.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/examples/full-project/pyproject.toml +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/examples/full-project/upstream.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/mkdocs.yml +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/setup.cfg +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/__main__.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/_coerce.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/app.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/cache.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/caches.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/constants.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/cookies.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/db_replicas.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/dns.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/framework.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/headers.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/hpack.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/http.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/http1.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/http2.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/http3.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/http3_server.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/http3_websocket.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/ia.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/logs.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/mdns.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/metrics.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/orm.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/pki.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/predicts.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/qpack.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/quic/__init__.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/quic/address.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/quic/connection.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/quic/crypto.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/quic/frames.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/quic/packet.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/quic/recovery.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/quic/tls.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/quic/varint.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/security.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/tasks.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder/ws.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder.egg-info/SOURCES.txt +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder.egg-info/dependency_links.txt +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder.egg-info/entry_points.txt +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder.egg-info/requires.txt +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/src/wsbuilder.egg-info/top_level.txt +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_app_threads.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_cache.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_caches.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_contributing_policy.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_demo_monitor.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_dns.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_docs.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_documentation_files.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_headers_cookies.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_hpack.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_http.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_http1.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_http2.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_http3.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_http3_server.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_http3_streaming.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_http3_streaming_udp.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_ia.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_logs.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_mdns.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_metrics.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_orm.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_orm_replicas.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_pki.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_pr_identity_policy.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_predicts.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_proxyi_routing.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_quic_address.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_quic_crypto.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_quic_protocol.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_quic_recovery.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_quic_tls.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_security.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_server_errors.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_tasks.py +0 -0
- {wsbuilder-1.2.5 → wsbuilder-1.2.7}/tests/test_ws.py +0 -0
|
@@ -869,7 +869,9 @@ class ProxyRule:
|
|
|
869
869
|
def choose_target(self, request, *, proxy=None):
|
|
870
870
|
targets = self.enabled_targets()
|
|
871
871
|
if not targets:
|
|
872
|
-
|
|
872
|
+
# Every upstream of this rule is disabled: the proxy's default
|
|
873
|
+
# rule, when there is one, still answers the request.
|
|
874
|
+
return proxy._fallback_target(request) if proxy is not None else None
|
|
873
875
|
mode = normalize_balance_mode(self.balance or BALANCING_ROUND_ROBIN)
|
|
874
876
|
if mode == BALANCING_ROUND_ROBIN:
|
|
875
877
|
target = self._round_robin(targets)
|
|
@@ -276,6 +276,12 @@ class HTTPServer:
|
|
|
276
276
|
except OSError:
|
|
277
277
|
pass
|
|
278
278
|
return
|
|
279
|
+
# Accepted sockets block forever by default; bound the handshake and
|
|
280
|
+
# the HTTP/2 preface sniff the same way as the first request read.
|
|
281
|
+
try:
|
|
282
|
+
conn.settimeout(self.REQUEST_READ_TIMEOUT_SECONDS)
|
|
283
|
+
except OSError:
|
|
284
|
+
pass
|
|
279
285
|
tls_meta = {
|
|
280
286
|
"enabled": context is not None,
|
|
281
287
|
"peer_cert": None,
|
|
@@ -204,6 +204,22 @@ class TestProxyI(unittest.TestCase):
|
|
|
204
204
|
self.assertIsNone(rule.choose_target(request))
|
|
205
205
|
self.assertEqual(proxy.dispatch(request).status, 502)
|
|
206
206
|
|
|
207
|
+
def test_a_rule_with_only_disabled_targets_falls_back_to_the_default_rule(self):
|
|
208
|
+
proxy = ProxyI(name="edge")
|
|
209
|
+
proxy.default({"url": f"http://127.0.0.1:{self.backend_port}", "name": "fallback"})
|
|
210
|
+
rule = (
|
|
211
|
+
proxy.route(name="api", path_prefix="/api")
|
|
212
|
+
.upstream("http://127.0.0.1:9001", enabled=False)
|
|
213
|
+
.build()
|
|
214
|
+
)
|
|
215
|
+
request = self._request(path="/api/users")
|
|
216
|
+
|
|
217
|
+
self.assertEqual(rule.choose_target(request, proxy=proxy).name, "fallback")
|
|
218
|
+
self.assertIsNone(rule.choose_target(request))
|
|
219
|
+
response = proxy.dispatch(request)
|
|
220
|
+
self.assertEqual(response.status, 200)
|
|
221
|
+
self.assertEqual(response.headers["X-ProxyI-Target"], "fallback")
|
|
222
|
+
|
|
207
223
|
def test_snapshot_does_not_advance_round_robin(self):
|
|
208
224
|
proxy = ProxyI(name="edge")
|
|
209
225
|
rule = (
|
|
@@ -2,6 +2,7 @@ import io
|
|
|
2
2
|
import os
|
|
3
3
|
import signal
|
|
4
4
|
import socket
|
|
5
|
+
import ssl
|
|
5
6
|
import threading
|
|
6
7
|
import unittest
|
|
7
8
|
from unittest.mock import patch
|
|
@@ -512,6 +513,42 @@ class TestHTTPServerLifecycle(unittest.TestCase):
|
|
|
512
513
|
self.assertFalse(thread.is_alive())
|
|
513
514
|
|
|
514
515
|
|
|
516
|
+
def test_silent_client_is_dropped_after_the_read_timeout(self):
|
|
517
|
+
server = HTTPServer("127.0.0.1", 0, self._ping_app(), request_read_timeout=0.2)
|
|
518
|
+
self._serve(server)
|
|
519
|
+
|
|
520
|
+
for opening in (b"", b"P"):
|
|
521
|
+
with self.subTest(opening=opening):
|
|
522
|
+
with socket.create_connection(server.server_address, timeout=5.0) as sock:
|
|
523
|
+
if opening:
|
|
524
|
+
sock.sendall(opening)
|
|
525
|
+
received = b""
|
|
526
|
+
while True:
|
|
527
|
+
chunk = sock.recv(4096)
|
|
528
|
+
if not chunk:
|
|
529
|
+
break
|
|
530
|
+
received += chunk
|
|
531
|
+
self.assertNotIn(b"200 OK", received)
|
|
532
|
+
|
|
533
|
+
def test_tls_handshake_runs_under_the_read_timeout(self):
|
|
534
|
+
seen = []
|
|
535
|
+
|
|
536
|
+
class RecordingContext:
|
|
537
|
+
def wrap_socket(self, conn, server_side):
|
|
538
|
+
seen.append(conn.gettimeout())
|
|
539
|
+
raise ssl.SSLError("stop after recording")
|
|
540
|
+
|
|
541
|
+
server = HTTPServer(
|
|
542
|
+
"127.0.0.1", 0, self._ping_app(), ssl_context=RecordingContext(), request_read_timeout=0.2
|
|
543
|
+
)
|
|
544
|
+
left, right = socket.socketpair()
|
|
545
|
+
self.addCleanup(right.close)
|
|
546
|
+
left.setblocking(True)
|
|
547
|
+
server.handle_conn(left, ("127.0.0.1", 0))
|
|
548
|
+
|
|
549
|
+
self.assertEqual(seen, [0.2])
|
|
550
|
+
|
|
551
|
+
|
|
515
552
|
class TestHTTPServerLimits(unittest.TestCase):
|
|
516
553
|
def test_constructor_limits_override_only_this_instance(self):
|
|
517
554
|
server = HTTPServer(
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|