#28440 closed Bug (fixed)
runserver doesn't close the connection for responses without a Content-Length
Reported by: | Tom Forbes | Owned by: | Tom Forbes |
---|---|---|---|
Component: | HTTP handling | Version: | dev |
Severity: | Release blocker | Keywords: | |
Cc: | Triage Stage: | Ready for checkin | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description (last modified by )
Using MacOS Python 3.5, runserver does not terminate a connection once a HTTP response is sent. This seems to be caused by #25619 (but could be platform specific?).
This results in tools like curl
hanging forever, and browsers continually displaying the loading bar.
This code appears to be the culprit, it seems to be copied from the http.server
stdlib module. It handles a response and sends the contents correctly in the first iteration of the loop, but then self.close_connection
is still true, so it continues to try and read from the socket whilst the client is also reading from the socket.
Replacing the current handle
function with handle_one_request
fixes this problem, and still seems to use HTTP 1.1.
Change History (15)
comment:1 by , 7 years ago
Description: | modified (diff) |
---|
comment:2 by , 7 years ago
comment:3 by , 7 years ago
Interesting, at first I could not reproduce this with a fresh project on either MacOS or Ubuntu.
However, if you do a plain startproject
/startapp
and remove all MIDDLEWARE
, INSTALLED_APPS
(bar your app) and default template CONTEXT_PROCESSORS
it is reproducible.
I've made a demo repository that is reproducible on my Ubuntu VM: https://github.com/orf/28440-django-issue
comment:4 by , 7 years ago
Severity: | Normal → Release blocker |
---|---|
Triage Stage: | Unreviewed → Accepted |
Thanks. I'm not sure what the issue could be, offhand.
comment:5 by , 7 years ago
The issue appears to be that the CommonMiddleware
sets the Content-Length
header, which causes the server to close the connection. When this header is not present (or the middleware not installed) the server continues to wait.
comment:6 by , 7 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
comment:7 by , 7 years ago
So this actually appears to be a bug in the http.server
module. If you use HTTP/1.1 with Connection: keep-alive
and *dont* send a Content-Length header the connection will hang forever. You can test this with a little tinkering in the http.server
module itself, and running python3 -mhttp.server
on your machine.
I've made a PR (https://github.com/django/django/pull/8820) to simply disable keep-alive for now.
comment:8 by , 7 years ago
Has patch: | set |
---|
comment:9 by , 7 years ago
Summary: | Runserver does not correctly close connections once a response is sent → runserver doesn't close the connection for responses without a Content-Length |
---|---|
Triage Stage: | Accepted → Ready for checkin |
comment:11 by , 7 years ago
A PR to fix the test on macOS as reported on reported on django-developers,
I don't see the behavior you describe on Linux. Not sure if I interpreted your suggested patch correctly but:
django/core/servers/basehttp.py
def handle(self):"""Handle multiple requests if necessary."""self.close_connection = 1self.handle_one_request()while not self.close_connection:self.handle_one_request()gives this test failure: