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

Changeset 480

Show
Ignore:
Timestamp:
07/18/05 12:38:27
Author:
fumanchu
Message:

1. New cherrypy.request.version, an instance of new _cphttptools.Version class. This will be min(request.protocol, server.protocolVersion).
2. Content-Length response header now defaults to None (since it must be finalized anyway).
3. Test suite: all client requests now HTTP/1.1
4. Test suite: new cmdline arg -1.1 to run server(s) as HTTP/1.1. Only -serverless currently passes as 1.1.
5. Test suite: turned getOptions into an Options object.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/cherrypy/_cperror.py

    r405 r480  
    117117        # http://ppewww.ph.gla.ac.uk/~flavell/www/post-redirect.html 
    118118        if status is None: 
    119             if cherrypy.request.protocol == "HTTP/1.1": 
     119            if cherrypy.request.version >= "1.1": 
    120120                status = 303 
    121121            else: 
  • trunk/cherrypy/_cphttptools.py

    r475 r480  
    3131""" 
    3232 
    33 import urllib, os, sys, time, types, cgi 
     33import urllib, os, sys, time, types, cgi, re 
    3434import mimetypes, Cookie 
    3535 
     
    6767    return ("%s, %02d %3s %4d %02d:%02d:%02d GMT" % 
    6868            (weekdayname[wd], day, monthname[month], year, hh, mm, ss)) 
     69 
     70 
     71class Version(object): 
     72     
     73    def __init__(self, atoms): 
     74        if isinstance(atoms, basestring): 
     75            self.atoms = re.split(r'\W', atoms) 
     76        else: 
     77            self.atoms = [str(x) for x in atoms] 
     78     
     79    def from_http(cls, version_str): 
     80        return cls(version_str[5:]) 
     81    from_http = classmethod(from_http) 
     82     
     83    def to_http(self): 
     84        return "HTTP/%s.%s" % tuple(self.atoms[:2]) 
     85     
     86    def __str__(self): 
     87        return ".".join([str(x) for x in self.atoms]) 
     88     
     89    def __cmp__(self, other): 
     90        cls = self.__class__ 
     91        if not isinstance(other, cls): 
     92            # Try to coerce other to a Version instance. 
     93            other = cls(other) 
     94         
     95        index = 0 
     96        while index < len(self.atoms) and index < len(other.atoms): 
     97            mine, theirs = self.atoms[index], other.atoms[index] 
     98            if mine.isdigit() and theirs.isdigit(): 
     99                mine, theirs = int(mine), int(theirs) 
     100            if mine < theirs: 
     101                return -1 
     102            if mine > theirs: 
     103                return 1 
     104            index += 1 
     105        if index < len(other.atoms): 
     106            return -1 
     107        if index < len(self.atoms): 
     108            return 1 
     109        return 0 
    69110 
    70111 
     
    125166    def __init__(self, clientAddress, remoteHost, requestLine, headers, 
    126167                 rfile, scheme="http"): 
    127         # When __init__ is finished, cherrypy.response should have three attributes: 
     168        # When __init__ is done, cherrypy.response should have 3 attributes: 
    128169        #   status, e.g. "200 OK" 
    129170        #   headers, a list of (name, value) tuples 
     
    157198            "Date": httpdate(), 
    158199            "Set-Cookie": [], 
    159             "Content-Length": 0 
     200            "Content-Length": None 
    160201        }) 
    161202        cherrypy.response.simpleCookie = Cookie.SimpleCookie() 
     
    204245        req.processRequestBody = req.method in ("POST", "PUT") 
    205246         
     247        # Compare request and server HTTP versions, in case our server does 
     248        # not support the requested version. We can't tell the server what 
     249        # version number to write in the response, so we limit our output 
     250        # to min(req, server). We want the following output: 
     251        #   request version   server version   response version   features 
     252        # a       1.0              1.0               1.0            1.0 
     253        # b       1.0              1.1               1.1            1.0 
     254        # c       1.1              1.0               1.0            1.0 
     255        # d       1.1              1.1               1.1            1.1 
     256        # Notice that, in (b), the response will be "HTTP/1.1" even though 
     257        # the client only understands 1.0. RFC 2616 10.5.6 says we should 
     258        # only return 505 if the _major_ version is different. 
     259        request_v = Version.from_http(req.protocol) 
     260        server_v = cherrypy.config.get("server.protocolVersion", "HTTP/1.0") 
     261        server_v = Version.from_http(server_v) 
     262        cherrypy.request.version = min(request_v, server_v) 
     263         
    206264        # find the queryString, or set it to "" if not found 
    207265        if "?" in path: 
     
    234292        cherrypy.log(msg, "HTTP") 
    235293         
    236         req.base = "%s://%s" % (req.scheme, req.headerMap.get('Host', '')) 
    237         req.browserUrl = req.base + path 
    238          
    239294        # Change objectPath in filters to change 
    240295        # the object that will get rendered 
     
    245300        req.originalParamMap = req.paramMap 
    246301        req.originalParamList = req.paramList 
     302         
     303        if cherrypy.request.version >= "1.1": 
     304            # All Internet-based HTTP/1.1 servers MUST respond with a 400 
     305            # (Bad Request) status code to any HTTP/1.1 request message 
     306            # which lacks a Host header field. 
     307            if not req.headerMap.has_key("Host"): 
     308                cherrypy.response.status = 400 
     309                cherrypy.response.body = ["HTTP/1.1 requires a 'Host' request header."] 
     310                finalize() 
     311                raise cherrypy.RequestHandled 
     312        req.base = "%s://%s" % (req.scheme, req.headerMap.get('Host', '')) 
     313        req.browserUrl = req.base + path 
    247314     
    248315    def processRequestBody(self): 
     
    431498        cherrypy.response.body = [] 
    432499     
    433     if (cherrypy.config.get("server.protocolVersion") != "HTTP/1.1" 
    434         and cherrypy.response.headerMap.get('Content-Length') == 0)
    435         content = ''.join([chunk for chunk in cherrypy.response.body]) 
    436         cherrypy.response.body = [content] 
    437         cherrypy.response.headerMap['Content-Length'] = len(content) 
     500    if cherrypy.response.headerMap.get('Content-Length') is None: 
     501        if cherrypy.request.version < "1.1"
     502            content = ''.join([chunk for chunk in cherrypy.response.body]) 
     503            cherrypy.response.body = [content] 
     504            cherrypy.response.headerMap['Content-Length'] = len(content) 
    438505     
    439506    # Headers 
     
    506573    except OSError: 
    507574        raise cherrypy.NotFound(cherrypy.request.path) 
    508  
     575     
    509576    # Set content-type based on filename extension 
    510577    i = filename.rfind('.') 
     
    513580    else: 
    514581        ext = "" 
    515          
     582     
    516583    contentType = mimetypes.types_map.get(ext, "text/plain") 
    517584    cherrypy.response.headerMap['Content-Type'] = contentType 
     
    531598    bodyfile = open(filename, 'rb') 
    532599    cherrypy.response.body = fileGenerator(bodyfile) 
    533      
    534      
    535600 
    536601 
  • trunk/cherrypy/lib/autoreload.py

    r277 r480  
    66import time 
    77import thread 
    8 from cherrypy import _cputil 
     8import cherrypy 
    99 
    1010RUN_RELOADER = True 
     
    2828    while True: 
    2929        args = [sys.executable] + sys.argv 
    30         if sys.platform == "win32": args = ['"%s"' % arg for arg in args] 
     30        if sys.platform == "win32": 
     31            args = ['"%s"' % arg for arg in args] 
    3132        new_environ = os.environ.copy() 
    3233        new_environ["RUN_MAIN"] = 'true' 
     
    5354            sys.exit(restart_with_reloader()) 
    5455        except KeyboardInterrupt: 
    55             _cputil.getSpecialAttribute('_cpLogMessage')("<Ctrl-C> hit: shutting down autoreloader", "HTTP") 
     56            cherrypy.log("<Ctrl-C> hit: shutting down autoreloader", "HTTP") 
  • trunk/cherrypy/test/helper.py

    r477 r480  
    8888        self.url = url 
    8989         
    90         requestLine = "%s %s HTTP/1.0" % (method.upper(), url) 
     90        requestLine = "%s %s HTTP/1.1" % (method.upper(), url) 
    9191        headers = webtest.cleanHeaders(headers, method, body, HOST, PORT) 
    9292        if body is not None: 
     
    175175 
    176176 
    177 def testmain(server=None, conf={}): 
     177def testmain(server=None, conf=None): 
     178    if conf is None: 
     179        conf = {} 
     180##        conf = {'global': {'server.socketHost': HOST, 
     181##                                  'server.socketPort': PORT, 
     182##                                  'server.protocolVersion': "HTTP/1.1", 
     183##                                  'server.threadPool': 10, 
     184##                                  'server.logToScreen': False, 
     185##                                  'server.environment': "production", 
     186##                                  } 
     187##                       } 
     188##    if server is None: 
     189##        server = "cherrypy._cphttpserver.embedded_server" 
    178190    if isinstance(conf, basestring): 
    179191        # assume it's a filename 
  • trunk/cherrypy/test/test.py

    r474 r480  
    7474 
    7575 
    76 def getOptions(args): 
    77      
    78     argSet = set([arg.lower() for arg in args]) 
    79      
    80     if '-help' in args: 
    81         raise DisplayHelp 
    82      
    83     servers = set() 
    84     if '-all' in argSet: 
    85         servers.update(['wsgi', 'native', 'serverless']) 
    86     else: 
    87         if '-native' in argSet: 
    88             servers.add('native') 
    89         if '-serverless' in argSet: 
    90             servers.add('serverless') 
    91         if '-wsgi' in argSet or not servers: 
    92             servers.add('wsgi') 
    93     argSet.difference_update(['-wsgi', '-native', '-serverless', '-all']) 
    94      
    95     cover = ("-cover" in argSet) 
    96     profile = ("-profile" in argSet) 
    97     if cover and profile: 
    98         raise BadArgument('Bad Arguments: you cannot run the profiler and the coverage tool at the same time.') 
    99     argSet.difference_update(['-cover', '-profile']) 
    100      
    101     tests = [] 
    102     for testString, test in testDict.iteritems(): 
    103         if testString.lower() in argSet: 
    104             tests.append(testDict[testString]) 
    105             argSet.discard(testString.lower()) 
    106     if not tests: 
    107         tests = testDict.values() 
    108      
    109     if len(argSet): 
    110         for arg in args: 
    111             if arg.lower() in argSet: 
    112                 raise BadArgument('Bad Argument: %s is not a valid option.' % arg) 
    113     return (servers, tests, cover, profile) 
    114  
    115  
    116 def main(servers, testList, cover=False, profile=False): 
     76class Options: 
     77     
     78    def __init__(self, args): 
     79        argSet = set([arg.lower() for arg in args]) 
     80         
     81        if '-help' in args: 
     82            raise DisplayHelp 
     83         
     84        servers = set() 
     85        if '-all' in argSet: 
     86            servers.update(['wsgi', 'native', 'serverless']) 
     87        else: 
     88            if '-native' in argSet: 
     89                servers.add('native') 
     90            if '-serverless' in argSet: 
     91                servers.add('serverless') 
     92            if '-wsgi' in argSet or not servers: 
     93                servers.add('wsgi') 
     94        self.servers = servers 
     95        argSet.difference_update(['-wsgi', '-native', '-serverless', '-all']) 
     96         
     97        self.cover = ("-cover" in argSet) 
     98        self.profile = ("-profile" in argSet) 
     99        if self.cover and self.profile: 
     100            raise BadArgument('Bad Arguments: you cannot run the profiler and the coverage tool at the same time.') 
     101        argSet.difference_update(['-cover', '-profile']) 
     102         
     103        if "-1.1" in argSet: 
     104            self.protocol = "HTTP/1.1" 
     105            argSet.difference_update(['-1.1']) 
     106        else: 
     107            self.protocol = "HTTP/1.0" 
     108         
     109        # All remaining args should be test names. 
     110        tests = [] 
     111        for testString, test in testDict.iteritems(): 
     112            if testString.lower() in argSet: 
     113                tests.append(testDict[testString]) 
     114                argSet.discard(testString.lower()) 
     115        if not tests: 
     116            tests = testDict.values() 
     117        self.tests = tests 
     118         
     119        if len(argSet): 
     120            for arg in args: 
     121                if arg.lower() in argSet: 
     122                    raise BadArgument('Bad Argument: %s is not a valid option.' % arg) 
     123 
     124 
     125def main(opts): 
    117126    # Place our current directory's parent (cherrypy/) at the beginning 
    118127    # of sys.path, so that all imports are from our current directory. 
     
    121130    sys.path.insert(0, os.path.normpath(os.path.join(curpath, '../../'))) 
    122131     
    123     if cover: 
     132    if opts.cover: 
    124133        # Start the coverage tool before importing cherrypy, 
    125134        # so module-level global statements are covered. 
     
    152161    server_conf = {'global': {'server.socketHost': helper.HOST, 
    153162                              'server.socketPort': helper.PORT, 
     163                              'server.protocolVersion': opts.protocol, 
    154164                              'server.threadPool': 10, 
    155165                              'server.logToScreen': False, 
     
    158168                   } 
    159169     
    160     if cover: 
     170    if opts.cover: 
    161171        cherrypy.codecoverage = True 
    162172     
    163     if profile: 
     173    if opts.profile: 
    164174        server_conf['profiling.on'] = True 
    165175     
    166     if 'serverless' in servers: 
    167         print 
    168         print "Running testList: Serverless" 
    169         helper.run_test_suite(testList, None, server_conf) 
    170      
    171     if 'native' in servers: 
    172         print 
    173         print "Running testList: Native HTTP Server" 
    174         helper.run_test_suite(testList, "cherrypy._cphttpserver.embedded_server", server_conf) 
    175      
    176     if 'wsgi' in servers: 
    177         print 
    178         print "Running testList: Native WSGI Server" 
    179         helper.run_test_suite(testList, "cherrypy._cpwsgi.WSGIServer", server_conf) 
    180      
    181     if profile or cover: 
    182         print 
    183      
    184     if profile: 
     176    if 'serverless' in opts.servers: 
     177        print 
     178        print "Running tests: Serverless" 
     179        helper.run_test_suite(opts.tests, None, server_conf) 
     180     
     181    if 'native' in opts.servers: 
     182        print 
     183        print "Running tests: Native HTTP Server" 
     184        helper.run_test_suite(opts.tests, 
     185                              "cherrypy._cphttpserver.embedded_server", 
     186                              server_conf) 
     187     
     188    if 'wsgi' in opts.servers: 
     189        print 
     190        print "Running tests: Native WSGI Server" 
     191        helper.run_test_suite(opts.tests, 
     192                              "cherrypy._cpwsgi.WSGIServer", 
     193                              server_conf) 
     194     
     195    if opts.profile or opts.cover: 
     196        print 
     197     
     198    if opts.profile: 
    185199        del server_conf['profiling.on'] 
    186200        print "run /cherrypy/lib/profiler.py as a script to serve profiling results on port 8080" 
    187201     
    188     if cover: 
     202    if opts.cover: 
    189203        cherrypy.codecoverage = False 
    190204        if coverage: 
     
    199213if __name__ == '__main__': 
    200214    try: 
    201         servers, testList, cover, profile = getOptions(sys.argv[1:]) 
     215        opts = Options(sys.argv[1:]) 
    202216    except DisplayHelp: 
    203217        help() 
     
    205219        print argError 
    206220    else: 
    207         main(servers, testList, cover, profile
     221        main(opts

Hosted by WebFaction

Log in as guest/cpguest to create tickets