Skip to content

Commit bbd28b7

Browse files
authored
Reducing HTTP Connection timeouts
1 parent 65cd1af commit bbd28b7

File tree

1 file changed

+33
-21
lines changed

1 file changed

+33
-21
lines changed

src/downloader/http_gateway.py

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
# You can download the latest version of this tool from:
1717
# https://github.com/MiSTer-devel/Downloader_MiSTer
1818

19+
import socket
1920
import ssl
2021
import sys
2122
import threading
@@ -183,7 +184,8 @@ def _take_connection(self, queue_id: '_QueueId') -> '_Connection':
183184
with self._connections_lock:
184185
if queue_id not in self._connections:
185186
self._connections[queue_id] = _ConnectionQueue(queue_id, self._timeout, self._ssl_ctx, self._logger, self._config)
186-
return self._connections[queue_id].pull()
187+
queue = self._connections[queue_id]
188+
return queue.pull()
187189

188190
def _clean_timeout_connections(self, now: float) -> None:
189191
if now - self._clean_timeout_connections_timer < 30.0:
@@ -416,21 +418,31 @@ def __init__(self, queue_id: _QueueId, timeout: float, ctx: ssl.SSLContext, logg
416418
self._queue_swap: List[_Connection] = []
417419
self._lock = threading.Lock()
418420
self._last_conn_id = -1
421+
self._queue_cleared = False
419422

420423
def pull(self) -> _Connection:
421424
with self._lock:
422-
if len(self._queue) == 0:
425+
if len(self._queue) > 0:
426+
return self._queue.pop()
427+
else:
423428
self._last_conn_id += 1
424-
http_conn = create_http_connection(self.id[0], self.id[1], self._timeout, self._ctx, self._config)
425-
return _Connection(conn_id=self._last_conn_id, http=http_conn, connection_queue=self, logger=self._logger)
426-
return self._queue.pop()
429+
conn_id = self._last_conn_id
430+
431+
http_conn = create_http_connection(self.id[0], self.id[1], self._timeout, self._ctx, self._config)
432+
with self._lock:
433+
if self._queue_cleared:
434+
http_conn.close()
435+
raise HttpGatewayException('Connection queue is already cleared.')
436+
437+
return _Connection(conn_id=conn_id, http=http_conn, connection_queue=self, logger=self._logger)
427438

428439
def push(self, connection: _Connection) -> None:
429440
with self._lock:
430441
self._queue.append(connection)
431442

432443
def clear_all(self) -> int:
433444
with self._lock:
445+
self._queue_cleared = True
434446
size = len(self._queue)
435447
for connection in self._queue:
436448
connection.kill()
@@ -454,36 +466,36 @@ def clear_timed_outs(self, now: float) -> int:
454466

455467
return expired_count
456468

457-
458469
def create_http_connection(scheme: str, netloc: str, timeout: float, ctx: ssl.SSLContext, config: Optional[dict[str, Any]]) -> HTTPConnection:
459470
if scheme == 'http':
460471
if config and config['http_proxy']:
461472
proxy = config['http_proxy']
462473
proxy_host = proxy.hostname
463474
proxy_port = proxy.port or (443 if proxy.scheme == 'https' else 80)
464475
if proxy.scheme == 'https':
465-
return HTTPSConnection(proxy_host, proxy_port, timeout=timeout, context=ctx)
466-
return HTTPConnection(proxy_host, proxy_port, timeout=timeout)
467-
return HTTPConnection(netloc, timeout=timeout)
476+
return _add_socket(HTTPSConnection(proxy_host, proxy_port, timeout=timeout, context=ctx), proxy_host, proxy_port, timeout, ssl_ctx=ctx)
477+
return _add_socket(HTTPConnection(proxy_host, proxy_port, timeout=timeout), proxy_host, proxy_port, timeout)
478+
return _add_socket(HTTPConnection(netloc, timeout=timeout), netloc, 80, timeout)
468479

469480
elif scheme == 'https':
470481
if config and config['https_proxy']:
471482
proxy = config['https_proxy']
472483
proxy_host = proxy.hostname
473484
proxy_port = proxy.port or (443 if proxy.scheme == 'https' else 80)
474-
parsed_netloc = urlparse(f'//{netloc}')
475-
target_host = parsed_netloc.hostname
476-
target_port = parsed_netloc.port or 443
477-
if not target_host:
478-
raise HttpGatewayException(f"Invalid netloc: {netloc}")
479-
480485
conn = HTTPSConnection(proxy_host, proxy_port, timeout=timeout, context=ctx)
481-
conn.set_tunnel(target_host, target_port, headers=config.get('https_proxy_headers'))
482-
return conn
483-
return HTTPSConnection(netloc, timeout=timeout, context=ctx)
484-
485-
else:
486-
raise HttpGatewayException(f"Scheme {scheme} not supported")
486+
conn.set_tunnel(netloc, 443, headers=config.get('https_proxy_headers'))
487+
return _add_socket(conn, proxy_host, proxy_port, timeout, ssl_ctx=(ctx if proxy.scheme == 'https' else None))
488+
return _add_socket(HTTPSConnection(netloc, timeout=timeout, context=ctx), netloc, 443, timeout, ssl_ctx=ctx)
489+
490+
raise HttpGatewayException(f"Scheme {scheme} not supported")
491+
492+
def _add_socket(conn: HTTPConnection, host: str, port: int, timeout: float, ssl_ctx: Optional[ssl.SSLContext] = None) -> HTTPConnection:
493+
sock = socket.create_connection((host, port), timeout=15)
494+
sock.settimeout(timeout)
495+
if ssl_ctx:
496+
sock = ssl_ctx.wrap_socket(sock, server_hostname=host)
497+
conn.sock = sock
498+
return conn
487499

488500

489501
class _ResponseHeaders:

0 commit comments

Comments
 (0)