def load(routes="routes.py", app=None): """ load: read and parse routes.py (called from main.py at web2py initialization time) store results in params """ symbols = {} if app is None: path = abspath(routes) else: path = abspath("applications", app, routes) if not os.path.exists(path): return try: routesfp = open(path, "r") exec routesfp.read().replace("\r\n", "\n") in symbols routesfp.close() logger.debug("URL rewrite is on. configuration in %s" % path) except SyntaxError, e: routesfp.close() logger.error( "Your %s has a syntax error " % path + "Please fix it before you restart web2py\n" + traceback.format_exc() ) raise e
def create_missing_folders(): if not global_settings.web2py_runtime_gae: for path in ("applications", "deposit", "site-packages", "logs"): path = abspath(path, gluon=True) if not os.path.exists(path): os.mkdir(path) paths = (global_settings.gluon_parent, abspath("site-packages", gluon=True), abspath("gluon", gluon=True), "") [add_path_first(path) for path in paths]
def create_missing_folders(): if not global_settings.web2py_runtime_gae: for path in ('applications', 'deposit', 'site-packages', 'logs'): path = abspath(path, gluon=True) if not os.path.exists(path): os.mkdir(path) paths = (global_settings.gluon_parent, abspath('site-packages', gluon=True), abspath('gluon', gluon=True), '') [add_path_first(path) for path in paths]
def make_apptree(): "build a temporary applications tree" # applications/ os.mkdir(abspath('applications')) # applications/app/ for app in ('admin', 'examples', 'welcome'): os.mkdir(abspath('applications', app)) # applications/app/(controllers, static) for subdir in ('controllers', 'static'): os.mkdir(abspath('applications', app, subdir)) # applications/admin/controllers/*.py for ctr in ('appadmin', 'default', 'gae', 'mercurial', 'shell', 'wizard'): open(abspath('applications', 'admin', 'controllers', '%s.py' % ctr), 'w').close() # applications/examples/controllers/*.py for ctr in ('ajax_examples', 'appadmin', 'default', 'global', 'spreadsheet'): open(abspath('applications', 'examples', 'controllers', '%s.py' % ctr), 'w').close() # applications/welcome/controllers/*.py for ctr in ('appadmin', 'default'): open(abspath('applications', 'welcome', 'controllers', '%s.py' % ctr), 'w').close() # create an app-specific routes.py for examples app routes = open(abspath('applications', 'examples', 'routes.py'), 'w') routes.write("routers=dict(examples=dict(default_function='exdef'))") routes.close() # create language files for examples app for lang in ('en', 'it'): os.mkdir(abspath('applications', 'examples', 'static', lang)) open(abspath('applications', 'examples', 'static', lang, 'file'), 'w').close()
def save_password(password, port): """ used by main() to save the password in the parameters_port.py file. """ password_file = abspath('parameters_%i.py' % port) if password == '<random>': # make up a new password chars = string.letters + string.digits password = ''.join([random.choice(chars) for i in range(8)]) cpassword = CRYPT()(password)[0] print '******************* IMPORTANT!!! ************************' print 'your admin password is "%s"' % password print '*********************************************************' elif password == '<recycle>': # reuse the current password if any if exists(password_file): return else: password = '' elif password.startswith('<pam_user:'******'w') if password: fp.write('password="******"\n' % cpassword) else: fp.write('password=None\n') fp.close()
def read_possible_plurals(): """ create list of all possible plural rules files result is cached to increase speed """ global pcache pdir = abspath('gluon', 'contrib', 'rules') plurals = {} # scan rules directory for plural_rules-*.py files: for pname in [ f for f in listdir(pdir, regex_plural_rules) if osep not in f ]: lang = pname[13:-3] fname = ospath.join(pdir, pname) mtime = ostat(fname).st_mtime if lang in pcache and pcache[lang][2] == mtime: # if plural_file's mtime wasn't changed - use previous value: plurals[lang] = pcache[lang] else: # otherwise, reread plural_rules-file: if 'plural_rules-' + lang in cfs: n, f1, f2, status = read_plural_rules(lang) else: n, f1, f2, status = read_plural_rules_aux(fname) plurals[lang] = (n, pname, mtime, status) pcache = plurals return pcache
def read_possible_plurals(): """ create list of all possible plural rules files result is cached to increase speed """ global pcache pdir = abspath('gluon','contrib','rules') plurals = {} # scan rules directory for plural_rules-*.py files: for pname in [f for f in listdir(pdir, regex_plural_rules) if osep not in f]: lang=pname[13:-3] fname=ospath.join(pdir, pname) mtime=ostat(fname).st_mtime if lang in pcache and pcache[lang][2] == mtime: # if plural_file's mtime wasn't changed - use previous value: plurals[lang]=pcache[lang] else: # otherwise, reread plural_rules-file: if 'plural_rules-'+lang in cfs: n,f1,f2,status=read_plural_rules(lang) else: n,f1,f2,status=read_plural_rules_aux(fname) plurals[lang]=(n, pname, mtime, status) pcache=plurals return pcache
def save_password(password, port): """ used by main() to save the password in the parameters_port.py file. """ password_file = abspath('parameters_%i.py' % port) if password == '<random>': # make up a new password chars = string.letters + string.digits password = ''.join([random.choice(chars) for i in range(8)]) cpassword = CRYPT()(password)[0] print '******************* IMPORTANT!!! ************************' print 'your admin password is "%s"' % password print '*********************************************************' elif password == '<recycle>': # reuse the current password if any if os.path.exists(password_file): return else: password = '' elif password.startswith('<pam_user:'******'w') if password: fp.write('password="******"\n' % cpassword) else: fp.write('password=None\n') fp.close()
def load(routes='routes.py', app=None, data=None, rdict=None): """ load: read (if file) and parse routes store results in params (called from main.py at web2py initialization time) If data is present, it's used instead of the routes.py contents. If rdict is present, it must be a dict to be used for routers (unit test) """ global params global routers if app is None: # reinitialize global params_apps params_apps = dict() params = _params_default(app=None) # regex rewrite parameters thread.routes = params # default to base regex rewrite parameters routers = None if isinstance(rdict, dict): symbols = dict(routers=rdict) path = 'rdict' else: if data is not None: path = 'routes' else: if app is None: path = abspath(routes) else: path = abspath('applications', app, routes) if not os.path.exists(path): return routesfp = open(path, 'r') data = routesfp.read().replace('\r\n','\n') routesfp.close() symbols = {} try: exec (data + '\n') in symbols except SyntaxError, e: logger.error( '%s has a syntax error and will not be loaded\n' % path + traceback.format_exc()) raise e
def load(routes='routes.py', app=None, data=None, rdict=None): """ load: read (if file) and parse routes store results in params (called from main.py at web2py initialization time) If data is present, it's used instead of the routes.py contents. If rdict is present, it must be a dict to be used for routers (unit test) """ global params global routers if app is None: # reinitialize global params_apps params_apps = dict() params = _params_default(app=None) # regex rewrite parameters thread.routes = params # default to base regex rewrite parameters routers = None if isinstance(rdict, dict): symbols = dict(routers=rdict) path = 'rdict' else: if data is not None: path = 'routes' else: if app is None: path = abspath(routes) else: path = abspath('applications', app, routes) if not os.path.exists(path): return routesfp = open(path, 'r') data = routesfp.read().replace('\r\n', '\n') routesfp.close() symbols = {} try: exec(data + '\n') in symbols except SyntaxError, e: logger.error('%s has a syntax error and will not be loaded\n' % path + traceback.format_exc()) raise e
def start(self): import newcron import logging import logging.config from settings import global_settings from fileutils import abspath from os.path import exists, join self.log('web2py Cron service starting') if not self.chdir(): return if len(sys.argv) == 2: opt_mod = sys.argv[1] else: opt_mod = self._exe_args_ options = __import__(opt_mod, [], [], '') logpath = abspath(join(options.folder, "logging.conf")) if exists(logpath): logging.config.fileConfig(logpath) else: logging.basicConfig() logger = logging.getLogger("web2py.cron") global_settings.web2py_crontype = 'external' if options.scheduler: # -K apps = [app.strip() for app in options.scheduler.split( ',') if check_existent_app(options, app.strip())] else: apps = None misfire_gracetime = float(options.misfire_gracetime) if 'misfire_gracetime' in dir(options) else 0.0 logger.info('Starting Window cron service with %0.2f secs gracetime.' % misfire_gracetime) self._started = True wait_full_min = lambda: 60 - time.time() % 60 while True: try: if wait_full_min() >= misfire_gracetime: # an offset of max. 5 secs before full minute (e.g. time.sleep(60) == 58.99 secs) self.extcron = newcron.extcron(options.folder, apps=apps) self.extcron.start() time.sleep(wait_full_min()) else: logger.debug('time.sleep() offset detected: %0.3f s' % wait_full_min()) while wait_full_min() <= misfire_gracetime: pass if apps != None: break if not self._started: break except Exception, ex: self.extcron = None self.log_error('%s, restarting service.' % ex) logger.exception('Exception! Restarting Windows cron service.' % ex) self.start()
def load(routes='routes.py', app=None): """ load: read and parse routes.py (called from main.py at web2py initialization time) store results in params """ if app is None: path = abspath(routes) else: path = abspath('applications', app, routes) if not os.path.exists(path): return symbols = {} try: routesfp = open(path, 'r') exec routesfp.read().replace('\r\n', '\n') in symbols routesfp.close() except SyntaxError, e: routesfp.close() logger.error('%s has a syntax error and will not be loaded\n' % path + traceback.format_exc()) raise e
def load(routes='routes.py', app=None): """ load: read and parse routes.py (called from main.py at web2py initialization time) store results in params """ if app is None: path = abspath(routes) else: path = abspath('applications', app, routes) if not os.path.exists(path): return symbols = {} try: routesfp = open(path, 'r') exec routesfp.read().replace('\r\n','\n') in symbols routesfp.close() except SyntaxError, e: routesfp.close() logger.error( '%s has a syntax error and will not be loaded\n' % path + traceback.format_exc()) raise e
def upgrade(request, url='http://web2py.com'): """ Upgrades web2py (src, osx, win) is a new version is posted. It detects whether src, osx or win is running and downloads the right one Parameters ---------- request: the current request object, required to determine version and path url: the incomplete url where to locate the latest web2py actual url is url+'/examples/static/web2py_(src|osx|win).zip' Returns ------- True on success, False on failure (network problem or old version) """ web2py_version = request.env.web2py_version gluon_parent = request.env.gluon_parent if not gluon_parent.endswith('/'): gluon_parent = gluon_parent + '/' (check, version) = check_new_version(web2py_version, url+'/examples/default/version') if not check: return (False, 'Already latest version') if os.path.exists(os.path.join(gluon_parent, 'web2py.exe')): version_type = 'win' destination = gluon_parent subfolder = 'web2py/' elif gluon_parent.endswith('/Contents/Resources/'): version_type = 'osx' destination = gluon_parent[:-len('/Contents/Resources/')] subfolder = 'web2py/web2py.app/' else: version_type = 'src' destination = gluon_parent subfolder = 'web2py/' full_url = url + '/examples/static/web2py_%s.zip' % version_type filename = abspath('web2py_%s_downloaded.zip' % version_type) file = None try: file = open(filename,'wb') file.write(urllib.urlopen(full_url).read()) file.close() except Exception,e: file and file.close() return False, e
def upgrade(request, url="http://web2py.com"): """ Upgrades web2py (src, osx, win) is a new version is posted. It detects whether src, osx or win is running and downloads the right one Parameters ---------- request: the current request object, required to determine version and path url: the incomplete url where to locate the latest web2py actual url is url+'/examples/static/web2py_(src|osx|win).zip' Returns ------- True on success, False on failure (network problem or old version) """ web2py_version = request.env.web2py_version gluon_parent = request.env.gluon_parent if not gluon_parent.endswith("/"): gluon_parent = gluon_parent + "/" (check, version) = check_new_version(web2py_version, url + "/examples/default/version") if not check: return (False, "Already latest version") if os.path.exists(os.path.join(gluon_parent, "web2py.exe")): version_type = "win" destination = gluon_parent subfolder = "web2py/" elif gluon_parent.endswith("/Contents/Resources/"): version_type = "osx" destination = gluon_parent[: -len("/Contents/Resources/")] subfolder = "web2py/web2py.app/" else: version_type = "src" destination = gluon_parent subfolder = "web2py/" full_url = url + "/examples/static/web2py_%s.zip" % version_type filename = abspath("web2py_%s_downloaded.zip" % version_type) file = None try: write_file(filename, urllib.urlopen(full_url).read(), "wb") except Exception, e: return False, e
def read_possible_plurals(): """ create list of all possible plural rules files result is cached to increase speed """ pdir = abspath('gluon','contrib','rules') plurals = {} # scan rules directory for plural_rules-*.py files: for pname in os.listdir(pdir): if not isdir(pname) and regex_plural_rules.match(pname): lang = pname[13:-3] fname = ospath.join(pdir, pname) n, f1, f2, status = read_global_plural_rules(fname) if status == 'ok': plurals[lang] = (lang, n, f1, f2, pname) plurals['default'] = ('default', DEFAULT_NPLURALS, DEFAULT_GET_PLURAL_ID, DEFAULT_CONSTRUCTOR_PLURAL_FORM, None) return plurals
def unzip(filename, dir, subfolder=''): """ Unzips filename into dir (.zip only, no .gz etc) if subfolder!='' it unzip only files in subfolder """ filename = abspath(filename) if not zipfile.is_zipfile(filename): raise RuntimeError('Not a valid zipfile') zf = zipfile.ZipFile(filename) if not subfolder.endswith('/'): subfolder = subfolder + '/' n = len(subfolder) for name in sorted(zf.namelist()): if not name.startswith(subfolder): continue #print name[n:] if name.endswith('/'): folder = os.path.join(dir, name[n:]) if not os.path.exists(folder): os.mkdir(folder) else: write_file(os.path.join(dir, name[n:]), zf.read(name), 'wb')
def unzip(filename, dir, subfolder=''): """ Unzips filename into dir (.zip only, no .gz etc) if subfolder!='' it unzip only files in subfolder """ filename = abspath(filename) if not zipfile.is_zipfile(filename): raise RuntimeError, 'Not a valid zipfile' zf = zipfile.ZipFile(filename) if not subfolder.endswith('/'): subfolder = subfolder + '/' n = len(subfolder) for name in sorted(zf.namelist()): if not name.startswith(subfolder): continue #print name[n:] if name.endswith('/'): folder = os.path.join(dir,name[n:]) if not os.path.exists(folder): os.mkdir(folder) else: write_file(os.path.join(dir, name[n:]), zf.read(name), 'wb')
def make_apptree(): "build a temporary applications tree" # applications/ os.mkdir(abspath("applications")) # applications/app/ for app in ("admin", "examples", "welcome"): os.mkdir(abspath("applications", app)) # applications/app/(controllers, static) for subdir in ("controllers", "static"): os.mkdir(abspath("applications", app, subdir)) # applications/admin/controllers/*.py for ctr in ("appadmin", "default", "gae", "mercurial", "shell", "wizard"): open(abspath("applications", "admin", "controllers", "%s.py" % ctr), "w").close() # applications/examples/controllers/*.py for ctr in ("ajax_examples", "appadmin", "default", "global", "spreadsheet"): open(abspath("applications", "examples", "controllers", "%s.py" % ctr), "w").close() # applications/welcome/controllers/*.py for ctr in ("appadmin", "default"): open(abspath("applications", "welcome", "controllers", "%s.py" % ctr), "w").close() # create an app-specific routes.py for examples app routes = open(abspath("applications", "examples", "routes.py"), "w") routes.write("default_function='exdef'\n") routes.close()
def __init__( self, ip='127.0.0.1', port=8000, password='', pid_filename='httpserver.pid', log_filename='httpserver.log', profiler_filename=None, ssl_certificate=None, ssl_private_key=None, ssl_ca_certificate=None, min_threads=None, max_threads=None, server_name=None, request_queue_size=5, timeout=10, socket_timeout = 1, shutdown_timeout=None, # Rocket does not use a shutdown timeout path=None, interfaces=None # Rocket is able to use several interfaces - must be list of socket-tuples as string ): """ starts the web server. """ if interfaces: # if interfaces is specified, it must be tested for rocket parameter correctness # not necessarily completely tested (e.g. content of tuples or ip-format) import types if isinstance(interfaces,types.ListType): for i in interfaces: if not isinstance(i,types.TupleType): raise "Wrong format for rocket interfaces parameter - see http://packages.python.org/rocket/" else: raise "Wrong format for rocket interfaces parameter - see http://packages.python.org/rocket/" if path: # if a path is specified change the global variables so that web2py # runs from there instead of cwd or os.environ['web2py_path'] global web2py_path path = os.path.normpath(path) web2py_path = path global_settings.applications_parent = path os.chdir(path) [add_path_first(p) for p in (path, abspath('site-packages'), "")] custom_import_install(web2py_path) if os.path.exists("logging.conf"): logging.config.fileConfig("logging.conf") save_password(password, port) self.pid_filename = pid_filename if not server_name: server_name = socket.gethostname() logger.info('starting web server...') rocket.SERVER_NAME = server_name rocket.SOCKET_TIMEOUT = socket_timeout sock_list = [ip, port] if not ssl_certificate or not ssl_private_key: logger.info('SSL is off') elif not rocket.ssl: logger.warning('Python "ssl" module unavailable. SSL is OFF') elif not os.path.exists(ssl_certificate): logger.warning('unable to open SSL certificate. SSL is OFF') elif not os.path.exists(ssl_private_key): logger.warning('unable to open SSL private key. SSL is OFF') else: sock_list.extend([ssl_private_key, ssl_certificate]) if ssl_ca_certificate: sock_list.append(ssl_ca_certificate) logger.info('SSL is ON') app_info = {'wsgi_app': appfactory(wsgibase, log_filename, profiler_filename) } self.server = rocket.Rocket(interfaces or tuple(sock_list), method='wsgi', app_info=app_info, min_threads=min_threads, max_threads=max_threads, queue_size=int(request_queue_size), timeout=int(timeout), handle_signals=False, )
# routers = params.routers # establish routers if present if isinstance(routers, dict): routers = Storage(routers) if routers is not None: router = _router_default() if routers.BASE: router.update(routers.BASE) routers.BASE = router # scan each app in applications/ # create a router, if routers are in use # parse the app-specific routes.py if present # all_apps = [] for appname in [app for app in os.listdir(abspath('applications')) if not app.startswith('.')]: if os.path.isdir(abspath('applications', appname)) and \ os.path.isdir(abspath('applications', appname, 'controllers')): all_apps.append(appname) if routers: router = Storage(routers.BASE) # new copy if appname in routers: for key in routers[appname].keys(): if key in ROUTER_BASE_KEYS: raise SyntaxError, "BASE-only key '%s' in router '%s'" % (key, appname) router.update(routers[appname]) routers[appname] = router if os.path.exists(abspath('applications', appname, routes)): load(routes, appname) if routers:
def crondance(applications_parent, ctype='soft', startup=False): apppath = os.path.join(applications_parent, 'applications') cron_path = os.path.join(apppath, 'admin', 'cron') token = Token(cron_path) cronmaster = token.acquire(startup=startup) if not cronmaster: return now_s = time.localtime() checks = (('min', now_s.tm_min), ('hr', now_s.tm_hour), ('mon', now_s.tm_mon), ('dom', now_s.tm_mday), ('dow', (now_s.tm_wday + 1) % 7)) apps = [ x for x in os.listdir(apppath) if os.path.isdir(os.path.join(apppath, x)) ] for app in apps: if _cron_stopping: break apath = os.path.join(apppath, app) cronpath = os.path.join(apath, 'cron') crontab = os.path.join(cronpath, 'crontab') if not os.path.exists(crontab): continue try: cronlines = fileutils.readlines_file(crontab, 'rt') lines = [ x.strip() for x in cronlines if x.strip() and not x.strip().startswith('#') ] tasks = [parsecronline(cline) for cline in lines] except Exception, e: logger.error('WEB2PY CRON: crontab read error %s' % e) continue for task in tasks: if _cron_stopping: break commands = [sys.executable] w2p_path = fileutils.abspath('web2py.py', gluon=True) if os.path.exists(w2p_path): commands.append(w2p_path) if global_settings.applications_parent != global_settings.gluon_parent: commands.extend(('-f', global_settings.applications_parent)) citems = [(k in task and not v in task[k]) for k, v in checks] task_min = task.get('min', []) if not task: continue elif not startup and task_min == [-1]: continue elif task_min != [-1] and reduce(lambda a, b: a or b, citems): continue logger.info('WEB2PY CRON (%s): %s executing %s in %s at %s' \ % (ctype, app, task.get('cmd'), os.getcwd(), datetime.datetime.now())) action, command, models = False, task['cmd'], '' if command.startswith('**'): (action, models, command) = (True, '', command[2:]) elif command.startswith('*'): (action, models, command) = (True, '-M', command[1:]) else: action = False if action and command.endswith('.py'): commands.extend(( '-J', # cron job models, # import models? '-S', app, # app name '-a', '"<recycle>"', # password '-R', command)) # command shell = True elif action: commands.extend(( '-J', # cron job models, # import models? '-S', app + '/' + command, # app name '-a', '"<recycle>"')) # password shell = True else: commands = command shell = False try: cronlauncher(commands, shell=shell).start() except Exception, e: logger.warning( 'WEB2PY CRON: Execution error for %s: %s' \ % (task.get('cmd'), e))
def read_plural_rules(lang): filename = abspath('gluon','contrib','rules', 'plural_rules-%s.py' % lang) return getcfs('plural_rules-'+lang, filename, lambda: read_plural_rules_aux(filename))
for sym in ('routes_app', 'routes_in', 'routes_out'): if sym in symbols: for (k, v) in symbols[sym]: p[sym].append(compile_re(k, v)) for sym in ('routes_onerror', 'routes_apps_raw', 'error_handler','error_message', 'error_message_ticket', 'default_application','default_controller', 'default_function'): if sym in symbols: p[sym] = symbols[sym] if app is None: global params params = p # install base rewrite parameters for appname in os.listdir('applications'): if os.path.exists(abspath('applications', appname, routes)): load(routes, appname) else: params_apps[app] = p logger.debug('URL rewrite is on. configuration in %s' % path) def filter_uri(e, regexes, tag, default=None): "filter incoming URI against a list of regexes" query = e.get('QUERY_STRING', None) path = e['PATH_INFO'] host = e.get('HTTP_HOST', 'localhost').lower() original_uri = path + (query and '?'+query or '') i = host.find(':') if i > 0: host = host[:i] key = '%s:%s://%s:%s %s' % \
def wsgibase(environ, responder): """ this is the gluon wsgi application. the first function called when a page is requested (static or dynamic). it can be called by paste.httpserver or by apache mod_wsgi. - fills request with info - the environment variables, replacing '.' with '_' - adds web2py path and version info - compensates for fcgi missing path_info and query_string - validates the path in url The url path must be either: 1. for static pages: - /<application>/static/<file> 2. for dynamic pages: - /<application>[/<controller>[/<function>[/<sub>]]][.<extension>] - (sub may go several levels deep, currently 3 levels are supported: sub1/sub2/sub3) The naming conventions are: - application, controller, function and extension may only contain [a-zA-Z0-9_] - file and sub may also contain '-', '=', '.' and '/' """ current.__dict__.clear() request = Request() response = Response() session = Session() request.env.web2py_path = global_settings.applications_parent request.env.web2py_version = web2py_version request.env.update(global_settings) static_file = False try: try: try: # ################################################## # handle fcgi missing path_info and query_string # select rewrite parameters # rewrite incoming URL # parse rewritten header variables # parse rewritten URL # serve file if static # ################################################## if not environ.get('PATH_INFO',None) and \ environ.get('REQUEST_URI',None): # for fcgi, get path_info and query_string from request_uri items = environ['REQUEST_URI'].split('?') environ['PATH_INFO'] = items[0] if len(items) > 1: environ['QUERY_STRING'] = items[1] else: environ['QUERY_STRING'] = '' if not environ.get('HTTP_HOST',None): environ['HTTP_HOST'] = '%s:%s' % (environ.get('SERVER_NAME'), environ.get('SERVER_PORT')) (static_file, environ) = rewrite.url_in(request, environ) if static_file: if request.env.get('query_string', '')[:10] == 'attachment': response.headers['Content-Disposition'] = 'attachment' response.stream(static_file, request=request) # ################################################## # fill in request items # ################################################## http_host = request.env.http_host.split(':',1)[0] local_hosts = [http_host,'::1','127.0.0.1','::ffff:127.0.0.1'] if not global_settings.web2py_runtime_gae: local_hosts += [socket.gethostname(), socket.gethostbyname(http_host)] request.client = get_client(request.env) request.folder = abspath('applications', request.application) + os.sep x_req_with = str(request.env.http_x_requested_with).lower() request.ajax = x_req_with == 'xmlhttprequest' request.cid = request.env.http_web2py_component_element request.is_local = request.env.remote_addr in local_hosts request.is_https = request.env.wsgi_url_scheme \ in ['https', 'HTTPS'] or request.env.https == 'on' # ################################################## # compute a request.uuid to be used for tickets and toolbar # ################################################## response.uuid = request.compute_uuid() # ################################################## # access the requested application # ################################################## if not os.path.exists(request.folder): if request.application == \ rewrite.thread.routes.default_application \ and request.application != 'welcome': request.application = 'welcome' redirect(Url(r=request)) elif rewrite.thread.routes.error_handler: _handler = rewrite.thread.routes.error_handler redirect(Url(_handler['application'], _handler['controller'], _handler['function'], args=request.application)) else: raise HTTP(404, rewrite.thread.routes.error_message \ % 'invalid request', web2py_error='invalid application') elif not request.is_local and \ os.path.exists(os.path.join(request.folder,'DISABLED')): raise HTTP(200, "<html><body><h1>Down for maintenance</h1></body></html>") request.url = Url(r=request, args=request.args, extension=request.raw_extension) # ################################################## # build missing folders # ################################################## create_missing_app_folders(request) # ################################################## # get the GET and POST data # ################################################## parse_get_post_vars(request, environ) # ################################################## # expose wsgi hooks for convenience # ################################################## request.wsgi.environ = environ_aux(environ,request) request.wsgi.start_response = \ lambda status='200', headers=[], \ exec_info=None, response=response: \ start_response_aux(status, headers, exec_info, response) request.wsgi.middleware = \ lambda *a: middleware_aux(request,response,*a) # ################################################## # load cookies # ################################################## if request.env.http_cookie: try: request.cookies.load(request.env.http_cookie) except Cookie.CookieError, e: pass # invalid cookies # ################################################## # try load session or create new session file # ################################################## session.connect(request, response) # ################################################## # set no-cache headers # ################################################## response.headers['Content-Type'] = \ contenttype('.'+request.extension) response.headers['Cache-Control'] = \ 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0' response.headers['Expires'] = \ time.strftime('%a, %d %b %Y %H:%M:%S GMT', time.gmtime()) response.headers['Pragma'] = 'no-cache' # ################################################## # run controller # ################################################## serve_controller(request, response, session) except HTTP, http_response: if static_file: return http_response.to(responder) if request.body: request.body.close() # ################################################## # on success, try store session in database # ################################################## session._try_store_in_db(request, response) # ################################################## # on success, commit database # ################################################## if response.do_not_commit is True: BaseAdapter.close_all_instances(None) elif response._custom_commit: response._custom_commit() else: BaseAdapter.close_all_instances('commit') # ################################################## # if session not in db try store session on filesystem # this must be done after trying to commit database! # ################################################## session._try_store_on_disk(request, response) # ################################################## # store cookies in headers # ################################################## if request.cid: if response.flash and not 'web2py-component-flash' in http_response.headers: http_response.headers['web2py-component-flash'] = \ str(response.flash).replace('\n','') if response.js and not 'web2py-component-command' in http_response.headers: http_response.headers['web2py-component-command'] = \ response.js.replace('\n','') if session._forget and \ response.session_id_name in response.cookies: del response.cookies[response.session_id_name] elif session._secure: response.cookies[response.session_id_name]['secure'] = True if len(response.cookies)>0: http_response.headers['Set-Cookie'] = \ [str(cookie)[11:] for cookie in response.cookies.values()] ticket=None except RestrictedError, e: if request.body: request.body.close() # ################################################## # on application error, rollback database # ################################################## ticket = e.log(request) or 'unknown' if response._custom_rollback: response._custom_rollback() else: BaseAdapter.close_all_instances('rollback') http_response = \ HTTP(500, rewrite.thread.routes.error_message_ticket % \ dict(ticket=ticket), web2py_error='ticket %s' % ticket)
if global_settings.db_sessions is not True: global_settings.db_sessions = set() global_settings.gluon_parent = os.environ.get('web2py_path', os.getcwd()) global_settings.applications_parent = global_settings.gluon_parent web2py_path = global_settings.applications_parent # backward compatibility global_settings.app_folders = set() global_settings.debugging = False custom_import_install(web2py_path) create_missing_folders() # set up logging for subsequent imports import logging import logging.config logpath = abspath("logging.conf") if os.path.exists(logpath): logging.config.fileConfig(abspath("logging.conf")) else: logging.basicConfig() logger = logging.getLogger("web2py") from restricted import RestrictedError from http import HTTP, redirect from globals import Request, Response, Session from compileapp import build_environment, run_models_in, \ run_controller_in, run_view_in from fileutils import copystream from contenttype import contenttype from dal import BaseAdapter from settings import global_settings
def start(self): import newcron import logging import logging.config from settings import global_settings from fileutils import abspath from os.path import exists, join self.log('web2py Cron service starting') if not self.chdir(): return if len(sys.argv) == 2: opt_mod = sys.argv[1] else: opt_mod = self._exe_args_ options = __import__(opt_mod, [], [], '') logpath = abspath(join(options.folder, "logging.conf")) if exists(logpath): logging.config.fileConfig(logpath) else: logging.basicConfig() logger = logging.getLogger("web2py.cron") global_settings.web2py_crontype = 'external' if options.scheduler: # -K apps = [ app.strip() for app in options.scheduler.split(',') if check_existent_app(options, app.strip()) ] else: apps = None misfire_gracetime = float( options.misfire_gracetime) if 'misfire_gracetime' in dir( options) else 0.0 logger.info('Starting Window cron service with %0.2f secs gracetime.' % misfire_gracetime) self._started = True wait_full_min = lambda: 60 - time.time() % 60 while True: try: if wait_full_min( ) >= misfire_gracetime: # an offset of max. 5 secs before full minute (e.g. time.sleep(60) == 58.99 secs) self.extcron = newcron.extcron(options.folder, apps=apps) self.extcron.start() time.sleep(wait_full_min()) else: logger.debug('time.sleep() offset detected: %0.3f s' % wait_full_min()) while wait_full_min() <= misfire_gracetime: pass if apps != None: break if not self._started: break except Exception, ex: self.extcron = None self.log_error('%s, restarting service.' % ex) logger.exception( 'Exception! Restarting Windows cron service.' % ex) self.start()
# set sys.path to ("", gluon_parent/site-packages, gluon_parent, ...) # # this is wrong: # web2py_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # because we do not want the path to this file which may be Library.zip # # gluon_parent is the directory containing gluon, web2py.py, logging.conf and the handlers. # applications_parent (web2py_path) is the directory containing applications/ and routes.py # The two are identical unless web2py_path is changed via the web2py.py -f folder option # main.web2py_path is the same as applications_parent (for backward compatibility) # global_settings.gluon_parent = os.environ.get('web2py_path', os.getcwd()) global_settings.applications_parent = global_settings.gluon_parent web2py_path = global_settings.applications_parent # backward compatibility for path in (global_settings.gluon_parent, abspath('site-packages', gluon=True), ""): try: sys.path.remove(path) except ValueError: pass sys.path.insert(0, path) # set up logging for subsequent imports import logging import logging.config logpath = abspath("logging.conf") if os.path.exists(logpath): logging.config.fileConfig(abspath("logging.conf")) else: logging.basicConfig() logger = logging.getLogger("web2py")
def appfactory(wsgiapp=wsgibase, logfilename='httpserver.log', profiler_dir=None): """ generates a wsgi application that does logging and profiling and calls wsgibase .. function:: gluon.main.appfactory( [wsgiapp=wsgibase [, logfilename='httpserver.log' [, profilerfilename='profiler.log']]]) """ if profiler_dir: profiler_dir = abspath(profiler_dir) logger.warn('profiler is on. will use dir %s', profiler_dir) if not os.path.isdir(profiler_dir): try: os.makedirs(profiler_dir) except: raise BaseException, "Can't create dir %s" % profiler_dir filepath = pjoin(profiler_dir, 'wtest') try: filehandle = open( filepath, 'w' ) filehandle.close() os.unlink(filepath) except IOError: raise BaseException, "Unable to write to dir %s" % profiler_dir def app_with_logging(environ, responder): """ a wsgi app that does logging and profiling and calls wsgibase """ status_headers = [] def responder2(s, h): """ wsgi responder app """ status_headers.append(s) status_headers.append(h) return responder(s, h) time_in = time.time() ret = [0] if not profiler_dir: ret[0] = wsgiapp(environ, responder2) else: import cProfile prof = cProfile.Profile() prof.enable() ret[0] = wsgiapp(environ, responder2) prof.disable() destfile = pjoin(profiler_dir, "req_%s.prof" % web2py_uuid()) prof.dump_stats(destfile) try: line = '%s, %s, %s, %s, %s, %s, %f\n' % ( environ['REMOTE_ADDR'], datetime.datetime.today().strftime('%Y-%m-%d %H:%M:%S'), environ['REQUEST_METHOD'], environ['PATH_INFO'].replace(',', '%2C'), environ['SERVER_PROTOCOL'], (status_headers[0])[:3], time.time() - time_in, ) if not logfilename: sys.stdout.write(line) elif isinstance(logfilename, str): write_file(logfilename, line, 'a') else: logfilename.write(line) except: pass return ret[0] return app_with_logging
def __init__( self, ip='127.0.0.1', port=8000, password='', pid_filename='httpserver.pid', log_filename='httpserver.log', profiler_filename=None, ssl_certificate=None, ssl_private_key=None, ssl_ca_certificate=None, min_threads=None, max_threads=None, server_name=None, request_queue_size=5, timeout=10, socket_timeout=1, shutdown_timeout=None, # Rocket does not use a shutdown timeout path=None, interfaces=None # Rocket is able to use several interfaces - must be list of socket-tuples as string ): """ starts the web server. """ if interfaces: # if interfaces is specified, it must be tested for rocket parameter correctness # not necessarily completely tested (e.g. content of tuples or ip-format) import types if isinstance(interfaces, types.ListType): for i in interfaces: if not isinstance(i, types.TupleType): raise "Wrong format for rocket interfaces parameter - see http://packages.python.org/rocket/" else: raise "Wrong format for rocket interfaces parameter - see http://packages.python.org/rocket/" if path: # if a path is specified change the global variables so that web2py # runs from there instead of cwd or os.environ['web2py_path'] global web2py_path path = os.path.normpath(path) web2py_path = path global_settings.applications_parent = path os.chdir(path) [add_path_first(p) for p in (path, abspath('site-packages'), "")] if exists("logging.conf"): logging.config.fileConfig("logging.conf") save_password(password, port) self.pid_filename = pid_filename if not server_name: server_name = socket.gethostname() logger.info('starting web server...') rocket.SERVER_NAME = server_name rocket.SOCKET_TIMEOUT = socket_timeout sock_list = [ip, port] if not ssl_certificate or not ssl_private_key: logger.info('SSL is off') elif not rocket.ssl: logger.warning('Python "ssl" module unavailable. SSL is OFF') elif not exists(ssl_certificate): logger.warning('unable to open SSL certificate. SSL is OFF') elif not exists(ssl_private_key): logger.warning('unable to open SSL private key. SSL is OFF') else: sock_list.extend([ssl_private_key, ssl_certificate]) if ssl_ca_certificate: sock_list.append(ssl_ca_certificate) logger.info('SSL is ON') app_info = { 'wsgi_app': appfactory(wsgibase, log_filename, profiler_filename) } self.server = rocket.Rocket( interfaces or tuple(sock_list), method='wsgi', app_info=app_info, min_threads=min_threads, max_threads=max_threads, queue_size=int(request_queue_size), timeout=int(timeout), handle_signals=False, )
# routers = params.routers # establish routers if present if isinstance(routers, dict): routers = Storage(routers) if routers is not None: router = _router_default() if routers.BASE: router.update(routers.BASE) routers.BASE = router # scan each app in applications/ # create a router, if routers are in use # parse the app-specific routes.py if present # all_apps = [] for appname in os.listdir(abspath('applications')): if os.path.isdir(abspath('applications', appname)): all_apps.append(appname) if routers: router = Storage(routers.BASE) # new copy if appname in routers: for key in routers[appname].keys(): if key in ROUTER_BASE_KEYS: raise SyntaxError, "BASE-only key '%s' in router '%s'" % (key, appname) router.update(routers[appname]) routers[appname] = router if os.path.exists(abspath('applications', appname, routes)): load(routes, appname) if routers: load_routers(all_apps)
def crondance(applications_parent, ctype="soft", startup=False, apps=None): apppath = os.path.join(applications_parent, "applications") cron_path = os.path.join(applications_parent) token = Token(cron_path) cronmaster = token.acquire(startup=startup) if not cronmaster: return now_s = time.localtime() checks = ( ("min", now_s.tm_min), ("hr", now_s.tm_hour), ("mon", now_s.tm_mon), ("dom", now_s.tm_mday), ("dow", (now_s.tm_wday + 1) % 7), ) if apps is None: apps = [x for x in os.listdir(apppath) if os.path.isdir(os.path.join(apppath, x))] full_apath_links = set() for app in apps: if _cron_stopping: break apath = os.path.join(apppath, app) # if app is a symbolic link to other app, skip it full_apath_link = absolute_path_link(apath) if full_apath_link in full_apath_links: continue else: full_apath_links.add(full_apath_link) cronpath = os.path.join(apath, "cron") crontab = os.path.join(cronpath, "crontab") if not os.path.exists(crontab): continue try: cronlines = fileutils.readlines_file(crontab, "rt") lines = [x.strip() for x in cronlines if x.strip() and not x.strip().startswith("#")] tasks = [parsecronline(cline) for cline in lines] except Exception, e: logger.error("WEB2PY CRON: crontab read error %s" % e) continue for task in tasks: if _cron_stopping: break if sys.executable.lower().endswith("pythonservice.exe"): _python_exe = os.path.join(sys.exec_prefix, "python.exe") else: _python_exe = sys.executable commands = [_python_exe] w2p_path = fileutils.abspath("web2py.py", gluon=True) if os.path.exists(w2p_path): commands.append(w2p_path) if applications_parent != global_settings.gluon_parent: commands.extend(("-f", applications_parent)) citems = [(k in task and not v in task[k]) for k, v in checks] task_min = task.get("min", []) if not task: continue elif not startup and task_min == [-1]: continue elif task_min != [-1] and reduce(lambda a, b: a or b, citems): continue logger.info( "WEB2PY CRON (%s): %s executing %s in %s at %s" % (ctype, app, task.get("cmd"), os.getcwd(), datetime.datetime.now()) ) action, command, models = False, task["cmd"], "" if command.startswith("**"): (action, models, command) = (True, "", command[2:]) elif command.startswith("*"): (action, models, command) = (True, "-M", command[1:]) else: action = False if action and command.endswith(".py"): commands.extend( ( "-J", # cron job models, # import models? "-S", app, # app name "-a", '"<recycle>"', # password "-R", command, ) ) # command elif action: commands.extend( ( "-J", # cron job models, # import models? "-S", app + "/" + command, # app name "-a", '"<recycle>"', ) ) # password else: commands = command # from python docs: # You do not need shell=True to run a batch file or # console-based executable. shell = False try: cronlauncher(commands, shell=shell).start() except Exception, e: logger.warning("WEB2PY CRON: Execution error for %s: %s" % (task.get("cmd"), e))
# # See <web2py-root-dir>/router.example.py for parameter's detail #------------------------------------------------------------------------------------- # To enable this route file you must do the steps: # # 1. rename <web2py-root-dir>/router.example.py to routes.py # 2. rename this APP/routes.example.py to APP/routes.py # (where APP - is your application directory) # 3. restart web2py (or reload routes in web2py admin interfase) # # YOU CAN COPY THIS FILE TO ANY APPLICATION'S ROOT DIRECTORY WITHOUT CHANGES! from fileutils import abspath from languages import read_possible_languages possible_languages = read_possible_languages(abspath('applications', app)) #NOTE! app - is an application based router's parameter with name of an # application. E.g.'welcome' routers = { app: dict(default_language=possible_languages['default'][0], languages=[lang for lang in possible_languages if lang != 'default']) } routers = dict(BASE=dict(default_application='py2manager'), ) routes_onerror = [('*/*', '/py2manager/static/error.html')] #NOTE! To change language in your application using these rules add this line #in one of your models files: # if request.uri_language: T.force(request.uri_language)
def read_plural_rules(lang): filename = abspath('gluon', 'contrib', 'rules', 'plural_rules-%s.py' % lang) return getcfs('plural_rules-' + lang, filename, lambda: read_plural_rules_aux(filename))
def wsgibase(environ, responder): """ this is the gluon wsgi application. the first function called when a page is requested (static or dynamic). it can be called by paste.httpserver or by apache mod_wsgi. - fills request with info - the environment variables, replacing '.' with '_' - adds web2py path and version info - compensates for fcgi missing path_info and query_string - validates the path in url The url path must be either: 1. for static pages: - /<application>/static/<file> 2. for dynamic pages: - /<application>[/<controller>[/<function>[/<sub>]]][.<extension>] - (sub may go several levels deep, currently 3 levels are supported: sub1/sub2/sub3) The naming conventions are: - application, controller, function and extension may only contain [a-zA-Z0-9_] - file and sub may also contain '-', '=', '.' and '/' """ current.__dict__.clear() request = Request() response = Response() session = Session() env = request.env env.web2py_path = global_settings.applications_parent env.web2py_version = web2py_version env.update(global_settings) static_file = False try: try: try: # ################################################## # handle fcgi missing path_info and query_string # select rewrite parameters # rewrite incoming URL # parse rewritten header variables # parse rewritten URL # serve file if static # ################################################## fixup_missing_path_info(environ) (static_file, version, environ) = url_in(request, environ) response.status = env.web2py_status_code or response.status if static_file: if environ.get('QUERY_STRING', '').startswith( 'attachment'): response.headers['Content-Disposition'] \ = 'attachment' if version: response.headers['Cache-Control'] = 'max-age=315360000' response.headers[ 'Expires'] = 'Thu, 31 Dec 2037 23:59:59 GMT' response.stream(static_file, request=request) # ################################################## # fill in request items # ################################################## app = request.application # must go after url_in! if not global_settings.local_hosts: local_hosts = set(['127.0.0.1', '::ffff:127.0.0.1', '::1']) if not global_settings.web2py_runtime_gae: try: fqdn = socket.getfqdn() local_hosts.add(socket.gethostname()) local_hosts.add(fqdn) local_hosts.update([ ip[4][0] for ip in socket.getaddrinfo( fqdn, 0)]) if env.server_name: local_hosts.add(env.server_name) local_hosts.update([ ip[4][0] for ip in socket.getaddrinfo( env.server_name, 0)]) except (socket.gaierror, TypeError): pass global_settings.local_hosts = list(local_hosts) else: local_hosts = global_settings.local_hosts client = get_client(env) x_req_with = str(env.http_x_requested_with).lower() request.update( client = client, folder = abspath('applications', app) + os.sep, ajax = x_req_with == 'xmlhttprequest', cid = env.http_web2py_component_element, is_local = env.remote_addr in local_hosts, is_https = env.wsgi_url_scheme in HTTPS_SCHEMES or \ request.env.http_x_forwarded_proto in HTTPS_SCHEMES \ or env.https == 'on') request.compute_uuid() # requires client request.url = environ['PATH_INFO'] # ################################################## # access the requested application # ################################################## if not exists(request.folder): if app == rwthread.routes.default_application \ and app != 'welcome': redirect(URL('welcome', 'default', 'index')) elif rwthread.routes.error_handler: _handler = rwthread.routes.error_handler redirect(URL(_handler['application'], _handler['controller'], _handler['function'], args=app)) else: raise HTTP(404, rwthread.routes.error_message % 'invalid request', web2py_error='invalid application') elif not request.is_local and \ exists(pjoin(request.folder, 'DISABLED')): raise HTTP(503, "<html><body><h1>Temporarily down for maintenance</h1></body></html>") # ################################################## # build missing folders # ################################################## create_missing_app_folders(request) # ################################################## # get the GET and POST data # ################################################## parse_get_post_vars(request, environ) # ################################################## # expose wsgi hooks for convenience # ################################################## request.wsgi.environ = environ_aux(environ, request) request.wsgi.start_response = \ lambda status='200', headers=[], \ exec_info=None, response=response: \ start_response_aux(status, headers, exec_info, response) request.wsgi.middleware = \ lambda *a: middleware_aux(request, response, *a) # ################################################## # load cookies # ################################################## if env.http_cookie: try: request.cookies.load(env.http_cookie) except Cookie.CookieError, e: pass # invalid cookies # ################################################## # try load session or create new session file # ################################################## if not env.web2py_disable_session: session.connect(request, response) # ################################################## # run controller # ################################################## if global_settings.debugging and app != "admin": import gluon.debug # activate the debugger gluon.debug.dbg.do_debug(mainpyfile=request.folder) serve_controller(request, response, session) except HTTP, http_response: if static_file: return http_response.to(responder, env=env) if request.body: request.body.close() # ################################################## # on success, try store session in database # ################################################## session._try_store_in_db(request, response) # ################################################## # on success, commit database # ################################################## if response.do_not_commit is True: BaseAdapter.close_all_instances(None) # elif response._custom_commit: # response._custom_commit() elif response.custom_commit: BaseAdapter.close_all_instances(response.custom_commit) else: BaseAdapter.close_all_instances('commit') # ################################################## # if session not in db try store session on filesystem # this must be done after trying to commit database! # ################################################## session._try_store_in_cookie_or_file(request, response) if request.cid: if response.flash: http_response.headers['web2py-component-flash'] = urllib2.quote(xmlescape(response.flash).replace('\n', '')) if response.js: http_response.headers['web2py-component-command'] = response.js.replace('\n', '') # ################################################## # store cookies in headers # ################################################## rcookies = response.cookies if session._forget and response.session_id_name in rcookies: del rcookies[response.session_id_name] elif session._secure: rcookies[response.session_id_name]['secure'] = True http_response.cookies2headers(rcookies) ticket = None except RestrictedError, e: if request.body: request.body.close() # ################################################## # on application error, rollback database # ################################################## ticket = e.log(request) or 'unknown' if response._custom_rollback: response._custom_rollback() else: BaseAdapter.close_all_instances('rollback') http_response = \ HTTP(500, rwthread.routes.error_message_ticket % dict(ticket=ticket), web2py_error='ticket %s' % ticket)
def wsgibase(environ, responder): """ this is the gluon wsgi application. the first function called when a page is requested (static or dynamic). it can be called by paste.httpserver or by apache mod_wsgi. - fills request with info - the environment variables, replacing '.' with '_' - adds web2py path and version info - compensates for fcgi missing path_info and query_string - validates the path in url The url path must be either: 1. for static pages: - /<application>/static/<file> 2. for dynamic pages: - /<application>[/<controller>[/<function>[/<sub>]]][.<extension>] - (sub may go several levels deep, currently 3 levels are supported: sub1/sub2/sub3) The naming conventions are: - application, controller, function and extension may only contain [a-zA-Z0-9_] - file and sub may also contain '-', '=', '.' and '/' """ current.__dict__.clear() request = Request() response = Response() session = Session() request.env.web2py_path = global_settings.applications_parent request.env.web2py_version = web2py_version request.env.update(global_settings) static_file = False try: try: try: # ################################################## # handle fcgi missing path_info and query_string # select rewrite parameters # rewrite incoming URL # parse rewritten header variables # parse rewritten URL # serve file if static # ################################################## if not environ.get('PATH_INFO',None) and \ environ.get('REQUEST_URI',None): # for fcgi, get path_info and query_string from request_uri items = environ['REQUEST_URI'].split('?') environ['PATH_INFO'] = items[0] if len(items) > 1: environ['QUERY_STRING'] = items[1] else: environ['QUERY_STRING'] = '' if not environ.get('HTTP_HOST',None): environ['HTTP_HOST'] = '%s:%s' % (environ.get('SERVER_NAME'), environ.get('SERVER_PORT')) (static_file, environ) = rewrite.url_in(request, environ) if static_file: if environ.get('QUERY_STRING', '')[:10] == 'attachment': response.headers['Content-Disposition'] = 'attachment' response.stream(static_file, request=request) # ################################################## # fill in request items # ################################################## http_host = request.env.http_host.split(':',1)[0] local_hosts = [http_host,'::1','127.0.0.1','::ffff:127.0.0.1'] if not global_settings.web2py_runtime_gae: local_hosts.append(socket.gethostname()) try: local_hosts.append(socket.gethostbyname(http_host)) except socket.gaierror: pass request.client = get_client(request.env) if not is_valid_ip_address(request.client): raise HTTP(400,"Bad Request (request.client=%s)" % \ request.client) request.folder = abspath('applications', request.application) + os.sep x_req_with = str(request.env.http_x_requested_with).lower() request.ajax = x_req_with == 'xmlhttprequest' request.cid = request.env.http_web2py_component_element request.is_local = request.env.remote_addr in local_hosts request.is_https = request.env.wsgi_url_scheme \ in ['https', 'HTTPS'] or request.env.https == 'on' # ################################################## # compute a request.uuid to be used for tickets and toolbar # ################################################## response.uuid = request.compute_uuid() # ################################################## # access the requested application # ################################################## if not os.path.exists(request.folder): if request.application == \ rewrite.thread.routes.default_application \ and request.application != 'welcome': request.application = 'welcome' redirect(Url(r=request)) elif rewrite.thread.routes.error_handler: _handler = rewrite.thread.routes.error_handler redirect(Url(_handler['application'], _handler['controller'], _handler['function'], args=request.application)) else: raise HTTP(404, rewrite.thread.routes.error_message \ % 'invalid request', web2py_error='invalid application') elif not request.is_local and \ os.path.exists(os.path.join(request.folder,'DISABLED')): raise HTTP(503, "<html><body><h1>Temporarily down for maintenance</h1></body></html>") request.url = Url(r=request, args=request.args, extension=request.raw_extension) # ################################################## # build missing folders # ################################################## create_missing_app_folders(request) # ################################################## # get the GET and POST data # ################################################## parse_get_post_vars(request, environ) # ################################################## # expose wsgi hooks for convenience # ################################################## request.wsgi.environ = environ_aux(environ,request) request.wsgi.start_response = \ lambda status='200', headers=[], \ exec_info=None, response=response: \ start_response_aux(status, headers, exec_info, response) request.wsgi.middleware = \ lambda *a: middleware_aux(request,response,*a) # ################################################## # load cookies # ################################################## if request.env.http_cookie: try: request.cookies.load(request.env.http_cookie) except Cookie.CookieError, e: pass # invalid cookies # ################################################## # try load session or create new session file # ################################################## session.connect(request, response) # ################################################## # set no-cache headers # ################################################## response.headers['Content-Type'] = \ contenttype('.'+request.extension) response.headers['Cache-Control'] = \ 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0' response.headers['Expires'] = \ time.strftime('%a, %d %b %Y %H:%M:%S GMT', time.gmtime()) response.headers['Pragma'] = 'no-cache' # ################################################## # run controller # ################################################## if global_settings.debugging and request.application != "admin": import gluon.debug # activate the debugger and wait to reach application code gluon.debug.dbg.do_debug(mainpyfile=request.folder) serve_controller(request, response, session) except HTTP, http_response: if static_file: return http_response.to(responder) if request.body: request.body.close() # ################################################## # on success, try store session in database # ################################################## session._try_store_in_db(request, response) # ################################################## # on success, commit database # ################################################## if response.do_not_commit is True: BaseAdapter.close_all_instances(None) # elif response._custom_commit: # response._custom_commit() elif response.custom_commit: BaseAdapter.close_all_instances(response.custom_commit) else: BaseAdapter.close_all_instances('commit') # ################################################## # if session not in db try store session on filesystem # this must be done after trying to commit database! # ################################################## session._try_store_on_disk(request, response) # ################################################## # store cookies in headers # ################################################## if request.cid: if response.flash and not 'web2py-component-flash' \ in http_response.headers: http_response.headers['web2py-component-flash'] = \ urllib2.quote(xmlescape(response.flash)\ .replace('\n','')) if response.js and not 'web2py-component-command' \ in http_response.headers: http_response.headers['web2py-component-command'] = \ response.js.replace('\n','') if session._forget and \ response.session_id_name in response.cookies: del response.cookies[response.session_id_name] elif session._secure: response.cookies[response.session_id_name]['secure'] = True http_response.cookies2headers(response.cookies) ticket=None except RestrictedError, e: if request.body: request.body.close() # ################################################## # on application error, rollback database # ################################################## ticket = e.log(request) or 'unknown' if response._custom_rollback: response._custom_rollback() else: BaseAdapter.close_all_instances('rollback') http_response = \ HTTP(500, rewrite.thread.routes.error_message_ticket % \ dict(ticket=ticket), web2py_error='ticket %s' % ticket)
def load_routers(all_apps): "load-time post-processing of routers" for app in routers.keys(): # initialize apps with routers that aren't present, on behalf of unit tests if app not in all_apps: all_apps.append(app) router = Storage(routers.BASE) # new copy if app != 'BASE': for key in routers[app].keys(): if key in ROUTER_BASE_KEYS: raise SyntaxError, "BASE-only key '%s' in router '%s'" % (key, app) router.update(routers[app]) routers[app] = router router = routers[app] for key in router.keys(): if key not in ROUTER_KEYS: raise SyntaxError, "unknown key '%s' in router '%s'" % (key, app) if not router.controllers: router.controllers = set() elif not isinstance(router.controllers, str): router.controllers = set(router.controllers) if router.languages: router.languages = set(router.languages) else: router.languages = set() if app != 'BASE': for base_only in ROUTER_BASE_KEYS: router.pop(base_only, None) if 'domain' in router: routers.BASE.domains[router.domain] = app if isinstance(router.controllers, str) and router.controllers == 'DEFAULT': router.controllers = set() if os.path.isdir(abspath('applications', app)): cpath = abspath('applications', app, 'controllers') for cname in os.listdir(cpath): if os.path.isfile(abspath(cpath, cname)) and cname.endswith('.py'): router.controllers.add(cname[:-3]) if router.controllers: router.controllers.add('static') router.controllers.add(router.default_controller) if router.functions: if isinstance(router.functions, (set, tuple, list)): functions = set(router.functions) if isinstance(router.default_function, str): functions.add(router.default_function) # legacy compatibility router.functions = { router.default_controller: functions } for controller in router.functions: router.functions[controller] = set(router.functions[controller]) else: router.functions = dict() if isinstance(routers.BASE.applications, str) and routers.BASE.applications == 'ALL': routers.BASE.applications = list(all_apps) if routers.BASE.applications: routers.BASE.applications = set(routers.BASE.applications) else: routers.BASE.applications = set() for app in routers.keys(): # set router name router = routers[app] router.name = app # compile URL validation patterns router._acfe_match = re.compile(router.acfe_match) router._file_match = re.compile(router.file_match) if router.args_match: router._args_match = re.compile(router.args_match) # convert path_prefix to a list of path elements if router.path_prefix: if isinstance(router.path_prefix, str): router.path_prefix = router.path_prefix.strip('/').split('/') # rewrite BASE.domains as tuples # # key: 'domain[:port]' -> (domain, port) # value: 'application[/controller] -> (application, controller) # (port and controller may be None) # domains = dict() if routers.BASE.domains: for (domain, app) in [(d.strip(':'), a.strip('/')) for (d, a) in routers.BASE.domains.items()]: port = None if ':' in domain: (domain, port) = domain.split(':') ctlr = None fcn = None if '/' in app: (app, ctlr) = app.split('/', 1) if ctlr and '/' in ctlr: (ctlr, fcn) = ctlr.split('/') if app not in all_apps and app not in routers: raise SyntaxError, "unknown app '%s' in domains" % app domains[(domain, port)] = (app, ctlr, fcn) routers.BASE.domains = domains
custom_import_install(web2py_path) create_missing_folders() # set up logging for subsequent imports import logging import logging.config # This needed to prevent exception on Python 2.5: # NameError: name 'gluon' is not defined # See http://bugs.python.org/issue1436 import gluon.messageboxhandler logging.gluon = gluon logpath = abspath("logging.conf") if os.path.exists(logpath): logging.config.fileConfig(abspath("logging.conf")) else: logging.basicConfig() logger = logging.getLogger("web2py") from restricted import RestrictedError from http import HTTP, redirect from globals import Request, Response, Session from compileapp import build_environment, run_models_in, \ run_controller_in, run_view_in from fileutils import copystream, parse_version from contenttype import contenttype from dal import BaseAdapter from settings import global_settings
routers = params.routers # establish routers if present if isinstance(routers, dict): routers = Storage(routers) if routers is not None: router = _router_default() if routers.BASE: router.update(routers.BASE) routers.BASE = router # scan each app in applications/ # create a router, if routers are in use # parse the app-specific routes.py if present # all_apps = [] for appname in [ app for app in os.listdir(abspath('applications')) if not app.startswith('.') ]: if os.path.isdir(abspath('applications', appname)) and \ os.path.isdir(abspath('applications', appname, 'controllers')): all_apps.append(appname) if routers: router = Storage(routers.BASE) # new copy if appname in routers: for key in routers[appname].keys(): if key in ROUTER_BASE_KEYS: raise SyntaxError, "BASE-only key '%s' in router '%s'" % ( key, appname) router.update(routers[appname]) routers[appname] = router if os.path.exists(abspath('applications', appname, routes)):
def load_routers(all_apps): "load-time post-processing of routers" for app in routers.keys(): # initialize apps with routers that aren't present, on behalf of unit tests if app not in all_apps: all_apps.append(app) router = Storage(routers.BASE) # new copy if app != 'BASE': for key in routers[app].keys(): if key in ROUTER_BASE_KEYS: raise SyntaxError, "BASE-only key '%s' in router '%s'" % ( key, app) router.update(routers[app]) routers[app] = router router = routers[app] for key in router.keys(): if key not in ROUTER_KEYS: raise SyntaxError, "unknown key '%s' in router '%s'" % (key, app) if not router.controllers: router.controllers = set() elif not isinstance(router.controllers, str): router.controllers = set(router.controllers) if router.languages: router.languages = set(router.languages) else: router.languages = set() if router.functions: if isinstance(router.functions, (set, tuple, list)): functions = set(router.functions) if isinstance(router.default_function, str): functions.add( router.default_function) # legacy compatibility router.functions = {router.default_controller: functions} for controller in router.functions: router.functions[controller] = set( router.functions[controller]) else: router.functions = dict() if app != 'BASE': for base_only in ROUTER_BASE_KEYS: router.pop(base_only, None) if 'domain' in router: routers.BASE.domains[router.domain] = app if isinstance(router.controllers, str) and router.controllers == 'DEFAULT': router.controllers = set() if os.path.isdir(abspath('applications', app)): cpath = abspath('applications', app, 'controllers') for cname in os.listdir(cpath): if os.path.isfile(abspath( cpath, cname)) and cname.endswith('.py'): router.controllers.add(cname[:-3]) if router.controllers: router.controllers.add('static') router.controllers.add(router.default_controller) if isinstance(routers.BASE.applications, str) and routers.BASE.applications == 'ALL': routers.BASE.applications = list(all_apps) if routers.BASE.applications: routers.BASE.applications = set(routers.BASE.applications) else: routers.BASE.applications = set() for app in routers.keys(): # set router name router = routers[app] router.name = app # compile URL validation patterns router._acfe_match = re.compile(router.acfe_match) router._file_match = re.compile(router.file_match) if router.args_match: router._args_match = re.compile(router.args_match) # convert path_prefix to a list of path elements if router.path_prefix: if isinstance(router.path_prefix, str): router.path_prefix = router.path_prefix.strip('/').split('/') # rewrite BASE.domains as tuples # # key: 'domain[:port]' -> (domain, port) # value: 'application[/controller] -> (application, controller) # (port and controller may be None) # domains = dict() if routers.BASE.domains: for (domain, app) in [(d.strip(':'), a.strip('/')) for (d, a) in routers.BASE.domains.items()]: port = None if ':' in domain: (domain, port) = domain.split(':') ctlr = None fcn = None if '/' in app: (app, ctlr) = app.split('/', 1) if ctlr and '/' in ctlr: (ctlr, fcn) = ctlr.split('/') if app not in all_apps and app not in routers: raise SyntaxError, "unknown app '%s' in domains" % app domains[(domain, port)] = (app, ctlr, fcn) routers.BASE.domains = domains
create_missing_folders() # set up logging for subsequent imports import logging import logging.config # This needed to prevent exception on Python 2.5: # NameError: name 'gluon' is not defined # See http://bugs.python.org/issue1436 import gluon.messageboxhandler logging.gluon = gluon exists = os.path.exists pjoin = os.path.join logpath = abspath("logging.conf") if exists(logpath): logging.config.fileConfig(abspath("logging.conf")) else: logging.basicConfig() logger = logging.getLogger("web2py") from restricted import RestrictedError from http import HTTP, redirect from globals import Request, Response, Session from compileapp import build_environment, run_models_in, \ run_controller_in, run_view_in from contenttype import contenttype from dal import BaseAdapter from settings import global_settings from validators import CRYPT
def crondance(applications_parent, ctype='soft', startup=False, apps=None): apppath = os.path.join(applications_parent, 'applications') cron_path = os.path.join(applications_parent) token = Token(cron_path) cronmaster = token.acquire(startup=startup) if not cronmaster: return now_s = time.localtime() checks = (('min', now_s.tm_min), ('hr', now_s.tm_hour), ('mon', now_s.tm_mon), ('dom', now_s.tm_mday), ('dow', (now_s.tm_wday + 1) % 7)) if apps is None: apps = [x for x in os.listdir(apppath) if os.path.isdir(os.path.join(apppath, x))] full_apath_links = set() for app in apps: if _cron_stopping: break apath = os.path.join(apppath, app) # if app is a symbolic link to other app, skip it full_apath_link = absolute_path_link(apath) if full_apath_link in full_apath_links: continue else: full_apath_links.add(full_apath_link) cronpath = os.path.join(apath, 'cron') crontab = os.path.join(cronpath, 'crontab') if not os.path.exists(crontab): continue try: cronlines = fileutils.readlines_file(crontab, 'rt') lines = [x.strip() for x in cronlines if x.strip( ) and not x.strip().startswith('#')] tasks = [parsecronline(cline) for cline in lines] except Exception, e: logger.error('WEB2PY CRON: crontab read error %s' % e) continue for task in tasks: if _cron_stopping: break commands = [sys.executable] w2p_path = fileutils.abspath('web2py.py', gluon=True) if os.path.exists(w2p_path): commands.append(w2p_path) if global_settings.applications_parent != global_settings.gluon_parent: commands.extend(('-f', global_settings.applications_parent)) citems = [(k in task and not v in task[k]) for k, v in checks] task_min = task.get('min', []) if not task: continue elif not startup and task_min == [-1]: continue elif task_min != [-1] and reduce(lambda a, b: a or b, citems): continue logger.info('WEB2PY CRON (%s): %s executing %s in %s at %s' % (ctype, app, task.get('cmd'), os.getcwd(), datetime.datetime.now())) action, command, models = False, task['cmd'], '' if command.startswith('**'): (action, models, command) = (True, '', command[2:]) elif command.startswith('*'): (action, models, command) = (True, '-M', command[1:]) else: action = False if action and command.endswith('.py'): commands.extend(('-J', # cron job models, # import models? '-S', app, # app name '-a', '"<recycle>"', # password '-R', command)) # command elif action: commands.extend(('-J', # cron job models, # import models? '-S', app + '/' + command, # app name '-a', '"<recycle>"')) # password else: commands = command # from python docs: # You do not need shell=True to run a batch file or # console-based executable. shell = False try: cronlauncher(commands, shell=shell).start() except Exception, e: logger.warning( 'WEB2PY CRON: Execution error for %s: %s' % (task.get('cmd'), e))
def wsgibase(environ, responder): """ this is the gluon wsgi application. the first function called when a page is requested (static or dynamic). it can be called by paste.httpserver or by apache mod_wsgi. - fills request with info - the environment variables, replacing '.' with '_' - adds web2py path and version info - compensates for fcgi missing path_info and query_string - validates the path in url The url path must be either: 1. for static pages: - /<application>/static/<file> 2. for dynamic pages: - /<application>[/<controller>[/<function>[/<sub>]]][.<extension>] - (sub may go several levels deep, currently 3 levels are supported: sub1/sub2/sub3) The naming conventions are: - application, controller, function and extension may only contain [a-zA-Z0-9_] - file and sub may also contain '-', '=', '.' and '/' """ current.__dict__.clear() request = Request() response = Response() session = Session() env = request.env env.web2py_path = global_settings.applications_parent env.web2py_version = web2py_version env.update(global_settings) static_file = False try: try: try: # ################################################## # handle fcgi missing path_info and query_string # select rewrite parameters # rewrite incoming URL # parse rewritten header variables # parse rewritten URL # serve file if static # ################################################## fixup_missing_path_info(environ) (static_file, version, environ) = url_in(request, environ) response.status = env.web2py_status_code or response.status if static_file: if environ.get('QUERY_STRING', '').startswith('attachment'): response.headers['Content-Disposition'] \ = 'attachment' if version: response.headers['Cache-Control'] = 'max-age=315360000' response.headers[ 'Expires'] = 'Thu, 31 Dec 2037 23:59:59 GMT' response.stream(static_file, request=request) # ################################################## # fill in request items # ################################################## app = request.application # must go after url_in! if not global_settings.local_hosts: local_hosts = set(['127.0.0.1', '::ffff:127.0.0.1', '::1']) if not global_settings.web2py_runtime_gae: try: fqdn = socket.getfqdn() local_hosts.add(socket.gethostname()) local_hosts.add(fqdn) local_hosts.update([ addrinfo[4][0] for addrinfo in getipaddrinfo(fqdn) ]) if env.server_name: local_hosts.add(env.server_name) local_hosts.update([ addrinfo[4][0] for addrinfo in getipaddrinfo(env.server_name) ]) except (socket.gaierror, TypeError): pass global_settings.local_hosts = list(local_hosts) else: local_hosts = global_settings.local_hosts client = get_client(env) x_req_with = str(env.http_x_requested_with).lower() request.update( client = client, folder = abspath('applications', app) + os.sep, ajax = x_req_with == 'xmlhttprequest', cid = env.http_web2py_component_element, is_local = env.remote_addr in local_hosts, is_https = env.wsgi_url_scheme in HTTPS_SCHEMES or \ request.env.http_x_forwarded_proto in HTTPS_SCHEMES \ or env.https == 'on') request.compute_uuid() # requires client request.url = environ['PATH_INFO'] # ################################################## # access the requested application # ################################################## if not exists(request.folder): if app == rwthread.routes.default_application \ and app != 'welcome': redirect(URL('welcome', 'default', 'index')) elif rwthread.routes.error_handler: _handler = rwthread.routes.error_handler redirect( URL(_handler['application'], _handler['controller'], _handler['function'], args=app)) else: raise HTTP(404, rwthread.routes.error_message % 'invalid request', web2py_error='invalid application') elif not request.is_local and \ exists(pjoin(request.folder, 'DISABLED')): raise HTTP( 503, "<html><body><h1>Temporarily down for maintenance</h1></body></html>" ) # ################################################## # build missing folders # ################################################## create_missing_app_folders(request) # ################################################## # get the GET and POST data # ################################################## parse_get_post_vars(request, environ) # ################################################## # expose wsgi hooks for convenience # ################################################## request.wsgi.environ = environ_aux(environ, request) request.wsgi.start_response = \ lambda status='200', headers=[], \ exec_info=None, response=response: \ start_response_aux(status, headers, exec_info, response) request.wsgi.middleware = \ lambda *a: middleware_aux(request, response, *a) # ################################################## # load cookies # ################################################## if env.http_cookie: try: request.cookies.load(env.http_cookie) except Cookie.CookieError, e: pass # invalid cookies # ################################################## # try load session or create new session file # ################################################## if not env.web2py_disable_session: session.connect(request, response) # ################################################## # run controller # ################################################## if global_settings.debugging and app != "admin": import gluon.debug # activate the debugger gluon.debug.dbg.do_debug(mainpyfile=request.folder) serve_controller(request, response, session) except HTTP, http_response: if static_file: return http_response.to(responder, env=env) if request.body: request.body.close() # ################################################## # on success, try store session in database # ################################################## session._try_store_in_db(request, response) # ################################################## # on success, commit database # ################################################## if response.do_not_commit is True: BaseAdapter.close_all_instances(None) # elif response._custom_commit: # response._custom_commit() elif response.custom_commit: BaseAdapter.close_all_instances(response.custom_commit) else: BaseAdapter.close_all_instances('commit') # ################################################## # if session not in db try store session on filesystem # this must be done after trying to commit database! # ################################################## session._try_store_in_cookie_or_file(request, response) if request.cid: if response.flash: http_response.headers['web2py-component-flash'] = \ urllib2.quote(xmlescape(response.flash)\ .replace('\n','')) if response.js: http_response.headers['web2py-component-command'] = \ urllib2.quote(response.js.replace('\n','')) # ################################################## # store cookies in headers # ################################################## rcookies = response.cookies if session._forget and response.session_id_name in rcookies: del rcookies[response.session_id_name] elif session._secure: rcookies[response.session_id_name]['secure'] = True http_response.cookies2headers(rcookies) ticket = None except RestrictedError, e: if request.body: request.body.close() # ################################################## # on application error, rollback database # ################################################## ticket = e.log(request) or 'unknown' if response._custom_rollback: response._custom_rollback() else: BaseAdapter.close_all_instances('rollback') http_response = \ HTTP(500, rwthread.routes.error_message_ticket % dict(ticket=ticket), web2py_error='ticket %s' % ticket)
# See <web2py-root-dir>/examples/routes.parametric.example.py for parameter's detail # ---------------------------------------------------------------------------------------------------------------------- # ---------------------------------------------------------------------------------------------------------------------- # To enable this route file you must do the steps: # 1. rename <web2py-root-dir>/examples/routes.parametric.example.py to routes.py # 2. rename this APP/routes.example.py to APP/routes.py (where APP - is your application directory) # 3. restart web2py (or reload routes in web2py admin interface) # # YOU CAN COPY THIS FILE TO ANY APPLICATION'S ROOT DIRECTORY WITHOUT CHANGES! # ---------------------------------------------------------------------------------------------------------------------- from fileutils import abspath from languages import read_possible_languages possible_languages = read_possible_languages(abspath("applications", app)) # ---------------------------------------------------------------------------------------------------------------------- # NOTE! app - is an application based router's parameter with name of an application. E.g.'welcome' # ---------------------------------------------------------------------------------------------------------------------- routers = { app: dict( default_language=possible_languages["default"][0], languages=[lang for lang in possible_languages if lang != "default"], ) } # ---------------------------------------------------------------------------------------------------------------------- # NOTE! To change language in your application using these rules add this line in one of your models files: # ----------------------------------------------------------------------------------------------------------------------
# To enable this route file you must do the steps: # # 1. rename <web2py-root-dir>/router.example.py to routes.py # 2. rename this APP/routes.example.py to APP/routes.py # (where APP - is your application directory) # 3. restart web2py (or reload routes in web2py admin interfase) # # YOU CAN COPY THIS FILE TO ANY APPLICATION'S ROOT DIRECTORY WITHOUT CHANGES! default_controller = "tasks" default_function = "index" from fileutils import abspath from languages import read_possible_languages possible_languages = read_possible_languages(abspath('applications', app)) #NOTE! app - is an application based router's parameter with name of an # application. E.g.'welcome' routers = { app: dict( default_language = possible_languages['default'][0], languages = [lang for lang in possible_languages if lang != 'default'] ) } #NOTE! To change language in your application using these rules add this line #in one of your models files: # if request.uri_language: T.force(request.uri_language)
for sym in ('routes_app', 'routes_in', 'routes_out'): if sym in symbols: for (k, v) in symbols[sym]: p[sym].append(compile_re(k, v)) for sym in ('routes_onerror', 'routes_apps_raw', 'error_handler', 'error_message', 'error_message_ticket', 'default_application', 'default_controller', 'default_function'): if sym in symbols: p[sym] = symbols[sym] if app is None: global params params = p # install base rewrite parameters for appname in os.listdir('applications'): if os.path.exists(abspath('applications', appname, routes)): load(routes, appname) else: params_apps[app] = p logger.debug('URL rewrite is on. configuration in %s' % path) def filter_uri(e, regexes, tag, default=None): "filter incoming URI against a list of regexes" query = e.get('QUERY_STRING', None) path = e['PATH_INFO'] host = e.get('HTTP_HOST', 'localhost').lower() original_uri = path + (query and '?' + query or '') i = host.find(':') if i > 0: host = host[:i]