1
0
Fork 0
mirror of https://github.com/rest-client/rest-client.git synced 2022-11-09 13:49:40 -05:00

Use built-in Net::HTTP support for compression.

The Net::HTTP in ruby 2.0+ supports gzip and deflate decoding on its
own. Remove Accept-Encoding from the default headers set, and instead
let Net::HTTP take care of it.

Note: this could break compatibility for users who are setting
Accept-Encoding headers themselves or who expect the body to still be
compressed with `:raw_response => true`.
This commit is contained in:
Andy Brody 2017-05-02 13:46:43 -04:00
parent aea752218a
commit 197bb96c94
5 changed files with 36 additions and 65 deletions

View file

@ -505,24 +505,6 @@ module RestClient
cert_store cert_store
end end
def self.decode content_encoding, body
if (!body) || body.empty?
body
elsif content_encoding == 'gzip'
Zlib::GzipReader.new(StringIO.new(body)).read
elsif content_encoding == 'deflate'
begin
Zlib::Inflate.new.inflate body
rescue Zlib::DataError
# No luck with Zlib decompression. Let's try with raw deflate,
# like some broken web servers do.
Zlib::Inflate.new(-Zlib::MAX_WBITS).inflate body
end
else
body
end
end
def redacted_uri def redacted_uri
if uri.password if uri.password
sanitized_uri = uri.dup sanitized_uri = uri.dup
@ -578,10 +560,13 @@ module RestClient
end end
end end
# Default headers set by RestClient. In addition to these headers, servers
# will receive headers set by Net::HTTP, such as Accept-Encoding and Host.
#
# @return [Hash<Symbol, String>]
def default_headers def default_headers
{ {
:accept => '*/*', :accept => '*/*',
:accept_encoding => 'gzip, deflate',
:user_agent => RestClient::Platform.default_user_agent, :user_agent => RestClient::Platform.default_user_agent,
} }
end end
@ -814,11 +799,12 @@ module RestClient
# @param start_time [Time] Time of request start # @param start_time [Time] Time of request start
def process_result(res, start_time, tempfile=nil, &block) def process_result(res, start_time, tempfile=nil, &block)
if @raw_response if @raw_response
# We don't decode raw requests unless tempfile
raise ArgumentError.new('tempfile is required')
end
response = RawResponse.new(tempfile, res, self, start_time) response = RawResponse.new(tempfile, res, self, start_time)
else else
decoded = Request.decode(res['content-encoding'], res.body) response = Response.create(res.body, res, self, start_time)
response = Response.create(decoded, res, self, start_time)
end end
response.log_response response.log_response

View file

@ -83,5 +83,21 @@ describe RestClient::Request do
expect(ex.http_code).to eq 401 expect(ex.http_code).to eq 401
} }
end end
it 'handles gzipped/deflated responses' do
[['gzip', 'gzipped'], ['deflate', 'deflated']].each do |encoding, var|
raw = execute_httpbin(encoding, method: :get)
begin
data = JSON.parse(raw)
rescue
puts "Failed to parse: " + raw.inspect
raise
end
expect(data['method']).to eq 'GET'
expect(data.fetch(var)).to be true
end
end
end end
end end

View file

@ -12,13 +12,6 @@ describe RestClient do
expect(response.body).to eq body expect(response.body).to eq body
end end
it "a simple request with gzipped content" do
stub_request(:get, "www.example.com").with(:headers => { 'Accept-Encoding' => 'gzip, deflate' }).to_return(:body => "\037\213\b\b\006'\252H\000\003t\000\313T\317UH\257\312,HM\341\002\000G\242(\r\v\000\000\000", :status => 200, :headers => { 'Content-Encoding' => 'gzip' } )
response = RestClient.get "www.example.com"
expect(response.code).to eq 200
expect(response.body).to eq "i'm gziped\n"
end
it "a 404" do it "a 404" do
body = "Ho hai ! I'm not here !" body = "Ho hai ! I'm not here !"
stub_request(:get, "www.example.com").to_return(:body => body, :status => 404) stub_request(:get, "www.example.com").to_return(:body => body, :status => 404)

View file

@ -4,20 +4,20 @@ describe RestClient::Request do
context 'params for GET requests' do context 'params for GET requests' do
it "manage params for get requests" do it "manage params for get requests" do
stub_request(:get, 'http://some/resource?a=b&c=d').with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip, deflate', 'Foo'=>'bar'}).to_return(:body => 'foo', :status => 200) stub_request(:get, 'http://some/resource?a=b&c=d').with(:headers => {'Accept'=>'*/*', 'Foo'=>'bar'}).to_return(:body => 'foo', :status => 200)
expect(RestClient::Request.execute(:url => 'http://some/resource', :method => :get, :headers => {:foo => :bar, :params => {:a => :b, 'c' => 'd'}}).body).to eq 'foo' expect(RestClient::Request.execute(:url => 'http://some/resource', :method => :get, :headers => {:foo => :bar, :params => {:a => :b, 'c' => 'd'}}).body).to eq 'foo'
stub_request(:get, 'http://some/resource').with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip, deflate', 'Foo'=>'bar'}).to_return(:body => 'foo', :status => 200) stub_request(:get, 'http://some/resource').with(:headers => {'Accept'=>'*/*', 'Foo'=>'bar'}).to_return(:body => 'foo', :status => 200)
expect(RestClient::Request.execute(:url => 'http://some/resource', :method => :get, :headers => {:foo => :bar, :params => :a}).body).to eq 'foo' expect(RestClient::Request.execute(:url => 'http://some/resource', :method => :get, :headers => {:foo => :bar, :params => :a}).body).to eq 'foo'
end end
it 'adds GET params when params are present in URL' do it 'adds GET params when params are present in URL' do
stub_request(:get, 'http://some/resource?a=b&c=d').with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip, deflate', 'Foo'=>'bar'}).to_return(:body => 'foo', :status => 200) stub_request(:get, 'http://some/resource?a=b&c=d').with(:headers => {'Accept'=>'*/*', 'Foo'=>'bar'}).to_return(:body => 'foo', :status => 200)
expect(RestClient::Request.execute(:url => 'http://some/resource?a=b', :method => :get, :headers => {:foo => :bar, :params => {:c => 'd'}}).body).to eq 'foo' expect(RestClient::Request.execute(:url => 'http://some/resource?a=b', :method => :get, :headers => {:foo => :bar, :params => {:c => 'd'}}).body).to eq 'foo'
end end
it 'encodes nested GET params' do it 'encodes nested GET params' do
stub_request(:get, 'http://some/resource?a[foo][]=1&a[foo][]=2&a[bar]&b=foo+bar&math=2+%2B+2+%3D%3D+4').with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip, deflate'}).to_return(:body => 'foo', :status => 200) stub_request(:get, 'http://some/resource?a[foo][]=1&a[foo][]=2&a[bar]&b=foo+bar&math=2+%2B+2+%3D%3D+4').with(:headers => {'Accept'=>'*/*',}).to_return(:body => 'foo', :status => 200)
expect(RestClient::Request.execute(url: 'http://some/resource', method: :get, headers: { expect(RestClient::Request.execute(url: 'http://some/resource', method: :get, headers: {
params: { params: {
a: { a: {
@ -37,7 +37,7 @@ describe RestClient::Request do
block = proc do |http_response| block = proc do |http_response|
response_value = http_response.body response_value = http_response.body
end end
stub_request(:get, 'http://some/resource?a=b&c=d').with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip, deflate', 'Foo'=>'bar'}).to_return(:body => 'foo', :status => 200) stub_request(:get, 'http://some/resource?a=b&c=d').with(:headers => {'Accept'=>'*/*', 'Foo'=>'bar'}).to_return(:body => 'foo', :status => 200)
RestClient::Request.execute(:url => 'http://some/resource', :method => :get, :headers => {:foo => :bar, :params => {:a => :b, 'c' => 'd'}}, :block_response => block) RestClient::Request.execute(:url => 'http://some/resource', :method => :get, :headers => {:foo => :bar, :params => {:a => :b, 'c' => 'd'}}, :block_response => block)
expect(response_value).to eq "foo" expect(response_value).to eq "foo"
end end
@ -45,7 +45,7 @@ describe RestClient::Request do
it 'closes payload if not nil' do it 'closes payload if not nil' do
test_file = File.new(File.join( File.dirname(File.expand_path(__FILE__)), 'master_shake.jpg')) test_file = File.new(File.join( File.dirname(File.expand_path(__FILE__)), 'master_shake.jpg'))
stub_request(:post, 'http://some/resource').with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip, deflate'}).to_return(:body => 'foo', :status => 200) stub_request(:post, 'http://some/resource').with(:headers => {'Accept'=>'*/*'}).to_return(:body => 'foo', :status => 200)
RestClient::Request.execute(:url => 'http://some/resource', :method => :post, :payload => {:file => test_file}) RestClient::Request.execute(:url => 'http://some/resource', :method => :post, :payload => {:file => test_file})
expect(test_file.closed?).to be true expect(test_file.closed?).to be true

View file

@ -27,30 +27,6 @@ describe RestClient::Request, :include_helpers do
expect(@request.default_headers[:accept]).to eq '*/*' expect(@request.default_headers[:accept]).to eq '*/*'
end end
describe "compression" do
it "decodes an uncompressed result body by passing it straight through" do
expect(RestClient::Request.decode(nil, 'xyz')).to eq 'xyz'
end
it "doesn't fail for nil bodies" do
expect(RestClient::Request.decode('gzip', nil)).to be_nil
end
it "decodes a gzip body" do
expect(RestClient::Request.decode('gzip', "\037\213\b\b\006'\252H\000\003t\000\313T\317UH\257\312,HM\341\002\000G\242(\r\v\000\000\000")).to eq "i'm gziped\n"
end
it "ingores gzip for empty bodies" do
expect(RestClient::Request.decode('gzip', '')).to be_empty
end
it "decodes a deflated body" do
expect(RestClient::Request.decode('deflate', "x\234+\316\317MUHIM\313I,IMQ(I\255(\001\000A\223\006\363")).to eq "some deflated text"
end
end
it "processes a successful result" do it "processes a successful result" do
res = res_double res = res_double
allow(res).to receive(:code).and_return("200") allow(res).to receive(:code).and_return("200")
@ -315,7 +291,7 @@ describe RestClient::Request, :include_helpers do
describe "user headers" do describe "user headers" do
it "merges user headers with the default headers" do it "merges user headers with the default headers" do
expect(@request).to receive(:default_headers).and_return({ :accept => '*/*', :accept_encoding => 'gzip, deflate' }) expect(@request).to receive(:default_headers).and_return({:accept => '*/*'})
headers = @request.make_headers("Accept" => "application/json", :accept_encoding => 'gzip') headers = @request.make_headers("Accept" => "application/json", :accept_encoding => 'gzip')
expect(headers).to have_key "Accept-Encoding" expect(headers).to have_key "Accept-Encoding"
expect(headers["Accept-Encoding"]).to eq "gzip" expect(headers["Accept-Encoding"]).to eq "gzip"
@ -644,25 +620,25 @@ describe RestClient::Request, :include_helpers do
it "logs a get request" do it "logs a get request" do
log = RestClient.log = [] log = RestClient.log = []
RestClient::Request.new(:method => :get, :url => 'http://url', :headers => {:user_agent => 'rest-client'}).log_request RestClient::Request.new(:method => :get, :url => 'http://url', :headers => {:user_agent => 'rest-client'}).log_request
expect(log[0]).to eq %Q{RestClient.get "http://url", "Accept"=>"*/*", "Accept-Encoding"=>"gzip, deflate", "User-Agent"=>"rest-client"\n} expect(log[0]).to eq %Q{RestClient.get "http://url", "Accept"=>"*/*", "User-Agent"=>"rest-client"\n}
end end
it "logs a post request with a small payload" do it "logs a post request with a small payload" do
log = RestClient.log = [] log = RestClient.log = []
RestClient::Request.new(:method => :post, :url => 'http://url', :payload => 'foo', :headers => {:user_agent => 'rest-client'}).log_request RestClient::Request.new(:method => :post, :url => 'http://url', :payload => 'foo', :headers => {:user_agent => 'rest-client'}).log_request
expect(log[0]).to eq %Q{RestClient.post "http://url", "foo", "Accept"=>"*/*", "Accept-Encoding"=>"gzip, deflate", "Content-Length"=>"3", "User-Agent"=>"rest-client"\n} expect(log[0]).to eq %Q{RestClient.post "http://url", "foo", "Accept"=>"*/*", "Content-Length"=>"3", "User-Agent"=>"rest-client"\n}
end end
it "logs a post request with a large payload" do it "logs a post request with a large payload" do
log = RestClient.log = [] log = RestClient.log = []
RestClient::Request.new(:method => :post, :url => 'http://url', :payload => ('x' * 1000), :headers => {:user_agent => 'rest-client'}).log_request RestClient::Request.new(:method => :post, :url => 'http://url', :payload => ('x' * 1000), :headers => {:user_agent => 'rest-client'}).log_request
expect(log[0]).to eq %Q{RestClient.post "http://url", 1000 byte(s) length, "Accept"=>"*/*", "Accept-Encoding"=>"gzip, deflate", "Content-Length"=>"1000", "User-Agent"=>"rest-client"\n} expect(log[0]).to eq %Q{RestClient.post "http://url", 1000 byte(s) length, "Accept"=>"*/*", "Content-Length"=>"1000", "User-Agent"=>"rest-client"\n}
end end
it "logs input headers as a hash" do it "logs input headers as a hash" do
log = RestClient.log = [] log = RestClient.log = []
RestClient::Request.new(:method => :get, :url => 'http://url', :headers => { :accept => 'text/plain', :user_agent => 'rest-client' }).log_request RestClient::Request.new(:method => :get, :url => 'http://url', :headers => { :accept => 'text/plain', :user_agent => 'rest-client' }).log_request
expect(log[0]).to eq %Q{RestClient.get "http://url", "Accept"=>"text/plain", "Accept-Encoding"=>"gzip, deflate", "User-Agent"=>"rest-client"\n} expect(log[0]).to eq %Q{RestClient.get "http://url", "Accept"=>"text/plain", "User-Agent"=>"rest-client"\n}
end end
it "logs a response including the status code, content type, and result body size in bytes" do it "logs a response including the status code, content type, and result body size in bytes" do
@ -695,7 +671,7 @@ describe RestClient::Request, :include_helpers do
it 'does not log request password' do it 'does not log request password' do
log = RestClient.log = [] log = RestClient.log = []
RestClient::Request.new(:method => :get, :url => 'http://user:password@url', :headers => {:user_agent => 'rest-client'}).log_request RestClient::Request.new(:method => :get, :url => 'http://user:password@url', :headers => {:user_agent => 'rest-client'}).log_request
expect(log[0]).to eq %Q{RestClient.get "http://user:REDACTED@url", "Accept"=>"*/*", "Accept-Encoding"=>"gzip, deflate", "User-Agent"=>"rest-client"\n} expect(log[0]).to eq %Q{RestClient.get "http://user:REDACTED@url", "Accept"=>"*/*", "User-Agent"=>"rest-client"\n}
end end
it 'logs to a passed logger, if provided' do it 'logs to a passed logger, if provided' do