Opened 7 years ago

Last modified 10 months ago

#5897 new New feature

Add Content-Length header in common middleware

Reported by: Scott Barr <scott@…> Owned by: ccahoon
Component: HTTP handling Version: master
Severity: Normal Keywords: Content-Length middleware
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

I've modified django.middleware.common.py to add a "Content-Length" header to the HTTP response if the response code is 200 and the "Content-Length" header hasn't already been supplied.

Attachments (1)

middleware.common.patch (515 bytes) - added by Scott Barr <scott@…> 7 years ago.
Patch

Download all attachments as: .zip

Change History (11)

Changed 7 years ago by Scott Barr <scott@…>

Patch

comment:1 Changed 7 years ago by Simon Greenhill <dev@…>

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Triage Stage changed from Unreviewed to Ready for checkin

comment:2 Changed 7 years ago by adrian

Hmmm, what's the advantage of doing this? I don't necessarily like the overhead of doing a len() on every request...

comment:3 Changed 7 years ago by adrian

  • Triage Stage changed from Ready for checkin to Design decision needed

comment:4 Changed 6 years ago by fumanchu

The advantage is following the HTTP spec, which mandates that messages either:

  1. be length 0 by design (e.g. HEAD)
  2. use "chunked" encoding
  3. provide Content-Length
  4. use the multipart/byteranges media type, or
  5. close the connection.

Options 1, 2, and 4 are rare, so omitting C-L leaves us with (5) and therefore means conns can't ever use keepalive. I would say that any response with a buffered body, not just 200, should get a C-L response header.

In addition, the len(str) function seems to be nearly O(1) up to about 95MB:

>>> for size in range(10):
...     timeit.Timer("len(a)", "a = 'a' * %d" % (10 ** size)).timeit()
...     
0.090876075031882553
0.092112894236557996
0.091411897322145691
0.096701326565247825
0.095689815325690875
0.098474945838088412
0.09903919352878654
0.097267250446634979
0.09309835467915617
0.4417090719630572
>>> 10 ** 8
100000000
>>> _ / 1024
97656
>>> _ / 1024
95

comment:5 Changed 6 years ago by ccahoon

  • Owner changed from nobody to ccahoon

comment:6 Changed 6 years ago by ccahoon

Three things:

That said, I am going to investigate further. This is closely related to #7581, which incidentally has a very similar bit of code to the patch provided here.

When dealing with streaming responses, probably intended for chunked transfer encoding, we want to ensure that we don't consume the whole generator/iterator in any effort to send a header that is not strictly required.

comment:7 Changed 5 years ago by graham_king

ConditionalGetMiddleware already does this (amongst other things). http://docs.djangoproject.com/en/dev/ref/middleware/#module-django.middleware.http
Is that not sufficient?

Also, Content-Length should be set for all header codes (Ajax and REST APIs will use a wider selection, 201 for example).
core/handlers/base.py will use http.conditional_content_removal to remove Content-Length for any response codes that shouldn't have it, so setting for all is safe.

comment:8 Changed 4 years ago by gabrielhurley

  • Severity set to Normal
  • Type set to New feature

comment:9 Changed 4 years ago by carljm

  • Easy pickings unset
  • Resolution set to wontfix
  • Status changed from new to closed
  • UI/UX unset

Discussion with Alex at sprint: since this is not required by spec, and is already available in ConditionalGetMiddleware for those who want it, we don't want to go exhausting iterator responses by default in CommonMiddleware.

comment:10 Changed 10 months ago by aaugustin

  • Has patch unset
  • Resolution wontfix deleted
  • Status changed from closed to new
  • Triage Stage changed from Design decision needed to Accepted

I'm reopening this ticket in the light of the introduction of explicit streaming responses, which removes the only objection to fixing this ticket.

I believe Content-Length should be added for non-streaming responses. Their content is consumed upon assignment. The overhead of computing response length will be negligible.

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