diff options
author | Lenny Marks <lenny@aps.org> | 2014-03-27 16:44:30 -0400 |
---|---|---|
committer | James Tucker <jftucker@gmail.com> | 2014-07-14 21:20:18 -0700 |
commit | ee0e35d7d47412ac71d92222bf8cf0777910057c (patch) | |
tree | 5cf8236279995b6164f9dfdc46ce562865764868 | |
parent | 2f3d6655218c967cf1b20600f701349bdb418bfc (diff) | |
download | rack-ee0e35d7d47412ac71d92222bf8cf0777910057c.tar.gz |
Rack::TempfileReaper
- should do nothing (i.e. not bomb out) without env[rack.tempfiles] - should close env[rack.tempfiles] when body is closed - should initialize env[rack.tempfiles] when not already present - should append env[rack.tempfiles] when already present
-rw-r--r-- | lib/rack.rb | 1 | ||||
-rw-r--r-- | lib/rack/tempfile_reaper.rb | 22 | ||||
-rw-r--r-- | test/spec_tempfile_reaper.rb | 63 |
3 files changed, 86 insertions, 0 deletions
diff --git a/lib/rack.rb b/lib/rack.rb index 57119df3..341514c5 100644 --- a/lib/rack.rb +++ b/lib/rack.rb @@ -53,6 +53,7 @@ module Rack autoload :ShowExceptions, "rack/showexceptions" autoload :ShowStatus, "rack/showstatus" autoload :Static, "rack/static" + autoload :TempfileReaper, "rack/tempfile_reaper" autoload :URLMap, "rack/urlmap" autoload :Utils, "rack/utils" autoload :Multipart, "rack/multipart" diff --git a/lib/rack/tempfile_reaper.rb b/lib/rack/tempfile_reaper.rb new file mode 100644 index 00000000..1500b06a --- /dev/null +++ b/lib/rack/tempfile_reaper.rb @@ -0,0 +1,22 @@ +require 'rack/body_proxy' + +module Rack + + # Middleware tracks and cleans Tempfiles created throughout a request (i.e. Rack::Multipart) + # Ideas/strategy based on posts by Eric Wong and Charles Oliver Nutter + # https://groups.google.com/forum/#!searchin/rack-devel/temp/rack-devel/brK8eh-MByw/sw61oJJCGRMJ + class TempfileReaper + def initialize(app) + @app = app + end + + def call(env) + env['rack.tempfiles'] ||= [] + status, headers, body = @app.call(env) + body_proxy = BodyProxy.new(body) do + env['rack.tempfiles'].each { |f| f.close! } unless env['rack.tempfiles'].nil? + end + [status, headers, body_proxy] + end + end +end diff --git a/test/spec_tempfile_reaper.rb b/test/spec_tempfile_reaper.rb new file mode 100644 index 00000000..ac39d878 --- /dev/null +++ b/test/spec_tempfile_reaper.rb @@ -0,0 +1,63 @@ +require 'rack/tempfile_reaper' +require 'rack/lint' +require 'rack/mock' + +describe Rack::TempfileReaper do + class MockTempfile + attr_reader :closed + + def initialize + @closed = false + end + + def close! + @closed = true + end + end + + before do + @env = Rack::MockRequest.env_for + end + + def call(app) + Rack::Lint.new(Rack::TempfileReaper.new(app)).call(@env) + end + + should 'do nothing (i.e. not bomb out) without env[rack.tempfiles]' do + app = lambda { |_| [200, {}, ['Hello, World!']] } + response = call(app) + response[2].close + response[0].should.equal(200) + end + + should 'close env[rack.tempfiles] when body is closed' do + tempfile1, tempfile2 = MockTempfile.new, MockTempfile.new + @env['rack.tempfiles'] = [ tempfile1, tempfile2 ] + app = lambda { |_| [200, {}, ['Hello, World!']] } + call(app)[2].close + tempfile1.closed.should.equal true + tempfile2.closed.should.equal true + end + + should 'initialize env[rack.tempfiles] when not already present' do + tempfile = MockTempfile.new + app = lambda do |env| + env['rack.tempfiles'] << tempfile + [200, {}, ['Hello, World!']] + end + call(app)[2].close + tempfile.closed.should.equal true + end + + should 'append env[rack.tempfiles] when already present' do + tempfile1, tempfile2 = MockTempfile.new, MockTempfile.new + @env['rack.tempfiles'] = [ tempfile1 ] + app = lambda do |env| + env['rack.tempfiles'] << tempfile2 + [200, {}, ['Hello, World!']] + end + call(app)[2].close + tempfile1.closed.should.equal true + tempfile2.closed.should.equal true + end +end |