httpi 3.0.2 → 4.0.1

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: cd06f829b3d33418dfe3ef465949f504f6acde0e9f5988edea9615e700bb8f23
4
- data.tar.gz: '00197cf31c50d34768c76325d42cc8dc325774ffe5a2ecaf6feb33f7d22c382c'
3
+ metadata.gz: 70c75f8e865f40f9218b34d091ab64aad2656467fff356ac18e2530b70dc52d7
4
+ data.tar.gz: fb86901d88b603911f98d1dbcad0132a0c3f6c28ce3d7b1640ce5b84f7524659
5
5
  SHA512:
6
- metadata.gz: 81a2a86d8a7784711c0a72995a21262c7bcdfb17d9127a06a9573c50f7eaffde7e544c07b332e905da3fb1b177d867d34c2b59a75f0605182a6d278db9eda4a6
7
- data.tar.gz: e59a0468efe743db6a4b4d7eff007714cb739e928396b7ff8797896a346e7808a2635185ccf1a9eb53db64d149626782a4f3dc530f3e9644c21923ce6a4a0f3d
6
+ metadata.gz: 4eddf2bd30c64892ec8bc478e5774382030a829b58450a7e0b2266ebdba4f7b01ead27315253c56ba454addc9c7a6112b77f553684e35d143e06397c51de5389
7
+ data.tar.gz: 5b497936201359ed9b45df8486875bb6be8706fedeeed5ec7d7b43a0c15555cff46e3a7fc48a50b1970a76e2dae202eef591ccf74325caf8d5faf77a09f46789
@@ -34,7 +34,7 @@ jobs:
34
34
  experimental: true
35
35
 
36
36
  steps:
37
- - uses: actions/checkout@v3
37
+ - uses: actions/checkout@v4
38
38
 
39
39
  - name: Install dependencies
40
40
  run: sudo apt-get install libcurl4-openssl-dev
data/CHANGELOG.md CHANGED
@@ -1,10 +1,23 @@
1
1
  ### Unreleased
2
2
 
3
- * Improvement: [#237](https://github.com/savonrb/httpi/pull/237) Implemented `adapter_client_setup`.
3
+ * Add your changelog entry here
4
+
5
+ ### 4.0.1 (2024-02-16)
6
+
7
+ HTTPI is officially in maintenance mode. Our emphasis will now be on bugs, security fixes, and compatibility with the wider ecosystem. See [this issue](https://github.com/savonrb/httpi/issues/238) for details.
8
+
9
+ * Adds support for rack 3.0.
10
+ * POTENTIAL BREAKING CHANGE: `HTTPI::Request#headers` and `HTTPI::Response#headers` now return `HTTPI::Utils::Headers` instead of `Rack::Utils::HeaderHash`. This change will prevent HTTPI from breaking or changing its public API whenever rack rearranges its classes. If you were relying on the `Rack::Utils::HeaderHash` implementation, you will need to update your code to use `HTTPI::Utils::Headers` instead.
11
+
12
+ ### 4.0.0 (yanked)
13
+
14
+ Yanked due to a bug when used with rack 2.
4
15
 
5
16
  ### 3.0.2 (2024-02-10)
6
17
 
18
+ * Improvement: [#237](https://github.com/savonrb/httpi/pull/237) Implemented `adapter_client_setup`.
7
19
  * Add support for ruby 3.1, 3.2, 3.3. Drop support for ruby 2.7 and below.
20
+ * Pin to rack version < 3, HTTPI is not tested with rack 3 yet.
8
21
 
9
22
  ### 3.0.1 (2021-12-17)
10
23
 
data/Gemfile CHANGED
@@ -15,7 +15,7 @@ gem 'net-http-persistent', '~> 4.0', :require => false
15
15
  gem 'http', :require => false
16
16
 
17
17
  # adapter extensions
18
- gem 'rack', '< 3'
18
+ gem 'rack'
19
19
  gem 'socksify'
20
20
 
21
21
  # coverage
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # HTTPI
2
2
 
3
- A common interface for Ruby's HTTP libraries.
3
+ A common interface for Ruby's HTTP libraries. This project is now in maintenance mode. For new projects, we recommend [faraday](https://github.com/lostisland/faraday).
4
4
 
5
5
  [Documentation](https://www.rubydoc.info/gems/httpi)
6
6
 
@@ -14,7 +14,7 @@ HTTPI is available through [Rubygems](https://rubygems.org/gems/httpi) and can b
14
14
 
15
15
  or add it to your Gemfile like this:
16
16
 
17
- gem 'httpi', '~> 3.0.0'
17
+ gem 'httpi', '~> 4.0.0'
18
18
 
19
19
  ## Usage example
20
20
 
@@ -36,6 +36,17 @@ HTTPI.adapter = :httpclient
36
36
 
37
37
  # and execute arbitary requests
38
38
  HTTPI.request(:custom, request)
39
+
40
+ # add a client setup block that will be called before each request
41
+ HTTPI.adapter = :httpclient
42
+ HTTPI.adapter_client_setup = proc do |x|
43
+ x.ssl_config.set_default_paths
44
+ x.force_basic_auth = true
45
+ end
46
+ # ...
47
+ HTTPI.get(request) do |x|
48
+ x.force_basic_auth = false
49
+ end
39
50
  ```
40
51
 
41
52
  ### SOCKS Proxy Support
data/UPDATING.md CHANGED
@@ -5,3 +5,7 @@
5
5
  BREAKING CHANGE: the [#255](https://github.com/savonrb/httpi/pull/225) made the gem socksify and rack gems optional dependencies.
6
6
 
7
7
  In order to restore the old behavior, see the README section "SOCKS Proxy Support" and "Rack Mock Adapter".
8
+
9
+ ## From 3.x to 4.x
10
+
11
+ POTENTIAL BREAKING CHANGE: `HTTPI::Request#headers` and `HTTPI::Response#headers` now return `HTTPI::Utils::Headers` instead of `Rack::Utils::HeaderHash`. This change will prevent HTTPI from breaking or changing its public API whenever rack rearranges its classes. If you were relying on the `Rack::Utils::HeaderHash` implementation, you will need to update your code to use `HTTPI::Utils::Headers` instead.
data/httpi.gemspec CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |s|
21
21
 
22
22
  s.license = 'MIT'
23
23
 
24
- s.add_dependency 'rack', '< 3'
24
+ s.add_dependency 'rack', '>= 2.0', '< 3.1'
25
25
  s.add_dependency 'nkf'
26
26
  s.add_dependency 'base64'
27
27
  s.add_dependency 'mutex_m'
@@ -30,7 +30,7 @@ Gem::Specification.new do |s|
30
30
  s.add_development_dependency 'rake', '~> 13.0'
31
31
  s.add_development_dependency 'rspec', '~> 3.5'
32
32
  s.add_development_dependency 'mocha', '~> 0.13'
33
- s.add_development_dependency 'puma', '~> 5.0'
33
+ s.add_development_dependency 'puma', '~> 6.0'
34
34
  s.add_development_dependency 'webmock'
35
35
 
36
36
  s.metadata["rubygems_mfa_required"] = "true"
data/lib/httpi/request.rb CHANGED
@@ -64,12 +64,12 @@ module HTTPI
64
64
 
65
65
  # Returns a Hash of HTTP headers. Defaults to return an empty Hash.
66
66
  def headers
67
- @headers ||= Rack::Utils::HeaderHash.new
67
+ @headers ||= HTTPI::Utils::Headers.new
68
68
  end
69
69
 
70
70
  # Sets the Hash of HTTP headers.
71
71
  def headers=(headers)
72
- @headers = Rack::Utils::HeaderHash.new(headers)
72
+ @headers = HTTPI::Utils::Headers.new.merge(headers)
73
73
  end
74
74
 
75
75
  # Adds a header information to accept gzipped content.
@@ -20,7 +20,7 @@ module HTTPI
20
20
  # Initializer expects an HTTP response +code+, +headers+ and +body+.
21
21
  def initialize(code, headers, body)
22
22
  self.code = code.to_i
23
- self.headers = Rack::Utils::HeaderHash.new(headers)
23
+ self.headers = HTTPI::Utils::Headers.new.merge(headers)
24
24
  self.raw_body = body
25
25
  end
26
26
 
@@ -0,0 +1,238 @@
1
+ # mostly verbatim from: https://github.com/rack/rack/blob/main/lib/rack/headers.rb
2
+ # Because this is part of httpi's public API, its better not to load an external
3
+ # library for it.
4
+ module HTTPI
5
+ module Utils
6
+ # HTTPI::Utils::Headers is a Hash subclass that downcases all keys.
7
+ class Headers < Hash
8
+ KNOWN_HEADERS = {}
9
+ %w(
10
+ Accept-CH
11
+ Accept-Patch
12
+ Accept-Ranges
13
+ Access-Control-Allow-Credentials
14
+ Access-Control-Allow-Headers
15
+ Access-Control-Allow-Methods
16
+ Access-Control-Allow-Origin
17
+ Access-Control-Expose-Headers
18
+ Access-Control-Max-Age
19
+ Age
20
+ Allow
21
+ Alt-Svc
22
+ Cache-Control
23
+ Connection
24
+ Content-Disposition
25
+ Content-Encoding
26
+ Content-Language
27
+ Content-Length
28
+ Content-Location
29
+ Content-MD5
30
+ Content-Range
31
+ Content-Security-Policy
32
+ Content-Security-Policy-Report-Only
33
+ Content-Type
34
+ Date
35
+ Delta-Base
36
+ ETag
37
+ Expect-CT
38
+ Expires
39
+ Feature-Policy
40
+ IM
41
+ Last-Modified
42
+ Link
43
+ Location
44
+ NEL
45
+ P3P
46
+ Permissions-Policy
47
+ Pragma
48
+ Preference-Applied
49
+ Proxy-Authenticate
50
+ Public-Key-Pins
51
+ Referrer-Policy
52
+ Refresh
53
+ Report-To
54
+ Retry-After
55
+ Server
56
+ Set-Cookie
57
+ Status
58
+ Strict-Transport-Security
59
+ Timing-Allow-Origin
60
+ Tk
61
+ Trailer
62
+ Transfer-Encoding
63
+ Upgrade
64
+ Vary
65
+ Via
66
+ WWW-Authenticate
67
+ Warning
68
+ X-Cascade
69
+ X-Content-Duration
70
+ X-Content-Security-Policy
71
+ X-Content-Type-Options
72
+ X-Correlation-ID
73
+ X-Correlation-Id
74
+ X-Download-Options
75
+ X-Frame-Options
76
+ X-Permitted-Cross-Domain-Policies
77
+ X-Powered-By
78
+ X-Redirect-By
79
+ X-Request-ID
80
+ X-Request-Id
81
+ X-Runtime
82
+ X-UA-Compatible
83
+ X-WebKit-CS
84
+ X-XSS-Protection
85
+ ).each do |str|
86
+ downcased = str.downcase.freeze
87
+ KNOWN_HEADERS[str] = KNOWN_HEADERS[downcased] = downcased
88
+ end
89
+
90
+ def self.[](*items)
91
+ if items.length % 2 != 0
92
+ if items.length == 1 && items.first.is_a?(Hash)
93
+ new.merge!(items.first)
94
+ else
95
+ raise ArgumentError, "odd number of arguments for Utils::Headers"
96
+ end
97
+ else
98
+ hash = new
99
+ loop do
100
+ break if items.length == 0
101
+ key = items.shift
102
+ value = items.shift
103
+ hash[key] = value
104
+ end
105
+ hash
106
+ end
107
+ end
108
+
109
+ def [](key)
110
+ super(downcase_key(key))
111
+ end
112
+
113
+ def []=(key, value)
114
+ super(KNOWN_HEADERS[key] || key.downcase.freeze, value)
115
+ end
116
+ alias store []=
117
+
118
+ def assoc(key)
119
+ super(downcase_key(key))
120
+ end
121
+
122
+ def compare_by_identity
123
+ raise TypeError, "Utils::Headers cannot compare by identity, use regular Hash"
124
+ end
125
+
126
+ def delete(key)
127
+ super(downcase_key(key))
128
+ end
129
+
130
+ def dig(key, *a)
131
+ super(downcase_key(key), *a)
132
+ end
133
+
134
+ def fetch(key, *default, &block)
135
+ key = downcase_key(key)
136
+ super
137
+ end
138
+
139
+ def fetch_values(*a)
140
+ super(*a.map!{|key| downcase_key(key)})
141
+ end
142
+
143
+ def has_key?(key)
144
+ super(downcase_key(key))
145
+ end
146
+ alias include? has_key?
147
+ alias key? has_key?
148
+ alias member? has_key?
149
+
150
+ def invert
151
+ hash = self.class.new
152
+ each{|key, value| hash[value] = key}
153
+ hash
154
+ end
155
+
156
+ def merge(hash, &block)
157
+ dup.merge!(hash, &block)
158
+ end
159
+
160
+ def reject(&block)
161
+ hash = dup
162
+ hash.reject!(&block)
163
+ hash
164
+ end
165
+
166
+ def replace(hash)
167
+ clear
168
+ update(hash)
169
+ end
170
+
171
+ def select(&block)
172
+ hash = dup
173
+ hash.select!(&block)
174
+ hash
175
+ end
176
+
177
+ def to_proc
178
+ lambda{|x| self[x]}
179
+ end
180
+
181
+ def transform_values(&block)
182
+ dup.transform_values!(&block)
183
+ end
184
+
185
+ def update(hash, &block)
186
+ hash.each do |key, value|
187
+ self[key] = if block_given? && include?(key)
188
+ block.call(key, self[key], value)
189
+ else
190
+ value
191
+ end
192
+ end
193
+ self
194
+ end
195
+ alias merge! update
196
+
197
+ def values_at(*keys)
198
+ keys.map{|key| self[key]}
199
+ end
200
+
201
+ # :nocov:
202
+ if RUBY_VERSION >= '2.5'
203
+ # :nocov:
204
+ def slice(*a)
205
+ h = self.class.new
206
+ a.each{|k| h[k] = self[k] if has_key?(k)}
207
+ h
208
+ end
209
+
210
+ def transform_keys(&block)
211
+ dup.transform_keys!(&block)
212
+ end
213
+
214
+ def transform_keys!
215
+ hash = self.class.new
216
+ each do |k, v|
217
+ hash[yield k] = v
218
+ end
219
+ replace(hash)
220
+ end
221
+ end
222
+
223
+ # :nocov:
224
+ if RUBY_VERSION >= '3.0'
225
+ # :nocov:
226
+ def except(*a)
227
+ super(*a.map!{|key| downcase_key(key)})
228
+ end
229
+ end
230
+
231
+ private
232
+
233
+ def downcase_key(key)
234
+ key.is_a?(String) ? KNOWN_HEADERS[key] || key.downcase : key
235
+ end
236
+ end
237
+ end
238
+ end
data/lib/httpi/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module HTTPI
2
- VERSION = '3.0.2'
2
+ VERSION = '4.0.1'
3
3
  end
data/lib/httpi.rb CHANGED
@@ -3,6 +3,7 @@ require "httpi/version"
3
3
  require "httpi/logger"
4
4
  require "httpi/request"
5
5
  require "httpi/query_builder"
6
+ require "httpi/utils"
6
7
 
7
8
  require "httpi/adapter/httpclient"
8
9
  require "httpi/adapter/curb"
@@ -92,11 +92,11 @@ describe HTTPI::Request do
92
92
  after { HTTPI.query_builder = :flat }
93
93
 
94
94
  it "lets you specify query parameter as Hash" do
95
- expect(request.url.to_s).to eq("http://example.com?q[]=nested&q[]=query")
95
+ expect(request.url.to_s).to eq("http://example.com?q%5B%5D=nested&q%5B%5D=query")
96
96
  end
97
97
 
98
98
  it "getter return String for query parameter as Hash" do
99
- expect(request.query).to eq("q[]=nested&q[]=query")
99
+ expect(request.query).to eq("q%5B%5D=nested&q%5B%5D=query")
100
100
  end
101
101
  end
102
102
  end
@@ -149,7 +149,7 @@ describe HTTPI::Request do
149
149
  describe "#headers" do
150
150
  it "lets you specify a Hash of HTTP request headers" do
151
151
  request.headers = { "Accept-Encoding" => "gzip" }
152
- expect(request.headers).to eq({ "Accept-Encoding" => "gzip" })
152
+ expect(request.headers).to eq HTTPI::Utils::Headers.new.merge({ "Accept-Encoding" => "gzip" })
153
153
  end
154
154
 
155
155
  it "defaults to return an empty Hash" do
@@ -235,7 +235,7 @@ describe HTTPI::Request do
235
235
  end
236
236
  it "request body using a Hash with Array" do
237
237
  request.body = {:foo => :bar, :baz => [:foo, :tst]}
238
- expect(request.body.split("&")).to match_array(["foo=bar", "baz[]=foo", "baz[]=tst"])
238
+ expect(request.body.split("&")).to match_array(["foo=bar", "baz%5B%5D=foo", "baz%5B%5D=tst"])
239
239
  end
240
240
  end
241
241
  end
@@ -88,7 +88,7 @@ describe HTTPI::Response do
88
88
 
89
89
  describe "#headers" do
90
90
  it "returns the HTTP response headers" do
91
- expect(response.headers).to eq({ "Content-Encoding" => "gzip" })
91
+ expect(response.headers).to eq HTTPI::Utils::Headers.new.merge({ "Content-Encoding" => "gzip" })
92
92
  end
93
93
  end
94
94
 
@@ -116,7 +116,7 @@ describe HTTPI::Response do
116
116
 
117
117
  describe "#headers" do
118
118
  it "returns the HTTP response headers" do
119
- expect(response.headers).to eq({ "Content-Type" => "application/dime" })
119
+ expect(response.headers).to eq HTTPI::Utils::Headers.new.merge({ "Content-Type" => "application/dime" })
120
120
  end
121
121
  end
122
122
 
@@ -57,7 +57,7 @@ class IntegrationServer
57
57
  private
58
58
 
59
59
  def events
60
- Puma::Events.new($stdout, $stderr)
60
+ Puma::Events.new
61
61
  end
62
62
 
63
63
  def add_tcp_listener
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: httpi
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.2
4
+ version: 4.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Harrington
@@ -9,22 +9,28 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2024-02-11 00:00:00.000000000 Z
12
+ date: 2024-02-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '2.0'
18
21
  - - "<"
19
22
  - !ruby/object:Gem::Version
20
- version: '3'
23
+ version: '3.1'
21
24
  type: :runtime
22
25
  prerelease: false
23
26
  version_requirements: !ruby/object:Gem::Requirement
24
27
  requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ version: '2.0'
25
31
  - - "<"
26
32
  - !ruby/object:Gem::Version
27
- version: '3'
33
+ version: '3.1'
28
34
  - !ruby/object:Gem::Dependency
29
35
  name: nkf
30
36
  requirement: !ruby/object:Gem::Requirement
@@ -129,14 +135,14 @@ dependencies:
129
135
  requirements:
130
136
  - - "~>"
131
137
  - !ruby/object:Gem::Version
132
- version: '5.0'
138
+ version: '6.0'
133
139
  type: :development
134
140
  prerelease: false
135
141
  version_requirements: !ruby/object:Gem::Requirement
136
142
  requirements:
137
143
  - - "~>"
138
144
  - !ruby/object:Gem::Version
139
- version: '5.0'
145
+ version: '6.0'
140
146
  - !ruby/object:Gem::Dependency
141
147
  name: webmock
142
148
  requirement: !ruby/object:Gem::Requirement
@@ -188,6 +194,7 @@ files:
188
194
  - lib/httpi/query_builder.rb
189
195
  - lib/httpi/request.rb
190
196
  - lib/httpi/response.rb
197
+ - lib/httpi/utils.rb
191
198
  - lib/httpi/version.rb
192
199
  - spec/fixtures/attachment.gif
193
200
  - spec/fixtures/client_cert.pem