2005-07-18 23:25:58 +08:00
|
|
|
"""
|
2011-05-29 05:28:52 +08:00
|
|
|
HTTP server that implements the Python WSGI protocol (PEP 333, rev 1.21).
|
2005-07-18 23:25:58 +08:00
|
|
|
|
2011-05-29 05:28:52 +08:00
|
|
|
Based on wsgiref.simple_server which is part of the standard library since 2.5.
|
2005-07-18 23:25:58 +08:00
|
|
|
|
|
|
|
This is a simple server for use in testing or debugging Django apps. It hasn't
|
2011-05-29 05:28:52 +08:00
|
|
|
been reviewed for security issues. DON'T USE IT FOR PRODUCTION USE!
|
2005-07-18 23:25:58 +08:00
|
|
|
"""
|
|
|
|
|
2012-08-16 19:01:16 +08:00
|
|
|
from __future__ import unicode_literals
|
|
|
|
|
2010-11-26 21:33:53 +08:00
|
|
|
import socket
|
2007-07-16 11:50:22 +08:00
|
|
|
import sys
|
2011-05-29 05:28:52 +08:00
|
|
|
from wsgiref import simple_server
|
2013-10-18 19:25:30 +08:00
|
|
|
from wsgiref.util import FileWrapper # NOQA: for backwards compatibility
|
2005-07-18 23:25:58 +08:00
|
|
|
|
2014-01-21 04:15:14 +08:00
|
|
|
from django.core.exceptions import ImproperlyConfigured
|
2010-01-04 20:16:09 +08:00
|
|
|
from django.core.management.color import color_style
|
2011-10-22 12:30:10 +08:00
|
|
|
from django.core.wsgi import get_wsgi_application
|
2014-01-21 04:15:14 +08:00
|
|
|
from django.utils import six
|
|
|
|
from django.utils.module_loading import import_string
|
2013-09-06 03:38:59 +08:00
|
|
|
from django.utils.six.moves import socketserver
|
2007-10-31 11:59:40 +08:00
|
|
|
|
2014-03-29 06:22:00 +08:00
|
|
|
__all__ = ('WSGIServer', 'WSGIRequestHandler')
|
2005-07-18 23:25:58 +08:00
|
|
|
|
|
|
|
|
2011-10-22 12:30:10 +08:00
|
|
|
def get_internal_wsgi_application():
|
|
|
|
"""
|
|
|
|
Loads and returns the WSGI application as configured by the user in
|
|
|
|
``settings.WSGI_APPLICATION``. With the default ``startproject`` layout,
|
|
|
|
this will be the ``application`` object in ``projectname/wsgi.py``.
|
|
|
|
|
|
|
|
This function, and the ``WSGI_APPLICATION`` setting itself, are only useful
|
|
|
|
for Django's internal servers (runserver, runfcgi); external WSGI servers
|
|
|
|
should just be configured to point to the correct application object
|
|
|
|
directly.
|
|
|
|
|
|
|
|
If settings.WSGI_APPLICATION is not set (is ``None``), we just return
|
|
|
|
whatever ``django.core.wsgi.get_wsgi_application`` returns.
|
|
|
|
|
|
|
|
"""
|
|
|
|
from django.conf import settings
|
|
|
|
app_path = getattr(settings, 'WSGI_APPLICATION')
|
|
|
|
if app_path is None:
|
|
|
|
return get_wsgi_application()
|
2013-02-03 05:58:02 +08:00
|
|
|
|
2014-01-21 04:15:14 +08:00
|
|
|
try:
|
|
|
|
return import_string(app_path)
|
|
|
|
except ImportError as e:
|
|
|
|
msg = (
|
|
|
|
"WSGI application '%(app_path)s' could not be loaded; "
|
|
|
|
"Error importing module: '%(exception)s'" % ({
|
|
|
|
'app_path': app_path,
|
|
|
|
'exception': e,
|
|
|
|
})
|
|
|
|
)
|
|
|
|
six.reraise(ImproperlyConfigured, ImproperlyConfigured(msg),
|
|
|
|
sys.exc_info()[2])
|
2011-10-22 12:30:10 +08:00
|
|
|
|
|
|
|
|
2011-05-29 05:28:52 +08:00
|
|
|
class WSGIServer(simple_server.WSGIServer, object):
|
2005-07-18 23:25:58 +08:00
|
|
|
"""BaseHTTPServer that implements the Python WSGI protocol"""
|
|
|
|
|
2013-04-28 16:47:07 +08:00
|
|
|
request_queue_size = 10
|
|
|
|
|
2010-11-26 21:33:53 +08:00
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
if kwargs.pop('ipv6', False):
|
|
|
|
self.address_family = socket.AF_INET6
|
2011-05-29 05:28:52 +08:00
|
|
|
super(WSGIServer, self).__init__(*args, **kwargs)
|
2010-11-26 21:33:53 +08:00
|
|
|
|
2005-07-18 23:25:58 +08:00
|
|
|
def server_bind(self):
|
|
|
|
"""Override server_bind to store the server name."""
|
2013-09-22 21:55:09 +08:00
|
|
|
super(WSGIServer, self).server_bind()
|
2005-07-18 23:25:58 +08:00
|
|
|
self.setup_environ()
|
|
|
|
|
|
|
|
|
2011-05-29 05:28:52 +08:00
|
|
|
class WSGIRequestHandler(simple_server.WSGIRequestHandler, object):
|
2005-07-27 01:49:49 +08:00
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
2010-01-04 20:16:09 +08:00
|
|
|
self.style = color_style()
|
2011-05-29 05:28:52 +08:00
|
|
|
super(WSGIRequestHandler, self).__init__(*args, **kwargs)
|
2005-07-27 01:49:49 +08:00
|
|
|
|
2012-11-04 03:07:56 +08:00
|
|
|
def address_string(self):
|
|
|
|
# Short-circuit parent method to not call socket.getfqdn
|
|
|
|
return self.client_address[0]
|
|
|
|
|
2005-07-27 01:49:49 +08:00
|
|
|
def log_message(self, format, *args):
|
2014-09-06 04:27:26 +08:00
|
|
|
|
|
|
|
msg = "[%s]" % self.log_date_time_string()
|
|
|
|
try:
|
|
|
|
msg += "%s\n" % (format % args)
|
|
|
|
except UnicodeDecodeError:
|
|
|
|
# e.g. accessing the server via SSL on Python 2
|
|
|
|
msg += "\n"
|
2010-01-04 20:16:09 +08:00
|
|
|
|
|
|
|
# Utilize terminal colors, if available
|
|
|
|
if args[1][0] == '2':
|
|
|
|
# Put 2XX first, since it should be the common case
|
|
|
|
msg = self.style.HTTP_SUCCESS(msg)
|
|
|
|
elif args[1][0] == '1':
|
|
|
|
msg = self.style.HTTP_INFO(msg)
|
2010-01-24 01:26:56 +08:00
|
|
|
elif args[1] == '304':
|
|
|
|
msg = self.style.HTTP_NOT_MODIFIED(msg)
|
2010-01-04 20:16:09 +08:00
|
|
|
elif args[1][0] == '3':
|
|
|
|
msg = self.style.HTTP_REDIRECT(msg)
|
|
|
|
elif args[1] == '404':
|
|
|
|
msg = self.style.HTTP_NOT_FOUND(msg)
|
|
|
|
elif args[1][0] == '4':
|
2014-09-06 04:27:26 +08:00
|
|
|
# 0x16 = Handshake, 0x03 = SSL 3.0 or TLS 1.x
|
|
|
|
if args[0].startswith(str('\x16\x03')):
|
|
|
|
msg = ("You're accessing the developement server over HTTPS, "
|
|
|
|
"but it only supports HTTP.\n")
|
2010-01-04 20:16:09 +08:00
|
|
|
msg = self.style.HTTP_BAD_REQUEST(msg)
|
|
|
|
else:
|
|
|
|
# Any 5XX, or any other response
|
|
|
|
msg = self.style.HTTP_SERVER_ERROR(msg)
|
|
|
|
|
|
|
|
sys.stderr.write(msg)
|
2005-07-27 01:49:49 +08:00
|
|
|
|
2010-10-20 09:33:24 +08:00
|
|
|
|
2011-06-17 21:08:36 +08:00
|
|
|
def run(addr, port, wsgi_handler, ipv6=False, threading=False):
|
2005-08-20 05:23:56 +08:00
|
|
|
server_address = (addr, port)
|
2011-06-17 21:08:36 +08:00
|
|
|
if threading:
|
2012-08-17 04:03:58 +08:00
|
|
|
httpd_cls = type(str('WSGIServer'), (socketserver.ThreadingMixIn, WSGIServer), {})
|
2011-06-17 21:08:36 +08:00
|
|
|
else:
|
|
|
|
httpd_cls = WSGIServer
|
|
|
|
httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)
|
2014-05-20 21:27:12 +08:00
|
|
|
if threading:
|
|
|
|
# ThreadingMixIn.daemon_threads indicates how threads will behave on an
|
|
|
|
# abrupt shutdown; like quitting the server by the user or restarting
|
|
|
|
# by the auto-reloader. True means the server will not wait for thread
|
|
|
|
# termination before it quits. This will make auto-reloader faster
|
|
|
|
# and will prevent the need to kill the server manually if a thread
|
|
|
|
# isn't terminating correctly.
|
|
|
|
httpd.daemon_threads = True
|
2005-07-18 23:25:58 +08:00
|
|
|
httpd.set_app(wsgi_handler)
|
|
|
|
httpd.serve_forever()
|