http server that implements the python wsgi protocol pep 333 rev 1 21 based on wsgiref simpleserver which is part of the standard library since 2 5 this is a simple server for use in testing or debugging django apps it hasn t been reviewed for security issues don t use it for production use load and return the wsgi application as configured by the user in settings wsgiapplication with the default startproject layout this will be the application object in projectnamewsgi py this function and the wsgiapplication setting itself are only useful for django s internal server runserver external wsgi servers should just be configured to point to the correct application object directly if settings wsgiapplication is not set is none return whatever django core wsgi getwsgiapplication returns basehttpserver that implements the python wsgi protocol requestqueuesize 10 def initself args ipv6false allowreuseaddresstrue kwargs if ipv6 self addressfamily socket afinet6 self allowreuseaddress allowreuseaddress super initargs kwargs def handleerrorself request clientaddress if isbrokenpipeerror logger info broken pipe from s clientaddress else super handleerrorrequest clientaddress class threadedwsgiserversocketserver threadingmixin wsgiserver socketserver threadingmixin processrequest passes this method as the target to a new thread object override this thread s database connections with the ones provided by the parent thread used for mocking in tests use a limitedstream so that unread request data will be ignored at the end of the request wsgirequest uses a limitedstream but it shouldn t discard the data since the upstream servers usually do this this fix applies only for testserverrunserver http1 1 requires support for persistent connections send close if the content length is unknown to prevent clients from reusing the connection persistent connections require threading server mark the connection for closing if it s set as such above or if the application sent the header don t call self finishcontent as if the headers have not been sent and contentlength isn t set it ll default to 0 which will prevent omission of the contentlength header with head requests as permitted by rfc 9110 section 9 3 2 instead send the headers if not sent yet shortcircuit parent method to not call socket getfqdn 0x16 handshake 0x03 ssl 3 0 or tls 1 x strip all headers with underscores in the name before constructing the wsgi environ this prevents headerspoofing based on ambiguity between underscores and dashes both normalized to underscores in wsgi env vars nginx and apache 2 4 both do this as well copy of wsgirequesthandler handle but with different serverhandler self rawrequestline self rfile readline65537 if lenself rawrequestline 65536 self requestline self requestversion self command self senderror414 return if not self parserequest an error code has been sent just exit return handler serverhandler self rfile self wfile self getstderr self getenviron handler requesthandler self backpointer for logging connection closing handler runself server getapp def run addr port wsgihandler ipv6false threadingfalse onbindnone serverclswsgiserver serveraddress addr port if threading httpdcls typewsgiserver socketserver threadingmixin servercls else httpdcls servercls httpd httpdclsserveraddress wsgirequesthandler ipv6ipv6 if onbind is not none onbindgetattrhttpd serverport port if threading threadingmixin daemonthreads indicates how threads will behave on an abrupt shutdown like quitting the server by the user or restarting by the autoreloader true means the server will not wait for thread termination before it quits this will make autoreloader faster and will prevent the need to kill the server manually if a thread isn t terminating correctly httpd daemonthreads true httpd setappwsgihandler httpd serveforever load and return 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 server runserver external wsgi servers should just be configured to point to the correct application object directly if settings wsgi_application is not set is none return whatever django core wsgi get_wsgi_application returns basehttpserver that implements the python wsgi protocol a threaded version of the wsgiserver socketserver threadingmixin process_request passes this method as the target to a new thread object override this thread s database connections with the ones provided by the parent thread used for mocking in tests use a limitedstream so that unread request data will be ignored at the end of the request wsgirequest uses a limitedstream but it shouldn t discard the data since the upstream servers usually do this this fix applies only for testserver runserver http 1 1 requires support for persistent connections send close if the content length is unknown to prevent clients from reusing the connection persistent connections require threading server mark the connection for closing if it s set as such above or if the application sent the header consume iterator don t call self finish_content as if the headers have not been sent and content length isn t set it ll default to 0 which will prevent omission of the content length header with head requests as permitted by rfc 9110 section 9 3 2 instead send the headers if not sent yet short circuit parent method to not call socket getfqdn 0x16 handshake 0x03 ssl 3 0 or tls 1 x strip all headers with underscores in the name before constructing the wsgi environ this prevents header spoofing based on ambiguity between underscores and dashes both normalized to underscores in wsgi env vars nginx and apache 2 4 both do this as well copy of wsgirequesthandler handle but with different serverhandler an error code has been sent just exit backpointer for logging connection closing 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
import logging
import socket
import socketserver
import sys
from collections import deque
from wsgiref import simple_server

from django.core.exceptions import ImproperlyConfigured
from django.core.handlers.wsgi import LimitedStream
from django.core.wsgi import get_wsgi_application
from django.db import connections
from django.utils.module_loading import import_string

__all__ = ("WSGIServer", "WSGIRequestHandler")

logger = logging.getLogger("django.server")


def get_internal_wsgi_application():
    
    from django.conf import settings

    app_path = getattr(settings, "WSGI_APPLICATION")
    if app_path is None:
        return get_wsgi_application()

    try:
        return import_string(app_path)
    except ImportError as err:
        raise ImproperlyConfigured(
            "WSGI application '%s' could not be loaded; "
            "Error importing module." % app_path
        ) from err


def is_broken_pipe_error():
    exc_type, _, _ = sys.exc_info()
    return issubclass(
        exc_type,
        (
            BrokenPipeError,
            ConnectionAbortedError,
            ConnectionResetError,
        ),
    )


class WSGIServer(simple_server.WSGIServer):
    

    request_queue_size = 10

    def __init__(self, *args, ipv6=False, allow_reuse_address=True, **kwargs):
        if ipv6:
            self.address_family = socket.AF_INET6
        self.allow_reuse_address = allow_reuse_address
        super().__init__(*args, **kwargs)

    def handle_error(self, request, client_address):
        if is_broken_pipe_error():
            logger.info("- Broken pipe from %s", client_address)
        else:
            super().handle_error(request, client_address)


class ThreadedWSGIServer(socketserver.ThreadingMixIn, WSGIServer):
    

    daemon_threads = True

    def __init__(self, *args, connections_override=None, **kwargs):
        super().__init__(*args, **kwargs)
        self.connections_override = connections_override

    
    
    def process_request_thread(self, request, client_address):
        if self.connections_override:
            
            
            for alias, conn in self.connections_override.items():
                connections[alias] = conn
        super().process_request_thread(request, client_address)

    def _close_connections(self):
        
        connections.close_all()

    def close_request(self, request):
        self._close_connections()
        super().close_request(request)


class ServerHandler(simple_server.ServerHandler):
    http_version = "1.1"

    def __init__(self, stdin, stdout, stderr, environ, **kwargs):
        
        try:
            content_length = int(environ.get("CONTENT_LENGTH"))
        except (ValueError, TypeError):
            content_length = 0
        super().__init__(
            LimitedStream(stdin, content_length), stdout, stderr, environ, **kwargs
        )

    def cleanup_headers(self):
        super().cleanup_headers()
        if (
            self.environ["REQUEST_METHOD"] == "HEAD"
            and "Content-Length" in self.headers
        ):
            del self.headers["Content-Length"]
        
        
        
        if (
            self.environ["REQUEST_METHOD"] != "HEAD"
            and "Content-Length" not in self.headers
        ):
            self.headers["Connection"] = "close"
        
        elif not isinstance(self.request_handler.server, socketserver.ThreadingMixIn):
            self.headers["Connection"] = "close"
        
        
        if self.headers.get("Connection") == "close":
            self.request_handler.close_connection = True

    def close(self):
        self.get_stdin().read()
        super().close()

    def finish_response(self):
        if self.environ["REQUEST_METHOD"] == "HEAD":
            try:
                deque(self.result, maxlen=0)  
                
                
                
                
                
                if not self.headers_sent:
                    self.send_headers()
            finally:
                self.close()
        else:
            super().finish_response()


class WSGIRequestHandler(simple_server.WSGIRequestHandler):
    protocol_version = "HTTP/1.1"

    def address_string(self):
        
        return self.client_address[0]

    def log_message(self, format, *args):
        extra = {
            "request": self.request,
            "server_time": self.log_date_time_string(),
        }
        if args[1][0] == "4":
            
            if args[0].startswith("\x16\x03"):
                extra["status_code"] = 500
                logger.error(
                    "You're accessing the development server over HTTPS, but "
                    "it only supports HTTP.",
                    extra=extra,
                )
                return

        if args[1].isdigit() and len(args[1]) == 3:
            status_code = int(args[1])
            extra["status_code"] = status_code

            if status_code >= 500:
                level = logger.error
            elif status_code >= 400:
                level = logger.warning
            else:
                level = logger.info
        else:
            level = logger.info

        level(format, *args, extra=extra)

    def get_environ(self):
        
        
        
        
        for k in self.headers:
            if "_" in k:
                del self.headers[k]

        return super().get_environ()

    def handle(self):
        self.close_connection = True
        self.handle_one_request()
        while not self.close_connection:
            self.handle_one_request()
        try:
            self.connection.shutdown(socket.SHUT_WR)
        except (AttributeError, OSError):
            pass

    def handle_one_request(self):
        
        self.raw_requestline = self.rfile.readline(65537)
        if len(self.raw_requestline) > 65536:
            self.requestline = ""
            self.request_version = ""
            self.command = ""
            self.send_error(414)
            return

        if not self.parse_request():  
            return

        handler = ServerHandler(
            self.rfile, self.wfile, self.get_stderr(), self.get_environ()
        )
        handler.request_handler = self  
        handler.run(self.server.get_app())


def run(
    addr,
    port,
    wsgi_handler,
    ipv6=False,
    threading=False,
    on_bind=None,
    server_cls=WSGIServer,
):
    server_address = (addr, port)
    if threading:
        httpd_cls = type("WSGIServer", (socketserver.ThreadingMixIn, server_cls), {})
    else:
        httpd_cls = server_cls
    httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)
    if on_bind is not None:
        on_bind(getattr(httpd, "server_port", port))
    if threading:
        
        
        
        
        
        
        httpd.daemon_threads = True
    httpd.set_app(wsgi_handler)
    httpd.serve_forever()