31
31
CARRIAGE_NEWLINE_CARRIAGE_NEWLINE = (CARRIAGE , NEWLINE , CARRIAGE , NEWLINE )
32
32
33
33
34
+ def iter_bytes (bytes_ : bytes ) -> tuple [bytes , ...]:
35
+ return struct .unpack (f"{ len (bytes_ )!s} c" , bytes_ )
36
+
37
+
38
+ VALID_COMMANDS = [list (iter_bytes (command )) for command in COMMANDS_TO_FRAMES ]
39
+
40
+
34
41
def dump_header (key : str , value : str ) -> bytes :
35
42
escaped_key = "" .join (ESCAPE_CHARS .get (char , char ) for char in key )
36
43
escaped_value = "" .join (ESCAPE_CHARS .get (char , char ) for char in value )
@@ -79,7 +86,7 @@ def parse_headers(buffer: list[bytes]) -> tuple[str, str] | None:
79
86
return (b"" .join (key_buffer ).decode (), b"" .join (value_buffer ).decode ()) if key_parsed else None
80
87
81
88
82
- def parse_lines_into_frame (lines : deque [list [bytes ]]) -> AnyClientFrame | AnyServerFrame | None :
89
+ def parse_lines_into_frame (lines : deque [list [bytes ]]) -> AnyClientFrame | AnyServerFrame :
83
90
command = b"" .join (lines .popleft ())
84
91
headers = {}
85
92
@@ -89,9 +96,7 @@ def parse_lines_into_frame(lines: deque[list[bytes]]) -> AnyClientFrame | AnySer
89
96
headers [header [0 ]] = header [1 ]
90
97
body = b"" .join (lines .popleft ()) if lines else b""
91
98
92
- if known_frame_type := COMMANDS_TO_FRAMES .get (command ):
93
- return known_frame_type (headers = cast (Any , headers ), body = body )
94
- return None
99
+ return COMMANDS_TO_FRAMES [command ](headers = cast (Any , headers ), body = body )
95
100
96
101
97
102
@dataclass
@@ -101,29 +106,33 @@ class Parser:
101
106
_previous_byte : bytes = field (default = b"" , init = False )
102
107
_headers_processed : bool = field (default = False , init = False )
103
108
109
+ def _reset (self ) -> None :
110
+ self ._headers_processed = False
111
+ self ._lines .clear ()
112
+ self ._current_line = []
113
+
104
114
def load_frames (self , raw_frames : bytes ) -> Iterator [AnyClientFrame | AnyServerFrame | HeartbeatFrame ]:
105
- buffer = deque (struct . unpack ( f" { len ( raw_frames )!s } c" , raw_frames ))
115
+ buffer = deque (iter_bytes ( raw_frames ))
106
116
while buffer :
107
117
byte = buffer .popleft ()
108
118
109
- if self ._headers_processed and byte == NULL :
110
- self ._lines .append (self ._current_line )
111
- if parsed_frame := parse_lines_into_frame (self ._lines ):
112
- yield parsed_frame
113
- self ._headers_processed = False
114
- self ._lines .clear ()
115
- self ._current_line = []
119
+ if byte == NULL :
120
+ if self ._headers_processed :
121
+ self ._lines .append (self ._current_line )
122
+ yield parse_lines_into_frame (self ._lines )
123
+ self ._reset ()
116
124
117
125
elif not self ._headers_processed and byte == NEWLINE :
118
126
if self ._current_line or self ._lines :
119
- if not self ._current_line : # extra empty line after headers
120
- self ._headers_processed = True
121
-
122
127
if self ._previous_byte == b"\r " :
123
128
self ._current_line .pop ()
129
+ self ._headers_processed = not self ._current_line # extra empty line after headers
124
130
125
- self ._lines .append (self ._current_line )
126
- self ._current_line = []
131
+ if not self ._lines and self ._current_line not in VALID_COMMANDS :
132
+ self ._reset ()
133
+ else :
134
+ self ._lines .append (self ._current_line )
135
+ self ._current_line = []
127
136
else :
128
137
yield HeartbeatFrame ()
129
138
0 commit comments