common methods used by wsgi and asgi handlers may be used to differentiate between handler types e g in a requestfinished signal middleware are already loaded for self application no need to reload them for self check if the path should be handled ignore the path if the host is provided as part of the baseurl the request s path isn t under the media path or equal return the relative path to the media file on disk for the given url serve the request path return serverequest self filepathrequest path insecuretrue def getresponseself request try return self serverequest except http404 as e return responseforexceptionrequest e async def getresponseasyncself request try return await synctoasyncself serve threadsensitivefalserequest except http404 as e return await synctoasyncresponseforexception threadsensitivefalse request e class staticfileshandlerstaticfileshandlermixin wsgihandler def initself application self application application self baseurl urlparseself getbaseurl super init def callself environ startresponse if not self shouldhandlegetpathinfoenviron return self applicationenviron startresponse return super callenviron startresponse class asgistaticfileshandlerstaticfileshandlermixin asgihandler def initself application self application application self baseurl urlparseself getbaseurl async def callself scope receive send only even look at http requests if scopetype http and self shouldhandlescopepath serve static content the one thing super doesn t do is call apparently return await super callscope receive send hand off to the main app return await self applicationscope receive send async def getresponseasyncself request response await super getresponseasyncrequest response resourceclosers appendrequest close fileresponse is not async compatible if response streaming and not response isasync iterator response streamingcontent async def awrapper for part in await synctoasynclistiterator yield part response streamingcontent awrapper return response common methods used by wsgi and asgi handlers may be used to differentiate between handler types e g in a request_finished signal middleware are already loaded for self application no need to reload them for self check if the path should be handled ignore the path if the host is provided as part of the base_url the request s path isn t under the media path or equal return the relative path to the media file on disk for the given url serve the request path wsgi middleware that intercepts calls to the static files directory as defined by the static_url setting and serves those files asgi application which wraps another and intercepts requests for static files passing them off to django s static file serving only even look at http requests serve static content the one thing super doesn t do is __call__ apparently hand off to the main app fileresponse is not async compatible
from urllib.parse import urlparse
from urllib.request import url2pathname

from asgiref.sync import sync_to_async

from django.conf import settings
from django.contrib.staticfiles import utils
from django.contrib.staticfiles.views import serve
from django.core.handlers.asgi import ASGIHandler
from django.core.handlers.exception import response_for_exception
from django.core.handlers.wsgi import WSGIHandler, get_path_info
from django.http import Http404


class StaticFilesHandlerMixin:
    

    
    
    handles_files = True

    def load_middleware(self):
        
        
        pass

    def get_base_url(self):
        utils.check_settings()
        return settings.STATIC_URL

    def _should_handle(self, path):
        
        return path.startswith(self.base_url[2]) and not self.base_url[1]

    def file_path(self, url):
        
        relative_url = url.removeprefix(self.base_url[2])
        return url2pathname(relative_url)

    def serve(self, request):
        
        return serve(request, self.file_path(request.path), insecure=True)

    def get_response(self, request):
        try:
            return self.serve(request)
        except Http404 as e:
            return response_for_exception(request, e)

    async def get_response_async(self, request):
        try:
            return await sync_to_async(self.serve, thread_sensitive=False)(request)
        except Http404 as e:
            return await sync_to_async(response_for_exception, thread_sensitive=False)(
                request, e
            )


class StaticFilesHandler(StaticFilesHandlerMixin, WSGIHandler):
    

    def __init__(self, application):
        self.application = application
        self.base_url = urlparse(self.get_base_url())
        super().__init__()

    def __call__(self, environ, start_response):
        if not self._should_handle(get_path_info(environ)):
            return self.application(environ, start_response)
        return super().__call__(environ, start_response)


class ASGIStaticFilesHandler(StaticFilesHandlerMixin, ASGIHandler):
    

    def __init__(self, application):
        self.application = application
        self.base_url = urlparse(self.get_base_url())

    async def __call__(self, scope, receive, send):
        
        if scope["type"] == "http" and self._should_handle(scope["path"]):
            
            
            return await super().__call__(scope, receive, send)
        
        return await self.application(scope, receive, send)

    async def get_response_async(self, request):
        response = await super().get_response_async(request)
        response._resource_closers.append(request.close)
        
        if response.streaming and not response.is_async:
            _iterator = response.streaming_content

            async def awrapper():
                for part in await sync_to_async(list)(_iterator):
                    yield part

            response.streaming_content = awrapper()
        return response