diff --git a/gluon/globals.py b/gluon/globals.py index 44c9b794..fc14ceff 100644 --- a/gluon/globals.py +++ b/gluon/globals.py @@ -56,8 +56,6 @@ except ImportError: have_minify = False -regex_session_id = re.compile('^([\w\-]+/)?[\w\-\.]+$') - __all__ = ['Request', 'Response', 'Session'] current = threading.local() # thread-local storage for request-scope globals @@ -357,9 +355,11 @@ class Request(Storage): """ cmd_opts = global_settings.cmd_options # checking if this is called within the scheduler or within the shell - # in addition to checking if it's not a cronjob - if ((cmd_opts and (cmd_opts.shell or cmd_opts.scheduler)) - or global_settings.cronjob or self.is_https): + # in addition to checking if it's a cronjob + # FIXME: cmd_opts.scheduler does not imply that + # we are running in the scheduler + if (self.is_https or cmd_opts and ( + cmd_opts.shell or cmd_opts.scheduler or cmd_opts.cronjob)): current.session.secure() else: current.session.forget() @@ -602,6 +602,7 @@ class Response(Storage): # for attachment settings and backward compatibility keys = [item.lower() for item in headers] if attachment: + # FIXME: should be done like in next download method if filename is None: attname = "" else: @@ -654,6 +655,7 @@ class Response(Storage): Downloads from http://..../download/filename """ + from pydal.helpers.regex import REGEX_UPLOAD_PATTERN from pydal.exceptions import NotAuthorizedException, NotFoundException current.session.forget(current.response) @@ -661,10 +663,10 @@ class Response(Storage): if not request.args: raise HTTP(404) name = request.args[-1] - items = re.compile('(?P.*?)\.(?P.*?)\..*').match(name) + items = re.match(REGEX_UPLOAD_PATTERN, name) if not items: raise HTTP(404) - (t, f) = (items.group('table'), items.group('field')) + t = items.group('table'); f = items.group('field') try: field = db[t][f] except (AttributeError, KeyError): @@ -801,6 +803,8 @@ class Session(Storage): - session_filename """ + REGEX_SESSION_FILE = r'^(?:[\w-]+/)?[\w.-]+$' + def connect(self, request=None, response=None, @@ -891,7 +895,7 @@ class Session(Storage): response.session_file = None # check if the session_id points to a valid sesion filename if response.session_id: - if not regex_session_id.match(response.session_id): + if not re.match(self.REGEX_SESSION_FILE, response.session_id): response.session_id = None else: response.session_filename = \ diff --git a/gluon/newcron.py b/gluon/newcron.py index a415b530..5eba24e0 100644 --- a/gluon/newcron.py +++ b/gluon/newcron.py @@ -31,7 +31,6 @@ _cron_subprocs = [] def absolute_path_link(path): """ Returns an absolute path for the destination of a symlink - """ if os.path.islink(path): link = os.readlink(path) @@ -73,16 +72,17 @@ class extcron(threading.Thread): class hardcron(threading.Thread): - def __init__(self, applications_parent): + def __init__(self, applications_parent, apps=None): threading.Thread.__init__(self) self.setDaemon(True) self.path = applications_parent - crondance(self.path, 'hard', startup=True) + self.apps = apps + crondance(self.path, 'hard', startup=True, apps=self.apps) def launch(self): if not _cron_stopping: logger.debug('hard cron invocation') - crondance(self.path, 'hard', startup=False) + crondance(self.path, 'hard', startup=False, apps=self.apps) def run(self): s = sched.scheduler(time.time, time.sleep) @@ -95,15 +95,16 @@ class hardcron(threading.Thread): class softcron(threading.Thread): - def __init__(self, applications_parent): + def __init__(self, applications_parent, apps=None): threading.Thread.__init__(self) self.path = applications_parent - # crondance(self.path, 'soft', startup=True) + self.apps = apps + # crondance(self.path, 'soft', startup=True, apps=self.apps) def run(self): if not _cron_stopping: logger.debug('soft cron invocation') - crondance(self.path, 'soft', startup=False) + crondance(self.path, 'soft', startup=False, apps=self.apps) class Token(object): @@ -270,7 +271,10 @@ class cronlauncher(threading.Thread): def crondance(applications_parent, ctype='soft', startup=False, apps=None): - # TODO: docstring + """ + Does the periodic job of cron service: read the crontab(s) and launch + the various commands. + """ apppath = os.path.join(applications_parent, 'applications') token = Token(applications_parent) cronmaster = token.acquire(startup=startup) @@ -299,7 +303,7 @@ def crondance(applications_parent, ctype='soft', startup=False, apps=None): base_commands.append(w2p_path) if applications_parent != global_settings.gluon_parent: base_commands.extend(('-f', applications_parent)) - base_commands.extend(('-J', + base_commands.extend(('--cronjob', '--no-banner', '--nogui', '--plain', # FIXME: this should not be needed since we are # not launching the web server '-a', '""')) diff --git a/gluon/packages/dal b/gluon/packages/dal index f3401dd8..f1cf5aab 160000 --- a/gluon/packages/dal +++ b/gluon/packages/dal @@ -1 +1 @@ -Subproject commit f3401dd8c05d089cb49cfd1215e2991388eace09 +Subproject commit f1cf5aab12b839ec168cc194f10c33e026b3de6b diff --git a/gluon/widget.py b/gluon/widget.py index 68e3b87a..bed5a665 100644 --- a/gluon/widget.py +++ b/gluon/widget.py @@ -216,6 +216,14 @@ class web2pyDialog(object): self.bannerarea.after(1000, self.update_canvas) # IP + # retrieves the list of server IP addresses + try: + if_ips = list(set( # no duplicates + [addrinfo[4][0] for addrinfo in getipaddrinfo(socket.getfqdn()) + if not is_loopback_ip_address(addrinfo=addrinfo)])) + except socket.gaierror: + if_ips = [] + tkinter.Label(self.root, text='Server IP:', bg=bg_color, justify=tkinter.RIGHT).grid(row=4, @@ -226,7 +234,7 @@ class web2pyDialog(object): row = 4 ips = [('127.0.0.1', 'Local (IPv4)')] + \ ([('::1', 'Local (IPv6)')] if socket.has_ipv6 else []) + \ - [(ip, 'Public') for ip in options.ips] + \ + [(ip, 'Public') for ip in if_ips] + \ [('0.0.0.0', 'Public')] for ip, legend in ips: self.ips[ip] = tkinter.Radiobutton( @@ -704,7 +712,7 @@ web2py will attempt to run a GUI to ask for it when starting the web server metavar='APPNAME', help=\ 'run web2py in interactive shell or IPython (if installed) with ' \ 'specified appname (if app does not exist it will be created). ' \ - 'APPNAME like a/c/f?x=y (c,f and vars x,y optional)') + 'APPNAME like a/c/f?x=y (c, f and vars optional)') parser.add_option('-B', '--bpython', default=False, @@ -752,7 +760,7 @@ web2py will attempt to run a GUI to ask for it when starting the web server default=None, metavar='TEST_PATH', help=\ 'run doctests in web2py environment; ' \ - 'TEST_PATH like a/c/f (c,f optional)') + 'TEST_PATH like a/c/f (c, f optional)') parser.add_option('-C', '--cron', dest='extcron', default=False, @@ -777,7 +785,9 @@ web2py will attempt to run a GUI to ask for it when starting the web server parser.add_option('-J', '--cronjob', default=False, action='store_true', - help='identify cron-initiated command') + # NOTE: help suppressed because this option is + # intended for internal use only + help=optparse.SUPPRESS_HELP) parser.add_option('-L', '--config', default='', @@ -840,6 +850,10 @@ web2py will attempt to run a GUI to ask for it when starting the web server # TODO: warn or error if args (should be no unparsed arguments) options.args = other_args + if options.taskbar and os.name != 'nt': + # TODO: warn and disable taskbar instead of exit + die('taskbar not supported on this platform') + if options.config.endswith('.py'): options.config = options.config[:-3] if options.config: @@ -853,20 +867,6 @@ web2py will attempt to run a GUI to ask for it when starting the web server if hasattr(options, key): setattr(options, key, getattr(options2, key)) - # store in options.ips the list of server IP addresses - try: - options.ips = list(set( # no duplicates - [addrinfo[4][0] for addrinfo in getipaddrinfo(socket.getfqdn()) - if not is_loopback_ip_address(addrinfo=addrinfo)])) - except socket.gaierror: - options.ips = [] - - if options.cronjob: - global_settings.cronjob = True # tell the world - options.plain = True # cronjobs use a plain shell - options.nobanner = True - options.nogui = True - # transform options.interfaces, in the form # "ip1:port1:key1:cert1:ca_cert1;[ip2]:port2;ip3:port3:key3:cert3" # (no spaces; optional key:cert:ca_cert indicate SSL), into @@ -1074,11 +1074,6 @@ def start(cron=True): # if no password provided and have Tk library start GUI (when not # explicitly disabled), we also need a GUI to put in taskbar (system tray) # when requested - - # FIXME: this check should be done first - if options.taskbar and os.name != 'nt': - die('taskbar not supported on this platform') - root = None if (not options.nogui and options.password == '') or options.taskbar: