Response#finish and ContentLength
Reported by Samuel Williams | May 16th, 2010 @ 05:34 AM
From Rack::ContentLength
12: def call(env) 13: status, headers, body = @app.call(env) 14: headers = HeaderHash.new(headers) 15: 16: if !STATUS_WITH_NO_ENTITY_BODY.include?(status) && 17: !headers['Content-Length'] && 18: !headers['Transfer-Encoding'] && 19: (body.respond_to?(:to_ary) || body.respond_to?(:to_str)) 20: 21: body = [body] if body.respond_to?(:to_str) # rack 0.4 compat 22: length = body.to_ary.inject(0) { |len, part| len + bytesize(part) } 23: headers['Content-Length'] = length.to_s 24: end 25: 26: [status, headers, body] 27: end
Rack::Response doesn't respond to either :to_ary or :to_str.
This means that no content length is generated.
An alternative is to use Response#write, but it isn't clearly documented exactly how this should work.
Proposed Fixes:
- Update the documentation to explain how to use Rack::Response(body, write)
- Update Rack::Response so it provides the correct functionality for Content-Length generation
- Update Rack::ContentLength so it knows about Rack::Response and generates the content length accordingly.
- Update Rack::Response#finish so if there is no content length, it is generated from the body.
Comments and changes to this ticket
-
Deleted User September 26th, 2010 @ 05:45 PM
- Milestone order changed from 0 to 0
A result of this issue is that regular responses in Rails 3 NEVER generate a Content-Length header.
This is a pretty serious problem -
raggi May 3rd, 2011 @ 07:24 AM
- State changed from new to wontfix
frameworks that send back iterative bodies need to find out themselves how to calculate the content-length header. enforcing this would break streaming.
-
Samuel Williams May 3rd, 2011 @ 10:22 AM
Raggi, with all respect, I think you've misunderstood the issue.
Rack::Response#finish
69: def finish(&block) 70: @block = block 71: 72: if [204, 304].include?(status.to_i) 73: header.delete "Content-Type" 74: [status.to_i, header, []] 75: else 76: [status.to_i, header, self] 77: end 78: end
At this point, the response sends itself as the body object.
When this is passed to Rack::ContentLength#call,
19: (body.respond_to?(:to_ary) || body.respond_to?(:to_str))
Then, no content length is generated. Actually, Rack::Response responds to :to_a, but not :to_ary. Weird huh?
If the user sets the body directly, the result isn't always the same as if the object simply provided body rather than itself.
The alternative is to use Rack::Response#write
91: def write(str) 92: s = str.to_s 93: @length += Rack::Utils.bytesize(s) 94: @writer.call s 95: 96: header["Content-Length"] = @length.to_s 97: str 98: end
So, to summarise, if I have a Rack::Response and I set the body to ["Bob"], and then return Rack::Response#finish, Rack::ContentLength behaves differently than if I simply returned ["Bob"]. In my mind, this is inconsistent. If you require further details, please let me know.
The key here is that even if the current behavior is desired, perhaps this should be documented somewhere.
Thanks,
Samuel -
jovyxule September 26th, 2019 @ 01:09 PM
Keep up the good work , I read few posts on this web site and I conceive that your blog is very interesting and has sets of fantastic information.
mobile klimaanlage
Please Sign in or create a free account to add a new ticket.
With your very own profile, you can contribute to projects, track your activity, watch tickets, receive and update tickets through your email and much more.
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile ยป