Skip to content

Commit

Permalink
Add a Gzip middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
romanbsd committed Mar 8, 2014
1 parent 5a19d04 commit b7ef6e9
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 1 deletion.
4 changes: 3 additions & 1 deletion lib/faraday_middleware.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ module FaradayMiddleware
autoload :RackCompatible, 'faraday_middleware/rack_compatible'
autoload :FollowRedirects, 'faraday_middleware/response/follow_redirects'
autoload :Instrumentation, 'faraday_middleware/instrumentation'
autoload :Gzip, 'faraday_middleware/gzip'

if Faraday.respond_to? :register_middleware
Faraday.register_middleware :request,
Expand All @@ -39,7 +40,8 @@ module FaradayMiddleware
:chunked => lambda { Chunked }

Faraday.register_middleware \
:instrumentation => lambda { Instrumentation }
:instrumentation => lambda { Instrumentation },
:gzip => lambda { Gzip }
end
end

Expand Down
45 changes: 45 additions & 0 deletions lib/faraday_middleware/gzip.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
require 'faraday'

module FaradayMiddleware
# A middleware that ensures that the client requests are sent with the
# headers that encourage servers to send compressed data, and then uncompresses it.
# The Content-Length will reflect the actual body length.
class Gzip < Faraday::Middleware
dependency 'zlib'

ACCEPT_ENCODING = 'Accept-Encoding'.freeze
ENCODINGS = 'gzip,deflate'.freeze

def initialize(app, options = nil)
@app = app
end

def call(env)
(env[:request_headers] ||= {})[ACCEPT_ENCODING] = ENCODINGS
@app.call(env).on_complete do |env|
encoding = env[:response_headers]['content-encoding'].to_s.downcase
if %w[gzip deflate].include?(encoding)
case encoding
when 'gzip'
env[:body] = uncompress_gzip(env[:body])
when 'deflate'
env[:body] = Zlib::Inflate.inflate(env[:body])
end
env[:response_headers].delete('content-encoding')
env[:response_headers]['content-length'] = env[:body].length
end
end
end

private
def uncompress_gzip(body)
io = StringIO.new(body)
gzip_reader = if '1.9'.respond_to?(:force_encoding)
Zlib::GzipReader.new(io, :encoding => 'ASCII-8BIT')
else
Zlib::GzipReader.new(io)
end
gzip_reader.read
end
end
end
67 changes: 67 additions & 0 deletions spec/gzip_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
require 'helper'
require 'faraday_middleware/gzip'

describe FaradayMiddleware::Gzip do

context 'request' do
let(:middleware) { described_class.new(lambda {|env| Faraday::Response.new(env)}) }

it 'sets the Accept-Encoding header' do
headers = Faraday::Utils::Headers.new
env = {:body => nil, :request_headers => headers, :response_headers => Faraday::Utils::Headers.new}
expect { middleware.call(env) }.to change {
headers['Accept-Encoding']
}.to('gzip,deflate')
end
end

context 'response', :type => :response do
let(:uncompressed_body) {
"<html><head><title>Rspec</title></head><body>Hello, spec!</body></html>"
}

shared_examples 'compressed response' do
it 'uncompresses the body' do
expect(process(body).body).to eq(uncompressed_body)
end

it 'sets the Content-Length' do
expect(process(body).headers['Content-Length']).to eq(uncompressed_body.length)
end

it 'removes the Content-Encoding' do
expect(process(body).headers['Content-Encoding']).to be_nil
end
end

context 'gzipped response' do
let(:body) do
f = StringIO.new
gz = Zlib::GzipWriter.new(f)
gz.write(uncompressed_body)
gz.close
res = f.string
res.force_encoding('BINARY') if res.respond_to?(:force_encoding)
res
end
let(:headers) { {'Content-Encoding' => 'gzip', 'Content-Length' => body.length} }

it_behaves_like 'compressed response'
end

context 'deflated response' do
let(:body) { Zlib::Deflate.deflate(uncompressed_body) }
let(:headers) { {'Content-Encoding' => 'deflate', 'Content-Length' => body.length} }

it_behaves_like 'compressed response'
end

context 'identity response' do
let(:body) { uncompressed_body }

it 'does not modify the body' do
expect(process(body).body).to eq(uncompressed_body)
end
end
end
end

0 comments on commit b7ef6e9

Please sign in to comment.