Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Disarm and document Content-Length checking in Rack::Lint for 0.4

  • Loading branch information...
commit f0977a8a204fc1074f0d0211d0bdcc258feb5735 1 parent e9f9f27
@chneukirchen authored
Showing with 19 additions and 100 deletions.
  1. +15 −1 README
  2. +4 −58 lib/rack/lint.rb
  3. +0 −41 test/spec_rack_lint.rb
View
16 README
@@ -9,6 +9,21 @@ middleware) into a single method call.
The exact details of this are described in the Rack specification,
which all Rack applications should conform to.
+== Future specification changes
+
+PLEASE NOTE: In versions of Rack LATER than 0.4, the following
+changes will be commited to the specification:
+
+* 1xx, 204 and 304 status codes MUST not contain a Content-Type.
+* A valid Content-Length header MUST be provided for non 1xx, 204 and 304
+ responses with an Transfer-Encoding of "identity" (default).
+ The Content-Length MUST be the same as the sum of the byte-sizes of
+ the chunks.
+
+Internal Rack modules have been updated to follow this behavior, but
+the Rack 0.4 Lint does NOT check it yet for compatibility reasons.
+Please update your libraries accordingly.
+
== Supported web servers
The included *handlers* connect all kinds of web servers to Rack:
@@ -160,7 +175,6 @@ Installing the Ruby fcgi gem:
Furthermore, to test Memcache sessions, you need memcached (will be
run on port 11211) and memcache-client installed.
-
== History
* March 3rd, 2007: First public release 0.1.
View
62 lib/rack/lint.rb
@@ -3,8 +3,6 @@ module Rack
# responses according to the Rack spec.
class Lint
- STATUS_WITH_NO_ENTITY_BODY = (100..199).to_a << 204 << 304
-
def initialize(app)
@app = app
end
@@ -51,7 +49,6 @@ def _call(env)
check_headers headers
## and the *body*.
check_content_type status, headers
- check_content_length status, headers
[status, headers, self]
end
@@ -353,69 +350,18 @@ def check_headers(header)
def check_content_type(status, headers)
headers.each { |key, value|
## There must be a <tt>Content-Type</tt>, except when the
- ## +Status+ is 1xx, 204 or 304, in which case there must be none
+ ## +Status+ is 204 or 304, in which case there must be none
## given.
if key.downcase == "content-type"
- assert("Content-Type header found in #{status} response, not allowed") {
- not STATUS_WITH_NO_ENTITY_BODY.include? status.to_i
+ assert("Content-Type header found in #{status} response, not allowed"){
+ not [204, 304].include? status.to_i
}
return
end
}
assert("No Content-Type header found") {
- STATUS_WITH_NO_ENTITY_BODY.include? status.to_i
- }
- end
-
- ## === The Content-Length
- def check_content_length(status, headers)
- chunked_response = false
- headers.each { |key, value|
- if key.downcase == 'transfer-encoding'
- chunked_response = value.downcase != 'identity'
- end
+ [204, 304].include? status.to_i
}
-
- headers.each { |key, value|
- if key.downcase == 'content-length'
- ## There must be a <tt>Content-Length</tt>, except when the
- ## +Status+ is 1xx, 204 or 304, in which case there must be none
- ## given.
- assert("Content-Length header found in #{status} response, not allowed") {
- not STATUS_WITH_NO_ENTITY_BODY.include? status.to_i
- }
-
- assert('Content-Length header should not be used if body is chunked') {
- not chunked_response
- }
-
- bytes = 0
- string_body = true
-
- @body.each { |part|
- unless part.kind_of?(String)
- string_body = false
- break
- end
-
- bytes += (part.respond_to?(:bytesize) ? part.bytesize : part.size)
- }
-
- if string_body
- assert("Content-Length header was #{value}, but should be #{bytes}") {
- value == bytes.to_s
- }
- end
-
- return
- end
- }
-
- if [ String, Array ].include?(@body.class) && !chunked_response
- assert('No Content-Length header found') {
- STATUS_WITH_NO_ENTITY_BODY.include? status.to_i
- }
- end
end
## === The Body
View
41 test/spec_rack_lint.rb
@@ -203,47 +203,6 @@ def env(*args)
}).call(env({}))
}.should.raise(Rack::Lint::LintError).
message.should.match(/No Content-Type/)
-
- [100, 101, 204, 304].each do |status|
- lambda {
- Rack::Lint.new(lambda { |env|
- [status, {"Content-type" => "text/plain", "Content-length" => "0"}, ""]
- }).call(env({}))
- }.should.raise(Rack::Lint::LintError).
- message.should.match(/Content-Type header found/)
- end
- end
-
- specify "notices content-length errors" do
- lambda {
- Rack::Lint.new(lambda { |env|
- [200, {"Content-type" => "text/plain"}, ""]
- }).call(env({}))
- }.should.raise(Rack::Lint::LintError).
- message.should.match(/No Content-Length/)
-
- [100, 101, 204, 304].each do |status|
- lambda {
- Rack::Lint.new(lambda { |env|
- [status, {"Content-length" => "0"}, ""]
- }).call(env({}))
- }.should.raise(Rack::Lint::LintError).
- message.should.match(/Content-Length header found/)
- end
-
- lambda {
- Rack::Lint.new(lambda { |env|
- [200, {"Content-type" => "text/plain", "Content-Length" => "0", "Transfer-Encoding" => "chunked"}, ""]
- }).call(env({}))
- }.should.raise(Rack::Lint::LintError).
- message.should.match(/Content-Length header should not be used/)
-
- lambda {
- Rack::Lint.new(lambda { |env|
- [200, {"Content-type" => "text/plain", "Content-Length" => "1"}, ""]
- }).call(env({}))
- }.should.raise(Rack::Lint::LintError).
- message.should.match(/Content-Length header was 1, but should be 0/)
end
specify "notices body errors" do
Please sign in to comment.
Something went wrong with that request. Please try again.