Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

Changeset 204

Show
Ignore:
Timestamp:
05/22/05 16:31:26
Author:
mikerobi
Message:

merged the trunk (r202) back into 132 branch

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/ticket-132/CHANGELOG.txt

    r135 r204  
    1     * if y is a static dir make y/a?b try and serve a file named a?b (Dan) 
    2     * pass threadIndex to onStartThreadList functions - ticket #91 (Remi) 
    3     * renamed "configDict" into "configMap" for consistency - ticket  #82 (Remi) 
     1    * BACKWARD INCOMPATIBILITY: New config system, see http://www.cherrypy.org/wiki/ConfigSystem21 (Remi) 
     2    * Fixed small bug in httptools.redirect (Remi) 
     3    * Allow methods to return recursive generators (Remi) 
     4    * Methods can now return file objects which are red in 64kb chunks. (Mike) 
     5 
     62005-04-25: 
     7    * CherryPy-2.0-final released 
     8    * Added tests about static content and httptools.redirect (Remi) 
     9    * Handle %20 (and others) in static content - ticket #104 (Remi) 
     10    * If y is a static dir make y/a?b try and serve a file named a?b (Dan) 
     11    * Pass threadIndex to onStartThreadList functions - ticket #91 (Remi) 
     12    * Renamed "configDict" into "configMap" for consistency - ticket  #82 (Remi) 
    413    * Dots in requests path are now replaced by underscores  - ticket #87 (Remi) 
    514    * Improved WSGI support and added example (seems to work OK) (Peter, Remi) 
    615    * Added DecodingFilter (Remi) 
    716    * Added form module (port from CP1 Form.cpy) (Remi) 
     17    * Improved the way static files are being served (Remi) 
    818 
    9 2004/12-29: 
     192004-12-29: 
    1020    * CherryPY-2.0-beta released 
    1121    * xmlrpcfilter added (Remco) 
     
    2939    * Fixed file upload bug (Remi) 
    3040 
    31 2004/10/13: 
     412004-10-13: 
    3242    * First alpha release of CherryPy-2 (Remi) 
    3343 
  • branches/ticket-132/MANIFEST.in

    r120 r204  
    22include CHERRYPYTEAM.txt 
    33include *.conf 
     4include cherrypy/tutorial/README.txt 
     5include cherrypy/test/style.css 
     6include cherrypy/test/static/index.html 
  • branches/ticket-132/README.txt

    r109 r204  
    1 * To install, just type
     1* To install, just type (python-2.3 or later needed)
    22 
    33    python setup.py install 
     
    55* To learn how to use it, look at the examples under cherrypy/tutorial/ or go to http://www.cherrypy.org for more info. 
    66 
    7 * To run the unittest, just go to the cherrypy/test/ directory and type: 
     7* To run the regression tests, just go to the cherrypy/test/ directory and type: 
    88 
    99    python test.py 
  • branches/ticket-132/cherrypy/__init__.py

    r101 r204  
    1 __version__ = '2.0.0b
     1__version__ = '2.0.0
  • branches/ticket-132/cherrypy/_cpconfig.py

    r194 r204  
    2929import _cputil, ConfigParser, cpg 
    3030 
    31 from lib.unrepr import unreprWrapper 
     31# Default config options 
     32configMap = { 
     33        '/': { 
     34            'server.socketPort': 8080, 
     35            'server.socketHost': '', 
     36            'server.socketFile': '', 
     37            'server.socketQueueSize': 5, 
     38 
     39            'server.env': 'dev', 
     40            'server.protocolVersion': 'HTTP/1.0', 
     41            'server.logToScreen': True, 
     42            'server.logFile': '', 
     43            'server.reverseDNS': False, 
     44            'server.threadPool': 0, 
     45            'server.environment': 'prod', 
     46 
     47            'session.storageType': 'ram', 
     48            'session.timeout': 60, 
     49            'session.cleanUpDelay': 60, 
     50            'session.cookieName': 'CherryPySession', 
     51            'session.storageFileDir': '', 
     52 
     53            'staticContent': {} 
     54        }, 
     55    } 
     56 
     57def update(updateMap = None, file = None): 
     58    if updateMap is not None: 
     59        for section, valueMap in updateMap.items(): 
     60            if section not in configMap: 
     61                configMap[section] = valueMap 
     62            else: 
     63                for key, value in valueMap.items(): 
     64                    configMap[section][key] = value 
     65    if file is not None: 
     66        _load(file) 
     67 
     68def _getSlashSections(): 
     69    """ Return all config sections from configMap 
     70        that start with a slash and return them sorted by length 
     71        (longest first) 
     72    """ 
     73    # TODO: the result could be cached and recomputed when 
     74    #   config.update() is called 
     75    sectionList = [section for section in configMap.keys() 
     76        if (section[0] == '/' or section.startswith('http://') or 
     77            section.startswith('https://'))] 
     78    sectionList.sort(_sortOnLength) 
     79    return sectionList 
     80 
     81def _sortOnLength(a, b): 
     82    l1, l2 = len(a), len(b) 
     83    if l1 == l2: 
     84        return 0 
     85    elif l1 < l2: 
     86        return 1 
     87    else: 
     88        return -1 
     89 
     90def _getFor(path, key, defaultValue = None, returnSection = False): 
     91    for section in _getSlashSections(): 
     92        if path.startswith(section): 
     93            res = configMap[section].get(key, '#NULL#') 
     94            if res != '#NULL#': 
     95                if returnSection: 
     96                    return section 
     97                return res 
     98    return defaultValue 
     99 
     100def _cast(type, value): 
     101    if type is None: 
     102        return value 
     103    if type == 'int': 
     104        return int(value) 
     105    elif type == 'float': 
     106        return float(value) 
     107    elif type == 'bool': 
     108        if isinstance(value, basestring): 
     109            value = value.lower() 
     110        if (not value) or (value in ('false', 'off', '0')): 
     111            return False 
     112        return True 
     113    elif type == 'list': 
     114        if isinstance(value, list): 
     115            return value 
     116        assert (not value) or ( 
     117            value[0] in ('(', '[') and value[-1] in (')', ']')) 
     118        return eval(value) # Convert value to list 
     119 
     120def get(key, defaultValue = None, cast = None, returnSection = False): 
     121    # First try the whole browserUrl 
     122    try: 
     123        path = cpg.request.browserUrl 
     124    except: 
     125        # At startup, we don't have a path yet 
     126        path = '/' 
     127    res = _getFor(path, key, '#NULL#', returnSection) 
     128    if res != '#NULL#': 
     129        return _cast(cast, res) 
     130    # Then try just path 
     131    try: 
     132        path = cpg.request.path 
     133    except: 
     134        # At startup, we don't have a path yet 
     135        path = '/' 
     136    res = _getFor(path, key, '#NULL#', returnSection) 
     137    if res != '#NULL#': 
     138        return _cast(cast, res) 
     139    return _cast(cast, defaultValue) 
    32140 
    33141class CaseSensitiveConfigParser(ConfigParser.ConfigParser): 
    34     """ Sub-class of ConfigParser that keeps the case of options """ 
     142    """ Sub-class of ConfigParser that keeps the case of options and 
     143        that raises an exception if the file cannot be read 
     144    """ 
    35145    def optionxform(self, optionstr): 
    36146        return optionstr 
    37  
    38 # Known types to check types: 
    39 knownTypes = { 
    40     'server': { 
    41         'logToScreen':    bool, 
    42         'socketPort' :     int, 
    43         'reverseDNS' :    bool, 
    44         'socketQueueSize': int, 
    45         'threadPool':      int}, 
    46     'session': { 
    47         'sessionTimeout':   int, 
    48         'cleanUpDelay'  :  bool, 
    49     } 
    50 
    51  
    52          
    53  
    54 def loadConfigFile(configFile = None): 
     147    def read(self, filenames): 
     148        if isinstance(filenames, basestring): 
     149            filenames = [filenames] 
     150        for filename in filenames: 
     151            # try: 
     152            #     fp = open(filename) 
     153            # except IOError: 
     154            #     continue 
     155            fp = open(filename) 
     156            self._read(fp, filename) 
     157            fp.close() 
     158 
     159def _load(configFile = None): 
    55160    """ Convert an INI file to a dictionary """ 
    56161    _cpLogMessage = _cputil.getSpecialFunction('_cpLogMessage') 
     
    67172    # Load INI file into cpg.configMap 
    68173    for section in configParser.sections(): 
    69         if section not in cpg.configMap: 
    70             cpg.configMap[section] = {} 
     174        if section not in configMap: 
     175            configMap[section] = {} 
    71176        for option in configParser.options(section): 
    72             # unrep and validate the type 
    73             value     = unreprWrapper(configParser.get(section, option)) 
    74             knownType = knownTypes.get(section, {}).get(option, object) 
    75             if knownType == bool: 
    76                 if value == 1 or value == 0: 
    77                      value = bool(value) 
    78            
    79                 elif value == 'on': 
    80                     value = True 
    81  
    82                 elif value == 'off': 
    83                      value = False 
    84  
    85             if not isinstance(value, knownType): 
    86                 raise TypeError('%s must be a %s' % (option, knownType.__name__)) 
    87             else: 
    88                 cpg.configMap[section][option] = value 
     177            value = configParser.get(section, option) 
     178            configMap[section][option] = value 
    89179 
    90180def outputConfigMap(): 
    91181    _cpLogMessage = _cputil.getSpecialFunction('_cpLogMessage') 
    92182    _cpLogMessage("Server parameters:", 'CONFIG') 
    93     _cpLogMessage("  server.logToScreen: %s" % cpg.getConfig('server', 'logToScreen'), 'CONFIG') 
    94     _cpLogMessage("  server.logFile: %s" % cpg.getConfig('server', 'logFile'), 'CONFIG') 
    95     _cpLogMessage("  server.protocolVersion: %s" % cpg.getConfig('server', 'protocolVersion'), 'CONFIG') 
    96     _cpLogMessage("  server.socketHost: %s" % cpg.getConfig('server', 'socketHost'), 'CONFIG') 
    97     _cpLogMessage("  server.socketPort: %s" % cpg.getConfig('server', 'socketPort'), 'CONFIG') 
    98     _cpLogMessage("  server.socketFile: %s" % cpg.getConfig('server', 'socketFile'), 'CONFIG') 
    99     _cpLogMessage("  server.reverseDNS: %s" % cpg.getConfig('server', 'reverseDNS'), 'CONFIG') 
    100     _cpLogMessage("  server.socketQueueSize: %s" % cpg.getConfig('server', 'socketQueueSize'), 'CONFIG') 
    101     _cpLogMessage("  server.threadPool: %s" % cpg.getConfig('server', 'threadPool'), 'CONFIG') 
    102     _cpLogMessage("  session.storageType: %s" % cpg.getConfig('session', 'storageType'), 'CONFIG') 
    103     if cpg.getConfig('session', 'storageType'): 
    104         _cpLogMessage("  session.timeout: %s min" % cpg.getConfig('session', 'timeout'), 'CONFIG') 
    105         _cpLogMessage("  session.cleanUpDelay: %s min" % cpg.getConfig('session', 'cleanUpDelay'), 'CONFIG') 
    106         _cpLogMessage("  session.cookieName: %s" % cpg.getConfig('session', 'cookieName'), 'CONFIG') 
    107         _cpLogMessage("  session.storageFileDir: %s" % cpg.getConfig('session', 'storageFileDir'), 'CONFIG') 
    108     _cpLogMessage("  staticContent: %s" % cpg.getConfig('staticContent'), 'CONFIG') 
    109  
     183    _cpLogMessage("  server.env: %s" % cpg.config.get('server.env'), 'CONFIG') 
     184    _cpLogMessage("  server.logToScreen: %s" % cpg.config.get('server.logToScreen', cast='bool'), 'CONFIG') 
     185    _cpLogMessage("  server.logFile: %s" % cpg.config.get('server.logFile'), 'CONFIG') 
     186    _cpLogMessage("  server.protocolVersion: %s" % cpg.config.get('server.protocolVersion'), 'CONFIG') 
     187    _cpLogMessage("  server.socketHost: %s" % cpg.config.get('server.socketHost'), 'CONFIG') 
     188    _cpLogMessage("  server.socketPort: %s" % cpg.config.get('server.socketPort', cast='int'), 'CONFIG') 
     189    _cpLogMessage("  server.socketFile: %s" % cpg.config.get('server.socketFile'), 'CONFIG') 
     190    _cpLogMessage("  server.reverseDNS: %s" % cpg.config.get('server.reverseDNS', cast='bool'), 'CONFIG') 
     191    _cpLogMessage("  server.socketQueueSize: %s" % cpg.config.get('server.socketQueueSize', cast='int'), 'CONFIG') 
     192    _cpLogMessage("  server.threadPool: %s" % cpg.config.get('server.threadPool', cast='int'), 'CONFIG') 
     193    _cpLogMessage("  session.storageType: %s" % cpg.config.get('session.storageType'), 'CONFIG') 
     194    if cpg.config.get('session.storageType'): 
     195        _cpLogMessage("  session.timeout: %s min" % cpg.config.get('session.timeout', cast='float'), 'CONFIG') 
     196        _cpLogMessage("  session.cleanUpDelay: %s min" % cpg.config.get('session.cleanUpDelay', cast='float'), 'CONFIG') 
     197        _cpLogMessage("  session.cookieName: %s" % cpg.config.get('session.cookieName'), 'CONFIG') 
     198        _cpLogMessage("  session.storageFileDir: %s" % cpg.config.get('session.storageFileDir'), 'CONFIG') 
     199    _cpLogMessage("  staticContent: %s" % cpg.config.get('staticContent'), 'CONFIG') 
     200 
     201def dummy(): 
     202    # Check that parameters are correct and that they don't conflict with each other 
     203    if _protocolVersion not in ("HTTP/1.1", "HTTP/1.0"): 
     204        raise "CherryError: protocolVersion must be 'HTTP/1.1' or 'HTTP/1.0'" 
     205    if _reverseDNS not in (0,1): raise "CherryError: reverseDNS must be '0' or '1'" 
     206    if _socketFile and not hasattr(socket, 'AF_UNIX'): raise "CherryError: Configuration file has socketFile, but this is only available on Unix machines" 
     207    if _sslKeyFile: 
     208        try: 
     209            global SSL 
     210            from OpenSSL import SSL 
     211        except: raise "CherryError: PyOpenSSL 0.5.1 or later must be installed to use SSL. You can get it from http://pyopenssl.sourceforge.net" 
     212    if _socketPort and _socketFile: raise "CherryError: In configuration file: socketPort and socketFile conflict with each other" 
     213    if not _socketFile and not _socketPort: _socketPort=8000 # Default port 
     214    if _sslKeyFile and not _sslCertificateFile: raise "CherryError: Configuration file has sslKeyFile but no sslCertificateFile" 
     215    if _sslCertificateFile and not _sslKeyFile: raise "CherryError: Configuration file has sslCertificateFile but no sslKeyFile" 
     216    try: sys.stdout.flush() 
     217    except: pass 
     218 
     219    if _sessionStorageType not in ('', 'custom', 'ram', 'file', 'cookie'): raise "CherryError: Configuration file an invalid sessionStorageType: '%s'"%_sessionStorageType 
     220    if _sessionStorageType in ('custom', 'ram', 'cookie') and _sessionStorageFileDir!='': raise "CherryError: Configuration file has sessionStorageType set to 'custom, 'ram' or 'cookie' but a sessionStorageFileDir is specified" 
     221    if _sessionStorageType=='file' and _sessionStorageFileDir=='': raise "CherryError: Configuration file has sessionStorageType set to 'file' but no sessionStorageFileDir" 
     222 
  • branches/ticket-132/cherrypy/_cpdefaults.py

    r203 r204  
    3232""" 
    3333 
    34 import time, thread, os, cpg 
    35 #import cPickle as pickle 
     34import time, thread, os 
     35import cPickle as pickle 
     36import cpg 
    3637 
    3738def _cpLogMessage(msg, context = '', severity = 0): 
     
    4041    nowTuple = time.localtime(time.time()) 
    4142    nowStr = '%04d/%02d/%02d %02d:%02d:%02d' % (nowTuple[:6]) 
    42     if severity == 0: level = "INFO" 
    43     elif severity == 1: level = "WARNING" 
    44     elif severity == 2: level = "ERROR" 
     43    if severity == 0: 
     44        level = "INFO" 
     45    elif severity == 1: 
     46        level = "WARNING" 
     47    elif severity == 2: 
     48        level = "ERROR" 
     49    else: 
     50        lebel = "UNKNOWN" 
    4551    try: 
    46         logToScreen = int(cpg.parsedConfigFile.get('server', 'logToScreen')) 
     52        logToScreen = int(cpg.config.get('server.logToScreen', cast='bool')) 
    4753    except: 
    4854        logToScreen = True 
     
    5056    if logToScreen: 
    5157        print s 
    52     if cpg.getConfig('server', 'logFile'): 
    53         f = open(cpg.getConfig('server','logFile'), 'ab') 
     58    if cpg.config.get('server.logFile'): 
     59        f = open(cpg.config.get('server.logFile'), 'ab') 
    5460        f.write(s + '\n') 
    5561        f.close() 
     
    6167    bodyFile = StringIO.StringIO() 
    6268    traceback.print_exc(file = bodyFile) 
    63     cpg.response.body = bodyFile.getvalue() 
     69    cpg.response.body = [bodyFile.getvalue()] 
    6470    cpg.response.headerMap['Content-Type'] = 'text/plain' 
    6571 
     
    7278                  'sql'  : GenericSqlSession 
    7379                } 
    74 # robinson,  this crap will be deleted soon, yay! 
     80# this crap will be deleted soon 
    7581''' 
    7682def _cpSaveSessionData(sessionId, sessionData, expirationTime, 
     
    8086 
    8187    if threadPool is None: 
    82         threadPool = cpg.getConfig('server', 'threadPool') 
     88        threadPool = cpg.config.get('server.threadPool', cast='int') 
    8389    if sessionStorageType is None: 
    84         sessionStorageType = cpg.getConfig('session', 'storageType') 
     90        sessionStorageType = cpg.config.get('session.storageType') 
    8591    if sessionStorageFileDir is None: 
    86         sessionStorageFileDir = cpg.getConfig('session', 'storageFileDir') 
     92        sessionStorageFileDir = cpg.config.get('session.storageFileDir') 
    8793 
    8894    t = time.localtime(expirationTime) 
     
    108114 
    109115    if threadPool is None: 
    110         threadPool = cpg.getConfig('server', 'threadPool') 
     116        threadPool = cpg.config.get('server.threadPool', cast='int') 
    111117    if sessionStorageType is None: 
    112         sessionStorageType = cpg.getConfig('session', 'storageType') 
     118        sessionStorageType = cpg.config.get('session.storageType') 
    113119    if sessionStorageFileDir is None: 
    114         sessionStorageFileDir = cpg.getConfig('session', 'storageFileDir') 
     120        sessionStorageFileDir = cpg.config.get('session.storageFileDir') 
    115121 
    116122    if sessionStorageType == "ram": 
     
    137143 
    138144    if threadPool is None: 
    139         threadPool = cpg.getConfig('server', 'threadPool') 
     145        threadPool = cpg.config.get('server.threadPool', cast='int') 
    140146    if sessionStorageType is None: 
    141         sessionStorageType = cpg.getConfig('session', 'storageType') 
     147        sessionStorageType = cpg.config.get('session.storageType') 
    142148    if sessionStorageFileDir is None: 
    143         sessionStorageFileDir = cpg.getConfig('session', 'storageFileDir') 
     149        sessionStorageFileDir = cpg.config.get('session.storageFileDir') 
    144150 
    145151    # Clean up old session data 
     
    171177 
    172178_cpFilterList = [] 
     179 
     180# Filters that are always included 
     181from cherrypy.lib.filter import baseurlfilter, cachefilter, \ 
     182    decodingfilter, encodingfilter, gzipfilter, logdebuginfofilter, \ 
     183    staticfilter, tidyfilter, virtualhostfilter, xmlrpcfilter 
     184_cpDefaultInputFilterList = [ 
     185    cachefilter.CacheInputFilter(), 
     186    logdebuginfofilter.LogDebugInfoInputFilter(), 
     187    virtualhostfilter.VirtualHostFilter(), 
     188    baseurlfilter.BaseUrlFilter(), 
     189    decodingfilter.DecodingFilter(), 
     190    staticfilter.StaticFilter(), 
     191    xmlrpcfilter.XmlRpcInputFilter(), 
     192] 
     193_cpDefaultOutputFilterList = [ 
     194    xmlrpcfilter.XmlRpcOutputFilter(), 
     195    encodingfilter.EncodingFilter(), 
     196    tidyfilter.TidyFilter(), 
     197    logdebuginfofilter.LogDebugInfoOutputFilter(), 
     198    gzipfilter.GzipFilter(), 
     199    cachefilter.CacheOutputFilter(), 
     200] 
     201 
  • branches/ticket-132/cherrypy/_cphttpserver.py

    r154 r204  
    3838    # If sessions are stored in files and we 
    3939    # use threading, we need a lock on the file 
    40     if (cpg.getConfig('server', 'threadPool') > 1) and \ 
    41             cpg.getConfig('session', 'storageType') == 'file': 
     40    if (cpg.config.get('server.threadPool', cast='int') > 1) and \ 
     41            cpg.config.get('session.storageType') == 'file': 
    4242        cpg._sessionFileLock = threading.RLock() 
    4343 
    4444 
    45     if cpg.getConfig('server', 'socketFile'): 
     45    if cpg.config.get('server.socketFile'): 
    4646        # AF_UNIX socket 
    4747        # TODO: Handle threading here 
     
    4949    else: 
    5050        # AF_INET socket 
    51         if cpg.getConfig('server', 'threadPool') > 1: 
     51        if cpg.config.get('server.threadPool', cast='int') > 1: 
    5252            MyCherryHTTPServer = PooledThreadServer 
    5353        else: 
    5454            MyCherryHTTPServer = CherryHTTPServer 
    5555 
    56     MyCherryHTTPServer.request_queue_size = cpg.getConfig('server', 'socketQueueSize') 
     56    MyCherryHTTPServer.request_queue_size = cpg.config.get('server.socketQueueSize', cast='int') 
    5757 
    5858    # Set protocol_version 
    59     CherryHTTPRequestHandler.protocol_version = cpg.getConfig('server', 'protocolVersion') 
     59    CherryHTTPRequestHandler.protocol_version = cpg.config.get('server.protocolVersion') 
    6060 
    6161    run_server(CherryHTTPRequestHandler, MyCherryHTTPServer, \ 
    62         (cpg.getConfig('server', 'socketHost'), cpg.getConfig('server', 'socketPort')), \ 
    63         cpg.getConfig('server', 'socketFile')) 
     62        (cpg.config.get('server.socketHost'), cpg.config.get('server.socketPort', cast='int')), \ 
     63        cpg.config.get('server.socketFile')) 
    6464 
    6565def run_server(HandlerClass, ServerClass, server_address, socketFile): 
    6666    """Run the HTTP request handler class.""" 
    6767 
    68     if cpg.getConfig('server', 'socketFile'): 
    69         try: os.unlink(cpg.getConfig('server', 'socketFile')) # So we can reuse the socket 
     68    if cpg.config.get('server.socketFile'): 
     69        try: os.unlink(cpg.config.get('server.socketFile')) # So we can reuse the socket 
    7070        except: pass 
    71         server_address = cpg.getConfig('server', 'socketFile') 
    72     if cpg.getConfig('server', 'threadPool') > 1: 
    73         myCherryHTTPServer = ServerClass(server_address, cpg.getConfig('server', 'threadPool'), HandlerClass) 
     71        server_address = cpg.config.get('server.socketFile') 
     72    if cpg.config.get('server.threadPool', cast='int') > 1: 
     73        myCherryHTTPServer = ServerClass(server_address, cpg.config.get('server.threadPool', cast='int'), HandlerClass) 
    7474    else: 
    7575        myCherryHTTPServer = ServerClass(server_address, HandlerClass) 
    7676    cpg._server = myCherryHTTPServer 
    77     if cpg.getConfig('server', 'socketFile'): 
     77    if cpg.config.get('server.socketFile'): 
    7878        try: os.chmod(socketFile, 0777) # So everyone can access the socket 
    7979        except: pass 
     
    8282 
    8383    servingWhat = "HTTP" 
    84     if cpg.getConfig('server', 'socketPort'):  
     84    if cpg.config.get('server.socketPort', cast='int'):  
    8585        onWhat = ("socket: ('%s', %s)" %  
    86                  (cpg.getConfig('server', 'socketHost'), cpg.getConfig('server', 'socketPort'))) 
    87     else: onWhat = "socket file: %s" % cpg.getConfig('server', 'socketFile') 
     86                 (cpg.config.get('server.socketHost'), cpg.config.get('server.socketPort', cast='int'))) 
     87    else: onWhat = "socket file: %s" % cpg.config.get('server.socketFile') 
    8888    _cpLogMessage("Serving %s on %s" % (servingWhat, onWhat), 'HTTP') 
    8989 
     
    113113    def address_string(self): 
    114114        """ Try to do a reverse DNS based on [server]reverseDNS in the config file """ 
    115         if cpg.getConfig('server', 'reverseDNS'): 
     115        if cpg.config.get('server.reverseDNS', cast='bool'): 
    116116            return BaseHTTPServer.BaseHTTPRequestHandler.address_string(self) 
    117117        else: 
  • branches/ticket-132/cherrypy/_cphttptools.py

    r203 r204  
    2828 
    2929import cpg, urllib, sys, time, traceback, types, StringIO, cgi, os 
    30 import mimetypes, sha, random, string, _cputil, cperror, Cookie 
     30import mimetypes, sha, random, string, _cputil, cperror, Cookie, urlparse 
    3131from lib.filter import basefilter 
     32import _cpdefaults 
    3233 
    3334""" 
     
    143144 
    144145def applyFilterList(methodName): 
    145     try: 
    146         filterList = _cputil.getSpecialFunction('_cpFilterList') 
    147         for filter in filterList: 
    148             method = getattr(filter, methodName, None) 
    149             if method: 
    150                 method() 
    151     except basefilter.InternalRedirect: 
    152         # If we get an InternalRedirect, we start the filter list   
    153         #   from scratch. Is cpg.request.path or cpg.request.objectPath 
    154         #   has been modified by the hook, then a new filter list 
    155         #   will be applied.   
    156         # We use recursion so if there is an infinite loop, we'll   
    157         #   get the regular python "recursion limit exceeded" exception.   
    158         applyFilterList(methodName)  
    159  
     146    filterList = _cpdefaults._cpDefaultInputFilterList + \ 
     147        _cputil.getSpecialFunction('_cpFilterList') + \ 
     148        _cpdefaults._cpDefaultOutputFilterList 
     149    for filter in filterList: 
     150        method = getattr(filter, methodName, None) 
     151        if method: 
     152            method() 
    160153 
    161154def insertIntoHeaderMap(key,value): 
     
    167160    cookHeaders(clientAddress, remoteHost, headers, requestLine) 
    168161 
    169     cpg.request.base = "http://" + cpg.request.headerMap['Host'] 
     162    cpg.request.base = "http://" + cpg.request.headerMap.get('Host', '') 
    170163    cpg.request.browserUrl = cpg.request.base + cpg.request.browserUrl 
    171164    cpg.request.isStatic = False 
     
    176169    cpg.request.objectPath = None  
    177170 
     171    applyFilterList('setConfig') 
    178172    applyFilterList('afterRequestHeader') 
    179173 
     
    186180    # creates some attributes on cpg.response so filters can use them 
    187181    cpg.response.wfile = wfile 
    188     cpg.response.sendResponse = 1 
    189     try: 
    190         initRequest(clientAddress, remoteHost, requestLine, headers, rfile, wfile) 
    191     except basefilter.RequestHandled: 
    192         # request was already fully handled; it may be a cache hit 
    193         return 
     182    cpg.response.sendResponse = True 
     183    cpg.response.body = None 
    194184 
    195185    # Prepare response variables 
     
    198188    date = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (weekdayname[wd], day, monthname[month], year, hh, mm, ss) 
    199189    cpg.response.headerMap = { 
    200         "protocolVersion": cpg.getConfig('server', 'protocolVersion'), 
     190        "protocolVersion": cpg.config.get('server.protocolVersion'), 
    201191        "Status": "200 OK", 
    202192        "Content-Type": "text/html", 
     
    209199 
    210200    try: 
     201        try: 
     202            initRequest(clientAddress, remoteHost, requestLine, headers, rfile, wfile) 
     203        except basefilter.RequestHandled: 
     204            # request was already fully handled; it may be a cache hit 
     205            return 
     206        except: 
     207            # exception raised in a filter. 
     208            # we don't have a response body yet, so create an empty one 
     209            cpg.response.body = [] 
     210            raise 
    211211        handleRequest(cpg.response.wfile) 
    212212    except: 
     
    214214        # error reporting seems to be broken in some cases. This code is  
    215215        # a helper to check it 
    216         print "%"*80 
    217         traceback.print_exc() 
    218         print "%"*80 
    219216        err = "" 
    220217        exc_info_1 = sys.exc_info()[1] 
     
    226223 
    227224            # Still save session data 
    228             if cpg.getConfig('session', 'storageType') and not cpg.request.isStatic: 
     225            if cpg.config.get('session.storageType') and not cpg.request.isStatic: 
    229226                cpg.sessionManager.saveSessionMap() 
    230227 
     228            applyFilterList('beforeErrorResponse') 
    231229            wfile.write('%s %s\r\n' % (cpg.response.headerMap['protocolVersion'], cpg.response.headerMap['Status'])) 
    232230 
     
    247245            for line in cpg.response.body: 
    248246                wfile.write(line) 
     247            applyFilterList('afterErrorResponse') 
    249248        except: 
    250             # TODO: in some cases exceptions and filters are conflicting;  
    251             # error reporting seems to be broken in some cases. This code is  
    252             # a helper to check it 
    253             #print "%"*80 
    254             #traceback.print_exc() 
    255             #print "%"*80 
    256249            bodyFile = StringIO.StringIO() 
    257250            traceback.print_exc(file = bodyFile) 
    258251            body = bodyFile.getvalue() 
    259             wfile.write('%s 200 OK\r\n' % cpg.getConfig('server', 'protocolVersion')) 
     252            wfile.write('%s 200 OK\r\n' % cpg.config.get('server.protocolVersion')) 
    260253            wfile.write('Content-Type: text/plain\r\n') 
    261254            wfile.write('Content-Length: %s\r\n' % len(body)) 
     
    265258def sendResponse(wfile): 
    266259    applyFilterList('beforeResponse') 
    267  
    268     # Save session data 
    269     if cpg.getConfig('session', 'storageType') and not cpg.request.isStatic: 
    270         cpg.sessionManager.saveSessionMap() 
    271          
    272260 
    273261    # Set the content-length 
     
    280268        cpg.response.headerMap['Content-Length'] = len(cpg.response.body[0]) 
    281269 
     270    # Save session data 
     271    if cpg.config.get('session.storageType') and not cpg.request.isStatic: 
     272        cpg.sessionManager.saveSessionMap() 
     273 
    282274    wfile.write('%s %s\r\n' % (cpg.response.headerMap['protocolVersion'], cpg.response.headerMap['Status'])) 
    283275    for key, valueList in cpg.response.headerMap.items(): 
     
    302294    # Clean up expired sessions if needed: 
    303295    now = time.time() 
    304     if (cpg.getConfig('session', 'storageType') and  
    305         cpg.getConfig('session', 'cleanUpDelay') and  
    306         (cpg._lastSessionCleanUpTime + cpg.getConfig('session', 'cleanUpDelay') * 60) <= now): 
     296    if (cpg.config.get('session.storageType') and  
     297        cpg.config.get('session.cleanUpDelay', cast='float') and  
     298        (cpg._lastSessionCleanUpTime + cpg.config.get('session.cleanUpDelay', cast='float') * 60) <= now): 
    307299        cpg._lastSessionCleanUpTime = now 
    308300        cpg.sessionManager.cleanUpOldSessions() 
     
    314306 
    315307    path = cpg.request.path 
    316     if path.startswith('/'): path = path[1:] # Remove leading slash 
    317     if path.endswith('/'): path = path[:-1] # Remove trailing slash 
    318  
    319     # Handle static directories 
    320     for urlDir, fsDir in cpg.getConfig('staticContent').items(): 
    321         if path == urlDir or path[:len(urlDir)+1]==urlDir+'/': 
    322  
    323             cpg.request.isStatic = 1 
    324  
    325             fname = fsDir + path[len(urlDir):] 
    326             start_url_var = cpg.request.browserUrl.find('?') 
    327             if start_url_var != -1: fname = fname + cpg.request.browserUrl[start_url_var:]   
    328             try: 
    329                 stat = os.stat(fname) 
    330             except OSError: 
    331                 raise cperror.NotFound 
    332             modifTime = stat.st_mtime 
    333  
    334             strModifTime = time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(modifTime)) 
    335  
    336             # Check if browser sent "if-modified-since" in request header 
    337             if cpg.request.headerMap.has_key('If-Modified-Since'): 
    338                 # Check if if-modified-since date is the same as strModifTime 
    339                 if cpg.request.headerMap['If-Modified-Since'] == strModifTime: 
    340                     cpg.response.headerMap = { 
    341                         'Status': 304,  
    342                         'protocolVersion': cpg.configMap['server']['protocolVersion'],  #robinson 
    343                         'Date': cpg.response.headerMap['Date']} 
    344                     cpg.response.body = [] 
    345                     sendResponse(wfile) 
    346                     return 
    347  
    348             cpg.response.headerMap['Last-Modified'] = strModifTime 
    349             # Set Content-Length and use an iterable (file object) 
    350             #   this way CP won't load the whole file in memory 
    351             cpg.response.headerMap['Content-Length'] = stat[6] 
    352             cpg.response.body = open(fname, 'rb') 
    353             # Set content-type based on filename extension 
    354             i = path.rfind('.') 
    355             if i != -1: ext = path[i:] 
    356             else: ext = "" 
    357             contentType = mimetypes.types_map.get(ext, "text/plain") 
    358             cpg.response.headerMap['Content-Type'] = contentType 
    359             sendResponse(wfile) 
     308    if path.startswith('/'): 
     309        # Remove leading slash 
     310        path = path[1:] 
     311    if path.endswith('/'): 
     312        # Remove trailing slash 
     313        path = path[:-1] 
     314    path = urllib.unquote(path) # Replace quoted chars (eg %20) from url 
     315 
     316    # Get session data 
     317    if cpg.config.get('session.storageType') and not cpg.request.isStatic: 
     318        cpg.sessionManager.loadSessionMap() 
     319    if cpg.response.body is None: 
     320        try: 
     321            func, objectPathList, virtualPathList = mapPathToObject() 
     322        except IndexRedirect, inst: 
     323            # For an IndexRedirect, we don't go through the regular 
     324            #   mechanism: we return the redirect immediately 
     325            newUrl = urlparse.urljoin(cpg.request.base, inst.args[0]) 
     326            wfile.write('%s 302\r\n' % (cpg.response.headerMap['protocolVersion'])) 
     327            cpg.response.headerMap['Location'] = newUrl 
     328            for key, valueList in cpg.response.headerMap.items(): 
     329                if key not in ('Status', 'protocolVersion'): 
     330                    if type(valueList) != type([]): valueList = [valueList] 
     331                    for value in valueList: 
     332                        wfile.write('%s: %s\r\n'%(key, value)) 
     333            wfile.write('\r\n') 
    360334            return 
    361  
    362     try: 
    363         func, objectPathList, virtualPathList = mapPathToObject() 
    364     except IndexRedirect, inst: 
    365         # For an IndexRedirect, we don't go through the regular 
    366         #   mechanism: we return the redirect immediately 
    367         newUrl = canonicalizeUrl(inst.args[0]) 
    368         wfile.write('%s 302\r\n' % (cpg.response.headerMap['protocolVersion'])) 
    369         cpg.response.headerMap['Location'] = newUrl 
    370         for key, valueList in cpg.response.headerMap.items(): 
    371             if key not in ('Status', 'protocolVersion'): 
    372                 if type(valueList) != type([]): valueList = [valueList] 
    373                 for value in valueList: 
    374                     wfile.write('%s: %s\r\n'%(key, value)) 
    375         wfile.write('\r\n') 
    376         return 
    377      
    378     # robinson 
    379     # Get session data 
    380     if cpg.getConfig('session', 'storageType') and not cpg.request.isStatic: 
    381         cpg.sessionManager.loadSessionMap() 
    382  
    383     # Remove "root" from objectPathList and join it to get objectPath 
    384     cpg.request.objectPath = '/' + '/'.join(objectPathList[1:]) 
    385     body = func(*(virtualPathList + cpg.request.paramList), **(cpg.request.paramMap)) 
    386      
     335              
     336        # Remove "root" from objectPathList and join it to get objectPath 
     337        cpg.request.objectPath = '/' + '/'.join(objectPathList[1:]) 
     338        body = func(*(virtualPathList + cpg.request.paramList), **(cpg.request.paramMap)) 
     339    else: 
     340        body = cpg.response.body 
     341 
    387342    # builds a uniform return type 
    388     if not isinstance(body, types.GeneratorType): 
     343    if isinstance(body, types.FileType): 
     344        cpg.response.body = fileGenerator(body) 
     345    elif not isinstance(body, types.GeneratorType): 
    389346        cpg.response.body = [body] 
    390347    else: 
    391         cpg.response.body = body 
     348        cpg.response.body = flattener(body) 
    392349 
    393350    if cpg.response.sendResponse: 
    394351        sendResponse(wfile) 
    395352 
    396 def getObjFromPath(objPathList, objCache): 
     353def fileGenerator(file, chunkSize = 65536): # 65536 = 64kb 
     354   """ make file objects iterable generators """ 
     355   input = file.read(chunkSize) 
     356   while input: 
     357      yield input 
     358      input = file.read(chunkSize)  
     359 
     360 
     361def flattener(input): 
     362    for x in input: 
     363        if not isinstance(x, types.GeneratorType): 
     364            yield x 
     365        else: 
     366            for y in flattener(x): 
     367                yield y  
     368 
     369 
     370def generateSessionId(): 
     371    s = '' 
     372    for i in range(50): 
     373        s += random.choice(string.letters+string.digits) 
     374    s += '%s'%time.time() 
     375    return sha.sha(s).hexdigest() 
     376