Socket listening and socket activation enabled on tornado
Refactoring of server code Updates requirements Improved requirements parsing for versions containing letters
This commit is contained in:
parent
d877fa1c68
commit
d26e60724a
|
@ -61,7 +61,7 @@ def dependency_check(optional=False):
|
||||||
deps = load_dependencies(optional)
|
deps = load_dependencies(optional)
|
||||||
for dep in deps:
|
for dep in deps:
|
||||||
try:
|
try:
|
||||||
dep_version_int = [int(x) for x in dep[0].split('.')]
|
dep_version_int = [int(x) if x.isnumeric() else 0 for x in dep[0].split('.')]
|
||||||
low_check = [int(x) for x in dep[3].split('.')]
|
low_check = [int(x) for x in dep[3].split('.')]
|
||||||
high_check = [int(x) for x in dep[5].split('.')]
|
high_check = [int(x) for x in dep[5].split('.')]
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
|
|
|
@ -21,10 +21,9 @@ import os
|
||||||
import errno
|
import errno
|
||||||
import signal
|
import signal
|
||||||
import socket
|
import socket
|
||||||
import subprocess # nosec
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from gevent.pywsgi import WSGIServer
|
from gevwent.pywsgi import WSGIServer
|
||||||
from .gevent_wsgi import MyWSGIHandler
|
from .gevent_wsgi import MyWSGIHandler
|
||||||
from gevent.pool import Pool
|
from gevent.pool import Pool
|
||||||
from gevent.socket import socket as GeventSocket
|
from gevent.socket import socket as GeventSocket
|
||||||
|
@ -37,6 +36,7 @@ except ImportError:
|
||||||
from .tornado_wsgi import MyWSGIContainer
|
from .tornado_wsgi import MyWSGIContainer
|
||||||
from tornado.httpserver import HTTPServer
|
from tornado.httpserver import HTTPServer
|
||||||
from tornado.ioloop import IOLoop
|
from tornado.ioloop import IOLoop
|
||||||
|
from tornado.netutil import bind_unix_socket
|
||||||
from tornado import version as _version
|
from tornado import version as _version
|
||||||
VERSION = 'Tornado ' + _version
|
VERSION = 'Tornado ' + _version
|
||||||
_GEVENT = False
|
_GEVENT = False
|
||||||
|
@ -101,7 +101,7 @@ class WebServer(object):
|
||||||
SD_LISTEN_FDS_START = 3
|
SD_LISTEN_FDS_START = 3
|
||||||
return GeventSocket(fileno=SD_LISTEN_FDS_START)
|
return GeventSocket(fileno=SD_LISTEN_FDS_START)
|
||||||
|
|
||||||
def _make_gevent_unix_socket(self, socket_file):
|
def _prepare_unix_socket(self, socket_file):
|
||||||
# the socket file must not exist prior to bind()
|
# the socket file must not exist prior to bind()
|
||||||
if os.path.exists(socket_file):
|
if os.path.exists(socket_file):
|
||||||
# avoid nuking regular files and symbolic links (could be a mistype or security issue)
|
# avoid nuking regular files and symbolic links (could be a mistype or security issue)
|
||||||
|
@ -109,32 +109,34 @@ class WebServer(object):
|
||||||
raise OSError(errno.EEXIST, os.strerror(errno.EEXIST), socket_file)
|
raise OSError(errno.EEXIST, os.strerror(errno.EEXIST), socket_file)
|
||||||
os.remove(socket_file)
|
os.remove(socket_file)
|
||||||
|
|
||||||
unix_sock = WSGIServer.get_listener(socket_file, family=socket.AF_UNIX)
|
|
||||||
self.unix_socket_file = socket_file
|
self.unix_socket_file = socket_file
|
||||||
|
|
||||||
# ensure current user and group have r/w permissions, no permissions for other users
|
def _make_gevent_listener(self):
|
||||||
# this way the socket can be shared in a semi-secure manner
|
|
||||||
# between the user running calibre-web and the user running the fronting webserver
|
|
||||||
os.chmod(socket_file, 0o660)
|
|
||||||
|
|
||||||
return unix_sock
|
|
||||||
|
|
||||||
def _make_gevent_socket(self):
|
|
||||||
if os.name != 'nt':
|
if os.name != 'nt':
|
||||||
socket_activated = os.environ.get("LISTEN_FDS")
|
socket_activated = os.environ.get("LISTEN_FDS")
|
||||||
if socket_activated:
|
if socket_activated:
|
||||||
sock = self._make_gevent_socket_activated()
|
sock = self._make_gevent_socket_activated()
|
||||||
return sock, sock.getsockname()
|
sock_info = sock.getsockname()
|
||||||
|
return sock, "systemd-socket:" + _readable_listen_address(sock_info[0], sock_info[1])
|
||||||
unix_socket_file = os.environ.get("CALIBRE_UNIX_SOCKET")
|
unix_socket_file = os.environ.get("CALIBRE_UNIX_SOCKET")
|
||||||
if unix_socket_file:
|
if unix_socket_file:
|
||||||
return self._make_gevent_unix_socket(unix_socket_file), "unix:" + unix_socket_file
|
self._prepare_unix_socket(unix_socket_file)
|
||||||
|
unix_sock = WSGIServer.get_listener(unix_socket_file, family=socket.AF_UNIX)
|
||||||
|
# ensure current user and group have r/w permissions, no permissions for other users
|
||||||
|
# this way the socket can be shared in a semi-secure manner
|
||||||
|
# between the user running calibre-web and the user running the fronting webserver
|
||||||
|
os.chmod(unix_socket_file, 0o660)
|
||||||
|
|
||||||
|
return unix_sock, "unix:" + unix_socket_file
|
||||||
|
|
||||||
if self.listen_address:
|
if self.listen_address:
|
||||||
return (self.listen_address, self.listen_port), None
|
return ((self.listen_address, self.listen_port),
|
||||||
|
_readable_listen_address(self.listen_address, self.listen_port))
|
||||||
|
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
self.listen_address = '0.0.0.0'
|
self.listen_address = '0.0.0.0'
|
||||||
return (self.listen_address, self.listen_port), None
|
return ((self.listen_address, self.listen_port),
|
||||||
|
_readable_listen_address(self.listen_address, self.listen_port))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
address = ('::', self.listen_port)
|
address = ('::', self.listen_port)
|
||||||
|
@ -211,9 +213,7 @@ class WebServer(object):
|
||||||
ssl_args = self.ssl_args or {}
|
ssl_args = self.ssl_args or {}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sock, output = self._make_gevent_socket()
|
sock, output = self._make_gevent_listener()
|
||||||
if output is None:
|
|
||||||
output = _readable_listen_address(self.listen_address, self.listen_port)
|
|
||||||
log.info('Starting Gevent server on %s', output)
|
log.info('Starting Gevent server on %s', output)
|
||||||
self.wsgiserver = WSGIServer(sock, self.app, log=self.access_logger, handler_class=MyWSGIHandler,
|
self.wsgiserver = WSGIServer(sock, self.app, log=self.access_logger, handler_class=MyWSGIHandler,
|
||||||
error_log=log,
|
error_log=log,
|
||||||
|
@ -238,17 +238,43 @@ class WebServer(object):
|
||||||
if os.name == 'nt' and sys.version_info > (3, 7):
|
if os.name == 'nt' and sys.version_info > (3, 7):
|
||||||
import asyncio
|
import asyncio
|
||||||
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
||||||
log.info('Starting Tornado server on %s', _readable_listen_address(self.listen_address, self.listen_port))
|
try:
|
||||||
|
|
||||||
# Max Buffersize set to 200MB
|
# Max Buffersize set to 200MB
|
||||||
http_server = HTTPServer(MyWSGIContainer(self.app),
|
http_server = HTTPServer(MyWSGIContainer(self.app),
|
||||||
max_buffer_size=209700000,
|
max_buffer_size=209700000,
|
||||||
ssl_options=self.ssl_args)
|
ssl_options=self.ssl_args)
|
||||||
|
|
||||||
|
unix_socket_file = os.environ.get("CALIBRE_UNIX_SOCKET")
|
||||||
|
if os.environ.get("LISTEN_FDS") and os.name != 'nt':
|
||||||
|
SD_LISTEN_FDS_START = 3
|
||||||
|
sock = socket.socket(fileno=SD_LISTEN_FDS_START)
|
||||||
|
http_server.add_socket(sock)
|
||||||
|
sock.setblocking(0)
|
||||||
|
socket_name =sock.getsockname()
|
||||||
|
output = "systemd-socket:" + _readable_listen_address(socket_name[0], socket_name[1])
|
||||||
|
# log.error("Tornado server isn't supporting socket activation, normal port is used")
|
||||||
|
elif unix_socket_file and os.name != 'nt':
|
||||||
|
self._prepare_unix_socket(unix_socket_file)
|
||||||
|
output = "unix:" + unix_socket_file
|
||||||
|
unix_socket = bind_unix_socket(self.unix_socket_file)
|
||||||
|
http_server.add_socket(unix_socket)
|
||||||
|
# ensure current user and group have r/w permissions, no permissions for other users
|
||||||
|
# this way the socket can be shared in a semi-secure manner
|
||||||
|
# between the user running calibre-web and the user running the fronting webserver
|
||||||
|
os.chmod(self.unix_socket_file, 0o660)
|
||||||
|
else:
|
||||||
|
output = _readable_listen_address(self.listen_address, self.listen_port)
|
||||||
http_server.listen(self.listen_port, self.listen_address)
|
http_server.listen(self.listen_port, self.listen_address)
|
||||||
|
log.info('Starting Tornado server on %s', output)
|
||||||
|
|
||||||
self.wsgiserver = IOLoop.current()
|
self.wsgiserver = IOLoop.current()
|
||||||
self.wsgiserver.start()
|
self.wsgiserver.start()
|
||||||
# wait for stop signal
|
# wait for stop signal
|
||||||
self.wsgiserver.close(True)
|
self.wsgiserver.close(True)
|
||||||
|
finally:
|
||||||
|
if self.unix_socket_file:
|
||||||
|
os.remove(self.unix_socket_file)
|
||||||
|
self.unix_socket_file = None
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
Werkzeug<3.0.0
|
Werkzeug<3.0.0
|
||||||
APScheduler>=3.6.3,<3.11.0
|
APScheduler>=3.6.3,<3.11.0
|
||||||
Babel>=1.3,<3.0
|
Babel>=1.3,<3.0
|
||||||
Flask-Babel>=0.11.1,<3.2.0
|
Flask-Babel>=0.11.1,<4.1.0
|
||||||
Flask-Login>=0.3.2,<0.6.3
|
Flask-Login>=0.3.2,<0.6.3
|
||||||
Flask-Principal>=0.3.2,<0.5.1
|
Flask-Principal>=0.3.2,<0.5.1
|
||||||
Flask>=1.0.2,<2.4.0
|
Flask>=1.0.2,<2.4.0
|
||||||
|
@ -14,7 +14,7 @@ tornado>=6.3,<6.4
|
||||||
Wand>=0.4.4,<0.7.0
|
Wand>=0.4.4,<0.7.0
|
||||||
unidecode>=0.04.19,<1.4.0
|
unidecode>=0.04.19,<1.4.0
|
||||||
lxml>=3.8.0,<5.0.0
|
lxml>=3.8.0,<5.0.0
|
||||||
flask-wtf>=0.14.2,<1.2.0
|
flask-wtf>=0.14.2,<1.3.0
|
||||||
chardet>=3.0.0,<4.1.0
|
chardet>=3.0.0,<4.1.0
|
||||||
advocate>=1.0.0,<1.1.0
|
advocate>=1.0.0,<1.1.0
|
||||||
Flask-Limiter>=2.3.0,<3.5.0
|
Flask-Limiter>=2.3.0,<3.6.0
|
||||||
|
|
Loading…
Reference in New Issue
Block a user