Skip to content

Commit

Permalink
Beautified Django 404 message (#20)
Browse files Browse the repository at this point in the history
Co-authored-by: Anders Hovmöller <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Aug 30, 2024
1 parent a486fe9 commit 4f617f8
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 14 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ Using the following categories, list your changes in this order:

## [Unreleased](https://github.com/Archmonger/ServeStatic/compare/1.1.0...HEAD)

### Added

- Verbose Django `404` error page when `settings.py:DEBUG` is `True` ([Upstream PR](https://github.com/evansd/whitenoise/pull/366))

### Fixed

- Fix compatibility with third-party sync only middleware
Expand Down
14 changes: 14 additions & 0 deletions src/servestatic/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
from django.http import FileResponse
from django.urls import get_script_prefix

from servestatic.responders import MissingFileError

from .asgi import BLOCK_SIZE
from .string_utils import ensure_leading_trailing_slash
from .wsgi import ServeStatic
Expand Down Expand Up @@ -175,6 +177,18 @@ async def __call__(self, request):
if static_file is not None:
return await self.aserve(static_file, request)

if settings.DEBUG and request.path.startswith(settings.STATIC_URL):
current_finders = finders.get_finders()
app_dirs = [
storage.location
for finder in current_finders
for storage in finder.storages.values()
]
app_dirs = "\n• ".join(sorted(app_dirs))
raise MissingFileError(
f"ServeStatic did not find the file '{request.path.lstrip(settings.STATIC_URL)}' within the following paths:\n{app_dirs}"
)

return await self.get_response(request)

@staticmethod
Expand Down
9 changes: 8 additions & 1 deletion tests/django_urls.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
from __future__ import annotations

urlpatterns = []
from django.urls import path


def avoid_django_default_welcome_page():
pass


urlpatterns = [path("", avoid_django_default_welcome_page)]
57 changes: 44 additions & 13 deletions tests/test_django_whitenoise.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,33 @@
from __future__ import annotations

import asyncio
import html
import shutil
import tempfile
from contextlib import closing
from urllib.parse import urljoin
from urllib.parse import urlparse
from pathlib import Path
from urllib.parse import urljoin, urlparse

import brotli
import pytest
from django.conf import settings
from django.contrib.staticfiles import finders
from django.contrib.staticfiles import storage
from django.contrib.staticfiles import finders, storage
from django.core.asgi import get_asgi_application
from django.core.management import call_command
from django.core.wsgi import get_wsgi_application
from django.test.utils import override_settings
from django.utils.functional import empty

from .utils import AppServer
from .utils import AsgiAppServer
from .utils import AsgiReceiveEmulator
from .utils import AsgiScopeEmulator
from .utils import AsgiSendEmulator
from .utils import Files
from servestatic.middleware import ServeStaticFileResponse
from servestatic.middleware import ServeStaticMiddleware
from servestatic.middleware import ServeStaticFileResponse, ServeStaticMiddleware

from .utils import (
AppServer,
AsgiAppServer,
AsgiReceiveEmulator,
AsgiScopeEmulator,
AsgiSendEmulator,
Files,
)


def reset_lazy_object(obj):
Expand Down Expand Up @@ -188,7 +190,7 @@ def test_file_served_from_static_dir(finder_static_files, finder_server):


def test_non_ascii_requests_safely_ignored(finder_server):
response = finder_server.get(settings.STATIC_URL + "test\u263A")
response = finder_server.get(settings.STATIC_URL + "test\u263a")
assert 404 == response.status_code


Expand Down Expand Up @@ -238,3 +240,32 @@ def test_relative_static_url(server, static_files, _collect_static):
url = storage.staticfiles_storage.url(static_files.js_path)
response = server.get(url)
assert response.content == static_files.js_content


def test_404_in_prod(server):
response = server.get(settings.STATIC_URL + "garbage")
response_content = str(response.content.decode())
response_content = html.unescape(response_content)

assert response.status_code == 404
assert (
"ServeStatic did not find the file 'garbage' within the following paths:"
not in response_content
)


@override_settings(DEBUG=True)
def test_error_message(server):
response = server.get(f"{settings.STATIC_URL}garbage")
response_content = str(response.content.decode())
response_content = html.unescape(response_content)

# Beautify for easier debugging
response_content = response_content[response_content.index("ServeStatic") :]

assert (
"ServeStatic did not find the file 'garbage' within the following paths:"
in response_content
)
assert "•" in response_content
assert str(Path(__file__).parent / "test_files" / "static") in response_content

0 comments on commit 4f617f8

Please sign in to comment.