@@ -51,10 +51,8 @@ def __init__(self):
5151 # These are both absolute offsets into self._data:
5252 self ._start = 0
5353 self ._looked_at = 0
54- self ._looked_for = b""
55-
56- self ._delimiter = b"\n \r ?\n "
57- self ._delimiter_regex = delimiter_regex
54+ self ._looked_for = default_delimiter
55+ self ._looked_for_regex = delimiter_regex
5856
5957 def __bool__ (self ):
6058 return bool (len (self ))
@@ -89,22 +87,22 @@ def maybe_extract_at_most(self, count):
8987 self ._start += len (out )
9088 return out
9189
92- def maybe_extract_until_delimiter (self , delimiter = b" \n \r ? \n " ):
90+ def maybe_extract_until_next (self , needle ):
9391 # Returns extracted bytes on success (advancing offset), or None on
9492 # failure
95- if delimiter == self . _delimiter :
96- looked_at = max (self ._start , self ._looked_at - len (delimiter ) + 1 )
93+ if self . _looked_for == needle :
94+ looked_at = max (self ._start , self ._looked_at - len (needle ) + 1 )
9795 else :
9896 looked_at = self ._start
99- self ._delimiter = delimiter
97+ self ._looked_for = needle
10098 # re.compile operation is more expensive than just byte compare
101- if delimiter == default_delimiter :
102- self ._delimiter_regex = delimiter_regex
99+ if needle == default_delimiter :
100+ self ._looked_for_regex = delimiter_regex
103101 else :
104- self ._delimiter_regex = re .compile (delimiter , re .MULTILINE )
102+ self ._looked_for_regex = re .compile (needle , re .MULTILINE )
105103
106104 delimiter_match = next (
107- self ._delimiter_regex .finditer (self ._data , looked_at ), None
105+ self ._looked_for_regex .finditer (self ._data , looked_at ), None
108106 )
109107
110108 if delimiter_match is None :
@@ -119,25 +117,30 @@ def maybe_extract_until_delimiter(self, delimiter=b"\n\r?\n"):
119117
120118 return out
121119
120+ def _get_fields_delimiter (self , data , lines_delimiter_regex ):
121+ delimiter_match = next (lines_delimiter_regex .finditer (data ), None )
122+
123+ if delimiter_match is not None :
124+ begin , end = delimiter_match .span (0 )
125+ result = data [begin :end ]
126+ else :
127+ result = b"\r \n "
128+
129+ return bytes (result )
130+
122131 # HTTP/1.1 has a number of constructs where you keep reading lines until
123132 # you see a blank one. This does that, and then returns the lines.
124133 def maybe_extract_lines (self ):
125- if self ._data [self ._start : self ._start + 2 ] == b"\r \n " :
126- self ._start += 2
127- return []
128- elif self ._start < len (self ._data ) and self ._data [self ._start ] == b"\n " :
129- self ._start += 1
134+ start_chunk = self ._data [self ._start : self ._start + 2 ]
135+ if start_chunk in [b"\r \n " , b"\n " ]:
136+ self ._start += len (start_chunk )
130137 return []
131138 else :
132- data = self .maybe_extract_until_delimiter (b"\n \r ?\n " )
133-
139+ data = self .maybe_extract_until_next (default_delimiter )
134140 if data is None :
135141 return None
136142
137- lines = line_delimiter_regex .split (data )
138-
139- assert lines [- 2 ] == lines [- 1 ] == b""
140-
141- del lines [- 2 :]
143+ delimiter = self ._get_fields_delimiter (data , line_delimiter_regex )
144+ lines = data .rstrip (b"\r \n " ).split (delimiter )
142145
143146 return lines
0 commit comments