poolrequests.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. import requests
  2. from itertools import cycle
  3. from threading import RLock
  4. from searx import settings
  5. class HTTPAdapterWithConnParams(requests.adapters.HTTPAdapter):
  6. def __init__(self, pool_connections=requests.adapters.DEFAULT_POOLSIZE,
  7. pool_maxsize=requests.adapters.DEFAULT_POOLSIZE,
  8. max_retries=requests.adapters.DEFAULT_RETRIES,
  9. pool_block=requests.adapters.DEFAULT_POOLBLOCK,
  10. **conn_params):
  11. if max_retries == requests.adapters.DEFAULT_RETRIES:
  12. self.max_retries = requests.adapters.Retry(0, read=False)
  13. else:
  14. self.max_retries = requests.adapters.Retry.from_int(max_retries)
  15. self.config = {}
  16. self.proxy_manager = {}
  17. super(requests.adapters.HTTPAdapter, self).__init__()
  18. self._pool_connections = pool_connections
  19. self._pool_maxsize = pool_maxsize
  20. self._pool_block = pool_block
  21. self._conn_params = conn_params
  22. self.init_poolmanager(pool_connections, pool_maxsize, block=pool_block, **conn_params)
  23. def __setstate__(self, state):
  24. # Can't handle by adding 'proxy_manager' to self.__attrs__ because
  25. # because self.poolmanager uses a lambda function, which isn't pickleable.
  26. self.proxy_manager = {}
  27. self.config = {}
  28. for attr, value in state.items():
  29. setattr(self, attr, value)
  30. self.init_poolmanager(self._pool_connections, self._pool_maxsize,
  31. block=self._pool_block, **self._conn_params)
  32. connect = settings['outgoing'].get('pool_connections', 100) # Magic number kept from previous code
  33. maxsize = settings['outgoing'].get('pool_maxsize', requests.adapters.DEFAULT_POOLSIZE) # Picked from constructor
  34. if settings['outgoing'].get('source_ips'):
  35. http_adapters = cycle(HTTPAdapterWithConnParams(pool_connections=connect, pool_maxsize=maxsize,
  36. source_address=(source_ip, 0))
  37. for source_ip in settings['outgoing']['source_ips'])
  38. https_adapters = cycle(HTTPAdapterWithConnParams(pool_connections=connect, pool_maxsize=maxsize,
  39. source_address=(source_ip, 0))
  40. for source_ip in settings['outgoing']['source_ips'])
  41. else:
  42. http_adapters = cycle((HTTPAdapterWithConnParams(pool_connections=connect, pool_maxsize=maxsize), ))
  43. https_adapters = cycle((HTTPAdapterWithConnParams(pool_connections=connect, pool_maxsize=maxsize), ))
  44. class SessionSinglePool(requests.Session):
  45. def __init__(self):
  46. super(SessionSinglePool, self).__init__()
  47. # reuse the same adapters
  48. with RLock():
  49. self.adapters.clear()
  50. self.mount('https://', next(https_adapters))
  51. self.mount('http://', next(http_adapters))
  52. def close(self):
  53. """Call super, but clear adapters since there are managed globaly"""
  54. self.adapters.clear()
  55. super(SessionSinglePool, self).close()
  56. def request(method, url, **kwargs):
  57. """same as requests/requests/api.py request(...) except it use SessionSinglePool and force proxies"""
  58. session = SessionSinglePool()
  59. kwargs['proxies'] = settings['outgoing'].get('proxies') or None
  60. response = session.request(method=method, url=url, **kwargs)
  61. session.close()
  62. return response
  63. def get(url, **kwargs):
  64. kwargs.setdefault('allow_redirects', True)
  65. return request('get', url, **kwargs)
  66. def options(url, **kwargs):
  67. kwargs.setdefault('allow_redirects', True)
  68. return request('options', url, **kwargs)
  69. def head(url, **kwargs):
  70. kwargs.setdefault('allow_redirects', False)
  71. return request('head', url, **kwargs)
  72. def post(url, data=None, **kwargs):
  73. return request('post', url, data=data, **kwargs)
  74. def put(url, data=None, **kwargs):
  75. return request('put', url, data=data, **kwargs)
  76. def patch(url, data=None, **kwargs):
  77. return request('patch', url, data=data, **kwargs)
  78. def delete(url, **kwargs):
  79. return request('delete', url, **kwargs)