Skip to content

Handle staticfiles OSError exceptions#1220

Merged
aminalaee merged 18 commits intoKludex:masterfrom
aminalaee:handle-staticfiles-os-errors
Oct 5, 2021
Merged

Handle staticfiles OSError exceptions#1220
aminalaee merged 18 commits intoKludex:masterfrom
aminalaee:handle-staticfiles-os-errors

Conversation

@aminalaee
Copy link
Contributor

@aminalaee aminalaee commented Jun 27, 2021

Closes #1123 Issue
And can also closes #1124 old PR

This will handle staticfiles exceptions:

  • If directory not found throws 404 (file not found was already handled)
  • if permission denied on file/folder returns 401
  • if any other OSError exceptions happen, returns 500


with mock.patch(
"starlette.staticfiles.StaticFiles.lookup_path"
) as mock_lookup_path:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't seen any usage of unittest.mock in the project, but I couldn't find any better way to create not-so-simple OSError exceptions.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any OSError that might cause this? Maybe a broken symlink or would that just 404?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess that would be a FileNotFound. I'll give it another try but all other unhandled OSError exceptions happened on writing a file or internal sys calls.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

statting a file you can't access gives you PermissionError:

>>> os.stat("/boot/bar")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
PermissionError: [Errno 13] Permission denied: '/boot/bar'

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah you already have a test for that

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JayH5 Changed that, please check again if that's what you meant.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks yes that is what I meant. Sorry for the slow response 😕

I've been thinking about this again and I'm not sure we actually want to return 500 from within the static files implementation. Should we not just allow/raise the exception since it is so unexpected? IMO, the ServerErrorMiddleware (and similar) should really be the only thing in Starlette that returns a 500 response.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JayH5
That makes sense. What about the other exceptions?
Like 404 and 401, can't ExceptionMiddleware handle those?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You do make a good point 🤔 I'm not sure why we don't raise an HTTPException in those cases. I'd be open to that change (if it's as straightforward as it seems) either in this PR or another.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JayH5 I played around this a bit and changed that.
I think we can raise HTTPException instead of returning PlaintTextResponses but there's a difference. If we raise HTTPException then we need to can't use StaticFiles alone as we need Starlette middlewares to handle the exception which StaticFiles doesn't have.


with mock.patch(
"starlette.staticfiles.StaticFiles.lookup_path"
) as mock_lookup_path:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any OSError that might cause this? Maybe a broken symlink or would that just 404?

@aminalaee aminalaee requested review from JayH5 and graingert June 30, 2021 04:37
@aminalaee aminalaee requested a review from a team August 11, 2021 18:39
Copy link
Contributor

@lovelydinosaur lovelydinosaur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aminalaee - Looks neatly done. Happy to leave this up to your judgement.

@aminalaee aminalaee requested a review from Kludex September 30, 2021 13:53
@aminalaee aminalaee merged commit 1db8b5b into Kludex:master Oct 5, 2021
@aminalaee aminalaee deleted the handle-staticfiles-os-errors branch October 5, 2021 06:01
@lambdaq
Copy link

lambdaq commented Jan 17, 2022

Heads up for anyone using lookup_path(): it's now changed to a sync method in starlette>=0.17.1

I am using await self.lookup_path in my code this PR breaks it lol.

I know it's my bad to use an undocumented internal method, but I just don't want to handle path on my own.

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

Successfully merging this pull request may close these issues.

StaticFiles causes Internal Server Error when user accesses existing files as directory

6 participants