CherryPy / _cpengine.py

Robert Brewer c740834 
Robert Brewer 1c3ef31 

Robert Brewer 238fba6 
Robert Brewer ec0aafa 
Robert Brewer 1c3ef31 




Robert Brewer a716407 
Robert Brewer 1c3ef31 
Robert Brewer c740834 
Robert Brewer 1c3ef31 




Robert Brewer 238fba6 






Robert Brewer e7868db 




Robert Brewer d3f51ed 
Robert Brewer e7868db 







Robert Brewer ec0aafa 
Robert Brewer 25739c0 
Robert Brewer 1c3ef31 
Robert Brewer c740834 
Robert Brewer 1c3ef31 
Robert Brewer a716407 

Robert Brewer 1c3ef31 




Robert Brewer c740834 

Robert Brewer 1c3ef31 

Robert Brewer c740834 
Robert Brewer 238fba6 
Robert Brewer adb12ff 

Robert Brewer 238fba6 

Robert Brewer 1c3ef31 
Robert Brewer c740834 



Robert Brewer 1c3ef31 


Robert Brewer 8f6f557 

Robert Brewer 1c3ef31 
Robert Brewer c740834 
Robert Brewer 1c3ef31 
Robert Brewer adb12ff 
Robert Brewer 1c3ef31 
Robert Brewer adb12ff 





Robert Brewer c740834 

Robert Brewer 1c3ef31 

Robert Brewer 890592f 
Robert Brewer 1c3ef31 
Robert Brewer 238fba6 




Robert Brewer 890592f 
Robert Brewer 1c3ef31 
Robert Brewer 238fba6 






Robert Brewer 1c3ef31 
Robert Brewer c740834 

Robert Brewer 1c3ef31 

Robert Brewer c740834 

Robert Brewer 1c3ef31 
Robert Brewer e2859b0 
Robert Brewer 1c3ef31 

Robert Brewer c740834 
Robert Brewer 1c3ef31 


Robert Brewer 238fba6 



















Robert Brewer 09ceda5 




Robert Brewer 238fba6 


Robert Brewer 09ceda5 

Robert Brewer 238fba6 

Robert Brewer 09ceda5 
Robert Brewer 238fba6 
Robert Brewer 09ceda5 



Robert Brewer 238fba6 
Robert Brewer 1c3ef31 
Robert Brewer c740834 
Robert Brewer 522b98a 








Robert Brewer adb12ff 



Robert Brewer 522b98a 

Robert Brewer 1c3ef31 

Robert Brewer c740834 
Robert Brewer 1c3ef31 
Robert Brewer c740834 
Robert Brewer 1c3ef31 







Robert Brewer c740834 
Robert Brewer 1c3ef31 

Robert Brewer 25739c0 
Robert Brewer 1c3ef31 

Robert Brewer 25739c0 

Robert Brewer 1c3ef31 


Robert Brewer adb12ff 
Robert Brewer 1c3ef31 
Robert Brewer adb12ff 
Robert Brewer f14b731 








Robert Brewer adb12ff 













Robert Brewer c740834 

















Robert Brewer 1c3ef31 
Robert Brewer f14b731 




Christian Wyglen… 1611a78 
Robert Brewer f14b731 
Robert Brewer 238fba6 


Robert Brewer eceb4cb 
Robert Brewer f14b731 




Robert Brewer 992e64b 































"""Create and manage the CherryPy application engine."""

import cgi
import os
import signal
import sys
import threading
import time

import cherrypy
from cherrypy import _cprequest

# Use a flag to indicate the state of the application engine.
STOPPED = 0
STARTING = None
STARTED = 1


def fileattr(m):
    if hasattr(m, "__loader__"):
        if hasattr(m.__loader__, "archive"):
            return m.__loader__.archive
    return getattr(m, "__file__", None)


try:
    if hasattr(signal, "SIGHUP"):
        def SIGHUP(signum=None, frame=None):
            cherrypy.engine.reexec()
        signal.signal(signal.SIGHUP, SIGHUP)

    if hasattr(signal, "SIGTERM"):
        def SIGTERM(signum=None, frame=None):
            cherrypy.server.stop()
            cherrypy.engine.stop()
        signal.signal(signal.SIGTERM, SIGTERM)
except ValueError, _signal_exc:
    if _signal_exc.args[0] != "signal only works in main thread":
        raise


class Engine(object):
    """The application engine, which exposes a request interface to (HTTP) servers."""
    
    request_class = _cprequest.Request
    response_class = _cprequest.Response
    
    def __init__(self):
        self.state = STOPPED
        
        # Startup/shutdown hooks
        self.on_start_engine_list = []
        self.on_stop_engine_list = []
        self.on_start_thread_list = []
        self.on_stop_thread_list = []
        self.seen_threads = {}
        
        self.servings = []
        
        self.mtimes = {}
        self.reload_files = []
    
    def start(self, blocking=True):
        """Start the application engine."""
        self.state = STARTING
        
        conf = cherrypy.config.get
        
        # Output config options to log
        if conf("log_config", True):
            cherrypy.config.log_config()
        
        for func in self.on_start_engine_list:
            func()
        
        self.state = STARTED
        
        freq = float(cherrypy.config.get('deadlock_poll_freq', 60))
        if freq > 0:
            self.monitor_thread = threading.Timer(freq, self.monitor)
            self.monitor_thread.start()
        
        if blocking:
            self.block()
    
    def block(self):
        """Block forever (wait for stop(), KeyboardInterrupt or SystemExit)."""
        try:
            autoreload = cherrypy.config.get('autoreload.on', False)
            if autoreload:
                i = 0
                freq = cherrypy.config.get('autoreload.frequency', 1)
            
            while self.state != STOPPED:
                time.sleep(.1)
                
                # Autoreload
                if autoreload:
                    i += .1
                    if i > freq:
                        i = 0
                        self.autoreload()
        except KeyboardInterrupt:
            cherrypy.log("<Ctrl-C> hit: shutting down app engine", "ENGINE")
            cherrypy.server.stop()
            self.stop()
        except SystemExit:
            cherrypy.log("SystemExit raised: shutting down app engine", "ENGINE")
            cherrypy.server.stop()
            self.stop()
            raise
        except:
            # Don't bother logging, since we're going to re-raise.
            # Note that we don't stop the HTTP server here.
            self.stop()
            raise
    
    def reexec(self):
        """Re-execute the current process."""
        cherrypy.server.stop()
        self.stop()
        
        args = sys.argv[:]
        cherrypy.log("Re-spawning %s" % " ".join(args), "ENGINE")
        args.insert(0, sys.executable)
        
        if sys.platform == "win32":
            args = ['"%s"' % arg for arg in args]
        os.execv(sys.executable, args)
    
    def autoreload(self):
        """Reload the process if registered files have been modified."""
        for filename in map(fileattr, sys.modules.values()) + self.reload_files:
            if filename:
                if filename.endswith(".pyc"):
                    filename = filename[:-1]
                
                oldtime = self.mtimes.get(filename, 0)
                if oldtime is None:
                    # Module with no .py file. Skip it.
                    continue
                
                try:
                    mtime = os.stat(filename).st_mtime
                except OSError:
                    # Either a module with no .py file, or it's been deleted.
                    mtime = None
                
                if filename not in self.mtimes:
                    # If a module has no .py file, this will be None.
                    self.mtimes[filename] = mtime
                else:
                    if mtime is None or mtime > oldtime:
                        # The file has been deleted or modified.
                        self.reexec()
    
    def stop(self):
        """Stop the application engine."""
        if self.state != STOPPED:
            for thread_ident, i in self.seen_threads.iteritems():
                for func in self.on_stop_thread_list:
                    func(i)
            self.seen_threads.clear()
            
            for func in self.on_stop_engine_list:
                func()
            
            if self.monitor_thread:
                self.monitor_thread.cancel()
                self.monitor_thread = None
            
            self.state = STOPPED
            cherrypy.log("CherryPy shut down", "ENGINE")
    
    def restart(self):
        """Restart the application engine (doesn't block)."""
        self.stop()
        self.start(blocking=False)
    
    def wait(self):
        """Block the caller until ready to receive requests (or error)."""
        while not self.ready:
            time.sleep(.1)
    
    def _is_ready(self):
        return bool(self.state == STARTED)
    ready = property(_is_ready, doc="Return True if the engine is ready to"
                                    " receive requests, False otherwise.")
    
    def request(self, local_host, remote_host, scheme="http"):
        """Obtain an HTTP Request object.
        
        local_host should be an http.Host object with the server info.
        remote_host should be an http.Host object with the client info.
        scheme: either "http" or "https"; defaults to "http"
        """
        if self.state == STOPPED:
            req = NotReadyRequest("The CherryPy engine has stopped.")
        elif self.state == STARTING:
            req = NotReadyRequest("The CherryPy engine could not start.")
        else:
            # Only run on_start_thread_list if the engine is running.
            threadID = threading._get_ident()
            if threadID not in self.seen_threads:
                i = len(self.seen_threads) + 1
                self.seen_threads[threadID] = i
                
                for func in self.on_start_thread_list:
                    func(i)
            req = self.request_class(local_host, remote_host, scheme)
        cherrypy.serving.request = req
        cherrypy.serving.response = resp = self.response_class()
        self.servings.append((req, resp))
        return req
    
    def monitor(self):
        """Check timeout on all responses."""
        if self.state == STARTED:
            for req, resp in self.servings:
                resp.check_timeout()
            freq = float(cherrypy.config.get('deadlock_poll_freq', 60))
            self.monitor_thread = threading.Timer(freq, self.monitor)
            self.monitor_thread.start()
    
    def start_with_callback(self, func, args=None, kwargs=None):
        """Start, then callback the given func in a new thread."""
        
        if args is None:
            args = ()
        if kwargs is None:
            kwargs = {}
        args = (func,) + args
        
        def _callback(func, *a, **kw):
            self.wait()
            func(*a, **kw)
        t = threading.Thread(target=_callback, args=args, kwargs=kwargs)
        t.setName("CPEngine Callback " + t.getName())
        t.start()
        
        self.start()


class NotReadyRequest:
    
    def __init__(self, msg):
        self.msg = msg
        self.protocol = (1,1)
    
    def close(self):
        pass
    
    def run(self, method, path, query_string, protocol, headers, rfile):
        self.method = "GET"
        cherrypy.HTTPError(503, self.msg).set_response()
        cherrypy.response.finalize()
        return cherrypy.response


def drop_privileges(new_user='nobody', new_group='nogroup'):
    """Drop privileges. UNIX only."""
    # Special thanks to Gavin Baker: http://antonym.org/node/100.
    
    import pwd, grp
    
    def names():
        return pwd.getpwuid(os.getuid())[0], grp.getgrgid(os.getgid())[0]
    name, group = names()
    cherrypy.log('Started as %r/%r' % (name, group), "PRIV")
    
    if os.getuid() != 0:
        # We're not root so, like, whatever dude.
        cherrypy.log("Already running as %r" % name, "PRIV")
        return
    
    # Try setting the new uid/gid (from new_user/new_group).
    try:
        os.setgid(grp.getgrnam(new_group)[2])
    except OSError, e:
        cherrypy.log('Could not set effective group id: %r' % e, "PRIV")
    
    try:
        os.setuid(pwd.getpwnam(new_user)[2])
    except OSError, e:
        cherrypy.log('Could not set effective user id: %r' % e, "PRIV")
    
    # Ensure a very convervative umask
    old_umask = os.umask(077)
    cherrypy.log('Old umask: %o, new umask: 077' % old_umask, "PRIV")
    cherrypy.log('Running as %r/%r' % names(), "PRIV")
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.