#29343: static file serving fails with "Connection reset by peer" on HEAD
requests
---------------------------------+------------------------------------
Reporter: Yehor Smoliakov | Owner: nobody
Type: Bug | Status: new
Component: HTTP handling | Version: 2.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
---------------------------------+------------------------------------
Comment (by Jannik Schürg):
I could reproduce it now a few times but not consistently, it is a timing
issue maybe. Or my version of curl is more hesitant with TCP RST (leading
to ConnectionResetError).
Here is what happens, I think:
1. Curl closes the connection by resetting it instead of closing it (RST
vs. FIN).
2. An exception is thrown in wsgiref/socket.
3. `wsgiref.handlers.BaseHandler.close()` is called, which reset the state
of the handler (in particular `self.environ` is set to `None`).
4. The error handler `handle_error()` is called. Here Django has
overwritten the method and checks if `is_broken_pipe_error()` in which
case nothing would happen.
5. But curl did reset instead of close, so we have not "broken pipe," but
"connection reset". The default handler is called, which tries to use
`self.environ`, exception.
A proper fix probably would be to modify
`core.servers.basehttp.ServerHandler` by adding the method
{{{#!python
def finish_response(self):
try:
if self.environ['REQUEST_METHOD'] == 'HEAD':
self.finish_content()
else:
if not self.result_is_file() or not self.sendfile():
for data in self.result:
self.write(data)
self.finish_content()
finally:
self.close()
}}}
With this the server does no longer try to send the body for a HEAD
request (as it should be).
I am sure there are cases where this does produce an incorrect HEAD
response according to the HTTP standard, but at least no body is sent
anymore.
Alternatively/additionally one might want to change the check with
`is_broken_pipe()`. For example one could also check for connection reset,
or if `self.environ` is not `None`, or if the connection was closed
(overwrite close() method).
--
Ticket URL: <https://code.djangoproject.com/ticket/29343#comment:7>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/066.090ee007e8243b40a8a740775d9aca7f%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.