summaryrefslogtreecommitdiff
path: root/cherrypy/server.py
diff options
context:
space:
mode:
Diffstat (limited to 'cherrypy/server.py')
-rw-r--r--cherrypy/server.py211
1 files changed, 211 insertions, 0 deletions
diff --git a/cherrypy/server.py b/cherrypy/server.py
new file mode 100644
index 00000000..d820c1e4
--- /dev/null
+++ b/cherrypy/server.py
@@ -0,0 +1,211 @@
+"""
+Copyright (c) 2004, CherryPy Team (team@cherrypy.org)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the CherryPy Team nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""
+
+"""
+Main CherryPy module:
+ - Creates a server
+"""
+
+import threading
+import time
+import sys
+
+import cherrypy
+from cherrypy import _cphttptools
+from cherrypy.lib import autoreload, profiler
+
+try:
+ from threading import local
+except ImportError:
+ from cherrypy._cpthreadinglocal import local
+
+
+# Set some special attributes for adding hooks
+onStartServerList = []
+onStartThreadList = []
+onStopServerList = []
+onStopThreadList = []
+
+def start(initOnly=False, serverClass=None):
+ if cherrypy.config.get("server.environment") == "development":
+ # Check initOnly. If True, we're probably not starting
+ # our own webserver, and therefore could do Very Bad Things
+ # when autoreload calls sys.exit.
+ if not initOnly:
+ autoreload.main(_start, (initOnly, serverClass))
+ return
+
+ _start(initOnly, serverClass)
+
+def _start(initOnly=False, serverClass=None):
+ """
+ Main function. All it does is this:
+ - output config options
+ - create response and request objects
+ - starts a server
+ """
+
+ # Create request and response object (the same objects will be used
+ # throughout the entire life of the webserver)
+ cherrypy.request = local()
+ cherrypy.response = local()
+
+ # Create as sessions object for accessing session data
+ cherrypy.sessions = local()
+
+ # Create threadData object as a thread-specific all-purpose storage
+ cherrypy.threadData = local()
+
+ # Output config options to log
+ if cherrypy.config.get("server.logConfigOptions", True):
+ cherrypy.config.outputConfigMap()
+
+ # Check the config options
+ # TODO
+ # config.checkConfigOptions()
+
+ # Initialize a few global variables
+ cherrypy._lastCacheFlushTime = time.time()
+ cherrypy._lastSessionCleanUpTime = time.time()
+ cherrypy._sessionMap = {} # Map of "cookie" -> ("session object", "expiration time")
+
+ # If sessions are stored in files and we
+ # use threading, we need a lock on the file
+ if (cherrypy.config.get('server.threadPool') > 1
+ and cherrypy.config.get('session.storageType') == 'file'):
+ cherrypy._sessionFileLock = threading.RLock()
+
+ # Call the functions from cherrypy.server.onStartServerList
+ for func in cherrypy.server.onStartServerList:
+ func()
+
+ # Set up the profiler if requested.
+ if cherrypy.config.get("profiling.on", False):
+ ppath = cherrypy.config.get("profiling.path", "")
+ cherrypy.profiler = profiler.Profiler(ppath)
+ else:
+ cherrypy.profiler = None
+
+ if not initOnly:
+ run_server(serverClass)
+
+def run_server(serverClass=None):
+ """Prepare the requested server and then run it."""
+
+ # Instantiate the server.
+ if serverClass is None:
+ serverClass = cherrypy.config.get("server.class", None)
+ if serverClass and isinstance(serverClass, basestring):
+ serverClass = attributes(serverClass)
+ if serverClass is None:
+ import _cpwsgi
+ serverClass = _cpwsgi.WSGIServer
+
+ cherrypy._httpserver = serverClass()
+
+ if cherrypy.config.get('server', 'socketPort'):
+ onWhat = "socket: ('%s', %s)" % (cherrypy.config.get('server.socketHost'),
+ cherrypy.config.get('server.socketPort'))
+ else:
+ onWhat = "socket file: %s" % cherrypy.config.get('server.socketFile')
+ cherrypy.log("Serving HTTP on %s" % onWhat, 'HTTP')
+
+ # Start the http server.
+ try:
+ cherrypy._httpserver.start()
+ except (KeyboardInterrupt, SystemExit):
+ cherrypy.log("<Ctrl-C> hit: shutting down", "HTTP")
+ stop()
+
+def modules(modulePath):
+ """Load a module and retrieve a reference to that module."""
+ try:
+ aMod = sys.modules[modulePath]
+ if aMod is None:
+ raise KeyError
+ except KeyError:
+ # The last [''] is important.
+ aMod = __import__(modulePath, globals(), locals(), [''])
+ return aMod
+
+def attributes(fullAttributeName):
+ """Load a module and retrieve an attribute of that module."""
+
+ # Parse out the path, module, and attribute
+ lastDot = fullAttributeName.rfind(u".")
+ attrName = fullAttributeName[lastDot + 1:]
+ modPath = fullAttributeName[:lastDot]
+
+ aMod = modules(modPath)
+ # Let an AttributeError propagate outward.
+ try:
+ anAttr = getattr(aMod, attrName)
+ except AttributeError:
+ raise AttributeError("'%s' object has no attribute '%s'"
+ % (modPath, attrName))
+
+ # Return a reference to the attribute.
+ return anAttr
+
+
+seen_threads = {}
+
+def request(clientAddress, remoteHost, requestLine, headers, rfile):
+ threadID = threading._get_ident()
+ if threadID not in seen_threads:
+ i = len(seen_threads) + 1
+ seen_threads[threadID] = i
+ # Call the functions from cherrypy.server.onStartThreadList
+ for func in cherrypy.server.onStartThreadList:
+ func(i)
+
+ if cherrypy.profiler:
+ cherrypy.profiler.run(_cphttptools.Request, clientAddress, remoteHost,
+ requestLine, headers, rfile)
+ else:
+ _cphttptools.Request(clientAddress, remoteHost,
+ requestLine, headers, rfile)
+
+def stop():
+ """Shutdown CherryPy (and any HTTP servers it started)."""
+ try:
+ httpstop = cherrypy._httpserver.stop
+ except AttributeError:
+ pass
+ else:
+ httpstop()
+
+ # Call the functions from cherrypy.server.onStopThreadList
+ for thread_ident, i in seen_threads.iteritems():
+ for func in cherrypy.server.onStopThreadList:
+ func(i)
+ seen_threads.clear()
+
+ # Call the functions from cherrypy.server.onStopServerList
+ for func in cherrypy.server.onStopServerList:
+ func()