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

feat(static): implement Last-Modified header for static route #2426

Open
wants to merge 16 commits into
base: master
Choose a base branch
from

Conversation

Cycloctane
Copy link

@Cycloctane Cycloctane commented Jan 11, 2025

Summary of Changes

  • Render Last-Modified header for static file responses.
  • Check request If-Modified-Since header and return 304 if date in this header is not earlier than mtime.
  • Return 403 Forbidden for PermissionError when serving static.

Related Issues

Fixes #2244

Pull Request Checklist

  • Applied changes to both WSGI and ASGI code paths and interfaces (where applicable).
  • Added tests for changed code.
  • Prefixed code comments with GitHub nick and an appropriate prefix.
  • Coding style is consistent with the rest of the framework.
  • Updated documentation for changed code.
    • Added docstrings for any new classes, functions, or modules.
    • Updated docstrings for any modifications to existing code.
    • Updated both WSGI and ASGI docs (where applicable).
    • Added references to new classes, functions, or modules to the relevant RST file under docs/.
    • Updated all relevant supporting documentation files under docs/.
    • A copyright notice is included at the top of any new modules (using your own name or the name of your organization).
    • Changed/added classes/methods/functions have appropriate versionadded, versionchanged, or deprecated directives.
  • Changes (and possible deprecations) have towncrier news fragments under docs/_newsfragments/, with the file name format {issue_number}.{fragment_type}.rst. (Run towncrier --draft to ensure it renders correctly.)

Copy link

codecov bot commented Jan 11, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 100.00%. Comparing base (ead6535) to head (6b7dd21).

Additional details and impacted files
@@            Coverage Diff            @@
##            master     #2426   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           64        64           
  Lines         7728      7743   +15     
  Branches      1071      1071           
=========================================
+ Hits          7728      7743   +15     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Member

@CaselIT CaselIT left a comment

Choose a reason for hiding this comment

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

nice improvement.

Some lines are not covered by tests, if you could add tests for them it would be great

try:
stream, length, content_range = _open_range(file_path, req_range)
resp.set_stream(stream, length)
fh = io.open(file_path, 'rb')
Copy link
Member

Choose a reason for hiding this comment

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

let's set fh to None above the try then in the except do if fn is not None: fh.close() since in theory the io error could happen in os.fstat

Copy link
Author

Choose a reason for hiding this comment

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

let's set fh to None above the try then in the except do if fn is not None: fh.close() since in theory the io error could happen in os.fstat

I tried using os.stat(file_path) instead to avoid handling fh outside _open_range(). This approach can also avoid unneccesary io.open when returning 304.

@Cycloctane Cycloctane force-pushed the last-modified_support branch from b1c90b4 to cf105d5 Compare January 15, 2025 14:01
@Cycloctane Cycloctane marked this pull request as ready for review January 15, 2025 14:02
try:
stream, length, content_range = _open_range(file_path, req_range)
resp.set_stream(stream, length)
st = _stat(file_path)
Copy link
Member

Choose a reason for hiding this comment

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

Nice going overall so far 👍

I don't like this specific change though, please revert it if possible. We do want to stat() an open fd instead of path, as this prevents a number of race conditions, for instance, if the file in question is deleted between stat() and open(), etc.

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.

Support Last-Modified header for static files
3 participants