Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

StaticFiles return 404 #1002

Closed
indeets-vasily opened this issue Jul 19, 2020 · 4 comments
Closed

StaticFiles return 404 #1002

indeets-vasily opened this issue Jul 19, 2020 · 4 comments

Comments

@indeets-vasily
Copy link

Hi!

I use example from the docs:

from starlette.applications import Starlette
from starlette.routing import Mount
from starlette.staticfiles import StaticFiles

routes = [
    Mount('/static', app=StaticFiles(directory='static', html=True), name="static"),
]

app = Starlette(routes=routes)

The code saved in .py file in a directory which has sub-directory named 'static'.
That sub-directory has file named 'index.html'.
I run app using uvicorn.

The bug:
When I access http://localhost:8000/static/index.html the response is 404 even though that file is present.

I have tried:

  • Using absolute path for directory parameter.
  • Using html=True in StaticFiles constructor

The result is still the same.

Is there something else that I should add to my app to make it work? The docs leave the impression that this is all I have to do.

I have Windows OS.

@pk400
Copy link

pk400 commented Jul 19, 2020

I tried running your code and got the same results as well using the following directory structure, and running the app from the project root:

myapp
├─ myapp
│   └─app.py
└─ static
     └─ index.html

It looks to be an issue with the lookup_path() method in staticfiles.py. Specifically this line:

if (
os.path.commonprefix([os.path.realpath(full_path), directory])
!= directory
):
# Don't allow misbehaving clients to break out of the static files directory.
continue

It is not able to find a common prefix between /Users/some_user/myapp/static and static, so it skips to the next directory.

I was able to serve static files under myapp/static by comparing the common prefix to the realpath of the directory value:

if (os.path.commonprefix([os.path.realpath(full_path), os.path.realpath(directory)])
  != os.path.realpath(directory)):

@pk400
Copy link

pk400 commented Jul 19, 2020

It looks to be already mentioned in this PR: #985

@indeets-vasily
Copy link
Author

Thanks for the input!

I have tested a little bit on my Windows 10 Notebook and it seems that StaticFiles return 404 if directory parameter is pathlib class. When you pass the string of correct format (Windows for Windows system) it works:

  • StaticFiles(directory=Path("C:\\path\\to\\directory")) -- 404
  • StaticFiles(directory=Path("C:/path/to/directory")) -- 404
  • StaticFiles(directory=str(Path("C:\\path\\to\\directory"))) -- OK
  • StaticFiles(directory=str(Path("C:/path/to/directory"))) -- OK, Path automatically converts Linux path to Windows format
  • StaticFiles(directory=StaticFiles(directory="C:\\path\\to\\directory") -- OK
  • StaticFiles(directory=StaticFiles(directory="C:/path/to/directory") -- 404, because this string is in Linux format

os.path.* functions work because they return string values, even if their argument is Path:

  • StaticFiles(directory=os.path.realpath("C:\\path\\to\\directory")) -- OK
  • StaticFiles(directory=os.path.realpath("C:/path/to/directory")) -- OK
  • StaticFiles(directory=os.path.realpath(Path("C:\\path\\to\\directory"))) -- OK

Most interestingly that there are different results depending on whether directory passed as Path exists or not:
Both StaticFiles(directory=Path("C:\\non\\existent\\directory")) and StaticFiles(directory="C:\\non\\existent\\directory") return same:
RuntimeError: Directory 'C:/non/existent/directory' does not exist

@tomchristie
Copy link
Member

Resolved in 0.13.6

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants