faraday-gzip 3.0.4 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5183c6f188272ea7e213adf03bb2d637c348e9f273b1b8829255f135a95b8c92
4
- data.tar.gz: ce73797d7aa191ef07c376af0193ea704a653237146affec2806031194d064c7
3
+ metadata.gz: aca2ddf08f8675bc1c6c9e466a6d593a34c52f02a3a32f4068427ca39aad7263
4
+ data.tar.gz: 96a6b9a912363c4849287acae53f8b3394ada2b943a677958f09c36fccbdd30e
5
5
  SHA512:
6
- metadata.gz: 8f9add78a8ff2c274ef021ae4e8ebfc1f525847ba4d05ca6ccf52cba1bc9f9d891e4627a354fdbf724393cb420e1225c33521d55f15f0c292490c8466e6ba202
7
- data.tar.gz: 2edf0cd82a52d2bf33d9024ed3363b4735dc7a7645f847bf1aca250947d14663d696d2bc64bb10fc83019a677a2b701d933766ed1afcc7f76d554a30b4e6c5f9
6
+ metadata.gz: 6c37c4a0ece9fb5eb4c23856c62dd2d1a0ac640e7f7401b621de518188e9f6cc822abba179ad99d7566e107c4267c2177977fef2c47b507c541a6fc60afab643
7
+ data.tar.gz: 9bb4a964ea2a41d2760847873551474d2bd91b4598ff0ce9700e096e423ff489f59fc4eca73d00f726a8ec7694642b3cc7d4f654c3bf1cd555c0693e0d2d0fd5
data/CHANGELOG.md CHANGED
@@ -1,8 +1,26 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.2.0 (12-Oct-2026)
4
+
5
+ - Moved development dependencies to `Gemfile` and improved SimpleCov compatibility across Ruby versions.
6
+ - Simplified response decompression logic.
7
+ - Prevented partial decompression when unsupported content encodings are present.
8
+ - Preserved response headers for empty, non-string, and partial (`206`) responses.
9
+ - Added support for concatenated gzip streams.
10
+ - Added regression tests for encoding chains, partial responses, and concatenated gzip streams.
11
+ - Fixed test helpers to properly initialize HTTP response environments.
12
+
13
+ ## 3.1.0 (05-Jan-2026)
14
+
15
+ * Improve handling of edge cases and malformed `Content-Encoding` headers
16
+ * Support multiple encodings and respect `identity` responses
17
+ * Avoid modifying streaming and non-string response bodies
18
+ * Normalize response headers after decompression
19
+ * Update and expand test coverage, test with Ruby 4.0
20
+
3
21
  ## 3.0.4 (06-Apr-2025)
4
22
 
5
- * Require StringIO that might not always be readily available
23
+ * Require `StringIO` that might not always be readily available
6
24
 
7
25
  ## 3.0.3 (25-Feb-2025)
8
26
 
data/README.md CHANGED
@@ -3,12 +3,14 @@
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
5
  ![Gem Total Downloads](https://img.shields.io/gem/dt/faraday-gzip)
6
+ [![Maintainability](https://qlty.sh/gh/bodrovis/projects/faraday-gzip/maintainability.svg)](https://qlty.sh/gh/bodrovis/projects/faraday-gzip)
7
+ [![Code Coverage](https://qlty.sh/gh/bodrovis/projects/faraday-gzip/coverage.svg)](https://qlty.sh/gh/bodrovis/projects/faraday-gzip)
6
8
 
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.
9
+ The `Gzip` middleware for Faraday 1 and 2 adds appropriate `Accept-Encoding` request headers and automatically decompresses supported response bodies (`gzip`, `deflate`, and optionally `br`). If the `Accept-Encoding` header is not explicitly set, it defaults to `gzip,deflate` and includes `br` when [Brotli](https://github.com/miyucy/brotli) support is available. The middleware safely handles multiple and malformed `Content-Encoding` headers, and avoids modifying unsupported or streaming response bodies. This behavior is similar in spirit to Ruby's internal handling in `Net::HTTP#get`, while remaining conservative to preserve compatibility with Faraday adapters.
8
10
 
9
11
  ## Prerequisites
10
12
 
11
- * faraday-gzip v3 supports only Faraday v2 and is tested with Ruby 3.0+ and JRuby 9.4
13
+ * faraday-gzip v3 supports only Faraday v2 and is tested with Ruby 3.0+ and JRuby 9.4+
12
14
  * [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.
13
15
 
14
16
  ## Installation
@@ -13,6 +13,11 @@ module Faraday
13
13
  module Gzip
14
14
  # Faraday middleware for decompression
15
15
  class Middleware < Faraday::Middleware
16
+ ACCEPT_ENCODING = 'Accept-Encoding'
17
+ CONTENT_ENCODING = 'Content-Encoding'
18
+ CONTENT_LENGTH = 'Content-Length'
19
+ IDENTITY = 'identity'
20
+
16
21
  # System method required by Faraday
17
22
  def self.optional_dependency(lib = nil)
18
23
  lib ? require(lib) : yield
@@ -31,9 +36,6 @@ module Faraday
31
36
  encodings
32
37
  end
33
38
 
34
- ACCEPT_ENCODING = 'Accept-Encoding'
35
- CONTENT_ENCODING = 'Content-Encoding'
36
- CONTENT_LENGTH = 'Content-Length'
37
39
  SUPPORTED_ENCODINGS = supported_encodings.join(',').freeze
38
40
 
39
41
  # Main method to process the response
@@ -47,32 +49,31 @@ module Faraday
47
49
 
48
50
  # Finds a proper processor
49
51
  def find_processor(response_env)
50
- if empty_body?(response_env)
51
- ->(body) { raw_body(body) }
52
- else
53
- processors[response_env[:response_headers][CONTENT_ENCODING]]
54
- end
52
+ encodings = parse_content_encoding(
53
+ response_env[:response_headers][CONTENT_ENCODING]
54
+ )
55
+ return nil if skip_decompression?(response_env, encodings)
56
+
57
+ chain = processor_chain(encodings)
58
+ return nil if chain.empty?
59
+
60
+ ->(body) { chain.reduce(body) { |acc, fn| fn.call(acc) } }
55
61
  end
56
62
 
57
63
  # Calls the proper processor to decompress body
58
64
  def reset_body(env, processor)
59
65
  return if processor.nil?
60
66
 
61
- env[:body] = processor.call(env[:body])
62
- env[:response_headers].delete(CONTENT_ENCODING)
67
+ body = processor.call(env[:body])
63
68
 
64
- env[:response_headers][CONTENT_LENGTH] = env[:body].nil? ? 0 : env[:body].length
69
+ env[:body] = body
70
+ env[:response_headers][CONTENT_LENGTH] = body.bytesize
71
+ env[:response_headers].delete(CONTENT_ENCODING)
65
72
  end
66
73
 
67
74
  # Process gzip
68
75
  def uncompress_gzip(body)
69
- io = StringIO.new(body)
70
- gzip_reader = Zlib::GzipReader.new(io, encoding: 'ASCII-8BIT')
71
- begin
72
- gzip_reader.read
73
- ensure
74
- gzip_reader.close
75
- end
76
+ Zlib::GzipReader.zcat(StringIO.new(body))
76
77
  end
77
78
 
78
79
  # Process deflate
@@ -95,23 +96,40 @@ module Faraday
95
96
  Brotli.inflate(body)
96
97
  end
97
98
 
98
- # Do not process anything, leave body as is
99
- def raw_body(body)
100
- body
99
+ private
100
+
101
+ def skip_decompression?(env, encodings)
102
+ body = env[:body]
103
+
104
+ return true unless body.is_a?(String) && !body.empty?
105
+ return true if env[:status] == 206
106
+
107
+ encodings.empty? || encodings.include?(IDENTITY)
101
108
  end
102
109
 
103
- private
110
+ def parse_content_encoding(value)
111
+ return [] if value.nil?
112
+
113
+ value.to_s
114
+ .split(',')
115
+ .map { |v| v.strip.downcase }
116
+ .reject(&:empty?)
117
+ end
118
+
119
+ # Decode in reverse order of application:
120
+ # "gzip, br" => br -> gzip
121
+ # If the encoding is unknown, do not touch the content
122
+ def processor_chain(encodings)
123
+ return [] unless encodings.all? { |enc| processors[enc] }
104
124
 
105
- def empty_body?(response_env)
106
- response_env[:body].nil? || response_env[:body].empty?
125
+ encodings.reverse.map { |enc| processors[enc] }
107
126
  end
108
127
 
109
- # Method providing the processors
110
128
  def processors
111
129
  @processors ||= {
112
130
  'gzip' => ->(body) { uncompress_gzip(body) },
113
131
  'deflate' => ->(body) { inflate(body) },
114
- 'br' => ->(body) { brotli_inflate(body) }
132
+ 'br' => (BROTLI_SUPPORTED ? ->(body) { brotli_inflate(body) } : nil)
115
133
  }
116
134
  end
117
135
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Faraday
4
4
  module Gzip
5
- VERSION = '3.0.4'
5
+ VERSION = '3.2.0'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: faraday-gzip
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.4
4
+ version: 3.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ilya Krukowski
@@ -43,104 +43,6 @@ dependencies:
43
43
  - - "~>"
44
44
  - !ruby/object:Gem::Version
45
45
  version: '3.0'
46
- - !ruby/object:Gem::Dependency
47
- name: bundler
48
- requirement: !ruby/object:Gem::Requirement
49
- requirements:
50
- - - "~>"
51
- - !ruby/object:Gem::Version
52
- version: '2.0'
53
- type: :development
54
- prerelease: false
55
- version_requirements: !ruby/object:Gem::Requirement
56
- requirements:
57
- - - "~>"
58
- - !ruby/object:Gem::Version
59
- version: '2.0'
60
- - !ruby/object:Gem::Dependency
61
- name: rake
62
- requirement: !ruby/object:Gem::Requirement
63
- requirements:
64
- - - "~>"
65
- - !ruby/object:Gem::Version
66
- version: '13.0'
67
- type: :development
68
- prerelease: false
69
- version_requirements: !ruby/object:Gem::Requirement
70
- requirements:
71
- - - "~>"
72
- - !ruby/object:Gem::Version
73
- version: '13.0'
74
- - !ruby/object:Gem::Dependency
75
- name: rspec
76
- requirement: !ruby/object:Gem::Requirement
77
- requirements:
78
- - - "~>"
79
- - !ruby/object:Gem::Version
80
- version: '3.0'
81
- type: :development
82
- prerelease: false
83
- version_requirements: !ruby/object:Gem::Requirement
84
- requirements:
85
- - - "~>"
86
- - !ruby/object:Gem::Version
87
- version: '3.0'
88
- - !ruby/object:Gem::Dependency
89
- name: simplecov
90
- requirement: !ruby/object:Gem::Requirement
91
- requirements:
92
- - - "~>"
93
- - !ruby/object:Gem::Version
94
- version: '0.22'
95
- type: :development
96
- prerelease: false
97
- version_requirements: !ruby/object:Gem::Requirement
98
- requirements:
99
- - - "~>"
100
- - !ruby/object:Gem::Version
101
- version: '0.22'
102
- - !ruby/object:Gem::Dependency
103
- name: rubocop
104
- requirement: !ruby/object:Gem::Requirement
105
- requirements:
106
- - - "~>"
107
- - !ruby/object:Gem::Version
108
- version: '1.32'
109
- type: :development
110
- prerelease: false
111
- version_requirements: !ruby/object:Gem::Requirement
112
- requirements:
113
- - - "~>"
114
- - !ruby/object:Gem::Version
115
- version: '1.32'
116
- - !ruby/object:Gem::Dependency
117
- name: rubocop-performance
118
- requirement: !ruby/object:Gem::Requirement
119
- requirements:
120
- - - "~>"
121
- - !ruby/object:Gem::Version
122
- version: '1.0'
123
- type: :development
124
- prerelease: false
125
- version_requirements: !ruby/object:Gem::Requirement
126
- requirements:
127
- - - "~>"
128
- - !ruby/object:Gem::Version
129
- version: '1.0'
130
- - !ruby/object:Gem::Dependency
131
- name: rubocop-rspec
132
- requirement: !ruby/object:Gem::Requirement
133
- requirements:
134
- - - "~>"
135
- - !ruby/object:Gem::Version
136
- version: '3.0'
137
- type: :development
138
- prerelease: false
139
- version_requirements: !ruby/object:Gem::Requirement
140
- requirements:
141
- - - "~>"
142
- - !ruby/object:Gem::Version
143
- version: '3.0'
144
46
  description: 'Faraday plugin to automatically set compression headers (GZip, Deflate,
145
47
  Brotli) and decompress the response.
146
48
 
@@ -163,7 +65,7 @@ licenses:
163
65
  metadata:
164
66
  bug_tracker_uri: https://github.com/bodrovis/faraday-gzip/issues
165
67
  changelog_uri: https://github.com/bodrovis/faraday-gzip/blob/master/CHANGELOG.md
166
- documentation_uri: http://www.rubydoc.info/gems/faraday-gzip/3.0.4
68
+ documentation_uri: https://www.rubydoc.info/gems/faraday-gzip/3.2.0
167
69
  source_code_uri: https://github.com/bodrovis/faraday-gzip
168
70
  rubygems_mfa_required: 'true'
169
71
  rdoc_options: []
@@ -180,7 +82,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
180
82
  - !ruby/object:Gem::Version
181
83
  version: '0'
182
84
  requirements: []
183
- rubygems_version: 3.6.7
85
+ rubygems_version: 4.0.22
184
86
  specification_version: 4
185
87
  summary: Automatically sets compression headers and decompresses the response
186
88
  test_files: []