Browse files

Rack::BodyProxy should execute block even on failures.

In general, Rack frameworks are moving logic to close hooks in order
to support async behavior increasing the chance an exception will
happen on close. Most servers will actually die if there is an exception
on close, but such exceptions can also happen in the test environment.
In such cases, we can accidentally leave a mutex locked, a database
connection not collected and so forth, therefore, we need to ensure
the block is called regardless closing the body failed.
  • Loading branch information...
1 parent 27234d7 commit b06ef82876416fe69429f7d3ee6e51bf26aec75f @josevalim josevalim committed Jan 13, 2012
Showing with 22 additions and 2 deletions.
  1. +5 −2 lib/rack/body_proxy.rb
  2. +17 −0 test/spec_body_proxy.rb
View
7 lib/rack/body_proxy.rb
@@ -11,8 +11,11 @@ def respond_to?(*args)
def close
return if @closed
@closed = true
- @body.close if @body.respond_to? :close
- @block.call
+ begin
+ @body.close if @body.respond_to? :close
+ ensure
+ @block.call
+ end
end
def closed?
View
17 test/spec_body_proxy.rb
@@ -1,4 +1,5 @@
require 'rack/body_proxy'
+require 'stringio'
describe Rack::BodyProxy do
should 'call each on the wrapped body' do
@@ -32,6 +33,22 @@
called.should.equal true
end
+ should 'call the passed block on close even if there is an exception' do
+ object = Object.new
+ def object.close() raise "No!" end
+ called = false
+
+ begin
+ proxy = Rack::BodyProxy.new(object) { called = true }
+ called.should.equal false
+ proxy.close
+ rescue RuntimeError => e
+ end
+
+ raise "Expected exception to have been raised" unless e
+ called.should.equal true
+ end
+
should 'not close more than one time' do
count = 0
proxy = Rack::BodyProxy.new([]) { count += 1; raise "Block invoked more than 1 time!" if count > 1 }

0 comments on commit b06ef82

Please sign in to comment.