faraday 0.9.2 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +276 -0
  3. data/LICENSE.md +1 -1
  4. data/README.md +27 -217
  5. data/Rakefile +7 -0
  6. data/UPGRADING.md +55 -0
  7. data/examples/client_spec.rb +65 -0
  8. data/examples/client_test.rb +79 -0
  9. data/lib/faraday/adapter/em_http.rb +149 -101
  10. data/lib/faraday/adapter/em_http_ssl_patch.rb +25 -19
  11. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +18 -15
  12. data/lib/faraday/adapter/em_synchrony.rb +106 -56
  13. data/lib/faraday/adapter/excon.rb +98 -55
  14. data/lib/faraday/adapter/httpclient.rb +89 -55
  15. data/lib/faraday/adapter/net_http.rb +132 -53
  16. data/lib/faraday/adapter/net_http_persistent.rb +70 -28
  17. data/lib/faraday/adapter/patron.rb +92 -38
  18. data/lib/faraday/adapter/rack.rb +30 -13
  19. data/lib/faraday/adapter/test.rb +136 -52
  20. data/lib/faraday/adapter/typhoeus.rb +7 -115
  21. data/lib/faraday/adapter.rb +89 -20
  22. data/lib/faraday/adapter_registry.rb +28 -0
  23. data/lib/faraday/autoload.rb +47 -36
  24. data/lib/faraday/connection.rb +345 -168
  25. data/lib/faraday/dependency_loader.rb +37 -0
  26. data/lib/faraday/encoders/flat_params_encoder.rb +98 -0
  27. data/lib/faraday/encoders/nested_params_encoder.rb +171 -0
  28. data/lib/faraday/error.rb +108 -29
  29. data/lib/faraday/file_part.rb +128 -0
  30. data/lib/faraday/logging/formatter.rb +105 -0
  31. data/lib/faraday/middleware.rb +12 -28
  32. data/lib/faraday/middleware_registry.rb +129 -0
  33. data/lib/faraday/options/connection_options.rb +22 -0
  34. data/lib/faraday/options/env.rb +181 -0
  35. data/lib/faraday/options/proxy_options.rb +28 -0
  36. data/lib/faraday/options/request_options.rb +22 -0
  37. data/lib/faraday/options/ssl_options.rb +59 -0
  38. data/lib/faraday/options.rb +57 -194
  39. data/lib/faraday/param_part.rb +53 -0
  40. data/lib/faraday/parameters.rb +4 -196
  41. data/lib/faraday/rack_builder.rb +74 -39
  42. data/lib/faraday/request/authorization.rb +42 -31
  43. data/lib/faraday/request/basic_authentication.rb +14 -7
  44. data/lib/faraday/request/instrumentation.rb +45 -27
  45. data/lib/faraday/request/multipart.rb +81 -45
  46. data/lib/faraday/request/retry.rb +211 -126
  47. data/lib/faraday/request/token_authentication.rb +15 -10
  48. data/lib/faraday/request/url_encoded.rb +41 -23
  49. data/lib/faraday/request.rb +84 -30
  50. data/lib/faraday/response/logger.rb +22 -48
  51. data/lib/faraday/response/raise_error.rb +38 -14
  52. data/lib/faraday/response.rb +27 -16
  53. data/lib/faraday/utils/headers.rb +139 -0
  54. data/lib/faraday/utils/params_hash.rb +61 -0
  55. data/lib/faraday/utils.rb +28 -228
  56. data/lib/faraday.rb +102 -204
  57. data/spec/external_adapters/faraday_specs_setup.rb +14 -0
  58. data/spec/faraday/adapter/em_http_spec.rb +47 -0
  59. data/spec/faraday/adapter/em_synchrony_spec.rb +16 -0
  60. data/spec/faraday/adapter/excon_spec.rb +49 -0
  61. data/spec/faraday/adapter/httpclient_spec.rb +73 -0
  62. data/spec/faraday/adapter/net_http_persistent_spec.rb +57 -0
  63. data/spec/faraday/adapter/net_http_spec.rb +64 -0
  64. data/spec/faraday/adapter/patron_spec.rb +18 -0
  65. data/spec/faraday/adapter/rack_spec.rb +8 -0
  66. data/spec/faraday/adapter/typhoeus_spec.rb +7 -0
  67. data/spec/faraday/adapter_registry_spec.rb +28 -0
  68. data/spec/faraday/adapter_spec.rb +55 -0
  69. data/spec/faraday/composite_read_io_spec.rb +80 -0
  70. data/spec/faraday/connection_spec.rb +691 -0
  71. data/spec/faraday/error_spec.rb +45 -0
  72. data/spec/faraday/middleware_spec.rb +26 -0
  73. data/spec/faraday/options/env_spec.rb +70 -0
  74. data/spec/faraday/options/options_spec.rb +297 -0
  75. data/spec/faraday/options/proxy_options_spec.rb +37 -0
  76. data/spec/faraday/options/request_options_spec.rb +19 -0
  77. data/spec/faraday/params_encoders/flat_spec.rb +34 -0
  78. data/spec/faraday/params_encoders/nested_spec.rb +134 -0
  79. data/spec/faraday/rack_builder_spec.rb +196 -0
  80. data/spec/faraday/request/authorization_spec.rb +88 -0
  81. data/spec/faraday/request/instrumentation_spec.rb +76 -0
  82. data/spec/faraday/request/multipart_spec.rb +274 -0
  83. data/spec/faraday/request/retry_spec.rb +242 -0
  84. data/spec/faraday/request/url_encoded_spec.rb +70 -0
  85. data/spec/faraday/request_spec.rb +109 -0
  86. data/spec/faraday/response/logger_spec.rb +220 -0
  87. data/spec/faraday/response/middleware_spec.rb +52 -0
  88. data/spec/faraday/response/raise_error_spec.rb +106 -0
  89. data/spec/faraday/response_spec.rb +75 -0
  90. data/spec/faraday/utils/headers_spec.rb +82 -0
  91. data/spec/faraday/utils_spec.rb +56 -0
  92. data/spec/faraday_spec.rb +37 -0
  93. data/spec/spec_helper.rb +132 -0
  94. data/spec/support/disabling_stub.rb +14 -0
  95. data/spec/support/fake_safe_buffer.rb +15 -0
  96. data/spec/support/helper_methods.rb +133 -0
  97. data/spec/support/shared_examples/adapter.rb +104 -0
  98. data/spec/support/shared_examples/params_encoder.rb +18 -0
  99. data/spec/support/shared_examples/request_method.rb +234 -0
  100. data/spec/support/streaming_response_checker.rb +35 -0
  101. data/spec/support/webmock_rack_app.rb +68 -0
  102. metadata +110 -64
  103. data/lib/faraday/upload_io.rb +0 -67
@@ -1,7 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'uri'
2
4
 
3
5
  module Faraday
4
6
  class Adapter
7
+ # EventMachine Synchrony adapter.
5
8
  class EMSynchrony < Faraday::Adapter
6
9
  include EMHttp::Options
7
10
 
@@ -13,77 +16,121 @@ module Faraday
13
16
 
14
17
  self.supports_parallel = true
15
18
 
16
- def self.setup_parallel_manager(options = {})
19
+ # @return [ParallelManager]
20
+ def self.setup_parallel_manager(_options = nil)
17
21
  ParallelManager.new
18
22
  end
19
23
 
20
24
  def call(env)
21
25
  super
22
- request = EventMachine::HttpRequest.new(Utils::URI(env[:url].to_s), connection_config(env))
26
+ request = create_request(env)
23
27
 
24
28
  http_method = env[:method].to_s.downcase.to_sym
25
29
 
26
- # Queue requests for parallel execution.
27
30
  if env[:parallel_manager]
28
- env[:parallel_manager].add(request, http_method, request_config(env)) do |resp|
29
- save_response(env, resp.response_header.status, resp.response) do |resp_headers|
30
- resp.response_header.each do |name, value|
31
- resp_headers[name.to_sym] = value
32
- end
33
- end
31
+ # Queue requests for parallel execution.
32
+ execute_parallel_request(env, request, http_method)
33
+ else
34
+ # Execute single request.
35
+ execute_single_request(env, request, http_method)
36
+ end
34
37
 
35
- # Finalize the response object with values from `env`.
36
- env[:response].finish(env)
37
- end
38
+ @app.call env
39
+ rescue Errno::ECONNREFUSED
40
+ raise Faraday::ConnectionFailed, $ERROR_INFO
41
+ rescue EventMachine::Connectify::CONNECTError => e
42
+ if e.message.include?('Proxy Authentication Required')
43
+ raise Faraday::ConnectionFailed,
44
+ %(407 "Proxy Authentication Required")
45
+ end
38
46
 
39
- # Execute single request.
40
- else
41
- client = nil
42
- block = lambda { request.send(http_method, request_config(env)) }
43
-
44
- if !EM.reactor_running?
45
- EM.run do
46
- Fiber.new {
47
- client = block.call
48
- EM.stop
49
- }.resume
50
- end
51
- else
52
- client = block.call
53
- end
47
+ raise Faraday::ConnectionFailed, e
48
+ rescue Errno::ETIMEDOUT => e
49
+ raise Faraday::TimeoutError, e
50
+ rescue RuntimeError => e
51
+ if e.message == 'connection closed by server'
52
+ raise Faraday::ConnectionFailed, e
53
+ end
54
+
55
+ raise Faraday::TimeoutError, e if e.message.include?('timeout error')
56
+
57
+ raise
58
+ rescue StandardError => e
59
+ if defined?(OpenSSL) && e.is_a?(OpenSSL::SSL::SSLError)
60
+ raise Faraday::SSLError, e
61
+ end
62
+
63
+ raise
64
+ end
65
+
66
+ def create_request(env)
67
+ EventMachine::HttpRequest.new(
68
+ Utils::URI(env[:url].to_s),
69
+ connection_config(env).merge(@connection_options)
70
+ )
71
+ end
54
72
 
55
- raise client.error if client.error
73
+ private
56
74
 
57
- save_response(env, client.response_header.status, client.response) do |resp_headers|
58
- client.response_header.each do |name, value|
75
+ def execute_parallel_request(env, request, http_method)
76
+ env[:parallel_manager].add(request, http_method,
77
+ request_config(env)) do |resp|
78
+ if (req = env[:request]).stream_response?
79
+ warn "Streaming downloads for #{self.class.name} " \
80
+ 'are not yet implemented.'
81
+ req.on_data.call(resp.response, resp.response.bytesize)
82
+ end
83
+
84
+ save_response(env, resp.response_header.status,
85
+ resp.response) do |resp_headers|
86
+ resp.response_header.each do |name, value|
59
87
  resp_headers[name.to_sym] = value
60
88
  end
61
89
  end
90
+
91
+ # Finalize the response object with values from `env`.
92
+ env[:response].finish(env)
62
93
  end
94
+ end
63
95
 
64
- @app.call env
65
- rescue Errno::ECONNREFUSED
66
- raise Error::ConnectionFailed, $!
67
- rescue EventMachine::Connectify::CONNECTError => err
68
- if err.message.include?("Proxy Authentication Required")
69
- raise Error::ConnectionFailed, %{407 "Proxy Authentication Required "}
70
- else
71
- raise Error::ConnectionFailed, err
96
+ def execute_single_request(env, request, http_method)
97
+ block = -> { request.send(http_method, request_config(env)) }
98
+ client = call_block(block)
99
+
100
+ raise client.error if client&.error
101
+
102
+ if env[:request].stream_response?
103
+ warn "Streaming downloads for #{self.class.name} " \
104
+ 'are not yet implemented.'
105
+ env[:request].on_data.call(
106
+ client.response,
107
+ client.response.bytesize
108
+ )
72
109
  end
73
- rescue Errno::ETIMEDOUT => err
74
- raise Error::TimeoutError, err
75
- rescue RuntimeError => err
76
- if err.message == "connection closed by server"
77
- raise Error::ConnectionFailed, err
78
- else
79
- raise
110
+ status = client.response_header.status
111
+ reason = client.response_header.http_reason
112
+ save_response(env, status, client.response, nil, reason) do |headers|
113
+ client.response_header.each do |name, value|
114
+ headers[name.to_sym] = value
115
+ end
80
116
  end
81
- rescue => err
82
- if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err
83
- raise Faraday::SSLError, err
117
+ end
118
+
119
+ def call_block(block)
120
+ client = nil
121
+
122
+ if EM.reactor_running?
123
+ client = block.call
84
124
  else
85
- raise
125
+ EM.run do
126
+ Fiber.new do
127
+ client = block.call
128
+ EM.stop
129
+ end.resume
130
+ end
86
131
  end
132
+
133
+ client
87
134
  end
88
135
  end
89
136
  end
@@ -91,10 +138,13 @@ end
91
138
 
92
139
  require 'faraday/adapter/em_synchrony/parallel_manager'
93
140
 
94
- begin
95
- require 'openssl'
96
- rescue LoadError
97
- warn "Warning: no such file to load -- openssl. Make sure it is installed if you want HTTPS support"
98
- else
99
- require 'faraday/adapter/em_http_ssl_patch'
100
- end if Faraday::Adapter::EMSynchrony.loaded?
141
+ if Faraday::Adapter::EMSynchrony.loaded?
142
+ begin
143
+ require 'openssl'
144
+ rescue LoadError
145
+ warn 'Warning: no such file to load -- openssl. ' \
146
+ 'Make sure it is installed if you want HTTPS support'
147
+ else
148
+ require 'faraday/adapter/em_http_ssl_patch'
149
+ end
150
+ end
@@ -1,81 +1,124 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Faraday
2
4
  class Adapter
5
+ # Excon adapter.
3
6
  class Excon < Faraday::Adapter
4
7
  dependency 'excon'
5
8
 
6
- def initialize(app, connection_options = {})
7
- @connection_options = connection_options
8
- super(app)
9
+ def build_connection(env)
10
+ opts = opts_from_env(env)
11
+ ::Excon.new(env[:url].to_s, opts.merge(@connection_options))
9
12
  end
10
13
 
11
14
  def call(env)
12
15
  super
13
16
 
14
- opts = {}
15
- if env[:url].scheme == 'https' && ssl = env[:ssl]
16
- opts[:ssl_verify_peer] = !!ssl.fetch(:verify, true)
17
- opts[:ssl_ca_path] = ssl[:ca_path] if ssl[:ca_path]
18
- opts[:ssl_ca_file] = ssl[:ca_file] if ssl[:ca_file]
19
- opts[:client_cert] = ssl[:client_cert] if ssl[:client_cert]
20
- opts[:client_key] = ssl[:client_key] if ssl[:client_key]
21
- opts[:certificate] = ssl[:certificate] if ssl[:certificate]
22
- opts[:private_key] = ssl[:private_key] if ssl[:private_key]
23
-
24
- # https://github.com/geemus/excon/issues/106
25
- # https://github.com/jruby/jruby-ossl/issues/19
26
- opts[:nonblock] = false
27
- end
28
-
29
- if ( req = env[:request] )
30
- if req[:timeout]
31
- opts[:read_timeout] = req[:timeout]
32
- opts[:connect_timeout] = req[:timeout]
33
- opts[:write_timeout] = req[:timeout]
34
- end
17
+ req_opts = {
18
+ method: env[:method].to_s.upcase,
19
+ headers: env[:request_headers],
20
+ body: read_body(env)
21
+ }
35
22
 
36
- if req[:open_timeout]
37
- opts[:connect_timeout] = req[:open_timeout]
38
- opts[:write_timeout] = req[:open_timeout]
39
- end
40
-
41
- if req[:proxy]
42
- opts[:proxy] = {
43
- :host => req[:proxy][:uri].host,
44
- :hostname => req[:proxy][:uri].hostname,
45
- :port => req[:proxy][:uri].port,
46
- :scheme => req[:proxy][:uri].scheme,
47
- :user => req[:proxy][:user],
48
- :password => req[:proxy][:password]
49
- }
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)
50
28
  end
51
29
  end
52
30
 
53
- conn = ::Excon.new(env[:url].to_s, opts.merge(@connection_options))
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)
54
34
 
55
- resp = conn.request \
56
- :method => env[:method].to_s.upcase,
57
- :headers => env[:request_headers],
58
- :body => read_body(env)
35
+ @app.call(env)
36
+ rescue ::Excon::Errors::SocketError => e
37
+ raise Faraday::TimeoutError, e if e.message =~ /\btimeout\b/
59
38
 
60
- save_response(env, resp.status.to_i, resp.body, resp.headers)
39
+ raise Faraday::SSLError, e if e.message =~ /\bcertificate\b/
61
40
 
62
- @app.call env
63
- rescue ::Excon::Errors::SocketError => err
64
- if err.message =~ /\btimeout\b/
65
- raise Error::TimeoutError, err
66
- elsif err.message =~ /\bcertificate\b/
67
- raise Faraday::SSLError, err
68
- else
69
- raise Error::ConnectionFailed, err
70
- end
71
- rescue ::Excon::Errors::Timeout => err
72
- raise Error::TimeoutError, err
41
+ raise Faraday::ConnectionFailed, e
42
+ rescue ::Excon::Errors::Timeout => e
43
+ raise Faraday::TimeoutError, e
73
44
  end
74
45
 
75
46
  # TODO: support streaming requests
76
47
  def read_body(env)
77
48
  env[:body].respond_to?(:read) ? env[:body].read : env[:body]
78
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
79
122
  end
80
123
  end
81
124
  end
@@ -1,76 +1,96 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Faraday
2
4
  class Adapter
5
+ # HTTPClient adapter.
3
6
  class HTTPClient < Faraday::Adapter
4
7
  dependency 'httpclient'
5
8
 
6
- def client
7
- @client ||= ::HTTPClient.new
8
- end
9
-
10
- def call(env)
11
- super
12
-
13
- # enable compression
14
- client.transparent_gzip_decompression = true
9
+ def build_connection(env)
10
+ @client ||= ::HTTPClient.new.tap do |cli|
11
+ # enable compression
12
+ cli.transparent_gzip_decompression = true
13
+ end
15
14
 
16
- if req = env[:request]
17
- if proxy = req[:proxy]
18
- configure_proxy proxy
15
+ if (req = env[:request])
16
+ if (proxy = req[:proxy])
17
+ configure_proxy @client, proxy
19
18
  end
20
19
 
21
- if bind = req[:bind]
22
- configure_socket bind
20
+ if (bind = req[:bind])
21
+ configure_socket @client, bind
23
22
  end
24
23
 
25
- configure_timeouts req
24
+ configure_timeouts @client, req
26
25
  end
27
26
 
28
- if env[:url].scheme == 'https' && ssl = env[:ssl]
29
- configure_ssl ssl
27
+ if env[:url].scheme == 'https' && (ssl = env[:ssl])
28
+ configure_ssl @client, ssl
30
29
  end
31
30
 
32
- # TODO Don't stream yet.
31
+ configure_client @client
32
+
33
+ @client
34
+ end
35
+
36
+ def call(env)
37
+ super
38
+
39
+ # TODO: Don't stream yet.
33
40
  # https://github.com/nahi/httpclient/pull/90
34
41
  env[:body] = env[:body].read if env[:body].respond_to? :read
35
42
 
36
- resp = client.request env[:method], env[:url],
37
- :body => env[:body],
38
- :header => env[:request_headers]
43
+ connection(env) do |http|
44
+ resp = http.request env[:method], env[:url],
45
+ body: env[:body],
46
+ header: env[:request_headers]
39
47
 
40
- save_response env, resp.status, resp.body, resp.headers
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
41
54
 
42
- @app.call env
55
+ @app.call env
56
+ end
43
57
  rescue ::HTTPClient::TimeoutError, Errno::ETIMEDOUT
44
- raise Faraday::Error::TimeoutError, $!
45
- rescue ::HTTPClient::BadResponseError => err
46
- if err.message.include?('status 407')
47
- raise Faraday::Error::ConnectionFailed, %{407 "Proxy Authentication Required "}
48
- else
49
- raise Faraday::Error::ClientError, $!
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 ")
50
63
  end
51
- rescue Errno::ECONNREFUSED, EOFError
52
- raise Faraday::Error::ConnectionFailed, $!
53
- rescue => err
54
- if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err
55
- raise Faraday::SSLError, err
56
- else
57
- raise
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) && e.is_a?(OpenSSL::SSL::SSLError)
70
+ raise Faraday::SSLError, e
58
71
  end
72
+
73
+ raise
59
74
  end
60
75
 
61
- def configure_socket(bind)
76
+ # @param bind [Hash]
77
+ def configure_socket(client, bind)
62
78
  client.socket_local.host = bind[:host]
63
79
  client.socket_local.port = bind[:port]
64
80
  end
65
81
 
66
- def configure_proxy(proxy)
82
+ # Configure proxy URI and any user credentials.
83
+ #
84
+ # @param proxy [Hash]
85
+ def configure_proxy(client, proxy)
67
86
  client.proxy = proxy[:uri]
68
- if proxy[:user] && proxy[:password]
69
- client.set_proxy_auth proxy[:user], proxy[:password]
70
- end
87
+ return unless proxy[:user] && proxy[:password]
88
+
89
+ client.set_proxy_auth(proxy[:user], proxy[:password])
71
90
  end
72
91
 
73
- def configure_ssl(ssl)
92
+ # @param ssl [Hash]
93
+ def configure_ssl(client, ssl)
74
94
  ssl_config = client.ssl_config
75
95
  ssl_config.verify_mode = ssl_verify_mode(ssl)
76
96
  ssl_config.cert_store = ssl_cert_store(ssl)
@@ -82,31 +102,45 @@ module Faraday
82
102
  ssl_config.verify_depth = ssl[:verify_depth] if ssl[:verify_depth]
83
103
  end
84
104
 
85
- def configure_timeouts(req)
86
- if req[:timeout]
87
- client.connect_timeout = req[:timeout]
88
- client.receive_timeout = req[:timeout]
89
- client.send_timeout = req[:timeout]
105
+ # @param req [Hash]
106
+ def configure_timeouts(client, req)
107
+ if (sec = request_timeout(:open, req))
108
+ client.connect_timeout = sec
90
109
  end
91
110
 
92
- if req[:open_timeout]
93
- client.connect_timeout = req[:open_timeout]
94
- client.send_timeout = req[:open_timeout]
111
+ if (sec = request_timeout(:write, req))
112
+ client.send_timeout = sec
95
113
  end
114
+
115
+ return unless (sec = request_timeout(:read, req))
116
+
117
+ client.receive_timeout = sec
118
+ end
119
+
120
+ def configure_client(client)
121
+ @config_block&.call(client)
96
122
  end
97
123
 
124
+ # @param ssl [Hash]
125
+ # @return [OpenSSL::X509::Store]
98
126
  def ssl_cert_store(ssl)
99
127
  return ssl[:cert_store] if ssl[:cert_store]
100
- # Use the default cert store by default, i.e. system ca certs
101
- cert_store = OpenSSL::X509::Store.new
102
- cert_store.set_default_paths
103
- cert_store
128
+
129
+ # Memoize the cert store so that the same one is passed to
130
+ # HTTPClient each time, to avoid resyncing SSL sessions when
131
+ # it's changed
132
+ @ssl_cert_store ||= begin
133
+ # Use the default cert store by default, i.e. system ca certs
134
+ OpenSSL::X509::Store.new.tap(&:set_default_paths)
135
+ end
104
136
  end
105
137
 
138
+ # @param ssl [Hash]
106
139
  def ssl_verify_mode(ssl)
107
140
  ssl[:verify_mode] || begin
108
141
  if ssl.fetch(:verify, true)
109
- OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
142
+ OpenSSL::SSL::VERIFY_PEER |
143
+ OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
110
144
  else
111
145
  OpenSSL::SSL::VERIFY_NONE
112
146
  end