Ticket #9886: 9886.diff
File 9886.diff, 12.1 KB (added by , 16 years ago) |
---|
-
django/core/handlers/modpython.py
=== modified file 'django/core/handlers/modpython.py'
36 36 # naughty, but also pretty harmless. 37 37 self.path_info = u'/' 38 38 self._post_parse_error = False 39 self._stream = self._req 40 self._read_started = False 39 41 40 42 def __repr__(self): 41 43 # Since this is called as part of error handling, we need to be very … … 75 77 # mod_python < 3.2.10 doesn't have req.is_https(). 76 78 return self._req.subprocess_env.get('HTTPS', '').lower() in ('on', '1') 77 79 78 def _load_post_and_files(self):79 "Populates self._post and self._files"80 if self.method != 'POST':81 self._post, self._files = http.QueryDict('', encoding=self._encoding), datastructures.MultiValueDict()82 return83 84 if 'content-type' in self._req.headers_in and self._req.headers_in['content-type'].startswith('multipart'):85 self._raw_post_data = ''86 try:87 self._post, self._files = self.parse_file_upload(self.META, self._req)88 except:89 # See django.core.handlers.wsgi.WSGIHandler for an explanation90 # of what's going on here.91 self._post = http.QueryDict('')92 self._files = datastructures.MultiValueDict()93 self._post_parse_error = True94 raise95 else:96 self._post, self._files = http.QueryDict(self.raw_post_data, encoding=self._encoding), datastructures.MultiValueDict()97 98 80 def _get_request(self): 99 81 if not hasattr(self, '_request'): 100 82 self._request = datastructures.MergeDict(self.POST, self.GET) … … 156 138 self._meta[key] = value 157 139 return self._meta 158 140 159 def _get_raw_post_data(self):160 try:161 return self._raw_post_data162 except AttributeError:163 self._raw_post_data = self._req.read()164 return self._raw_post_data165 166 141 def _get_method(self): 167 142 return self.META['REQUEST_METHOD'].upper() 168 143 … … 172 147 FILES = property(_get_files) 173 148 META = property(_get_meta) 174 149 REQUEST = property(_get_request) 175 raw_post_data = property(_get_raw_post_data)176 150 method = property(_get_method) 177 151 178 152 class ModPythonHandler(BaseHandler): -
django/core/handlers/wsgi.py
=== modified file 'django/core/handlers/wsgi.py'
4 4 from cStringIO import StringIO 5 5 except ImportError: 6 6 from StringIO import StringIO 7 import socket 7 8 8 9 from django import http 9 10 from django.core import signals … … 57 58 505: 'HTTP VERSION NOT SUPPORTED', 58 59 } 59 60 60 def safe_copyfileobj(fsrc, fdst, length=16*1024, size=0): 61 """ 62 A version of shutil.copyfileobj that will not read more than 'size' bytes. 63 This makes it safe from clients sending more than CONTENT_LENGTH bytes of 64 data in the body. 65 """ 66 if not size: 67 return 68 while size > 0: 69 buf = fsrc.read(min(length, size)) 70 if not buf: 71 break 72 fdst.write(buf) 73 size -= len(buf) 61 class LimitedInput(object): 62 BUF_SIZE = 64 * 2**10 63 64 def __init__(self, stream, limit, buf_size=None): 65 self.stream = stream 66 self.remaining = limit 67 self.buffer = '' 68 self.buf_size = buf_size or self.BUF_SIZE 69 70 def _read_limited(self, size=None): 71 if size is None or size > self.remaining: 72 size = self.remaining 73 if size == 0: 74 return '' 75 result = self.stream.read(size) 76 self.remaining -= len(result) 77 return result 78 79 def read(self, size=None): 80 if size is None: 81 result = self.buffer + self._read_limited() 82 self.buffer = '' 83 elif size < len(self.buffer): 84 result = self.buffer[:size] 85 self.buffer = self.buffer[size:] 86 else: # size >= len(self.buffer) 87 result = self.buffer + self._read_limited(size - len(self.buffer)) 88 self.buffer = '' 89 return result 90 91 def readline(self, size=None): 92 while '\n' not in self.buffer or \ 93 (size is not None and len(self.buffer) < size): 94 chunk = self._read_limited(self.buf_size) 95 if not chunk: 96 break 97 self.buffer += chunk 98 sio = StringIO(self.buffer) 99 line = sio.readline() 100 self.buffer = sio.read() 101 return line 74 102 75 103 class WSGIRequest(http.HttpRequest): 76 104 def __init__(self, environ): … … 93 121 self.META['SCRIPT_NAME'] = script_name 94 122 self.method = environ['REQUEST_METHOD'].upper() 95 123 self._post_parse_error = False 124 if isinstance(self.environ['wsgi.input'], socket._fileobject): 125 # Under development server 'wsgi.input' is an instance of 126 # socket._fileobject which hangs indefinitely on reading bytes past 127 # available count. To prevent this it's wrapped in LimitedInput 128 # that doesn't read past Content-Length bytes. 129 # 130 # This is not done for other kinds of inputs (like flup's FastCGI 131 # streams) beacuse they don't suffer from this problem and we can 132 # avoid using another wrapper with its own .read and .readline 133 # implementation. 134 try: 135 content_length = int(self.environ.get('CONTENT_LENGTH', 0)) 136 except (ValueError, TypeError): 137 content_length = 0 138 self._stream = LimitedInput(self.environ['wsgi.input'], content_length) 139 else: 140 self._stream = self.environ['wsgi.input'] 141 self._read_started = False 96 142 97 143 def __repr__(self): 98 144 # Since this is called as part of error handling, we need to be very … … 126 172 return 'wsgi.url_scheme' in self.environ \ 127 173 and self.environ['wsgi.url_scheme'] == 'https' 128 174 129 def _load_post_and_files(self):130 # Populates self._post and self._files131 if self.method == 'POST':132 if self.environ.get('CONTENT_TYPE', '').startswith('multipart'):133 self._raw_post_data = ''134 try:135 self._post, self._files = self.parse_file_upload(self.META, self.environ['wsgi.input'])136 except:137 # An error occured while parsing POST data. Since when138 # formatting the error the request handler might access139 # self.POST, set self._post and self._file to prevent140 # attempts to parse POST data again.141 self._post = http.QueryDict('')142 self._files = datastructures.MultiValueDict()143 # Mark that an error occured. This allows self.__repr__ to144 # be explicit about it instead of simply representing an145 # empty POST146 self._post_parse_error = True147 raise148 else:149 self._post, self._files = http.QueryDict(self.raw_post_data, encoding=self._encoding), datastructures.MultiValueDict()150 else:151 self._post, self._files = http.QueryDict('', encoding=self._encoding), datastructures.MultiValueDict()152 153 175 def _get_request(self): 154 176 if not hasattr(self, '_request'): 155 177 self._request = datastructures.MergeDict(self.POST, self.GET) … … 185 207 self._load_post_and_files() 186 208 return self._files 187 209 188 def _get_raw_post_data(self):189 try:190 return self._raw_post_data191 except AttributeError:192 buf = StringIO()193 try:194 # CONTENT_LENGTH might be absent if POST doesn't have content at all (lighttpd)195 content_length = int(self.environ.get('CONTENT_LENGTH', 0))196 except (ValueError, TypeError):197 # If CONTENT_LENGTH was empty string or not an integer, don't198 # error out. We've also seen None passed in here (against all199 # specs, but see ticket #8259), so we handle TypeError as well.200 content_length = 0201 if content_length > 0:202 safe_copyfileobj(self.environ['wsgi.input'], buf,203 size=content_length)204 self._raw_post_data = buf.getvalue()205 buf.close()206 return self._raw_post_data207 208 210 GET = property(_get_get, _set_get) 209 211 POST = property(_get_post, _set_post) 210 212 COOKIES = property(_get_cookies, _set_cookies) 211 213 FILES = property(_get_files) 212 214 REQUEST = property(_get_request) 213 raw_post_data = property(_get_raw_post_data)214 215 215 216 class WSGIHandler(base.BaseHandler): 216 217 initLock = Lock() -
django/http/__init__.py
=== modified file 'django/http/__init__.py'
5 5 from urllib import urlencode 6 6 from urlparse import urljoin 7 7 try: 8 from cStringIO import StringIO 9 except ImportError: 10 from StringIO import StringIO 11 try: 8 12 # The mod_python version is more efficient, so try importing it first. 9 13 from mod_python.util import parse_qsl 10 14 except ImportError: … … 123 127 parser = MultiPartParser(META, post_data, self.upload_handlers, self.encoding) 124 128 return parser.parse() 125 129 130 def _get_raw_post_data(self): 131 if not hasattr(self, '_raw_post_data'): 132 if self._read_started: 133 raise Exception("You cannot access raw_post_data after reading from request's data stream") 134 self._raw_post_data = self.read() 135 self._stream = StringIO(self._raw_post_data) 136 return self._raw_post_data 137 raw_post_data = property(_get_raw_post_data) 138 139 def _mark_post_parse_error(self): 140 self._post = QueryDict('') 141 self._files = MultiValueDict() 142 self._post_parse_error = True 143 144 def _load_post_and_files(self): 145 # Populates self._post and self._files 146 if self.method != 'POST': 147 self._post, self._files = QueryDict('', encoding=self._encoding), MultiValueDict() 148 return 149 if self._read_started: 150 self._mark_post_parse_error() 151 return 152 153 if self.META.get('CONTENT_TYPE', '').startswith('multipart'): 154 self._raw_post_data = '' 155 try: 156 self._post, self._files = self.parse_file_upload(self.META, self) 157 except: 158 # An error occured while parsing POST data. Since when 159 # formatting the error the request handler might access 160 # self.POST, set self._post and self._file to prevent 161 # attempts to parse POST data again. 162 # Mark that an error occured. This allows self.__repr__ to 163 # be explicit about it instead of simply representing an 164 # empty POST 165 self._mark_post_parse_error() 166 raise 167 else: 168 self._post, self._files = QueryDict(self.raw_post_data, encoding=self._encoding), MultiValueDict() 169 170 ## File-like and iterator interface. 171 ## 172 ## Expects self._stream to be set to an appropriate source of bytes by 173 ## a corresponding request subclass (WSGIRequest or ModPythonRequest). 174 ## Also when request data has already been read by request.POST or 175 ## request.raw_post_data self._stream pooints to a StringIO instance 176 ## containing that data. 177 178 def read(self, size=None): 179 self._read_started = True 180 return self._stream.read(size) 181 182 def readline(self, *args, **kwargs): 183 self._read_started = True 184 return self._stream.readline(*args, **kwargs) 185 186 def xreadlines(self): 187 while True: 188 buf = self.readline() 189 if not buf: 190 break 191 yield buf 192 __iter__ = xreadlines 193 194 def readlines(self): 195 return list(iter(self)) 196 126 197 class QueryDict(MultiValueDict): 127 198 """ 128 199 A specialized MultiValueDict that takes a query string when initialized.