Content server: Add an option to control the timeout for making AJAX queries to the server. Fixes #1722016 [Private bug](https://bugs.launchpad.net/calibre/+bug/1722016)

This commit is contained in:
Kovid Goyal 2017-10-18 10:48:56 +05:30
parent a7c4335c2c
commit f26ce3c724
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 38 additions and 22 deletions

View File

@ -48,16 +48,14 @@ def robots(ctx, rd):
return b'User-agent: *\nDisallow: /'
@endpoint('/auto-reload-port', auth_required=False, cache_control='no-cache')
def auto_reload(ctx, rd):
@endpoint('/ajax-setup', auth_required=False, cache_control='no-cache', postprocess=json)
def ajax_setup(ctx, rd):
auto_reload_port = getattr(rd.opts, 'auto_reload_port', 0)
rd.outheaders.set('Content-Type', 'text/plain')
return str(max(0, auto_reload_port))
@endpoint('/allow-console-print', cache_control='no-cache', auth_required=False)
def allow_console_print(ctx, rd):
return 'y' if getattr(rd.opts, 'allow_console_print', False) else 'n'
return {
'auto_reload_port': max(0, auto_reload_port),
'allow_console_print': bool(getattr(rd.opts, 'allow_console_print', False)),
'ajax_timeout': rd.opts.ajax_timeout,
}
print_lock = Lock()

View File

@ -40,6 +40,10 @@ raw_options = (
'timeout', 120.0,
None,
_('Time (in seconds) to wait for a response from the server when making queries'),
'ajax_timeout', 60.0,
None,
_('Total time in seconds to wait for clean shutdown'),
'shutdown_timeout', 5.0,
None,

View File

@ -4,6 +4,15 @@ from __python__ import hash_literals
from gettext import gettext as _
default_timeout = 60
def set_default_timeout(val):
nonlocal default_timeout
default_timeout = val
def encode_query_component(x):
ans = encodeURIComponent(x)
# The following exceptions are to make epubcfi() look better
@ -38,7 +47,7 @@ def absolute_path(path):
return path
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):
def ajax(path, on_complete, on_progress=None, bypass_cache=True, method='GET', query=None, timeout=None, ok_code=200, progress_totals_needed=True):
# Run an AJAX request. on_complete must be a function that accepts three
# arguments: end_type, xhr, ev where end_type is one of 'abort', 'error',
# 'load', 'timeout'. In case end_type is anything other than 'load' you can
@ -47,6 +56,8 @@ def ajax(path, on_complete, on_progress=None, bypass_cache=True, method='GET', q
# where loaded is the number of bytes received, total is the total size.
#
# Returns the xhr object, call xhr.send() to start the request.
if timeout is None:
timeout = default_timeout
query = query or {}
xhr = XMLHttpRequest()
eq = encode_query(query)
@ -62,7 +73,7 @@ def ajax(path, on_complete, on_progress=None, bypass_cache=True, method='GET', q
if is_network_error:
xhr.error_html = str.format(_('Failed to communicate with "{}", network error, is the server running and accessible?'), xhr.request_path)
elif event is 'timeout':
xhr.error_html = str.format(_('Failed to communicate with "{}", timed out after: {} seconds'), xhr.request_path, timeout/1000)
xhr.error_html = str.format(_('Failed to communicate with "{}", timed out after: {} seconds'), xhr.request_path, timeout)
elif event is 'abort':
xhr.error_html = str.format(_('Failed to communicate with "{}", aborted'), xhr.request_path)
else:
@ -99,7 +110,7 @@ def ajax(path, on_complete, on_progress=None, bypass_cache=True, method='GET', q
xhr.addEventListener('load', def(ev): complete_callback('load', ev);)
xhr.addEventListener('timeout', def(ev): complete_callback('timeout', ev);)
xhr.open(method, path)
xhr.timeout = timeout # IE requires timeout to be set after open
xhr.timeout = timeout * 1000 # IE requires timeout to be set after open
return xhr
def ajax_send(path, data, on_complete, on_progress=None, query=None, timeout=30*1000, ok_code=200):

View File

@ -5,7 +5,7 @@ from __python__ import hash_literals
from gettext import gettext as _
import initialize # noqa: unused-import
from ajax import ajax, console_print
from ajax import ajax, console_print, set_default_timeout
from autoreload import create_auto_reload_watcher
from book_list.globals import main_js
from book_list.main import main
@ -50,17 +50,20 @@ else:
# we know are going to be needed immediately.
window.addEventListener('load', main)
ajax('auto-reload-port', def(end_type, xhr, event):
nonlocal autoreload_enabled
ajax('ajax-setup', def(end_type, xhr, event):
nonlocal autoreload_enabled, print
if end_type is 'load':
port = parseInt(xhr.responseText)
try:
data = JSON.parse(xhr.responseText)
except:
return
tim = data.ajax_timeout
if not isNaN(tim) and tim > 0:
set_default_timeout(tim)
port = data.auto_reload_port
if not isNaN(port) and port > 0:
autoreload_enabled = True
create_auto_reload_watcher(port)
).send() # We must bypass cache as otherwise we could get stale port info
ajax('allow-console-print', def(end_type, xhr, event):
nonlocal print
if end_type is 'load':
if xhr.responseText == 'y':
if data.allow_console_print:
print = console_print
).send()
).send() # We must bypass cache as otherwise we could get stale info