Fixed #28440 -- Fixed WSGIServer hang on responses without a Content-Length.

Disabled keep-alive to fix the regression in
e6065c7b83.
This commit is contained in:
Tom 2017-07-28 15:10:13 +01:00 committed by Tim Graham
parent 2a4b331348
commit ac756f16c5
2 changed files with 31 additions and 19 deletions

View File

@ -135,13 +135,6 @@ class WSGIRequestHandler(simple_server.WSGIRequestHandler):
return super().get_environ() return super().get_environ()
def handle(self): def handle(self):
"""Handle multiple requests if necessary."""
self.close_connection = 1
self.handle_one_request()
while not self.close_connection:
self.handle_one_request()
def handle_one_request(self):
"""Copy of WSGIRequestHandler.handle() but with different ServerHandler""" """Copy of WSGIRequestHandler.handle() but with different ServerHandler"""
self.raw_requestline = self.rfile.readline(65537) self.raw_requestline = self.rfile.readline(65537)
if len(self.raw_requestline) > 65536: if len(self.raw_requestline) > 65536:

View File

@ -4,16 +4,21 @@ Tests for django.core.servers.
import errno import errno
import os import os
import socket import socket
import sys
from http.client import HTTPConnection from http.client import HTTPConnection
from urllib.error import HTTPError from urllib.error import HTTPError
from urllib.parse import urlencode from urllib.parse import urlencode
from urllib.request import urlopen from urllib.request import urlopen
from django.test import LiveServerTestCase, override_settings from django.test import LiveServerTestCase, override_settings
from django.test.utils import captured_stdout
from .models import Person from .models import Person
try:
from http.client import RemoteDisconnected
except ImportError: # Python 3.4
from http.client import BadStatusLine as RemoteDisconnected
TEST_ROOT = os.path.dirname(__file__) TEST_ROOT = os.path.dirname(__file__)
TEST_SETTINGS = { TEST_SETTINGS = {
'MEDIA_URL': '/media/', 'MEDIA_URL': '/media/',
@ -54,17 +59,31 @@ class LiveServerAddress(LiveServerBase):
class LiveServerViews(LiveServerBase): class LiveServerViews(LiveServerBase):
def test_protocol(self): def test_protocol(self):
"""Launched server serves with HTTP 1.1.""" """Launched server serves with HTTP 1.1."""
with captured_stdout() as debug_output: with self.urlopen('/example_view/') as f:
conn = HTTPConnection(LiveServerViews.server_thread.host, LiveServerViews.server_thread.port) self.assertEqual(f.version, 11)
@override_settings(MIDDLEWARE=[])
def test_closes_connection_without_content_length(self):
"""
The server doesn't support keep-alive because Python's http.server
module that it uses hangs if a Content-Length header isn't set (for
example, if CommonMiddleware isn't enabled or if the response is a
StreamingHttpResponse) (#28440 / https://bugs.python.org/issue31076).
"""
conn = HTTPConnection(LiveServerViews.server_thread.host, LiveServerViews.server_thread.port, timeout=1)
try:
conn.request('GET', '/example_view/', headers={'Connection': 'keep-alive'})
response = conn.getresponse().read()
conn.request('GET', '/example_view/', headers={'Connection': 'close'})
with self.assertRaises(RemoteDisconnected, msg='Server did not close the connection'):
try: try:
conn.set_debuglevel(1)
conn.request('GET', '/example_view/', headers={"Connection": "keep-alive"})
conn.getresponse().read()
conn.request('GET', '/example_view/', headers={"Connection": "close"})
conn.getresponse() conn.getresponse()
except ConnectionAbortedError:
if sys.platform == 'win32':
self.skipTest('Ignore nondeterministic failure on Windows.')
finally: finally:
conn.close() conn.close()
self.assertEqual(debug_output.getvalue().count("reply: 'HTTP/1.1 200 OK"), 2) self.assertEqual(response, b'example view')
def test_404(self): def test_404(self):
with self.assertRaises(HTTPError) as err: with self.assertRaises(HTTPError) as err: