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 create_missing_folders(): if not global_settings.web2py_runtime_gae: for path in ('applications', 'deposit', 'site-packages', 'logs'): try_mkdir(abspath(path, gluon=True)) """ OLD sys.path dance paths = (global_settings.gluon_parent, abspath( 'site-packages', gluon=True), abspath('gluon', gluon=True), '') """ paths = (global_settings.gluon_parent, abspath( 'site-packages', gluon=True), '') [add_path_first(p) for p in paths]
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 unzip(filename, dir, subfolder=''): """Unzips filename into dir (.zip only, no .gz etc) Args: filename(str): archive dir(str): destination subfolder(str): if != '' unzips 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 += '/' 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 start(self): from gluon import newcron import logging import logging.config from gluon.settings import global_settings from gluon.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 upgrade(request, url='http://web2py.com'): """Upgrades web2py (src, osx, win) if a new version is posted. It detects whether src, osx or win is running and downloads the right one Args: 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 tuple: completed, traceback - completed: True on success, False on failure (network problem or old version) - traceback: None on success, raised exception details on failure """ web2py_version = request.env.web2py_version gluon_parent = request.env.gluon_parent if not gluon_parent.endswith('/'): 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) try: write_file(filename, urllib.urlopen(full_url).read(), 'wb') except Exception as e: return False, e try: unzip(filename, destination, subfolder) return True, None except Exception as e: return False, e
def _download_links_write(self): """ Write a file to static/ajax/<random number> containing all Download Links """ files = [] for filename in os.listdir(self.BinDir): size = os.path.getsize(os.path.join(self.BinDir, filename)) files.append({'name': filename, 'size': size}) r = json.dumps(sorted(files)) # Write info to file static_ajax_file = os.path.join( abspath(request.folder), "static", "ajax", self.Rand ) mkutils.write_file(static_ajax_file, str(r))
def change_password(): if session.pam_user: session.flash = T('PAM authenticated user, cannot change password here') redirect(URL('site')) form=SQLFORM.factory(Field('current_admin_password','password'), Field('new_admin_password','password',requires=IS_STRONG()), Field('new_admin_password_again','password')) if form.accepts(request.vars): if not verify_password(request.vars.current_admin_password): form.errors.current_admin_password = T('invalid password') elif form.vars.new_admin_password != form.vars.new_admin_password_again: form.errors.new_admin_password_again = T('no match') else: path = abspath('parameters_%s.py' % request.env.server_port) safe_write(path, 'password="******"' % CRYPT()(request.vars.new_admin_password)[0]) session.flash = T('password changed') redirect(URL('site')) return dict(form=form)
def wsgibase(environ, responder): """ 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 (or any WSGI-compatible server). - 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>] The naming conventions are: - application, controller, function and extension may only contain `[a-zA-Z0-9_]` - file and sub may also contain '-', '=', '.' and '/' """ eget = environ.get current.__dict__.clear() request = Request(environ) 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 http_response = None 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 eget('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() cmd_opts = global_settings.cmd_options 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 and client == env.remote_addr), is_shell=False, is_scheduler=False, is_https=env.wsgi_url_scheme in HTTPS_SCHEMES or request.env.http_x_forwarded_proto in HTTPS_SCHEMES or env.https == 'on' ) request.url = environ['PATH_INFO'] # ################################################## # access the requested application # ################################################## disabled = pjoin(request.folder, 'DISABLED') 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(disabled): five0three = os.path.join(request.folder, 'static', '503.html') if os.path.exists(five0three): raise HTTP(503, file(five0three, 'r').read()) else: 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 = LazyWSGI(environ, request, response) # ################################################## # load cookies # ################################################## if env.http_cookie: for single_cookie in env.http_cookie.split(';'): single_cookie = single_cookie.strip() if single_cookie: try: request.cookies.load(single_cookie) except Cookie.CookieError: pass # single invalid cookie ignore # ################################################## # 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 as hr: http_response = hr if static_file: return http_response.to(responder, env=env) if request.body: request.body.close() if hasattr(current, 'request'): # ################################################## # on success, try store session in database # ################################################## if not env.web2py_disable_session: 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: 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! # ################################################## if not env.web2py_disable_session: session._try_store_in_cookie_or_file(request, response) # Set header so client can distinguish component requests. if request.cid: http_response.headers.setdefault( 'web2py-component-content', 'replace') if request.ajax: if response.flash: http_response.headers['web2py-component-flash'] = \ urllib2.quote(xmlescape(response.flash).replace(b'\n', b'')) if response.js: http_response.headers['web2py-component-command'] = \ urllib2.quote(response.js.replace('\n', '')) # ################################################## # store cookies in headers # ################################################## session._fixup_before_save() http_response.cookies2headers(response.cookies) ticket = None except RestrictedError as e: if request.body: request.body.close() # ################################################## # on application error, rollback database # ################################################## # log tickets before rollback if not in DB if not request.tickets_db: ticket = e.log(request) or 'unknown' # rollback if response._custom_rollback: response._custom_rollback() else: BaseAdapter.close_all_instances('rollback') # if tickets in db, reconnect and store it in db if request.tickets_db: ticket = e.log(request) or 'unknown' http_response = \ HTTP(500, rwthread.routes.error_message_ticket % dict(ticket=ticket), web2py_error='ticket %s' % ticket) except: if request.body: request.body.close() # ################################################## # on application error, rollback database # ################################################## try: if response._custom_rollback: response._custom_rollback() else: BaseAdapter.close_all_instances('rollback') except: pass e = RestrictedError('Framework', '', '', locals()) ticket = e.log(request) or 'unrecoverable' http_response = \ HTTP(500, rwthread.routes.error_message_ticket % dict(ticket=ticket), web2py_error='ticket %s' % ticket) finally: if response and hasattr(response, 'session_file') \ and response.session_file: response.session_file.close() session._unlock(response) http_response, new_environ = try_rewrite_on_error( http_response, request, environ, ticket) if not http_response: return wsgibase(new_environ, responder) if global_settings.web2py_crontype == 'soft': newcron.softcron(global_settings.applications_parent).start() return http_response.to(responder, env=env)
def prepare_subfolder(subfolder): pth = path.join(abspath(request.folder), subfolder) if not path.isdir(pth): mkdir(pth) return pth
def __init__( self, ip='127.0.0.1', port=8000, password='', pid_filename='httpserver.pid', log_filename='httpserver.log', profiler_dir=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, list): for i in interfaces: if not isinstance(i, tuple): 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) load_routes() for p in (path, abspath('site-packages'), ""): add_path_first(p) 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.has_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_dir)} 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, )
def appfactory(wsgiapp=wsgibase, logfilename='httpserver.log', profiler_dir=None, profilerfilename=None): """ generates a wsgi application that does logging and profiling and calls wsgibase Args: wsgiapp: the base application logfilename: where to store apache-compatible requests log profiler_dir: where to store profile files """ if profilerfilename is not None: raise BaseException("Deprecated API") 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 appfactory(wsgiapp=wsgibase, logfilename='httpserver.log', profiler_dir=None, profilerfilename=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 profilerfilename is not None: raise BaseException("Deprecated API") 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_dir=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_dir)} 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, )
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 '/' """ eget = environ.get current.__dict__.clear() request = Request(environ) 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 eget('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 # ################################################## disabled = pjoin(request.folder, 'DISABLED') 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(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 = LazyWSGI(environ, request, response) # ################################################## # 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() if hasattr(current,'request'): # ################################################## # 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: 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) # Set header so client can distinguish component requests. if request.cid: http_response.headers.setdefault( 'web2py-component-content', 'replace') if request.ajax: 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 # ################################################## session._fixup_before_save() http_response.cookies2headers(response.cookies) ticket = None except RestrictedError, e: if request.body: request.body.close() # ################################################## # on application error, rollback database # ################################################## # log tickets before rollback if not in DB if not request.tickets_db: ticket = e.log(request) or 'unknown' # rollback if response._custom_rollback: response._custom_rollback() else: BaseAdapter.close_all_instances('rollback') # if tickets in db, reconnect and store it in db if request.tickets_db: ticket = e.log(request) or 'unknown' 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 gluon.fileutils import abspath from gluon.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)
def crondance(applications_parent, ctype='soft', startup=False, apps=None): apppath = os.path.join(applications_parent, 'applications') token = Token(applications_parent) 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 = [ line.strip() for line in fileutils.readlines_file(crontab, 'rt') ] lines = [ line for line in cronlines if line and not line.startswith('#') ] tasks = [parsecronline(cline) for cline in lines] except Exception as 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 as e: logger.warning('WEB2PY CRON: Execution error for %s: %s' % (task.get('cmd'), e)) token.release()
# This needed to prevent exception on Python 2.5: # NameError: name 'gluon' is not defined # See http://bugs.python.org/issue1436 # attention!, the import Tkinter in messageboxhandler, changes locale ... import gluon.messageboxhandler logging.gluon = gluon # so we must restore it! Thanks ozancag import locale locale.setlocale(locale.LC_CTYPE, "C") # IMPORTANT, web2py requires locale "C" 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 gluon.restricted import RestrictedError from gluon.http import HTTP, redirect from gluon.globals import Request, Response, Session from gluon.compileapp import build_environment, run_models_in, \ run_controller_in, run_view_in from gluon.contenttype import contenttype from gluon.dal import BaseAdapter from gluon.validators import CRYPT from gluon.html import URL, xmlescape
def crondance(applications_parent, ctype='soft', startup=False, apps=None): # TODO: docstring apppath = os.path.join(applications_parent, 'applications') token = Token(applications_parent) 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() if sys.executable.lower().endswith('pythonservice.exe'): _python_exe = os.path.join(sys.exec_prefix, 'python.exe') else: _python_exe = sys.executable base_commands = [_python_exe] w2p_path = fileutils.abspath('web2py.py', gluon=True) if os.path.exists(w2p_path): base_commands.append(w2p_path) if applications_parent != global_settings.gluon_parent: base_commands.extend(('-f', applications_parent)) base_commands.extend(('-J', # FIXME: this should not be needed since we are # not launching the web server '-a', '"<recycle>"')) 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 = [line.strip() for line in fileutils.readlines_file(crontab, 'rt')] lines = [line for line in cronlines if line and not line.startswith('#')] tasks = [parsecronline(cline) for cline in lines] except Exception as e: logger.error('crontab read error %s', e) continue for task in tasks: if _cron_stopping: break 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('%s cron: %s executing %s in %s at %s', ctype, app, task.get('cmd'), os.getcwd(), datetime.datetime.now()) action = models = False command = task['cmd'] if command.startswith('**'): action = True command = command[2:] elif command.startswith('*'): action = models = True command = command[1:] if action: commands = base_commands[:] if command.endswith('.py'): commands.extend(('-S', app, '-R', command)) else: commands.extend(('-S', app + '/' + command)) if models: commands.append('-M') else: commands = command try: cronlauncher(commands).start() except Exception as e: logger.warning('execution error for %s: %s', task.get('cmd'), e) token.release()
def crondance(applications_parent, ctype='soft', startup=False, apps=None): """ 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) 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)) logger = getLogger(logger_name) if not apps: apps = [x for x in os.listdir(apppath) if os.path.isdir(os.path.join(apppath, x))] full_apath_links = set() if sys.executable.lower().endswith('pythonservice.exe'): _python_exe = os.path.join(sys.exec_prefix, 'python.exe') else: _python_exe = sys.executable base_commands = [_python_exe] w2p_path = fileutils.abspath('web2py.py', gluon=True) if os.path.exists(w2p_path): base_commands.append(w2p_path) if applications_parent != global_settings.gluon_parent: base_commands.extend(('-f', applications_parent)) base_commands.extend(('--cron_job', '--no_banner', '--no_gui', '--plain')) 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 = [line.strip() for line in fileutils.readlines_file(crontab, 'rt')] lines = [line for line in cronlines if line and not line.startswith('#')] tasks = [parsecronline(cline) for cline in lines] except Exception as e: logger.error('crontab read error %s', e) continue for task in tasks: if _cron_stopping: break if not task: continue task_min = task.get('min', []) if not startup and task_min == [-1]: continue citems = [(k in task and not v in task[k]) for k, v in checks] if task_min != [-1] and reduce(lambda a, b: a or b, citems): continue logger.info('%s cron: %s executing %r in %s at %s', ctype, app, task.get('cmd'), os.getcwd(), datetime.datetime.now()) action = models = False command = task['cmd'] if command.startswith('**'): action = True command = command[2:] elif command.startswith('*'): action = models = True command = command[1:] if action: commands = base_commands[:] if command.endswith('.py'): commands.extend(('-S', app, '-R', command)) else: commands.extend(('-S', app + '/' + command)) if models: commands.append('-M') else: commands = shlex.split(command) try: # FIXME: using a new thread every time there is a task to # launch is not a good idea in a long running process cronlauncher(commands).start() except Exception: logger.exception('error starting %r', task['cmd']) token.release()
# This needed to prevent exception on Python 2.5: # NameError: name 'gluon' is not defined # See http://bugs.python.org/issue1436 # attention!, the import Tkinter in messageboxhandler, changes locale ... import gluon.messageboxhandler logging.gluon = gluon # so we must restore it! Thanks ozancag import locale locale.setlocale(locale.LC_CTYPE, "C") # IMPORTANT, web2py requires locale "C" exists = os.path.exists pjoin = os.path.join try: logging.config.fileConfig(abspath("logging.conf")) except: # fails on GAE or when logfile is missing logging.basicConfig() logger = logging.getLogger("web2py") from gluon.restricted import RestrictedError from gluon.http import HTTP, redirect from gluon.globals import Request, Response, Session from gluon.compileapp import build_environment, run_models_in, \ run_controller_in, run_view_in from gluon.contenttype import contenttype from pydal.base import BaseAdapter from gluon.validators import CRYPT from gluon.html import URL, xmlescape from gluon.utils import is_valid_ip_address, getipaddrinfo from gluon.rewrite import load as load_routes, url_in, THREAD_LOCAL as rwthread, \
def run_controller_in(controller, function, environment): """ Runs the controller.function() (for the app specified by the current folder). It tries pre-compiled controller.function.pyc first before compiling it. """ # if compiled should run compiled! folder = current.request.folder cpath = pjoin(folder, 'compiled') badc = 'invalid controller (%s/%s)' % (controller, function) badf = 'invalid function (%s/%s)' % (controller, function) if exists(cpath): filename = pjoin(cpath, 'controllers.%s.%s.pyc' % (controller, function)) try: ccode = getcfs(filename, filename, lambda: read_pyc(filename)) except IOError: raise HTTP(404, rewrite.THREAD_LOCAL.routes.error_message % badf, web2py_error=badf) elif function == '_TEST': # TESTING: adjust the path to include site packages paths = (global_settings.gluon_parent, abspath( 'site-packages', gluon=True), abspath('gluon', gluon=True), '') [add_path_first(path) for path in paths] # TESTING END filename = pjoin(folder, 'controllers/%s.py' % controller) if not exists(filename): raise HTTP(404, rewrite.THREAD_LOCAL.routes.error_message % badc, web2py_error=badc) environment['__symbols__'] = list(environment.keys()) code = read_file(filename) code += TEST_CODE ccode = compile2(code, filename) else: filename = pjoin(folder, 'controllers/%s.py' % controller) try: code = getcfs(filename, filename, lambda: read_file(filename)) except IOError: raise HTTP(404, rewrite.THREAD_LOCAL.routes.error_message % badc, web2py_error=badc) exposed = find_exposed_functions(code) if function not in exposed: raise HTTP(404, rewrite.THREAD_LOCAL.routes.error_message % badf, web2py_error=badf) code = "%s\nresponse._vars=response._caller(%s)" % (code, function) layer = "%s:%s" % (filename, function) ccode = getcfs(layer, filename, lambda: compile2(code, filename)) restricted(ccode, environment, layer=filename) response = environment["response"] vars = response._vars if response.postprocessing: vars = reduce(lambda vars, p: p(vars), response.postprocessing, vars) if isinstance(vars, unicodeT): vars = to_native(vars) elif hasattr(vars, 'xml') and callable(vars.xml): vars = vars.xml() return vars
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 as 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 as e: logger.warning( 'WEB2PY CRON: Execution error for %s: %s' % (task.get('cmd'), e)) token.release()