summary refs log tree commit
diff options
context:
space:
mode:
authorEugene Kenny <elkenny@gmail.com>2022-07-29 03:48:15 +0100
committerGitHub <noreply@github.com>2022-07-29 14:48:15 +1200
commit0ba88559cd15ffc2b7a0fed7a05d62622349ea6f (patch)
treecf26f1fe73b5673711a23b791cee59a7dad7fe36
parent63ca628d7809758b332021e2f1f9ee69f4252441 (diff)
downloadrack-0ba88559cd15ffc2b7a0fed7a05d62622349ea6f.tar.gz
Don't close body prematurely in Rack::Deflater (#1931)
GzipWriter#close also closes the underlying IO, which in turn closes the
wrapped response body. If that body is a Rack::BodyProxy, the associated
block will run too early, before control has returned to the app server.

GzipWriter#finish closes the gzip stream, but not the underlying IO. The
response body will then be closed by the app server after iteration.
-rw-r--r--lib/rack/deflater.rb2
-rw-r--r--test/spec_deflater.rb9
2 files changed, 10 insertions, 1 deletions
diff --git a/lib/rack/deflater.rb b/lib/rack/deflater.rb
index 3f6177e6..cc01c32a 100644
--- a/lib/rack/deflater.rb
+++ b/lib/rack/deflater.rb
@@ -116,7 +116,7 @@ module Rack
           }
         end
       ensure
-        gzip.close
+        gzip.finish
       end
 
       # Call the block passed to #each with the gzipped data.
diff --git a/test/spec_deflater.rb b/test/spec_deflater.rb
index 6cac22ac..23880eaa 100644
--- a/test/spec_deflater.rb
+++ b/test/spec_deflater.rb
@@ -510,4 +510,13 @@ describe Rack::Deflater do
       raw_bytes.must_be(:<, content.bytesize)
     end
   end
+
+  it 'does not close the response body prematurely' do
+    app_body = Object.new
+    class << app_body; attr_reader :closed; def each; yield('foo'); yield('bar'); end; def close; @closed = true; end; end
+
+    verify(200, 'foobar', deflate_or_gzip, { 'app_body' => app_body }) do |status, headers, body|
+      assert_nil app_body.closed
+    end
+  end
 end