diff --git a/src/calibre/srv/opts.py b/src/calibre/srv/opts.py index 977b05794e..10330ba758 100644 --- a/src/calibre/srv/opts.py +++ b/src/calibre/srv/opts.py @@ -82,7 +82,7 @@ raw_options = ( _('A prefix to prepend to all URLs'), 'url_prefix', None, - _('Useful if you wish to run this server behind a reverse proxy.'), + _('Useful if you wish to run this server behind a reverse proxy. For example use, /calibre as the URL prefix.'), _('Advertise OPDS feeds via BonJour'), 'use_bonjour', True, diff --git a/src/calibre/srv/routes.py b/src/calibre/srv/routes.py index a024898a73..4d7fb100cd 100644 --- a/src/calibre/srv/routes.py +++ b/src/calibre/srv/routes.py @@ -199,7 +199,12 @@ class Router(object): def __init__(self, endpoints=None, ctx=None, url_prefix=None, auth_controller=None): self.routes = {} - self.url_prefix = url_prefix or '' + self.url_prefix = (url_prefix or '').rstrip('/') + self.strip_path = None + if self.url_prefix: + if not self.url_prefix.startswith('/'): + self.url_prefix = '/' + self.url_prefix + self.strip_path = tuple(self.url_prefix[1:].split('/')) self.ctx = ctx self.auth_controller = auth_controller self.init_session = getattr(ctx, 'init_session', lambda ep, data:None) @@ -236,6 +241,8 @@ class Router(object): self.soak_routes = sorted(frozenset(r for r in self if r.soak_up_extra), key=attrgetter('min_size'), reverse=True) def find_route(self, path): + if self.strip_path is not None and path[:len(self.strip_path)] == self.strip_path: + path = path[len(self.strip_path):] size = len(path) # routes for which min_size <= size <= max_size routes = self.max_size_map.get(size, set()) & self.min_size_map.get(size, set()) diff --git a/src/pyj/ajax.pyj b/src/pyj/ajax.pyj index 331588b4a5..cc498ce2b6 100644 --- a/src/pyj/ajax.pyj +++ b/src/pyj/ajax.pyj @@ -15,20 +15,20 @@ def encode_query_component(x): ans = ans.replace(/%3[aA]/g, ':') return ans -def encode_query(query): +def encode_query(query, qchar): if not query: return '' + qchar = qchar or '?' keys = Object.keys(query) - has_query = False - path = '' + ans = '' if keys.length: for k in keys: val = query[k] if val is undefined or val is None: continue - path += ('&' if has_query else '?') + encodeURIComponent(k) + '=' + encode_query_component(val.toString()) - has_query = True - return path + ans += qchar + encodeURIComponent(k) + '=' + encode_query_component(val.toString()) + qchar = '&' + return ans def ajax(path, on_complete, on_progress=None, bypass_cache=True, method='GET', query=None, timeout=30*1000, ok_code=200, progress_totals_needed=True): # Run an AJAX request. on_complete must be a function that accepts three diff --git a/src/pyj/book_list/router.pyj b/src/pyj/book_list/router.pyj index b2e963409d..85d1e6d69c 100644 --- a/src/pyj/book_list/router.pyj +++ b/src/pyj/book_list/router.pyj @@ -2,12 +2,10 @@ # License: GPL v3 Copyright: 2017, Kovid Goyal from __python__ import hash_literals, bound_methods -from ajax import encode_query as ajax_encode_query - from book_list.constants import read_book_container_id, book_list_container_id from book_list.globals import get_current_query from book_list.library_data import current_library_id -from utils import parse_url_params +from utils import parse_url_params, encode_query_with_path mode_handlers = {} default_mode_handler = None @@ -54,16 +52,12 @@ def open_book(book_id, fmt, library_id=None, replace=False): push_state({'book_id':book_id, 'fmt':fmt, 'library_id':library_id}, replace=replace, mode=read_book_mode) -def encode_query(query): - ans = ajax_encode_query(query) - return '#' + ans[1:] - def push_state(query, replace=False, mode='book_list', call_handler=True): query = {k:query[k] for k in query} if mode is not 'book_list': query.mode = mode - query = encode_query(query) + query = encode_query_with_path(query) if replace: window.history.replaceState(None, '', query) else: diff --git a/src/pyj/utils.pyj b/src/pyj/utils.pyj index fa128c05ed..ad6812bc54 100644 --- a/src/pyj/utils.pyj +++ b/src/pyj/utils.pyj @@ -2,6 +2,7 @@ # License: GPL v3 Copyright: 2015, Kovid Goyal from __python__ import hash_literals +from ajax import encode_query from encodings import hexlify def debounce(func, wait, immediate=False): @@ -52,6 +53,12 @@ def parse_url_params(url=None, allow_multiple=False): return ans parse_url_params.cache = {} + +def encode_query_with_path(query, path): + path = path or window.location.pathname + return path + encode_query(query, '#') + + _roman = list(zip( [1000,900,500,400,100,90,50,40,10,9,5,4,1], ["M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"]