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

Changeset 626

Show
Ignore:
Timestamp:
09/11/05 13:58:26
Author:
rdelon
Message:

Implemented ticket #90 (still need to write docs though)

Files:

Legend:

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

    r624 r626  
    4545 
    4646import cherrypy 
    47 from cherrypy import _cputil, _cpcgifs 
     47from cherrypy import _cputil, _cpcgifs, _cperror, _cpwsgiserver 
    4848from cherrypy.lib import cptools 
    4949 
     
    373373        # FieldStorage only recognizes POST, so fake it. 
    374374        methenv = {'REQUEST_METHOD': "POST"} 
    375         forms = _cpcgifs.FieldStorage(fp=request.rfile, 
     375        try: 
     376            forms = _cpcgifs.FieldStorage(fp=request.rfile, 
    376377                                      headers=lowerHeaderMap, 
    377378                                      environ=methenv, 
    378379                                      keep_blank_values=1) 
     380        except _cpwsgiserver.MaxSizeExceeded: 
     381            # Post data is too big 
     382            raise _cperror.HTTPStatusError(413) 
    379383         
    380384        if forms.file: 
  • trunk/cherrypy/_cpwsgi.py

    r605 r626  
    159159                        conf("server.threadPool"), 
    160160                        conf("server.socketHost"), 
     161                        config = cherrypy.config 
    161162                        ) 
  • trunk/cherrypy/_cpwsgiserver.py

    r579 r626  
    4242monthname = [None, 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 
    4343                   'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] 
     44 
     45class MaxSizeExceeded(Exception): 
     46    pass 
     47 
     48class SizeCheckWrapper(object): 
     49    """ Wrapper around the rfile object. For each data reading method, 
     50        it reads the data but it checks that the size of the data doesn't 
     51        except a certain limit 
     52    """ 
     53    def __init__(self, rfile, maxlen): 
     54        self.rfile = rfile 
     55        self.maxlen = maxlen 
     56        self.bytes_read = 0 
     57    def _check_length(self): 
     58        if self.maxlen and self.bytes_read > self.maxlen: 
     59            raise MaxSizeExceeded() 
     60    def read(self, size = None): 
     61        data = self.rfile.read(size) 
     62        self.bytes_read += len(data) 
     63        self._check_length() 
     64        return data 
     65    def readline(self, size = None): 
     66        if size is not None: 
     67            data = self.rfile.readline(size) 
     68            self.bytes_read += len(data) 
     69            self._check_length() 
     70            return data 
     71 
     72        # User didn't specify a size ... 
     73        # We read the line in chunks to make sure it's not a 100MB line ! 
     74        res = [] 
     75        while True: 
     76            data = self.rfile.readline(256) 
     77            self.bytes_read += len(data) 
     78            self._check_length() 
     79            res.append(data) 
     80            if len(data) < 256: 
     81                return ''.join(data) 
     82    def close(self): 
     83        self.rfile.close() 
    4484 
    4585 
     
    5696        self.outheaderkeys = None 
    5797        self.rfile = self.socket.makefile("r", self.server.bufsize) 
     98        if self.server.config: 
     99            mhs = self.server.config.get( 
     100                'server.maxRequestHeaderSize', 
     101                500 * 1024) # 500KB by default 
     102            self.rfile = SizeCheckWrapper(self.rfile, mhs) 
    58103        self.wfile = self.socket.makefile("w", self.server.bufsize) 
    59104        self.sent_headers = False 
     
    99144            self.environ[envname] = v 
    100145        self.ready = True 
     146 
     147        # Request header is parsed 
     148        # We prepare the SizeCheckWrapper for the request body 
     149        if self.server.config: 
     150            mbs = self.server.config.get( 
     151                'server.maxRequestBodySize', 
     152                100 * 1024 * 1024, # 100MB by default 
     153                path = path) 
     154            self.rfile.bytes_read = 0 
     155            self.rfile.maxlen = mbs 
    101156     
    102157    def start_response(self, status, headers, exc_info = None): 
     
    181236                    else: 
    182237                        raise 
     238                except MaxSizeExceeded: 
     239                    str = "Request Entity Too Large" 
     240                    proto = request.environ.get("SERVER_PROTOCOL", "HTTP/1.0") 
     241                    request.wfile.write("%s 413 %s\r\n" % (proto, str)) 
     242                    request.wfile.write("Content-Length: %s\r\n\r\n" % len(str)) 
     243                    request.wfile.write(str) 
     244                    request.wfile.flush() 
    183245                except: 
    184246                    traceback.print_exc() 
     
    190252    version = "CherryPy/2.1.0-beta" 
    191253    def __init__(self, bind_addr, wsgi_app, numthreads=10, server_name=None, 
    192                  stderr=sys.stderr, bufsize=-1, max=-1): 
     254                 stderr=sys.stderr, bufsize=-1, max=-1, 
     255                 config = None): 
    193256        ''' 
    194257        be careful w/ max 
     
    198261        self.bind_addr = bind_addr 
    199262        self.numthreads = numthreads or 1 
     263        self.config = config 
    200264        if server_name: 
    201265            self.server_name = server_name 
  • trunk/cherrypy/config.py

    r605 r626  
    5555    'server.reverseDNS': False, 
    5656    'server.threadPool': 0, 
    57  
    58     'server.maxRequestSize' : 0, # 0 == unlimited 
    5957    } 
    6058 
     
    8987        _load(file, override) 
    9088 
    91 def get(key, defaultValue=None, returnSection=False): 
     89def get(key, defaultValue=None, returnSection=False, path = None): 
    9290    """Return the configuration value corresponding to key 
    9391    If specified, return defaultValue on lookup failure. If returnSection is 
     
    9694    # Look, ma, no Python function calls! Uber-fast. 
    9795 
    98     try: 
    99         path = cherrypy.request.path 
    100     except AttributeError: 
    101         # There's no request.path yet, so use the global settings. 
    102         path = "global" 
    103      
     96    if path is None: 
     97        try: 
     98            path = cherrypy.request.path 
     99        except AttributeError: 
     100            # There's no request.path yet, so use the global settings. 
     101            path = "global" 
     102 
    104103    while True: 
    105104        if path == "": 
  • trunk/cherrypy/test/test_core.py

    r624 r626  
    236236        return cherrypy.request.body 
    237237 
    238  
    239238class Cookies(Test): 
    240239     
     
    248247            cherrypy.response.simpleCookie[name] = cookie.value 
    249248 
     249class MaxRequestSize(Test): 
     250     
     251    def index(self): 
     252        return "OK" 
     253 
     254    def upload(self, file): 
     255        return "Size: %s" % len(file.file.read()) 
    250256 
    251257logFile = os.path.join(localDir, "error.log") 
     
    633639        self.assertHeader('Set-Cookie', 'Last=Piranha;') 
    634640 
     641    def testMaxRequestSize(self): 
     642        self.getPage("/maxrequestsize/index") 
     643        self.assertBody("OK") 
     644        cherrypy.config.update({'server.maxRequestHeaderSize': 10}) 
     645        self.getPage("/maxrequestsize/index") 
     646        self.assertStatus("413 Request Entity Too Large") 
     647        self.assertBody("Request Entity Too Large") 
     648        cherrypy.config.update({'server.maxRequestHeaderSize': 0}) 
     649 
     650        # Test upload 
     651        h = [("Content-type", "multipart/form-data; boundary=x"), 
     652             ("Content-Length", "110")] 
     653        b = """--x 
     654Content-Disposition: form-data; name="file"; filename="hello.txt" 
     655Content-Type: text/plain 
     656 
     657hello 
     658--x-- 
     659""" 
     660        self.getPage('/maxrequestsize/upload', h, "POST", b) 
     661        self.assertBody('Size: 5') 
     662        cherrypy.config.update({ 
     663            '/maxrequestsize': {'server.maxRequestBodySize': 3}}) 
     664        self.getPage('/maxrequestsize/upload', h, "POST", b) 
     665        self.assertStatus("413 Request Entity Too Large") 
     666        self.assertInBody("Request Entity Too Large") 
    635667 
    636668if __name__ == '__main__': 

Hosted by WebFaction

Log in as guest/cpguest to create tickets