diff options
Diffstat (limited to 'django/core/handlers/wsgi.py')
-rw-r--r-- | django/core/handlers/wsgi.py | 61 |
1 files changed, 51 insertions, 10 deletions
diff --git a/django/core/handlers/wsgi.py b/django/core/handlers/wsgi.py index 5c48c9dace..71cfecd9a0 100644 --- a/django/core/handlers/wsgi.py +++ b/django/core/handlers/wsgi.py @@ -4,6 +4,11 @@ from django.dispatch import dispatcher from django.utils import datastructures from django import http from pprint import pformat +from shutil import copyfileobj +try: + from cStringIO import StringIO +except ImportError: + from StringIO import StringIO # See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html STATUS_CODE_TEXT = { @@ -50,17 +55,49 @@ STATUS_CODE_TEXT = { 505: 'HTTP VERSION NOT SUPPORTED', } +def safe_copyfileobj(fsrc, fdst, length=16*1024, size=0): + """ + A version of shutil.copyfileobj that will not read more than 'size' bytes. + This makes it safe from clients sending more than CONTENT_LENGTH bytes of + data in the body. + """ + if not size: + return + while size > 0: + buf = fsrc.read(min(length, size)) + if not buf: + break + fdst.write(buf) + size -= len(buf) + class WSGIRequest(http.HttpRequest): def __init__(self, environ): self.environ = environ self.path = environ['PATH_INFO'] - self.META = environ + self.META = environ self.method = environ['REQUEST_METHOD'].upper() def __repr__(self): + # Since this is called as part of error handling, we need to be very + # robust against potentially malformed input. + try: + get = pformat(self.GET) + except: + get = '<could not parse>' + try: + post = pformat(self.POST) + except: + post = '<could not parse>' + try: + cookies = pformat(self.COOKIES) + except: + cookies = '<could not parse>' + try: + meta = pformat(self.META) + except: + meta = '<could not parse>' return '<WSGIRequest\nGET:%s,\nPOST:%s,\nCOOKIES:%s,\nMETA:%s>' % \ - (pformat(self.GET), pformat(self.POST), pformat(self.COOKIES), - pformat(self.META)) + (get, post, cookies, meta) def get_full_path(self): return '%s%s' % (self.path, self.environ.get('QUERY_STRING', '') and ('?' + self.environ.get('QUERY_STRING', '')) or '') @@ -119,7 +156,15 @@ class WSGIRequest(http.HttpRequest): try: return self._raw_post_data except AttributeError: - self._raw_post_data = self.environ['wsgi.input'].read(int(self.environ["CONTENT_LENGTH"])) + buf = StringIO() + try: + # CONTENT_LENGTH might be absent if POST doesn't have content at all (lighttpd) + content_length = int(self.environ.get('CONTENT_LENGTH', 0)) + except ValueError: # if CONTENT_LENGTH was empty string or not an integer + content_length = 0 + safe_copyfileobj(self.environ['wsgi.input'], buf, size=content_length) + self._raw_post_data = buf.getvalue() + buf.close() return self._raw_post_data GET = property(_get_get, _set_get) @@ -133,10 +178,6 @@ class WSGIHandler(BaseHandler): def __call__(self, environ, start_response): from django.conf import settings - if settings.ENABLE_PSYCO: - import psyco - psyco.profile() - # Set up middleware if needed. We couldn't do this earlier, because # settings weren't available. if self._request_middleware is None: @@ -145,7 +186,7 @@ class WSGIHandler(BaseHandler): dispatcher.send(signal=signals.request_started) try: request = WSGIRequest(environ) - response = self.get_response(request.path, request) + response = self.get_response(request) # Apply response middleware for middleware_method in self._response_middleware: @@ -163,4 +204,4 @@ class WSGIHandler(BaseHandler): for c in response.cookies.values(): response_headers.append(('Set-Cookie', c.output(header=''))) start_response(status, response_headers) - return response.iterator + return response |