def server_start(): from optparse import OptionParser p = OptionParser() p.add_option('-d', action="store_true", dest='daemonize', help="Run the server as a daemon") p.add_option('-q', '--quiet', action="store_true", dest='quiet', help="Don't log to console") p.add_option('-p', '--pidfile', dest='pidfile', default=None, help="Store the process id in the given file") p.add_option('--config', dest='config', default=None, help="Path to config.ini file") p.add_option('--datadir', dest='datadir', default=None, help="Path to the data directory") options, args = p.parse_args() if options.datadir: datadir = options.datadir if not os.path.isdir(datadir): os.makedirs(datadir) else: datadir = rundir datadir = os.path.abspath(datadir) if not os.access(datadir, os.W_OK): raise SystemExit("Data dir must be writeable '" + datadir + "'") import app.config app.config.DATADIR = datadir if options.config: config = options.config else: config = os.path.join(datadir, 'config.ini') config = os.path.abspath(config) if not os.access(os.path.dirname(config), os.W_OK) and not os.access( config, os.W_OK): if not os.path.exists(os.path.dirname(config)): os.makedirs(os.path.dirname(config)) else: raise SystemExit("Directory for config file must be writeable") import cherrypy import app.config.render # Configure logging from app.config.cplog import CPLog # Setup logging debug = os.path.isfile(os.path.join(datadir, 'debug.conf')) log = CPLog() log.config(os.path.join(datadir, 'logs'), debug) # Create cache dir cachedir = os.path.join(datadir, 'cache') if not os.path.isdir(cachedir): os.mkdir(cachedir) # Stop logging if options.quiet or options.daemonize: cherrypy.config.update({'log.screen': False}) # Config app from app.config.configApp import configApp ca = configApp(config) # Setup db from app.config.db import initDb initDb() from app.config.routes import setup as Routes from app.lib.cron import CronJobs from app.config.updater import Updater from cherrypy.process import plugins # Check an see if CP is already running import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) host = ca.get('global', 'host') port = int(ca.get('global', 'port')) try: s.connect((host, port)) s.shutdown(0) app.launchBrowser(host, port) return except: pass # Start threads myCrons = CronJobs(cherrypy.engine, ca, debug) myCrons.subscribe() # Update script myUpdater = Updater(cherrypy.engine) myUpdater.subscribe() # User config, use own stuff to prevent unexpected results cherrypy.config.update({ 'global': { 'server.thread_pool': 10, 'server.socket_port': int(ca.get('global', 'port')), 'server.socket_host': ca.get('global', 'host'), 'server.environment': ca.get('global', 'server.environment'), 'engine.autoreload_on': ca.get('global', 'server.environment') == 'development', 'tools.mako.collection_size': 500, 'tools.mako.directories': os.path.join(path_base, 'app', 'views'), 'basePath': path_base, 'runPath': rundir, 'cachePath': cachedir, 'debug': debug, 'frozen': frozen, # Global workers 'config': ca, 'updater': myUpdater, 'cron': myCrons.threads, 'searchers': myCrons.searchers, 'flash': app.flash() } }) # Static config conf = { '/': { 'request.dispatch': Routes(), 'tools.sessions.on': True, 'tools.sessions.timeout': 240, 'tools.gzip.on': True, 'tools.gzip.mime_types': [ 'text/html', 'text/plain', 'text/css', 'text/javascript', 'application/javascript' ] }, '/media': { 'tools.staticdir.on': True, 'tools.staticdir.root': path_base, 'tools.staticdir.dir': "media", 'tools.expires.on': True, 'tools.expires.secs': 3600 * 24 * 7 }, '/cache': { 'tools.staticdir.on': True, 'tools.staticdir.root': datadir, 'tools.staticdir.dir': "cache", 'tools.expires.on': True, 'tools.expires.secs': 3600 * 24 * 7 } } # Don't use auth when password is empty if ca.get('global', 'password') != '': conf['/'].update({ 'tools.basic_auth.on': True, 'tools.basic_auth.realm': 'Awesomeness', 'tools.basic_auth.users': { ca.get('global', 'username'): ca.get('global', 'password') }, 'tools.basic_auth.encrypt': app.clearAuthText }) cherrypy.tools.mybasic_auth = cherrypy.Tool('on_start_resource', app.basicAuth) # I'll do my own logging, thanks! #cherrypy.log.error_log.propagate = False #cherrypy.log.access_log.propagate = False #No Root controller as we provided all our own. cherrypy.tree.mount(root=None, config=conf) #HTTP Errors def http_error_hander(status, message, traceback, version): args = [status, message, traceback, version] return "<html><body><h1>Error %s</h1>Something unexpected has happened.</body></html>" % args[ 0] cherrypy.config.update({'error_page.default': http_error_hander}) # Deamonize if options.daemonize: plugins.Daemonizer(cherrypy.engine).subscribe() # PIDfile if options.pidfile: plugins.PIDFile(cherrypy.engine, options.pidfile).subscribe() # Setup the signal handler if hasattr(cherrypy.engine, "signal_handler"): cherrypy.engine.signal_handler.subscribe() if hasattr(cherrypy.engine, "console_control_handler"): cherrypy.engine.console_control_handler.subscribe() ## start the app try: cherrypy.engine.start() except: sys.exit(1) else: # Launch browser if ca.get('global', 'launchbrowser'): app.launchBrowser(ca.get('global', 'host'), ca.get('global', 'port')) cherrypy.engine.block()
Renders a mako template to HTML and sets the CherryPy response's body with it. """ if cherrypy.response.status > 399: return data = cherrypy.response.body or {} template = lookup.get_template(template) if template and isinstance(data, dict): cherrypy.response.body = template.render(**data) # Creating our tool so that they can be # used below in the CherryPy applications cherrypy.tools.render = cherrypy.Tool('before_finalize', render_template) cherrypy.tools.websocket = WebSocketTool() # Web Application class SharedDrawingBoardApp(object): @cherrypy.expose @cherrypy.tools.render(template='index.html') def index(self): return {'boardid': str(uuid.uuid4())[:4], 'baseurl': BASE_URL} @cherrypy.expose @cherrypy.tools.render(template='board.html') def board(self, board_id): bus.websockets.register_board(board_id) return {
"tools.addheader.on": True } def addheader(*args, **kwargs): "This function's only purpose is to tell the browser to cache requests for an hour" cherrypy.response.headers['Cache-Control'] = "max-age=3600" #del cherrypy.response.headers['Expires'] def pageloadnotify(*args, **kwargs): systasks.aPageJustLoaded() cherrypy.config.update(site_config) cherrypy.tools.pageloadnotify = cherrypy.Tool('on_start_resource', pageloadnotify) cherrypy.config['tools.pageloadnotify.on'] = True cherrypy.tools.addheader = cherrypy.Tool('before_finalize', addheader) if hasattr(cherrypy.engine, 'signal_handler'): cherrypy.engine.signal_handler.subscribe() cherrypy.tree.mount(root, config=cnf) #As far as I can tell, this second server inherits everything from the "implicit" server #except what we override. server2 = cherrypy._cpserver.Server() server2.socket_port = config['http-port'] server2._socket_host = bindto server2.thread_pool = config['http-thread-pool']
def _configureCherryPy(self): """ _configureCherryPy_ Configure the CherryPy server, ignoring items in the configuration file that aren't CherryPy configurables. """ configDict = self.serverConfig.dictionary_() # If you add configurables update the testLongHandConfigurables in Root_t configurables = [ 'engine', 'hooks', 'log', 'request', 'response', 'server', 'tools', 'wsgi', 'checker' ] # Deal with "long hand" configuration variables for i in configurables: if i in configDict.keys(): for config_param, param_value in configDict[i].dictionary_( ).items(): if isinstance(param_value, ConfigSection): # TODO: make this loads better for child_param, child_param_value in param_value.dictionary_( ).items(): cherrypy.config["%s.%s.%s" % (i, config_param, child_param)] = child_param_value elif type(param_value) in [type('string'), type(123)]: cherrypy.config["%s.%s" % (i, config_param)] = param_value else: raise Exception("Unsupported configuration type: %s" % type(v)) # which we then over write with short hand variables if necessary cherrypy.config["server.environment"] = configDict.get( "environment", "production") #Set up the tools and the logging cherrypy.tools.time = cherrypy.Tool('on_start_resource', mytime) cherrypy.config.update({'tools.time.on': True}) if configDict.get("proxy_base", False): cherrypy.tools.proxy = cherrypy.Tool('before_request_body', myproxy, priority=30) cherrypy.config.update({ 'tools.proxy.on': True, 'tools.proxy.base': configDict["proxy_base"] }) cherrypy.log = WTLogger() cherrypy.config["log.screen"] = bool( configDict.get("log_screen", False)) cherrypy.config.update({ 'tools.expires.on': True, 'tools.expires.secs': configDict.get("expires", 300), 'tools.response_headers.on': True, 'tools.etags.on': True, 'tools.etags.autotags': True, 'tools.encode.on': True, 'tools.gzip.on': True, }) if cherrypy.config["server.environment"] == "production": # If we're production these should be set regardless cherrypy.config["request.show_tracebacks"] = False cherrypy.config["engine.autoreload_on"] = False # In production mode only allow errors at WARNING or greater to the log err_lvl = max((configDict.get("error_log_level", logging.WARNING), logging.WARNING)) acc_lvl = max((configDict.get("access_log_level", logging.INFO), logging.INFO)) cherrypy.log.error_log.setLevel(err_lvl) cherrypy.log.access_log.setLevel(acc_lvl) else: print print 'THIS BETTER NOT BE A PRODUCTION SERVER' print cherrypy.config["request.show_tracebacks"] = configDict.get( "show_tracebacks", False) cherrypy.config["engine.autoreload_on"] = configDict.get( "autoreload", False) # Allow debug output cherrypy.log.error_log.setLevel( configDict.get("error_log_level", logging.DEBUG)) cherrypy.log.access_log.setLevel( configDict.get("access_log_level", logging.DEBUG)) default_port = 8080 if "server.socket_port" in cherrypy.config.keys(): default_port = cherrypy.config["server.socket_port"] cherrypy.config["server.thread_pool"] = configDict.get( "thread_pool", 10) cherrypy.config["server.socket_port"] = configDict.get( "port", default_port) cherrypy.config["server.socket_host"] = configDict.get( "host", "0.0.0.0") #A little hacky way to pass the expire second to config self.appconfig.default_expires = cherrypy.config["tools.expires.secs"] # SecurityModule config # Registers secmodv2 into cherrypy.tools so it can be used through # decorators if self.secconfig.dictionary_().get('dangerously_insecure', False): cherrypy.tools.secmodv2 = NullAuth(self.secconfig) else: cherrypy.tools.secmodv2 = FrontEndAuth(self.secconfig) if hasattr(self.secconfig, "default"): # If the 'default' section is present, it will force the # authn/z to be called even for non-decorated methods cherrypy.config.update({ 'tools.secmodv2.on': True, 'tools.secmodv2.role': self.secconfig.default.role, 'tools.secmodv2.group': self.secconfig.default.group, 'tools.secmodv2.site': self.secconfig.default.site }) cherrypy.log.error_log.debug('Application %s initialised in %s mode' % (self.app, self.mode))
def _validate_event_scheduled_failed(self, event): if 'message' not in event: raise cherrypy.HTTPError(400, 'Missing message') def actually_decode(): """ CherryPy decode tool doesn't actually decode anything unless the body is multipart. This tool is different and will decode the body. """ # assume UTF-8 and to hell with the specs dec = codecs.getincrementaldecoder('utf-8')() cherrypy.request.body = map(dec.decode, cherrypy.request.body) adt = cherrypy.Tool('before_handler', actually_decode) cherrypy.tools.actually_decode = adt class Server(object): queue = [] new_relic = NewRelic() kiln = Kiln() jenkins = Jenkins() fogbugz = FogBugz() bitbucket = BitBucket() velociraptor = Velociraptor() @classmethod def send_to(cls, channel, *msgs):
class App(object): @cherrypy.expose def __init__(self): self.auth = AuthController() self.postprocessing = Postprocessing() self.api = api.API() if core.CONFIG['Server']['authrequired']: self._cp_config = {'auth.require': []} self.ajax = ajax.Ajax() localization.get() localization.install() # point server toward custom 404 cherrypy.config.update({'error_page.404': self.error_page_404}) if core.CONFIG['Server']['checkupdates']: scheduler.AutoUpdateCheck.update_check(install=False) def https_redirect(self=None): ''' Cherrypy tool to redirect http:// to https:// Use as before_handler when https is enabled for the server. Enable in config as {'tools.https_redirect.on': True} ''' if cherrypy.request.scheme == 'http': raise cherrypy.HTTPRedirect(cherrypy.url().replace( 'http:', 'https:'), status=302) cherrypy.tools.https_redirect = cherrypy.Tool('before_handler', https_redirect) def defaults(self): defaults = { 'head': self.head(), 'navbar': self.nav_bar(current=sys._getframe().f_back.f_code.co_name), 'url_base': core.URL_BASE } return defaults # All dispatching methods from here down status_template = Template(filename='templates/library/status.html', module_directory=core.MAKO_CACHE) manage_template = Template(filename='templates/library/manage.html', module_directory=core.MAKO_CACHE) import_template = Template(filename='templates/library/import.html', module_directory=core.MAKO_CACHE) couchpotato_template = Template( filename='templates/library/import/couchpotato.html', module_directory=core.MAKO_CACHE) kodi_template = Template(filename='templates/library/import/kodi.html', module_directory=core.MAKO_CACHE) plex_template = Template(filename='templates/library/import/plex.html', module_directory=core.MAKO_CACHE) directory_template = Template( filename='templates/library/import/directory.html', module_directory=core.MAKO_CACHE) stats_template = Template(filename='templates/library/stats.html', module_directory=core.MAKO_CACHE) add_movie_template = Template(filename='templates/add_movie.html', module_directory=core.MAKO_CACHE) server_template = Template(filename='templates/settings/server.html', module_directory=core.MAKO_CACHE) search_template = Template(filename='templates/settings/search.html', module_directory=core.MAKO_CACHE) quality_template = Template(filename='templates/settings/quality.html', module_directory=core.MAKO_CACHE) indexers_template = Template(filename='templates/settings/indexers.html', module_directory=core.MAKO_CACHE) downloader_template = Template( filename='templates/settings/downloader.html', module_directory=core.MAKO_CACHE) postprocessing_template = Template( filename='templates/settings/postprocessing.html', module_directory=core.MAKO_CACHE) plugins_template = Template(filename='templates/settings/plugins.html', module_directory=core.MAKO_CACHE) logs_template = Template(filename='templates/settings/logs.html', module_directory=core.MAKO_CACHE) system_template = Template(filename='templates/system.html', module_directory=core.MAKO_CACHE) shutdown_template = Template(filename='templates/system/shutdown.html', module_directory=core.MAKO_CACHE) restart_template = Template(filename='templates/system/restart.html', module_directory=core.MAKO_CACHE) update_template = Template(filename='templates/system/update.html', module_directory=core.MAKO_CACHE) fourohfour_template = Template(filename='templates/404.html', module_directory=core.MAKO_CACHE) head_template = Template(filename='templates/head.html', module_directory=core.MAKO_CACHE) navbar_template = Template(filename='templates/navbar.html', module_directory=core.MAKO_CACHE) @cherrypy.expose def default(self): return self.library('status') @cherrypy.expose def _test(self): return 'This is not the page you are looking for.' @cherrypy.expose def library(self, *path): page = path[0] if len(path) > 0 else 'status' if page == 'status': if core.CONFIG['Server']['hidefinished']: movie_count = core.sql.get_library_count(hide_finished=True) hidden_count = core.sql.get_library_count() - movie_count else: movie_count = core.sql.get_library_count() hidden_count = 0 return App.status_template.render( profiles=core.CONFIG['Quality']['Profiles'].keys(), movie_count=movie_count, hidden_count=hidden_count, **self.defaults()) elif page == 'manage': movies = core.sql.get_user_movies() return App.manage_template.render( movies=movies, profiles=core.CONFIG['Quality']['Profiles'].keys(), **self.defaults()) elif page == 'import': subpage = path[1] if len(path) > 1 else None if not subpage: return App.import_template.render(**self.defaults()) elif subpage == 'couchpotato': return App.couchpotato_template.render( sources=core.SOURCES, profiles=core.CONFIG['Quality']['Profiles'].keys(), **self.defaults()) elif subpage == 'kodi': return App.kodi_template.render( sources=core.SOURCES, profiles=core.CONFIG['Quality']['Profiles'].keys(), **self.defaults()) elif subpage == 'plex': return App.plex_template.render( sources=core.SOURCES, profiles=core.CONFIG['Quality']['Profiles'].keys(), **self.defaults()) elif subpage == 'directory': try: start_dir = os.path.expanduser('~') file_list = [ i for i in os.listdir(start_dir) if os.path.isdir(os.path.join(start_dir, i)) and not i.startswith('.') ] except Exception as e: start_dir = core.PROG_PATH file_list = [ i for i in os.listdir(start_dir) if os.path.isdir(os.path.join(start_dir, i)) and not i.startswith('.') ] file_list.append('..') return App.directory_template.render( sources=core.SOURCES, profiles=core.CONFIG['Quality']['Profiles'].keys(), current_dir=start_dir, file_list=file_list, **self.defaults()) else: return self.error_page_404() elif page == 'stats': return App.stats_template.render(**self.defaults()) else: return self.error_page_404() @cherrypy.expose def add_movie(self): return App.add_movie_template.render(profiles=[ i for i in core.CONFIG['Quality']['Profiles'] if i != 'Default' ], **self.defaults()) @cherrypy.expose def settings(self, *path): page = path[0] if len(path) > 0 else 'server' tor = torrent.Torrent() if page == 'server': themes = [ i[:-4] for i in os.listdir('static/css/themes/') if i.endswith('.css') and os.path.isfile( os.path.join(core.PROG_PATH, 'static/css/themes', i)) ] return App.server_template.render(config=core.CONFIG['Server'], themes=themes, version=core.CURRENT_HASH or '', languages=core.LANGUAGES.keys(), **self.defaults()) elif page == 'search': return App.search_template.render(config=core.CONFIG['Search'], **self.defaults()) elif page == 'quality': return App.quality_template.render(config=core.CONFIG['Quality'], sources=core.SOURCES, **self.defaults()) elif page == 'indexers': return App.indexers_template.render( config=core.CONFIG['Indexers'], providers=tor.get_torrent_providers(), **self.defaults()) elif page == 'downloader': return App.downloader_template.render( config=core.CONFIG['Downloader'], **self.defaults()) elif page == 'postprocessing': return App.postprocessing_template.render( config=core.CONFIG['Postprocessing'], os=core.PLATFORM, **self.defaults()) elif page == 'plugins': plugs = plugins.list_plugins() return App.plugins_template.render(config=core.CONFIG['Plugins'], plugins=plugs, **self.defaults()) elif page == 'logs': logdir = os.path.join(core.PROG_PATH, core.LOG_DIR) logfiles = [ i for i in os.listdir(logdir) if os.path.isfile(os.path.join(logdir, i)) ] return App.logs_template.render(logdir=logdir, logfiles=logfiles, **self.defaults()) elif page == 'download_log': if len(path) > 1: l = os.path.join(os.path.abspath(core.LOG_DIR), path[1]) return cherrypy.lib.static.serve_file( l, 'application/x-download', 'attachment') else: raise cherrypy.HTTPError(400) elif page == 'system': tasks = {} for name, obj in core.scheduler_plugin.task_list.items(): tasks[name] = { 'name': name, 'interval': obj.interval, 'last_execution': obj.last_execution, 'enabled': obj.timer.is_alive() if obj.timer else False } system = { 'database': { 'file': core.DB_FILE, 'size': os.path.getsize(core.DB_FILE) / 1024 }, 'config': { 'file': core.CONF_FILE }, 'system': { 'path': core.PROG_PATH, 'arguments': sys.argv, 'version': sys.version[:5] } } t = int(time.time()) dt = time.strftime('%a, %B %d, %Y %H:%M:%S %z', time.localtime(t)) return App.system_template.render(tasks=json.dumps(tasks), system=system, server_time=[dt, t], **self.defaults()) else: return self.error_page_404() @cherrypy.expose def system(self, *path, **kwargs): if len(path) == 0: return self.error_page_404() page = path[0] if page == 'shutdown': return App.shutdown_template.render(**self.defaults()) if page == 'restart': return App.restart_template.render(**self.defaults()) if page == 'update': return App.update_template.render(updating=core.UPDATING, **self.defaults()) @cherrypy.expose def error_page_404(self, *args, **kwargs): return App.fourohfour_template.render(**self.defaults()) def head(self): return App.head_template.render( url_base=core.URL_BASE, uitheme=core.CONFIG['Server']['uitheme'], notifications=json.dumps( [i for i in core.NOTIFICATIONS if i is not None]), language=core.LANGUAGE) def nav_bar(self, current=None): show_logout = True if cherrypy.session.get(core.SESSION_KEY) else False return App.navbar_template.render(url_base=core.URL_BASE, current=current, show_logout=show_logout)
cherrypy.response.headers["Access-Control-Allow-Origin"] = "*" if __name__ == '__main__': cherrypy_cors.install() conf = { '/': { 'request.dispatch': cherrypy.dispatch.MethodDispatcher(), 'tools.sessions.on': True, 'tools.response_headers.on': True, 'tools.CORS.on': True, 'cors.expose.on': True, 'tools.response_headers.headers': [ ('Content-Type', 'application/json'), ] } } cherrypy.config.update({ 'server.socket_host': '0.0.0.0', 'server.socket_port': 9191, }) cherrypy.tools.CORS = cherrypy.Tool('before_handler', CORS) cherrypy.tree.mount(loginWebService(), '/loginservice', conf) cherrypy.engine.start() cherrypy.engine.block()
return "http://www.qlik.com/" def secureheaders(): headers = cherrypy.response.headers headers['X-Frame-Options'] = 'DENY' headers['X-XSS-Protection'] = '1; mode=block' headers['Content-Security-Policy'] = "default-src='self'" if (cherrypy.server.ssl_certificate != None and cherrypy.server.ssl_private_key != None): headers['Strict-Transport-Security'] = 'max-age=31536000' # one year if __name__ == '__main__': server_config = { 'server.socket_host': '0.0.0.0', 'server.socket_port': 1443, 'server.ssl_module': 'builtin', 'server.ssl_certificate': 'cert.pem', 'server.ssl_private_key': 'privkey.pem', 'tools.secureheaders.on': True, 'tools.sessions.on': True, 'tools.sessions.secure': True, 'tools.sessions.httponly': True } cherrypy.tools.secureheaders = cherrypy.Tool('before_finalize', secureheaders, priority=60) cherrypy.config.update(server_config) cherrypy.quickstart(GoogleAuth())
def __init__(self, *args, **kwargs): cherrypy.tools.authenticate = cherrypy.Tool('before_handler', Auth.check_auth) cherrypy.tools.session_expire_at_browser_close = SessionExpireAtBrowserCloseTool() cherrypy.config.update({'error_page.default': json_error_page}) super(ControllerTestCase, self).__init__(*args, **kwargs)
from lib import FileService from lib.CAS import CAS from lib.Constants import Actions from lib.Models import * from lib.Formatters import * from lib.FileFieldStorage import FileFieldStorage cherrypy.server.max_request_body_size = 0 def before_upload(**kwargs): cherrypy.request.process_request_body = False cherrypy.tools.before_upload = cherrypy.Tool('before_request_body', before_upload, priority=71) def requires_login(permissionId=None, **kwargs): from lib import AccountService format, rootURL = None, cherrypy.request.app.config['filelocker'][ 'root_url'] if cherrypy.request.params.has_key("format"): format = cherrypy.request.params['format'] if cherrypy.session.has_key("user") and cherrypy.session.get( 'user') is not None: user = cherrypy.session.get('user') if user.date_tos_accept == None: raise cherrypy.HTTPRedirect(rootURL + "/sign_tos") elif permissionId is not None:
import cherrypy import imp import os import uuid import tempfile from cgi import FieldStorage def noBodyProcess(): """Sets cherrypy.request.process_request_body = False, giving us direct control of the file upload destination. By default cherrypy loads it to memory, we are directing it to disk.""" cherrypy.request.process_request_body = False cherrypy.tools.noBodyProcess = cherrypy.Tool('before_request_body', noBodyProcess) class PyCurlRESTModel(RESTModel): """ Check if the file upload work with the rest model """ def __init__(self, config={}): RESTModel.__init__(self, config) self._addMethod('POST', 'file', self.uploadFile, args=['file1']) cherrypy.engine.subscribe('start_thread', self.initThread) def initThread(self, thread_index): """
def setup_server(): class Root: def index(self): return "hello" index.exposed = True favicon_ico = tools.staticfile.handler(filename=favicon_path) def defct(self, newct): newct = "text/%s" % newct cherrypy.config.update({ 'tools.response_headers.on': True, 'tools.response_headers.headers': [('Content-Type', newct)] }) defct.exposed = True def baseurl(self, path_info, relative=None): return cherrypy.url(path_info, relative=bool(relative)) baseurl.exposed = True root = Root() root.expose_dec = ExposeExamples() class TestType(type): """Metaclass which automatically exposes all functions in each subclass, and adds an instance of the subclass as an attribute of root. """ def __init__(cls, name, bases, dct): type.__init__(cls, name, bases, dct) for value in itervalues(dct): if isinstance(value, types.FunctionType): value.exposed = True setattr(root, name.lower(), cls()) Test = TestType('Test', (object, ), {}) class URL(Test): _cp_config = {'tools.trailing_slash.on': False} def index(self, path_info, relative=None): if relative != 'server': relative = bool(relative) return cherrypy.url(path_info, relative=relative) def leaf(self, path_info, relative=None): if relative != 'server': relative = bool(relative) return cherrypy.url(path_info, relative=relative) def log_status(): Status.statuses.append(cherrypy.response.status) cherrypy.tools.log_status = cherrypy.Tool('on_end_resource', log_status) class Status(Test): def index(self): return "normal" def blank(self): cherrypy.response.status = "" # According to RFC 2616, new status codes are OK as long as they # are between 100 and 599. # Here is an illegal code... def illegal(self): cherrypy.response.status = 781 return "oops" # ...and here is an unknown but legal code. def unknown(self): cherrypy.response.status = "431 My custom error" return "funky" # Non-numeric code def bad(self): cherrypy.response.status = "error" return "bad news" statuses = [] def on_end_resource_stage(self): return repr(self.statuses) on_end_resource_stage._cp_config = {'tools.log_status.on': True} class Redirect(Test): class Error: _cp_config = { "tools.err_redirect.on": True, "tools.err_redirect.url": "/errpage", "tools.err_redirect.internal": False, } def index(self): raise NameError("redirect_test") index.exposed = True error = Error() def index(self): return "child" def custom(self, url, code): raise cherrypy.HTTPRedirect(url, code) def by_code(self, code): raise cherrypy.HTTPRedirect("somewhere%20else", code) by_code._cp_config = {'tools.trailing_slash.extra': True} def nomodify(self): raise cherrypy.HTTPRedirect("", 304) def proxy(self): raise cherrypy.HTTPRedirect("proxy", 305) def stringify(self): return str(cherrypy.HTTPRedirect("/")) def fragment(self, frag): raise cherrypy.HTTPRedirect("/some/url#%s" % frag) def url_with_quote(self): raise cherrypy.HTTPRedirect("/some\"url/that'we/want") def url_with_unicode(self): raise cherrypy.HTTPRedirect( ntou("\u0442\u0435\u0441\u0442", 'escape')) def login_redir(): if not getattr(cherrypy.request, "login", None): raise cherrypy.InternalRedirect("/internalredirect/login") tools.login_redir = _cptools.Tool('before_handler', login_redir) def redir_custom(): raise cherrypy.InternalRedirect("/internalredirect/custom_err") class InternalRedirect(Test): def index(self): raise cherrypy.InternalRedirect("/") def choke(self): return 3 / 0 choke.exposed = True choke._cp_config = {'hooks.before_error_response': redir_custom} def relative(self, a, b): raise cherrypy.InternalRedirect("cousin?t=6") def cousin(self, t): assert cherrypy.request.prev.closed return cherrypy.request.prev.query_string def petshop(self, user_id): if user_id == "parrot": # Trade it for a slug when redirecting raise cherrypy.InternalRedirect( '/image/getImagesByUser?user_id=slug') elif user_id == "terrier": # Trade it for a fish when redirecting raise cherrypy.InternalRedirect( '/image/getImagesByUser?user_id=fish') else: # This should pass the user_id through to getImagesByUser raise cherrypy.InternalRedirect( '/image/getImagesByUser?user_id=%s' % str(user_id)) # We support Python 2.3, but the @-deco syntax would look like # this: # @tools.login_redir() def secure(self): return "Welcome!" secure = tools.login_redir()(secure) # Since calling the tool returns the same function you pass in, # you could skip binding the return value, and just write: # tools.login_redir()(secure) def login(self): return "Please log in" def custom_err(self): return "Something went horribly wrong." def early_ir(self, arg): return "whatever" early_ir._cp_config = {'hooks.before_request_body': redir_custom} class Image(Test): def getImagesByUser(self, user_id): return "0 images for %s" % user_id class Flatten(Test): def as_string(self): return "content" def as_list(self): return ["con", "tent"] def as_yield(self): yield ntob("content") def as_dblyield(self): yield self.as_yield() as_dblyield._cp_config = {'tools.flatten.on': True} def as_refyield(self): for chunk in self.as_yield(): yield chunk class Ranges(Test): def get_ranges(self, bytes): return repr(httputil.get_ranges('bytes=%s' % bytes, 8)) def slice_file(self): path = os.path.join(os.getcwd(), os.path.dirname(__file__)) return static.serve_file( os.path.join(path, "static/index.html")) class Cookies(Test): def single(self, name): cookie = cherrypy.request.cookie[name] # Python2's SimpleCookie.__setitem__ won't take unicode keys. cherrypy.response.cookie[str(name)] = cookie.value def multiple(self, names): list(map(self.single, names)) def append_headers(header_list, debug=False): if debug: cherrypy.log( "Extending response headers with %s" % repr(header_list), "TOOLS.APPEND_HEADERS") cherrypy.serving.response.header_list.extend(header_list) cherrypy.tools.append_headers = cherrypy.Tool('on_end_resource', append_headers) class MultiHeader(Test): def header_list(self): pass header_list = cherrypy.tools.append_headers(header_list=[ (ntob('WWW-Authenticate'), ntob('Negotiate')), (ntob('WWW-Authenticate'), ntob('Basic realm="foo"')), ])(header_list) def commas(self): cherrypy.response.headers[ 'WWW-Authenticate'] = 'Negotiate,Basic realm="foo"' cherrypy.tree.mount(root)
def _configure(self): """ Configure CherryPy and initialize self.url_prefix :returns our URI """ server_addr = self.get_localized_module_option( 'server_addr', get_default_addr()) ssl = self.get_localized_module_option('ssl', True) if not ssl: server_port = self.get_localized_module_option('server_port', 8080) else: server_port = self.get_localized_module_option('ssl_server_port', 8443) if server_addr is None: raise ServerConfigException( 'no server_addr configured; ' 'try "ceph config set mgr mgr/{}/{}/server_addr <ip>"' .format(self.module_name, self.get_mgr_id())) self.log.info('server: ssl=%s host=%s port=%d', 'yes' if ssl else 'no', server_addr, server_port) # Initialize custom handlers. cherrypy.tools.authenticate = AuthManagerTool() cherrypy.tools.plugin_hooks_filter_request = cherrypy.Tool( 'before_handler', lambda: PLUGIN_MANAGER.hook.filter_request_before_handler(request=cherrypy.request), priority=1) cherrypy.tools.request_logging = RequestLoggingTool() cherrypy.tools.dashboard_exception_handler = HandlerWrapperTool(dashboard_exception_handler, priority=31) # Apply the 'global' CherryPy configuration. config = { 'engine.autoreload.on': False, 'server.socket_host': server_addr, 'server.socket_port': int(server_port), 'error_page.default': json_error_page, 'tools.request_logging.on': True, 'tools.gzip.on': True, 'tools.gzip.mime_types': [ # text/html and text/plain are the default types to compress 'text/html', 'text/plain', # We also want JSON and JavaScript to be compressed 'application/json', 'application/javascript', ], 'tools.json_in.on': True, 'tools.json_in.force': False, 'tools.plugin_hooks_filter_request.on': True, } if ssl: # SSL initialization cert = self.get_store("crt") if cert is not None: self.cert_tmp = tempfile.NamedTemporaryFile() self.cert_tmp.write(cert.encode('utf-8')) self.cert_tmp.flush() # cert_tmp must not be gc'ed cert_fname = self.cert_tmp.name else: cert_fname = self.get_localized_module_option('crt_file') pkey = self.get_store("key") if pkey is not None: self.pkey_tmp = tempfile.NamedTemporaryFile() self.pkey_tmp.write(pkey.encode('utf-8')) self.pkey_tmp.flush() # pkey_tmp must not be gc'ed pkey_fname = self.pkey_tmp.name else: pkey_fname = self.get_localized_module_option('key_file') verify_tls_files(cert_fname, pkey_fname) config['server.ssl_module'] = 'builtin' config['server.ssl_certificate'] = cert_fname config['server.ssl_private_key'] = pkey_fname self.update_cherrypy_config(config) self._url_prefix = prepare_url_prefix(self.get_module_option('url_prefix', default='')) uri = "{0}://{1}:{2}{3}/".format( 'https' if ssl else 'http', socket.getfqdn() if server_addr in ['::', '0.0.0.0'] else server_addr, server_port, self.url_prefix ) return uri
'/favicon.ico': { 'tools.staticfile.on': True, 'tools.staticfile.filename': resourcedir + '/img/favicon.ico', }}) api.v1.mount('/api/v1') log.i(_('Starting server on port %s ...') % config['server.port']) cherrypy.lib.caching.expires(0) # disable expiry caching cherrypy.engine.start() cherrypy.engine.block() def _cm_auth_tool(httphandler): if not httphandler.isAuthorized(): raise cherrypy.HTTPError(403) cherrypy.tools.cm_auth = cherrypy.Tool( 'before_handler', _cm_auth_tool, priority=70) # priority=70 -->> make tool run after session is locked (at 50) def _get_user_consent_for_db_schema_update(reasons): """Ask the user if the database schema update should happen now """ import textwrap wrap = lambda r: os.linesep.join( textwrap.wrap(r, initial_indent=' - ', subsequent_indent=" ")) msg = _(""" ========================================================================== A database schema update is needed and requires your consent. {reasons}
def check_auth(*args, **kwargs): conditions = cherrypy.request.config.get('auth.require', None) if conditions is not None: username = cherrypy.session.get(SESSION_KEY) if username: cherrypy.request.login = username for condition in conditions: if not condition(): raise cherrypy.HTTPRedirect('/auth/login') else: raise cherrypy.HTTPRedirect('/auth/login') cherrypy.tools.auth = cherrypy.Tool('before_handler', check_auth) def require(*conditions): def decorate(f): if not hasattr(f, '_cp_config'): f._cp_config = dict() if 'auth.require' not in f._cp_config: f._cp_config['auth.require'] = [] f._cp_config['auth.require'].extend(conditions) return f return decorate class AuthController(object):
def _configure(self): """ Configure CherryPy and initialize self.url_prefix :returns our URI """ server_addr = self.get_localized_module_option( # type: ignore 'server_addr', get_default_addr()) use_ssl = self.get_localized_module_option('ssl', True) # type: ignore if not use_ssl: server_port = self.get_localized_module_option('server_port', 8080) # type: ignore else: server_port = self.get_localized_module_option('ssl_server_port', 8443) # type: ignore if server_addr is None: raise ServerConfigException( 'no server_addr configured; ' 'try "ceph config set mgr mgr/{}/{}/server_addr <ip>"' .format(self.module_name, self.get_mgr_id())) # type: ignore self.log.info('server: ssl=%s host=%s port=%d', 'yes' if use_ssl else 'no', # type: ignore server_addr, server_port) # Initialize custom handlers. cherrypy.tools.authenticate = AuthManagerTool() cherrypy.tools.plugin_hooks_filter_request = cherrypy.Tool( 'before_handler', lambda: PLUGIN_MANAGER.hook.filter_request_before_handler(request=cherrypy.request), priority=1) cherrypy.tools.request_logging = RequestLoggingTool() cherrypy.tools.dashboard_exception_handler = HandlerWrapperTool(dashboard_exception_handler, priority=31) cherrypy.log.access_log.propagate = False cherrypy.log.error_log.propagate = False # Apply the 'global' CherryPy configuration. config = { 'engine.autoreload.on': False, 'server.socket_host': server_addr, 'server.socket_port': int(server_port), 'error_page.default': json_error_page, 'tools.request_logging.on': True, 'tools.gzip.on': True, 'tools.gzip.mime_types': [ # text/html and text/plain are the default types to compress 'text/html', 'text/plain', # We also want JSON and JavaScript to be compressed 'application/json', 'application/*+json', 'application/javascript', ], 'tools.json_in.on': True, 'tools.json_in.force': True, 'tools.plugin_hooks_filter_request.on': True, } if use_ssl: # SSL initialization cert = self.get_localized_store("crt") # type: ignore if cert is not None: self.cert_tmp = tempfile.NamedTemporaryFile() self.cert_tmp.write(cert.encode('utf-8')) self.cert_tmp.flush() # cert_tmp must not be gc'ed cert_fname = self.cert_tmp.name else: cert_fname = self.get_localized_module_option('crt_file') # type: ignore pkey = self.get_localized_store("key") # type: ignore if pkey is not None: self.pkey_tmp = tempfile.NamedTemporaryFile() self.pkey_tmp.write(pkey.encode('utf-8')) self.pkey_tmp.flush() # pkey_tmp must not be gc'ed pkey_fname = self.pkey_tmp.name else: pkey_fname = self.get_localized_module_option('key_file') # type: ignore verify_tls_files(cert_fname, pkey_fname) # Create custom SSL context to disable TLS 1.0 and 1.1. context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) context.load_cert_chain(cert_fname, pkey_fname) if sys.version_info >= (3, 7): context.minimum_version = ssl.TLSVersion.TLSv1_2 else: context.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1 config['server.ssl_module'] = 'builtin' config['server.ssl_certificate'] = cert_fname config['server.ssl_private_key'] = pkey_fname config['server.ssl_context'] = context self.update_cherrypy_config(config) self._url_prefix = prepare_url_prefix(self.get_module_option( # type: ignore 'url_prefix', default='')) if server_addr in ['::', '0.0.0.0']: server_addr = self.get_mgr_ip() # type: ignore base_url = build_url( scheme='https' if use_ssl else 'http', host=server_addr, port=server_port, ) uri = f'{base_url}{self.url_prefix}/' return uri
def setup_sites(self): context_path = "%s/src/context" % self.install_dir doc_dir = "%s/doc" % self.install_dir plugin_dir = Environment.get_plugin_dir() builtin_plugin_dir = Environment.get_builtin_plugin_dir() dist_dir = Environment.get_dist_dir() log_dir = "%s/log" % Environment.get_tmp_dir() def CORS(): #cherrypy.response.headers["Access-Control-Allow-Origin"] = "http://192.168.0.15:8100" cherrypy.response.headers["Access-Control-Allow-Origin"] = "*" cherrypy.response.headers[ "Access-Control-Allow-Headers"] = "Origin, X-Requested-With, Content-Type, Accept" cherrypy.tools.CORS = cherrypy.Tool('before_handler', CORS) config = { 'global': { 'server.socket_host': '127.0.0.1', 'server.socket_port': 80, 'log.screen': False, 'request.show_tracebacks': True, 'tools.log_headers.on': True, 'server.log_file': "%s/tactic_log" % log_dir, 'server.max_request_body_size': 0, #'server.socket_timeout': 60, 'response.timeout': 3600, 'tools.encode.on': True, 'tools.encode.encoding': 'utf-8', 'tools.decode.on': True, 'tools.decode.encoding': 'utf-8', #'encoding_filter.on': True, #'decoding_filter.on': True 'tools.CORS.on': True }, '/context': { 'tools.staticdir.on': True, 'tools.staticdir.dir': context_path, # Need to do this because on windows servers, jar files # are served as text/html 'tools.staticdir.content_types': { 'jar': 'application/java-archive' } }, '/assets': { 'tools.staticdir.on': True, 'tools.staticdir.dir': Environment.get_asset_dir() }, '/doc': { 'tools.staticdir.on': True, 'tools.staticdir.dir': doc_dir, 'tools.staticdir.index': "index.html" }, # NOTE: expose the entire plugins directory '/tactic/plugins': { 'tools.staticdir.on': True, 'tools.staticdir.dir': plugin_dir, }, '/tactic/builtin_plugins': { 'tools.staticdir.on': True, 'tools.staticdir.dir': builtin_plugin_dir, }, '/tactic/dist': { 'tools.staticdir.on': True, 'tools.staticdir.dir': dist_dir, }, '/plugins': { 'tools.staticdir.on': True, 'tools.staticdir.dir': plugin_dir, }, '/builtin_plugins': { 'tools.staticdir.on': True, 'tools.staticdir.dir': builtin_plugin_dir, }, '/dist': { 'tools.staticdir.on': True, 'tools.staticdir.dir': dist_dir, }, } # set up the root directory cherrypy.root = Root() cherrypy.tree.mount(cherrypy.root, config=config) from pyasm.search import Search search = Search("sthpw/project") search.add_filter("type", "resource", op="!=") projects = search.get_sobjects() # find out if one of the projects is the root root_initialized = False if not root_initialized: project_code = Project.get_default_project() if not project_code: project_code = Config.get_value('install', 'default_project') if project_code and project_code != 'default': from tactic.ui.app import SitePage cherrypy.root.tactic = SitePage(project_code) cherrypy.root.projects = SitePage(project_code) root_initialized = True if not root_initialized: # load in the base site at root from tactic_sites.default.context.Index import Index cherrypy.root.tactic = Index() cherrypy.root.projects = Index() for project in projects: project_code = project.get_code() self.register_project(project_code, config) self.register_project("default", config) from pyasm.security import Site site_obj = Site.get() site_obj.register_sites(self, config) #self.register_project("vfx", config, site="vfx_demo") #self.register_project("default", config, site="vfx_demo") return config
if "APPENGINE_RUNTIME" in os.environ: google_app_engine = True else: google_app_engine = False # for simpler usage rpcmethod = rpclib.rpcmethod def _no_body_processor_tool(): if cherrypy.request.method == "POST": cherrypy.request.body.processors = {} cherrypy.tools.no_body_processor = cherrypy.Tool( "on_start_resource", _no_body_processor_tool ) class CherryPyJsonRpc(rpclib.JsonRpc): """ CherryPy JSON-RPC """ @cherrypy.expose @cherrypy.tools.encode(encoding = "utf-8") @cherrypy.tools.no_body_processor() def request_handler(self, *args, **kwargs): """ Json-RPC Handler """
def __init__(self, normalizer=None, svc_cfg=None): self.logger = c.logger self._backendp = BackendClientProcessor(exchange='', routing_key=c.AMQP_RPC_BACKEND_QUEUE) cherrypy.tools.cors_tool = cherrypy.Tool('before_request_body', cors_tool, name='cors_tool', priority=50) self._source_plugin = normalizer self._plugin_cfg = svc_cfg
def main(): p = argparse.ArgumentParser(description="Start a Tangelo server.") p.add_argument("-c", "--config", type=str, default=None, metavar="FILE", help="specifies configuration file or json string to use") p.add_argument( "-a", "--access-auth", action="store_const", const=True, default=None, help= "enable HTTP authentication (i.e. processing of .htaccess files) (default)" ) p.add_argument( "-na", "--no-access-auth", action="store_const", const=True, default=None, help="disable HTTP authentication (i.e. processing of .htaccess files)" ) p.add_argument( "-p", "--drop-privileges", action="store_const", const=True, default=None, help="enable privilege drop when started as superuser (default)") p.add_argument("-np", "--no-drop-privileges", action="store_const", const=True, default=None, help="disable privilege drop when started as superuser") p.add_argument("-s", "--sessions", action="store_const", const=True, default=None, help="enable session tracking (default)") p.add_argument("-ns", "--no-sessions", action="store_const", const=True, default=None, help="disable session tracking") p.add_argument("--list-dir", action="store_true", default=None, help="enable directory content serving") p.add_argument("--no-list-dir", action="store_true", default=None, help="disable directory content serving (default)") p.add_argument("--show-py", action="store_true", default=None, help="enable Python service source code serving") p.add_argument("--no-show-py", action="store_true", default=None, help="disable Python service source code serving (default)") p.add_argument( "--hostname", type=str, default=None, metavar="HOSTNAME", help="overrides configured hostname on which to run Tangelo") p.add_argument( "--port", type=int, default=None, metavar="PORT", help="overrides configured port number on which to run Tangelo") p.add_argument( "-u", "--user", type=str, default=None, metavar="USERNAME", help="specifies the user to run as when root privileges are dropped") p.add_argument( "-g", "--group", type=str, default=None, metavar="GROUPNAME", help="specifies the group to run as when root privileges are dropped") p.add_argument("-r", "--root", type=str, default=None, metavar="DIR", help="the directory from which Tangelo will serve content") p.add_argument("--verbose", "-v", action="append_const", help="display extra information as Tangelo runs", default=[logging.INFO], const=logging.DEBUG - logging.INFO) p.add_argument("--quiet", "-q", action="append_const", help="reduce the amount of information displayed", dest="verbose", const=logging.INFO - logging.DEBUG) p.add_argument("--version", action="store_true", help="display Tangelo version number") p.add_argument( "--key", type=str, default=None, metavar="FILE", help= "the path to the SSL key. You must also specify --cert to serve content over https." ) p.add_argument( "--cert", type=str, default=None, metavar="FILE", help= "the path to the SSL certificate. You must also specify --key to serve content over https." ) p.add_argument("--examples", action="store_true", default=None, help="Serve the Tangelo example applications") p.add_argument( "--watch", action="store_true", default=None, help="Add the watch plugin (reload python files if they change).") args = p.parse_args() # If version flag is present, print the version number and exit. if args.version: print tangelo_version return 0 # Set the verbosity log_level = max(sum(args.verbose), 1) cherrypy.log.error_log.setLevel(log_level) # Make sure user didn't specify conflicting flags. if args.access_auth and args.no_access_auth: tangelo.log_critical( "ERROR", "can't specify both --access-auth (-a) and --no-access-auth (-na) together" ) return 1 if args.drop_privileges and args.no_drop_privileges: tangelo.log_critical( "ERROR", "can't specify both --drop-privileges (-p) and --no-drop-privileges (-np) together" ) return 1 if args.no_sessions and args.sessions: tangelo.log_critical( "ERROR", "can't specify both --sessions (-s) and --no-sessions (-ns) together" ) return 1 if args.examples and args.root: tangelo.log_critical( "ERROR", "can't specify both --examples and --root (-r) together") return 1 if args.examples and args.config: tangelo.log_critical( "ERROR", "can't specify both --examples and --config (-c) together") return 1 if args.no_list_dir and args.list_dir: tangelo.log_critical( "ERROR", "can't specify both --list-dir and --no-list-dir together") return 1 if args.no_show_py and args.show_py: tangelo.log_critical( "ERROR", "can't specify both --show-py and --no-show-py together") return 1 # Report the logging level. if log_level > logging.CRITICAL: log_level_tag = "NONE" elif log_level > logging.ERROR: log_level_tag = "CRITICAL" elif log_level > logging.WARNING: log_level_tag = "ERROR" elif log_level > logging.INFO: log_level_tag = "WARNING" elif log_level > logging.DEBUG: log_level_tag = "INFO" else: log_level_tag = "DEBUG" tangelo.log_info("TANGELO", "Logging level: %s (%d)" % (log_level_tag, log_level)) # Decide if we have a configuration file or not. cfg_file = args.config if cfg_file is None: tangelo.log_info( "TANGELO", "No configuration file specified - using command line args and defaults" ) else: if os.path.exists(tangelo.util.expandpath( cfg_file)) or not cfg_file.startswith("{"): cfg_file = tangelo.util.expandpath(cfg_file) tangelo.log("TANGELO", "Using configuration file %s" % (cfg_file)) else: tangelo.log("TANGELO", "Using configuration string") # Parse the config file; report errors if any. try: config = Config(cfg_file) except (IOError, ValueError) as e: tangelo.log_critical("ERROR", e) return 1 # Type check the config entries. if not config.type_check(): for message in config.errors: tangelo.log_critical("TANGELO", message) return 1 # Determine whether to use access auth. access_auth = True if args.access_auth is None and args.no_access_auth is None: if config.access_auth is not None: access_auth = config.access_auth else: access_auth = (args.access_auth is not None) or (not args.no_access_auth) tangelo.log_info( "TANGELO", "Access authentication %s" % ("enabled" if access_auth else "disabled")) # Determine whether to perform privilege drop. drop_privileges = True if args.drop_privileges is None and args.no_drop_privileges is None: if config.drop_privileges is not None: drop_privileges = config.drop_privileges else: drop_privileges = (args.drop_privileges is not None) or (not args.no_drop_privileges) # Determine whether to enable sessions. sessions = True if args.sessions is None and args.no_sessions is None: if config.sessions is not None: sessions = config.sessions else: sessions = (args.sessions is not None) or (not args.no_sessions) tangelo.log_info("TANGELO", "Sessions %s" % ("enabled" if sessions else "disabled")) # Determine whether to serve directory listings by default. listdir = False if args.list_dir is None and args.no_list_dir is None: if config.list_dir is not None: listdir = config.list_dir else: listdir = (args.list_dir is not None) or (not args.no_list_dir) cherrypy.config["listdir"] = listdir tangelo.log_info( "TANGELO", "Directory content serving %s" % ("enabled" if listdir else "disabled")) # Determine whether to serve web service Python source code by default. showpy = False if args.show_py is None and args.no_show_py is None: if config.show_py is not None: showpy = config.show_py else: showpy = (args.show_py is not None) or (not args.no_show_py) cherrypy.config["showpy"] = showpy tangelo.log_info( "TANGELO", "Web service source code serving %s" % ("enabled" if showpy else "disabled")) # Extract the rest of the arguments, giving priority first to command line # arguments, then to the configuration file (if any), and finally to a # hard-coded default value. hostname = args.hostname or config.hostname or "localhost" port = args.port or config.port or 8080 user = args.user or config.user or "nobody" group = args.group or config.group or "nobody" tangelo.log_info("TANGELO", "Hostname: %s" % (hostname)) tangelo.log_info("TANGELO", "Port: %d" % (port)) tangelo.log_info( "TANGELO", "Privilege drop %s" % ("enabled (if necessary)" if drop_privileges else "disabled")) if drop_privileges: tangelo.log_info("TANGELO", "\tUser: %s" % (user)) tangelo.log_info("TANGELO", "\tGroup: %s" % (group)) # HTTPS support # # Grab the ssl key file. ssl_key = args.key or config.key if ssl_key is not None: ssl_key = tangelo.util.expandpath(ssl_key) # Grab the cert file. ssl_cert = args.cert or config.cert if ssl_cert is not None: ssl_cert = tangelo.util.expandpath(ssl_cert) # In order to enable HTTPS, *both* the key and cert must be specified. If # only one or the other is specified, this is considered an error, because # we don't want to serve what the user is considering sensitive content over # HTTP by default. if ssl_key is not None and ssl_cert is not None: cherrypy.config.update({ "server.ssl_module": "pyopenssl", "server.ssl_certificate": ssl_cert, "server.ssl_private_key": ssl_key }) tangelo.log_info("TANGELO", "HTTPS enabled") tangelo.log_info("TANGELO", "\tSSL Cert file: %s" % (ssl_cert)) tangelo.log_info("TANGELO", "\tSSL Key file: %s" % (ssl_key)) elif not (ssl_key is None and ssl_cert is None): tangelo.log_critical("TANGELO", "error: SSL key or SSL cert missing") return 1 else: tangelo.log_info("TANGELO", "HTTPS disabled") # We need a web root - use the installed example web directory as a # fallback. This might be found in a few different places, so try them one # by one until we find one that exists. root = args.root or config.root if root: root = tangelo.util.expandpath(root) elif args.examples: # Set the examples web root. root = get_web_directory() tangelo.log_info("TANGELO", "Looking for example web content path in %s" % (root)) if not os.path.exists(root): tangelo.log_critical("ERROR", "could not find examples package") return 1 # Set the examples plugins. config.plugins = [{ "name": "config" }, { "name": "data" }, { "name": "docs" }, { "name": "mapping" }, { "name": "mongo" }, { "name": "stream" }, { "name": "tangelo" }, { "name": "ui" }, { "name": "vis" }] else: root = tangelo.util.expandpath(".") # All that the core does when --watch is includes is to make sure it is in # the list of plugins. If it isn't present, it gets added to the beginning # of the list so that other plugins will be monitored. if args.watch: if config.plugins is None: config.plugins = [] if "watch" not in [plugin.get("name") for plugin in config.plugins]: config.plugins.insert(0, {"name": "watch"}) tangelo.log_info("TANGELO", "Serving content from %s" % (root)) # Set the web root directory. cherrypy.config.update({"webroot": root}) # Place an empty dict to hold per-module configuration into the global # configuration object, and one for persistent per-module storage (the # latter can be manipulated by the service). cherrypy.config.update({"module-config": {}}) cherrypy.config.update({"module-store": {}}) # Analogs of the module storage dicts, but for plugins. cherrypy.config.update({"plugin-config": {}}) cherrypy.config.update({"plugin-store": {}}) # Create a plugin manager. plugins = tangelo.server.Plugins("tangelo.plugin", config=config.plugins, plugin_dir=get_bundled_plugin_directory()) # Check for any errors - if there are, report them and exit. if not plugins.good(): for message in plugins.errors: tangelo.log_critical("PLUGIN", message) return 1 # Save the plugin manager for use later (when unloading plugins during # shutdown). cherrypy.config.update({"plugins": plugins}) # Create an instance of the main handler object. module_cache = tangelo.util.ModuleCache() tangelo_server = tangelo.server.Tangelo(module_cache=module_cache, plugins=plugins) rootapp = cherrypy.Application(tangelo_server, "/") # Place an AuthUpdate handler in the Tangelo object if access authorization # is on. tangelo_server.auth_update = tangelo.server.AuthUpdate(app=rootapp) # Mount the root application object. cherrypy.tree.mount(rootapp, config={ "/": { "tools.sessions.on": sessions }, "/favicon.ico": { "tools.staticfile.on": True, "tools.staticfile.filename": get_tangelo_ico() } }) # Set up the global configuration. cherrypy.config.update({ "environment": "production", "log.screen": True, "server.socket_host": hostname, "server.socket_port": port }) # Dump in any other global configuration present in the configuration. if config.server_settings: tangelo.log_info("TANGELO", "User server settings:") for setting, value in config.server_settings.iteritems(): tangelo.util.set_server_setting(setting, value) tangelo.log_info( "TANGELO", "\t%s -> %s" % (setting, cherrypy.config.get(setting))) # Try to drop privileges if requested, since we've bound to whatever port # superuser privileges were needed for already. if drop_privileges: # If we're on windows, don't supply any username/groupname, and just # assume we should drop priveleges. if platform.system() == "Windows": tangelo.log_info("TANGELO", "Performing privilege drop") cherrypy.process.plugins.DropPrivileges( cherrypy.engine).subscribe() elif os.getuid() == 0: tangelo.log_info("TANGELO", "Performing privilege drop") # Reaching here means we're on unix, and we are the root user, so go # ahead and drop privileges to the requested user/group. import grp import pwd # On some systems, negative uids and gids are allowed. These can # render in Python (in particular, on OS X) as very large unsigned # values. This function first checks to see if the input value is # already negative; if so, there's no issue and we return it # unchanged. Otherwise, we treat the argument as a bit # representation of a *signed* value, check the sign bit to see if # it *should* be a negative number, and then perform the proper # arithmetic to turn it into a signed one. def to_signed(val): # If we already see a negative number, just return it. if val < 0: return val # Check sign bit, and subtract the unsigned range from the value # if it is set. return val - 0x100000000 if val & 0x80000000 else val # Find the UID and GID for the requested user and group. try: mode = "user" value = user uid = to_signed(pwd.getpwnam(user).pw_uid) mode = "group" value = group gid = to_signed(grp.getgrnam(group).gr_gid) except KeyError: tangelo.log_critical( "TANGELO", "no such %s '%s' to drop privileges to" % (mode, value)) return 1 # Set the process home directory to be the dropped-down user's. os.environ["HOME"] = os.path.expanduser("~%s" % (user)) # Perform the actual UID/GID change. cherrypy.process.plugins.DropPrivileges(cherrypy.engine, uid=uid, gid=gid).subscribe() else: tangelo.log_info( "TANGELO", "Not performing privilege drop (because not running as superuser)" ) # Set up websocket handling. Use the pass-through subclassed version of the # plugin so we can set a priority on it that doesn't conflict with privilege # drop. tangelo.websocket.WebSocketLowPriorityPlugin(cherrypy.engine).subscribe() cherrypy.tools.websocket = ws4py.server.cherrypyserver.WebSocketTool() # Replace the stock auth_digest and auth_basic tools with ones that have # slightly lower priority (so the AuthUpdate tool can run before them). cherrypy.tools.auth_basic = cherrypy.Tool( "before_handler", cherrypy.lib.auth_basic.basic_auth, priority=2) cherrypy.tools.auth_digest = cherrypy.Tool( "before_handler", cherrypy.lib.auth_digest.digest_auth, priority=2) # Install signal handlers to allow for proper cleanup/shutdown. for sig in [signal.SIGINT, signal.SIGTERM]: signal.signal(sig, shutdown) # Send SIGQUIT to an immediate, ungraceful shutdown instead. if platform.system() != "Windows": signal.signal(signal.SIGQUIT, die) # Start the CherryPy engine. cherrypy.engine.start() tangelo.log_info("\033[32mTANGELO", "\033[32mServer is running") cherrypy.engine.block()
_version = get_version() _com_args, _op_arg, config = cb_setup(args) folder = os.path.abspath(os.curdir) _flowsdir = os.path.normpath(os.path.join(folder, args.flowsdir)) _flows = Flow(_flowsdir, profile_handler=SimpleProfileHandler) try: csi = config.CHECK_SESSION_IFRAME except AttributeError: op_handler = OPHandler(provider.Provider, _op_arg, _com_args, _flows, folder) else: op_handler = OPHandler(provider.Provider, _op_arg, _com_args, _flows, folder, csi.format(args.port)) cherrypy.tools.dumplog = cherrypy.Tool('before_finalize', dump_log) cherrypy.config.update({ 'environment': 'production', 'log.error_file': 'site.log', 'tools.trailing_slash.on': False, 'server.socket_host': '0.0.0.0', 'log.screen': True, 'tools.sessions.on': True, 'tools.encode.on': True, 'tools.encode.encoding': 'utf-8', 'tools.dumplog.on': True, 'server.socket_port': args.port }) provider_config = {
def _configure(self): """ Configure CherryPy and initialize self.url_prefix :returns our URI """ server_addr = self.get_localized_config('server_addr', '::') server_port = self.get_localized_config('server_port', '8443') if server_addr is None: raise ServerConfigException( 'no server_addr configured; ' 'try "ceph config set mgr mgr/{}/{}/server_addr <ip>"'.format( self.module_name, self.get_mgr_id())) self.log.info('server_addr: %s server_port: %s', server_addr, server_port) # Initialize custom handlers. cherrypy.tools.authenticate = cherrypy.Tool('before_handler', Auth.check_auth) cherrypy.tools.session_expire_at_browser_close = SessionExpireAtBrowserCloseTool( ) cherrypy.tools.request_logging = RequestLoggingTool() # SSL initialization cert = self.get_store("crt") if cert is not None: self.cert_tmp = tempfile.NamedTemporaryFile() self.cert_tmp.write(cert.encode('utf-8')) self.cert_tmp.flush() # cert_tmp must not be gc'ed cert_fname = self.cert_tmp.name else: cert_fname = self.get_localized_config('crt_file') pkey = self.get_store("key") if pkey is not None: self.pkey_tmp = tempfile.NamedTemporaryFile() self.pkey_tmp.write(pkey.encode('utf-8')) self.pkey_tmp.flush() # pkey_tmp must not be gc'ed pkey_fname = self.pkey_tmp.name else: pkey_fname = self.get_localized_config('key_file') if not cert_fname or not pkey_fname: raise ServerConfigException('no certificate configured') if not os.path.isfile(cert_fname): raise ServerConfigException('certificate %s does not exist' % cert_fname) if not os.path.isfile(pkey_fname): raise ServerConfigException('private key %s does not exist' % pkey_fname) # Apply the 'global' CherryPy configuration. config = { 'engine.autoreload.on': False, 'server.socket_host': server_addr, 'server.socket_port': int(server_port), 'server.ssl_module': 'builtin', 'server.ssl_certificate': cert_fname, 'server.ssl_private_key': pkey_fname, 'error_page.default': json_error_page, 'tools.request_logging.on': True } cherrypy.config.update(config) self._url_prefix = prepare_url_prefix( self.get_config('url_prefix', default='')) uri = "https://{0}:{1}{2}/".format( socket.getfqdn() if server_addr == "::" else server_addr, server_port, self.url_prefix) return uri