Skip to content

Commit 04efb25

Browse files
committed
optimize chunked encoding parsing
1 parent 5bab1e1 commit 04efb25

2 files changed

Lines changed: 39 additions & 48 deletions

File tree

tremolo/lib/http_protocol.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -423,11 +423,6 @@ async def _handle_keepalive(self):
423423
self.close()
424424
return
425425

426-
if b'transfer-encoding' in self.request.headers:
427-
self.request.clear()
428-
self.close()
429-
return
430-
431426
self.events['request'] = self.loop.create_future()
432427

433428
self.add_task(self.app.create_task(
@@ -464,7 +459,7 @@ def connection_lost(self, _):
464459
self.print_exception(exc, 'connection_lost')
465460

466461
while self.queue:
467-
self.queue.pop().clear()
462+
self.queue.pop().queue.clear()
468463

469464
self.request = None
470465

tremolo/lib/http_request.py

Lines changed: 38 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -193,68 +193,64 @@ async def stream(self, timeout=None, raw=False):
193193
agen = super().recv(timeout)
194194
paused = False
195195
bytes_unread = 0
196+
chunk_size = -1
196197

197198
while True:
198199
if not paused:
199-
try:
200-
buf.extend(await agen.__anext__())
201-
except StopAsyncIteration as exc:
202-
if b'\r\n\r\n' not in buf:
203-
raise BadRequest(
204-
'bad chunked encoding: incomplete read'
205-
) from exc
200+
buf.extend(await agen.__anext__())
206201

207202
if bytes_unread > 2:
208203
data = bytes(buf[:bytes_unread - 2])
209-
210204
yield data
211-
del buf[:bytes_unread - 2]
212205

206+
del buf[:bytes_unread - 2]
213207
bytes_unread -= len(data)
214208

215-
if bytes_unread > 2:
216-
continue
217-
218-
paused = True
219-
else:
220-
# bytes_unread should only be either 0 or 2 at this point
221-
i = buf.find(b'\r\n', bytes_unread)
222-
223-
if i == -1:
224-
if len(buf) > 64:
225-
raise BadRequest(
226-
'bad chunked encoding: no chunk size'
227-
)
209+
paused = False
210+
continue
228211

212+
if bytes_unread == 2:
213+
if len(buf) < 2:
229214
paused = False
230215
continue
231216

232-
try:
233-
chunk_size = parse_int(
234-
buf[bytes_unread:i].split(b';', 1)[0], 16
235-
)
236-
except ValueError as exc:
237-
raise BadRequest('bad chunked encoding') from exc
217+
if not buf.startswith(b'\r\n'):
218+
raise BadRequest('bad chunked encoding: '
219+
'invalid chunk terminator')
238220

239-
data = bytes(buf[i + 2:i + 2 + chunk_size])
240-
bytes_unread = chunk_size - len(data) + 2
221+
if chunk_size == 0:
222+
if self.server.options['experimental']:
223+
self.server.queue[0].queue.appendleft(buf[2:])
224+
else:
225+
self.http_keepalive = False
241226

242-
if bytes_unread > 2:
243-
paused = False
244227
del buf[:]
245-
else:
246-
paused = True
247-
del buf[:i + 2 + chunk_size]
228+
break
248229

249-
if bytes_unread == 2 and not b'\r\n'.startswith(buf[:2]):
250-
raise BadRequest(
251-
'bad chunked encoding: invalid chunk terminator'
252-
)
230+
# bytes_unread should only be either 0 or 2 at this point
231+
i = buf.find(b'\r\n', bytes_unread)
253232

254-
if chunk_size <= 0:
255-
break
233+
if i == -1:
234+
if len(buf) > 64:
235+
raise BadRequest('bad chunked encoding: no chunk size')
256236

257-
yield data
237+
paused = False
238+
continue
239+
240+
try:
241+
chunk_size = parse_int(
242+
buf[bytes_unread:i].split(b';', 1)[0], 16
243+
)
244+
except ValueError as exc:
245+
raise BadRequest('bad chunked encoding') from exc
246+
247+
data = bytes(buf[i + 2:i + 2 + chunk_size])
248+
bytes_unread = chunk_size - len(data) + 2
249+
250+
del buf[:i + 2 + chunk_size]
251+
252+
yield data
253+
paused = True
258254
else:
259255
if (self.content_length >
260256
self.server.options['client_max_body_size']):

0 commit comments

Comments
 (0)