Not a serious patch for now, at least not all of it.
I suspect middlewares will break badly if the body.each/body.close
checks are enforced.
---
lib/rack/lint.rb | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/lib/rack/lint.rb b/lib/rack/lint.rb
index 1bc2127..f895772 100644
--- a/lib/rack/lint.rb
+++ b/lib/rack/lint.rb
@@ -9,6 +9,7 @@ class Lint
def initialize(app)
@app = app
@content_length = nil
+ @response_hijacked = false
end
# :stopdoc:
@@ -47,6 +48,15 @@ def _call(env)
## and returns an Array of exactly three values:
status, headers, @body = @app.call(env)
+
+ # hijacked requests may not give a valid response, do not check them
+ if env.include?("rack.hijack_io")
+ # request hijacking implies response hijacking, this will ensure
+ # the response body raises if body.each or body.close gets called
+ @response_hijacked = true
+ return [ status, headers, self ]
+ end
+
## The *status*,
check_status status
## the *headers*,
@@ -530,6 +540,7 @@ def check_hijack_response(headers, env)
headers['rack.hijack'] = proc do |io|
original_hijack.call HijackWrapper.new(io)
end
+ @response_hijacked = true
else
##
## The special response header <tt>rack.hijack</tt> must only be set
@@ -636,6 +647,9 @@ def verify_content_length(bytes)
## === The Body
def each
+ assert("server is not attempting to iterate hijacked response body") {
+ @response_hijacked == false
+ }
@closed = false
bytes = 0
@@ -683,6 +697,9 @@ def each
end
def close
+ assert("server is not attempting to close hijacked response") {
+ @response_hijacked == false
+ }
@closed = true
@body.close if @body.respond_to?(:close)
end
--
Eric Wong