faraday 1.3.0 → 1.4.3
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 +4 -4
- data/CHANGELOG.md +30 -0
- data/README.md +1 -2
- data/lib/faraday.rb +4 -0
- data/lib/faraday/adapter.rb +0 -7
- data/lib/faraday/autoload.rb +0 -4
- data/lib/faraday/connection.rb +10 -3
- data/lib/faraday/options/proxy_options.rb +4 -0
- data/lib/faraday/version.rb +1 -1
- data/spec/faraday/connection_spec.rb +45 -0
- data/spec/faraday/options/proxy_options_spec.rb +7 -0
- metadata +62 -13
- data/lib/faraday/adapter/em_http.rb +0 -289
- data/lib/faraday/adapter/em_http_ssl_patch.rb +0 -62
- data/lib/faraday/adapter/em_synchrony.rb +0 -153
- data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +0 -69
- data/lib/faraday/adapter/excon.rb +0 -124
- data/lib/faraday/adapter/net_http_persistent.rb +0 -91
- data/spec/faraday/adapter/net_http_persistent_spec.rb +0 -57
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bc82ee913ef4ffa6468eea5e656c49d4eab0f769321eb63a85fdb4caa9a90143
|
4
|
+
data.tar.gz: cccf1ae40f10f353ca2cc5e4e92bb01e4b1d65a9ac3ed50b7e5c5951680ba019
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5360375fef63ad3e1068792458dd8ccc956b603be65e5571b9b6ce73938fc7ba2d220aeb99d4f3b022fa9945a07c8264c6452916e58963883fdd6843ded2d58e
|
7
|
+
data.tar.gz: fac76254509856e7e827fecda3c76a070c53cdb1771782ff5d668f14a4b8a4b126be9761d0856fe28eccda4607daf031cb7c8ea4559e245b100db08e95f01a0a
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,35 @@
|
|
1
1
|
# Faraday Changelog
|
2
2
|
|
3
|
+
## [v1.3.0](https://github.com/lostisland/faraday/releases/tag/v1.3.0) (2020-12-31)
|
4
|
+
|
5
|
+
### Highlights
|
6
|
+
Faraday v1.3.0 is the first release to officially support Ruby 3.0 in the CI pipeline 🎉 🍾!
|
7
|
+
|
8
|
+
This is also the first release with a previously "included" adapter (Net::HTTP) being isolated into a [separate gem](https://github.com/lostisland/faraday-net_http) 🎊!
|
9
|
+
The new adapter is added to Faraday as a dependency for now, so that means full backwards-compatibility, but just to be safe be careful when upgrading!
|
10
|
+
|
11
|
+
This is a huge step towards are Faraday v2.0 objective of pushing adapters and middleware into separate gems.
|
12
|
+
Many thanks to the Faraday Team, @JanDintel and everyone who attended the [ROSS Conf remote event](https://www.rossconf.io/event/remote/)
|
13
|
+
|
14
|
+
### Features
|
15
|
+
|
16
|
+
* Improves consistency with Faraday::Error and Faraday::RaiseError (#1229, @qsona, @iMacTia)
|
17
|
+
|
18
|
+
### Fixes
|
19
|
+
|
20
|
+
* Don't assign to global ::Timer (#1227, @bpo)
|
21
|
+
|
22
|
+
### Documentation
|
23
|
+
|
24
|
+
* CHANGELOG: add releases after 1.0 (#1225, @olleolleolle)
|
25
|
+
* Improves retry middleware documentation. (#1228, @iMacTia)
|
26
|
+
|
27
|
+
### Misc
|
28
|
+
|
29
|
+
* Move out Net::HTTP adapter (#1222, @JanDintel, @iMacTia)
|
30
|
+
* Adds Ruby 3.0 to CI Matrix (#1226, @iMacTia)
|
31
|
+
|
32
|
+
|
3
33
|
## [v1.2.0](https://github.com/lostisland/faraday/releases/tag/v1.2.0) (2020-12-23)
|
4
34
|
|
5
35
|
### Features
|
data/README.md
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
[](https://rubygems.org/gems/faraday)
|
4
4
|
[](https://github.com/lostisland/faraday/actions?query=workflow%3ACI)
|
5
|
-
[](https://codeclimate.com/github/lostisland/faraday/maintainability)
|
6
5
|
[](https://gitter.im/lostisland/faraday?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
7
6
|
|
8
7
|
|
@@ -47,7 +46,7 @@ But before you start coding, please read our [Contributing Guide][contributing]
|
|
47
46
|
[website]: https://lostisland.github.io/faraday
|
48
47
|
[faraday_team]: https://lostisland.github.io/faraday/team
|
49
48
|
[contributing]: https://github.com/lostisland/faraday/blob/master/.github/CONTRIBUTING.md
|
50
|
-
[apidoc]:
|
49
|
+
[apidoc]: https://www.rubydoc.info/github/lostisland/faraday
|
51
50
|
[actions]: https://github.com/lostisland/faraday/actions
|
52
51
|
[jruby]: http://jruby.org/
|
53
52
|
[rubinius]: http://rubini.us/
|
data/lib/faraday.rb
CHANGED
@@ -27,7 +27,11 @@ require 'faraday/error'
|
|
27
27
|
require 'faraday/file_part'
|
28
28
|
require 'faraday/param_part'
|
29
29
|
|
30
|
+
require 'faraday/em_http'
|
31
|
+
require 'faraday/em_synchrony'
|
32
|
+
require 'faraday/excon'
|
30
33
|
require 'faraday/net_http'
|
34
|
+
require 'faraday/net_http_persistent'
|
31
35
|
|
32
36
|
# This is the main namespace for Faraday.
|
33
37
|
#
|
data/lib/faraday/adapter.rb
CHANGED
@@ -11,15 +11,8 @@ module Faraday
|
|
11
11
|
|
12
12
|
register_middleware File.expand_path('adapter', __dir__),
|
13
13
|
test: [:Test, 'test'],
|
14
|
-
net_http_persistent: [
|
15
|
-
:NetHttpPersistent,
|
16
|
-
'net_http_persistent'
|
17
|
-
],
|
18
14
|
typhoeus: [:Typhoeus, 'typhoeus'],
|
19
15
|
patron: [:Patron, 'patron'],
|
20
|
-
em_synchrony: [:EMSynchrony, 'em_synchrony'],
|
21
|
-
em_http: [:EMHttp, 'em_http'],
|
22
|
-
excon: [:Excon, 'excon'],
|
23
16
|
rack: [:Rack, 'rack'],
|
24
17
|
httpclient: [:HTTPClient, 'httpclient']
|
25
18
|
|
data/lib/faraday/autoload.rb
CHANGED
@@ -58,12 +58,8 @@ module Faraday
|
|
58
58
|
class Adapter
|
59
59
|
extend AutoloadHelper
|
60
60
|
autoload_all 'faraday/adapter',
|
61
|
-
NetHttpPersistent: 'net_http_persistent',
|
62
|
-
EMSynchrony: 'em_synchrony',
|
63
|
-
EMHttp: 'em_http',
|
64
61
|
Typhoeus: 'typhoeus',
|
65
62
|
Patron: 'patron',
|
66
|
-
Excon: 'excon',
|
67
63
|
Test: 'test',
|
68
64
|
Rack: 'rack',
|
69
65
|
HTTPClient: 'httpclient'
|
data/lib/faraday/connection.rb
CHANGED
@@ -73,6 +73,7 @@ module Faraday
|
|
73
73
|
@options = options.request
|
74
74
|
@ssl = options.ssl
|
75
75
|
@default_parallel_manager = options.parallel_manager
|
76
|
+
@manual_proxy = nil
|
76
77
|
|
77
78
|
@builder = options.builder || begin
|
78
79
|
# pass an empty block to Builder so it doesn't assume default middleware
|
@@ -419,6 +420,8 @@ module Faraday
|
|
419
420
|
basic_auth user, password
|
420
421
|
uri.user = uri.password = nil
|
421
422
|
end
|
423
|
+
|
424
|
+
@proxy = proxy_from_env(url) unless @manual_proxy
|
422
425
|
end
|
423
426
|
|
424
427
|
# Sets the path prefix and ensures that it always has a leading
|
@@ -517,11 +520,11 @@ module Faraday
|
|
517
520
|
# @return [URI]
|
518
521
|
def build_exclusive_url(url = nil, params = nil, params_encoder = nil)
|
519
522
|
url = nil if url.respond_to?(:empty?) && url.empty?
|
520
|
-
base = url_prefix
|
523
|
+
base = url_prefix.dup
|
521
524
|
if url && base.path && base.path !~ %r{/$}
|
522
|
-
base = base.dup
|
523
525
|
base.path = "#{base.path}/" # ensure trailing slash
|
524
526
|
end
|
527
|
+
url = url && URI.parse(url.to_s).opaque ? url.to_s.gsub(':', '%3A') : url
|
525
528
|
uri = url ? base + url : base
|
526
529
|
if params
|
527
530
|
uri.query = params.to_query(params_encoder || options.params_encoder)
|
@@ -576,7 +579,11 @@ module Faraday
|
|
576
579
|
case url
|
577
580
|
when String
|
578
581
|
uri = Utils.URI(url)
|
579
|
-
uri =
|
582
|
+
uri = if uri.host.nil?
|
583
|
+
find_default_proxy
|
584
|
+
else
|
585
|
+
URI.parse("#{uri.scheme}://#{uri.host}").find_proxy
|
586
|
+
end
|
580
587
|
when URI
|
581
588
|
uri = url.find_proxy
|
582
589
|
when nil
|
@@ -11,6 +11,9 @@ module Faraday
|
|
11
11
|
def self.from(value)
|
12
12
|
case value
|
13
13
|
when String
|
14
|
+
# URIs without a scheme should default to http (like 'example:123').
|
15
|
+
# This fixes #1282 and prevents a silent failure in some adapters.
|
16
|
+
value = "http://#{value}" unless value.include?('://')
|
14
17
|
value = { uri: Utils.URI(value) }
|
15
18
|
when URI
|
16
19
|
value = { uri: value }
|
@@ -19,6 +22,7 @@ module Faraday
|
|
19
22
|
value[:uri] = Utils.URI(uri)
|
20
23
|
end
|
21
24
|
end
|
25
|
+
|
22
26
|
super(value)
|
23
27
|
end
|
24
28
|
|
data/lib/faraday/version.rb
CHANGED
@@ -18,6 +18,13 @@ shared_examples 'initializer with url' do
|
|
18
18
|
it { expect(subject.path_prefix).to eq('/fish') }
|
19
19
|
it { expect(subject.params).to eq('a' => '1') }
|
20
20
|
end
|
21
|
+
|
22
|
+
context 'with IPv6 address' do
|
23
|
+
let(:address) { 'http://[::1]:85/' }
|
24
|
+
|
25
|
+
it { expect(subject.host).to eq('[::1]') }
|
26
|
+
it { expect(subject.port).to eq(85) }
|
27
|
+
end
|
21
28
|
end
|
22
29
|
|
23
30
|
shared_examples 'default connection options' do
|
@@ -246,6 +253,13 @@ RSpec.describe Faraday::Connection do
|
|
246
253
|
expect(uri.path).to eq('/sake.html')
|
247
254
|
end
|
248
255
|
|
256
|
+
it 'always returns new URI instance' do
|
257
|
+
conn.url_prefix = 'http://sushi.com'
|
258
|
+
uri1 = conn.build_exclusive_url(nil)
|
259
|
+
uri2 = conn.build_exclusive_url(nil)
|
260
|
+
expect(uri1).not_to equal(uri2)
|
261
|
+
end
|
262
|
+
|
249
263
|
context 'with url_prefixed connection' do
|
250
264
|
let(:url) { 'http://sushi.com/sushi/' }
|
251
265
|
|
@@ -270,6 +284,29 @@ RSpec.describe Faraday::Connection do
|
|
270
284
|
expect(uri.to_s).to eq('http://sushi.com/sake/')
|
271
285
|
end
|
272
286
|
end
|
287
|
+
|
288
|
+
context 'with colon in path' do
|
289
|
+
let(:url) { 'http://service.com' }
|
290
|
+
|
291
|
+
it 'joins url to base when used absolute path' do
|
292
|
+
conn = Faraday.new(url: url)
|
293
|
+
uri = conn.build_exclusive_url('/service:search?limit=400')
|
294
|
+
expect(uri.to_s).to eq('http://service.com/service:search?limit=400')
|
295
|
+
end
|
296
|
+
|
297
|
+
it 'joins url to base when used relative path' do
|
298
|
+
conn = Faraday.new(url: url)
|
299
|
+
uri = conn.build_exclusive_url('service:search?limit=400')
|
300
|
+
expect(uri.to_s).to eq('http://service.com/service%3Asearch?limit=400')
|
301
|
+
end
|
302
|
+
|
303
|
+
it 'joins url to base when used with path prefix' do
|
304
|
+
conn = Faraday.new(url: url)
|
305
|
+
conn.path_prefix = '/api'
|
306
|
+
uri = conn.build_exclusive_url('service:search?limit=400')
|
307
|
+
expect(uri.to_s).to eq('http://service.com/api/service%3Asearch?limit=400')
|
308
|
+
end
|
309
|
+
end
|
273
310
|
end
|
274
311
|
|
275
312
|
describe '#build_url' do
|
@@ -412,6 +449,14 @@ RSpec.describe Faraday::Connection do
|
|
412
449
|
end
|
413
450
|
end
|
414
451
|
|
452
|
+
it 'allows when url in no proxy list with url_prefix' do
|
453
|
+
with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'example.com' do
|
454
|
+
conn = Faraday::Connection.new
|
455
|
+
conn.url_prefix = 'http://example.com'
|
456
|
+
expect(conn.proxy).to be_nil
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
415
460
|
it 'allows when prefixed url is not in no proxy list' do
|
416
461
|
with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'example.com' do
|
417
462
|
conn = Faraday::Connection.new('http://prefixedexample.com')
|
@@ -14,6 +14,13 @@ RSpec.describe Faraday::ProxyOptions do
|
|
14
14
|
expect(options.inspect).to match('#<Faraday::ProxyOptions uri=')
|
15
15
|
end
|
16
16
|
|
17
|
+
it 'defaults to http' do
|
18
|
+
options = Faraday::ProxyOptions.from 'example.org'
|
19
|
+
expect(options.port).to eq(80)
|
20
|
+
expect(options.host).to eq('example.org')
|
21
|
+
expect(options.scheme).to eq('http')
|
22
|
+
end
|
23
|
+
|
17
24
|
it 'works with nil' do
|
18
25
|
options = Faraday::ProxyOptions.from nil
|
19
26
|
expect(options).to be_a_kind_of(Faraday::ProxyOptions)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: faraday
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.3
|
4
|
+
version: 1.4.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- "@technoweenie"
|
@@ -10,8 +10,50 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2021-06-24 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: faraday-em_http
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - "~>"
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - "~>"
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: '1.0'
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: faraday-em_synchrony
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - "~>"
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '1.0'
|
36
|
+
type: :runtime
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - "~>"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '1.0'
|
43
|
+
- !ruby/object:Gem::Dependency
|
44
|
+
name: faraday-excon
|
45
|
+
requirement: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '1.1'
|
50
|
+
type: :runtime
|
51
|
+
prerelease: false
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - "~>"
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '1.1'
|
15
57
|
- !ruby/object:Gem::Dependency
|
16
58
|
name: faraday-net_http
|
17
59
|
requirement: !ruby/object:Gem::Requirement
|
@@ -26,6 +68,20 @@ dependencies:
|
|
26
68
|
- - "~>"
|
27
69
|
- !ruby/object:Gem::Version
|
28
70
|
version: '1.0'
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: faraday-net_http_persistent
|
73
|
+
requirement: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - "~>"
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '1.1'
|
78
|
+
type: :runtime
|
79
|
+
prerelease: false
|
80
|
+
version_requirements: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - "~>"
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '1.1'
|
29
85
|
- !ruby/object:Gem::Dependency
|
30
86
|
name: multipart-post
|
31
87
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,14 +108,14 @@ dependencies:
|
|
52
108
|
requirements:
|
53
109
|
- - ">="
|
54
110
|
- !ruby/object:Gem::Version
|
55
|
-
version:
|
111
|
+
version: 0.0.4
|
56
112
|
type: :runtime
|
57
113
|
prerelease: false
|
58
114
|
version_requirements: !ruby/object:Gem::Requirement
|
59
115
|
requirements:
|
60
116
|
- - ">="
|
61
117
|
- !ruby/object:Gem::Version
|
62
|
-
version:
|
118
|
+
version: 0.0.4
|
63
119
|
description:
|
64
120
|
email: technoweenie@gmail.com
|
65
121
|
executables: []
|
@@ -74,13 +130,7 @@ files:
|
|
74
130
|
- examples/client_test.rb
|
75
131
|
- lib/faraday.rb
|
76
132
|
- lib/faraday/adapter.rb
|
77
|
-
- lib/faraday/adapter/em_http.rb
|
78
|
-
- lib/faraday/adapter/em_http_ssl_patch.rb
|
79
|
-
- lib/faraday/adapter/em_synchrony.rb
|
80
|
-
- lib/faraday/adapter/em_synchrony/parallel_manager.rb
|
81
|
-
- lib/faraday/adapter/excon.rb
|
82
133
|
- lib/faraday/adapter/httpclient.rb
|
83
|
-
- lib/faraday/adapter/net_http_persistent.rb
|
84
134
|
- lib/faraday/adapter/patron.rb
|
85
135
|
- lib/faraday/adapter/rack.rb
|
86
136
|
- lib/faraday/adapter/test.rb
|
@@ -126,7 +176,6 @@ files:
|
|
126
176
|
- spec/faraday/adapter/em_synchrony_spec.rb
|
127
177
|
- spec/faraday/adapter/excon_spec.rb
|
128
178
|
- spec/faraday/adapter/httpclient_spec.rb
|
129
|
-
- spec/faraday/adapter/net_http_persistent_spec.rb
|
130
179
|
- spec/faraday/adapter/net_http_spec.rb
|
131
180
|
- spec/faraday/adapter/patron_spec.rb
|
132
181
|
- spec/faraday/adapter/rack_spec.rb
|
@@ -172,7 +221,7 @@ licenses:
|
|
172
221
|
- MIT
|
173
222
|
metadata:
|
174
223
|
homepage_uri: https://lostisland.github.io/faraday
|
175
|
-
changelog_uri: https://github.com/lostisland/faraday/releases/tag/v1.3
|
224
|
+
changelog_uri: https://github.com/lostisland/faraday/releases/tag/v1.4.3
|
176
225
|
source_code_uri: https://github.com/lostisland/faraday
|
177
226
|
bug_tracker_uri: https://github.com/lostisland/faraday/issues
|
178
227
|
post_install_message:
|
@@ -191,7 +240,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
191
240
|
- !ruby/object:Gem::Version
|
192
241
|
version: '0'
|
193
242
|
requirements: []
|
194
|
-
rubygems_version: 3.0.3
|
243
|
+
rubygems_version: 3.0.3.1
|
195
244
|
signing_key:
|
196
245
|
specification_version: 4
|
197
246
|
summary: HTTP/REST API client library.
|
@@ -1,289 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Faraday
|
4
|
-
class Adapter
|
5
|
-
# EventMachine adapter. This adapter is useful for either asynchronous
|
6
|
-
# requests when in an EM reactor loop, or for making parallel requests in
|
7
|
-
# synchronous code.
|
8
|
-
class EMHttp < Faraday::Adapter
|
9
|
-
# Options is a module containing helpers to convert the Faraday env object
|
10
|
-
# into options hashes for EMHTTP method calls.
|
11
|
-
module Options
|
12
|
-
# @return [Hash]
|
13
|
-
def connection_config(env)
|
14
|
-
options = {}
|
15
|
-
configure_proxy(options, env)
|
16
|
-
configure_timeout(options, env)
|
17
|
-
configure_socket(options, env)
|
18
|
-
configure_ssl(options, env)
|
19
|
-
options
|
20
|
-
end
|
21
|
-
|
22
|
-
def request_config(env)
|
23
|
-
options = {
|
24
|
-
body: read_body(env),
|
25
|
-
head: env[:request_headers]
|
26
|
-
# keepalive: true,
|
27
|
-
# file: 'path/to/file', # stream data off disk
|
28
|
-
}
|
29
|
-
configure_compression(options, env)
|
30
|
-
options
|
31
|
-
end
|
32
|
-
|
33
|
-
def read_body(env)
|
34
|
-
body = env[:body]
|
35
|
-
body.respond_to?(:read) ? body.read : body
|
36
|
-
end
|
37
|
-
|
38
|
-
# Reads out proxy settings from env into options
|
39
|
-
def configure_proxy(options, env)
|
40
|
-
proxy = request_options(env)[:proxy]
|
41
|
-
return unless proxy
|
42
|
-
|
43
|
-
options[:proxy] = {
|
44
|
-
host: proxy[:uri].host,
|
45
|
-
port: proxy[:uri].port,
|
46
|
-
authorization: [proxy[:user], proxy[:password]]
|
47
|
-
}
|
48
|
-
end
|
49
|
-
|
50
|
-
# Reads out host and port settings from env into options
|
51
|
-
def configure_socket(options, env)
|
52
|
-
bind = request_options(env)[:bind]
|
53
|
-
return unless bind
|
54
|
-
|
55
|
-
options[:bind] = {
|
56
|
-
host: bind[:host],
|
57
|
-
port: bind[:port]
|
58
|
-
}
|
59
|
-
end
|
60
|
-
|
61
|
-
# Reads out SSL certificate settings from env into options
|
62
|
-
def configure_ssl(options, env)
|
63
|
-
return unless env[:url].scheme == 'https' && env[:ssl]
|
64
|
-
|
65
|
-
options[:ssl] = {
|
66
|
-
cert_chain_file: env[:ssl][:ca_file],
|
67
|
-
verify_peer: env[:ssl].fetch(:verify, true)
|
68
|
-
}
|
69
|
-
end
|
70
|
-
|
71
|
-
# Reads out timeout settings from env into options
|
72
|
-
def configure_timeout(options, env)
|
73
|
-
req = request_options(env)
|
74
|
-
options[:inactivity_timeout] = request_timeout(:read, req)
|
75
|
-
options[:connect_timeout] = request_timeout(:open, req)
|
76
|
-
end
|
77
|
-
|
78
|
-
# Reads out compression header settings from env into options
|
79
|
-
def configure_compression(options, env)
|
80
|
-
return unless (env[:method] == :get) &&
|
81
|
-
!options[:head].key?('accept-encoding')
|
82
|
-
|
83
|
-
options[:head]['accept-encoding'] = 'gzip, compressed'
|
84
|
-
end
|
85
|
-
|
86
|
-
def request_options(env)
|
87
|
-
env[:request]
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
include Options
|
92
|
-
|
93
|
-
dependency do
|
94
|
-
require 'em-http'
|
95
|
-
|
96
|
-
begin
|
97
|
-
require 'openssl'
|
98
|
-
rescue LoadError
|
99
|
-
warn 'Warning: no such file to load -- openssl. ' \
|
100
|
-
'Make sure it is installed if you want HTTPS support'
|
101
|
-
else
|
102
|
-
require 'em-http/version'
|
103
|
-
if EventMachine::HttpRequest::VERSION < '1.1.6'
|
104
|
-
require 'faraday/adapter/em_http_ssl_patch'
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
self.supports_parallel = true
|
110
|
-
|
111
|
-
# @return [Manager]
|
112
|
-
def self.setup_parallel_manager(_options = nil)
|
113
|
-
Manager.new
|
114
|
-
end
|
115
|
-
|
116
|
-
def call(env)
|
117
|
-
super
|
118
|
-
perform_request env
|
119
|
-
@app.call env
|
120
|
-
end
|
121
|
-
|
122
|
-
def perform_request(env)
|
123
|
-
if parallel?(env)
|
124
|
-
manager = env[:parallel_manager]
|
125
|
-
manager.add do
|
126
|
-
perform_single_request(env)
|
127
|
-
.callback { env[:response].finish(env) }
|
128
|
-
end
|
129
|
-
elsif EventMachine.reactor_running?
|
130
|
-
# EM is running: instruct upstream that this is an async request
|
131
|
-
env[:parallel_manager] = true
|
132
|
-
perform_single_request(env)
|
133
|
-
.callback { env[:response].finish(env) }
|
134
|
-
.errback do
|
135
|
-
# TODO: no way to communicate the error in async mode
|
136
|
-
raise NotImplementedError
|
137
|
-
end
|
138
|
-
else
|
139
|
-
error = nil
|
140
|
-
# start EM, block until request is completed
|
141
|
-
EventMachine.run do
|
142
|
-
perform_single_request(env)
|
143
|
-
.callback { EventMachine.stop }
|
144
|
-
.errback do |client|
|
145
|
-
error = error_message(client)
|
146
|
-
EventMachine.stop
|
147
|
-
end
|
148
|
-
end
|
149
|
-
raise_error(error) if error
|
150
|
-
end
|
151
|
-
rescue EventMachine::Connectify::CONNECTError => e
|
152
|
-
if e.message.include?('Proxy Authentication Required')
|
153
|
-
raise Faraday::ConnectionFailed,
|
154
|
-
%(407 "Proxy Authentication Required ")
|
155
|
-
end
|
156
|
-
|
157
|
-
raise Faraday::ConnectionFailed, e
|
158
|
-
rescue StandardError => e
|
159
|
-
if defined?(::OpenSSL::SSL::SSLError) && \
|
160
|
-
e.is_a?(::OpenSSL::SSL::SSLError)
|
161
|
-
raise Faraday::SSLError, e
|
162
|
-
end
|
163
|
-
|
164
|
-
raise
|
165
|
-
end
|
166
|
-
|
167
|
-
# TODO: reuse the connection to support pipelining
|
168
|
-
def perform_single_request(env)
|
169
|
-
req = create_request(env)
|
170
|
-
req = req.setup_request(env[:method], request_config(env))
|
171
|
-
req.callback do |client|
|
172
|
-
if env[:request].stream_response?
|
173
|
-
warn "Streaming downloads for #{self.class.name} " \
|
174
|
-
'are not yet implemented.'
|
175
|
-
env[:request].on_data.call(
|
176
|
-
client.response,
|
177
|
-
client.response.bytesize
|
178
|
-
)
|
179
|
-
end
|
180
|
-
status = client.response_header.status
|
181
|
-
reason = client.response_header.http_reason
|
182
|
-
save_response(env, status, client.response, nil, reason) do |headers|
|
183
|
-
client.response_header.each do |name, value|
|
184
|
-
headers[name.to_sym] = value
|
185
|
-
end
|
186
|
-
end
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
|
-
def create_request(env)
|
191
|
-
EventMachine::HttpRequest.new(
|
192
|
-
env[:url], connection_config(env).merge(@connection_options)
|
193
|
-
)
|
194
|
-
end
|
195
|
-
|
196
|
-
def error_message(client)
|
197
|
-
client.error || 'request failed'
|
198
|
-
end
|
199
|
-
|
200
|
-
def raise_error(msg)
|
201
|
-
error_class = Faraday::ClientError
|
202
|
-
if timeout_message?(msg)
|
203
|
-
error_class = Faraday::TimeoutError
|
204
|
-
msg = 'request timed out'
|
205
|
-
elsif msg == Errno::ECONNREFUSED
|
206
|
-
error_class = Faraday::ConnectionFailed
|
207
|
-
msg = 'connection refused'
|
208
|
-
elsif msg == 'connection closed by server'
|
209
|
-
error_class = Faraday::ConnectionFailed
|
210
|
-
end
|
211
|
-
raise error_class, msg
|
212
|
-
end
|
213
|
-
|
214
|
-
def timeout_message?(msg)
|
215
|
-
msg == Errno::ETIMEDOUT ||
|
216
|
-
(msg.is_a?(String) && msg.include?('timeout error'))
|
217
|
-
end
|
218
|
-
|
219
|
-
# @return [Boolean]
|
220
|
-
def parallel?(env)
|
221
|
-
!!env[:parallel_manager]
|
222
|
-
end
|
223
|
-
|
224
|
-
# This parallel manager is designed to start an EventMachine loop
|
225
|
-
# and block until all registered requests have been completed.
|
226
|
-
class Manager
|
227
|
-
# @see reset
|
228
|
-
def initialize
|
229
|
-
reset
|
230
|
-
end
|
231
|
-
|
232
|
-
# Re-initializes instance variables
|
233
|
-
def reset
|
234
|
-
@registered_procs = []
|
235
|
-
@num_registered = 0
|
236
|
-
@num_succeeded = 0
|
237
|
-
@errors = []
|
238
|
-
@running = false
|
239
|
-
end
|
240
|
-
|
241
|
-
# @return [Boolean]
|
242
|
-
def running?
|
243
|
-
@running
|
244
|
-
end
|
245
|
-
|
246
|
-
def add(&block)
|
247
|
-
if running?
|
248
|
-
perform_request(&block)
|
249
|
-
else
|
250
|
-
@registered_procs << block
|
251
|
-
end
|
252
|
-
@num_registered += 1
|
253
|
-
end
|
254
|
-
|
255
|
-
def run
|
256
|
-
if @num_registered.positive?
|
257
|
-
@running = true
|
258
|
-
EventMachine.run do
|
259
|
-
@registered_procs.each do |proc|
|
260
|
-
perform_request(&proc)
|
261
|
-
end
|
262
|
-
end
|
263
|
-
unless @errors.empty?
|
264
|
-
raise Faraday::ClientError, @errors.first || 'connection failed'
|
265
|
-
end
|
266
|
-
end
|
267
|
-
ensure
|
268
|
-
reset
|
269
|
-
end
|
270
|
-
|
271
|
-
def perform_request
|
272
|
-
client = yield
|
273
|
-
client.callback do
|
274
|
-
@num_succeeded += 1
|
275
|
-
check_finished
|
276
|
-
end
|
277
|
-
client.errback do
|
278
|
-
@errors << client.error
|
279
|
-
check_finished
|
280
|
-
end
|
281
|
-
end
|
282
|
-
|
283
|
-
def check_finished
|
284
|
-
EventMachine.stop if @num_succeeded + @errors.size == @num_registered
|
285
|
-
end
|
286
|
-
end
|
287
|
-
end
|
288
|
-
end
|
289
|
-
end
|
@@ -1,62 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'openssl'
|
4
|
-
require 'em-http'
|
5
|
-
|
6
|
-
# EventMachine patch to make SSL work.
|
7
|
-
module EmHttpSslPatch
|
8
|
-
def ssl_verify_peer(cert_string)
|
9
|
-
begin
|
10
|
-
@last_seen_cert = OpenSSL::X509::Certificate.new(cert_string)
|
11
|
-
rescue OpenSSL::X509::CertificateError
|
12
|
-
return false
|
13
|
-
end
|
14
|
-
|
15
|
-
unless certificate_store.verify(@last_seen_cert)
|
16
|
-
raise OpenSSL::SSL::SSLError,
|
17
|
-
%(unable to verify the server certificate for "#{host}")
|
18
|
-
end
|
19
|
-
|
20
|
-
begin
|
21
|
-
certificate_store.add_cert(@last_seen_cert)
|
22
|
-
rescue OpenSSL::X509::StoreError => e
|
23
|
-
raise e unless e.message == 'cert already in hash table'
|
24
|
-
end
|
25
|
-
true
|
26
|
-
end
|
27
|
-
|
28
|
-
def ssl_handshake_completed
|
29
|
-
return true unless verify_peer?
|
30
|
-
|
31
|
-
unless verified_cert_identity?
|
32
|
-
raise OpenSSL::SSL::SSLError,
|
33
|
-
%(host "#{host}" does not match the server certificate)
|
34
|
-
end
|
35
|
-
|
36
|
-
true
|
37
|
-
end
|
38
|
-
|
39
|
-
def verify_peer?
|
40
|
-
parent.connopts.tls[:verify_peer]
|
41
|
-
end
|
42
|
-
|
43
|
-
def verified_cert_identity?
|
44
|
-
OpenSSL::SSL.verify_certificate_identity(@last_seen_cert, host)
|
45
|
-
end
|
46
|
-
|
47
|
-
def host
|
48
|
-
parent.uri.host
|
49
|
-
end
|
50
|
-
|
51
|
-
def certificate_store
|
52
|
-
@certificate_store ||= begin
|
53
|
-
store = OpenSSL::X509::Store.new
|
54
|
-
store.set_default_paths
|
55
|
-
ca_file = parent.connopts.tls[:cert_chain_file]
|
56
|
-
store.add_file(ca_file) if ca_file
|
57
|
-
store
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
EventMachine::HttpStubConnection.include(EmHttpSslPatch)
|
@@ -1,153 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'uri'
|
4
|
-
|
5
|
-
module Faraday
|
6
|
-
class Adapter
|
7
|
-
# EventMachine Synchrony adapter.
|
8
|
-
class EMSynchrony < Faraday::Adapter
|
9
|
-
include EMHttp::Options
|
10
|
-
|
11
|
-
dependency do
|
12
|
-
require 'em-synchrony/em-http'
|
13
|
-
require 'em-synchrony/em-multi'
|
14
|
-
require 'fiber'
|
15
|
-
|
16
|
-
require 'faraday/adapter/em_synchrony/parallel_manager'
|
17
|
-
|
18
|
-
if Faraday::Adapter::EMSynchrony.loaded?
|
19
|
-
begin
|
20
|
-
require 'openssl'
|
21
|
-
rescue LoadError
|
22
|
-
warn 'Warning: no such file to load -- openssl. ' \
|
23
|
-
'Make sure it is installed if you want HTTPS support'
|
24
|
-
else
|
25
|
-
require 'em-http/version'
|
26
|
-
if EventMachine::HttpRequest::VERSION < '1.1.6'
|
27
|
-
require 'faraday/adapter/em_http_ssl_patch'
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
self.supports_parallel = true
|
34
|
-
|
35
|
-
# @return [ParallelManager]
|
36
|
-
def self.setup_parallel_manager(_options = nil)
|
37
|
-
ParallelManager.new
|
38
|
-
end
|
39
|
-
|
40
|
-
def call(env)
|
41
|
-
super
|
42
|
-
request = create_request(env)
|
43
|
-
|
44
|
-
http_method = env[:method].to_s.downcase.to_sym
|
45
|
-
|
46
|
-
if env[:parallel_manager]
|
47
|
-
# Queue requests for parallel execution.
|
48
|
-
execute_parallel_request(env, request, http_method)
|
49
|
-
else
|
50
|
-
# Execute single request.
|
51
|
-
execute_single_request(env, request, http_method)
|
52
|
-
end
|
53
|
-
|
54
|
-
@app.call env
|
55
|
-
rescue Errno::ECONNREFUSED
|
56
|
-
raise Faraday::ConnectionFailed, $ERROR_INFO
|
57
|
-
rescue EventMachine::Connectify::CONNECTError => e
|
58
|
-
if e.message.include?('Proxy Authentication Required')
|
59
|
-
raise Faraday::ConnectionFailed,
|
60
|
-
%(407 "Proxy Authentication Required")
|
61
|
-
end
|
62
|
-
|
63
|
-
raise Faraday::ConnectionFailed, e
|
64
|
-
rescue Errno::ETIMEDOUT => e
|
65
|
-
raise Faraday::TimeoutError, e
|
66
|
-
rescue RuntimeError => e
|
67
|
-
if e.message == 'connection closed by server'
|
68
|
-
raise Faraday::ConnectionFailed, e
|
69
|
-
end
|
70
|
-
|
71
|
-
raise Faraday::TimeoutError, e if e.message.include?('timeout error')
|
72
|
-
|
73
|
-
raise
|
74
|
-
rescue StandardError => e
|
75
|
-
if defined?(OpenSSL) && e.is_a?(OpenSSL::SSL::SSLError)
|
76
|
-
raise Faraday::SSLError, e
|
77
|
-
end
|
78
|
-
|
79
|
-
raise
|
80
|
-
end
|
81
|
-
|
82
|
-
def create_request(env)
|
83
|
-
EventMachine::HttpRequest.new(
|
84
|
-
Utils::URI(env[:url].to_s),
|
85
|
-
connection_config(env).merge(@connection_options)
|
86
|
-
)
|
87
|
-
end
|
88
|
-
|
89
|
-
private
|
90
|
-
|
91
|
-
def execute_parallel_request(env, request, http_method)
|
92
|
-
env[:parallel_manager].add(request, http_method,
|
93
|
-
request_config(env)) do |resp|
|
94
|
-
if (req = env[:request]).stream_response?
|
95
|
-
warn "Streaming downloads for #{self.class.name} " \
|
96
|
-
'are not yet implemented.'
|
97
|
-
req.on_data.call(resp.response, resp.response.bytesize)
|
98
|
-
end
|
99
|
-
|
100
|
-
save_response(env, resp.response_header.status,
|
101
|
-
resp.response) do |resp_headers|
|
102
|
-
resp.response_header.each do |name, value|
|
103
|
-
resp_headers[name.to_sym] = value
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
# Finalize the response object with values from `env`.
|
108
|
-
env[:response].finish(env)
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
def execute_single_request(env, request, http_method)
|
113
|
-
block = -> { request.send(http_method, request_config(env)) }
|
114
|
-
client = call_block(block)
|
115
|
-
|
116
|
-
raise client.error if client&.error
|
117
|
-
|
118
|
-
if env[:request].stream_response?
|
119
|
-
warn "Streaming downloads for #{self.class.name} " \
|
120
|
-
'are not yet implemented.'
|
121
|
-
env[:request].on_data.call(
|
122
|
-
client.response,
|
123
|
-
client.response.bytesize
|
124
|
-
)
|
125
|
-
end
|
126
|
-
status = client.response_header.status
|
127
|
-
reason = client.response_header.http_reason
|
128
|
-
save_response(env, status, client.response, nil, reason) do |headers|
|
129
|
-
client.response_header.each do |name, value|
|
130
|
-
headers[name.to_sym] = value
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
def call_block(block)
|
136
|
-
client = nil
|
137
|
-
|
138
|
-
if EM.reactor_running?
|
139
|
-
client = block.call
|
140
|
-
else
|
141
|
-
EM.run do
|
142
|
-
Fiber.new do
|
143
|
-
client = block.call
|
144
|
-
EM.stop
|
145
|
-
end.resume
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
client
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
153
|
-
end
|
@@ -1,69 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Faraday
|
4
|
-
class Adapter
|
5
|
-
class EMSynchrony < Faraday::Adapter
|
6
|
-
# A parallel manager for EMSynchrony.
|
7
|
-
class ParallelManager
|
8
|
-
# Add requests to queue.
|
9
|
-
#
|
10
|
-
# @param request [EM::HttpRequest]
|
11
|
-
# @param method [Symbol, String] HTTP method
|
12
|
-
# @param args [Array] the rest of the positional arguments
|
13
|
-
def add(request, method, *args, &block)
|
14
|
-
queue << {
|
15
|
-
request: request,
|
16
|
-
method: method,
|
17
|
-
args: args,
|
18
|
-
block: block
|
19
|
-
}
|
20
|
-
end
|
21
|
-
|
22
|
-
# Run all requests on queue with `EM::Synchrony::Multi`, wrapping
|
23
|
-
# it in a reactor and fiber if needed.
|
24
|
-
def run
|
25
|
-
result = nil
|
26
|
-
if !EM.reactor_running?
|
27
|
-
EM.run do
|
28
|
-
Fiber.new do
|
29
|
-
result = perform
|
30
|
-
EM.stop
|
31
|
-
end.resume
|
32
|
-
end
|
33
|
-
else
|
34
|
-
result = perform
|
35
|
-
end
|
36
|
-
result
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
|
41
|
-
# The request queue.
|
42
|
-
def queue
|
43
|
-
@queue ||= []
|
44
|
-
end
|
45
|
-
|
46
|
-
# Main `EM::Synchrony::Multi` performer.
|
47
|
-
def perform
|
48
|
-
multi = ::EM::Synchrony::Multi.new
|
49
|
-
|
50
|
-
queue.each do |item|
|
51
|
-
method = "a#{item[:method]}".to_sym
|
52
|
-
|
53
|
-
req = item[:request].send(method, *item[:args])
|
54
|
-
req.callback(&item[:block])
|
55
|
-
|
56
|
-
req_name = "req_#{multi.requests.size}".to_sym
|
57
|
-
multi.add(req_name, req)
|
58
|
-
end
|
59
|
-
|
60
|
-
# Clear the queue, so parallel manager objects can be reused.
|
61
|
-
@queue = []
|
62
|
-
|
63
|
-
# Block fiber until all requests have returned.
|
64
|
-
multi.perform
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
@@ -1,124 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Faraday
|
4
|
-
class Adapter
|
5
|
-
# Excon adapter.
|
6
|
-
class Excon < Faraday::Adapter
|
7
|
-
dependency 'excon'
|
8
|
-
|
9
|
-
def build_connection(env)
|
10
|
-
opts = opts_from_env(env)
|
11
|
-
::Excon.new(env[:url].to_s, opts.merge(@connection_options))
|
12
|
-
end
|
13
|
-
|
14
|
-
def call(env)
|
15
|
-
super
|
16
|
-
|
17
|
-
req_opts = {
|
18
|
-
method: env[:method].to_s.upcase,
|
19
|
-
headers: env[:request_headers],
|
20
|
-
body: read_body(env)
|
21
|
-
}
|
22
|
-
|
23
|
-
req = env[:request]
|
24
|
-
if req&.stream_response?
|
25
|
-
total = 0
|
26
|
-
req_opts[:response_block] = lambda do |chunk, _remain, _total|
|
27
|
-
req.on_data.call(chunk, total += chunk.size)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
resp = connection(env) { |http| http.request(req_opts) }
|
32
|
-
save_response(env, resp.status.to_i, resp.body, resp.headers,
|
33
|
-
resp.reason_phrase)
|
34
|
-
|
35
|
-
@app.call(env)
|
36
|
-
rescue ::Excon::Errors::SocketError => e
|
37
|
-
raise Faraday::TimeoutError, e if e.message.match?(/\btimeout\b/)
|
38
|
-
|
39
|
-
raise Faraday::SSLError, e if e.message.match?(/\bcertificate\b/)
|
40
|
-
|
41
|
-
raise Faraday::ConnectionFailed, e
|
42
|
-
rescue ::Excon::Errors::Timeout => e
|
43
|
-
raise Faraday::TimeoutError, e
|
44
|
-
end
|
45
|
-
|
46
|
-
# TODO: support streaming requests
|
47
|
-
def read_body(env)
|
48
|
-
env[:body].respond_to?(:read) ? env[:body].read : env[:body]
|
49
|
-
end
|
50
|
-
|
51
|
-
private
|
52
|
-
|
53
|
-
def opts_from_env(env)
|
54
|
-
opts = {}
|
55
|
-
amend_opts_with_ssl!(opts, env[:ssl]) if needs_ssl_settings?(env)
|
56
|
-
|
57
|
-
if (req = env[:request])
|
58
|
-
amend_opts_with_timeouts!(opts, req)
|
59
|
-
amend_opts_with_proxy_settings!(opts, req)
|
60
|
-
end
|
61
|
-
|
62
|
-
opts
|
63
|
-
end
|
64
|
-
|
65
|
-
def needs_ssl_settings?(env)
|
66
|
-
env[:url].scheme == 'https' && env[:ssl]
|
67
|
-
end
|
68
|
-
|
69
|
-
OPTS_KEYS = [
|
70
|
-
%i[client_cert client_cert],
|
71
|
-
%i[client_key client_key],
|
72
|
-
%i[certificate certificate],
|
73
|
-
%i[private_key private_key],
|
74
|
-
%i[ssl_ca_path ca_path],
|
75
|
-
%i[ssl_ca_file ca_file],
|
76
|
-
%i[ssl_version version],
|
77
|
-
%i[ssl_min_version min_version],
|
78
|
-
%i[ssl_max_version max_version]
|
79
|
-
].freeze
|
80
|
-
|
81
|
-
def amend_opts_with_ssl!(opts, ssl)
|
82
|
-
opts[:ssl_verify_peer] = !!ssl.fetch(:verify, true)
|
83
|
-
# https://github.com/geemus/excon/issues/106
|
84
|
-
# https://github.com/jruby/jruby-ossl/issues/19
|
85
|
-
opts[:nonblock] = false
|
86
|
-
|
87
|
-
OPTS_KEYS.each do |(key_in_opts, key_in_ssl)|
|
88
|
-
next unless ssl[key_in_ssl]
|
89
|
-
|
90
|
-
opts[key_in_opts] = ssl[key_in_ssl]
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
def amend_opts_with_timeouts!(opts, req)
|
95
|
-
if (sec = request_timeout(:read, req))
|
96
|
-
opts[:read_timeout] = sec
|
97
|
-
end
|
98
|
-
|
99
|
-
if (sec = request_timeout(:write, req))
|
100
|
-
opts[:write_timeout] = sec
|
101
|
-
end
|
102
|
-
|
103
|
-
return unless (sec = request_timeout(:open, req))
|
104
|
-
|
105
|
-
opts[:connect_timeout] = sec
|
106
|
-
end
|
107
|
-
|
108
|
-
def amend_opts_with_proxy_settings!(opts, req)
|
109
|
-
opts[:proxy] = proxy_settings_for_opts(req[:proxy]) if req[:proxy]
|
110
|
-
end
|
111
|
-
|
112
|
-
def proxy_settings_for_opts(proxy)
|
113
|
-
{
|
114
|
-
host: proxy[:uri].host,
|
115
|
-
hostname: proxy[:uri].hostname,
|
116
|
-
port: proxy[:uri].port,
|
117
|
-
scheme: proxy[:uri].scheme,
|
118
|
-
user: proxy[:user],
|
119
|
-
password: proxy[:password]
|
120
|
-
}
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
@@ -1,91 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Faraday
|
4
|
-
class Adapter
|
5
|
-
# Net::HTTP::Persistent adapter.
|
6
|
-
class NetHttpPersistent < NetHttp
|
7
|
-
dependency 'net/http/persistent'
|
8
|
-
|
9
|
-
private
|
10
|
-
|
11
|
-
def net_http_connection(env)
|
12
|
-
@cached_connection ||=
|
13
|
-
if Net::HTTP::Persistent.instance_method(:initialize)
|
14
|
-
.parameters.first == %i[key name]
|
15
|
-
options = { name: 'Faraday' }
|
16
|
-
if @connection_options.key?(:pool_size)
|
17
|
-
options[:pool_size] = @connection_options[:pool_size]
|
18
|
-
end
|
19
|
-
Net::HTTP::Persistent.new(**options)
|
20
|
-
else
|
21
|
-
Net::HTTP::Persistent.new('Faraday')
|
22
|
-
end
|
23
|
-
|
24
|
-
proxy_uri = proxy_uri(env)
|
25
|
-
if @cached_connection.proxy_uri != proxy_uri
|
26
|
-
@cached_connection.proxy = proxy_uri
|
27
|
-
end
|
28
|
-
@cached_connection
|
29
|
-
end
|
30
|
-
|
31
|
-
def proxy_uri(env)
|
32
|
-
proxy_uri = nil
|
33
|
-
if (proxy = env[:request][:proxy])
|
34
|
-
proxy_uri = if proxy[:uri].is_a?(::URI::HTTP)
|
35
|
-
proxy[:uri].dup
|
36
|
-
else
|
37
|
-
::URI.parse(proxy[:uri].to_s)
|
38
|
-
end
|
39
|
-
proxy_uri.user = proxy_uri.password = nil
|
40
|
-
# awful patch for net-http-persistent 2.8
|
41
|
-
# not unescaping user/password
|
42
|
-
if proxy[:user]
|
43
|
-
(class << proxy_uri; self; end).class_eval do
|
44
|
-
define_method(:user) { proxy[:user] }
|
45
|
-
define_method(:password) { proxy[:password] }
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
proxy_uri
|
50
|
-
end
|
51
|
-
|
52
|
-
def perform_request(http, env)
|
53
|
-
http.request env[:url], create_request(env)
|
54
|
-
rescue Errno::ETIMEDOUT, Net::OpenTimeout => e
|
55
|
-
raise Faraday::TimeoutError, e
|
56
|
-
rescue Net::HTTP::Persistent::Error => e
|
57
|
-
raise Faraday::TimeoutError, e if e.message.include? 'Timeout'
|
58
|
-
|
59
|
-
if e.message.include? 'connection refused'
|
60
|
-
raise Faraday::ConnectionFailed, e
|
61
|
-
end
|
62
|
-
|
63
|
-
raise
|
64
|
-
end
|
65
|
-
|
66
|
-
SSL_CONFIGURATIONS = {
|
67
|
-
certificate: :client_cert,
|
68
|
-
private_key: :client_key,
|
69
|
-
ca_file: :ca_file,
|
70
|
-
ssl_version: :version,
|
71
|
-
min_version: :min_version,
|
72
|
-
max_version: :max_version
|
73
|
-
}.freeze
|
74
|
-
|
75
|
-
def configure_ssl(http, ssl)
|
76
|
-
return unless ssl
|
77
|
-
|
78
|
-
http_set(http, :verify_mode, ssl_verify_mode(ssl))
|
79
|
-
http_set(http, :cert_store, ssl_cert_store(ssl))
|
80
|
-
|
81
|
-
SSL_CONFIGURATIONS
|
82
|
-
.select { |_, key| ssl[key] }
|
83
|
-
.each { |target, key| http_set(http, target, ssl[key]) }
|
84
|
-
end
|
85
|
-
|
86
|
-
def http_set(http, attr, value)
|
87
|
-
http.send("#{attr}=", value) if http.send(attr) != value
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
@@ -1,57 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
RSpec.describe Faraday::Adapter::NetHttpPersistent do
|
4
|
-
features :request_body_on_query_methods, :reason_phrase_parse, :compression, :trace_method
|
5
|
-
|
6
|
-
it_behaves_like 'an adapter'
|
7
|
-
|
8
|
-
it 'allows to provide adapter specific configs' do
|
9
|
-
url = URI('https://example.com')
|
10
|
-
|
11
|
-
adapter = described_class.new do |http|
|
12
|
-
http.idle_timeout = 123
|
13
|
-
end
|
14
|
-
|
15
|
-
http = adapter.send(:connection, url: url, request: {})
|
16
|
-
adapter.send(:configure_request, http, {})
|
17
|
-
|
18
|
-
expect(http.idle_timeout).to eq(123)
|
19
|
-
end
|
20
|
-
|
21
|
-
it 'sets max_retries to 0' do
|
22
|
-
url = URI('http://example.com')
|
23
|
-
|
24
|
-
adapter = described_class.new
|
25
|
-
|
26
|
-
http = adapter.send(:connection, url: url, request: {})
|
27
|
-
adapter.send(:configure_request, http, {})
|
28
|
-
|
29
|
-
# `max_retries=` is only present in Ruby 2.5
|
30
|
-
expect(http.max_retries).to eq(0) if http.respond_to?(:max_retries=)
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'allows to set pool_size on initialize' do
|
34
|
-
url = URI('https://example.com')
|
35
|
-
|
36
|
-
adapter = described_class.new(nil, pool_size: 5)
|
37
|
-
|
38
|
-
http = adapter.send(:connection, url: url, request: {})
|
39
|
-
|
40
|
-
# `pool` is only present in net_http_persistent >= 3.0
|
41
|
-
expect(http.pool.size).to eq(5) if http.respond_to?(:pool)
|
42
|
-
end
|
43
|
-
|
44
|
-
context 'min_version' do
|
45
|
-
it 'allows to set min_version in SSL settings' do
|
46
|
-
url = URI('https://example.com')
|
47
|
-
|
48
|
-
adapter = described_class.new(nil)
|
49
|
-
|
50
|
-
http = adapter.send(:connection, url: url, request: {})
|
51
|
-
adapter.send(:configure_ssl, http, min_version: :TLS1_2)
|
52
|
-
|
53
|
-
# `min_version` is only present in net_http_persistent >= 3.1 (UNRELEASED)
|
54
|
-
expect(http.min_version).to eq(:TLS1_2) if http.respond_to?(:min_version)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|