mirror of
https://github.com/django/django.git
synced 2025-03-31 19:46:42 +00:00
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.
|
# connection.
|
||||||
if 'Content-Length' not in self.headers:
|
if 'Content-Length' not in self.headers:
|
||||||
self.headers['Connection'] = 'close'
|
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
|
# Mark the connection for closing if it's set as such above or if the
|
||||||
# application sent the header.
|
# application sent the header.
|
||||||
if self.headers.get('Connection') == 'close':
|
if self.headers.get('Connection') == 'close':
|
||||||
|
@ -9,7 +9,9 @@ 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.core.servers.basehttp import WSGIServer
|
||||||
from django.test import LiveServerTestCase, override_settings
|
from django.test import LiveServerTestCase, override_settings
|
||||||
|
from django.test.testcases import LiveServerThread, QuietWSGIRequestHandler
|
||||||
|
|
||||||
from .models import Person
|
from .models import Person
|
||||||
|
|
||||||
@ -50,6 +52,15 @@ class LiveServerAddress(LiveServerBase):
|
|||||||
self.assertEqual(self.live_server_url_test[0], self.live_server_url)
|
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):
|
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."""
|
||||||
@ -162,6 +173,32 @@ class LiveServerViews(LiveServerBase):
|
|||||||
self.assertIn(b"QUERY_STRING: 'q=%D1%82%D0%B5%D1%81%D1%82'", f.read())
|
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):
|
class LiveServerDatabase(LiveServerBase):
|
||||||
|
|
||||||
def test_fixtures_loaded(self):
|
def test_fixtures_loaded(self):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user