Commits

Robert Brewer committed c6576d4

Implements ticket #195.
1. cpg module removed, all content moved into cherrypy.__init__.
2. Removed some circular imports in sessionfilter by moving sessionfilter.sessionfilter and _sessionTypes into sessionfilter.__init__.
3. renamed _cpconfig to "config".
4. renamed _cpserver to "server".
5. renamed cperror to _cperror; cherrypy.__init__ now imports * from _cperror.

  • Participants
  • Parent commits 48699a5
  • Branches cherrypy

Comments (0)

Files changed (64)

+"""
+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.
+"""
+
+"""
+Global module that all modules developing with CherryPy should import.
+"""
+
 __version__ = '2.1.0 alpha'
+
+from _cperror import *
+
+import config
+import server
+
+_httpserver = None
+
+# decorator function for exposing methods
+def expose(func):
+    func.exposed = True
+    return func
+
+def log(msg, context='', severity=0):
+    """Syntactic sugar for writing to the log."""
+    import _cputil
+    logfunc = _cputil.getSpecialAttribute('_cpLogMessage')
+    logfunc(msg, context, severity)
+

File _cpconfig.py

-
-import ConfigParser
-
-import _cputil, cperror
-from lib import autoreload
-
-cpg = None # delayed import
-def init():
-    global cpg
-    if not cpg:
-        import cpg
-    reset()
-
-def reset(useDefaults=True):
-    configMap.clear()
-    if useDefaults:
-        configMap["global"] = defaultGlobal.copy()
-
-# This configMap dict holds the settings metadata for all cpg objects.
-# Keys are URL paths, and values are dicts.
-configMap = {}
-
-defaultGlobal = {
-    'server.socketPort': 8080,
-    'server.socketHost': '',
-    'server.socketFile': '',
-    'server.socketQueueSize': 5,
-
-    'server.environment': 'development',
-    'server.protocolVersion': 'HTTP/1.0',
-    'server.logToScreen': True,
-    'server.logFile': '',
-    'server.reverseDNS': False,
-    'server.threadPool': 0,
-
-    'sessionFilter.on' : False,
-    'sessionFilter.sessionList' : ['default'],
-    'sessionFilter.default.on': True,
-    'sessionFilter.default.timeout': 60,
-    'sessionFilter.default.cleanUpDelay': 60,
-    'sessionFilter.default.storageType' : 'ram',
-    'sessionFilter.default.cookiePrefix': 'CherryPySession',
-    'sessionFilter.default.storageFileDir': '.sessionFiles'
-    }
-
-def update(updateMap=None, file=None):
-    if updateMap:
-        for section, valueMap in updateMap.items():
-            if not isinstance(valueMap, dict):
-                # Shortcut syntax
-                #   ex: update({'server.socketPort': 80})
-                valueMap = {section: valueMap}
-                section = 'global'
-            s = configMap.get(section)
-            if not s:
-                configMap[section] = valueMap
-            else:
-                s.update(valueMap)
-    if file:
-        if file not in autoreload.reloadFiles:
-            autoreload.reloadFiles.append(file)
-        _load(file)
-
-def get(key, defaultValue=None, returnSection=False, startPath = None):
-    # Look, ma, no Python function calls! Uber-fast.
-    # start path lest you overload the starting search path (needed by getAll)
-    if startPath:
-        path = startPath
-    else:
-        try:
-            path = cpg.request.path
-        except AttributeError:
-            path = "/"
-    
-    while True:
-        if path == "":
-            path = "/"
-        try:
-            result = configMap[path][key]
-        except KeyError:
-            if path not in ("/", "global"):
-                i = path.rfind("/")
-                if i < 0:
-                    result = defaultValue
-                else:
-                    path = path[:i]
-                    continue
-            elif path != "global":
-                path = "global"
-                continue
-            else:
-                result = defaultValue
-        break
-    
-    if returnSection:
-        if path == 'global':
-            return '/'
-        return path
-    else:
-        return result
-        
-import os.path
-
-def getAll(key):
-    """
-    getAll will lookup the key in the current node and all of its parent nodes,
-    it will return a dictionary paths of each node containing the key and its value
-
-    This function is required by the session filter
-    """
-    path = get(key, None, returnSection = True)
-    value = get(key)
-    
-    result = {}
-    while value != None and path != '/':
-        result[path]= value
-        path = os.path.split(path)[0]
-        value = get(key, None, returnSection = False, startPath = path)
-        path  = get(key, None, returnSection = True, startPath = path)
-    
-    if path == '/' and value != None:
-        result[path] = value
-    
-    return result
-
-class CaseSensitiveConfigParser(ConfigParser.ConfigParser):
-    """ Sub-class of ConfigParser that keeps the case of options and
-        that raises an exception if the file cannot be read
-    """
-    def optionxform(self, optionstr):
-        return optionstr
-    def read(self, filenames):
-        if isinstance(filenames, basestring):
-            filenames = [filenames]
-        for filename in filenames:
-            # try:
-            #     fp = open(filename)
-            # except IOError:
-            #     continue
-            fp = open(filename)
-            self._read(fp, filename)
-            fp.close()
-
-def _load(configFile = None):
-    """ Convert an INI file to a dictionary """
-    
-    # Parse config file
-    configParser = CaseSensitiveConfigParser()
-    if hasattr(configFile, 'read'):
-        cpg.log("Reading infos from configFile stream", 'CONFIG')
-        configParser.readfp(configFile)
-    else:
-        cpg.log("Reading infos from configFile: %s" % configFile, 'CONFIG')
-        configParser.read(configFile)
-
-    # Load INI file into cpg.configMap
-    for section in configParser.sections():
-        if section not in configMap:
-            configMap[section] = {}
-        for option in configParser.options(section):
-            value = configParser.get(section, option)
-            try:
-                value = _cputil.unrepr(value)
-            except cperror.WrongUnreprValue, s:
-                msg = ("section: %s, option: %s, value: %s" %
-                       (repr(section), repr(option), repr(value)))
-                raise cperror.WrongConfigValue, msg
-            configMap[section][option] = value
-
-def outputConfigMap():
-    cpg.log("Server parameters:", 'CONFIG')
-    cpg.log("  server.environment: %s" % get('server.environment'), 'CONFIG')
-    cpg.log("  server.logToScreen: %s" % get('server.logToScreen'), 'CONFIG')
-    cpg.log("  server.logFile: %s" % get('server.logFile'), 'CONFIG')
-    cpg.log("  server.protocolVersion: %s" % get('server.protocolVersion'), 'CONFIG')
-    cpg.log("  server.socketHost: %s" % get('server.socketHost'), 'CONFIG')
-    cpg.log("  server.socketPort: %s" % get('server.socketPort'), 'CONFIG')
-    cpg.log("  server.socketFile: %s" % get('server.socketFile'), 'CONFIG')
-    cpg.log("  server.reverseDNS: %s" % get('server.reverseDNS'), 'CONFIG')
-    cpg.log("  server.socketQueueSize: %s" % get('server.socketQueueSize'), 'CONFIG')
-    cpg.log("  server.threadPool: %s" % get('server.threadPool'), 'CONFIG')
-    cpg.log("  session.storageType: %s" % get('session.storageType'), 'CONFIG')
-    if get('session.storageType'):
-        cpg.log("  session.timeout: %s min" % get('session.timeout'), 'CONFIG')
-        cpg.log("  session.cleanUpDelay: %s min" % get('session.cleanUpDelay'), 'CONFIG')
-        cpg.log("  session.cookieName: %s" % get('session.cookieName'), 'CONFIG')
-        cpg.log("  session.storageFileDir: %s" % get('session.storageFileDir'), 'CONFIG')
-    cpg.log("  staticContent: %s" % get('staticContent'), 'CONFIG')
+"""
+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.
+"""
+
+
+class Error(Exception):
+    pass
+
+class InternalError(Error):
+    """ Error that should never happen """
+    pass
+
+class NotFound(Error):
+    """ Happens when a URL couldn't be mapped to any class.method """
+    pass
+
+class WrongResponseType(Error):
+    """ Happens when the cherrypy.response.body is not a string """
+    pass
+
+class WrongUnreprValue(Error):
+    """ Happens when unrepr can't parse a value """
+    pass
+
+class WrongConfigValue(Error):
+    """ Happens when unrepr can't parse a config value """
+    pass
+
+class RequestHandled(Exception):
+    """Exception raised when no further request handling should occur."""
+    pass
+
+class InternalRedirect(Exception):
+    """Exception raised when processing should be handled by a different path.
+    
+    If you supply a queryString, it will be used to re-populate paramMap.
+    
+    If you omit queryString, the paramMap from the original request will
+    remain in effect, including any POST parameters.
+    """
+    
+    def __init__(self, path, queryString=None):
+        import cherrypy
+        import cgi
+        
+        self.path = path
+        if queryString is not None:
+            cherrypy.request.queryString = queryString
+            
+            pm = cgi.parse_qs(cherrypy.request.queryString, keep_blank_values=True)
+            for key, val in pm.items():
+                if len(val) == 1:
+                    pm[key] = val[0]
+            cherrypy.request.paramMap = pm
+        
+        cherrypy.request.browserUrl = cherrypy.request.base + path
+
+
+
+class HTTPRedirect(Exception):
+    """Exception raised when the request should be redirected.
+    
+    The new URL must be passed as the first argument to the Exception, e.g.,
+        cperror.HTTPRedirect(newUrl). Multiple URLs are allowed.
+    """
+    
+    def __init__(self, urls, status=None):
+        import urlparse
+        import cherrypy
+        
+        if isinstance(urls, basestring):
+            urls = [urls]
+        
+        abs_urls = []
+        for url in urls:
+            if url.startswith("/"):
+                url = urlparse.urljoin(cherrypy.request.base, url)
+            abs_urls.append(url)
+        self.urls = abs_urls
+        
+        # RFC 2616 indicates a 301 response code fits our goal; however,
+        # browser support for 301 is quite messy. Do 302 instead.
+        # http://ppewww.ph.gla.ac.uk/~flavell/www/post-redirect.html
+        if status is None:
+            if cherrypy.request.protocol == "HTTP/1.1":
+                status = 303
+            else:
+                status = 302
+        else:
+            status = int(status)
+            if status < 300 or status > 399:
+                raise ValueError("status must be between 300 and 399.")
+        
+        self.status = status
+    
+    def set_response(self):
+        import cherrypy
+        cherrypy.response.status = status = self.status
+        cherrypy.response.headerMap['Content-Type'] = "text/html"
+        
+        if status in (300, 301, 302, 303, 307):
+            # "The ... URI SHOULD be given by the Location field
+            # in the response."
+            cherrypy.response.headerMap['Location'] = self.urls[0]
+            
+            # "Unless the request method was HEAD, the entity of the response
+            # SHOULD contain a short hypertext note with a hyperlink to the
+            # new URI(s)."
+            msg = {300: "This resource can be found at <a href='%s'>%s</a>.",
+                   301: "This resource has permanently moved to <a href='%s'>%s</a>.",
+                   302: "This resource resides temporarily at <a href='%s'>%s</a>.",
+                   303: "This resource can be found at <a href='%s'>%s</a>.",
+                   307: "This resource has moved temporarily to <a href='%s'>%s</a>.",
+                   }[status]
+            cherrypy.response.body = "<br />\n".join([msg % (url, url)
+                                                 for url in self.urls])
+        elif status == 304:
+            # Not Modified.
+            # "The response MUST include the following header fields:
+            # Date, unless its omission is required by section 14.18.1"
+            # The "Date" header should have been set in Request.__init__
+            
+            # "The 304 response MUST NOT contain a message-body."
+            cherrypy.response.body = []
+        elif status == 305:
+            # Use Proxy.
+            # self.urls[0] should be the URI of the proxy.
+            cherrypy.response.headerMap['Location'] = self.urls[0]
+            cherrypy.response.body = []
+        else:
+            raise ValueError("The %s status code is unknown." % status)

File _cphttpserver.py

 """
 
 import threading, SocketServer, BaseHTTPServer, socket, Queue
-import cpg, _cpserver, _cphttptools
+import cherrypy
+from cherrypy import _cphttptools
 
 try:
     import cStringIO as StringIO
     
     def address_string(self):
         """ Try to do a reverse DNS based on [server]reverseDNS in the config file """
-        if cpg.config.get('server.reverseDNS'):
+        if cherrypy.config.get('server.reverseDNS'):
             return BaseHTTPServer.BaseHTTPRequestHandler.address_string(self)
         else:
             return self.client_address[0]
         if not self.parse_request(): # An error code has been sent, just exit
             return
         
-        cpg.request.multithread = cpg.config.get("server.threadPool") > 1
-        cpg.request.multiprocess = False
-        _cpserver.request(self.client_address[0],
-                          self.address_string(),
-                          self.raw_requestline,
-                          self._headerlist(),
-                          self.rfile)
+        cherrypy.request.multithread = cherrypy.config.get("server.threadPool") > 1
+        cherrypy.request.multiprocess = False
+        cherrypy.server.request(self.client_address[0],
+                                self.address_string(),
+                                self.raw_requestline,
+                                self._headerlist(),
+                                self.rfile)
         wfile = self.wfile
-        wfile.write("%s %s\r\n" % (self.protocol_version, cpg.response.status))
+        wfile.write("%s %s\r\n" % (self.protocol_version, cherrypy.response.status))
         
-        for name, value in cpg.response.headers:
+        for name, value in cherrypy.response.headers:
             wfile.write("%s: %s\r\n" % (name, value))
         
         wfile.write("\r\n")
         try:
-            for chunk in cpg.response.body:
+            for chunk in cherrypy.response.body:
                 wfile.write(chunk)
         except:
             s, h, b = _cphttptools.bareError()
     
     def log_message(self, format, *args):
         """ We have to override this to use our own logging mechanism """
-        cpg.log(format % args, "HTTP")
+        cherrypy.log(format % args, "HTTP")
 
 
 class CherryHTTPServer(BaseHTTPServer.HTTPServer):
             # interrupts on Win32, which don't interrupt accept() by default
             return 1
         except (KeyboardInterrupt, SystemExit):
-            cpg.log("<Ctrl-C> hit: shutting down http server", "HTTP")
+            cherrypy.log("<Ctrl-C> hit: shutting down http server", "HTTP")
             self.shutdown()
     
     def serve_forever(self):
     def handle_error(self, request, client_address):
         """Handle an error gracefully.  May be overridden."""
         errorBody = _cphttptools.formatExc()
-        cpg.log(errorBody)
+        cherrypy.log(errorBody)
 
 
 class PooledThreadServer(SocketServer.TCPServer):
         try:
             request, client_address = self.get_request()
         except (KeyboardInterrupt, SystemExit):
-            cpg.log("<Ctrl-C> hit: shutting down", "HTTP")
+            cherrypy.log("<Ctrl-C> hit: shutting down", "HTTP")
             return 0
         except socket.error, e:
             return 1
     """Selects and instantiates the appropriate server."""
     
     # Set protocol_version
-    proto = cpg.config.get('server.protocolVersion')
+    proto = cherrypy.config.get('server.protocolVersion')
     if not proto:
         proto = "HTTP/1.0"
     CherryHTTPRequestHandler.protocol_version = proto
     
     # Select the appropriate server based on config options
-    sockFile = cpg.config.get('server.socketFile')
-    threadPool = cpg.config.get('server.threadPool')
+    sockFile = cherrypy.config.get('server.socketFile')
+    threadPool = cherrypy.config.get('server.threadPool')
     if sockFile:
         # AF_UNIX socket
         # TODO: Handle threading here
             ServerClass = PooledThreadServer
         else:
             ServerClass = CherryHTTPServer
-        server_address = (cpg.config.get('server.socketHost'),
-                          cpg.config.get('server.socketPort'))
+        server_address = (cherrypy.config.get('server.socketHost'),
+                          cherrypy.config.get('server.socketPort'))
     
-    ServerClass.request_queue_size = cpg.config.get('server.socketQueueSize')
+    ServerClass.request_queue_size = cherrypy.config.get('server.socketQueueSize')
     
     if handler is None:
         handler = CherryHTTPRequestHandler

File _cphttptools.py

 import mimetypes, Cookie, urlparse
 from lib.filter import basefilter
 
-import cpg, _cputil, cperror, _cpcgifs
+import cherrypy
+from cherrypy import _cputil, _cpcgifs
 
 # Can't use cStringIO; doesn't support unicode strings  
 # See http://www.python.org/sf/216388  
     """
     
     def __init__(self, clientAddress, remoteHost, requestLine, headers, rfile):
-        # When __init__ is finished, cpg.response should have three attributes:
+        # When __init__ is finished, cherrypy.response should have three attributes:
         #   status, e.g. "200 OK"
         #   headers, a list of (name, value) tuples
         #   body, an iterable yielding strings
         self.requestLine = requestLine
         self.requestHeaders = headers
         
-        # Prepare cpg.request variables
-        cpg.request.remoteAddr = clientAddress
-        cpg.request.remoteHost = remoteHost
-        cpg.request.paramList = [] # Only used for Xml-Rpc
-        cpg.request.headerMap = {}
-        cpg.request.requestLine = requestLine
-        cpg.request.simpleCookie = Cookie.SimpleCookie()
-        cpg.request.rfile = rfile
+        # Prepare cherrypy.request variables
+        cherrypy.request.remoteAddr = clientAddress
+        cherrypy.request.remoteHost = remoteHost
+        cherrypy.request.paramList = [] # Only used for Xml-Rpc
+        cherrypy.request.headerMap = {}
+        cherrypy.request.requestLine = requestLine
+        cherrypy.request.simpleCookie = Cookie.SimpleCookie()
+        cherrypy.request.rfile = rfile
         
-        # Prepare cpg.response variables
-        cpg.response.status = None
-        cpg.response.headers = None
-        cpg.response.body = None
+        # Prepare cherrypy.response variables
+        cherrypy.response.status = None
+        cherrypy.response.headers = None
+        cherrypy.response.body = None
         
         year, month, day, hh, mm, ss, wd, y, z = time.gmtime()
         date = ("%s, %02d %3s %4d %02d:%02d:%02d GMT" %
                 (weekdayname[wd], day, monthname[month], year, hh, mm, ss))
-        cpg.response.headerMap = KeyTitlingDict()
-        cpg.response.headerMap.update({
+        cherrypy.response.headerMap = KeyTitlingDict()
+        cherrypy.response.headerMap.update({
             "Content-Type": "text/html",
-            "Server": "CherryPy/" + cpg.__version__,
+            "Server": "CherryPy/" + cherrypy.__version__,
             "Date": date,
             "Set-Cookie": [],
             "Content-Length": 0
         })
-        cpg.response.simpleCookie = Cookie.SimpleCookie()
+        cherrypy.response.simpleCookie = Cookie.SimpleCookie()
         
         self.run()
         
-        if cpg.request.method == "HEAD":
+        if cherrypy.request.method == "HEAD":
             # HEAD requests MUST NOT return a message-body in the response.
-            cpg.response.body = []
+            cherrypy.response.body = []
     
     def run(self):
         try:
                     self.processRequestHeaders()
                     
                     applyFilters('beforeRequestBody')
-                    if cpg.request.processRequestBody:
+                    if cherrypy.request.processRequestBody:
                         self.processRequestBody()
                     
                     applyFilters('beforeMain')
-                    if cpg.response.body is None:
+                    if cherrypy.response.body is None:
                         main()
                     
                     applyFilters('beforeFinalize')
                     finalize()
-                except cperror.RequestHandled:
+                except cherrypy.RequestHandled:
                     pass
-                except cperror.HTTPRedirect, inst:
+                except cherrypy.HTTPRedirect, inst:
                     # For an HTTPRedirect, we don't go through the regular
                     # mechanism: we return the redirect immediately
                     inst.set_response()
     
     def processRequestHeaders(self):
         # Parse first line
-        cpg.request.method, path, cpg.request.protocol = self.requestLine.split()
-        cpg.request.processRequestBody = cpg.request.method in ("POST",)
+        cherrypy.request.method, path, cherrypy.request.protocol = self.requestLine.split()
+        cherrypy.request.processRequestBody = cherrypy.request.method in ("POST",)
         
         # find the queryString, or set it to "" if not found
         if "?" in path:
-            cpg.request.path, cpg.request.queryString = path.split("?", 1)
+            cherrypy.request.path, cherrypy.request.queryString = path.split("?", 1)
         else:
-            cpg.request.path, cpg.request.queryString = path, ""
+            cherrypy.request.path, cherrypy.request.queryString = path, ""
         
         # build a paramMap dictionary from queryString
-        pm = cgi.parse_qs(cpg.request.queryString, keep_blank_values=True)
+        pm = cgi.parse_qs(cherrypy.request.queryString, keep_blank_values=True)
         for key, val in pm.items():
             if len(val) == 1:
                 pm[key] = val[0]
-        cpg.request.paramMap = pm
+        cherrypy.request.paramMap = pm
         
         # Process the headers into request.headerMap
         for name, value in self.requestHeaders:
             # Warning: if there is more than one header entry for cookies (AFAIK,
             # only Konqueror does that), only the last one will remain in headerMap
             # (but they will be correctly stored in request.simpleCookie).
-            cpg.request.headerMap[name] = value
+            cherrypy.request.headerMap[name] = value
             
             # Handle cookies differently because on Konqueror, multiple cookies
             # come on different lines with the same key
             if name == 'Cookie':
-                cpg.request.simpleCookie.load(value)
+                cherrypy.request.simpleCookie.load(value)
         
-        msg = "%s - %s" % (cpg.request.remoteAddr, self.requestLine[:-2])
-        cpg.log(msg, "HTTP")
+        msg = "%s - %s" % (cherrypy.request.remoteAddr, self.requestLine[:-2])
+        cherrypy.log(msg, "HTTP")
         
-        cpg.request.base = "http://" + cpg.request.headerMap.get('Host', '')
-        cpg.request.browserUrl = cpg.request.base + path
+        cherrypy.request.base = "http://" + cherrypy.request.headerMap.get('Host', '')
+        cherrypy.request.browserUrl = cherrypy.request.base + path
         
         # Change objectPath in filters to change
         # the object that will get rendered
-        cpg.request.objectPath = None
+        cherrypy.request.objectPath = None
         
         # Save original values (in case they get modified by filters)
-        cpg.request.originalPath = cpg.request.path
-        cpg.request.originalParamMap = cpg.request.paramMap
-        cpg.request.originalParamList = cpg.request.paramList
+        cherrypy.request.originalPath = cherrypy.request.path
+        cherrypy.request.originalParamMap = cherrypy.request.paramMap
+        cherrypy.request.originalParamList = cherrypy.request.paramList
     
     def processRequestBody(self):
         # Create a copy of headerMap with lowercase keys because
         # FieldStorage doesn't work otherwise
         lowerHeaderMap = {}
-        for key, value in cpg.request.headerMap.items():
+        for key, value in cherrypy.request.headerMap.items():
             lowerHeaderMap[key.lower()] = value
-        forms = _cpcgifs.FieldStorage(fp=cpg.request.rfile, headers=lowerHeaderMap,
+        forms = _cpcgifs.FieldStorage(fp=cherrypy.request.rfile, headers=lowerHeaderMap,
                                       environ = {'REQUEST_METHOD': 'POST'},
                                       keep_blank_values = 1)
         
         for key in forms.keys():
             valueList = forms[key]
             if isinstance(valueList, list):
-                cpg.request.paramMap[key] = []
+                cherrypy.request.paramMap[key] = []
                 for item in valueList:
                     if item.file is not None:
                         value = item # It's a file upload
                     else:
                         value = item.value # It's a regular field
-                    cpg.request.paramMap[key].append(value)
+                    cherrypy.request.paramMap[key].append(value)
             else:
                 if valueList.file is not None:
                     value = valueList # It's a file upload
                 else:
                     value = valueList.value # It's a regular field
-                cpg.request.paramMap[key] = value
+                cherrypy.request.paramMap[key] = value
 
 
 # Error handling
     try:
         applyFilters('beforeErrorResponse')
         
-        # _cpOnError will probably change cpg.response.body.
+        # _cpOnError will probably change cherrypy.response.body.
         # It may also change the headerMap, etc.
         _cputil.getSpecialAttribute('_cpOnError')()
         
         # Failure in _cpOnError, error filter, or finalize.
         # Bypass them all.
         body = dbltrace % (formatExc(exc), formatExc())
-        cpg.response.status, cpg.response.headers, body = bareError(body)
-        cpg.response.body = body
+        cherrypy.response.status, cherrypy.response.headers, body = bareError(body)
+        cherrypy.response.body = body
 
 def formatExc(exc=None):
     """formatExc(exc=None) -> exc (or sys.exc_info), formatted."""
 # Response functions
 
 def main(path=None):
-    """Obtain and set cpg.response.body."""
+    """Obtain and set cherrypy.response.body."""
     if path is None:
-        path = cpg.request.objectPath or cpg.request.path
+        path = cherrypy.request.objectPath or cherrypy.request.path
     
     while True:
         try:
             func, objectPathList, virtualPathList = mapPathToObject(path)
             
             # Remove "root" from objectPathList and join it to get objectPath
-            cpg.request.objectPath = '/' + '/'.join(objectPathList[1:])
-            body = func(*(virtualPathList + cpg.request.paramList),
-                        **(cpg.request.paramMap))
-            cpg.response.body = iterable(body)
+            cherrypy.request.objectPath = '/' + '/'.join(objectPathList[1:])
+            body = func(*(virtualPathList + cherrypy.request.paramList),
+                        **(cherrypy.request.paramMap))
+            cherrypy.response.body = iterable(body)
             return
-        except cperror.InternalRedirect, x:
+        except cherrypy.InternalRedirect, x:
             # Try again with the new path
             path = x.path
 
     return body
 
 def checkStatus():
-    """Test/set cpg.response.status. Provide Reason-phrase if missing."""
-    if not cpg.response.status:
-        cpg.response.status = "200 OK"
+    """Test/set cherrypy.response.status. Provide Reason-phrase if missing."""
+    if not cherrypy.response.status:
+        cherrypy.response.status = "200 OK"
     else:
-        status = str(cpg.response.status)
+        status = str(cherrypy.response.status)
         parts = status.split(" ", 1)
         if len(parts) == 1:
             # No reason supplied.
             except (KeyError, IndexError):
                 reason = ""
         
-        cpg.response.status = "%s %s" % (code, reason)
-    return cpg.response.status
+        cherrypy.response.status = "%s %s" % (code, reason)
+    return cherrypy.response.status
 
 
 general_header_fields = ["Cache-Control", "Connection", "Date", "Pragma",
 
 
 def finalize():
-    """Transform headerMap + cookies into cpg.response.headers."""
+    """Transform headerMap + cookies into cherrypy.response.headers."""
     
     checkStatus()
     
-    if (cpg.config.get("server.protocolVersion") != "HTTP/1.1"
-        and cpg.response.headerMap.get('Content-Length') == 0):
-        content = ''.join(cpg.response.body)
-        cpg.response.body = [content]
-        cpg.response.headerMap['Content-Length'] = len(content)
+    if (cherrypy.config.get("server.protocolVersion") != "HTTP/1.1"
+        and cherrypy.response.headerMap.get('Content-Length') == 0):
+        content = ''.join(cherrypy.response.body)
+        cherrypy.response.body = [content]
+        cherrypy.response.headerMap['Content-Length'] = len(content)
     
     # Headers
     headers = []
-    for key, valueList in cpg.response.headerMap.iteritems():
+    for key, valueList in cherrypy.response.headerMap.iteritems():
         order = _header_order_map.get(key, 3)
         if not isinstance(valueList, list):
             valueList = [valueList]
     # first, followed by request-header or response-header fields, and
     # ending with the entity-header fields.'
     headers.sort()
-    cpg.response.headers = [item[1] for item in headers]
+    cherrypy.response.headers = [item[1] for item in headers]
     
-    cookie = cpg.response.simpleCookie.output()
+    cookie = cherrypy.response.simpleCookie.output()
     if cookie:
         name, value = cookie.split(": ", 1)
-        cpg.response.headers.append((name, value))
-    return cpg.response.headers
+        cherrypy.response.headers.append((name, value))
+    return cherrypy.response.headers
 
 def applyFilters(methodName):
     if methodName in ('beforeRequestBody', 'beforeMain'):
 
 
 def serve_file(filename):
-    # If filename is relative, make absolute using cpg.root's module.
+    # If filename is relative, make absolute using cherrypy.root's module.
     if not os.path.isabs(filename):
-        root = os.path.dirname(sys.modules[cpg.root.__module__].__file__)
+        root = os.path.dirname(sys.modules[cherrypy.root.__module__].__file__)
         filename = os.path.join(root, filename)
     
     # Serve filename
     try:
         stat = os.stat(filename)
     except OSError:
-        raise cperror.NotFound(cpg.request.path)
+        raise cherrypy.NotFound(cherrypy.request.path)
     
     modifTime = stat.st_mtime
     strModifTime = time.strftime("%a, %d %b %Y %H:%M:%S GMT",
                                  time.gmtime(modifTime))
-    if cpg.request.headerMap.has_key('If-Modified-Since'):
+    if cherrypy.request.headerMap.has_key('If-Modified-Since'):
         # Check if if-modified-since date is the same as strModifTime
-        if cpg.request.headerMap['If-Modified-Since'] == strModifTime:
-            cpg.response.status = "304 Not Modified"
-            cpg.response.body = []
+        if cherrypy.request.headerMap['If-Modified-Since'] == strModifTime:
+            cherrypy.response.status = "304 Not Modified"
+            cherrypy.response.body = []
             return
-    cpg.response.headerMap['Last-Modified'] = strModifTime
+    cherrypy.response.headerMap['Last-Modified'] = strModifTime
     
     # Set Content-Length and use an iterable (file object)
     #   this way CP won't load the whole file in memory
-    cpg.response.headerMap['Content-Length'] = stat[6]
-    cpg.response.body = open(filename, 'rb')
+    cherrypy.response.headerMap['Content-Length'] = stat[6]
+    cherrypy.response.body = open(filename, 'rb')
     
     # Set content-type based on filename extension
     i = filename.rfind('.')
     else:
         ext = ""
     contentType = mimetypes.types_map.get(ext, "text/plain")
-    cpg.response.headerMap['Content-Type'] = contentType
+    cherrypy.response.headerMap['Content-Type'] = contentType
 
 
 # Object lookup
     """ For a given objectPathList (like ['root', 'a', 'b', 'index']),
          return the object (or None if it doesn't exist).
     """
-    root = cpg
+    root = cherrypy
     for objname in objPathList:
         # maps virtual filenames to Python identifiers (substitutes '.' for '_')
         objname = objname.replace('.', '_')
-        if getattr(cpg, "debug", None):
+        if getattr(cherrypy, "debug", None):
             print "Attempting to call method: %s.%s" % (root, objname)
         root = getattr(root, objname, None)
         if root is None:
         objectPathList = tpath.split('/')
     objectPathList = ['root'] + objectPathList + ['index']
     
-    if getattr(cpg, "debug", None):
+    if getattr(cherrypy, "debug", None):
         print "Attempting to map path: %s" % tpath
         print "    objectPathList: %s" % objectPathList
     
             icofile = os.path.join(os.path.dirname(__file__), "favicon.ico")
             serve_file(icofile)
             finalize()
-            raise cperror.RequestHandled
+            raise cherrypy.RequestHandled
         else:
             # We didn't find anything
-            raise cperror.NotFound(path)
+            raise cherrypy.NotFound(path)
     
     if isFirst:
         # We found the extra ".index"
         #   a redirect)
         if path[-1] != '/':
             newUrl = path + '/'
-            if cpg.request.queryString:
-                newUrl += "?" + cpg.request.queryString
-            raise cperror.HTTPRedirect(newUrl)
+            if cherrypy.request.queryString:
+                newUrl += "?" + cherrypy.request.queryString
+            raise cherrypy.HTTPRedirect(newUrl)
     
     return candidate, objectPathList, virtualPathList
 

File _cpserver.py

-"""
-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 cpg, _cphttptools
-
-try:
-    from threading import local
-except ImportError:
-    from _cpthreadinglocal import local
-
-
-from lib import autoreload, profiler
-
-
-# Set some special attributes for adding hooks
-onStartServerList = []
-onStartThreadList = []
-onStopServerList = []
-onStopThreadList = []
-
-def start(initOnly=False, serverClass=None):
-    if cpg.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)
-    cpg.request = local()
-    cpg.response = local()
-
-    # Create as sessions object for accessing session data
-    cpg.sessions = local()
-    
-    # Create threadData object as a thread-specific all-purpose storage
-    cpg.threadData = local()
-    
-    # Output config options to log
-    if cpg.config.get("server.logConfigOptions", True):
-        cpg.config.outputConfigMap()
-    
-    # Check the config options
-    # TODO
-    # _cpconfig.checkConfigOptions()
-    
-    # Initialize a few global variables
-    cpg._lastCacheFlushTime = time.time()
-    cpg._lastSessionCleanUpTime = time.time()
-    cpg._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 (cpg.config.get('server.threadPool') > 1
-        and cpg.config.get('session.storageType') == 'file'):
-        cpg._sessionFileLock = threading.RLock()
-    
-    # Call the functions from cpg.server.onStartServerList
-    for func in cpg.server.onStartServerList:
-        func()
-    
-    # Set up the profiler if requested.
-    if cpg.config.get("profiling.on", False):
-        ppath = cpg.config.get("profiling.path", "")
-        cpg.profiler = profiler.Profiler(ppath)
-    else:
-        cpg.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 = cpg.config.get("server.class", None)
-    if serverClass and isinstance(serverClass, basestring):
-        serverClass = attributes(serverClass)
-    if serverClass is None:
-        import _cpwsgi
-        serverClass = _cpwsgi.WSGIServer
-    
-    cpg._httpserver = serverClass()
-    
-    if cpg.config.get('server', 'socketPort'):
-        onWhat = "socket: ('%s', %s)" % (cpg.config.get('server.socketHost'),
-                                         cpg.config.get('server.socketPort'))
-    else:
-        onWhat = "socket file: %s" % cpg.config.get('server.socketFile')
-    cpg.log("Serving HTTP on %s" % onWhat, 'HTTP')
-    
-    # Start the http server.
-    try:
-        cpg._httpserver.start()
-    except (KeyboardInterrupt, SystemExit):
-        cpg.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 cpg.server.onStartThreadList
-        for func in cpg.server.onStartThreadList:
-            func(i)
-    
-    if cpg.profiler:
-        cpg.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 = cpg._httpserver.stop
-    except AttributeError:
-        pass
-    else:
-        httpstop()
-    
-    # Call the functions from cpg.server.onStopThreadList
-    for thread_ident, i in seen_threads.iteritems():
-        for func in cpg.server.onStopThreadList:
-            func(i)
-    seen_threads.clear()
-    
-    # Call the functions from cpg.server.onStopServerList
-    for func in cpg.server.onStopServerList:
-        func()
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 """
 
-
 """
 A module containing a few utility classes/functions used by CherryPy
 """
 
-import time, cpg, cperror
+import time
+import cherrypy
 
 
 class EmptyClass:
 
 
 def getObjectTrail():
-    """ Return all objects from the currenct object to cpg """
-    root = getattr(cpg, 'root', None)
+    """ Return all objects from the currenct object to cherrypy """
+    root = getattr(cherrypy, 'root', None)
     if root:
         objectTrail = [root]
         # Try object path
         try:
-            path = cpg.request.objectPath or cpg.request.path
+            path = cherrypy.request.objectPath or cherrypy.request.path
         except AttributeError:
             path = '/'
         if path:
     return None
 
 def getSpecialAttribute(name):
-    """ Return the special attribute. A special attribute is
-    one that applies to all of the children from where it is
-    defined, such as _cpFilterList."""
+    """Return the special attribute. A special attribute is one that
+    applies to all of the children from where it is defined, such as
+    _cpFilterList."""
     
     # First, we look in the right-most object if this special attribute is implemented.
-    # If not, then we try the previous object and so on until we reach cpg.root
+    # If not, then we try the previous object and so on until we reach cherrypy.root
     # If it's still not there, we use the implementation from this module.
     
     objectList = getObjectTrail()
     try:
         return globals()[name]
     except KeyError:
-        raise cperror.InternalError("Special attribute %s could not be found"
-                                    % repr(name))
-
-def getSpecialAttributePath(name):
-    """ Return the path to the special attribute """
-    objectList = getObjectTrail()
-    if objectList:
-        pathList = (cpg.request.objectPath or cpg.request.path).split("/")[1:]
-        for i in xrange(len(objectList) - 1, -1, -1):
-            if hasattr(objectList[i], name):
-                return "/" + "/".join(pathList[:i] + [name])
-    raise cperror.InternalError("Special attribute %s could not be found"
-                                    % repr(name))
+        raise cherrypy.InternalError("Special attribute %s could not be found"
+                                     % repr(name))
+
+def getSpecialAttributePath(name):
+    """ Return the path to the special attribute """
+    objectList = getObjectTrail()
+    if objectList:
+        pathList = cherrypy.request.objectPath or cherrypy.request.path
+        pathList = pathList.split("/")[1:]
+        for i in xrange(len(objectList) - 1, -1, -1):
+            if hasattr(objectList[i], name):
+                return "/" + "/".join(pathList[:i] + [name])
+    raise cherrypy.InternalError("Special attribute %s could not be found"
+                                 % repr(name))
 
 def _cpLogMessage(msg, context = '', severity = 0):
     """ Default method for logging messages """
     else:
         level = "UNKNOWN"
     try:
-        logToScreen = cpg.config.get('server.logToScreen')
+        logToScreen = cherrypy.config.get('server.logToScreen')
     except:
         logToScreen = True
     s = nowStr + ' ' + context + ' ' + level + ' ' + msg
     if logToScreen:
         print s
-    if cpg.config.get('server.logFile'):
-        f = open(cpg.config.get('server.logFile'), 'ab')
+    if cherrypy.config.get('server.logFile'):
+        f = open(cherrypy.config.get('server.logFile'), 'ab')
         f.write(s + '\n')
         f.close()
 
     """ Default _cpOnError method """
     import sys, traceback
     content = "".join(traceback.format_exception(*sys.exc_info()))
-    cpg.response.body = [content]
-    cpg.response.headerMap['Content-Type'] = 'text/plain'
-    if cpg.response.headerMap.has_key('Content-Encoding'):
-        del cpg.response.headerMap['Content-Encoding']
+    cherrypy.response.body = [content]
+    cherrypy.response.headerMap['Content-Type'] = 'text/plain'
+    if cherrypy.response.headerMap.has_key('Content-Encoding'):
+        del cherrypy.response.headerMap['Content-Encoding']
 
 _cpFilterList = []
 
     staticfilter, nsgmlsfilter, tidyfilter, \
     virtualhostfilter, xmlrpcfilter, sessionauthenticatefilter
 
-from cherrypy.lib.filter.sessionfilter import sessionfilter
+from cherrypy.lib.filter import sessionfilter
 
 _cachefilter = cachefilter.CacheFilter()
 _logdebuginfofilter = logdebuginfofilter.LogDebugInfoFilter()
     try:
         return Builder().build(getObj(s))
     except:
-        raise cperror.WrongUnreprValue, repr(s)
+        raise cherrypy.WrongUnreprValue, repr(s)
 import threading
 import os, socket, sys, traceback, urllib
 import SocketServer, BaseHTTPServer
-import cpg, _cpserver, _cphttptools, _cpwsgiserver
+import cherrypy
+from cherrypy import _cphttptools, _cpwsgiserver
 
 
 def requestLine(environ):
 def wsgiApp(environ, start_response):
     
     # Trap screen output from BaseHTTPRequestHandler.log_message()
-    if not cpg.config.get('server.logToScreen'):
+    if not cherrypy.config.get('server.logToScreen'):
         sys.stderr = NullWriter()
     
     try:
         # LOGON_USER is served by IIS, and is the name of the
         # user after having been mapped to a local account.
         # Both IIS and Apache set REMOTE_USER, when possible.
-        cpg.request.login = (environ.get('LOGON_USER')
+        cherrypy.request.login = (environ.get('LOGON_USER')
                              or environ.get('REMOTE_USER') or None)
-        cpg.request.multithread = environ['wsgi.multithread']
-        cpg.request.multiprocess = environ['wsgi.multiprocess']
-        _cpserver.request(environ.get('REMOTE_ADDR', ''),
-                          environ.get('REMOTE_ADDR', ''),
-                          requestLine(environ),
-                          translate_headers(environ),
-                          environ['wsgi.input'],
-                          )
-        start_response(cpg.response.status, cpg.response.headers)
-        for chunk in cpg.response.body:
+        cherrypy.request.multithread = environ['wsgi.multithread']
+        cherrypy.request.multiprocess = environ['wsgi.multiprocess']
+        cherrypy.server.request(environ.get('REMOTE_ADDR', ''),
+                                environ.get('REMOTE_ADDR', ''),
+                                requestLine(environ),
+                                translate_headers(environ),
+                                environ['wsgi.input'],
+                                )
+        start_response(cherrypy.response.status, cherrypy.response.headers)
+        for chunk in cherrypy.response.body:
             # WSGI requires all data to be of type "str". This coercion should
             # not take any time at all if chunk is already of type "str".
             # If it's unicode, it could be a big performance hit (x ~500).
             yield chunk
     except:
         tb = _cphttptools.formatExc()
-        cpg.log(tb)
+        cherrypy.log(tb)
         s, h, b = _cphttptools.bareError(tb)
         # CherryPy test suite expects bareError body to be output,
         # so don't call start_response (which, according to PEP 333,
 
 
 
-# Server components
+# Server components.
+# _cpwsgiserver should not reference CherryPy in any way, so that it can
+# be used in other frameworks and applications. Therefore, we wrap it here.
 
 class WSGIServer(_cpwsgiserver.CherryPyWSGIServer):
     def __init__(self):
+        conf = cherrypy.config.get
         _cpwsgiserver.CherryPyWSGIServer.__init__(self,
-                                                  (cpg.config.get("server.socketHost"),
-                                                   cpg.config.get("server.socketPort")),
+                                                  (conf("server.socketHost"),
+                                                   conf("server.socketPort")),
                                                   wsgiApp,
-                                                  cpg.config.get("server.threadPool"),
-                                                  cpg.config.get("server.socketHost"))
+                                                  conf("server.threadPool"),
+                                                  conf("server.socketHost"))

File _cpwsgiserver.py

         run the server forever
         '''
         # We don't have to trap KeyboardInterrupt or SystemExit here,
-        # because _cpserver already does so, calling self.stop() for us.
+        # because cherrpy.server already does so, calling self.stop() for us.
         # If you're using this server with another framework, you should
         # trap those exceptions in whatever code block calls start().
         self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP)
+"""
+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.
+"""
+
+"""
+Configuration system for CherryPy.
+"""
+
+import os.path
+import ConfigParser
+
+import cherrypy
+from cherrypy import _cputil, _cperror
+from cherrypy.lib import autoreload
+
+
+# This configMap dict holds the settings metadata for all cherrypy objects.
+# Keys are URL paths, and values are dicts.
+configMap = {}
+
+defaultGlobal = {
+    'server.socketPort': 8080,
+    'server.socketHost': '',
+    'server.socketFile': '',
+    'server.socketQueueSize': 5,
+
+    'server.environment': 'development',
+    'server.protocolVersion': 'HTTP/1.0',
+    'server.logToScreen': True,
+    'server.logFile': '',
+    'server.reverseDNS': False,
+    'server.threadPool': 0,
+
+    'sessionFilter.on' : False,
+    'sessionFilter.sessionList' : ['default'],
+    'sessionFilter.default.on': True,
+    'sessionFilter.default.timeout': 60,
+    'sessionFilter.default.cleanUpDelay': 60,
+    'sessionFilter.default.storageType' : 'ram',
+    'sessionFilter.default.cookiePrefix': 'CherryPySession',
+    'sessionFilter.default.storageFileDir': '.sessionFiles'
+    }
+
+def reset(useDefaults=True):
+    configMap.clear()
+    if useDefaults:
+        configMap["global"] = defaultGlobal.copy()
+reset()
+
+def update(updateMap=None, file=None):
+    if updateMap:
+        for section, valueMap in updateMap.items():
+            if not isinstance(valueMap, dict):
+                # Shortcut syntax
+                #   ex: update({'server.socketPort': 80})
+                valueMap = {section: valueMap}
+                section = 'global'
+            s = configMap.get(section)
+            if not s:
+                configMap[section] = valueMap
+            else:
+                s.update(valueMap)
+    if file:
+        if file not in autoreload.reloadFiles:
+            autoreload.reloadFiles.append(file)
+        _load(file)
+
+def get(key, defaultValue=None, returnSection=False, startPath = None):
+    # Look, ma, no Python function calls! Uber-fast.
+    # startPath lets you overload the starting search path (needed by getAll)
+    if startPath:
+        path = startPath
+    else:
+        try:
+            path = cherrypy.request.path
+        except AttributeError:
+            path = "/"
+    
+    while True:
+        if path == "":
+            path = "/"
+        try:
+            result = configMap[path][key]
+        except KeyError:
+            if path not in ("/", "global"):
+                i = path.rfind("/")
+                if i < 0:
+                    result = defaultValue
+                else:
+                    path = path[:i]
+                    continue
+            elif path != "global":
+                path = "global"
+                continue
+            else:
+                result = defaultValue
+        break
+    
+    if returnSection:
+        if path == 'global':
+            return '/'
+        return path
+    else:
+        return result
+
+def getAll(key):
+    """
+    getAll will lookup the key in the current node and all of its parent nodes,
+    it will return a dictionary paths of each node containing the key and its value
+
+    This function is required by the session filter
+    """
+    path = get(key, None, returnSection = True)
+    value = get(key)
+    
+    result = {}
+    while value != None and path != '/':
+        result[path]= value
+        path = os.path.split(path)[0]
+        value = get(key, None, returnSection = False, startPath = path)
+        path  = get(key, None, returnSection = True, startPath = path)
+    
+    if path == '/' and value != None:
+        result[path] = value
+    
+    return result
+
+
+class CaseSensitiveConfigParser(ConfigParser.ConfigParser):
+    """ Sub-class of ConfigParser that keeps the case of options and
+        that raises an exception if the file cannot be read
+    """
+    def optionxform(self, optionstr):
+        return optionstr
+    def read(self, filenames):
+        if isinstance(filenames, basestring):
+            filenames = [filenames]
+        for filename in filenames:
+            # try:
+            #     fp = open(filename)
+            # except IOError:
+            #     continue
+            fp = open(filename)
+            self._read(fp, filename)
+            fp.close()
+
+def _load(configFile = None):
+    """ Convert an INI file to a dictionary """
+    
+    # Parse config file
+    configParser = CaseSensitiveConfigParser()
+    if hasattr(configFile, 'read'):
+        cherrypy.log("Reading infos from configFile stream", 'CONFIG')
+        configParser.readfp(configFile)
+    else:
+        cherrypy.log("Reading infos from configFile: %s" % configFile, 'CONFIG')
+        configParser.read(configFile)
+    
+    # Load INI file into cherrypy.configMap
+    for section in configParser.sections():
+        if section not in configMap:
+            configMap[section] = {}
+        for option in configParser.options(section):
+            value = configParser.get(section, option)
+            try:
+                value = _cputil.unrepr(value)
+            except _cperror.WrongUnreprValue, s:
+                msg = ("section: %s, option: %s, value: %s" %
+                       (repr(section), repr(option), repr(value)))
+                raise _cperror.WrongConfigValue, msg
+            configMap[section][option] = value
+
+def outputConfigMap():
+    cherrypy.log("Server parameters:", 'CONFIG')
+    cherrypy.log("  server.environment: %s" % get('server.environment'), 'CONFIG')
+    cherrypy.log("  server.logToScreen: %s" % get('server.logToScreen'), 'CONFIG')
+    cherrypy.log("  server.logFile: %s" % get('server.logFile'), 'CONFIG')
+    cherrypy.log("  server.protocolVersion: %s" % get('server.protocolVersion'), 'CONFIG')
+    cherrypy.log("  server.socketHost: %s" % get('server.socketHost'), 'CONFIG')
+    cherrypy.log("  server.socketPort: %s" % get('server.socketPort'), 'CONFIG')
+    cherrypy.log("  server.socketFile: %s" % get('server.socketFile'), 'CONFIG')
+    cherrypy.log("  server.reverseDNS: %s" % get('server.reverseDNS'), 'CONFIG')
+    cherrypy.log("  server.socketQueueSize: %s" % get('server.socketQueueSize'), 'CONFIG')
+    cherrypy.log("  server.threadPool: %s" % get('server.threadPool'), 'CONFIG')
+    cherrypy.log("  session.storageType: %s" % get('session.storageType'), 'CONFIG')
+    if get('session.storageType'):
+        cherrypy.log("  session.timeout: %s min" % get('session.timeout'), 'CONFIG')
+        cherrypy.log("  session.cleanUpDelay: %s min" % get('session.cleanUpDelay'), 'CONFIG')
+        cherrypy.log("  session.cookieName: %s" % get('session.cookieName'), 'CONFIG')
+        cherrypy.log("  session.storageFileDir: %s" % get('session.storageFileDir'), 'CONFIG')
+    cherrypy.log("  staticContent: %s" % get('staticContent'), 'CONFIG')

File cperror.py

-"""
-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.
-"""
-
-
-class Error(Exception):
-    pass
-
-class InternalError(Error):
-    """ Error that should never happen """
-    pass
-
-class NotFound(Error):
-    """ Happens when a URL couldn't be mapped to any class.method """
-    pass
-
-class WrongResponseType(Error):
-    """ Happens when the cpg.response.body is not a string """
-    pass
-
-class WrongUnreprValue(Error):
-    """ Happens when unrepr can't parse a value """
-    pass
-
-class WrongConfigValue(Error):
-    """ Happens when unrepr can't parse a config value """
-    pass
-
-class RequestHandled(Exception):
-    """Exception raised when no further request handling should occur."""
-    pass
-
-class InternalRedirect(Exception):
-    """Exception raised when processing should be handled by a different path.
-    
-    If you supply a queryString, it will be used to re-populate paramMap.
-    
-    If you omit queryString, the paramMap from the original request will
-    remain in effect, including any POST parameters.
-    """
-    
-    def __init__(self, path, queryString=None):
-        from cherrypy import cpg
-        import cgi
-        
-        self.path = path
-        if queryString is not None:
-            cpg.request.queryString = queryString
-            
-            pm = cgi.parse_qs(cpg.request.queryString, keep_blank_values=True)
-            for key, val in pm.items():
-                if len(val) == 1:
-                    pm[key] = val[0]
-            cpg.request.paramMap = pm
-        
-        cpg.request.browserUrl = cpg.request.base + path
-
-
-
-class HTTPRedirect(Exception):
-    """Exception raised when the request should be redirected.
-    
-    The new URL must be passed as the first argument to the Exception, e.g.,
-        cperror.HTTPRedirect(newUrl). Multiple URLs are allowed.
-    """
-    
-    def __init__(self, urls, status=None):
-        import urlparse
-        from cherrypy import cpg
-        
-        if isinstance(urls, basestring):
-            urls = [urls]
-        
-        abs_urls = []
-        for url in urls:
-            if url.startswith("/"):
-                url = urlparse.urljoin(cpg.request.base, url)
-            abs_urls.append(url)
-        self.urls = abs_urls
-        
-        # RFC 2616 indicates a 301 response code fits our goal; however,
-        # browser support for 301 is quite messy. Do 302 instead.
-        # http://ppewww.ph.gla.ac.uk/~flavell/www/post-redirect.html
-        if status is None:
-            if cpg.request.protocol == "HTTP/1.1":
-                status = 303
-            else:
-                status = 302
-        else:
-            status = int(status)
-            if status < 300 or status > 399:
-                raise ValueError("status must be between 300 and 399.")
-        
-        self.status = status
-    
-    def set_response(self):
-        import cpg
-        cpg.response.status = status = self.status
-        cpg.response.headerMap['Content-Type'] = "text/html"
-        
-        if status in (300, 301, 302, 303, 307):
-            # "The ... URI SHOULD be given by the Location field
-            # in the response."
-            cpg.response.headerMap['Location'] = self.urls[0]
-            
-            # "Unless the request method was HEAD, the entity of the response
-            # SHOULD contain a short hypertext note with a hyperlink to the
-            # new URI(s)."
-            msg = {300: "This resource can be found at <a href='%s'>%s</a>.",
-                   301: "This resource has permanently moved to <a href='%s'>%s</a>.",
-                   302: "This resource resides temporarily at <a href='%s'>%s</a>.",
-                   303: "This resource can be found at <a href='%s'>%s</a>.",
-                   307: "This resource has moved temporarily to <a href='%s'>%s</a>.",
-                   }[status]
-            cpg.response.body = "<br />\n".join([msg % (url, url)
-                                                 for url in self.urls])
-        elif status == 304:
-            # Not Modified.
-            # "The response MUST include the following header fields:
-            # Date, unless its omission is required by section 14.18.1"
-            # The "Date" header should have been set in Request.__init__
-            
-            # "The 304 response MUST NOT contain a message-body."
-            cpg.response.body = []
-        elif status == 305:
-            # Use Proxy.
-            # self.urls[0] should be the URI of the proxy.
-            cpg.response.headerMap['Location'] = self.urls[0]
-            cpg.response.body = []
-        else:
-            raise ValueError("The %s status code is unknown." % status)

File cpg.py

-"""
-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.
-"""
-
-"""
-Global module that all modules developing with CherryPy should import.
-"""
-
-from __init__ import __version__
-
-_httpserver = None
-
-# import server module
-import _cpserver as server
-import _cpconfig as config
-config.init()
-
-# decorator function for exposing methods
-def expose(func):
-    func.exposed = True
-    return func
-
-def log(msg, context='', severity=0):
-    """Syntactic sugar for writing to the log."""
-    import _cputil
-    logfunc = _cputil.getSpecialAttribute('_cpLogMessage')
-    logfunc(msg, context, severity)
-

File lib/cptools.py

 """
 
 """
-Just a few convenient functions and classes.
+Just a few convenient functions and classes
 """
-
-import inspect
-
-def decorate(func, decorator):
-    """
-    Return the decorated func. This will automatically copy all
-    non-standard attributes (like exposed) to the newly decorated function.
-    """
-    newfunc = decorator(func)
-    for (k,v) in inspect.getmembers(func):
-        if not hasattr(newfunc, k):
-            setattr(newfunc, k, v)
-    return newfunc
-
-def decorateAll(obj, decorator):
-    """
-    Recursively decorate all exposed functions of obj and all of its children,
-    grandchildren, etc. If you used to use aspects, you might want to look
-    into these. This function modifies obj; there is no return value.
-    """
-    obj_type = type(obj)
-    for (k,v) in inspect.getmembers(obj):
-        if hasattr(obj_type, k): # only deal with user-defined attributes
-            continue
-        if callable(v) and getattr(v, "exposed", False):
-            setattr(obj, k, decorate(v, decorator))
-        decorateAll(v, decorator)
+
+import inspect
+
+def decorate(func, decorator):
+    """
+    Return the decorated func. This will automatically copy all
+    non-standard attributes (like exposed) to the newly decorated function.
+    """
+    newfunc = decorator(func)
+    for (k,v) in inspect.getmembers(func):
+        if not hasattr(newfunc, k):
+            setattr(newfunc, k, v)
+    return newfunc
+
+def decorateAll(obj, decorator):
+    """
+    Recursively decorate all exposed functions of obj and all of its children,
+    grandchildren, etc. If you used to use aspects, you might want to look
+    into these. This function modifies obj; there is no return value.
+    """
+    obj_type = type(obj)
+    for (k,v) in inspect.getmembers(obj):
+        if hasattr(obj_type, k): # only deal with user-defined attributes
+            continue
+        if callable(v) and getattr(v, "exposed", False):
+            setattr(obj, k, decorate(v, decorator))
+        decorateAll(v, decorator)
+
 
 class ExposeItems:
     """
     
     from cherrypy.lib.cptools import ExposeItems
     ...
-    cpg.root.foo = ExposeItems(mylist)
-    cpg.root.bar = ExposeItems(mydict)
+    cherrypy.root.foo = ExposeItems(mylist)
+    cherrypy.root.bar = ExposeItems(mydict)
     """
     exposed = True
     def __init__(self, items):
     Use case:
 
     from cherrypy.lib import cptools
-    from cherrypy import cpg
+    import cherrypy
     class Root(cptools.PositionalParametersAware):
         def something(self, name):
             return "hello, " + name
         something.exposed
-    cpg.root = Root()
-    cpg.server.start()
+    cherrypy.root = Root()
+    cherrypy.server.start()
 
     Now, fetch http://localhost:8080/something/name_is_here
     """

File lib/csauthenticate.py

 """
 
 import time, random
-from cherrypy import cpg
+import cherrypy
 
 from aspect import Aspect, STOP, CONTINUE
 
     timeout = 60 # in minutes
 
     def notLoggedIn(self, message):
-        return STOP, self.loginScreen(message, cpg.request.browserUrl)
+        return STOP, self.loginScreen(message, cherrypy.request.browserUrl)
 
     def _before(self, methodName, method):
         # If the method is not exposed, don't do anything
         if not getattr(method, 'exposed', None):
             return CONTINUE, None
 
-        cpg.request.login = ''
+        cherrypy.request.login = ''
         # If the method is one of these 4, do not try to find out who is logged in
         if methodName in ["loginScreen", "logoutScreen", "doLogin", "doLogout", "notLoggedIn"]:
             return CONTINUE, None
         # Check if a user is logged in:
         #   - If they are, set request.login with the right value
         #   - If not, return the login screen
-        if not cpg.request.simpleCookie.has_key(self.sessionIdCookieName):
-            # return STOP, self.loginScreen(self.noCookieMessage, cpg.request.browserUrl)
+        if not cherrypy.request.simpleCookie.has_key(self.sessionIdCookieName):
+            # return STOP, self.loginScreen(self.noCookieMessage, cherrypy.request.browserUrl)
             return self.notLoggedIn(self.noCookieMessage)
-        sessionId = cpg.request.simpleCookie[self.sessionIdCookieName].value
+        sessionId = cherrypy.request.simpleCookie[self.sessionIdCookieName].value
         now=time.time()
 
         # Check that session exists and hasn't timed out
         timeout=0
-        if not cpg.request.sessionMap.has_key(sessionId):
-            # return STOP, self.loginScreen(self.noCookieMessage, cpg.request.browserUrl)
+        if not cherrypy.request.sessionMap.has_key(sessionId):
+            # return STOP, self.loginScreen(self.noCookieMessage, cherrypy.request.browserUrl)
             return self.notLoggedIn(self.noCookieMessage)
         else:
-            login, expire = cpg.request.sessionMap[sessionId]
+            login, expire = cherrypy.request.sessionMap[sessionId]
             if expire < now: timeout=1
             else:
                 expire = now + self.timeout*60
-                cpg.request.sessionMap[sessionId] = login, expire
+                cherrypy.request.sessionMap[sessionId] = login, expire
 
         if timeout:
-            # return STOP, self.loginScreen(self.timeoutMessage, cpg.request.browserUrl)
+            # return STOP, self.loginScreen(self.timeoutMessage, cherrypy.request.browserUrl)
             return self.notLoggedIn(self.timeoutMessage)
 
-        cpg.request.login = login
+        cherrypy.request.login = login
         return CONTINUE, None
 
     def checkLoginAndPassword(self, login, password):
         # Check that login/password match
         errorMsg = self.checkLoginAndPassword(login, password)
         if errorMsg:
-            cpg.request.login = ''
+            cherrypy.request.login = ''
             return self.loginScreen(errorMsg, fromPage, login)
-        cpg.request.login = login
+        cherrypy.request.login = login
         # Set session
-        newSessionId = self.generateSessionId(cpg.request.sessionMap.keys())
-        cpg.request.sessionMap[newSessionId] = login, time.time()+self.timeout*60
+        newSessionId = self.generateSessionId(cherrypy.request.sessionMap.keys())
+        cherrypy.request.sessionMap[newSessionId] = login, time.time()+self.timeout*60
         
-        cpg.response.simpleCookie[self.sessionIdCookieName] = newSessionId
-        cpg.response.simpleCookie[self.sessionIdCookieName]['path'] = '/'
-        cpg.response.simpleCookie[self.sessionIdCookieName]['max-age'] = 31536000
-        cpg.response.simpleCookie[self.sessionIdCookieName]['version'] = 1
-        cpg.response.status = "302 Found"
-        cpg.response.headerMap['Location'] = fromPage
+        cherrypy.response.simpleCookie[self.sessionIdCookieName] = newSessionId
+        cherrypy.response.simpleCookie[self.sessionIdCookieName]['path'] = '/'
+        cherrypy.response.simpleCookie[self.sessionIdCookieName]['max-age'] = 31536000
+        cherrypy.response.simpleCookie[self.sessionIdCookieName]['version'] = 1
+        cherrypy.response.status = "302 Found"
+        cherrypy.response.headerMap['Location'] = fromPage
         return ""
     doLogin.exposed = True
 
             del request.sessionMap[sessionId]
         except: pass
         
-        cpg.response.simpleCookie[self.sessionIdCookieName] = ""
-        cpg.response.simpleCookie[self.sessionIdCookieName]['path'] = '/'
-        cpg.response.simpleCookie[self.sessionIdCookieName]['max-age'] = 0
-        cpg.response.simpleCookie[self.sessionIdCookieName]['version'] = 1
-        cpg.request.login = ''
-        cpg.response.status = "302 Found"
-        cpg.response.headerMap['Location'] = 'logoutScreen'
+        cherrypy.response.simpleCookie[self.sessionIdCookieName] = ""
+        cherrypy.response.simpleCookie[self.sessionIdCookieName]['path'] = '/'
+        cherrypy.response.simpleCookie[self.sessionIdCookieName]['max-age'] = 0
+        cherrypy.response.simpleCookie[self.sessionIdCookieName]['version'] = 1
+        cherrypy.request.login = ''
+        cherrypy.response.status = "302 Found"
+        cherrypy.response.headerMap['Location'] = 'logoutScreen'
         return ""
     doLogout.exposed = True
 

File lib/filter/baseurlfilter.py

 
 from basefilter import BaseFilter
 
+
 class BaseUrlFilter(BaseFilter):
     """Filter that changes the base URL.
     
     """
     
     def beforeRequestBody(self):
-        # We have to dynamically import cpg because Python can't handle
-        #   circular module imports :-(
-        global cpg
-        from cherrypy import cpg
+        import cherrypy
         
-        if not cpg.config.get('baseUrlFilter.on', False):
+        if not cherrypy.config.get('baseUrlFilter.on', False):
             return
         
-        newBaseUrl = cpg.config.get('baseUrlFilter.baseUrl', 'http://localhost')
-        if cpg.config.get('baseUrlFilter.useXForwardedHost', True):
-            newBaseUrl = cpg.request.headerMap.get("X-Forwarded-Host", newBaseUrl)
+        req = cherrypy.request
+        newBaseUrl = cherrypy.config.get('baseUrlFilter.baseUrl', 'http://localhost')
+        if cherrypy.config.get('baseUrlFilter.useXForwardedHost', True):
+            newBaseUrl = req.headerMap.get("X-Forwarded-Host", newBaseUrl)
         
         if newBaseUrl.find("://") == -1:
-            # add http:// or https:// if needed	
-            newBaseUrl = cpg.request.base[:cpg.request.base.find("://") + 3] + newBaseUrl
+            # add http:// or https:// if needed
+            newBaseUrl = req.base[:req.base.find("://") + 3] + newBaseUrl
         
-        cpg.request.browserUrl = cpg.request.browserUrl.replace(
-            cpg.request.base, newBaseUrl)
-        cpg.request.base = newBaseUrl
+        req.browserUrl = req.browserUrl.replace(req.base, newBaseUrl)
+        req.base = newBaseUrl

File lib/filter/cachefilter.py

 import basefilter
 
 def defaultCacheKey():
-    return cpg.request.browserUrl
+    return cherrypy.request.browserUrl
 
 
 class MemoryCache:
         self.maxobjects = maxobjects
     
     def onStartResource(self):
-        # We have to dynamically import cpg because Python can't handle
+        # We have to dynamically import cherrypy because Python can't handle</