faraday-gzip 2.0.1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 44ad7c4e9c57927b182f8da9719aeb71455cd664607582af5be4440d660c9015
4
- data.tar.gz: cfd6528ad8d82ce76f1b62cddbd63e2af086dab192a62c1dc14e6603ae5f5a18
3
+ metadata.gz: c547f7957c575bd7890701209c77e2cde7efb0f4375ccb5d27d279d3683d8864
4
+ data.tar.gz: f85480f1c243cd5f23f608b5b1086b88236d1859272f8d726f974a4aca6d4522
5
5
  SHA512:
6
- metadata.gz: 61a096ffcf59316c2c7a1e9be64f159e879887a4a56dbfe495268d4c70a7636944885307277dd62c1a705df063676a6526921a65d01a0436cf01331349a01828
7
- data.tar.gz: 174bd0148dfcdc7e33acddb9c086629b37f8179905081c45ea4c35fb2e916c6f07c994a8065fce6b900aca34de1624e162330b185766f8c18a9d3edb6098c6f3
6
+ metadata.gz: 673a7119d69404b34f0f781add8234f5740eaa60fd51b50c094fbe74bff4171f5a60bd80d5c45df0190cb534fc30d223a836e7fa67f603318019d64b2bf8c7f2
7
+ data.tar.gz: c8fc4695719ab535d64e41e10cbea2d6a18656014ffb290959c2e8f2bd1fbe9f3040fcf8bacd68e26f260e1de029e71b997c1584372d45be8e042bd2f923c7a2
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.0.0 (29-Oct-2024)
4
+
5
+ * **Breaking change**: Drop support for Ruby 2, require 3.0+
6
+ * **Breaking change**: Drop support for Faraday v1. If you need to support Faraday v1, stay on [faraday-gzip version 2](https://github.com/bodrovis/faraday-gzip/tree/v2).
7
+ * Various code tweaks
8
+ * Remove JRuby 9.3 from CI matrix
9
+
3
10
  ## 2.0.1 (02-Jan-2024)
4
11
 
5
12
  * Handle cases when body is `nil` (thanks, @bendangelo)
data/README.md CHANGED
@@ -2,54 +2,58 @@
2
2
 
3
3
  ![CI](https://github.com/bodrovis/faraday-gzip/actions/workflows/ci.yaml/badge.svg)
4
4
  [![Gem](https://img.shields.io/gem/v/faraday-gzip.svg?style=flat-square)](https://rubygems.org/gems/faraday-gzip)
5
+ ![Gem Total Downloads](https://img.shields.io/gem/dt/faraday-gzip)
5
6
 
6
- The `Gzip` middleware for Faraday 1 and 2 adds the necessary `Accept-Encoding` headers and automatically decompresses the response. If the "Accept-Encoding" header wasn't set in the request, this sets it to "gzip,deflate" and appropriately handles the compressed response from the server. This resembles what Ruby does internally in Net::HTTP#get. If [Brotli](https://github.com/miyucy/brotli) is added to the Gemfile, it will also add "br" to the header.
7
+ The `Gzip` middleware for Faraday 1 and 2 adds the necessary `Accept-Encoding` headers and automatically decompresses the response. If the "Accept-Encoding" header isn't set in the request, it defaults to `gzip,deflate` and appropriately handles the server's compressed response. This functionality resembles what Ruby does internally in `Net::HTTP#get`. If [Brotli](https://github.com/miyucy/brotli) is included in your Gemfile, the middleware also adds `br` to the header for Brotli support.
7
8
 
8
9
  ## Prerequisites
9
10
 
10
- This gem is tested with Ruby 2.6+ and JRuby 9.3+. Faraday 1 and 2 is supported.
11
+ * faraday-gzip v3 supports only Faraday v2 and is tested with Ruby 3.0+ and JRuby 9.4
12
+ * [faraday-gzip v2](https://github.com/bodrovis/faraday-gzip/tree/v2) supports Faraday v1 and v2 and is tested with Ruby 2.7+ and JRuby 9.4.
11
13
 
12
14
  ## Installation
13
15
 
14
16
  Add this line to your application's Gemfile:
15
17
 
16
18
  ```ruby
17
- gem 'faraday-gzip'
19
+ gem 'faraday-gzip', '~> 3'
18
20
  ```
19
21
 
20
22
  And then execute:
21
23
 
22
- ```shell
24
+ ```
23
25
  bundle install
24
26
  ```
25
27
 
26
28
  Or install it yourself as:
27
29
 
28
- ```shell
30
+ ```
29
31
  gem install faraday-gzip
30
32
  ```
31
33
 
32
34
  ## Usage
33
35
 
36
+ To enable the middleware in your Faraday connection, add it as shown below:
37
+
34
38
  ```ruby
35
- require 'faraday/gzip' # <=== add this line
39
+ require 'faraday/gzip' # <=== Add this line
36
40
 
37
41
  conn = Faraday.new(...) do |f|
38
- f.request :gzip # <=== add this line
39
- #...
42
+ f.request :gzip # <=== Add this line
43
+ # Additional configuration...
40
44
  end
41
45
  ```
42
46
 
43
47
  ## Development
44
48
 
45
- After checking out the repo, run `bin/setup` to install dependencies.
46
-
47
- Then, run `bin/test` to run the tests.
48
-
49
- To install this gem onto your local machine, run `rake build`.
49
+ To contribute or make changes:
50
50
 
51
- To release a new version, make a commit with a message such as "Bumped to 0.0.2" and then run `rake release`.
52
- See how it works [here](https://bundler.io/guides/creating_gem.html#releasing-the-gem).
51
+ * Clone the repo
52
+ * Run `bundle` to install dependencies
53
+ * Implement your feature
54
+ * Write and run tests using `rspec .`
55
+ * Use rake build to build the gem locally if needed
56
+ * Create a new PR with your changes
53
57
 
54
58
  ## Contributing
55
59
 
@@ -57,4 +61,4 @@ Bug reports and pull requests are welcome on GitHub.
57
61
 
58
62
  ## License
59
63
 
60
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
64
+ This gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -2,15 +2,17 @@
2
2
 
3
3
  require 'zlib'
4
4
 
5
+ # Middleware to automatically decompress response bodies. If the
6
+ # "Accept-Encoding" header wasn't set in the request, this sets it to
7
+ # "gzip,deflate" and appropriately handles the compressed response from the
8
+ # server. This resembles what Ruby 1.9+ does internally in Net::HTTP#get.
9
+ # Based on https://github.com/lostisland/faraday_middleware/blob/main/lib/faraday_middleware/gzip.rb
5
10
  module Faraday
11
+ # Main module
6
12
  module Gzip
7
- # Middleware to automatically decompress response bodies. If the
8
- # "Accept-Encoding" header wasn't set in the request, this sets it to
9
- # "gzip,deflate" and appropriately handles the compressed response from the
10
- # server. This resembles what Ruby 1.9+ does internally in Net::HTTP#get.
11
- # Based on https://github.com/lostisland/faraday_middleware/blob/main/lib/faraday_middleware/gzip.rb
12
-
13
+ # Faraday middleware for decompression
13
14
  class Middleware < Faraday::Middleware
15
+ # System method required by Faraday
14
16
  def self.optional_dependency(lib = nil)
15
17
  lib ? require(lib) : yield
16
18
  true
@@ -20,6 +22,8 @@ module Faraday
20
22
 
21
23
  BROTLI_SUPPORTED = optional_dependency 'brotli'
22
24
 
25
+ # Returns supported encodings, adds brotli if the corresponding
26
+ # dependency is present
23
27
  def self.supported_encodings
24
28
  encodings = %w[gzip deflate]
25
29
  encodings << 'br' if BROTLI_SUPPORTED
@@ -31,37 +35,42 @@ module Faraday
31
35
  CONTENT_LENGTH = 'Content-Length'
32
36
  SUPPORTED_ENCODINGS = supported_encodings.join(',').freeze
33
37
 
38
+ # Main method to process the response
34
39
  def call(env)
35
40
  env[:request_headers][ACCEPT_ENCODING] ||= SUPPORTED_ENCODINGS
41
+
36
42
  @app.call(env).on_complete do |response_env|
37
- if empty_body?(response_env)
38
- reset_body(response_env) { |body| raw_body(body) }
39
- else
40
- case response_env[:response_headers][CONTENT_ENCODING]
41
- when 'gzip'
42
- reset_body(response_env) { |body| uncompress_gzip(body) }
43
- when 'deflate'
44
- reset_body(response_env) { |body| inflate(body) }
45
- when 'br'
46
- reset_body(response_env) { |body| brotli_inflate(body) }
47
- end
48
- end
43
+ reset_body(response_env, find_processor(response_env))
44
+ end
45
+ end
46
+
47
+ # Finds a proper processor
48
+ def find_processor(response_env)
49
+ if empty_body?(response_env)
50
+ ->(body) { raw_body(body) }
51
+ else
52
+ processors[response_env[:response_headers][CONTENT_ENCODING]]
49
53
  end
50
54
  end
51
55
 
52
- def reset_body(env)
53
- env[:body] = yield(env[:body])
56
+ # Calls the proper processor to decompress body
57
+ def reset_body(env, processor)
58
+ return if processor.nil?
59
+
60
+ env[:body] = processor.call(env[:body])
54
61
  env[:response_headers].delete(CONTENT_ENCODING)
55
62
 
56
63
  env[:response_headers][CONTENT_LENGTH] = env[:body].nil? ? 0 : env[:body].length
57
64
  end
58
65
 
66
+ # Process gzip
59
67
  def uncompress_gzip(body)
60
68
  io = StringIO.new(body)
61
69
  gzip_reader = Zlib::GzipReader.new(io, encoding: 'ASCII-8BIT')
62
70
  gzip_reader.read
63
71
  end
64
72
 
73
+ # Process deflate
65
74
  def inflate(body)
66
75
  # Inflate as a DEFLATE (RFC 1950+RFC 1951) stream
67
76
  Zlib::Inflate.inflate(body)
@@ -76,10 +85,12 @@ module Faraday
76
85
  end
77
86
  end
78
87
 
88
+ # Process brotli
79
89
  def brotli_inflate(body)
80
90
  Brotli.inflate(body)
81
91
  end
82
92
 
93
+ # Do not process anything, leave body as is
83
94
  def raw_body(body)
84
95
  body
85
96
  end
@@ -89,6 +100,15 @@ module Faraday
89
100
  def empty_body?(response_env)
90
101
  response_env[:body].nil? || response_env[:body].empty?
91
102
  end
103
+
104
+ # Method providing the processors
105
+ def processors
106
+ {
107
+ 'gzip' => ->(body) { uncompress_gzip(body) },
108
+ 'deflate' => ->(body) { inflate(body) },
109
+ 'br' => ->(body) { brotli_inflate(body) }
110
+ }
111
+ end
92
112
  end
93
113
  end
94
114
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Faraday
4
4
  module Gzip
5
- VERSION = '2.0.1'
5
+ VERSION = '3.0.0'
6
6
  end
7
7
  end
@@ -0,0 +1,179 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Faraday::Gzip::Middleware do
4
+ require 'brotli' if Faraday::Gzip::Middleware::BROTLI_SUPPORTED
5
+
6
+ subject(:middleware) do
7
+ described_class.new(->(env) { Faraday::Response.new(env) })
8
+ end
9
+
10
+ let(:headers) { {} }
11
+
12
+ def process(body, content_type = nil, options = {})
13
+ env = {
14
+ body: body, request: options,
15
+ request_headers: Faraday::Utils::Headers.new,
16
+ response_headers: Faraday::Utils::Headers.new(headers)
17
+ }
18
+ env[:response_headers]['content-type'] = content_type if content_type
19
+ yield(env) if block_given?
20
+ middleware.call(env)
21
+ end
22
+
23
+ context 'when request' do
24
+ it 'sets the Accept-Encoding request header' do
25
+ env = process('').env
26
+ encodings = Faraday::Gzip::Middleware::BROTLI_SUPPORTED ? 'gzip,deflate,br' : 'gzip,deflate'
27
+ expect(env[:request_headers][:accept_encoding]).to eq(encodings)
28
+ end
29
+
30
+ it 'doesnt overwrite existing Accept-Encoding request header' do
31
+ env = process('') do |e|
32
+ e[:request_headers][:accept_encoding] = 'zopfli'
33
+ end.env
34
+ expect(env[:request_headers][:accept_encoding]).to eq('zopfli')
35
+ end
36
+ end
37
+
38
+ context 'when response' do
39
+ let(:uncompressed_body) do
40
+ '<html><head><title>Rspec</title></head><body>Hello, spec!</body></html>'
41
+ end
42
+ let(:empty_body) { '' }
43
+ let(:gzipped_body) do
44
+ io = StringIO.new
45
+ gz = Zlib::GzipWriter.new(io)
46
+ gz.write(uncompressed_body)
47
+ gz.close
48
+ res = io.string
49
+ res.force_encoding('BINARY')
50
+ res
51
+ end
52
+ let(:deflated_body) do
53
+ Zlib::Deflate.deflate(uncompressed_body)
54
+ end
55
+ let(:raw_deflated_body) do
56
+ z = Zlib::Deflate.new(Zlib::DEFAULT_COMPRESSION, -Zlib::MAX_WBITS)
57
+ compressed_body = z.deflate(uncompressed_body, Zlib::FINISH)
58
+ z.close
59
+ compressed_body
60
+ end
61
+
62
+ if Faraday::Gzip::Middleware::BROTLI_SUPPORTED
63
+ let(:brotlied_body) do
64
+ Brotli.deflate(uncompressed_body)
65
+ end
66
+ end
67
+
68
+ shared_examples 'compressed response' do
69
+ it 'uncompresses the body' do
70
+ expect(process(body).body).to eq(uncompressed_body)
71
+ end
72
+
73
+ it 'sets the Content-Length' do
74
+ expect(process(body).headers['Content-Length']).to eq(uncompressed_body.length)
75
+ end
76
+
77
+ it 'removes the Content-Encoding' do
78
+ expect(process(body).headers['Content-Encoding']).to be_nil
79
+ end
80
+ end
81
+
82
+ context 'when gzipped response' do
83
+ let(:body) { gzipped_body }
84
+ let(:headers) { { 'Content-Encoding' => 'gzip', 'Content-Length' => body.length } }
85
+
86
+ it_behaves_like 'compressed response'
87
+ end
88
+
89
+ context 'when deflated response' do
90
+ let(:body) { deflated_body }
91
+ let(:headers) { { 'Content-Encoding' => 'deflate', 'Content-Length' => body.length } }
92
+
93
+ it_behaves_like 'compressed response'
94
+ end
95
+
96
+ context 'when raw deflated response' do
97
+ let(:body) { raw_deflated_body }
98
+ let(:headers) { { 'Content-Encoding' => 'deflate', 'Content-Length' => body.length } }
99
+
100
+ it_behaves_like 'compressed response'
101
+ end
102
+
103
+ if Faraday::Gzip::Middleware::BROTLI_SUPPORTED
104
+ context 'when brotlied response' do
105
+ let(:body) { brotlied_body }
106
+ let(:headers) { { 'Content-Encoding' => 'br', 'Content-Length' => body.length } }
107
+
108
+ it_behaves_like 'compressed response'
109
+ end
110
+ end
111
+
112
+ context 'when empty response' do
113
+ let(:body) { empty_body }
114
+ let(:headers) { { 'Content-Encoding' => 'gzip', 'Content-Length' => body.length } }
115
+
116
+ it 'sets the Content-Length' do
117
+ expect(process(body).headers['Content-Length']).to eq(empty_body.length)
118
+ end
119
+
120
+ it 'removes the Content-Encoding' do
121
+ expect(process(body).headers['Content-Encoding']).to be_nil
122
+ end
123
+ end
124
+
125
+ context 'when nil response' do
126
+ let(:body) { nil }
127
+ let(:headers) { { 'Content-Encoding' => 'gzip', 'Content-Length' => 0 } }
128
+
129
+ it 'sets the Content-Length' do
130
+ expect(process(body).headers['Content-Length']).to eq(0)
131
+ end
132
+
133
+ it 'removes the Content-Encoding' do
134
+ expect(process(body).headers['Content-Encoding']).to be_nil
135
+ end
136
+ end
137
+
138
+ context 'when identity response' do
139
+ let(:body) { uncompressed_body }
140
+
141
+ it 'does not modify the body' do
142
+ expect(process(body).body).to eq(uncompressed_body)
143
+ end
144
+ end
145
+
146
+ context 'when unsupported encoding response' do
147
+ let(:body) { 'unsupported' }
148
+ let(:headers) { { 'Content-Encoding' => 'unsupported' } }
149
+
150
+ it 'does not modify the body' do
151
+ expect(process(body).body).to eq(body)
152
+ end
153
+
154
+ it 'preserves the Content-Encoding header' do
155
+ expect(process(body).headers['Content-Encoding']).to eq('unsupported')
156
+ end
157
+ end
158
+
159
+ context 'when no Content-Encoding header' do
160
+ let(:body) { uncompressed_body }
161
+ let(:headers) { {} }
162
+
163
+ it 'does not modify the body' do
164
+ expect(process(body).body).to eq(uncompressed_body)
165
+ end
166
+
167
+ it 'does not add a Content-Encoding header' do
168
+ expect(process(body).headers['Content-Encoding']).to be_nil
169
+ end
170
+ end
171
+
172
+ context 'when Content-Length is a string' do
173
+ let(:body) { gzipped_body }
174
+ let(:headers) { { 'Content-Encoding' => 'gzip', 'Content-Length' => body.length.to_s } }
175
+
176
+ it_behaves_like 'compressed response'
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe 'Faraday::Gzip::VERSION' do
4
+ subject { Object.const_get(self.class.description) }
5
+
6
+ it { is_expected.to match(/^\d+\.\d+\.\d+(\.\w+(\.\d+)?)?$/) }
7
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
4
+ require 'simplecov'
5
+
6
+ SimpleCov.start do
7
+ add_filter 'spec/'
8
+ add_filter '.github/'
9
+ end
10
+
11
+ require_relative '../lib/faraday/gzip'
12
+
13
+ RSpec.configure do |config|
14
+ # Enable flags like --only-failures and --next-failure
15
+ config.example_status_persistence_file_path = '.rspec_status'
16
+
17
+ # Disable RSpec exposing methods globally on `Module` and `main`
18
+ config.disable_monkey_patching!
19
+
20
+ config.expect_with :rspec do |c|
21
+ c.syntax = :expect
22
+ end
23
+
24
+ config.order = :random
25
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: faraday-gzip
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ilya Krukowski
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-01-02 00:00:00.000000000 Z
11
+ date: 2024-10-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -16,14 +16,20 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1.0'
19
+ version: '2.0'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '3'
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
27
  - - ">="
25
28
  - !ruby/object:Gem::Version
26
- version: '1.0'
29
+ version: '2.0'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '3'
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: zlib
29
35
  requirement: !ruby/object:Gem::Requirement
@@ -142,14 +148,14 @@ dependencies:
142
148
  requirements:
143
149
  - - "~>"
144
150
  - !ruby/object:Gem::Version
145
- version: '2.11'
151
+ version: '3.0'
146
152
  type: :development
147
153
  prerelease: false
148
154
  version_requirements: !ruby/object:Gem::Requirement
149
155
  requirements:
150
156
  - - "~>"
151
157
  - !ruby/object:Gem::Version
152
- version: '2.11'
158
+ version: '3.0'
153
159
  description: 'Faraday plugin to automatically set compression headers (GZip, Deflate,
154
160
  Brotli) and decompress the response.
155
161
 
@@ -166,13 +172,16 @@ files:
166
172
  - lib/faraday/gzip.rb
167
173
  - lib/faraday/gzip/middleware.rb
168
174
  - lib/faraday/gzip/version.rb
175
+ - spec/faraday/gzip/middleware_spec.rb
176
+ - spec/faraday/gzip/version_spec.rb
177
+ - spec/spec_helper.rb
169
178
  homepage: https://github.com/bodrovis/faraday-gzip
170
179
  licenses:
171
180
  - MIT
172
181
  metadata:
173
182
  bug_tracker_uri: https://github.com/bodrovis/faraday-gzip/issues
174
183
  changelog_uri: https://github.com/bodrovis/faraday-gzip/blob/master/CHANGELOG.md
175
- documentation_uri: http://www.rubydoc.info/gems/faraday-gzip/2.0.1
184
+ documentation_uri: http://www.rubydoc.info/gems/faraday-gzip/3.0.0
176
185
  homepage_uri: https://github.com/bodrovis/faraday-gzip
177
186
  source_code_uri: https://github.com/bodrovis/faraday-gzip
178
187
  rubygems_mfa_required: 'true'
@@ -184,7 +193,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
184
193
  requirements:
185
194
  - - ">="
186
195
  - !ruby/object:Gem::Version
187
- version: '2.6'
196
+ version: '3.0'
188
197
  - - "<"
189
198
  - !ruby/object:Gem::Version
190
199
  version: '4'
@@ -194,7 +203,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
194
203
  - !ruby/object:Gem::Version
195
204
  version: '0'
196
205
  requirements: []
197
- rubygems_version: 3.5.3
206
+ rubygems_version: 3.5.22
198
207
  signing_key:
199
208
  specification_version: 4
200
209
  summary: Automatically sets compression headers and decompresses the response