app/django/core/handlers/wsgi.py
changeset 323 ff1a9aa48cfd
parent 54 03e267d67478
--- a/app/django/core/handlers/wsgi.py	Tue Oct 14 12:36:55 2008 +0000
+++ b/app/django/core/handlers/wsgi.py	Tue Oct 14 16:00:59 2008 +0000
@@ -7,8 +7,8 @@
 
 from django import http
 from django.core import signals
-from django.core.handlers.base import BaseHandler
-from django.dispatch import dispatcher
+from django.core.handlers import base
+from django.core.urlresolvers import set_script_prefix
 from django.utils import datastructures
 from django.utils.encoding import force_unicode
 
@@ -74,10 +74,25 @@
 
 class WSGIRequest(http.HttpRequest):
     def __init__(self, environ):
+        script_name = base.get_script_name(environ)
+        path_info = force_unicode(environ.get('PATH_INFO', u'/'))
+        if not path_info or path_info == script_name:
+            # Sometimes PATH_INFO exists, but is empty (e.g. accessing
+            # the SCRIPT_NAME URL without a trailing slash). We really need to
+            # operate as if they'd requested '/'. Not amazingly nice to force
+            # the path like this, but should be harmless.
+            #
+            # (The comparison of path_info to script_name is to work around an
+            # apparent bug in flup 1.0.1. Se Django ticket #8490).
+            path_info = u'/'
         self.environ = environ
-        self.path = force_unicode(environ['PATH_INFO'])
+        self.path_info = path_info
+        self.path = '%s%s' % (script_name, path_info)
         self.META = environ
+        self.META['PATH_INFO'] = path_info
+        self.META['SCRIPT_NAME'] = script_name
         self.method = environ['REQUEST_METHOD'].upper()
+        self._post_parse_error = False
 
     def __repr__(self):
         # Since this is called as part of error handling, we need to be very
@@ -86,10 +101,13 @@
             get = pformat(self.GET)
         except:
             get = '<could not parse>'
-        try:
-            post = pformat(self.POST)
-        except:
+        if self._post_parse_error:
             post = '<could not parse>'
+        else:
+            try:
+                post = pformat(self.POST)
+            except:
+                post = '<could not parse>'
         try:
             cookies = pformat(self.COOKIES)
         except:
@@ -112,9 +130,21 @@
         # Populates self._post and self._files
         if self.method == 'POST':
             if self.environ.get('CONTENT_TYPE', '').startswith('multipart'):
-                header_dict = dict([(k, v) for k, v in self.environ.items() if k.startswith('HTTP_')])
-                header_dict['Content-Type'] = self.environ.get('CONTENT_TYPE', '')
-                self._post, self._files = http.parse_file_upload(header_dict, self.raw_post_data)
+                self._raw_post_data = ''
+                try:
+                    self._post, self._files = self.parse_file_upload(self.META, self.environ['wsgi.input'])
+                except:
+                    # An error occured while parsing POST data.  Since when
+                    # formatting the error the request handler might access
+                    # self.POST, set self._post and self._file to prevent
+                    # attempts to parse POST data again.
+                    self._post = http.QueryDict('')
+                    self._files = datastructures.MultiValueDict()
+                    # Mark that an error occured.  This allows self.__repr__ to
+                    # be explicit about it instead of simply representing an
+                    # empty POST
+                    self._post_parse_error = True
+                    raise
             else:
                 self._post, self._files = http.QueryDict(self.raw_post_data, encoding=self._encoding), datastructures.MultiValueDict()
         else:
@@ -163,7 +193,10 @@
             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
+            except (ValueError, TypeError):
+                # If CONTENT_LENGTH was empty string or not an integer, don't
+                # error out. We've also seen None passed in here (against all
+                # specs, but see ticket #8259), so we handle TypeError as well.
                 content_length = 0
             if content_length > 0:
                 safe_copyfileobj(self.environ['wsgi.input'], buf,
@@ -179,7 +212,7 @@
     REQUEST = property(_get_request)
     raw_post_data = property(_get_raw_post_data)
 
-class WSGIHandler(BaseHandler):
+class WSGIHandler(base.BaseHandler):
     initLock = Lock()
     request_class = WSGIRequest
 
@@ -195,7 +228,8 @@
                 self.load_middleware()
             self.initLock.release()
 
-        dispatcher.send(signal=signals.request_started)
+        set_script_prefix(base.get_script_name(environ))
+        signals.request_started.send(sender=self.__class__)
         try:
             try:
                 request = self.request_class(environ)
@@ -209,7 +243,7 @@
                     response = middleware_method(request, response)
                 response = self.apply_response_fixes(request, response)
         finally:
-            dispatcher.send(signal=signals.request_finished)
+            signals.request_finished.send(sender=self.__class__)
 
         try:
             status_text = STATUS_CODE_TEXT[response.status_code]