Fix for #11, with chunked encoding, closing chunk is sometimes sent twice

This commit is contained in:
Ryan Williams
2010-02-17 09:16:01 -08:00
parent 60f14370d3
commit c8c0a94bd4
2 changed files with 34 additions and 3 deletions

View File

@@ -270,7 +270,11 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
if use_chunked[0]: if use_chunked[0]:
## Write the chunked encoding ## Write the chunked encoding
towrite.append("%x\r\n%s\r\n" % (len(data), data)) if data:
towrite.append("%x\r\n%s\r\n" % (len(data), data))
else:
# last-chunk format
towrite.append("0\r\n")
else: else:
towrite.append(data) towrite.append(data)
try: try:
@@ -315,16 +319,19 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
headers_set[1].append(('Content-Length', str(sum(map(len, result))))) headers_set[1].append(('Content-Length', str(sum(map(len, result)))))
towrite = [] towrite = []
towrite_size = 0 towrite_size = 0
just_written_size = 0
for data in result: for data in result:
towrite.append(data) towrite.append(data)
towrite_size += len(data) towrite_size += len(data)
if towrite_size >= self.minimum_chunk_size: if towrite_size >= self.minimum_chunk_size:
write(''.join(towrite)) write(''.join(towrite))
towrite = [] towrite = []
just_written_size = towrite_size
towrite_size = 0 towrite_size = 0
if towrite: if towrite:
just_written_size = towrite_size
write(''.join(towrite)) write(''.join(towrite))
if not headers_sent or use_chunked[0]: if not headers_sent or (use_chunked[0] and just_written_size):
write('') write('')
except Exception, e: except Exception, e:
self.close_connection = 1 self.close_connection = 1

View File

@@ -328,7 +328,7 @@ class TestHttpd(LimitedTestCase):
while chunklen: while chunklen:
chunks += 1 chunks += 1
chunk = fd.read(chunklen) chunk = fd.read(chunklen)
fd.readline() fd.readline() # CRLF
chunklen = int(fd.readline(), 16) chunklen = int(fd.readline(), 16)
self.assert_(chunks > 1) self.assert_(chunks > 1)
@@ -768,5 +768,29 @@ class TestHttpd(LimitedTestCase):
pass # TODO: should test with OpenSSL pass # TODO: should test with OpenSSL
greenthread.kill(g) greenthread.kill(g)
def test_zero_length_chunked_response(self):
def zero_chunked_app(env, start_response):
start_response('200 OK', [('Content-type', 'text/plain')])
yield ""
self.site.application = zero_chunked_app
sock = api.connect_tcp(
('localhost', self.port))
fd = sock.makefile()
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
fd.flush()
response = fd.read().split('\r\n')
headers = []
while True:
h = response.pop(0)
headers.append(h)
if h == '':
break
self.assert_('Transfer-Encoding: chunked' in ''.join(headers))
# should only be one chunk of zero size
self.assertEqual(response, ['0', ''])
if __name__ == '__main__': if __name__ == '__main__':
main() main()