comparison roundup/scripts/roundup_server.py @ 6972:8e4028669d2a

flake8 fixes.
author John Rouillard <rouilj@ieee.org>
date Tue, 13 Sep 2022 21:12:00 -0400
parents 5129fc03dc1f
children c0d030bd472e
comparison
equal deleted inserted replaced
6971:861511d23a56 6972:8e4028669d2a
18 """Command-line script that runs a server over roundup.cgi.client. 18 """Command-line script that runs a server over roundup.cgi.client.
19 """ 19 """
20 from __future__ import print_function 20 from __future__ import print_function
21 __docformat__ = 'restructuredtext' 21 __docformat__ = 'restructuredtext'
22 22
23 import base64 # decode icon
24 import errno
25 import getopt
26 import io
27 import logging
28 import os
29 import socket
30 import sys # modify sys.path when running in source tree
31 import time
32 import traceback
33 import zlib # decompress icon
34
35 try:
36 # Python 3.
37 import socketserver
38 except ImportError:
39 # Python 2.
40 import SocketServer as socketserver
41
42 try:
43 # Python 2.
44 reload
45 except NameError:
46 # Python 3.
47 from importlib import reload
48
49 try:
50 from OpenSSL import SSL
51 except ImportError:
52 SSL = None
23 53
24 # --- patch sys.path to make sure 'import roundup' finds correct version 54 # --- patch sys.path to make sure 'import roundup' finds correct version
25 import sys
26 import os.path as osp 55 import os.path as osp
27
28 import logging
29 56
30 thisdir = osp.dirname(osp.abspath(__file__)) 57 thisdir = osp.dirname(osp.abspath(__file__))
31 rootdir = osp.dirname(osp.dirname(thisdir)) 58 rootdir = osp.dirname(osp.dirname(thisdir))
32 if (osp.exists(thisdir + '/__init__.py') and 59 if (osp.exists(thisdir + '/__init__.py') and
33 osp.exists(rootdir + '/roundup/__init__.py')): 60 osp.exists(rootdir + '/roundup/__init__.py')):
34 # the script is located inside roundup source code 61 # the script is located inside roundup source code
35 sys.path.insert(0, rootdir) 62 sys.path.insert(0, rootdir)
36 # --/ 63 # --/
37 64
38 65 import roundup.instance # noqa: E402
39 import errno, getopt, io, os, socket, sys, traceback, time 66
40 67 # python version_check raises exception if imported for wrong python version
41 try: 68 from roundup import configuration, version_check # noqa: F401,E402
42 # Python 3. 69 from roundup import __version__ as roundup_version # noqa: E402
43 import socketserver
44 except ImportError:
45 # Python 2.
46 import SocketServer as socketserver
47
48 try:
49 # Python 2.
50 reload
51 except NameError:
52 # Python 3.
53 from importlib import reload
54
55 try:
56 from OpenSSL import SSL
57 except ImportError:
58 SSL = None
59
60 from roundup.anypy.html import html_escape
61
62 # python version check
63 from roundup import configuration, version_check
64 from roundup import __version__ as roundup_version
65
66 # Roundup modules of use here 70 # Roundup modules of use here
67 from roundup.anypy import http_, urllib_ 71 from roundup.anypy import http_, urllib_ # noqa: E402
68 from roundup.anypy.strings import s2b, StringIO 72 from roundup.anypy.html import html_escape # noqa: E402
69 from roundup.cgi import cgitb, client 73 from roundup.anypy.strings import s2b, StringIO # noqa: E402
70 from roundup.cgi.PageTemplates.PageTemplate import PageTemplate 74 from roundup.cgi import cgitb, client # noqa: E402
71 import roundup.instance 75 from roundup.cgi.PageTemplates.PageTemplate import PageTemplate # noqa: E402
72 from roundup.i18n import _ 76 from roundup.i18n import _ # noqa: E402
73 77
74 # "default" favicon.ico 78 # "default" favicon.ico
75 # generate by using "icotool" and tools/base64 79 # generate by using "icotool" and tools/base64
76 import zlib, base64
77 favico = zlib.decompress(base64.b64decode(b''' 80 favico = zlib.decompress(base64.b64decode(b'''
78 eJztjr1PmlEUh59XgVoshdYPWorFIhaRFq0t9pNq37b60lYSTRzcTFw6GAfj5gDYaF0dTB0MxMSE 81 eJztjr1PmlEUh59XgVoshdYPWorFIhaRFq0t9pNq37b60lYSTRzcTFw6GAfj5gDYaF0dTB0MxMSE
79 gQQd3FzKJiEC0UCIUUN1M41pV2JCXySg/0ITn5tfzvmdc+85FwT56HSc81UJjXJsk1UsNcsSqCk1 82 gQQd3FzKJiEC0UCIUUN1M41pV2JCXySg/0ITn5tfzvmdc+85FwT56HSc81UJjXJsk1UsNcsSqCk1
80 BS64lK+vr7OyssLJyQl2ux2j0cjU1BQajYZIJEIwGMRms+H3+zEYDExOTjI2Nsbm5iZWqxWv18vW 83 BS64lK+vr7OyssLJyQl2ux2j0cjU1BQajYZIJEIwGMRms+H3+zEYDExOTjI2Nsbm5iZWqxWv18vW
81 1hZDQ0Ok02kmJiY4Ojpienqa3d1dxsfHUSqVeDwe5ufnyeVyrK6u4nK5ODs7Y3FxEYfDwdzcHCaT 84 1hZDQ0Ok02kmJiY4Ojpienqa3d1dxsfHUSqVeDwe5ufnyeVyrK6u4nK5ODs7Y3FxEYfDwdzcHCaT
93 # Note: the order is important. Preferred multiprocess type 96 # Note: the order is important. Preferred multiprocess type
94 # is the last element of this list. 97 # is the last element of this list.
95 # "debug" means "none" + no tracker/template cache 98 # "debug" means "none" + no tracker/template cache
96 MULTIPROCESS_TYPES = ["debug", "none"] 99 MULTIPROCESS_TYPES = ["debug", "none"]
97 try: 100 try:
98 import threading # nosrc: F401 101 import threading # noqa: F401
99 except ImportError: 102 except ImportError:
100 pass 103 pass
101 else: 104 else:
102 MULTIPROCESS_TYPES.append("thread") 105 MULTIPROCESS_TYPES.append("thread")
103 if hasattr(os, 'fork'): 106 if hasattr(os, 'fork'):
105 DEFAULT_MULTIPROCESS = MULTIPROCESS_TYPES[-1] 108 DEFAULT_MULTIPROCESS = MULTIPROCESS_TYPES[-1]
106 109
107 110
108 def auto_ssl(): 111 def auto_ssl():
109 print(_('WARNING: generating temporary SSL certificate')) 112 print(_('WARNING: generating temporary SSL certificate'))
110 import OpenSSL, random 113 import OpenSSL, random # noqa: E401
111 pkey = OpenSSL.crypto.PKey() 114 pkey = OpenSSL.crypto.PKey()
112 pkey.generate_key(OpenSSL.crypto.TYPE_RSA, 2048) 115 pkey.generate_key(OpenSSL.crypto.TYPE_RSA, 2048)
113 cert = OpenSSL.crypto.X509() 116 cert = OpenSSL.crypto.X509()
114 cert.set_serial_number(random.randint(0, sys.maxsize)) 117 cert.set_serial_number(random.randint(0, sys.maxsize))
115 cert.gmtime_adj_notBefore(0) 118 cert.gmtime_adj_notBefore(0)
116 cert.gmtime_adj_notAfter(60 * 60 * 24 * 365) # one year 119 cert.gmtime_adj_notAfter(60 * 60 * 24 * 365) # one year
117 cert.get_subject().CN = '*' 120 cert.get_subject().CN = '*'
118 cert.get_subject().O = 'Roundup Dummy Certificate' 121 cert.get_subject().O = 'Roundup Dummy Certificate' # noqa: E741
119 cert.get_issuer().CN = 'Roundup Dummy Certificate Authority' 122 cert.get_issuer().CN = 'Roundup Dummy Certificate Authority'
120 cert.get_issuer().O = 'Self-Signed' 123 cert.get_issuer().O = 'Self-Signed' # noqa: E741
121 cert.set_pubkey(pkey) 124 cert.set_pubkey(pkey)
122 cert.sign(pkey, 'sha512') 125 cert.sign(pkey, 'sha512')
123 ctx = SSL.Context(OpenSSL.SSL.TLSv1_2_METHOD) 126 ctx = SSL.Context(OpenSSL.SSL.TLSv1_2_METHOD)
124 ctx.use_privatekey(pkey) 127 ctx.use_privatekey(pkey)
125 ctx.use_certificate(cert) 128 ctx.use_certificate(cert)
262 self.inner_run_cgi() 265 self.inner_run_cgi()
263 except client.NotFound: 266 except client.NotFound:
264 self.send_error(404, self.path) 267 self.send_error(404, self.path)
265 except client.Unauthorised as message: 268 except client.Unauthorised as message:
266 self.send_error(403, '%s (%s)' % (self.path, message)) 269 self.send_error(403, '%s (%s)' % (self.path, message))
267 except: 270 except Exception:
268 exc, val, tb = sys.exc_info() 271 exc, val, tb = sys.exc_info()
269 if hasattr(socket, 'timeout') and isinstance(val, socket.timeout): 272 if hasattr(socket, 'timeout') and isinstance(val, socket.timeout):
270 self.log_error('timeout') 273 self.log_error('timeout')
271 else: 274 else:
272 # it'd be nice to be able to detect if these are going to have 275 # it'd be nice to be able to detect if these are going to have
277 if self.DEBUG_MODE: 280 if self.DEBUG_MODE:
278 try: 281 try:
279 reload(cgitb) 282 reload(cgitb)
280 self.wfile.write(s2b(cgitb.breaker())) 283 self.wfile.write(s2b(cgitb.breaker()))
281 self.wfile.write(s2b(cgitb.html())) 284 self.wfile.write(s2b(cgitb.html()))
282 except: 285 except Exception:
283 s = StringIO() 286 s = StringIO()
284 traceback.print_exc(None, s) 287 traceback.print_exc(None, s)
285 self.wfile.write(b"<pre>") 288 self.wfile.write(b"<pre>")
286 self.wfile.write(s2b(html_escape(s.getvalue()))) 289 self.wfile.write(s2b(html_escape(s.getvalue())))
287 self.wfile.write(b"</pre>\n") 290 self.wfile.write(b"</pre>\n")
294 # out to the logfile 297 # out to the logfile
295 print('EXCEPTION AT', ts) 298 print('EXCEPTION AT', ts)
296 traceback.print_exc() 299 traceback.print_exc()
297 300
298 do_GET = do_POST = do_HEAD = do_PUT = do_DELETE = \ 301 do_GET = do_POST = do_HEAD = do_PUT = do_DELETE = \
299 do_PATCH = do_OPTIONS = run_cgi 302 do_PATCH = do_OPTIONS = run_cgi
300 303
301 def index(self): 304 def index(self):
302 ''' Print up an index of the available trackers 305 ''' Print up an index of the available trackers
303 ''' 306 '''
304 keys = list(self.TRACKER_HOMES.keys()) 307 keys = list(self.TRACKER_HOMES.keys())
318 pt = PageTemplate() 321 pt = PageTemplate()
319 pt.write(template) 322 pt.write(template)
320 extra = {'trackers': self.TRACKERS, 323 extra = {'trackers': self.TRACKERS,
321 'nothing': None, 324 'nothing': None,
322 'true': 1, 325 'true': 1,
323 'false': 0, 326 'false': 0}
324 }
325 w(s2b(pt.pt_render(extra_context=extra))) 327 w(s2b(pt.pt_render(extra_context=extra)))
326 else: 328 else:
327 w(s2b(_('<html><head><title>Roundup trackers index</title></head>\n' 329 w(s2b(_('<html><head><title>Roundup trackers index</title></head>\n'
328 '<body><h1>Roundup trackers index</h1><ol>\n'))) 330 '<body><h1>Roundup trackers index</h1><ol>\n')))
329 keys.sort() 331 keys.sort()
528 self.log_date_time_string(), 530 self.log_date_time_string(),
529 format % args)) 531 format % args))
530 else: 532 else:
531 try: 533 try:
532 http_.server.BaseHTTPRequestHandler.log_message(self, 534 http_.server.BaseHTTPRequestHandler.log_message(self,
533 format, *args) 535 format, *args)
534 except IOError: 536 except IOError:
535 # stderr is no longer viable 537 # stderr is no longer viable
536 pass 538 pass
537 539
538 def start_response(self, headers, response): 540 def start_response(self, headers, response):
616 618
617 619
618 class ServerConfig(configuration.Config): 620 class ServerConfig(configuration.Config):
619 621
620 SETTINGS = ( 622 SETTINGS = (
621 ("main", ( 623 ("main", (
622 (configuration.Option, "host", "localhost", 624 (configuration.Option, "host", "localhost",
623 "Host name of the Roundup web server instance.\n" 625 "Host name of the Roundup web server instance.\n"
624 "If left unconfigured (no 'host' setting) the default\n" 626 "If left unconfigured (no 'host' setting) the default\n"
625 "will be used.\n" 627 "will be used.\n"
626 "If empty, listen on all network interfaces.\n" 628 "If empty, listen on all network interfaces.\n"
726 self.add_option(TrackerHomeOption(self, "trackers", name)) 728 self.add_option(TrackerHomeOption(self, "trackers", name))
727 729
728 def getopt(self, args, short_options="", long_options=(), 730 def getopt(self, args, short_options="", long_options=(),
729 config_load_options=("C", "config"), **options): 731 config_load_options=("C", "config"), **options):
730 options.update(self.OPTIONS) 732 options.update(self.OPTIONS)
731 return configuration.Config.getopt(self, args, 733 return configuration.Config.getopt(
732 short_options, long_options, config_load_options, **options) 734 self, args, short_options, long_options,
735 config_load_options, **options)
733 736
734 def _get_name(self): 737 def _get_name(self):
735 return "Roundup server" 738 return "Roundup server"
736 739
737 def trackers(self): 740 def trackers(self):
774 # perform initial ssl handshake. This will set 777 # perform initial ssl handshake. This will set
775 # internal state correctly so that later closing SSL 778 # internal state correctly so that later closing SSL
776 # socket works (with SSL end-handshake started) 779 # socket works (with SSL end-handshake started)
777 self.request.do_handshake() 780 self.request.do_handshake()
778 RoundupRequestHandler.protocol_version = \ 781 RoundupRequestHandler.protocol_version = \
779 self.CONFIG["HTTP_VERSION"] 782 self.CONFIG["HTTP_VERSION"]
780 RoundupRequestHandler.setup(self) 783 RoundupRequestHandler.setup(self)
781 784
782 def finish(self): 785 def finish(self):
783 RoundupRequestHandler.finish(self) 786 RoundupRequestHandler.finish(self)
784 if self.CONFIG["SSL"]: 787 if self.CONFIG["SSL"]:
825 except socket.error as e: 828 except socket.error as e:
826 if e.args[0] == errno.EADDRINUSE: 829 if e.args[0] == errno.EADDRINUSE:
827 raise socket.error(_("Unable to bind to port %s, " 830 raise socket.error(_("Unable to bind to port %s, "
828 "port already in use.") % self["PORT"]) 831 "port already in use.") % self["PORT"])
829 if e.args[0] == errno.EACCES: 832 if e.args[0] == errno.EACCES:
830 raise socket.error(_("Unable to bind to port %(port)s, " 833 raise socket.error(_(
831 "access not allowed, " 834 "Unable to bind to port %(port)s, "
832 "errno: %(errno)s %(msg)s" % { 835 "access not allowed, "
833 "port": self["PORT"], 836 "errno: %(errno)s %(msg)s" % {
834 "errno": e.args[0], 837 "port": self["PORT"],
835 "msg": e.args[1] } 838 "errno": e.args[0],
839 "msg": e.args[1]}
836 )) 840 ))
837 841
838 raise 842 raise
839 # change user and/or group 843 # change user and/or group
840 setgid(self["GROUP"]) 844 setgid(self["GROUP"])
841 setuid(self["USER"]) 845 setuid(self["USER"])
842 # return the server 846 # return the server
867 import servicemanager 871 import servicemanager
868 self.ReportServiceStatus(win32service.SERVICE_START_PENDING) 872 self.ReportServiceStatus(win32service.SERVICE_START_PENDING)
869 config = ServerConfig() 873 config = ServerConfig()
870 (optlist, args) = config.getopt(sys.argv[1:]) 874 (optlist, args) = config.getopt(sys.argv[1:])
871 if not config["LOGFILE"]: 875 if not config["LOGFILE"]:
872 servicemanager.LogMsg(servicemanager.EVENTLOG_ERROR_TYPE, 876 servicemanager.LogMsg(
873 servicemanager.PYS_SERVICE_STOPPED, 877 servicemanager.EVENTLOG_ERROR_TYPE,
878 servicemanager.PYS_SERVICE_STOPPED,
874 (self._svc_display_name_, "\r\nMissing logfile option")) 879 (self._svc_display_name_, "\r\nMissing logfile option"))
875 self.ReportServiceStatus(win32service.SERVICE_STOPPED) 880 self.ReportServiceStatus(win32service.SERVICE_STOPPED)
876 return 881 return
877 config.set_logging() 882 config.set_logging()
878 self.server = config.get_server() 883 self.server = config.get_server()

Roundup Issue Tracker: http://roundup-tracker.org/