From 6df6e89cbc185c47e83eb59a8ebc431f558c7dc4 Mon Sep 17 00:00:00 2001 From: benoitc Date: Fri, 26 Feb 2010 14:05:35 +0100 Subject: [PATCH] allow gunicorn to send chunked response (if Transfer-Encoding == chunked) --- gunicorn/http/request.py | 4 ++++ gunicorn/http/response.py | 10 +++++++++- gunicorn/util.py | 18 ++++++++++++------ 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/gunicorn/http/request.py b/gunicorn/http/request.py index 947c6973..6d3b1da5 100644 --- a/gunicorn/http/request.py +++ b/gunicorn/http/request.py @@ -48,6 +48,7 @@ class Request(object): self.parser = Parser() self.start_response_called = False self.log = logging.getLogger(__name__) + self.response_chunked = False def read(self): environ = {} @@ -154,6 +155,9 @@ class Request(object): self.response_status = status for name, value in response_headers: name = normalize_name(name) + if name == "Transfer-Encoding": + if value.lower() == "chunked": + self.response_chunked = True if not isinstance(value, basestring): value = str(value) self.response_headers.append((name, value.strip())) diff --git a/gunicorn/http/response.py b/gunicorn/http/response.py index cad1dce1..f2813e9e 100644 --- a/gunicorn/http/response.py +++ b/gunicorn/http/response.py @@ -14,6 +14,7 @@ class Response(object): self.headers = req.response_headers or [] self.status = req.response_status self.SERVER_VERSION = req.SERVER_VERSION + self.chunked = req.response_chunked def send(self): # send headers @@ -31,8 +32,15 @@ class Response(object): write(self.sock, "%s\r\n" % "".join(resp_head)) + last_chunk = None for chunk in list(self.data): - write(self.sock, chunk) + write(self.sock, chunk, self.chunked) + last_chunk = chunk + + if self.chunked: + if last_chunk or last_chunk is None: + # send last chunk + write_chunk("") close(self.sock) diff --git a/gunicorn/util.py b/gunicorn/util.py index f500bb9f..fa0f4b5f 100644 --- a/gunicorn/util.py +++ b/gunicorn/util.py @@ -94,23 +94,29 @@ def close(sock): def read_partial(sock, length): return sock.recv(length) -def write(sock, data): +def write_chunk(sock, data): + chunk = "".join(("%X\r\n" % len(data), data, "\r\n")) + sock.sendall(chunk) + +def write(sock, data, chunked=False): + if chunked: + return write_chunk(sock, data) sock.sendall(data) -def write_nonblock(sock, data): +def write_nonblock(sock, data, chunked=False): timeout = sock.gettimeout() if timeout != 0.0: try: sock.setblocking(0) - return write(sock, data) + return write(sock, data, chunked) finally: sock.setblocking(1) else: - return write(sock, data) + return write(sock, data, chunked) -def writelines(sock, lines): +def writelines(sock, lines, chunked=False): for line in list(lines): - write(sock, line) + write(sock, line, chunked) def write_error(sock, msg): html = textwrap.dedent("""\