mirror of
https://github.com/frappe/gunicorn.git
synced 2026-01-14 11:09:11 +08:00
handle TE: chunked .
This commit is contained in:
parent
6f5b16ab91
commit
ccd24a15ae
@ -30,7 +30,10 @@ class HttpParser(object):
|
|||||||
self.version = None
|
self.version = None
|
||||||
self.method = None
|
self.method = None
|
||||||
self.path = None
|
self.path = None
|
||||||
self._content_len = None
|
self._content_len = None
|
||||||
|
self.start_offset = 0
|
||||||
|
self.chunk_size = 0
|
||||||
|
self._chunk_eof = False
|
||||||
|
|
||||||
def headers(self, headers, buf):
|
def headers(self, headers, buf):
|
||||||
""" take a string buff. It return
|
""" take a string buff. It return
|
||||||
@ -121,22 +124,39 @@ class HttpParser(object):
|
|||||||
|
|
||||||
def body_eof(self):
|
def body_eof(self):
|
||||||
"""do we have all the body ?"""
|
"""do we have all the body ?"""
|
||||||
#TODO : add chunk
|
if self.is_chunked and self._chunk_eof:
|
||||||
|
return True
|
||||||
if self._content_len == 0:
|
if self._content_len == 0:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def read_chunk(self, data):
|
def read_chunk(self, data):
|
||||||
dlen = len(data)
|
dlen = len(data)
|
||||||
i = data.find("\n")
|
if not self.start_offset:
|
||||||
if i != -1:
|
i = data.find("\n")
|
||||||
chunk = data[:i].strip().split(";", 1)
|
if i != -1:
|
||||||
chunk_size = int(line.pop(0), 16)
|
chunk = data[:i].strip().split(";", 1)
|
||||||
if chunk_size <= 0:
|
chunk_size = int(line.pop(0), 16)
|
||||||
self._chunk_eof = True
|
self.start_offset = i+1
|
||||||
return None
|
self.chunk_size = chunk_size
|
||||||
self.start_offset = i+1
|
else:
|
||||||
|
buf = self.data[self.start_offset:]
|
||||||
|
|
||||||
|
end_offset = chunk_size + 2
|
||||||
|
# we wait CRLF else return None
|
||||||
|
if len(buf) == end_offset:
|
||||||
|
if chunk_size <= 0:
|
||||||
|
self._chunk_eof = True
|
||||||
|
# we put data
|
||||||
|
return None, data[:end_offset]
|
||||||
|
self.chunk_size = 0
|
||||||
|
return buf[chunk_size:], data[:end_offset]
|
||||||
|
return None, data
|
||||||
|
|
||||||
|
def trailing_header(self, data):
|
||||||
|
i = data.find("\r\n\r\n")
|
||||||
|
return (i != -1)
|
||||||
|
|
||||||
def filter_body(self, data):
|
def filter_body(self, data):
|
||||||
""" filter body and return a tuple:
|
""" filter body and return a tuple:
|
||||||
body_chunk, new_buffer. They could be None.
|
body_chunk, new_buffer. They could be None.
|
||||||
@ -146,7 +166,9 @@ class HttpParser(object):
|
|||||||
dlen = len(data)
|
dlen = len(data)
|
||||||
chunk = None
|
chunk = None
|
||||||
if self.is_chunked:
|
if self.is_chunked:
|
||||||
pass
|
chunk, data = self.read_chunk(data)
|
||||||
|
if not chunk:
|
||||||
|
return None, data
|
||||||
else:
|
else:
|
||||||
if self._content_len > 0:
|
if self._content_len > 0:
|
||||||
nr = min(dlen, self._content_len)
|
nr = min(dlen, self._content_len)
|
||||||
|
|||||||
@ -102,10 +102,7 @@ class HTTPRequest(object):
|
|||||||
wsgi_input = StringIO.StringIO()
|
wsgi_input = StringIO.StringIO()
|
||||||
else:
|
else:
|
||||||
wsgi_input = TeeInput(self.socket, self.parser, buf)
|
wsgi_input = TeeInput(self.socket, self.parser, buf)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
environ = {
|
environ = {
|
||||||
"wsgi.url_scheme": 'http',
|
"wsgi.url_scheme": 'http',
|
||||||
"wsgi.input": wsgi_input,
|
"wsgi.input": wsgi_input,
|
||||||
@ -135,29 +132,6 @@ class HTTPRequest(object):
|
|||||||
environ[key] = value
|
environ[key] = value
|
||||||
return environ
|
return environ
|
||||||
|
|
||||||
|
|
||||||
def decode_chunked(self):
|
|
||||||
"""Decode the 'chunked' transfer coding."""
|
|
||||||
length = 0
|
|
||||||
data = StringIO.StringIO()
|
|
||||||
while True:
|
|
||||||
line = self.io.readuntil("\n").strip().split(";", 1)
|
|
||||||
chunk_size = int(line.pop(0), 16)
|
|
||||||
if chunk_size <= 0:
|
|
||||||
break
|
|
||||||
length += chunk_size
|
|
||||||
data.write(self.io.recv(chunk_size))
|
|
||||||
crlf = self.io.read(2)
|
|
||||||
if crlf != "\r\n":
|
|
||||||
raise RequestError((400, "Bad chunked transfer coding "
|
|
||||||
"(expected '\\r\\n', got %r)" % crlf))
|
|
||||||
return
|
|
||||||
|
|
||||||
# Grab any trailer headers
|
|
||||||
self.read_headers()
|
|
||||||
data.seek(0)
|
|
||||||
return data, str(length) or ""
|
|
||||||
|
|
||||||
def start_response(self, status, response_headers):
|
def start_response(self, status, response_headers):
|
||||||
self.response_status = status
|
self.response_status = status
|
||||||
for name, value in response_headers:
|
for name, value in response_headers:
|
||||||
|
|||||||
@ -69,7 +69,9 @@ class TeeInput(object):
|
|||||||
self._len = self._tmp_size()
|
self._len = self._tmp_size()
|
||||||
return self._len
|
return self._len
|
||||||
|
|
||||||
|
def flush(self):
|
||||||
|
self.tmp.flush()
|
||||||
|
|
||||||
def read(self, length=None):
|
def read(self, length=None):
|
||||||
""" read """
|
""" read """
|
||||||
if not self.socket:
|
if not self.socket:
|
||||||
@ -148,6 +150,13 @@ class TeeInput(object):
|
|||||||
""" here we wil fetch final trailers
|
""" here we wil fetch final trailers
|
||||||
if any."""
|
if any."""
|
||||||
if self.parser.body_eof():
|
if self.parser.body_eof():
|
||||||
|
# handle trailing headers
|
||||||
|
if self.parser.is_chunked:
|
||||||
|
while not self.parser.trailing_header(self.buf):
|
||||||
|
data = read_partial(self.socket, CHUNK_SIZE)
|
||||||
|
if not data: break
|
||||||
|
self.buf += data
|
||||||
|
del self.buf
|
||||||
self.socket = None
|
self.socket = None
|
||||||
|
|
||||||
def _tmp_size(self):
|
def _tmp_size(self):
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user