Fixed #30619 -- Made runserver --nothreading use single threaded WSGIServer.

Browsers often use multiple connections with Connection: keep-alive.
If --nothreading is specified, the WSGI server cannot accept new
connections until the old connection is closed, causing hangs.

Force Connection: close when --nothreading option is used.
This commit is contained in:
atsuo ishimoto 2019-07-07 00:43:59 +09:00 committed by Mariusz Felisiak
parent 00d4e6f8b5
commit a9c6ab0356
2 changed files with 40 additions and 0 deletions

View file

@ -9,7 +9,9 @@ from urllib.error import HTTPError
from urllib.parse import urlencode
from urllib.request import urlopen
from django.core.servers.basehttp import WSGIServer
from django.test import LiveServerTestCase, override_settings
from django.test.testcases import LiveServerThread, QuietWSGIRequestHandler
from .models import Person
@ -50,6 +52,15 @@ class LiveServerAddress(LiveServerBase):
self.assertEqual(self.live_server_url_test[0], self.live_server_url)
class LiveServerSingleThread(LiveServerThread):
def _create_server(self):
return WSGIServer((self.host, self.port), QuietWSGIRequestHandler, allow_reuse_address=False)
class SingleThreadLiveServerTestCase(LiveServerTestCase):
server_thread_class = LiveServerSingleThread
class LiveServerViews(LiveServerBase):
def test_protocol(self):
"""Launched server serves with HTTP 1.1."""
@ -162,6 +173,32 @@ class LiveServerViews(LiveServerBase):
self.assertIn(b"QUERY_STRING: 'q=%D1%82%D0%B5%D1%81%D1%82'", f.read())
@override_settings(ROOT_URLCONF='servers.urls')
class SingleTreadLiveServerViews(SingleThreadLiveServerTestCase):
available_apps = ['servers']
def test_closes_connection_with_content_length(self):
"""
Contrast to
LiveServerViews.test_keep_alive_on_connection_with_content_length().
Persistent connections require threading server.
"""
conn = HTTPConnection(
SingleTreadLiveServerViews.server_thread.host,
SingleTreadLiveServerViews.server_thread.port,
timeout=1,
)
try:
conn.request('GET', '/example_view/', headers={'Connection': 'keep-alive'})
response = conn.getresponse()
self.assertTrue(response.will_close)
self.assertEqual(response.read(), b'example view')
self.assertEqual(response.status, 200)
self.assertEqual(response.getheader('Connection'), 'close')
finally:
conn.close()
class LiveServerDatabase(LiveServerBase):
def test_fixtures_loaded(self):