-
Notifications
You must be signed in to change notification settings - Fork 3
Description
Hello,
Thank you for the work on stompman.
I was trying to pull content from a server that returns binary content in the body.
However, I found out the parser was cutting off the stream mid-string and was not respecting the content-length header.
I implemented a really dirty workaround to get around the problem but I think the whole parsing would need to be redone to parse the headers as they come and to use the content-length for body processing. Unfortunately, I don't really know how one would go about doing this change correctly and cleanly...
--
@DataClass(kw_only=True, slots=True)
class FrameParser:
_lines: deque[bytearray] = field(default_factory=deque, init=False)
_current_line: bytearray = field(default_factory=bytearray, init=False)
_previous_byte: bytes = field(default=b"", init=False)
_headers_processed: bool = field(default=False, init=False)
_binary: bool = field(default=False, init=False)
def parse_frames_from_chunk(self, chunk: bytes) -> Iterator[AnyClientFrame | AnyServerFrame]:
for byte in iter_bytes(chunk):
if byte == NULL and not self._binary:
if self._headers_processed:
self._lines.append(self._current_line)
yield parse_lines_into_frame(self._lines)
self._reset()
elif not self._headers_processed and byte == NEWLINE:
if self._current_line or self._lines:
if self._previous_byte == CARRIAGE:
self._current_line.pop()
self._headers_processed = not self._current_line # extra empty line after headers
if self._headers_processed:
# check if content-length
for l in self._lines:
header = parse_header(l)
if header and header[0] == "content-length":
self._binary = True
break
if not self._lines and bytes(self._current_line) not in COMMANDS_TO_FRAMES:
self._reset()
else:
self._lines.append(self._current_line)
self._current_line = bytearray()
else:
yield HeartbeatFrame()
else:
self._current_line += byte
self._previous_byte = byte
if self._previous_byte == NULL and len(self._current_line):
self._lines.append(self._current_line)
yield parse_lines_into_frame(self._lines)
self._reset()