-
-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Fix race in FileResponse
if file is replaced during prepare
#10101
Conversation
…d open calls There was a race in ``FileResponse`` where the stat would be incorrect if the file was changed out between the `stat` and `open` syscalls. This would lead to various unexpected behaviors such as trying to read beyond the length of the file or sending a partial file. This problem is likely to occour when files are being renamed/linked into place. An example of how this can happen with a system that provides weather data every 60s: An external process writes `.weather.txt` at the top of each minute, and than renames it to `weather.txt`. In this case `aiohttp` may stat the old `weather.txt`, and than open the new `weather.txt`, and use the `stat` result from the original file. To fix this we now `fstat` the open file on operating systems where `fstat` is available fixes #8013
Codecov ReportAll modified and coverable lines are covered by tests ✅
✅ All tests successful. No failed tests found. Additional details and impacted files@@ Coverage Diff @@
## master #10101 +/- ##
==========================================
- Coverage 98.76% 98.75% -0.01%
==========================================
Files 122 122
Lines 36912 36927 +15
Branches 4402 4409 +7
==========================================
+ Hits 36455 36469 +14
Misses 311 311
- Partials 146 147 +1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
CodSpeed Performance ReportMerging #10101 will improve performances by 15.95%Comparing Summary
Benchmarks breakdown
|
FileResponse
if file is replaced during prepareFileResponse
if file is replaced during prepare
close reopen because github flaked in the middle of the CI run. Hopefully I don't have to make a new PR |
Backport to 3.11: 💚 backport PR created✅ Backport PR branch: Backported as #10105 🤖 @patchback |
(cherry picked from commit 678993a)
Backport to 3.12: 💚 backport PR created✅ Backport PR branch: Backported as #10106 🤖 @patchback |
(cherry picked from commit 678993a)
…e is replaced during `prepare` (#10105) Co-authored-by: J. Nick Koston <[email protected]> fixes #8013
…e is replaced during `prepare` (#10106) Co-authored-by: J. Nick Koston <[email protected]> fixes #8013
@bdraco As far as I can see from codecov history, this PR is the one that loses coverage on web_response.py. Should we remove that check or adjust the tests to get coverage again? https://app.codecov.io/gh/aio-libs/aiohttp/pull/10101/indirect-changes |
After fighting with
That's a bit surprising. I'm a bit curious what we were passing in there before that would have hit that branch https://app.codecov.io/gh/aio-libs/aiohttp/pull/10095/blob/aiohttp/web_response.py#L268 |
@Dreamsorcerer Made a small change diff --git a/aiohttp/web_response.py b/aiohttp/web_response.py
index cb3e3717c..907f061f5 100644
--- a/aiohttp/web_response.py
+++ b/aiohttp/web_response.py
@@ -267,6 +267,10 @@ class StreamResponse(BaseClass, HeadersMixin, CookieMixin):
)
elif isinstance(value, str):
self._headers[hdrs.LAST_MODIFIED] = value
+ else:
+ raise ValueError(
+ "Unsupported type for last_modified: %s" % type(value).__name__
+ )
@property
def etag(self) -> Optional[ETag]: And... it looks like it was only covering the branch because it was passing in a
|
Maybe raising ValueError when it's going to do nothing does make the most sense (along with a test for it). However not sure if we should backport something like that to 3.x as the current behavior is to swallow unsupported types and raising an exception might be breaking change. |
Captured as #10143 |
There was a race in
FileResponse
where thestat
would be incorrect if the file was changed out between thestat
andopen
syscalls. This would lead to various unexpected behaviors such as trying to read beyond the length of the file or sending a partial file. This problem is likely to occour when files are being renamed/linked into place.An example of how this can happen with a system that provides weather data every 60s:
An external process writes
.weather.txt
at the top of each minute, and than renames it into place asweather.txt
. In this caseFileResponse.prepare
maystat
the oldweather.txt
, and thanopen
the newweather.txt
, and use theos.stat_result
from the original file.To fix this we now
fstat
the open file on operating systems wherefstat
is available.This change looks much larger than it actually is because most of the function now needs to be wrapped in the
try
/finally
to ensure that we close the file cleanly as we open it a lot sooner now. Its best to compare without white space as well.fixes #8013