# Buggy code
def feed_data(
    self, chunk: bytes, SEP: bytes = b"\r\n", CHUNK_EXT: bytes = b";"
) -> Tuple[bool, bytes]:
    # Read specified amount of bytes
    if self._type == ParseState.PARSE_LENGTH:
        required = self._length
        chunk_len = len(chunk)

        if required >= chunk_len:
            self._length = required - chunk_len
            self.payload.feed_data(chunk, chunk_len)
            if self._length == 0:
                self.payload.feed_eof()
                return True, b""
        else:
            self._length = 0
            self.payload.feed_data(chunk[:required], required)
            self.payload.feed_eof()
            return True, chunk[required:]

    # Chunked transfer encoding parser
    elif self._type == ParseState.PARSE_CHUNKED:
        if self._chunk_tail:
            chunk = self._chunk_tail + chunk
            self._chunk_tail = b""

        while chunk:
            # read next chunk size
            if self._chunk == ChunkState.PARSE_CHUNKED_SIZE:
                pos = chunk.find(SEP)
                if pos >= 0:
                    i = chunk.find(CHUNK_EXT, 0, pos)
                    if i >= 0:
                        size_b = chunk[:i]  # strip chunk-extensions
                    else:
                        size_b = chunk[:pos]

                    try:
                        size = int(bytes(size_b), 16)
                    except ValueError:
                        exc = TransferEncodingError(
                            chunk[:pos].decode("ascii", "surrogateescape")
                        )
                        self.payload.set_exception(exc)
                        raise exc from None

                    chunk = chunk[pos + 2 :]
                    if size == 0:  # eof marker
                        self._chunk = ChunkState.PARSE_MAYBE_TRAILERS
                    else:
                        self._chunk = ChunkState.PARSE_CHUNKED_CHUNK
                        self._chunk_size = size
                        self.payload.begin_http_chunk_receiving()
                else:
                    self._chunk_tail = chunk
                    return False, b""

            # read chunk and feed buffer
            if self._chunk == ChunkState.PARSE_CHUNKED_CHUNK:
                required = self._chunk_size
                chunk_len = len(chunk)

                if required > chunk_len:
                    self._chunk_size = required - chunk_len
                    self.payload.feed_data(chunk, chunk_len)
                    return False, b""
                else:
                    self._chunk_size = 0
                    self.payload.feed_data(chunk[:required], required)
                    chunk = chunk[required:]
                    self._chunk = ChunkState.PARSE_CHUNKED_CHUNK_EOF
                    self.payload.end_http_chunk_receiving()

            # toss the CRLF at the end of the chunk
            if self._chunk == ChunkState.PARSE_CHUNKED_CHUNK_EOF:
                if chunk[:2] == SEP:
                    chunk = chunk[2:]
                    self._chunk = ChunkState.PARSE_CHUNKED_SIZE
                else:
                    self._chunk_tail = chunk
                    return False, b""

            # if stream does not contain trailer, after 0\r\n
            # we should get another \r\n otherwise
            # trailers needs to be skiped until \r\n\r\n
            if self._chunk == ChunkState.PARSE_MAYBE_TRAILERS:
                if chunk[:2] == SEP:
                    # end of stream
                    self.payload.feed_eof()
                    return True, chunk[2:]
                else:
                    self._chunk = ChunkState.PARSE_TRAILERS

            # read and discard trailer up to the CRLF terminator
            if self._chunk == ChunkState.PARSE_TRAILERS:
                pos = chunk.find(SEP)
                if pos >= 0:
                    chunk = chunk[pos + 2 :]
                    self._chunk = ChunkState.PARSE_MAYBE_TRAILERS
                else:
                    self._chunk_tail = chunk
                    return False, b""

    # Read all bytes until eof
    elif self._type == ParseState.PARSE_UNTIL_EOF:
        self.payload.feed_data(chunk, len(chunk))

    return False, b""


# Traceback (aiohttp.http_exceptions.TransferEncodingError)
(False, b'')
(False, b'')
Traceback (most recent call last):
File "aiohttp-test.py", line 32, in <module>
print(repr(parser.feed_eof()))
File ".../lib/python3.6/site-packages/aiohttp/http_parser.py", line 575, in feed_eof
"Not enough data for satisfy transfer length header.")
aiohttp.http_exceptions.TransferEncodingError: 400, message='Not enough data for satisfy transfer length header.'

# Fixed code
def feed_data(
    self, chunk: bytes, SEP: bytes = b"\r\n", CHUNK_EXT: bytes = b";"
) -> Tuple[bool, bytes]:
    # Read specified amount of bytes
    if self._type == ParseState.PARSE_LENGTH:
        required = self._length
        chunk_len = len(chunk)

        if required >= chunk_len:
            self._length = required - chunk_len
            self.payload.feed_data(chunk, chunk_len)
            if self._length == 0:
                self.payload.feed_eof()
                return True, b""
        else:
            self._length = 0
            self.payload.feed_data(chunk[:required], required)
            self.payload.feed_eof()
            return True, chunk[required:]

    # Chunked transfer encoding parser
    elif self._type == ParseState.PARSE_CHUNKED:
        if self._chunk_tail:
            chunk = self._chunk_tail + chunk
            self._chunk_tail = b""

        while chunk:
            # read next chunk size
            if self._chunk == ChunkState.PARSE_CHUNKED_SIZE:
                pos = chunk.find(SEP)
                if pos >= 0:
                    i = chunk.find(CHUNK_EXT, 0, pos)
                    if i >= 0:
                        size_b = chunk[:i]  # strip chunk-extensions
                    else:
                        size_b = chunk[:pos]

                    try:
                        size = int(bytes(size_b), 16)
                    except ValueError:
                        exc = TransferEncodingError(
                            chunk[:pos].decode("ascii", "surrogateescape")
                        )
                        self.payload.set_exception(exc)
                        raise exc from None

                    chunk = chunk[pos + 2 :]
                    if size == 0:  # eof marker
                        self._chunk = ChunkState.PARSE_MAYBE_TRAILERS
                    else:
                        self._chunk = ChunkState.PARSE_CHUNKED_CHUNK
                        self._chunk_size = size
                        self.payload.begin_http_chunk_receiving()
                else:
                    self._chunk_tail = chunk
                    return False, b""

            # read chunk and feed buffer
            if self._chunk == ChunkState.PARSE_CHUNKED_CHUNK:
                required = self._chunk_size
                chunk_len = len(chunk)

                if required > chunk_len:
                    self._chunk_size = required - chunk_len
                    self.payload.feed_data(chunk, chunk_len)
                    return False, b""
                else:
                    self._chunk_size = 0
                    self.payload.feed_data(chunk[:required], required)
                    chunk = chunk[required:]
                    self._chunk = ChunkState.PARSE_CHUNKED_CHUNK_EOF
                    self.payload.end_http_chunk_receiving()

            # toss the CRLF at the end of the chunk
            if self._chunk == ChunkState.PARSE_CHUNKED_CHUNK_EOF:
                if chunk[:2] == SEP:
                    chunk = chunk[2:]
                    self._chunk = ChunkState.PARSE_CHUNKED_SIZE
                else:
                    self._chunk_tail = chunk
                    return False, b""

            # if stream does not contain trailer, after 0\r\n
            # we should get another \r\n otherwise
            # trailers needs to be skiped until \r\n\r\n
            if self._chunk == ChunkState.PARSE_MAYBE_TRAILERS:
                head = chunk[:2]
                if head == SEP:
                    # end of stream
                    self.payload.feed_eof()
                    return True, chunk[2:]
                # Both CR and LF, or only LF may not be received yet. It is
                # expected that CRLF or LF will be shown at the very first
                # byte next time, otherwise trailers should come. The last
                # CRLF which marks the end of response might not be
                # contained in the same TCP segment which delivered the
                # size indicator.
                if not head:
                    return False, b""
                if head == SEP[:1]:
                    self._chunk_tail = head
                    return False, b""
                self._chunk = ChunkState.PARSE_TRAILERS

            # read and discard trailer up to the CRLF terminator
            if self._chunk == ChunkState.PARSE_TRAILERS:
                pos = chunk.find(SEP)
                if pos >= 0:
                    chunk = chunk[pos + 2 :]
                    self._chunk = ChunkState.PARSE_MAYBE_TRAILERS
                else:
                    self._chunk_tail = chunk
                    return False, b""

    # Read all bytes until eof
    elif self._type == ParseState.PARSE_UNTIL_EOF:
        self.payload.feed_data(chunk, len(chunk))

    return False, b""