faraday-gzip 3.0.3 → 3.1.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: 801efea11d6b5a0e1f2d82c802cb6e0eea73bf542f7b9a793ff2288cefcc6c7f
4
- data.tar.gz: d6d5f77de67e0223cdbf225cdb52e121d548a7202bd91bc4acfd50b9b0ef7e25
3
+ metadata.gz: 838c02901688f672d7a94781a50997dc0dd82d9ea8f00addafc7e610cbf2c230
4
+ data.tar.gz: 6719045f1cccd8e339e0f97aea37b221bf61152c679248d2428ae92ea96a7a7c
5
5
  SHA512:
6
- metadata.gz: 715ab8b38d3050eacbbe21ac8f7444390e31d4807bd9908c6671ced6511c36b849ab11ec806140f2730d131b39dd8b90f7e08d03f69c4b2851a0df366020a78a
7
- data.tar.gz: dd479efd565f0b80e371ee7f5b1883614c52f7d55a78b8e5df92a80cb5a5d940e1f8049bc0dddff5d97a56e6935b554d106fa223700f35536d3dfc3b876effa4
6
+ metadata.gz: d096aedb098363e777d5d818f8d050ed1c87df5edb032c26cd761976ed052baa92d01333665b2f72daffbdc0cea75606f3eeef8f0616140088cba5281a640ea1
7
+ data.tar.gz: 50adf03a07cc7968e26b44f276ddbdf6c087c86f33bcff589ba368b5ed557e043e9fc21500bb9f6999e5e7148e52bf4fabec42ae7b8c322807207dd7bbf45307
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.1.0 (05-Jan-2026)
4
+
5
+ * Improve handling of edge cases and malformed `Content-Encoding` headers
6
+ * Support multiple encodings and respect `identity` responses
7
+ * Avoid modifying streaming and non-string response bodies
8
+ * Normalize response headers after decompression
9
+ * Update and expand test coverage, test with Ruby 4.0
10
+
11
+ ## 3.0.4 (06-Apr-2025)
12
+
13
+ * Require `StringIO` that might not always be readily available
14
+
3
15
  ## 3.0.3 (25-Feb-2025)
4
16
 
5
17
  * Minor code fixes, make some methods more solid
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
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'zlib'
4
+ require 'stringio'
4
5
 
5
6
  # Middleware to automatically decompress response bodies. If the
6
7
  # "Accept-Encoding" header wasn't set in the request, this sets it to
@@ -12,6 +13,11 @@ module Faraday
12
13
  module Gzip
13
14
  # Faraday middleware for decompression
14
15
  class Middleware < Faraday::Middleware
16
+ ACCEPT_ENCODING = 'Accept-Encoding'
17
+ CONTENT_ENCODING = 'Content-Encoding'
18
+ CONTENT_LENGTH = 'Content-Length'
19
+ IDENTITY = 'identity'
20
+
15
21
  # System method required by Faraday
16
22
  def self.optional_dependency(lib = nil)
17
23
  lib ? require(lib) : yield
@@ -30,9 +36,6 @@ module Faraday
30
36
  encodings
31
37
  end
32
38
 
33
- ACCEPT_ENCODING = 'Accept-Encoding'
34
- CONTENT_ENCODING = 'Content-Encoding'
35
- CONTENT_LENGTH = 'Content-Length'
36
39
  SUPPORTED_ENCODINGS = supported_encodings.join(',').freeze
37
40
 
38
41
  # Main method to process the response
@@ -46,21 +49,40 @@ module Faraday
46
49
 
47
50
  # Finds a proper processor
48
51
  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]]
53
- end
52
+ body = response_env[:body]
53
+
54
+ encodings = parse_content_encoding(
55
+ response_env[:response_headers][CONTENT_ENCODING]
56
+ )
57
+ return nil if encodings.empty? || encodings.include?(IDENTITY)
58
+
59
+ # If body is nil/empty, we still want to normalize headers:
60
+ # Content-Encoding is meaningless without an encoded body.
61
+ return ->(b) { b } if body_nil_or_empty?(body)
62
+
63
+ chain = processor_chain(encodings)
64
+ return nil if chain.empty?
65
+
66
+ ->(b) { chain.reduce(b) { |acc, fn| fn.call(acc) } }
54
67
  end
55
68
 
56
69
  # Calls the proper processor to decompress body
57
70
  def reset_body(env, processor)
58
71
  return if processor.nil?
59
72
 
60
- env[:body] = processor.call(env[:body])
61
- env[:response_headers].delete(CONTENT_ENCODING)
73
+ body = env[:body]
74
+ headers = env[:response_headers]
75
+
76
+ # Don't touch streaming / IO-like bodies.
77
+ return unless body.is_a?(String) || body_nil_or_empty?(body)
62
78
 
63
- env[:response_headers][CONTENT_LENGTH] = env[:body].nil? ? 0 : env[:body].length
79
+ if body.is_a?(String)
80
+ env[:body] = processor.call(body)
81
+ headers[CONTENT_LENGTH] = env[:body].bytesize
82
+ end
83
+
84
+ # Normalize encoding header even for nil/empty body.
85
+ headers.delete(CONTENT_ENCODING)
64
86
  end
65
87
 
66
88
  # Process gzip
@@ -94,23 +116,38 @@ module Faraday
94
116
  Brotli.inflate(body)
95
117
  end
96
118
 
97
- # Do not process anything, leave body as is
98
- def raw_body(body)
99
- body
119
+ private
120
+
121
+ def body_nil_or_empty?(body)
122
+ return true if body.nil?
123
+ return body.empty? if body.respond_to?(:empty?)
124
+ # rubocop:disable Style/ZeroLengthPredicate
125
+ return body.size.zero? if body.respond_to?(:size)
126
+ # rubocop:enable Style/ZeroLengthPredicate
127
+
128
+ false
100
129
  end
101
130
 
102
- private
131
+ def parse_content_encoding(value)
132
+ return [] if value.nil?
133
+
134
+ value.to_s
135
+ .split(',')
136
+ .map { |v| v.strip.downcase }
137
+ .reject(&:empty?)
138
+ end
103
139
 
104
- def empty_body?(response_env)
105
- response_env[:body].nil? || response_env[:body].empty?
140
+ # Decode in reverse order of application:
141
+ # "gzip, br" => br -> gzip
142
+ def processor_chain(encodings)
143
+ encodings.reverse.filter_map { |enc| processors[enc] }
106
144
  end
107
145
 
108
- # Method providing the processors
109
146
  def processors
110
147
  @processors ||= {
111
148
  'gzip' => ->(body) { uncompress_gzip(body) },
112
149
  'deflate' => ->(body) { inflate(body) },
113
- 'br' => ->(body) { brotli_inflate(body) }
150
+ 'br' => (BROTLI_SUPPORTED ? ->(body) { brotli_inflate(body) } : nil)
114
151
  }
115
152
  end
116
153
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Faraday
4
4
  module Gzip
5
- VERSION = '3.0.3'
5
+ VERSION = '3.1.0'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: faraday-gzip
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.3
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ilya Krukowski
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-02-25 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: faraday
@@ -43,20 +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
46
  - !ruby/object:Gem::Dependency
61
47
  name: rake
62
48
  requirement: !ruby/object:Gem::Requirement
@@ -105,42 +91,42 @@ dependencies:
105
91
  requirements:
106
92
  - - "~>"
107
93
  - !ruby/object:Gem::Version
108
- version: '1.32'
94
+ version: '1.82'
109
95
  type: :development
110
96
  prerelease: false
111
97
  version_requirements: !ruby/object:Gem::Requirement
112
98
  requirements:
113
99
  - - "~>"
114
100
  - !ruby/object:Gem::Version
115
- version: '1.32'
101
+ version: '1.82'
116
102
  - !ruby/object:Gem::Dependency
117
103
  name: rubocop-performance
118
104
  requirement: !ruby/object:Gem::Requirement
119
105
  requirements:
120
106
  - - "~>"
121
107
  - !ruby/object:Gem::Version
122
- version: '1.0'
108
+ version: '1.26'
123
109
  type: :development
124
110
  prerelease: false
125
111
  version_requirements: !ruby/object:Gem::Requirement
126
112
  requirements:
127
113
  - - "~>"
128
114
  - !ruby/object:Gem::Version
129
- version: '1.0'
115
+ version: '1.26'
130
116
  - !ruby/object:Gem::Dependency
131
117
  name: rubocop-rspec
132
118
  requirement: !ruby/object:Gem::Requirement
133
119
  requirements:
134
120
  - - "~>"
135
121
  - !ruby/object:Gem::Version
136
- version: '3.0'
122
+ version: '3.8'
137
123
  type: :development
138
124
  prerelease: false
139
125
  version_requirements: !ruby/object:Gem::Requirement
140
126
  requirements:
141
127
  - - "~>"
142
128
  - !ruby/object:Gem::Version
143
- version: '3.0'
129
+ version: '3.8'
144
130
  description: 'Faraday plugin to automatically set compression headers (GZip, Deflate,
145
131
  Brotli) and decompress the response.
146
132
 
@@ -163,7 +149,7 @@ licenses:
163
149
  metadata:
164
150
  bug_tracker_uri: https://github.com/bodrovis/faraday-gzip/issues
165
151
  changelog_uri: https://github.com/bodrovis/faraday-gzip/blob/master/CHANGELOG.md
166
- documentation_uri: http://www.rubydoc.info/gems/faraday-gzip/3.0.3
152
+ documentation_uri: http://www.rubydoc.info/gems/faraday-gzip/3.1.0
167
153
  source_code_uri: https://github.com/bodrovis/faraday-gzip
168
154
  rubygems_mfa_required: 'true'
169
155
  rdoc_options: []
@@ -180,7 +166,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
180
166
  - !ruby/object:Gem::Version
181
167
  version: '0'
182
168
  requirements: []
183
- rubygems_version: 3.6.5
169
+ rubygems_version: 4.0.3
184
170
  specification_version: 4
185
171
  summary: Automatically sets compression headers and decompresses the response
186
172
  test_files: []