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:
parent
2a4b331348
commit
ac756f16c5
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
Loading…
Reference in New Issue