diff --git a/src/calibre/srv/http_request.py b/src/calibre/srv/http_request.py index 71d6cb9c36..57f840156c 100644 --- a/src/calibre/srv/http_request.py +++ b/src/calibre/srv/http_request.py @@ -66,7 +66,7 @@ def parse_request_uri(uri): return None, uri, None -def parse_uri(uri, parse_query=True): +def parse_uri(uri, parse_query=True, unquote_func=unquote): scheme, authority, path = parse_request_uri(uri) if path is None: raise HTTPSimpleResponse(http_client.BAD_REQUEST, "No path component") @@ -89,7 +89,7 @@ def parse_uri(uri, parse_query=True): query = None try: - path = '%2F'.join(unquote(x).decode('utf-8') for x in quoted_slash.split(path)) + path = '%2F'.join(unquote_func(x).decode('utf-8') for x in quoted_slash.split(path)) except ValueError as e: raise HTTPSimpleResponse(http_client.BAD_REQUEST, as_unicode(e)) path = tuple(filter(None, (x.replace('%2F', '/') for x in path.split('/')))) @@ -212,6 +212,7 @@ class HTTPRequest(Connection): self.max_header_line_size = int(1024 * self.opts.max_header_line_size) self.max_request_body_size = int(1024 * 1024 * self.opts.max_request_body_size) self.forwarded_for = None + self.request_original_uri = None def read(self, buf, endpos): size = endpos - buf.tell() @@ -279,6 +280,7 @@ class HTTPRequest(Connection): except KeyError: return self.simple_response(http_client.HTTP_VERSION_NOT_SUPPORTED) self.response_protocol = protocol_map[min((1, 1), rp)] + self.request_original_uri = uri try: self.scheme, self.path, self.query = parse_uri(uri) except HTTPSimpleResponse as e: diff --git a/src/calibre/srv/http_response.py b/src/calibre/srv/http_response.py index 0bd1991ad7..0755ea3bc8 100644 --- a/src/calibre/srv/http_response.py +++ b/src/calibre/srv/http_response.py @@ -219,15 +219,18 @@ class RequestData(object): # {{{ username = None def __init__(self, method, path, query, inheaders, request_body_file, outheaders, response_protocol, - static_cache, opts, remote_addr, remote_port, is_local_connection, translator_cache, tdir, forwarded_for): + static_cache, opts, remote_addr, remote_port, is_local_connection, translator_cache, + tdir, forwarded_for, request_original_uri=None): (self.method, self.path, self.query, self.inheaders, self.request_body_file, self.outheaders, self.response_protocol, self.static_cache, self.translator_cache) = ( method, path, query, inheaders, request_body_file, outheaders, response_protocol, static_cache, translator_cache ) + self.remote_addr, self.remote_port, self.is_local_connection = remote_addr, remote_port, is_local_connection self.forwarded_for = forwarded_for + self.request_original_uri = request_original_uri self.opts = opts self.status_code = http_client.OK self.outcookie = Cookie() @@ -444,7 +447,7 @@ class HTTPConnection(HTTPRequest): self.method, self.path, self.query, inheaders, request_body_file, outheaders, self.response_protocol, self.static_cache, self.opts, self.remote_addr, self.remote_port, self.is_local_connection, - self.translator_cache, self.tdir, self.forwarded_for + self.translator_cache, self.tdir, self.forwarded_for, self.request_original_uri ) self.queue_job(self.run_request_handler, data) diff --git a/src/calibre/srv/opds.py b/src/calibre/srv/opds.py index e3bcb240a3..59f3e75612 100644 --- a/src/calibre/srv/opds.py +++ b/src/calibre/srv/opds.py @@ -26,9 +26,10 @@ from calibre import force_unicode from calibre.srv.errors import HTTPNotFound, HTTPInternalServerError from calibre.srv.routes import endpoint +from calibre.srv.http_request import parse_uri from calibre.srv.utils import get_library_data, http_date, Offsets from polyglot.builtins import iteritems, unicode_type, filter, as_bytes -from polyglot.urllib import urlencode +from polyglot.urllib import urlencode, unquote_plus from polyglot.binary import as_hex_unicode, from_hex_unicode @@ -624,6 +625,11 @@ def opds_search(ctx, rd, query): raise HTTPNotFound('Not found') rc = RequestContext(ctx, rd) + if query: + path = parse_uri(rd.request_original_uri, parse_query=False, unquote_func=unquote_plus)[1] + query = path[-1] + if isinstance(query, bytes): + query = query.decode('utf-8') try: ids = rc.search(query) except Exception: diff --git a/src/polyglot/urllib.py b/src/polyglot/urllib.py index 8f9e008f8c..1d30c99eca 100644 --- a/src/polyglot/urllib.py +++ b/src/polyglot/urllib.py @@ -22,6 +22,7 @@ if is_py3: if binary: ans = ans.encode(encoding, errors) return ans + else: from urllib import (getproxies, quote, unquote as uq, quote_plus, url2pathname, # noqa urlencode) # noqa @@ -43,3 +44,9 @@ else: if not binary: ans = ans.decode(encoding, errors) return ans + + +def unquote_plus(x, encoding='utf-8', errors='replace'): + q, repl = (b'+', b' ') if isinstance(x, bytes) else ('+', ' ') + x = x.replace(q, repl) + return unquote(x, encoding=encoding, errors=errors)