.oO SearXNG Developer Documentation Oo.
Loading...
Searching...
No Matches
searx.network.client Namespace Reference

Classes

class  AsyncHTTPTransportNoHttp
class  AsyncProxyTransportFixed

Functions

 shuffle_ciphers (SSLContext ssl_context)
SSLContext get_sslcontexts (str|None proxy_url=None, CertTypes|None cert=None, bool verify=True, bool trust_env=True)
 get_transport_for_socks_proxy (bool verify, bool http2, str local_address, str proxy_url, httpx.Limits limit, int retries)
 get_transport (bool verify, bool http2, str local_address, str|None proxy_url, httpx.Limits limit, int retries)
httpx.AsyncClient new_client (bool enable_http, bool verify, bool enable_http2, int max_connections, int max_keepalive_connections, float keepalive_expiry, dict[str, str] proxies, str local_address, int retries, int max_redirects, t.Callable[..., t.Any]|None hook_log_response)
asyncio.AbstractEventLoop get_loop ()
 init ()

Variables

 CertTypes = str | tuple[str, str] | tuple[str, str, str]
 SslContextKeyType = tuple[str | None, CertTypes | None, bool, bool]
 logger = logger.getChild('searx.network.client')
asyncio LOOP = None
dict SSLCONTEXTS = {}

Function Documentation

◆ get_loop()

asyncio.AbstractEventLoop searx.network.client.get_loop ( )

Definition at line 209 of file client.py.

209def get_loop() -> asyncio.AbstractEventLoop:
210 return LOOP
211
212

Referenced by get_transport_for_socks_proxy().

Here is the caller graph for this function:

◆ get_sslcontexts()

SSLContext searx.network.client.get_sslcontexts ( str | None proxy_url = None,
CertTypes | None cert = None,
bool verify = True,
bool trust_env = True )

Definition at line 51 of file client.py.

53) -> SSLContext:
54 key: SslContextKeyType = (proxy_url, cert, verify, trust_env)
55 if key not in SSLCONTEXTS:
56 SSLCONTEXTS[key] = httpx.create_ssl_context(verify, cert, trust_env)
57 shuffle_ciphers(SSLCONTEXTS[key])
58 return SSLCONTEXTS[key]
59
60

References shuffle_ciphers().

Referenced by get_transport(), and get_transport_for_socks_proxy().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_transport()

searx.network.client.get_transport ( bool verify,
bool http2,
str local_address,
str | None proxy_url,
httpx.Limits limit,
int retries )

Definition at line 145 of file client.py.

147):
148 _verify = get_sslcontexts(None, None, verify, True) if verify is True else verify
149 return httpx.AsyncHTTPTransport(
150 # pylint: disable=protected-access
151 verify=_verify,
152 http2=http2,
153 limits=limit,
154 proxy=httpx._config.Proxy(proxy_url) if proxy_url else None, # pyright: ignore[reportPrivateUsage]
155 local_address=local_address,
156 retries=retries,
157 )
158
159

References get_sslcontexts().

Referenced by new_client().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_transport_for_socks_proxy()

searx.network.client.get_transport_for_socks_proxy ( bool verify,
bool http2,
str local_address,
str proxy_url,
httpx.Limits limit,
int retries )

Definition at line 114 of file client.py.

116):
117 # support socks5h (requests compatibility):
118 # https://requests.readthedocs.io/en/master/user/advanced/#socks
119 # socks5:// hostname is resolved on client side
120 # socks5h:// hostname is resolved on proxy side
121 rdns = False
122 socks5h = 'socks5h://'
123 if proxy_url.startswith(socks5h):
124 proxy_url = 'socks5://' + proxy_url[len(socks5h) :]
125 rdns = True
126
127 proxy_type, proxy_host, proxy_port, proxy_username, proxy_password = parse_proxy_url(proxy_url)
128 _verify = get_sslcontexts(proxy_url, None, verify, True) if verify is True else verify
129 return AsyncProxyTransportFixed(
130 proxy_type=proxy_type,
131 proxy_host=proxy_host,
132 proxy_port=proxy_port,
133 username=proxy_username,
134 password=proxy_password,
135 rdns=rdns,
136 loop=get_loop(),
137 verify=_verify, # pyright: ignore[reportArgumentType]
138 http2=http2,
139 local_address=local_address,
140 limits=limit,
141 retries=retries,
142 )
143
144

References get_loop(), and get_sslcontexts().

Referenced by new_client().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ init()

searx.network.client.init ( )

Definition at line 213 of file client.py.

213def init():
214 # log
215 for logger_name in (
216 'httpx',
217 'httpcore.proxy',
218 'httpcore.connection',
219 'httpcore.http11',
220 'httpcore.http2',
221 'hpack.hpack',
222 'hpack.table',
223 ):
224 logging.getLogger(logger_name).setLevel(logging.WARNING)
225
226 # loop
227 def loop_thread():
228 global LOOP
229 LOOP = asyncio.new_event_loop()
230 LOOP.run_forever()
231
232 thread = threading.Thread(
233 target=loop_thread,
234 name='asyncio_loop',
235 daemon=True,
236 )
237 thread.start()
238
239

References init().

Referenced by init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ new_client()

httpx.AsyncClient searx.network.client.new_client ( bool enable_http,
bool verify,
bool enable_http2,
int max_connections,
int max_keepalive_connections,
float keepalive_expiry,
dict[str, str] proxies,
str local_address,
int retries,
int max_redirects,
t.Callable[..., t.Any] | None hook_log_response )

Definition at line 160 of file client.py.

173) -> httpx.AsyncClient:
174 limit = httpx.Limits(
175 max_connections=max_connections,
176 max_keepalive_connections=max_keepalive_connections,
177 keepalive_expiry=keepalive_expiry,
178 )
179 # See https://www.python-httpx.org/advanced/#routing
180 mounts = {}
181 mounts: None | (dict[str, t.Any | None]) = {}
182 for pattern, proxy_url in proxies.items():
183 if not enable_http and pattern.startswith('http://'):
184 continue
185 if proxy_url.startswith('socks4://') or proxy_url.startswith('socks5://') or proxy_url.startswith('socks5h://'):
186 mounts[pattern] = get_transport_for_socks_proxy(
187 verify, enable_http2, local_address, proxy_url, limit, retries
188 )
189 else:
190 mounts[pattern] = get_transport(verify, enable_http2, local_address, proxy_url, limit, retries)
191
192 if not enable_http:
193 mounts['http://'] = AsyncHTTPTransportNoHttp()
194
195 transport = get_transport(verify, enable_http2, local_address, None, limit, retries)
196
197 event_hooks = None
198 if hook_log_response:
199 event_hooks = {'response': [hook_log_response]}
200
201 return httpx.AsyncClient(
202 transport=transport,
203 mounts=mounts,
204 max_redirects=max_redirects,
205 event_hooks=event_hooks,
206 )
207
208

References get_transport(), and get_transport_for_socks_proxy().

Here is the call graph for this function:

◆ shuffle_ciphers()

searx.network.client.shuffle_ciphers ( SSLContext ssl_context)
Shuffle httpx's default ciphers of a SSL context randomly.

From `What Is TLS Fingerprint and How to Bypass It`_

> When implementing TLS fingerprinting, servers can't operate based on a
> locked-in whitelist database of fingerprints.  New fingerprints appear
> when web clients or TLS libraries release new versions. So, they have to
> live off a blocklist database instead.
> ...
> It's safe to leave the first three as is but shuffle the remaining ciphers
> and you can bypass the TLS fingerprint check.

.. _What Is TLS Fingerprint and How to Bypass It:
   https://www.zenrows.com/blog/what-is-tls-fingerprint#how-to-bypass-tls-fingerprinting

Definition at line 28 of file client.py.

28def shuffle_ciphers(ssl_context: SSLContext):
29 """Shuffle httpx's default ciphers of a SSL context randomly.
30
31 From `What Is TLS Fingerprint and How to Bypass It`_
32
33 > When implementing TLS fingerprinting, servers can't operate based on a
34 > locked-in whitelist database of fingerprints. New fingerprints appear
35 > when web clients or TLS libraries release new versions. So, they have to
36 > live off a blocklist database instead.
37 > ...
38 > It's safe to leave the first three as is but shuffle the remaining ciphers
39 > and you can bypass the TLS fingerprint check.
40
41 .. _What Is TLS Fingerprint and How to Bypass It:
42 https://www.zenrows.com/blog/what-is-tls-fingerprint#how-to-bypass-tls-fingerprinting
43
44 """
45 c_list = [cipher["name"] for cipher in ssl_context.get_ciphers()]
46 sc_list, c_list = c_list[:3], c_list[3:]
47 random.shuffle(c_list)
48 ssl_context.set_ciphers(":".join(sc_list + c_list))
49
50

Referenced by get_sslcontexts().

Here is the caller graph for this function:

Variable Documentation

◆ CertTypes

searx.network.client.CertTypes = str | tuple[str, str] | tuple[str, str, str]

Definition at line 19 of file client.py.

◆ logger

searx.network.client.logger = logger.getChild('searx.network.client')

Definition at line 22 of file client.py.

◆ LOOP

asyncio searx.network.client.LOOP = None

Definition at line 23 of file client.py.

◆ SslContextKeyType

searx.network.client.SslContextKeyType = tuple[str | None, CertTypes | None, bool, bool]

Definition at line 20 of file client.py.

◆ SSLCONTEXTS

dict searx.network.client.SSLCONTEXTS = {}

Definition at line 25 of file client.py.