@@ -22,11 +22,12 @@ if __name__ == '__main__':
22 from os.path import realpath, dirname
22 from os.path import realpath, dirname
23 path.append(realpath(dirname(realpath(__file__)) + '/../'))
23 path.append(realpath(dirname(realpath(__file__)) + '/../'))
26import hashlib
25import hashlib
27import hmac
26import hmac
28import json
27import json
30import requests
31import requests
32from searx import logger
33from searx import logger
@@ -42,8 +43,6 @@ except:
43from cgi import escape
44from cgi import escape
44from datetime import datetime, timedelta
45from datetime import datetime, timedelta
45−from urllib import urlencode
46−from urlparse import urlparse, urljoin
47from werkzeug.contrib.fixers import ProxyFix
46from werkzeug.contrib.fixers import ProxyFix
48from flask import (
47from flask import (
49 Flask, request, render_template, url_for, Response, make_response,
48 Flask, request, render_template, url_for, Response, make_response,
@@ -52,7 +51,7 @@ from flask import (
52from flask_babel import Babel, gettext, format_date, format_decimal
51from flask_babel import Babel, gettext, format_date, format_decimal
53from flask.json import jsonify
52from flask.json import jsonify
54from searx import settings, searx_dir, searx_debug
53from searx import settings, searx_dir, searx_debug
55−from searx.exceptions import SearxException, SearxParameterException
54+from searx.exceptions import SearxParameterException
56from searx.engines import (
55from searx.engines import (
57 categories, engines, engine_shortcuts, get_engines_stats, initialize_engines
56 categories, engines, engine_shortcuts, get_engines_stats, initialize_engines
@@ -69,6 +68,7 @@ from searx.autocomplete import searx_bang, backends as autocomplete_backends
69from searx.plugins import plugins
68from searx.plugins import plugins
70from searx.preferences import Preferences, ValidationException
69from searx.preferences import Preferences, ValidationException
71from searx.answerers import answerers
70from searx.answerers import answerers
71+from searx.url_utils import urlencode, urlparse, urljoin
73# check if the pyopenssl package is installed.
73# check if the pyopenssl package is installed.
74# It is needed for SSL connection without trouble, see #298
74# It is needed for SSL connection without trouble, see #298
@@ -78,6 +78,15 @@ except ImportError:
78 logger.critical("The pyopenssl package has to be installed.\n"
78 logger.critical("The pyopenssl package has to be installed.\n"
79 "Some HTTPS connections will fail")
79 "Some HTTPS connections will fail")
82+ from cStringIO import StringIO
84+ from io import StringIO
87+if sys.version_info[0] == 3:
81# serve pages with HTTP/1.1
90# serve pages with HTTP/1.1
82from werkzeug.serving import WSGIRequestHandler
91from werkzeug.serving import WSGIRequestHandler
83WSGIRequestHandler.protocol_version = "HTTP/{}".format(settings['server'].get('http_protocol_version', '1.0'))
92WSGIRequestHandler.protocol_version = "HTTP/{}".format(settings['server'].get('http_protocol_version', '1.0'))
@@ -357,6 +366,8 @@ def render(template_name, override_theme=None, **kwargs):
358 kwargs['results_on_new_tab'] = request.preferences.get_value('results_on_new_tab')
367 kwargs['results_on_new_tab'] = request.preferences.get_value('results_on_new_tab')
369+ kwargs['unicode'] = unicode
360 kwargs['scripts'] = set()
371 kwargs['scripts'] = set()
361 for plugin in request.user_plugins:
372 for plugin in request.user_plugins:
362 for script in plugin.js_dependencies:
373 for script in plugin.js_dependencies:
@@ -375,7 +386,7 @@ def render(template_name, override_theme=None, **kwargs):
375def pre_request():
386def pre_request():
376 request.errors = []
387 request.errors = []
378− preferences = Preferences(themes, categories.keys(), engines, plugins)
389+ preferences = Preferences(themes, list(categories.keys()), engines, plugins)
379 request.preferences = preferences
390 request.preferences = preferences
381 preferences.parse_cookies(request.cookies)
392 preferences.parse_cookies(request.cookies)
@@ -479,10 +490,8 @@ def index():
479 for result in results:
490 for result in results:
480 if output_format == 'html':
491 if output_format == 'html':
481 if 'content' in result and result['content']:
492 if 'content' in result and result['content']:
482− result['content'] = highlight_content(escape(result['content'][:1024]),
493+ result['content'] = highlight_content(escape(result['content'][:1024]), search_query.query)
483− search_query.query.encode('utf-8'))
484− result['title'] = highlight_content(escape(result['title'] or u''),
494+ result['title'] = highlight_content(escape(result['title'] or u''), search_query.query)
485− search_query.query.encode('utf-8'))
487 if result.get('content'):
496 if result.get('content'):
488 result['content'] = html_to_text(result['content']).strip()
497 result['content'] = html_to_text(result['content']).strip()
@@ -510,7 +519,7 @@ def index():
510 result['publishedDate'] = format_date(result['publishedDate'])
519 result['publishedDate'] = format_date(result['publishedDate'])
512 if output_format == 'json':
521 if output_format == 'json':
513− return Response(json.dumps({'query': search_query.query,
522+ return Response(json.dumps({'query': search_query.query.decode('utf-8'),
514 'number_of_results': number_of_results,
523 'number_of_results': number_of_results,
515 'results': results,
524 'results': results,
516 'answers': list(result_container.answers),
525 'answers': list(result_container.answers),
@@ -519,7 +528,7 @@ def index():
519 'suggestions': list(result_container.suggestions)}),
528 'suggestions': list(result_container.suggestions)}),
520 mimetype='application/json')
529 mimetype='application/json')
521 elif output_format == 'csv':
530 elif output_format == 'csv':
522− csv = UnicodeWriter(cStringIO.StringIO())
531+ csv = UnicodeWriter(StringIO())
523 keys = ('title', 'url', 'content', 'host', 'engine', 'score')
532 keys = ('title', 'url', 'content', 'host', 'engine', 'score')
524 csv.writerow(keys)
533 csv.writerow(keys)
525 for row in results:
534 for row in results:
@@ -527,7 +536,7 @@ def index():
527 csv.writerow([row.get(key, '') for key in keys])
536 csv.writerow([row.get(key, '') for key in keys])
528 csv.stream.seek(0)
537 csv.stream.seek(0)
529 response = Response(csv.stream.read(), mimetype='application/csv')
538 response = Response(csv.stream.read(), mimetype='application/csv')
530− cont_disp = 'attachment;Filename=searx_-_{0}.csv'.format(search_query.query.encode('utf-8'))
539+ cont_disp = 'attachment;Filename=searx_-_{0}.csv'.format(search_query.query)
531 response.headers.add('Content-Disposition', cont_disp)
540 response.headers.add('Content-Disposition', cont_disp)
532 return response
541 return response
533 elif output_format == 'rss':
542 elif output_format == 'rss':
@@ -578,7 +587,7 @@ def autocompleter():
578 disabled_engines = request.preferences.engines.get_disabled()
587 disabled_engines = request.preferences.engines.get_disabled()
580 # parse query
589 # parse query
581− raw_text_query = RawTextQuery(request.form.get('q', '').encode('utf-8'), disabled_engines)
590+ raw_text_query = RawTextQuery(request.form.get('q', u'').encode('utf-8'), disabled_engines)
582 raw_text_query.parse_query()
591 raw_text_query.parse_query()
584 # check if search query is set
593 # check if search query is set
@@ -820,6 +829,7 @@ def page_not_found(e):
822def run():
831def run():
832+ logger.debug('starting webserver on %s:%s', settings['server']['port'], settings['server']['bind_address'])
824 debug=searx_debug,
834 debug=searx_debug,
825 use_debugger=searx_debug,
835 use_debugger=searx_debug,