def get_form( self, keep_blank_values: bool = False) -> Optional[RequestParameters]: self.parsed_form = RequestParameters() self.parsed_files = RequestParameters() content_type = self.headers.getone("content-type", DEFAULT_HTTP_CONTENT_TYPE) content_type, parameters = parse_content_header(content_type) try: if content_type == "application/x-www-form-urlencoded": self.parsed_form = RequestParameters( parse_qs( self.body.decode("utf-8"), keep_blank_values=keep_blank_values, )) elif content_type == "multipart/form-data": # TODO: Stream this instead of reading to/from memory boundary = parameters["boundary"].encode( # type: ignore "utf-8") # type: ignore self.parsed_form, self.parsed_files = parse_multipart_form( self.body, boundary) except Exception: error_logger.exception("Failed when parsing form") return self.parsed_form
def form(self): if self.parsed_form is None: self.parsed_form = RequestParameters() self.parsed_files = RequestParameters() content_type = self.headers.getone("content-type", DEFAULT_HTTP_CONTENT_TYPE) content_type, parameters = parse_content_header(content_type) try: if content_type == "application/x-www-form-urlencoded": self.parsed_form = RequestParameters( parse_qs(self.body.decode("utf-8"))) elif content_type == "multipart/form-data": # TODO: Stream this instead of reading to/from memory boundary = parameters["boundary"].encode("utf-8") self.parsed_form, self.parsed_files = parse_multipart_form( self.body, boundary) except Exception: error_logger.exception("Failed when parsing form") return self.parsed_form
def parse_multipart_form(body, boundary): """ Parse a request body and returns fields and files :param body: bytes request body :param boundary: bytes multipart boundary :return: fields (RequestParameters), files (RequestParameters) """ files = RequestParameters() fields = RequestParameters() form_parts = body.split(boundary) for form_part in form_parts[1:-1]: file_name = None content_type = "text/plain" content_charset = "utf-8" field_name = None line_index = 2 line_end_index = 0 while not line_end_index == -1: line_end_index = form_part.find(b"\r\n", line_index) form_line = form_part[line_index:line_end_index].decode("utf-8") line_index = line_end_index + 2 if not form_line: break colon_index = form_line.index(":") form_header_field = form_line[0:colon_index].lower() form_header_value, form_parameters = parse_content_header( form_line[colon_index + 2:]) if form_header_field == "content-disposition": field_name = form_parameters.get("name") file_name = form_parameters.get("filename") # non-ASCII filenames in RFC2231, "filename*" format if file_name is None and form_parameters.get("filename*"): encoding, _, value = email.utils.decode_rfc2231( form_parameters["filename*"]) file_name = unquote(value, encoding=encoding) elif form_header_field == "content-type": content_type = form_header_value content_charset = form_parameters.get("charset", "utf-8") if field_name: post_data = form_part[line_index:-4] if file_name is None: value = post_data.decode(content_charset) if field_name in fields: fields[field_name].append(value) else: fields[field_name] = [value] else: form_file = File(type=content_type, name=file_name, body=post_data) if field_name in files: files[field_name].append(form_file) else: files[field_name] = [form_file] else: logger.debug("Form-data field does not have a 'name' parameter " "in the Content-Disposition header") return fields, files
def test_parse_headers(input, expected): assert headers.parse_content_header(input) == expected