Opened 5 weeks ago

Closed 4 weeks ago

#36081 closed New feature (wontfix)

HttpResponse 204 (No Content) causes client code to hang if data is present.

Reported by: Cleophus Robinson Owned by: Aditya Upadhye
Component: HTTP handling Version: dev
Severity: Normal Keywords: 204, HTTP, API, Timeout
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: yes UI/UX: no

Description

What Happened
I discovered this when returning "{}" as the body for a 204 status response.

Explanation
When returning an HttpResponse to the client with a status of 204 (no content), their system will hang if data is actually sent back in the body.
It does this because it's an invalid response and it breaks the HTTP spec. Clients will hang until a valid response is returned from the server.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/204#compatibility_notes

"Although this status code is intended for responses with no body, servers may erroneously include data after the headers. This issue is observable in persistent connections, where the invalid body may include a distinct response to a subsequent request. The HTTP protocol allows browsers to handle such responses differently (there is an ongoing discussion regarding the specification text in the HTTPWG http-core GitHub repository).

Apple Safari rejects any such data. Google Chrome and Microsoft Edge discard up to four invalid bytes preceding a valid response. Firefox tolerates over a kilobyte of invalid data preceding a valid response."

Examples

  1. This is observed in Postman and other systems, the response is already returned but it's still "Receiving Response". In this case, it will timeout after a minute. Browsers may handle it differently.
  2. My webhook made the client code timeout and forced the webhook into a retry sequence.

Solution
I think Django should raise an exception in the HttpResponse class if this happens. Browsers take their own approach on what to do in this scenario and an opinionated stance may be warranted. It will also save developers from bizarre behavior.

Attachments (1)

ReceivingResponse.png (89.7 KB ) - added by Cleophus Robinson 5 weeks ago.

Download all attachments as: .zip

Change History (11)

by Cleophus Robinson, 5 weeks ago

Attachment: ReceivingResponse.png added

comment:1 by Cleophus Robinson, 5 weeks ago

Version: 4.2

comment:2 by Jacob Lincoln, 5 weeks ago

Owner: set to Jacob Lincoln
Status: newassigned

comment:3 by Jacob Lincoln, 5 weeks ago

Owner: Jacob Lincoln removed
Status: assignednew

comment:4 by Cleophus Robinson, 5 weeks ago

Triage Stage: UnreviewedAccepted

comment:5 by Carlton Gibson, 5 weeks ago

Triage Stage: AcceptedUnreviewed
Type: UncategorizedBug
Version: 5.1

Hi Cleophus — please don't "Accept" your own tickets. It needs to be triaged by someone other than the reporter. Thanks.

comment:6 by Carlton Gibson, 5 weeks ago

Type: BugNew feature

Marking this as a New Feature — Reading the report, it's the client that needs to handle this.

Best approach is for users to not send data when using 204 status codes. A project-level response class would be my suggestion.

I'm sceptical about adding something for this in Django itself. I'd argue for wontfix probably.

Version 0, edited 5 weeks ago by Carlton Gibson (next)

comment:7 by Aditya Upadhye, 5 weeks ago

Hi Carlton and Cleophus, this looks like additional handling for HTTP 204. Should a project-level class other than HttpResponse be set up for more stricter validations? I would like to work on this.

Last edited 5 weeks ago by Aditya Upadhye (previous) (diff)

comment:8 by Aditya Upadhye, 5 weeks ago

Owner: set to Aditya Upadhye
Status: newassigned

comment:9 by Cleophus Robinson, 5 weeks ago

Whoops, I was confused by the "next steps" message above - I'll know for next time.

If I'm understanding correctly the original suggestion was for us to handle it at the project level? Or by project level do you mean another, more strict class within the django.http module? My team and I won't make this mistake again so the fix isn't so much for us. I'm more worried about the bizarreness of it as it will certainly trip up other developers. For a little more context, we were using it in our JSON API and returning "{}" for a 200 response. We changed this to a 204 later on and thought nothing of it - to our surprise.

I do think this looks like additional handling / validation for 204. The lowest hanging fruit would be a warning in the documentation but it wouldn't be as effective. The issue is too innocuous for someone to suspect a 2xx status code as the root cause.

In any case, thank you both for taking a look! Let me know if I can assist in any way.

comment:10 by Natalia Bidart, 4 weeks ago

Resolution: wontfix
Status: assignedclosed
Version: 5.1dev

Thank you all for the discussion and the context surrounding the report. I've reviewed the relevant sections of the RFC and done some additional research. Following that, I think that ensuring a proper 204 response is the responsibility of the project itself. For reference, Flask doesn't implement any special handling for 204 responses, and Django doesn't have a custom HttpResponse class for 20x status codes. Additionally, I believe clients should ideally be more resilient and not hang on 204 responses that include content.

Note: See TracTickets for help on using tickets.
Back to Top