@@ -32,7 +32,8 @@ from searx.utils import gen_useragent
32from searx.results import ResultContainer
32from searx.results import ResultContainer
33from searx import logger
33from searx import logger
34from searx.plugins import plugins
34from searx.plugins import plugins
35−from searx.exceptions import SearxEngineCaptchaException
35+from searx.exceptions import (SearxEngineAccessDeniedException, SearxEngineCaptchaException,
36+ SearxEngineTooManyRequestsException,)
36from searx.metrology.error_recorder import record_exception, record_error
37from searx.metrology.error_recorder import record_exception, record_error
@@ -131,6 +132,9 @@ def send_http_request(engine, request_params):
131 # soft_max_redirects
132 # soft_max_redirects
132 soft_max_redirects = request_params.get('soft_max_redirects', max_redirects or 0)
133 soft_max_redirects = request_params.get('soft_max_redirects', max_redirects or 0)
136+ request_args['raise_for_httperror'] = request_params.get('raise_for_httperror', False)
134 # specific type of request (GET or POST)
138 # specific type of request (GET or POST)
135 if request_params['method'] == 'GET':
139 if request_params['method'] == 'GET':
136 req = requests_lib.get
140 req = requests_lib.get
@@ -142,10 +146,6 @@ def send_http_request(engine, request_params):
142 # send the request
146 # send the request
143 response = req(request_params['url'], **request_args)
147 response = req(request_params['url'], **request_args)
146− if request_params.get('raise_for_status'):
147− response.raise_for_status()
149 # check soft limit of the redirect count
149 # check soft limit of the redirect count
150 if len(response.history) > soft_max_redirects:
150 if len(response.history) > soft_max_redirects:
151 # unexpected redirect : record an error
151 # unexpected redirect : record an error
@@ -191,6 +191,7 @@ def search_one_http_request_safe(engine_name, query, request_params, result_cont
192 # suppose everything will be alright
192 # suppose everything will be alright
193 requests_exception = False
193 requests_exception = False
194+ suspended_time = None
196 # send requests and parse the results
197 # send requests and parse the results
@@ -240,6 +241,15 @@ def search_one_http_request_safe(engine_name, query, request_params, result_cont
240 elif (issubclass(e.__class__, SearxEngineCaptchaException)):
241 elif (issubclass(e.__class__, SearxEngineCaptchaException)):
241 result_container.add_unresponsive_engine(engine_name, 'CAPTCHA required')
242 result_container.add_unresponsive_engine(engine_name, 'CAPTCHA required')
242 logger.exception('engine {0} : CAPTCHA')
243 logger.exception('engine {0} : CAPTCHA')
244+ suspended_time = e.suspended_time # pylint: disable=no-member
245+ elif (issubclass(e.__class__, SearxEngineTooManyRequestsException)):
246+ result_container.add_unresponsive_engine(engine_name, 'too many requests')
247+ logger.exception('engine {0} : Too many requests')
248+ suspended_time = e.suspended_time # pylint: disable=no-member
249+ elif (issubclass(e.__class__, SearxEngineAccessDeniedException)):
250+ result_container.add_unresponsive_engine(engine_name, 'blocked')
251+ logger.exception('engine {0} : Searx is blocked')
252+ suspended_time = e.suspended_time # pylint: disable=no-member
244 result_container.add_unresponsive_engine(engine_name, 'unexpected crash')
254 result_container.add_unresponsive_engine(engine_name, 'unexpected crash')
245 # others errors
255 # others errors
@@ -248,16 +258,18 @@ def search_one_http_request_safe(engine_name, query, request_params, result_cont
248 if getattr(threading.current_thread(), '_timeout', False):
258 if getattr(threading.current_thread(), '_timeout', False):
249 record_error(engine_name, 'Timeout')
259 record_error(engine_name, 'Timeout')
251− # suspend or not the engine if there are HTTP errors
261+ # suspend the engine if there is an HTTP error
262+ # or suspended_time is defined
252 with threading.RLock():
263 with threading.RLock():
253− if requests_exception:
264+ if requests_exception or suspended_time:
254 # update continuous_errors / suspend_end_time
265 # update continuous_errors / suspend_end_time
255 engine.continuous_errors += 1
266 engine.continuous_errors += 1
267+ if suspended_time is None:
256− engine.suspend_end_time = time() + min(settings['search']['max_ban_time_on_fail'],
268+ suspended_time = min(settings['search']['max_ban_time_on_fail'],
257− engine.continuous_errors * settings['search']['ban_time_on_fail'])
269+ engine.continuous_errors * settings['search']['ban_time_on_fail'])
270+ engine.suspend_end_time = time() + suspended_time
259− # no HTTP error (perhaps an engine error)
260− # anyway, reset the suspend variables
272+ # reset the suspend variables
261 engine.continuous_errors = 0
273 engine.continuous_errors = 0
262 engine.suspend_end_time = 0
274 engine.suspend_end_time = 0
@@ -342,7 +354,7 @@ def default_request_params():
342 'cookies': {},
354 'cookies': {},
343 'verify': True,
355 'verify': True,
344 'auth': None,
356 'auth': None,
345− 'raise_for_status': True
357+ 'raise_for_httperror': True