@@ -51,10 +51,8 @@ def __init__(self):
51
51
# These are both absolute offsets into self._data:
52
52
self ._start = 0
53
53
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
58
56
59
57
def __bool__ (self ):
60
58
return bool (len (self ))
@@ -89,22 +87,22 @@ def maybe_extract_at_most(self, count):
89
87
self ._start += len (out )
90
88
return out
91
89
92
- def maybe_extract_until_delimiter (self , delimiter = b" \n \r ? \n " ):
90
+ def maybe_extract_until_next (self , needle ):
93
91
# Returns extracted bytes on success (advancing offset), or None on
94
92
# 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 )
97
95
else :
98
96
looked_at = self ._start
99
- self ._delimiter = delimiter
97
+ self ._looked_for = needle
100
98
# 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
103
101
else :
104
- self ._delimiter_regex = re .compile (delimiter , re .MULTILINE )
102
+ self ._looked_for_regex = re .compile (needle , re .MULTILINE )
105
103
106
104
delimiter_match = next (
107
- self ._delimiter_regex .finditer (self ._data , looked_at ), None
105
+ self ._looked_for_regex .finditer (self ._data , looked_at ), None
108
106
)
109
107
110
108
if delimiter_match is None :
@@ -119,25 +117,30 @@ def maybe_extract_until_delimiter(self, delimiter=b"\n\r?\n"):
119
117
120
118
return out
121
119
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
+
122
131
# HTTP/1.1 has a number of constructs where you keep reading lines until
123
132
# you see a blank one. This does that, and then returns the lines.
124
133
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 )
130
137
return []
131
138
else :
132
- data = self .maybe_extract_until_delimiter (b"\n \r ?\n " )
133
-
139
+ data = self .maybe_extract_until_next (default_delimiter )
134
140
if data is None :
135
141
return None
136
142
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 )
142
145
143
146
return lines
0 commit comments