| 1157 | MULTIPART_BOUNDARY_PATT = re.compile(r'^multipart/.+?boundary=(.+?)(;|$)') |
| 1158 | |
| 1159 | class MPHeadersEaeter: |
| 1160 | end_headers_patt = re.compile(tob(r'(\r\n\r\n)|(\r(\n\r?)?)$')) |
| 1161 | |
| 1162 | def __init__(self): |
| 1163 | self.headers_end_expected = None |
| 1164 | self.eat_meth = self._eat_first_crlf_or_last_hyphens |
| 1165 | self._meth_map = { |
| 1166 | CR: self._eat_lf, |
| 1167 | HYPHEN: self._eat_last_hyphen |
| 1168 | } |
| 1169 | self.stopped = False |
| 1170 | |
| 1171 | def eat(self, chunk, base): |
| 1172 | pos = self.eat_meth(chunk, base) |
| 1173 | if pos is None: return |
| 1174 | if self.eat_meth != self._eat_headers: |
| 1175 | if self.stopped: |
| 1176 | raise StopMarkupException() |
| 1177 | base = pos |
| 1178 | self.eat_meth = self._eat_headers |
| 1179 | return self.eat(chunk, base) |
| 1180 | # found headers section end, reset eater |
| 1181 | self.eat_meth = self._eat_first_crlf_or_last_hyphens |
| 1182 | return pos |
| 1183 | |
| 1184 | def _eat_last_hyphen(self, chunk, base): |
| 1185 | chunk_start = chunk[base: base + 2] |
| 1186 | if not chunk_start: return |
| 1187 | if chunk_start == HYPHEN: |
| 1188 | self.stopped = True |
| 1189 | return base + 1 |
| 1190 | raise HTTPError(422, 'Last hyphen was expected, got (first 2 symbols slice): %s' % chunk_start) |
| 1191 | |
| 1192 | def _eat_lf(self, chunk, base): |
| 1193 | chunk_start = chunk[base: base + 1] |
| 1194 | if not chunk_start: return |
| 1195 | if chunk_start == LF: return base + 1 |
| 1196 | invalid_sequence = CR + chunk_start |
| 1197 | raise HTTPError(422, 'Malformed headers, found invalid sequence: %s' % invalid_sequence) |
| 1198 | |
| 1199 | def _eat_first_crlf_or_last_hyphens(self, chunk, base): |
| 1200 | chunk_start = chunk[base: base + 2] |
| 1201 | if not chunk_start: return |
| 1202 | if chunk_start == CRLF: return base + 2 |
| 1203 | if len(chunk_start) == 1: |
| 1204 | self.eat_meth = self._meth_map.get(chunk_start) |
| 1205 | elif chunk_start == HYPHENx2: |
| 1206 | self.stopped = True |
| 1207 | return base + 2 |
| 1208 | if self.eat_meth is None: |
| 1209 | raise HTTPError(422, 'Malformed headers, invalid section start: %s' % chunk_start) |
| 1210 | |
| 1211 | def _eat_headers(self, chunk, base): |
| 1212 | expected = self.headers_end_expected |
| 1213 | if expected is not None: |
| 1214 | expected_len = len(expected) |
| 1215 | chunk_start = chunk[base:expected_len] |
| 1216 | if chunk_start == expected: |