Project

General

Profile

Feature #6492 » net.http.inflate_by_default.patch

drbrain (Eric Hodel), 05/25/2012 09:15 AM

View differences:

lib/net/http/response.rb (working copy)
private
##
# Checks for a supported Content-Encoding header and returns the Inflate
# wrapper for this response's socket when zlib is present. If the
# Content-Encoding is unsupported or zlib is missing the plain socket is
# returned.
def inflater # :nodoc:
return @socket unless Net::HTTP::HAVE_ZLIB
case self['content-encoding']
when 'deflate', 'gzip', 'x-gzip' then
self.delete 'content-encoding'
Inflater.new @socket
when 'none', 'identity' then
self.delete 'content-encoding'
@socket
else
@socket
end
end
def read_body_0(dest)
if chunked?
read_chunked dest
read_chunked dest, inflater
return
end
@socket = inflater
clen = content_length()
if clen
@socket.read clen, dest, true # ignore EOF
......
return
end
@socket.read_all dest
ensure
@socket.finish if Inflater === @socket
end
def read_chunked(dest)
def read_chunked(dest, inflater)
len = nil
total = 0
while true
......
len = hexlen.hex
break if len == 0
begin
@socket.read len, dest
inflater.read len, dest
ensure
total += len
@socket.read 2 # \r\n
......
end
def procdest(dest, block)
raise ArgumentError, 'both arg and block given for HTTP method' \
if dest and block
raise ArgumentError, 'both arg and block given for HTTP method' if
dest and block
if block
Net::ReadAdapter.new(block)
else
......
end
end
##
# Inflater is a wrapper around Net::BufferedIO that transparently inflates
# zlib and gzip streams.
class Inflater # :nodoc:
##
# Creates a new Inflater wrapping +socket+
def initialize socket
@socket = socket
# zlib with automatic gzip detection
@inflate = Zlib::Inflate.new(32 + Zlib::MAX_WBITS)
end
##
# Reads +clen+ bytes from the socket, inflates them, then writes them to
# +dest+. +ignore_eof+ is passed down to Net::BufferedIO#read
def read clen, dest, ignore_eof = false
temp_dest = ''
@socket.read clen, temp_dest, ignore_eof
dest << @inflate.inflate(temp_dest)
end
##
# Reads the rest of the socket, inflates it, then writes it to +dest+.
def read_all dest
temp_dest = ''
@socket.read_all temp_dest
dest << @inflate.inflate(temp_dest)
end
##
# Finishes the inflate stream.
def finish
@inflate.finish
end
end
end
lib/net/http.rb (working copy)
@use_ssl = false
@ssl_context = nil
@enable_post_connection_check = true
@compression = nil
@sspi_enabled = false
SSL_IVNAMES.each do |ivname|
instance_variable_set ivname, nil
......
initheader = initheader.merge({
"accept-encoding" => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3"
})
@compression = true
end
end
request(Get.new(path, initheader)) {|r|
if r.key?("content-encoding") and @compression
@compression = nil # Clear it till next set.
the_body = r.read_body dest, &block
case r["content-encoding"]
when "gzip"
r.body= Zlib::GzipReader.new(StringIO.new(the_body), encoding: "ASCII-8BIT").read
r.delete("content-encoding")
when "deflate"
r.body= Zlib::Inflate.inflate(the_body);
r.delete("content-encoding")
when "identity"
; # nothing needed
else
; # Don't do anything dramatic, unless we need to later
end
else
r.read_body dest, &block
end
r.read_body dest, &block
res = r
}
res
test/net/http/test_httpresponse.rb (working copy)
class HTTPResponseTest < Test::Unit::TestCase
def test_singleline_header
io = dummy_io(<<EOS.gsub(/\n/, "\r\n"))
io = dummy_io(<<EOS)
HTTP/1.1 200 OK
Content-Length: 5
Connection: close
......
end
def test_multiline_header
io = dummy_io(<<EOS.gsub(/\n/, "\r\n"))
io = dummy_io(<<EOS)
HTTP/1.1 200 OK
X-Foo: XXX
YYY
......
assert_equal('XXX YYY', res.header['x-bar'])
end
def test_read_body
io = dummy_io(<<EOS)
HTTP/1.1 200 OK
Connection: close
Content-Length: 5
hello
EOS
res = Net::HTTPResponse.read_new(io)
body = nil
res.reading_body io, true do
body = res.read_body
end
assert_equal 'hello', body
end
def test_read_body_block
io = dummy_io(<<EOS)
HTTP/1.1 200 OK
Connection: close
Content-Length: 5
hello
EOS
res = Net::HTTPResponse.read_new(io)
body = ''
res.reading_body io, true do
res.read_body do |chunk|
body << chunk
end
end
assert_equal 'hello', body
end
def test_read_body_content_encoding_deflate
io = dummy_io(<<EOS)
HTTP/1.1 200 OK
Connection: close
Content-Encoding: deflate
Content-Length: 13
x\x9C\xCBH\xCD\xC9\xC9\a\x00\x06,\x02\x15
EOS
res = Net::HTTPResponse.read_new(io)
body = nil
res.reading_body io, true do
body = res.read_body
end
assert_equal 'hello', body
end
def test_read_body_content_encoding_deflate_chunked
io = dummy_io(<<EOS)
HTTP/1.1 200 OK
Connection: close
Content-Encoding: deflate
Transfer-Encoding: chunked
6
x\x9C\xCBH\xCD\xC9
7
\xC9\a\x00\x06,\x02\x15
0
EOS
res = Net::HTTPResponse.read_new(io)
body = nil
res.reading_body io, true do
body = res.read_body
end
assert_equal 'hello', body
end
def test_read_body_content_encoding_deflate_no_length
io = dummy_io(<<EOS)
HTTP/1.1 200 OK
Connection: close
Content-Encoding: deflate
x\x9C\xCBH\xCD\xC9\xC9\a\x00\x06,\x02\x15
EOS
res = Net::HTTPResponse.read_new(io)
body = nil
res.reading_body io, true do
body = res.read_body
end
assert_equal 'hello', body
end
def test_read_body_string
io = dummy_io(<<EOS)
HTTP/1.1 200 OK
Connection: close
Content-Length: 5
hello
EOS
res = Net::HTTPResponse.read_new(io)
body = ''
res.reading_body io, true do
res.read_body body
end
assert_equal 'hello', body
end
private
def dummy_io(str)
str = str.gsub(/\n/, "\r\n")
Net::BufferedIO.new(StringIO.new(str))
end
end
(1-1/4)