diff --git a/django/core/servers/basehttp.py b/django/core/servers/basehttp.py index 090a694c3e..8b03e9bb4d 100644 --- a/django/core/servers/basehttp.py +++ b/django/core/servers/basehttp.py @@ -9,10 +9,8 @@ been reviewed for security issues. DON'T USE IT FOR PRODUCTION USE! from __future__ import unicode_literals -from io import BytesIO import socket import sys -import traceback from wsgiref import simple_server from wsgiref.util import FileWrapper # NOQA: for backwards compatibility @@ -23,13 +21,7 @@ from django.utils import six from django.utils.module_loading import import_string from django.utils.six.moves import socketserver -__all__ = ('WSGIServer', 'WSGIRequestHandler', 'MAX_SOCKET_CHUNK_SIZE') - - -# If data is too large, socket will choke, so write chunks no larger than 32MB -# at a time. The rationale behind the 32MB can be found on Django's Trac: -# https://code.djangoproject.com/ticket/5596#comment:4 -MAX_SOCKET_CHUNK_SIZE = 32 * 1024 * 1024 # 32 MB +__all__ = ('WSGIServer', 'WSGIRequestHandler') def get_internal_wsgi_application(): @@ -66,46 +58,6 @@ def get_internal_wsgi_application(): sys.exc_info()[2]) -class ServerHandler(simple_server.ServerHandler, object): - error_status = str("500 INTERNAL SERVER ERROR") - - def write(self, data): - """'write()' callable as specified by PEP 3333""" - - assert isinstance(data, bytes), "write() argument must be bytestring" - - if not self.status: - raise AssertionError("write() before start_response()") - - elif not self.headers_sent: - # Before the first output, send the stored headers - self.bytes_sent = len(data) # make sure we know content-length - self.send_headers() - else: - self.bytes_sent += len(data) - - # XXX check Content-Length and truncate if too many bytes written? - data = BytesIO(data) - for chunk in iter(lambda: data.read(MAX_SOCKET_CHUNK_SIZE), b''): - self._write(chunk) - self._flush() - - def error_output(self, environ, start_response): - super(ServerHandler, self).error_output(environ, start_response) - return ['\n'.join(traceback.format_exception(*sys.exc_info()))] - - # Backport of http://hg.python.org/cpython/rev/d5af1b235dab. See #16241. - # This can be removed when support for Python <= 2.7.3 is deprecated. - def finish_response(self): - try: - if not self.result_is_file() or not self.sendfile(): - for data in self.result: - self.write(data) - self.finish_content() - finally: - self.close() - - class WSGIServer(simple_server.WSGIServer, object): """BaseHTTPServer that implements the Python WSGI protocol""" diff --git a/tests/builtin_server/tests.py b/tests/builtin_server/tests.py index ef215ccf97..2bfdfac66b 100644 --- a/tests/builtin_server/tests.py +++ b/tests/builtin_server/tests.py @@ -1,9 +1,56 @@ from __future__ import unicode_literals from io import BytesIO +import sys +import traceback from unittest import TestCase +from wsgiref import simple_server -from django.core.servers.basehttp import ServerHandler, MAX_SOCKET_CHUNK_SIZE + +# If data is too large, socket will choke, so write chunks no larger than 32MB +# at a time. The rationale behind the 32MB can be found on Django's Trac: +# https://code.djangoproject.com/ticket/5596#comment:4 +MAX_SOCKET_CHUNK_SIZE = 32 * 1024 * 1024 # 32 MB + + +class ServerHandler(simple_server.ServerHandler, object): + error_status = str("500 INTERNAL SERVER ERROR") + + def write(self, data): + """'write()' callable as specified by PEP 3333""" + + assert isinstance(data, bytes), "write() argument must be bytestring" + + if not self.status: + raise AssertionError("write() before start_response()") + + elif not self.headers_sent: + # Before the first output, send the stored headers + self.bytes_sent = len(data) # make sure we know content-length + self.send_headers() + else: + self.bytes_sent += len(data) + + # XXX check Content-Length and truncate if too many bytes written? + data = BytesIO(data) + for chunk in iter(lambda: data.read(MAX_SOCKET_CHUNK_SIZE), b''): + self._write(chunk) + self._flush() + + def error_output(self, environ, start_response): + super(ServerHandler, self).error_output(environ, start_response) + return ['\n'.join(traceback.format_exception(*sys.exc_info()))] + + # Backport of http://hg.python.org/cpython/rev/d5af1b235dab. See #16241. + # This can be removed when support for Python <= 2.7.3 is deprecated. + def finish_response(self): + try: + if not self.result_is_file() or not self.sendfile(): + for data in self.result: + self.write(data) + self.finish_content() + finally: + self.close() class DummyHandler(object):