def parse_multipart_headers(iterable): """Parses multipart headers from an iterable that yields lines (including the trailing newline symbol). The iterable has to be newline terminated. The iterable will stop at the line where the headers ended so it can be further consumed. :param iterable: iterable of strings that are newline terminated """ def _line_parse(l): """Removes line ending characters and returns a tuple (`stripped_line`, `is_terminated`). """ if l[-2:] in ['\r\n']: return l[:-2], True elif l[-1:] in ['\r', '\n']: return l[:-1], True return l, False result = [] for line in iterable: line, line_terminated = _line_parse(safe_str(line)) if not line_terminated: raise ValueError('unexpected end of line in multipart header.') if not line: break elif line[0] in ' \t' and result: key, value = result[-1] result[-1] = (key, value + '\n ' + line[1:]) else: parts = line.split(':', 1) if len(parts) == 2: result.append((parts[0].strip(), parts[1].strip())) return HeadersDict(result)
def __init__(self, headers=None, status_code=None, content_type=None): super().__init__() if isinstance(headers, HeadersDict): self._headers = headers elif not headers: self._headers = HeadersDict() else: self._headers = HeadersDict(headers) if status_code is None: status_code = self.default_status_code if isinstance(status_code, int): self.status_code = status_code else: self.status = status_code if content_type is None: self._headers['Content-Type'] = self.default_content_type else: self._headers['Content-Type'] = content_type