Created
November 17, 2010 01:20
-
-
Save Teshootub7/702845 to your computer and use it in GitHub Desktop.
Patch to add gzip support for httpclient
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/lib/httpclient.rb b/lib/httpclient.rb | |
index 11a4da4..475fa51 100644 | |
--- a/lib/httpclient.rb | |
+++ b/lib/httpclient.rb | |
@@ -317,6 +317,8 @@ class HTTPClient | |
# An array of response HTTP String (not a HTTP message body) which is used | |
# for loopback test. See test/* to see how to use it. | |
attr_proxy(:test_loopback_http_response) | |
+ # Decompress a compressed (with gzip or deflate) content body transparently. false by default. | |
+ attr_proxy(:transparent_gzip_decompression, true) | |
# Default extheader for PROPFIND request. | |
PROPFIND_DEFAULT_EXTHEADER = { 'Depth' => '0' } | |
diff --git a/lib/httpclient/session.rb b/lib/httpclient/session.rb | |
index 16ab037..ac8ef59 100644 | |
--- a/lib/httpclient/session.rb | |
+++ b/lib/httpclient/session.rb | |
@@ -13,6 +13,7 @@ | |
require 'socket' | |
require 'thread' | |
require 'stringio' | |
+require 'zlib' | |
require 'httpclient/timeout' | |
require 'httpclient/ssl_config' | |
@@ -106,6 +107,8 @@ class HTTPClient | |
attr_reader :test_loopback_http_response | |
+ attr_accessor :transparent_gzip_decompression | |
+ | |
def initialize(client) | |
@client = client | |
@proxy = client.proxy | |
@@ -128,6 +131,8 @@ class HTTPClient | |
@ssl_config = nil | |
@test_loopback_http_response = [] | |
+ @transparent_gzip_decompression = false | |
+ | |
@sess_pool = [] | |
@sess_pool_mutex = Mutex.new | |
end | |
@@ -185,6 +190,7 @@ class HTTPClient | |
sess.ssl_config = @ssl_config | |
sess.debug_dev = @debug_dev | |
sess.test_loopback_http_response = @test_loopback_http_response | |
+ sess.transparent_gzip_decompression = @transparent_gzip_decompression | |
end | |
sess | |
end | |
@@ -482,6 +488,8 @@ class HTTPClient | |
attr_reader :ssl_peer_cert | |
attr_accessor :test_loopback_http_response | |
+ attr_accessor :transparent_gzip_decompression | |
+ | |
def initialize(client, dest, agent_name, from) | |
@client = client | |
@dest = dest | |
@@ -515,6 +523,8 @@ class HTTPClient | |
@socket = nil | |
@readbuf = nil | |
+ | |
+ @transparent_gzip_decompression = false | |
end | |
# Send a request to the server | |
@@ -586,6 +596,20 @@ class HTTPClient | |
begin | |
read_header if @state == :META | |
return nil if @state != :DATA | |
+ if @gzipped and @transparent_gzip_decompression | |
+ # zlib itself has a functionality to decompress gzip stream. | |
+ # - zlib 1.2.5 Manual | |
+ # http://www.zlib.net/manual.html#Advanced | |
+ # > windowBits can also be greater than 15 for optional gzip decoding. Add 32 to | |
+ # > windowBits to enable zlib and gzip decoding with automatic header detection, | |
+ # > or add 16 to decode only the gzip format | |
+ inflate_stream = Zlib::Inflate.new( Zlib::MAX_WBITS + 32 ) | |
+ original_block = block | |
+ block = Proc.new do | |
+ |buf| | |
+ original_block.call( inflate_stream.inflate( buf ) ) | |
+ end | |
+ end | |
if @chunked | |
read_body_chunked(&block) | |
elsif @content_length | |
@@ -621,6 +645,9 @@ class HTTPClient | |
if @from | |
req.header.set('From', @from) | |
end | |
+ if @transparent_gzip_decompression | |
+ req.header.set('Accept-Encoding', 'gzip,deflate') | |
+ end | |
req.header.set('Date', Time.now.httpdate) | |
end | |
@@ -724,6 +751,7 @@ class HTTPClient | |
def read_header | |
@content_length = nil | |
@chunked = false | |
+ @gzipped = false | |
@chunk_length = 0 | |
parse_header | |
# Header of the request has been parsed. | |
@@ -798,6 +826,9 @@ class HTTPClient | |
key = key.downcase | |
if key == 'content-length' | |
@content_length = value.to_i | |
+ elsif key == 'content-encoding' and ( value.downcase == 'gzip' or | |
+ value.downcase == 'x-gzip' or value.downcase == 'deflate' ) | |
+ @gzipped = true | |
elsif key == 'transfer-encoding' and value.downcase == 'chunked' | |
@chunked = true | |
@chunk_length = 0 | |
diff --git a/test/test_httpclient.rb b/test/test_httpclient.rb | |
index 94129c2..26286b2 100644 | |
--- a/test/test_httpclient.rb | |
+++ b/test/test_httpclient.rb | |
@@ -472,6 +472,17 @@ EOS | |
assert(called) | |
end | |
+ def test_get_gzipped_content | |
+ @client.transparent_gzip_decompression = false | |
+ assert_not_equal('hello', @client.get_content(@url + 'compressed?enc=gzip')) | |
+ assert_equal("\x1f\x8b\x08\x00\x1a\x96\xe0\x4c\x00\x03\xcb\x48\xcd\xc9\xc9\x07\x00\x86\xa6\x10\x36\x05\x00\x00\x00", | |
+ @client.get_content(@url + 'compressed?enc=gzip')) | |
+ @client.transparent_gzip_decompression = true | |
+ assert_equal('hello', @client.get_content(@url + 'compressed?enc=gzip')) | |
+ assert_equal('hello', @client.get_content(@url + 'compressed?enc=deflate')) | |
+ @client.transparent_gzip_decompression = false | |
+ end | |
+ | |
def test_get_content_with_block | |
@client.get_content(@url + 'hello') do |str| | |
assert_equal('hello', str) | |
@@ -1119,7 +1130,7 @@ private | |
:AccessLog => [], | |
:DocumentRoot => File.dirname(File.expand_path(__FILE__)) | |
) | |
- [:hello, :sleep, :servlet_redirect, :redirect1, :redirect2, :redirect3, :redirect_self, :relative_redirect, :chunked, :largebody, :status].each do |sym| | |
+ [:hello, :sleep, :servlet_redirect, :redirect1, :redirect2, :redirect3, :redirect_self, :relative_redirect, :chunked, :largebody, :status, :compressed].each do |sym| | |
@server.mount( | |
"/#{sym}", | |
WEBrick::HTTPServlet::ProcHandler.new(method("do_#{sym}").to_proc) | |
@@ -1236,6 +1247,16 @@ private | |
res.body = "a" * 1000 * 1000 | |
end | |
+ def do_compressed(req, res) | |
+ if req.query['enc'] == 'gzip' | |
+ res['content-encoding'] = 'gzip' | |
+ res.body = "\x1f\x8b\x08\x00\x1a\x96\xe0\x4c\x00\x03\xcb\x48\xcd\xc9\xc9\x07\x00\x86\xa6\x10\x36\x05\x00\x00\x00" | |
+ elsif req.query['enc'] == 'deflate' | |
+ res['content-encoding'] = 'deflate' | |
+ res.body = "\x78\x9c\xcb\x48\xcd\xc9\xc9\x07\x00\x06\x2c\x02\x15" | |
+ end | |
+ end | |
+ | |
def do_status(req, res) | |
res.status = req.query['status'].to_i | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment