Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Implemented Rack::Head, modified Rack::Lint to ensure responses to HE…

…AD requests have empty bodies
  • Loading branch information...
commit 8b784d3f00432547fa3fb45defe09fa384792eb5 1 parent 6874dab
@spicyj spicyj authored chneukirchen committed
View
1  lib/rack.rb
@@ -35,6 +35,7 @@ def self.release
autoload :Directory, "rack/directory"
autoload :ForwardRequest, "rack/recursive"
autoload :Handler, "rack/handler"
+ autoload :Head, "rack/head"
autoload :Lint, "rack/lint"
autoload :MethodOverride, "rack/methodoverride"
autoload :Mime, "rack/mime"
View
19 lib/rack/head.rb
@@ -0,0 +1,19 @@
+module Rack
+
+class Head
+ def initialize(app)
+ @app = app
+ end
+
+ def call(env)
+ status, headers, body = @app.call(env)
+
+ if env["REQUEST_METHOD"] == "HEAD"
+ [status, headers, []]
+ else
+ [status, headers, body]
+ end
+ end
+end
+
+end
View
16 lib/rack/lint.rb
@@ -51,7 +51,7 @@ def _call(env)
check_headers headers
## and the *body*.
check_content_type status, headers
- check_content_length status, headers
+ check_content_length status, headers, env
[status, headers, self]
end
@@ -370,7 +370,7 @@ def check_content_type(status, headers)
end
## === The Content-Length
- def check_content_length(status, headers)
+ def check_content_length(status, headers, env)
chunked_response = false
headers.each { |key, value|
if key.downcase == 'transfer-encoding'
@@ -403,10 +403,16 @@ def check_content_length(status, headers)
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
+ if env["REQUEST_METHOD"] == "HEAD"
+ assert("Response body was given for HEAD request, but should be empty") {
+ bytes == 0
}
+ else
+ if string_body
+ assert("Content-Length header was #{value}, but should be #{bytes}") {
+ value == bytes.to_s
+ }
+ end
end
return
View
30 test/spec_rack_head.rb
@@ -0,0 +1,30 @@
+require 'rack/head'
+require 'rack/mock'
+
+context "Rack::Head" do
+ def test_response(headers = {})
+ app = lambda { |env| [200, {"Content-type" => "test/plain", "Content-length" => "3"}, ["foo"]] }
+ request = Rack::MockRequest.env_for("/", headers)
+ response = Rack::Head.new(app).call(request)
+
+ return response
+ end
+
+ specify "passes GET, POST, PUT, DELETE, OPTIONS, TRACE requests" do
+ %w[GET POST PUT DELETE OPTIONS TRACE].each do |type|
+ resp = test_response("REQUEST_METHOD" => type)
+
+ resp[0].should.equal(200)
+ resp[1].should.equal({"Content-type" => "test/plain", "Content-length" => "3"})
+ resp[2].should.equal(["foo"])
+ end
+ end
+
+ specify "removes body from HEAD requests" do
+ resp = test_response("REQUEST_METHOD" => "HEAD")
+
+ resp[0].should.equal(200)
+ resp[1].should.equal({"Content-type" => "test/plain", "Content-length" => "3"})
+ resp[2].should.equal([])
+ end
+end
View
15 test/spec_rack_lint.rb
@@ -340,6 +340,21 @@ def each
}.should.raise(Rack::Lint::LintError).
message.should.match(/close must not be called/)
end
+
+ specify "notices HEAD errors" do
+ lambda {
+ Rack::Lint.new(lambda { |env|
+ [200, {"Content-type" => "test/plain", "Content-length" => "3"}, []]
+ }).call(env({"REQUEST_METHOD" => "HEAD"}))
+ }.should.not.raise
+
+ lambda {
+ Rack::Lint.new(lambda { |env|
+ [200, {"Content-type" => "test/plain", "Content-length" => "3"}, "foo"]
+ }).call(env({"REQUEST_METHOD" => "HEAD"}))
+ }.should.raise(Rack::Lint::LintError).
+ message.should.match(/body was given for HEAD/)
+ end
end
context "Rack::Lint::InputWrapper" do
Please sign in to comment.
Something went wrong with that request. Please try again.