Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/django/core/servers/basehttp.py: 26%
127 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1"""
2HTTP server that implements the Python WSGI protocol (PEP 333, rev 1.21).
4Based on wsgiref.simple_server which is part of the standard library since 2.5.
6This is a simple server for use in testing or debugging Django apps. It hasn't
7been reviewed for security issues. DON'T USE IT FOR PRODUCTION USE!
8"""
10import logging
11import socket
12import socketserver
13import sys
14from wsgiref import simple_server
16from django.core.exceptions import ImproperlyConfigured
17from django.core.handlers.wsgi import LimitedStream
18from django.core.wsgi import get_wsgi_application
19from django.db import connections
20from django.utils.module_loading import import_string
22__all__ = ("WSGIServer", "WSGIRequestHandler")
24logger = logging.getLogger("django.server")
27def get_internal_wsgi_application():
28 """
29 Load and return the WSGI application as configured by the user in
30 ``settings.WSGI_APPLICATION``. With the default ``startproject`` layout,
31 this will be the ``application`` object in ``projectname/wsgi.py``.
33 This function, and the ``WSGI_APPLICATION`` setting itself, are only useful
34 for Django's internal server (runserver); external WSGI servers should just
35 be configured to point to the correct application object directly.
37 If settings.WSGI_APPLICATION is not set (is ``None``), return
38 whatever ``django.core.wsgi.get_wsgi_application`` returns.
39 """
40 from django.conf import settings
42 app_path = getattr(settings, "WSGI_APPLICATION")
43 if app_path is None:
44 return get_wsgi_application()
46 try:
47 return import_string(app_path)
48 except ImportError as err:
49 raise ImproperlyConfigured(
50 "WSGI application '%s' could not be loaded; "
51 "Error importing module." % app_path
52 ) from err
55def is_broken_pipe_error():
56 exc_type, _, _ = sys.exc_info()
57 return issubclass(
58 exc_type,
59 (
60 BrokenPipeError,
61 ConnectionAbortedError,
62 ConnectionResetError,
63 ),
64 )
67class WSGIServer(simple_server.WSGIServer):
68 """BaseHTTPServer that implements the Python WSGI protocol"""
70 request_queue_size = 10
72 def __init__(self, *args, ipv6=False, allow_reuse_address=True, **kwargs):
73 if ipv6:
74 self.address_family = socket.AF_INET6
75 self.allow_reuse_address = allow_reuse_address
76 super().__init__(*args, **kwargs)
78 def handle_error(self, request, client_address):
79 if is_broken_pipe_error():
80 logger.info("- Broken pipe from %s\n", client_address)
81 else:
82 super().handle_error(request, client_address)
85class ThreadedWSGIServer(socketserver.ThreadingMixIn, WSGIServer):
86 """A threaded version of the WSGIServer"""
88 daemon_threads = True
90 def __init__(self, *args, connections_override=None, **kwargs):
91 super().__init__(*args, **kwargs)
92 self.connections_override = connections_override
94 # socketserver.ThreadingMixIn.process_request() passes this method as
95 # the target to a new Thread object.
96 def process_request_thread(self, request, client_address):
97 if self.connections_override:
98 # Override this thread's database connections with the ones
99 # provided by the parent thread.
100 for alias, conn in self.connections_override.items():
101 connections[alias] = conn
102 super().process_request_thread(request, client_address)
104 def _close_connections(self):
105 # Used for mocking in tests.
106 connections.close_all()
108 def close_request(self, request):
109 self._close_connections()
110 super().close_request(request)
113class ServerHandler(simple_server.ServerHandler):
114 http_version = "1.1"
116 def __init__(self, stdin, stdout, stderr, environ, **kwargs):
117 """
118 Use a LimitedStream so that unread request data will be ignored at
119 the end of the request. WSGIRequest uses a LimitedStream but it
120 shouldn't discard the data since the upstream servers usually do this.
121 This fix applies only for testserver/runserver.
122 """
123 try:
124 content_length = int(environ.get("CONTENT_LENGTH"))
125 except (ValueError, TypeError):
126 content_length = 0
127 super().__init__(
128 LimitedStream(stdin, content_length), stdout, stderr, environ, **kwargs
129 )
131 def cleanup_headers(self):
132 super().cleanup_headers()
133 # HTTP/1.1 requires support for persistent connections. Send 'close' if
134 # the content length is unknown to prevent clients from reusing the
135 # connection.
136 if "Content-Length" not in self.headers:
137 self.headers["Connection"] = "close"
138 # Persistent connections require threading server.
139 elif not isinstance(self.request_handler.server, socketserver.ThreadingMixIn):
140 self.headers["Connection"] = "close"
141 # Mark the connection for closing if it's set as such above or if the
142 # application sent the header.
143 if self.headers.get("Connection") == "close":
144 self.request_handler.close_connection = True
146 def close(self):
147 self.get_stdin()._read_limited()
148 super().close()
151class WSGIRequestHandler(simple_server.WSGIRequestHandler):
152 protocol_version = "HTTP/1.1"
154 def address_string(self):
155 # Short-circuit parent method to not call socket.getfqdn
156 return self.client_address[0]
158 def log_message(self, format, *args):
159 extra = {
160 "request": self.request,
161 "server_time": self.log_date_time_string(),
162 }
163 if args[1][0] == "4":
164 # 0x16 = Handshake, 0x03 = SSL 3.0 or TLS 1.x
165 if args[0].startswith("\x16\x03"):
166 extra["status_code"] = 500
167 logger.error(
168 "You're accessing the development server over HTTPS, but "
169 "it only supports HTTP.\n",
170 extra=extra,
171 )
172 return
174 if args[1].isdigit() and len(args[1]) == 3:
175 status_code = int(args[1])
176 extra["status_code"] = status_code
178 if status_code >= 500:
179 level = logger.error
180 elif status_code >= 400:
181 level = logger.warning
182 else:
183 level = logger.info
184 else:
185 level = logger.info
187 level(format, *args, extra=extra)
189 def get_environ(self):
190 # Strip all headers with underscores in the name before constructing
191 # the WSGI environ. This prevents header-spoofing based on ambiguity
192 # between underscores and dashes both normalized to underscores in WSGI
193 # env vars. Nginx and Apache 2.4+ both do this as well.
194 for k in self.headers:
195 if "_" in k:
196 del self.headers[k]
198 return super().get_environ()
200 def handle(self):
201 self.close_connection = True
202 self.handle_one_request()
203 while not self.close_connection:
204 self.handle_one_request()
205 try:
206 self.connection.shutdown(socket.SHUT_WR)
207 except (AttributeError, OSError):
208 pass
210 def handle_one_request(self):
211 """Copy of WSGIRequestHandler.handle() but with different ServerHandler"""
212 self.raw_requestline = self.rfile.readline(65537)
213 if len(self.raw_requestline) > 65536:
214 self.requestline = ""
215 self.request_version = ""
216 self.command = ""
217 self.send_error(414)
218 return
220 if not self.parse_request(): # An error code has been sent, just exit
221 return
223 handler = ServerHandler(
224 self.rfile, self.wfile, self.get_stderr(), self.get_environ()
225 )
226 handler.request_handler = self # backpointer for logging & connection closing
227 handler.run(self.server.get_app())
230def run(addr, port, wsgi_handler, ipv6=False, threading=False, server_cls=WSGIServer):
231 server_address = (addr, port)
232 if threading:
233 httpd_cls = type("WSGIServer", (socketserver.ThreadingMixIn, server_cls), {})
234 else:
235 httpd_cls = server_cls
236 httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)
237 if threading:
238 # ThreadingMixIn.daemon_threads indicates how threads will behave on an
239 # abrupt shutdown; like quitting the server by the user or restarting
240 # by the auto-reloader. True means the server will not wait for thread
241 # termination before it quits. This will make auto-reloader faster
242 # and will prevent the need to kill the server manually if a thread
243 # isn't terminating correctly.
244 httpd.daemon_threads = True
245 httpd.set_app(wsgi_handler)
246 httpd.serve_forever()