Fix for #11, with chunked encoding, closing chunk is sometimes sent twice
This commit is contained in:
@@ -270,7 +270,11 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||||||
|
|
||||||
if use_chunked[0]:
|
if use_chunked[0]:
|
||||||
## Write the chunked encoding
|
## Write the chunked encoding
|
||||||
|
if data:
|
||||||
towrite.append("%x\r\n%s\r\n" % (len(data), 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
|
||||||
|
@@ -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()
|
||||||
|
Reference in New Issue
Block a user