diff options
| author | Russell Keith-Magee <russell@keith-magee.com> | 2010-10-29 16:39:25 +0000 |
|---|---|---|
| committer | Russell Keith-Magee <russell@keith-magee.com> | 2010-10-29 16:39:25 +0000 |
| commit | 269e921756371bee6d35a967bc2ffe84d1ae39eb (patch) | |
| tree | fddacb8946dc19376e3425763c8aa4a63b32d00a /django/http | |
| parent | 3086b55b0e96b82a7f5f7a5c488f97ff5ed76420 (diff) | |
Fixed #9886 -- Added a file-like interface to HttpRequest. Thanks to Ivan Sagalaev for the suggestion and patch.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@14394 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django/http')
| -rw-r--r-- | django/http/__init__.py | 77 |
1 files changed, 74 insertions, 3 deletions
diff --git a/django/http/__init__.py b/django/http/__init__.py index 406c217b28..2fa683dbbb 100644 --- a/django/http/__init__.py +++ b/django/http/__init__.py @@ -7,6 +7,10 @@ from pprint import pformat from urllib import urlencode from urlparse import urljoin try: + from cStringIO import StringIO +except ImportError: + from StringIO import StringIO +try: # The mod_python version is more efficient, so try importing it first. from mod_python.util import parse_qsl except ImportError: @@ -132,6 +136,73 @@ class HttpRequest(object): parser = MultiPartParser(META, post_data, self.upload_handlers, self.encoding) return parser.parse() + def _get_raw_post_data(self): + if not hasattr(self, '_raw_post_data'): + if self._read_started: + raise Exception("You cannot access raw_post_data after reading from request's data stream") + self._raw_post_data = self.read() + self._stream = StringIO(self._raw_post_data) + return self._raw_post_data + raw_post_data = property(_get_raw_post_data) + + def _mark_post_parse_error(self): + self._post = QueryDict('') + self._files = MultiValueDict() + self._post_parse_error = True + + def _load_post_and_files(self): + # Populates self._post and self._files + if self.method != 'POST': + self._post, self._files = QueryDict('', encoding=self._encoding), MultiValueDict() + return + if self._read_started: + self._mark_post_parse_error() + return + + if self.META.get('CONTENT_TYPE', '').startswith('multipart'): + self._raw_post_data = '' + try: + self._post, self._files = self.parse_file_upload(self.META, self) + 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. + # Mark that an error occured. This allows self.__repr__ to + # be explicit about it instead of simply representing an + # empty POST + self._mark_post_parse_error() + raise + else: + self._post, self._files = QueryDict(self.raw_post_data, encoding=self._encoding), MultiValueDict() + + ## File-like and iterator interface. + ## + ## Expects self._stream to be set to an appropriate source of bytes by + ## a corresponding request subclass (WSGIRequest or ModPythonRequest). + ## Also when request data has already been read by request.POST or + ## request.raw_post_data, self._stream points to a StringIO instance + ## containing that data. + + def read(self, *args, **kwargs): + self._read_started = True + return self._stream.read(*args, **kwargs) + + def readline(self, *args, **kwargs): + self._read_started = True + return self._stream.readline(*args, **kwargs) + + def xreadlines(self): + while True: + buf = self.readline() + if not buf: + break + yield buf + __iter__ = xreadlines + + def readlines(self): + return list(iter(self)) + class QueryDict(MultiValueDict): """ A specialized MultiValueDict that takes a query string when initialized. @@ -198,7 +269,7 @@ class QueryDict(MultiValueDict): for key, value in dict.items(self): dict.__setitem__(result, copy.deepcopy(key, memo), copy.deepcopy(value, memo)) return result - + def setlist(self, key, list_): self._assert_mutable() key = str_to_unicode(key, self.encoding) @@ -385,7 +456,7 @@ class HttpResponse(object): """ Sets a cookie. - ``expires`` can be a string in the correct format or a + ``expires`` can be a string in the correct format or a ``datetime.datetime`` object in UTC. If ``expires`` is a datetime object then ``max_age`` will be calculated. """ @@ -407,7 +478,7 @@ class HttpResponse(object): # IE requires expires, so set it if hasn't been already. if not expires: self.cookies[key]['expires'] = cookie_date(time.time() + - max_age) + max_age) if path is not None: self.cookies[key]['path'] = path if domain is not None: |
