faraday 1.4.0 → 1.5.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: 9232bd1a6a03e460d5959725591c2aeae3094f3e29a48dadcf9531ee878d61b2
4
- data.tar.gz: 261fa4b48f2eb5633abc5352f30965693e8b0b283c7204645ad0ea562d82d3ad
3
+ metadata.gz: 05b41e618d412fbb6199856f571098ff152bf81b42839139a2f0527d8f54e6d4
4
+ data.tar.gz: 5bf7bfe979404c4b58c6030b2348181bfada78c7eca1e352e1eec271b2c490aa
5
5
  SHA512:
6
- metadata.gz: d707ade012eacb6eb017365b18778ad8553cec5f27a8571331ab5b3bc388605f0b8692de98c1ab36c60528dfbcd2cfe0e12b0bdec343240721dd08f16d4fd376
7
- data.tar.gz: 86fef1e9db15dcb666b9255d1f5aea529aa2c2a51fe0cdd7ca011f00870299c2200d6b200d801516269281f2b524248670b40bb0ca57d130358a2383e7e50f01
6
+ metadata.gz: af7ce1cc0c2a34c6733e2cb655ba2b8fe66729300ee40d9ba0a9161d56ba7e4318ffa4fa754f66d80714732bafe895ec2d2eac717ce62115ee3e3e1979830672
7
+ data.tar.gz: 3b92a28b2c1172da22f5892d2105e266d3873eb48d07a11090b2b52b5e5bb4a7bacfd8cd15e43b1094ea9df373014d9eb8a1a56226c808440c97489974b249b4
data/lib/faraday.rb CHANGED
@@ -27,9 +27,15 @@ require 'faraday/error'
27
27
  require 'faraday/file_part'
28
28
  require 'faraday/param_part'
29
29
 
30
+ unless defined?(JRUBY_VERSION)
31
+ require 'faraday/em_http'
32
+ require 'faraday/em_synchrony'
33
+ end
34
+ require 'faraday/excon'
35
+ require 'faraday/httpclient'
30
36
  require 'faraday/net_http'
31
37
  require 'faraday/net_http_persistent'
32
- require 'faraday/excon'
38
+ require 'faraday/patron'
33
39
 
34
40
  # This is the main namespace for Faraday.
35
41
  #
@@ -12,11 +12,7 @@ module Faraday
12
12
  register_middleware File.expand_path('adapter', __dir__),
13
13
  test: [:Test, 'test'],
14
14
  typhoeus: [:Typhoeus, 'typhoeus'],
15
- patron: [:Patron, 'patron'],
16
- em_synchrony: [:EMSynchrony, 'em_synchrony'],
17
- em_http: [:EMHttp, 'em_http'],
18
- rack: [:Rack, 'rack'],
19
- httpclient: [:HTTPClient, 'httpclient']
15
+ rack: [:Rack, 'rack']
20
16
 
21
17
  # This module marks an Adapter as supporting parallel requests.
22
18
  module Parallelism
@@ -58,13 +58,9 @@ module Faraday
58
58
  class Adapter
59
59
  extend AutoloadHelper
60
60
  autoload_all 'faraday/adapter',
61
- EMSynchrony: 'em_synchrony',
62
- EMHttp: 'em_http',
63
61
  Typhoeus: 'typhoeus',
64
- Patron: 'patron',
65
62
  Test: 'test',
66
- Rack: 'rack',
67
- HTTPClient: 'httpclient'
63
+ Rack: 'rack'
68
64
  end
69
65
 
70
66
  # Request represents a single HTTP request for a Faraday adapter to make.
@@ -26,7 +26,7 @@ module Faraday
26
26
  # Connection. This includes a default host name, scheme, port, and path.
27
27
  attr_reader :url_prefix
28
28
 
29
- # @return [Faraday::Builder] Builder for this Connection.
29
+ # @return [Faraday::RackBuilder] Builder for this Connection.
30
30
  attr_reader :builder
31
31
 
32
32
  # @return [Hash] SSL options.
@@ -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,9 +520,8 @@ 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
525
527
  url = url && URI.parse(url.to_s).opaque ? url.to_s.gsub(':', '%3A') : url
@@ -577,7 +579,11 @@ module Faraday
577
579
  case url
578
580
  when String
579
581
  uri = Utils.URI(url)
580
- uri = URI.parse("#{uri.scheme}://#{uri.host}").find_proxy
582
+ uri = if uri.host.nil?
583
+ find_default_proxy
584
+ else
585
+ URI.parse("#{uri.scheme}://#{uri.host}").find_proxy
586
+ end
581
587
  when URI
582
588
  uri = url.find_proxy
583
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
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Faraday
4
- VERSION = '1.4.0'
4
+ VERSION = '1.5.1'
5
5
  end
@@ -1,47 +1,49 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- RSpec.describe Faraday::Adapter::EMHttp, unless: defined?(JRUBY_VERSION) do
4
- features :request_body_on_query_methods, :reason_phrase_parse, :trace_method,
5
- :skip_response_body_on_head, :parallel, :local_socket_binding
3
+ unless defined?(JRUBY_VERSION)
4
+ RSpec.describe Faraday::Adapter::EMHttp do
5
+ features :request_body_on_query_methods, :reason_phrase_parse, :trace_method,
6
+ :skip_response_body_on_head, :parallel, :local_socket_binding
6
7
 
7
- it_behaves_like 'an adapter'
8
+ it_behaves_like 'an adapter'
8
9
 
9
- it 'allows to provide adapter specific configs' do
10
- url = URI('https://example.com:1234')
11
- adapter = described_class.new nil, inactivity_timeout: 20
12
- req = adapter.create_request(url: url, request: {})
10
+ it 'allows to provide adapter specific configs' do
11
+ url = URI('https://example.com:1234')
12
+ adapter = described_class.new nil, inactivity_timeout: 20
13
+ req = adapter.create_request(url: url, request: {})
13
14
 
14
- expect(req.connopts.inactivity_timeout).to eq(20)
15
- end
16
-
17
- context 'Options' do
18
- let(:request) { Faraday::RequestOptions.new }
19
- let(:env) { { request: request } }
20
- let(:options) { {} }
21
- let(:adapter) { Faraday::Adapter::EMHttp.new }
22
-
23
- it 'configures timeout' do
24
- request.timeout = 5
25
- adapter.configure_timeout(options, env)
26
- expect(options[:inactivity_timeout]).to eq(5)
27
- expect(options[:connect_timeout]).to eq(5)
28
- end
29
-
30
- it 'configures timeout and open_timeout' do
31
- request.timeout = 5
32
- request.open_timeout = 1
33
- adapter.configure_timeout(options, env)
34
- expect(options[:inactivity_timeout]).to eq(5)
35
- expect(options[:connect_timeout]).to eq(1)
15
+ expect(req.connopts.inactivity_timeout).to eq(20)
36
16
  end
37
17
 
38
- it 'configures all timeout settings' do
39
- request.timeout = 5
40
- request.read_timeout = 3
41
- request.open_timeout = 1
42
- adapter.configure_timeout(options, env)
43
- expect(options[:inactivity_timeout]).to eq(3)
44
- expect(options[:connect_timeout]).to eq(1)
18
+ context 'Options' do
19
+ let(:request) { Faraday::RequestOptions.new }
20
+ let(:env) { { request: request } }
21
+ let(:options) { {} }
22
+ let(:adapter) { Faraday::Adapter::EMHttp.new }
23
+
24
+ it 'configures timeout' do
25
+ request.timeout = 5
26
+ adapter.configure_timeout(options, env)
27
+ expect(options[:inactivity_timeout]).to eq(5)
28
+ expect(options[:connect_timeout]).to eq(5)
29
+ end
30
+
31
+ it 'configures timeout and open_timeout' do
32
+ request.timeout = 5
33
+ request.open_timeout = 1
34
+ adapter.configure_timeout(options, env)
35
+ expect(options[:inactivity_timeout]).to eq(5)
36
+ expect(options[:connect_timeout]).to eq(1)
37
+ end
38
+
39
+ it 'configures all timeout settings' do
40
+ request.timeout = 5
41
+ request.read_timeout = 3
42
+ request.open_timeout = 1
43
+ adapter.configure_timeout(options, env)
44
+ expect(options[:inactivity_timeout]).to eq(3)
45
+ expect(options[:connect_timeout]).to eq(1)
46
+ end
45
47
  end
46
48
  end
47
49
  end
@@ -1,16 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- RSpec.describe Faraday::Adapter::EMSynchrony, unless: defined?(JRUBY_VERSION) do
4
- features :request_body_on_query_methods, :reason_phrase_parse,
5
- :skip_response_body_on_head, :parallel, :local_socket_binding
3
+ unless defined?(JRUBY_VERSION)
4
+ RSpec.describe Faraday::Adapter::EMSynchrony do
5
+ features :request_body_on_query_methods, :reason_phrase_parse,
6
+ :skip_response_body_on_head, :parallel, :local_socket_binding
6
7
 
7
- it_behaves_like 'an adapter'
8
+ it_behaves_like 'an adapter'
8
9
 
9
- it 'allows to provide adapter specific configs' do
10
- url = URI('https://example.com:1234')
11
- adapter = described_class.new nil, inactivity_timeout: 20
12
- req = adapter.create_request(url: url, request: {})
10
+ it 'allows to provide adapter specific configs' do
11
+ url = URI('https://example.com:1234')
12
+ adapter = described_class.new nil, inactivity_timeout: 20
13
+ req = adapter.create_request(url: url, request: {})
13
14
 
14
- expect(req.connopts.inactivity_timeout).to eq(20)
15
+ expect(req.connopts.inactivity_timeout).to eq(20)
16
+ end
15
17
  end
16
18
  end
@@ -253,6 +253,13 @@ RSpec.describe Faraday::Connection do
253
253
  expect(uri.path).to eq('/sake.html')
254
254
  end
255
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
+
256
263
  context 'with url_prefixed connection' do
257
264
  let(:url) { 'http://sushi.com/sushi/' }
258
265
 
@@ -442,6 +449,14 @@ RSpec.describe Faraday::Connection do
442
449
  end
443
450
  end
444
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
+
445
460
  it 'allows when prefixed url is not in no proxy list' do
446
461
  with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'example.com' do
447
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.4.0
4
+ version: 1.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - "@technoweenie"
@@ -10,10 +10,24 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2021-04-16 00:00:00.000000000 Z
13
+ date: 2021-07-11 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
- name: faraday-excon
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
17
31
  requirement: !ruby/object:Gem::Requirement
18
32
  requirements:
19
33
  - - "~>"
@@ -26,6 +40,34 @@ dependencies:
26
40
  - - "~>"
27
41
  - !ruby/object:Gem::Version
28
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'
57
+ - !ruby/object:Gem::Dependency
58
+ name: faraday-httpclient
59
+ requirement: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - "~>"
62
+ - !ruby/object:Gem::Version
63
+ version: 1.0.1
64
+ type: :runtime
65
+ prerelease: false
66
+ version_requirements: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - "~>"
69
+ - !ruby/object:Gem::Version
70
+ version: 1.0.1
29
71
  - !ruby/object:Gem::Dependency
30
72
  name: faraday-net_http
31
73
  requirement: !ruby/object:Gem::Requirement
@@ -42,6 +84,20 @@ dependencies:
42
84
  version: '1.0'
43
85
  - !ruby/object:Gem::Dependency
44
86
  name: faraday-net_http_persistent
87
+ requirement: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - "~>"
90
+ - !ruby/object:Gem::Version
91
+ version: '1.1'
92
+ type: :runtime
93
+ prerelease: false
94
+ version_requirements: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - "~>"
97
+ - !ruby/object:Gem::Version
98
+ version: '1.1'
99
+ - !ruby/object:Gem::Dependency
100
+ name: faraday-patron
45
101
  requirement: !ruby/object:Gem::Requirement
46
102
  requirements:
47
103
  - - "~>"
@@ -102,12 +158,6 @@ files:
102
158
  - examples/client_test.rb
103
159
  - lib/faraday.rb
104
160
  - lib/faraday/adapter.rb
105
- - lib/faraday/adapter/em_http.rb
106
- - lib/faraday/adapter/em_http_ssl_patch.rb
107
- - lib/faraday/adapter/em_synchrony.rb
108
- - lib/faraday/adapter/em_synchrony/parallel_manager.rb
109
- - lib/faraday/adapter/httpclient.rb
110
- - lib/faraday/adapter/patron.rb
111
161
  - lib/faraday/adapter/rack.rb
112
162
  - lib/faraday/adapter/test.rb
113
163
  - lib/faraday/adapter/typhoeus.rb
@@ -197,7 +247,7 @@ licenses:
197
247
  - MIT
198
248
  metadata:
199
249
  homepage_uri: https://lostisland.github.io/faraday
200
- changelog_uri: https://github.com/lostisland/faraday/releases/tag/v1.4.0
250
+ changelog_uri: https://github.com/lostisland/faraday/releases/tag/v1.5.1
201
251
  source_code_uri: https://github.com/lostisland/faraday
202
252
  bug_tracker_uri: https://github.com/lostisland/faraday/issues
203
253
  post_install_message:
@@ -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,152 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Faraday
4
- class Adapter
5
- # HTTPClient adapter.
6
- class HTTPClient < Faraday::Adapter
7
- dependency 'httpclient'
8
-
9
- def build_connection(env)
10
- @client ||= ::HTTPClient.new.tap do |cli|
11
- # enable compression
12
- cli.transparent_gzip_decompression = true
13
- end
14
-
15
- if (req = env[:request])
16
- if (proxy = req[:proxy])
17
- configure_proxy @client, proxy
18
- end
19
-
20
- if (bind = req[:bind])
21
- configure_socket @client, bind
22
- end
23
-
24
- configure_timeouts @client, req
25
- end
26
-
27
- if env[:url].scheme == 'https' && (ssl = env[:ssl])
28
- configure_ssl @client, ssl
29
- end
30
-
31
- configure_client @client
32
-
33
- @client
34
- end
35
-
36
- def call(env)
37
- super
38
-
39
- # TODO: Don't stream yet.
40
- # https://github.com/nahi/httpclient/pull/90
41
- env[:body] = env[:body].read if env[:body].respond_to? :read
42
-
43
- connection(env) do |http|
44
- resp = http.request env[:method], env[:url],
45
- body: env[:body],
46
- header: env[:request_headers]
47
-
48
- if (req = env[:request]).stream_response?
49
- warn "Streaming downloads for #{self.class.name} " \
50
- 'are not yet implemented.'
51
- req.on_data.call(resp.body, resp.body.bytesize)
52
- end
53
- save_response env, resp.status, resp.body, resp.headers, resp.reason
54
-
55
- @app.call env
56
- end
57
- rescue ::HTTPClient::TimeoutError, Errno::ETIMEDOUT
58
- raise Faraday::TimeoutError, $ERROR_INFO
59
- rescue ::HTTPClient::BadResponseError => e
60
- if e.message.include?('status 407')
61
- raise Faraday::ConnectionFailed,
62
- %(407 "Proxy Authentication Required ")
63
- end
64
-
65
- raise Faraday::ClientError, $ERROR_INFO
66
- rescue Errno::EADDRNOTAVAIL, Errno::ECONNREFUSED, IOError, SocketError
67
- raise Faraday::ConnectionFailed, $ERROR_INFO
68
- rescue StandardError => e
69
- if defined?(::OpenSSL::SSL::SSLError) && \
70
- e.is_a?(::OpenSSL::SSL::SSLError)
71
- raise Faraday::SSLError, e
72
- end
73
-
74
- raise
75
- end
76
-
77
- # @param bind [Hash]
78
- def configure_socket(client, bind)
79
- client.socket_local.host = bind[:host]
80
- client.socket_local.port = bind[:port]
81
- end
82
-
83
- # Configure proxy URI and any user credentials.
84
- #
85
- # @param proxy [Hash]
86
- def configure_proxy(client, proxy)
87
- client.proxy = proxy[:uri]
88
- return unless proxy[:user] && proxy[:password]
89
-
90
- client.set_proxy_auth(proxy[:user], proxy[:password])
91
- end
92
-
93
- # @param ssl [Hash]
94
- def configure_ssl(client, ssl)
95
- ssl_config = client.ssl_config
96
- ssl_config.verify_mode = ssl_verify_mode(ssl)
97
- ssl_config.cert_store = ssl_cert_store(ssl)
98
-
99
- ssl_config.add_trust_ca ssl[:ca_file] if ssl[:ca_file]
100
- ssl_config.add_trust_ca ssl[:ca_path] if ssl[:ca_path]
101
- ssl_config.client_cert = ssl[:client_cert] if ssl[:client_cert]
102
- ssl_config.client_key = ssl[:client_key] if ssl[:client_key]
103
- ssl_config.verify_depth = ssl[:verify_depth] if ssl[:verify_depth]
104
- end
105
-
106
- # @param req [Hash]
107
- def configure_timeouts(client, req)
108
- if (sec = request_timeout(:open, req))
109
- client.connect_timeout = sec
110
- end
111
-
112
- if (sec = request_timeout(:write, req))
113
- client.send_timeout = sec
114
- end
115
-
116
- return unless (sec = request_timeout(:read, req))
117
-
118
- client.receive_timeout = sec
119
- end
120
-
121
- def configure_client(client)
122
- @config_block&.call(client)
123
- end
124
-
125
- # @param ssl [Hash]
126
- # @return [OpenSSL::X509::Store]
127
- def ssl_cert_store(ssl)
128
- return ssl[:cert_store] if ssl[:cert_store]
129
-
130
- # Memoize the cert store so that the same one is passed to
131
- # HTTPClient each time, to avoid resyncing SSL sessions when
132
- # it's changed
133
- @ssl_cert_store ||= begin
134
- # Use the default cert store by default, i.e. system ca certs
135
- OpenSSL::X509::Store.new.tap(&:set_default_paths)
136
- end
137
- end
138
-
139
- # @param ssl [Hash]
140
- def ssl_verify_mode(ssl)
141
- ssl[:verify_mode] || begin
142
- if ssl.fetch(:verify, true)
143
- OpenSSL::SSL::VERIFY_PEER |
144
- OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
145
- else
146
- OpenSSL::SSL::VERIFY_NONE
147
- end
148
- end
149
- end
150
- end
151
- end
152
- end
@@ -1,132 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Faraday
4
- class Adapter
5
- # Patron adapter.
6
- class Patron < Faraday::Adapter
7
- dependency 'patron'
8
-
9
- def build_connection(env)
10
- session = ::Patron::Session.new
11
- @config_block&.call(session)
12
- if (env[:url].scheme == 'https') && env[:ssl]
13
- configure_ssl(session, env[:ssl])
14
- end
15
-
16
- if (req = env[:request])
17
- configure_timeouts(session, req)
18
- configure_proxy(session, req[:proxy])
19
- end
20
-
21
- session
22
- end
23
-
24
- def call(env)
25
- super
26
- # TODO: support streaming requests
27
- env[:body] = env[:body].read if env[:body].respond_to? :read
28
-
29
- response = connection(env) do |session|
30
- begin
31
- data = env[:body] ? env[:body].to_s : nil
32
- session.request(env[:method], env[:url].to_s,
33
- env[:request_headers], data: data)
34
- rescue Errno::ECONNREFUSED, ::Patron::ConnectionFailed
35
- raise Faraday::ConnectionFailed, $ERROR_INFO
36
- end
37
- end
38
-
39
- if (req = env[:request]).stream_response?
40
- warn "Streaming downloads for #{self.class.name} " \
41
- 'are not yet implemented.'
42
- req.on_data.call(response.body, response.body.bytesize)
43
- end
44
- # Remove the "HTTP/1.1 200", leaving just the reason phrase
45
- reason_phrase = response.status_line.gsub(/^.* \d{3} /, '')
46
-
47
- save_response(env, response.status, response.body,
48
- response.headers, reason_phrase)
49
-
50
- @app.call env
51
- rescue ::Patron::TimeoutError => e
52
- if connection_timed_out_message?(e.message)
53
- raise Faraday::ConnectionFailed, e
54
- end
55
-
56
- raise Faraday::TimeoutError, e
57
- rescue ::Patron::Error => e
58
- if e.message.include?('code 407')
59
- raise Faraday::ConnectionFailed,
60
- %(407 "Proxy Authentication Required ")
61
- end
62
-
63
- raise Faraday::ConnectionFailed, e
64
- end
65
-
66
- if loaded? && defined?(::Patron::Request::VALID_ACTIONS)
67
- # HAX: helps but doesn't work completely
68
- # https://github.com/toland/patron/issues/34
69
- ::Patron::Request::VALID_ACTIONS.tap do |actions|
70
- if actions[0].is_a?(Symbol)
71
- actions << :patch unless actions.include? :patch
72
- actions << :options unless actions.include? :options
73
- else
74
- # Patron 0.4.20 and up
75
- actions << 'PATCH' unless actions.include? 'PATCH'
76
- actions << 'OPTIONS' unless actions.include? 'OPTIONS'
77
- end
78
- end
79
- end
80
-
81
- def configure_ssl(session, ssl)
82
- if ssl.fetch(:verify, true)
83
- session.cacert = ssl[:ca_file]
84
- else
85
- session.insecure = true
86
- end
87
- end
88
-
89
- def configure_timeouts(session, req)
90
- return unless req
91
-
92
- if (sec = request_timeout(:read, req))
93
- session.timeout = sec
94
- end
95
-
96
- return unless (sec = request_timeout(:open, req))
97
-
98
- session.connect_timeout = sec
99
- end
100
-
101
- def configure_proxy(session, proxy)
102
- return unless proxy
103
-
104
- proxy_uri = proxy[:uri].dup
105
- proxy_uri.user = proxy[:user] &&
106
- Utils.escape(proxy[:user]).gsub('+', '%20')
107
- proxy_uri.password = proxy[:password] &&
108
- Utils.escape(proxy[:password]).gsub('+', '%20')
109
- session.proxy = proxy_uri.to_s
110
- end
111
-
112
- private
113
-
114
- CURL_TIMEOUT_MESSAGES = [
115
- 'Connection time-out',
116
- 'Connection timed out',
117
- 'Timed out before name resolve',
118
- 'server connect has timed out',
119
- 'Resolving timed out',
120
- 'name lookup timed out',
121
- 'timed out before SSL',
122
- 'connect() timed out'
123
- ].freeze
124
-
125
- def connection_timed_out_message?(message)
126
- CURL_TIMEOUT_MESSAGES.any? do |curl_message|
127
- message.include?(curl_message)
128
- end
129
- end
130
- end
131
- end
132
- end