Skip to content

comply with http caching validation with etag and if-modified-since#2891

Closed
Smixi-syn wants to merge 6 commits intoKludex:mainfrom
Smixi-syn:master
Closed

comply with http caching validation with etag and if-modified-since#2891
Smixi-syn wants to merge 6 commits intoKludex:mainfrom
Smixi-syn:master

Conversation

@Smixi-syn
Copy link
Contributor

Summary

Change the caching validation precedence to comply with HTTP RFC: https://datatracker.ietf.org/doc/html/rfc7232#section-6

The issue was that it must not check the "If-Modified-Since" header when the "If-None-Match" is set. It prioritize file content for caching instead of time based caching (I encountered this when timestamp on file are incorrect for example).

Checklist

  • I understand that this PR may be closed in case there was no previous discussion. (This doesn't apply to typos!)
  • I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change.

@grindhold
Copy link
Contributor

lol i just spent a day figuring this problem out as well. i did the same research and came to the same conclusion on how to fix it. i was about to prepare a PR but i found that @Smixi-syn already made an awesome one that even contains tests.
can we please get this merged? it causes problems in the real world ™. :)

thanks @Smixi-syn for the effort!

try:
if "if-none-match" in request_headers:
if_none_match = request_headers["if-none-match"]
etag = response_headers["etag"]
Copy link
Owner

Choose a reason for hiding this comment

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

Can the etag not be available here?

Copy link
Contributor Author

@Smixi-syn Smixi-syn Nov 1, 2025

Choose a reason for hiding this comment

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

Currently, FileResponse always compute the etag. To be future proof or just to ensure this behavior, I adjusted the logic, and considered that it could be removed (for reasons I don't know, maybe a user would not want to give etags ?) in case it is not present, the method will return False and the entire file will be sent.

Comment on lines 209 to 216
else:
try:
if_modified_since = parsedate(request_headers["if-modified-since"])
last_modified = parsedate(response_headers["last-modified"])
if if_modified_since is not None and last_modified is not None and if_modified_since >= last_modified:
return True
except KeyError:
pass
Copy link
Owner

Choose a reason for hiding this comment

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

I would prefer to avoid an unnecessary diff.

Suggested change
else:
try:
if_modified_since = parsedate(request_headers["if-modified-since"])
last_modified = parsedate(response_headers["last-modified"])
if if_modified_since is not None and last_modified is not None and if_modified_since >= last_modified:
return True
except KeyError:
pass
try:
if_modified_since = parsedate(request_headers["if-modified-since"])
last_modified = parsedate(response_headers["last-modified"])
if if_modified_since is not None and last_modified is not None and if_modified_since >= last_modified:
return True
except KeyError:
pass

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 adjusted the code so the when If-None-Match is present it returns early.

@Smixi-syn
Copy link
Contributor Author

I also added a test func for the edge case of the missing etag header in response, and fixed linting rules.

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.

3 participants