Skip to content

Commit

Permalink
Make "Filename too long" return 404 not 500
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeremy Epstein committed Apr 30, 2024
1 parent 9f16bf5 commit 2437fe4
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 2 deletions.
14 changes: 12 additions & 2 deletions starlette/staticfiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import importlib.util
import os
import re
import stat
import typing
from email.utils import parsedate
Expand Down Expand Up @@ -124,8 +125,17 @@ async def get_response(self, path: str, scope: Scope) -> Response:
)
except PermissionError:
raise HTTPException(status_code=401)
except OSError:
raise
except OSError as ex:
# If the filename is too long for the underlying OS to handle, then the
# file couldn't possibly exist, so we treat it as "not found", rather than
# as as an unknown error that gets propagated.
# From testing in a few different POSIX environments, some return
# "File name too long" (with a space), while others return
# "Filename too long" (without a space). Hence the regex.
if re.search(r"File ?name too long", f"{ex}") is not None:
raise HTTPException(status_code=404)

raise ex

if stat_result and stat.S_ISREG(stat_result.st_mode):
# We have a static file to serve.
Expand Down
15 changes: 15 additions & 0 deletions tests/test_staticfiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,21 @@ def test_staticfiles_access_file_as_dir_returns_404(
assert response.text == "Not Found"


def test_staticfiles_filename_too_long_returns_404(
tmpdir: Path, test_client_factory: TestClientFactory
) -> None:
routes = [Mount("/", app=StaticFiles(directory=tmpdir), name="static")]
app = Starlette(routes=routes)
client = test_client_factory(app)

# The exact filename limit is platform specific (mainly filesystem specific), but,
# as of 2024, it appears to be not more than 4096 chars on POSIX systems, so this
# test should behave consistently with a filename longer than that.
response = client.get(f"/{'a' * 5000}.txt")
assert response.status_code == 404
assert response.text == "Not Found"


def test_staticfiles_unhandled_os_error_returns_500(
tmpdir: Path,
test_client_factory: TestClientFactory,
Expand Down

0 comments on commit 2437fe4

Please sign in to comment.