55import asyncio
66import logging
77import threading
8+
89import httpcore
910import httpx
1011from httpx_socks import AsyncProxyTransport
2627 uvloop .install ()
2728
2829
29- logger = logger .getChild ('searx.http .client' )
30+ logger = logger .getChild ('searx.network .client' )
3031LOOP = None
3132SSLCONTEXTS = {}
3233TRANSPORT_KWARGS = {
33- 'backend' : 'asyncio' ,
34+ # use anyio :
35+ # * https://github.com/encode/httpcore/issues/344
36+ # * https://github.com/encode/httpx/discussions/1511
37+ 'backend' : 'anyio' ,
3438 'trust_env' : False ,
3539}
3640
3741
3842# pylint: disable=protected-access
3943async def close_connections_for_url (
40- connection_pool : httpcore .AsyncConnectionPool ,
41- url : httpcore . _utils . URL ):
44+ connection_pool : httpcore .AsyncConnectionPool , url : httpcore . _utils . URL
45+ ):
4246
4347 origin = httpcore ._utils .url_to_origin (url )
4448 logger .debug ('Drop connections for %r' , origin )
@@ -47,7 +51,7 @@ async def close_connections_for_url(
4751 await connection_pool ._remove_from_pool (connection )
4852 try :
4953 await connection .aclose ()
50- except httpcore .NetworkError as e :
54+ except httpx .NetworkError as e :
5155 logger .warning ('Error closing an existing connection' , exc_info = e )
5256# pylint: enable=protected-access
5357
@@ -60,80 +64,78 @@ def get_sslcontexts(proxy_url=None, cert=None, verify=True, trust_env=True, http
6064 return SSLCONTEXTS [key ]
6165
6266
63- class AsyncHTTPTransportNoHttp (httpcore .AsyncHTTPTransport ):
67+ class AsyncHTTPTransportNoHttp (httpx .AsyncHTTPTransport ):
6468 """Block HTTP request"""
6569
66- async def arequest (self , method , url , headers = None , stream = None , ext = None ):
67- raise httpcore .UnsupportedProtocol ("HTTP protocol is disabled" )
70+ async def handle_async_request (
71+ self , method , url , headers = None , stream = None , extensions = None
72+ ):
73+ raise httpx .UnsupportedProtocol ('HTTP protocol is disabled' )
6874
6975
7076class AsyncProxyTransportFixed (AsyncProxyTransport ):
7177 """Fix httpx_socks.AsyncProxyTransport
7278
73- Map python_socks exceptions to httpcore.ProxyError
74-
75- Map socket.gaierror to httpcore.ConnectError
79+ Map python_socks exceptions to httpx.ProxyError / httpx.ConnectError
7680
77- Note: keepalive_expiry is ignored, AsyncProxyTransport should call:
78- * self._keepalive_sweep()
79- * self._response_closed(self, connection)
81+ Map socket.gaierror to httpx.ConnectError
8082
8183 Note: AsyncProxyTransport inherit from AsyncConnectionPool
82-
83- Note: the API is going to change on httpx 0.18.0
84- see https://github.com/encode/httpx/pull/1522
8584 """
8685
87- async def arequest (self , method , url , headers = None , stream = None , ext = None ):
86+ async def handle_async_request (
87+ self , method , url , headers = None , stream = None , extensions = None
88+ ):
8889 retry = 2
8990 while retry > 0 :
9091 retry -= 1
9192 try :
92- return await super ().arequest (method , url , headers , stream , ext )
93+ return await super ().handle_async_request (
94+ method , url , headers = headers , stream = stream , extensions = extensions
95+ )
9396 except (ProxyConnectionError , ProxyTimeoutError , ProxyError ) as e :
94- raise httpcore .ProxyError ( e )
97+ raise httpx .ProxyError from e
9598 except OSError as e :
9699 # socket.gaierror when DNS resolution fails
97- raise httpcore .NetworkError (e )
98- except httpcore .RemoteProtocolError as e :
99- # in case of httpcore.RemoteProtocolError: Server disconnected
100- await close_connections_for_url (self , url )
101- logger .warning ('httpcore.RemoteProtocolError: retry' , exc_info = e )
102- # retry
103- except (httpcore .NetworkError , httpcore .ProtocolError ) as e :
104- # httpcore.WriteError on HTTP/2 connection leaves a new opened stream
100+ raise httpx .ConnectError from e
101+ except httpx .NetworkError as e :
102+ # httpx.WriteError on HTTP/2 connection leaves a new opened stream
105103 # then each new request creates a new stream and raise the same WriteError
106104 await close_connections_for_url (self , url )
107105 raise e
106+ except httpx .RemoteProtocolError as e :
107+ # in case of httpx.RemoteProtocolError: Server disconnected
108+ await close_connections_for_url (self , url )
109+ logger .warning ('httpx.RemoteProtocolError: retry' , exc_info = e )
110+ # retry
108111
109112
110113class AsyncHTTPTransportFixed (httpx .AsyncHTTPTransport ):
111114 """Fix httpx.AsyncHTTPTransport"""
112115
113- async def arequest (self , method , url , headers = None , stream = None , ext = None ):
116+ async def handle_async_request (
117+ self , method , url , headers = None , stream = None , extensions = None
118+ ):
114119 retry = 2
115120 while retry > 0 :
116121 retry -= 1
117122 try :
118- return await super ().arequest (method , url , headers , stream , ext )
123+ return await super ().handle_async_request (
124+ method , url , headers = headers , stream = stream , extensions = extensions
125+ )
119126 except OSError as e :
120127 # socket.gaierror when DNS resolution fails
121- raise httpcore .ConnectError (e )
122- except httpcore .CloseError as e :
123- # httpcore.CloseError: [Errno 104] Connection reset by peer
124- # raised by _keepalive_sweep()
125- # from https://github.com/encode/httpcore/blob/4b662b5c42378a61e54d673b4c949420102379f5/httpcore/_backends/asyncio.py#L198 # pylint: disable=line-too-long
126- await close_connections_for_url (self ._pool , url )
127- logger .warning ('httpcore.CloseError: retry' , exc_info = e )
128- # retry
129- except httpcore .RemoteProtocolError as e :
130- # in case of httpcore.RemoteProtocolError: Server disconnected
128+ raise httpx .ConnectError from e
129+ except httpx .NetworkError as e :
130+ # httpx.WriteError on HTTP/2 connection leaves a new opened stream
131+ # then each new request creates a new stream and raise the same WriteError
132+ await close_connections_for_url (self , url )
133+ raise e
134+ except httpx .RemoteProtocolError as e :
135+ # in case of httpx.RemoteProtocolError: Server disconnected
131136 await close_connections_for_url (self ._pool , url )
132- logger .warning ('httpcore .RemoteProtocolError: retry' , exc_info = e )
137+ logger .warning ('httpx .RemoteProtocolError: retry' , exc_info = e )
133138 # retry
134- except (httpcore .ProtocolError , httpcore .NetworkError ) as e :
135- await close_connections_for_url (self ._pool , url )
136- raise e
137139
138140
139141def get_transport_for_socks_proxy (verify , http2 , local_address , proxy_url , limit , retries ):
@@ -206,7 +208,7 @@ def new_client(
206208 if not enable_http and (pattern == 'http' or pattern .startswith ('http://' )):
207209 continue
208210 if (proxy_url .startswith ('socks4://' )
209- or proxy_url .startswith ('socks5://' )
211+ or proxy_url .startswith ('socks5://' )
210212 or proxy_url .startswith ('socks5h://' )
211213 ):
212214 mounts [pattern ] = get_transport_for_socks_proxy (
0 commit comments