Skip to content

Commit

Permalink
Added back lazy-loading for POST and FILES to prevent consuming the s…
Browse files Browse the repository at this point in the history
…tream too early
  • Loading branch information
loic committed Jul 6, 2013
1 parent ee9ccc4 commit c209df8
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 17 deletions.
41 changes: 25 additions & 16 deletions django/core/handlers/wsgi.py
Expand Up @@ -73,7 +73,7 @@ def readline(self, size=None):


class WSGIRequest(http.HttpRequest):
_request_vars_loaded = False
_post_loaded = False

@property
def encoding(self):
Expand All @@ -82,10 +82,13 @@ def encoding(self):
@encoding.setter
def encoding(self, val):
self._encoding = val
if self._request_vars_loaded:
self._load_request_vars()

self._load_get()
self._post_loaded = False

def __init__(self, environ):
self.environ = environ

super(WSGIRequest, self).__init__()

script_name = base.get_script_name(environ)
Expand All @@ -99,13 +102,10 @@ def __init__(self, environ):
self.path_info = path_info
self.path = '%s/%s' % (script_name.rstrip('/'), path_info.lstrip('/'))

self.environ = environ
self.META = environ
self.META['SCRIPT_NAME'] = script_name
self.META['PATH_INFO'] = path_info

self.COOKIES = http.parse_cookie(self.environ.get('HTTP_COOKIE', ''))

self.method = environ['REQUEST_METHOD'].upper()

content_params = self._parse_content_type(self.META.get('CONTENT_TYPE', ''))[1]
Expand All @@ -124,24 +124,27 @@ def __init__(self, environ):
self._stream = LimitedStream(self.environ['wsgi.input'], content_length)
self._read_started = False

# `self.GET` and `self.COOKIES` get their data from the environ, so we can
# safely load them here. `self.POST`, `self.FILES` and `self.REQUEST` need
# to consume the stream so we lazy load them in `__getattribute__()`.
self._load_get()
self._load_cookies()

def __getattribute__(self, name):
_request_vars_loaded = super(WSGIRequest, self).__getattribute__('_request_vars_loaded')
if _request_vars_loaded is False and name in {'GET', 'POST', 'FILES', 'REQUEST'}:
self._request_vars_loaded = True
self._load_request_vars()
_post_loaded = super(WSGIRequest, self).__getattribute__('_post_loaded')
if _post_loaded is False and name in set(['POST', 'FILES', 'REQUEST']):
self._post_loaded = True
self._load_post_and_files()
self._load_request()
return super(WSGIRequest, self).__getattribute__(name)

def _load_request_vars(self):
def _load_get(self):
# The WSGI spec says 'QUERY_STRING' may be absent.
self.GET = http.QueryDict(self.environ.get('QUERY_STRING', ''), encoding=self.encoding)

# self.POST and self.FILES
self._load_post_and_files()

self.REQUEST = datastructures.MergeDict(self.POST, self.GET)

def _load_post_and_files(self):
"""Populate self.POST and self.FILES if the content-type is a form type"""

if self.method != 'POST':
self.POST, self.FILES = http.QueryDict('', encoding=self.encoding), MultiValueDict()
return
Expand Down Expand Up @@ -171,6 +174,12 @@ def _load_post_and_files(self):
else:
self.POST, self.FILES = http.QueryDict('', encoding=self.encoding), MultiValueDict()

def _load_request(self):
self.REQUEST = datastructures.MergeDict(self.POST, self.GET)

def _load_cookies(self):
self.COOKIES = http.parse_cookie(self.environ.get('HTTP_COOKIE', ''))

def _is_secure(self):
return 'wsgi.url_scheme' in self.environ and self.environ['wsgi.url_scheme'] == 'https'

Expand Down
2 changes: 1 addition & 1 deletion tests/requests/tests.py
Expand Up @@ -94,7 +94,7 @@ def test_wsgirequest_repr(self):
request.POST = {'post-key': 'post-value'}
request.COOKIES = {'post-key': 'post-value'}
request.META = {'post-key': 'post-value'}
request._request_vars_loaded = True
request._post_loaded = True
self.assertEqual(repr(request), str_prefix("<WSGIRequest\npath:/somepath/,\nGET:{%(_)s'get-key': %(_)s'get-value'},\nPOST:{%(_)s'post-key': %(_)s'post-value'},\nCOOKIES:{%(_)s'post-key': %(_)s'post-value'},\nMETA:{%(_)s'post-key': %(_)s'post-value'}>"))
self.assertEqual(build_request_repr(request), repr(request))
self.assertEqual(build_request_repr(request, path_override='/otherpath/', GET_override={'a': 'b'}, POST_override={'c': 'd'}, COOKIES_override={'e': 'f'}, META_override={'g': 'h'}),
Expand Down

0 comments on commit c209df8

Please sign in to comment.