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:
parent
00d4e6f8b5
commit
a9c6ab0356
|
@ -101,6 +101,9 @@ class ServerHandler(simple_server.ServerHandler):
|
|||
# connection.
|
||||
if 'Content-Length' not in self.headers:
|
||||
self.headers['Connection'] = 'close'
|
||||
# Persistent connections require threading server.
|
||||
elif not isinstance(self.request_handler.server, socketserver.ThreadingMixIn):
|
||||
self.headers['Connection'] = 'close'
|
||||
# Mark the connection for closing if it's set as such above or if the
|
||||
# application sent the header.
|
||||
if self.headers.get('Connection') == 'close':
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in New Issue