summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom <tom@tomforb.es>2017-07-28 15:10:13 +0100
committerTim Graham <timograham@gmail.com>2017-09-12 10:41:28 -0400
commitac756f16c5bbbe544ad82a8f3ab2eac6cccdb62e (patch)
tree00531ef5ce9c62fc14475ac25ac5a6393568d2aa
parent2a4b33134883b80870b4b23e59ccd3b6cb7266a3 (diff)
Fixed #28440 -- Fixed WSGIServer hang on responses without a Content-Length.
Disabled keep-alive to fix the regression in e6065c7b8363202c5eb13ba10c97a8c24d014b45.
-rw-r--r--django/core/servers/basehttp.py7
-rw-r--r--tests/servers/tests.py43
2 files changed, 31 insertions, 19 deletions
diff --git a/django/core/servers/basehttp.py b/django/core/servers/basehttp.py
index d725241170..f36317e216 100644
--- a/django/core/servers/basehttp.py
+++ b/django/core/servers/basehttp.py
@@ -135,13 +135,6 @@ class WSGIRequestHandler(simple_server.WSGIRequestHandler):
return super().get_environ()
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"""
self.raw_requestline = self.rfile.readline(65537)
if len(self.raw_requestline) > 65536:
diff --git a/tests/servers/tests.py b/tests/servers/tests.py
index 410d180596..ea64c246e2 100644
--- a/tests/servers/tests.py
+++ b/tests/servers/tests.py
@@ -4,16 +4,21 @@ Tests for django.core.servers.
import errno
import os
import socket
+import sys
from http.client import HTTPConnection
from urllib.error import HTTPError
from urllib.parse import urlencode
from urllib.request import urlopen
from django.test import LiveServerTestCase, override_settings
-from django.test.utils import captured_stdout
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_SETTINGS = {
'MEDIA_URL': '/media/',
@@ -54,17 +59,31 @@ class LiveServerAddress(LiveServerBase):
class LiveServerViews(LiveServerBase):
def test_protocol(self):
"""Launched server serves with HTTP 1.1."""
- with captured_stdout() as debug_output:
- conn = HTTPConnection(LiveServerViews.server_thread.host, LiveServerViews.server_thread.port)
- 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()
- finally:
- conn.close()
- self.assertEqual(debug_output.getvalue().count("reply: 'HTTP/1.1 200 OK"), 2)
+ with self.urlopen('/example_view/') as f:
+ 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:
+ conn.getresponse()
+ except ConnectionAbortedError:
+ if sys.platform == 'win32':
+ self.skipTest('Ignore nondeterministic failure on Windows.')
+ finally:
+ conn.close()
+ self.assertEqual(response, b'example view')
def test_404(self):
with self.assertRaises(HTTPError) as err: