evansd / whitenoise

Radically simplified static file serving for Python web apps
https://whitenoise.readthedocs.io
MIT License
2.51k stars 148 forks source link

Static files not found / bad args passed to finders.find (dev, Windows) #472

Open marcperrinoptel opened 1 year ago

marcperrinoptel commented 1 year ago

Python Version

3.7.9

Django Version

3.2.16

Package Version

6.2.0

Description

Hi,

I've stumbled upon an issue about serving "non-collectstatic'd" static files in dev, on Windows. The issue isn't present with the classic Django runserver.

(To give more context: basically I have React js files that get modified during the dev, in their dedicated directory; and I don't have/want to collectstatic this directory towards the static root all the time; in dev they're served directly from this additional STATICFILES_DIRS item)

In detail, what happens is that: In the non-Whitenoise case, the request path / url goes through the following "pipeline" before Django calls finders.find:

  1. path = url[len(self.base_url[2]):] (see here - bit different in more recent Django, but it's the same thing)
  2. path = url2pathname(path) (see here)
  3. path = posixpath.normpath(path).lstrip('/') (see here)

Whitenoise does (the equivalent of) 1 (see here), but neither 2 (that's the important piece) nor 3, so what I see passed to finders.find in Whitenoise case is e.g. react_bundle/foo.js vs. react_bundle\foo.js in Django case.

And yes, FileSystemFinder.find_location (see here) is indeed quite harsh (unnecessarily harsh?) re os separators.

I think I'll open a pull request about that (considering we should probably align on Django, rather than try to get FileSystemFinder.find_location to be more lax? It's worth noting however that AppDirectoriesFinder is indeed more lax than FileSystemFinder, and doesn't exhibit the issue - e.g. it uses safe_join from django.utils._os; so that would be an argument in favor of fixing in Django rather than in Whitenoise...)

Thanks

marcperrinoptel commented 1 year ago

I've opened this on Django side https://code.djangoproject.com/ticket/34341, might help deciding whether to fix on Django side vs. whitenoise side.

marcperrinoptel commented 1 year ago

The probable takeaway from the discussion on Django side is that finders.find() is really supposed to be called with an OS-standardized path.

Here's my pull request to address that: https://github.com/evansd/whitenoise/pull/474