def _parse_arg_list(self): """Parse the supplied request parameters into a list of `(name, value)` tuples. """ fp = self.environ['wsgi.input'] # Avoid letting cgi.FieldStorage consume the input stream when the # request does not contain form data ctype = self.get_header('Content-Type') if ctype: ctype, options = cgi.parse_header(ctype) if ctype not in ('application/x-www-form-urlencoded', 'multipart/form-data'): fp = StringIO('') # Python 2.6 introduced a backwards incompatible change for # FieldStorage where QUERY_STRING is no longer ignored for POST # requests. We'll keep the pre 2.6 behaviour for now... if self.method == 'POST': qs_on_post = self.environ.pop('QUERY_STRING', '') try: fs = _FieldStorage(fp, environ=self.environ, keep_blank_values=True) except IOError as e: if is_client_disconnect_exception(e): raise HTTPBadRequest( _("Exception caught while reading request: %(msg)s", msg=exception_to_unicode(e))) raise if self.method == 'POST': self.environ['QUERY_STRING'] = qs_on_post def raise_if_null_bytes(value): if value and '\x00' in value: raise HTTPBadRequest(_("Invalid request arguments.")) args = [] for value in fs.list or (): name = value.name raise_if_null_bytes(name) try: if name is not None: name = unicode(name, 'utf-8') if value.filename: raise_if_null_bytes(value.filename) else: value = value.value raise_if_null_bytes(value) value = unicode(value, 'utf-8') except UnicodeDecodeError as e: raise HTTPBadRequest( _("Invalid encoding in form data: %(msg)s", msg=exception_to_unicode(e))) args.append((name, value)) return args
def _is_client_disconnected(self, e): if is_client_disconnect_exception(e): return True # Note that mod_wsgi raises an IOError with only a message # if the client disconnects if 'mod_wsgi.version' in self.environ: return e.args[0] in ('failed to write data', 'client connection closed', 'request data read error') return False
def write(self, data): """Write the given data to the response body. *data* **must** be a `str` string or an iterable instance which iterates `str` strings, encoded with the charset which has been specified in the ``'Content-Type'`` header or UTF-8 otherwise. Note that when the ``'Content-Length'`` header is specified, its value either corresponds to the length of *data*, or, if there are multiple calls to `write`, to the cumulative length of the *data* arguments. """ if not self._write: self.end_headers() try: chunk_size = self.CHUNK_SIZE bufsize = 0 buf = [] buf_append = buf.append if isinstance(data, basestring): data = [data] for chunk in data: if isinstance(chunk, unicode): raise ValueError("Can't send unicode content") if not chunk: continue bufsize += len(chunk) buf_append(chunk) if bufsize >= chunk_size: self._write(''.join(buf)) bufsize = 0 buf[:] = () if bufsize > 0: self._write(''.join(buf)) except IOError as e: if is_client_disconnect_exception(e): raise RequestDone raise