[PATCH] deflater: always finish zlib stream before closing

26 views
Skip to first unread message

Eric Wong

unread,
Sep 21, 2015, 5:16:16 PM9/21/15
to rack-...@googlegroups.com
This helps avoid Zlib::DataError when a client disconnects on
the server while the server is writing the response.

This fixes the following backtraces on my server:

data error (Zlib::DataError)
rack/deflater.rb:124:in `close'
rack/deflater.rb:124:in `ensure in each'
rack/deflater.rb:124:in `each'
rack/chunked.rb:23:in `each'
...
---
If you prefer: git pull git://80x24.org/rack zlib-disco

The following changes since commit c28f271d0c91f45e13bfa8f07bed445ef91f41de:

Merge pull request #942 from keepcosmos/remove-fulltest-guide (2015-09-08 07:45:02 -0700)

are available in the git repository at:

git://80x24.org/rack zlib-disco

for you to fetch changes up to f769efe714f5b8b417e0440ce05f8b4e4b504c57:

deflater: always finish zlib stream before closing (2015-09-21 21:11:50 +0000)

----------------------------------------------------------------
Eric Wong (1):
deflater: always finish zlib stream before closing

lib/rack/deflater.rb | 3 ++-
test/spec_deflater.rb | 25 +++++++++++++++++++++++++
2 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/lib/rack/deflater.rb b/lib/rack/deflater.rb
index 19dc755..62a1124 100644
--- a/lib/rack/deflater.rb
+++ b/lib/rack/deflater.rb
@@ -118,8 +118,9 @@ module Rack
def each
deflator = ::Zlib::Deflate.new(*DEFLATE_ARGS)
@body.each { |part| yield deflator.deflate(part, Zlib::SYNC_FLUSH) }
- yield deflator.finish
+ yield fin = deflator.finish
ensure
+ deflator.finish unless fin
deflator.close
end

diff --git a/test/spec_deflater.rb b/test/spec_deflater.rb
index 2c7a428..ba7ec5d 100644
--- a/test/spec_deflater.rb
+++ b/test/spec_deflater.rb
@@ -114,6 +114,31 @@ describe Rack::Deflater do
end
end

+ it 'does not raise when a client aborts reading' do
+ app_body = Object.new
+ class << app_body; def each; yield('foo'); yield('bar'); end; end
+ opts = { 'skip_body_verify' => true }
+ verify(200, app_body, 'deflate', opts) do |status, headers, body|
+ headers.must_equal({
+ 'Content-Encoding' => 'deflate',
+ 'Vary' => 'Accept-Encoding',
+ 'Content-Type' => 'text/plain'
+ })
+
+ buf = []
+ inflater = Zlib::Inflate.new(-Zlib::MAX_WBITS)
+ FakeDisconnect = Class.new(RuntimeError)
+ assert_raises(FakeDisconnect, "not Zlib::DataError not raised") do
+ body.each do |part|
+ buf << inflater.inflate(part)
+ raise FakeDisconnect
+ end
+ end
+ assert_raises(Zlib::BufError) { inflater.finish }
+ buf.must_equal(%w(foo))
+ end
+ end
+
# TODO: This is really just a special case of the above...
it 'be able to deflate String bodies' do
verify(200, 'Hello world!', 'deflate') do |status, headers, body|
--
EW

Aaron Patterson

unread,
Sep 21, 2015, 5:50:40 PM9/21/15
to Eric Wong, rack-...@googlegroups.com
Applied, thanks!
> --
>
> ---
> You received this message because you are subscribed to the Google Groups "Rack Development" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to rack-devel+...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

--
Aaron Patterson
http://tenderlovemaking.com/
Reply all
Reply to author
Forward
0 new messages