import cgi


crlf = b'\r\n'


class ParseFailedException(Exception):
    pass


def parse_content_boundary(headers):
    content_type = headers.get('Content-Type')
    if not content_type:
        raise ParseFailedException()

    value, params = cgi.parse_header(content_type)

    if not value or value.lower() != 'multipart/form-data':
        raise ParseFailedException('Content-Type not multipart/form-data')

    boundary = params.get('boundary')
    if not boundary:
        raise ParseFailedException('Boundary not found')

    return boundary.encode('utf-8')


class StreamingFormDataParser(object):
    def __init__(self, expected_parts, headers):
        self.expected_parts = expected_parts
        self.headers = headers

        self.__separator = b'--'
        self._boundary = parse_content_boundary(headers)
        self._delimiter = self.__separator + self._boundary + crlf
        self._ender = \
            self.__separator + self._boundary + self.__separator + crlf

        self._state = None
        self._active_part = None

        self.__leftover_chunk = None
        self.__headers = (b'Content-Disposition', b'Content-Type')

    @property
    def active_part(self):
        return self._active_part

    def _unset_active_part(self):
        if self._active_part:
            self._active_part.finish()
        self._active_part = None

    def _set_active_part(self, part):
        self._unset_active_part()
        self._active_part = part

    def data_received(self, chunk):
        if not self.expected_parts:
            return

        if len(chunk) < len(self._boundary):
            raise ParseFailedException('Chunk size less than boundary')

        self._parse(chunk)

    def _part_for(self, name):
        for part in self.expected_parts:
            if part.name == name:
                return part

    def _is_header(self, line):
        for header in self.__headers:
            if line.startswith(header):
                return True
        return False

    def _parse(self, chunk):
        if self.__leftover_chunk:
            chunk = chunk + self.__leftover_chunk
            self.__leftover_chunk = None

        lines = chunk.split(crlf)

        for line in lines:
            if not line:
                continue
            elif self._is_boundary(line) or self._is_ender(line):
                self._unset_active_part()
            elif self._is_header(line):
                self._unset_active_part()

                value, params = cgi.parse_header(line.decode('utf-8'))
                if value.startswith('Content-Disposition'):
                    part = self._part_for(params['name'])
                    part.start()

                    self._set_active_part(part)
            else:
                if self.__separator in line:
                    index = line.index(self.__separator)
                    self._active_part.data_received(line[:index])

                    self.__leftover_chunk = line[index:]
                else:
                    self._active_part.data_received(line)

    def _is_boundary(self, line):
        return line == self.__separator + self._boundary

    def _is_ender(self, line):
        return line == self.__separator + self._boundary + self.__separator

@@ -598,24 +598,211 @@
 er(object):%0A
+    %22%22%22Parse multipart/form-data in chunks, one at a time.%0A%0A    This code is based off of the %60parse_multipart_form_data%60 function supplied%0A    in the %60tornado.httputil%60 module.%0A    %22%22%22%0A%0A
     def __in
@@ -921,33 +921,32 @@
 %0A%0A        self._
-_
 separator = b'--
@@ -1028,33 +1028,32 @@
 limiter = self._
-_
 separator + self
@@ -1108,25 +1108,24 @@
       self._
-_
 separator + 
@@ -1139,33 +1139,32 @@
 oundary + self._
-_
 separator + crlf
@@ -1165,16 +1165,145 @@
 + crlf%0A%0A
+        if self._boundary.startswith(b'%22') and self._boundary.endswith(b'%22'):%0A            self._boundary = self._boundary%5B1:-1%5D%0A%0A
         
@@ -2397,16 +2397,8 @@
 nk =
- chunk +
  sel
@@ -2415,16 +2415,24 @@
 er_chunk
+ + chunk
 %0A       
@@ -3079,25 +3079,24 @@
    if self._
-_
 separator in
@@ -3143,25 +3143,24 @@
 index(self._
-_
 separator)%0A 
@@ -3418,33 +3418,32 @@
 n line == self._
-_
 separator + self
@@ -3510,25 +3510,24 @@
 ne == self._
-_
 separator + 
@@ -3549,17 +3549,16 @@
 + self._
-_
 separato

prepend leftover chunk instead of appending