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,26 +1,56 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Faraday
2
4
  class Adapter
3
- # test = Faraday::Connection.new do
4
- # use Faraday::Adapter::Test do |stub|
5
- # stub.get '/nigiri/sake.json' do
6
- # [200, {}, 'hi world']
5
+ # @example
6
+ # test = Faraday::Connection.new do
7
+ # use Faraday::Adapter::Test do |stub|
8
+ # # Define matcher to match the request
9
+ # stub.get '/resource.json' do
10
+ # # return static content
11
+ # [200, {'Content-Type' => 'application/json'}, 'hi world']
12
+ # end
13
+ #
14
+ # # response with content generated based on request
15
+ # stub.get '/showget' do |env|
16
+ # [200, {'Content-Type' => 'text/plain'}, env[:method].to_s]
17
+ # end
18
+ #
19
+ # # A regular expression can be used as matching filter
20
+ # stub.get /\A\/items\/(\d+)\z/ do |env, meta|
21
+ # # in case regular expression is used, an instance of MatchData
22
+ # # can be received
23
+ # [200,
24
+ # {'Content-Type' => 'text/plain'},
25
+ # "showing item: #{meta[:match_data][1]}"
26
+ # ]
27
+ # end
7
28
  # end
8
29
  # end
9
- # end
10
30
  #
11
- # resp = test.get '/nigiri/sake.json'
12
- # resp.body # => 'hi world'
31
+ # resp = test.get '/resource.json'
32
+ # resp.body # => 'hi world'
13
33
  #
34
+ # resp = test.get '/showget'
35
+ # resp.body # => 'get'
36
+ #
37
+ # resp = test.get '/items/1'
38
+ # resp.body # => 'showing item: 1'
39
+ #
40
+ # resp = test.get '/items/2'
41
+ # resp.body # => 'showing item: 2'
14
42
  class Test < Faraday::Adapter
15
43
  attr_accessor :stubs
16
44
 
45
+ # A stack of Stubs
17
46
  class Stubs
18
47
  class NotFound < StandardError
19
48
  end
20
49
 
21
50
  def initialize
22
- # {:get => [Stub, Stub]}
23
- @stack, @consumed = {}, {}
51
+ # { get: [Stub, Stub] }
52
+ @stack = {}
53
+ @consumed = {}
24
54
  yield(self) if block_given?
25
55
  end
26
56
 
@@ -28,17 +58,18 @@ module Faraday
28
58
  @stack.empty?
29
59
  end
30
60
 
31
- def match(request_method, path, headers, body)
32
- return false if !@stack.key?(request_method)
61
+ def match(request_method, host, path, headers, body)
62
+ return false unless @stack.key?(request_method)
63
+
33
64
  stack = @stack[request_method]
34
65
  consumed = (@consumed[request_method] ||= [])
35
66
 
36
- if stub = matches?(stack, path, headers, body)
67
+ stub, meta = matches?(stack, host, path, headers, body)
68
+ if stub
37
69
  consumed << stack.delete(stub)
38
- stub
39
- else
40
- matches?(consumed, path, headers, body)
70
+ return stub, meta
41
71
  end
72
+ matches?(consumed, host, path, headers, body)
42
73
  end
43
74
 
44
75
  def get(path, headers = {}, &block)
@@ -49,15 +80,15 @@ module Faraday
49
80
  new_stub(:head, path, headers, &block)
50
81
  end
51
82
 
52
- def post(path, body=nil, headers = {}, &block)
83
+ def post(path, body = nil, headers = {}, &block)
53
84
  new_stub(:post, path, headers, body, &block)
54
85
  end
55
86
 
56
- def put(path, body=nil, headers = {}, &block)
87
+ def put(path, body = nil, headers = {}, &block)
57
88
  new_stub(:put, path, headers, body, &block)
58
89
  end
59
90
 
60
- def patch(path, body=nil, headers = {}, &block)
91
+ def patch(path, body = nil, headers = {}, &block)
61
92
  new_stub(:patch, path, headers, body, &block)
62
93
  end
63
94
 
@@ -73,45 +104,83 @@ module Faraday
73
104
  def verify_stubbed_calls
74
105
  failed_stubs = []
75
106
  @stack.each do |method, stubs|
76
- unless stubs.size == 0
77
- failed_stubs.concat(stubs.map {|stub|
107
+ next if stubs.empty?
108
+
109
+ failed_stubs.concat(
110
+ stubs.map do |stub|
78
111
  "Expected #{method} #{stub}."
79
- })
80
- end
112
+ end
113
+ )
81
114
  end
82
- raise failed_stubs.join(" ") unless failed_stubs.size == 0
115
+ raise failed_stubs.join(' ') unless failed_stubs.empty?
83
116
  end
84
117
 
85
118
  protected
86
119
 
87
- def new_stub(request_method, path, headers = {}, body=nil, &block)
88
- normalized_path = Faraday::Utils.normalize_path(path)
89
- (@stack[request_method] ||= []) << Stub.new(normalized_path, headers, body, block)
120
+ def new_stub(request_method, path, headers = {}, body = nil, &block)
121
+ normalized_path, host =
122
+ if path.is_a?(Regexp)
123
+ path
124
+ else
125
+ [
126
+ Faraday::Utils.normalize_path(path),
127
+ Faraday::Utils.URI(path).host
128
+ ]
129
+ end
130
+
131
+ stub = Stub.new(host, normalized_path, headers, body, block)
132
+ (@stack[request_method] ||= []) << stub
90
133
  end
91
134
 
92
- def matches?(stack, path, headers, body)
93
- stack.detect { |stub| stub.matches?(path, headers, body) }
135
+ def matches?(stack, host, path, headers, body)
136
+ stack.each do |stub|
137
+ match_result, meta = stub.matches?(host, path, headers, body)
138
+ return stub, meta if match_result
139
+ end
140
+ nil
94
141
  end
95
142
  end
96
143
 
97
- class Stub < Struct.new(:path, :params, :headers, :body, :block)
98
- def initialize(full, headers, body, block)
99
- path, query = full.split('?')
100
- params = query ?
101
- Faraday::Utils.parse_nested_query(query) :
102
- {}
103
- super(path, params, headers, body, block)
144
+ # Stub request
145
+ # rubocop:disable Style/StructInheritance
146
+ class Stub < Struct.new(:host, :path, :params, :headers, :body, :block)
147
+ # rubocop:enable Style/StructInheritance
148
+ def initialize(host, full, headers, body, block)
149
+ path, query = full.respond_to?(:split) ? full.split('?') : full
150
+ params =
151
+ if query
152
+ Faraday::Utils.parse_nested_query(query)
153
+ else
154
+ {}
155
+ end
156
+
157
+ super(host, path, params, headers, body, block)
104
158
  end
105
159
 
106
- def matches?(request_uri, request_headers, request_body)
160
+ def matches?(request_host, request_uri, request_headers, request_body)
107
161
  request_path, request_query = request_uri.split('?')
108
- request_params = request_query ?
109
- Faraday::Utils.parse_nested_query(request_query) :
110
- {}
111
- request_path == path &&
162
+ request_params =
163
+ if request_query
164
+ Faraday::Utils.parse_nested_query(request_query)
165
+ else
166
+ {}
167
+ end
168
+ # meta is a hash used as carrier
169
+ # that will be yielded to consumer block
170
+ meta = {}
171
+ [(host.nil? || host == request_host) &&
172
+ path_match?(request_path, meta) &&
112
173
  params_match?(request_params) &&
113
174
  (body.to_s.size.zero? || request_body == body) &&
114
- headers_match?(request_headers)
175
+ headers_match?(request_headers), meta]
176
+ end
177
+
178
+ def path_match?(request_path, meta)
179
+ if path.is_a?(Regexp)
180
+ !!(meta[:match_data] = path.match(request_path))
181
+ else
182
+ path == request_path
183
+ end
115
184
  end
116
185
 
117
186
  def params_match?(request_params)
@@ -131,7 +200,7 @@ module Faraday
131
200
  end
132
201
  end
133
202
 
134
- def initialize(app, stubs=nil, &block)
203
+ def initialize(app, stubs = nil, &block)
135
204
  super(app)
136
205
  @stubs = stubs || Stubs.new
137
206
  configure(&block) if block
@@ -143,18 +212,33 @@ module Faraday
143
212
 
144
213
  def call(env)
145
214
  super
215
+ host = env[:url].host
146
216
  normalized_path = Faraday::Utils.normalize_path(env[:url])
147
- params_encoder = env.request.params_encoder || Faraday::Utils.default_params_encoder
217
+ params_encoder = env.request.params_encoder ||
218
+ Faraday::Utils.default_params_encoder
219
+
220
+ stub, meta = stubs.match(env[:method], host, normalized_path,
221
+ env.request_headers, env[:body])
222
+
223
+ unless stub
224
+ raise Stubs::NotFound, "no stubbed request for #{env[:method]} "\
225
+ "#{normalized_path} #{env[:body]}"
226
+ end
227
+
228
+ env[:params] = if (query = env[:url].query)
229
+ params_encoder.decode(query)
230
+ else
231
+ {}
232
+ end
233
+ block_arity = stub.block.arity
234
+ status, headers, body =
235
+ if block_arity >= 0
236
+ stub.block.call(*[env, meta].take(block_arity))
237
+ else
238
+ stub.block.call(env, meta)
239
+ end
240
+ save_response(env, status, body, headers)
148
241
 
149
- if stub = stubs.match(env[:method], normalized_path, env.request_headers, env[:body])
150
- env[:params] = (query = env[:url].query) ?
151
- params_encoder.decode(query) :
152
- {}
153
- status, headers, body = stub.block.call(env)
154
- save_response(env, status, body, headers)
155
- else
156
- raise Stubs::NotFound, "no stubbed request for #{env[:method]} #{normalized_path} #{env[:body]}"
157
- end
158
242
  @app.call(env)
159
243
  end
160
244
  end
@@ -1,123 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Faraday
2
4
  class Adapter
5
+ # Typhoeus adapter. This class is just a stub, the real adapter is in
6
+ # https://github.com/philsturgeon/typhoeus/blob/master/lib/typhoeus/adapters/faraday.rb
3
7
  class Typhoeus < Faraday::Adapter
4
- self.supports_parallel = true
5
-
6
- def self.setup_parallel_manager(options = {})
7
- options.empty? ? ::Typhoeus::Hydra.hydra : ::Typhoeus::Hydra.new(options)
8
- end
8
+ # Needs to define this method in order to support Typhoeus <= 1.3.0
9
+ def call; end
9
10
 
10
11
  dependency 'typhoeus'
11
-
12
- def call(env)
13
- super
14
- perform_request env
15
- @app.call env
16
- end
17
-
18
- def perform_request(env)
19
- read_body env
20
-
21
- hydra = env[:parallel_manager] || self.class.setup_parallel_manager
22
- hydra.queue request(env)
23
- hydra.run unless parallel?(env)
24
- rescue Errno::ECONNREFUSED
25
- raise Error::ConnectionFailed, $!
26
- end
27
-
28
- # TODO: support streaming requests
29
- def read_body(env)
30
- env[:body] = env[:body].read if env[:body].respond_to? :read
31
- end
32
-
33
- def request(env)
34
- method = env[:method]
35
- # For some reason, prevents Typhoeus from using "100-continue".
36
- # We want this because Webrick 1.3.1 can't seem to handle it w/ PUT.
37
- method = method.to_s.upcase if method == :put
38
-
39
- req = ::Typhoeus::Request.new env[:url].to_s,
40
- :method => method,
41
- :body => env[:body],
42
- :headers => env[:request_headers],
43
- :disable_ssl_peer_verification => (env[:ssl] && env[:ssl].disable?)
44
-
45
- configure_ssl req, env
46
- configure_proxy req, env
47
- configure_timeout req, env
48
- configure_socket req, env
49
-
50
- req.on_complete do |resp|
51
- if resp.timed_out?
52
- if parallel?(env)
53
- # TODO: error callback in async mode
54
- else
55
- raise Faraday::Error::TimeoutError, "request timed out"
56
- end
57
- end
58
-
59
- case resp.curl_return_code
60
- when 0
61
- # everything OK
62
- when 7
63
- raise Error::ConnectionFailed, resp.curl_error_message
64
- when 60
65
- raise Faraday::SSLError, resp.curl_error_message
66
- else
67
- raise Error::ClientError, resp.curl_error_message
68
- end
69
-
70
- save_response(env, resp.code, resp.body) do |response_headers|
71
- response_headers.parse resp.headers
72
- end
73
- # in async mode, :response is initialized at this point
74
- env[:response].finish(env) if parallel?(env)
75
- end
76
-
77
- req
78
- end
79
-
80
- def configure_ssl(req, env)
81
- ssl = env[:ssl]
82
-
83
- req.ssl_version = ssl[:version] if ssl[:version]
84
- req.ssl_cert = ssl[:client_cert] if ssl[:client_cert]
85
- req.ssl_key = ssl[:client_key] if ssl[:client_key]
86
- req.ssl_cacert = ssl[:ca_file] if ssl[:ca_file]
87
- req.ssl_capath = ssl[:ca_path] if ssl[:ca_path]
88
- end
89
-
90
- def configure_proxy(req, env)
91
- proxy = request_options(env)[:proxy]
92
- return unless proxy
93
-
94
- req.proxy = "#{proxy[:uri].host}:#{proxy[:uri].port}"
95
-
96
- if proxy[:user] && proxy[:password]
97
- req.proxy_username = proxy[:user]
98
- req.proxy_password = proxy[:password]
99
- end
100
- end
101
-
102
- def configure_timeout(req, env)
103
- env_req = request_options(env)
104
- req.timeout = req.connect_timeout = (env_req[:timeout] * 1000) if env_req[:timeout]
105
- req.connect_timeout = (env_req[:open_timeout] * 1000) if env_req[:open_timeout]
106
- end
107
-
108
- def configure_socket(req, env)
109
- if bind = request_options(env)[:bind]
110
- req.interface = bind[:host]
111
- end
112
- end
113
-
114
- def request_options(env)
115
- env[:request]
116
- end
117
-
118
- def parallel?(env)
119
- !!env[:parallel_manager]
120
- end
12
+ dependency 'typhoeus/adapters/faraday'
121
13
  end
122
14
  end
123
15
  end
@@ -1,46 +1,115 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Faraday
2
- # Public: This is a base class for all Faraday adapters. Adapters are
4
+ # Base class for all Faraday adapters. Adapters are
3
5
  # responsible for fulfilling a Faraday request.
4
- class Adapter < Middleware
5
- CONTENT_LENGTH = 'Content-Length'.freeze
6
-
7
- register_middleware File.expand_path('../adapter', __FILE__),
8
- :test => [:Test, 'test'],
9
- :net_http => [:NetHttp, 'net_http'],
10
- :net_http_persistent => [:NetHttpPersistent, 'net_http_persistent'],
11
- :typhoeus => [:Typhoeus, 'typhoeus'],
12
- :patron => [:Patron, 'patron'],
13
- :em_synchrony => [:EMSynchrony, 'em_synchrony'],
14
- :em_http => [:EMHttp, 'em_http'],
15
- :excon => [:Excon, 'excon'],
16
- :rack => [:Rack, 'rack'],
17
- :httpclient => [:HTTPClient, 'httpclient']
18
-
19
- # Public: This module marks an Adapter as supporting parallel requests.
6
+ class Adapter
7
+ extend MiddlewareRegistry
8
+ extend DependencyLoader
9
+
10
+ CONTENT_LENGTH = 'Content-Length'
11
+
12
+ register_middleware File.expand_path('adapter', __dir__),
13
+ test: [:Test, 'test'],
14
+ net_http: [:NetHttp, 'net_http'],
15
+ net_http_persistent: [
16
+ :NetHttpPersistent,
17
+ 'net_http_persistent'
18
+ ],
19
+ typhoeus: [:Typhoeus, 'typhoeus'],
20
+ patron: [:Patron, 'patron'],
21
+ em_synchrony: [:EMSynchrony, 'em_synchrony'],
22
+ em_http: [:EMHttp, 'em_http'],
23
+ excon: [:Excon, 'excon'],
24
+ rack: [:Rack, 'rack'],
25
+ httpclient: [:HTTPClient, 'httpclient']
26
+
27
+ # This module marks an Adapter as supporting parallel requests.
20
28
  module Parallelism
21
29
  attr_writer :supports_parallel
22
- def supports_parallel?() @supports_parallel end
30
+ def supports_parallel?
31
+ @supports_parallel
32
+ end
23
33
 
24
34
  def inherited(subclass)
25
35
  super
26
- subclass.supports_parallel = self.supports_parallel?
36
+ subclass.supports_parallel = supports_parallel?
27
37
  end
28
38
  end
29
39
 
30
40
  extend Parallelism
31
41
  self.supports_parallel = false
32
42
 
43
+ def initialize(_app = nil, opts = {}, &block)
44
+ @app = ->(env) { env.response }
45
+ @connection_options = opts
46
+ @config_block = block
47
+ end
48
+
49
+ # Yields or returns an adapter's configured connection. Depends on
50
+ # #build_connection being defined on this adapter.
51
+ #
52
+ # @param env [Faraday::Env, Hash] The env object for a faraday request.
53
+ #
54
+ # @return The return value of the given block, or the HTTP connection object
55
+ # if no block is given.
56
+ def connection(env)
57
+ conn = build_connection(env)
58
+ return conn unless block_given?
59
+
60
+ yield conn
61
+ end
62
+
63
+ # Close any persistent connections. The adapter should still be usable
64
+ # after calling close.
65
+ def close
66
+ # Possible implementation:
67
+ # @app.close if @app.respond_to?(:close)
68
+ end
69
+
33
70
  def call(env)
34
71
  env.clear_body if env.needs_body?
72
+ env.response = Response.new
35
73
  end
36
74
 
37
- def save_response(env, status, body, headers = nil)
75
+ private
76
+
77
+ def save_response(env, status, body, headers = nil, reason_phrase = nil)
38
78
  env.status = status
39
79
  env.body = body
80
+ env.reason_phrase = reason_phrase&.to_s&.strip
40
81
  env.response_headers = Utils::Headers.new.tap do |response_headers|
41
82
  response_headers.update headers unless headers.nil?
42
83
  yield(response_headers) if block_given?
43
84
  end
85
+
86
+ env.response.finish(env) unless env.parallel?
87
+ env.response
44
88
  end
89
+
90
+ # Fetches either a read, write, or open timeout setting. Defaults to the
91
+ # :timeout value if a more specific one is not given.
92
+ #
93
+ # @param type [Symbol] Describes which timeout setting to get: :read,
94
+ # :write, or :open.
95
+ # @param options [Hash] Hash containing Symbol keys like :timeout,
96
+ # :read_timeout, :write_timeout, :open_timeout, or
97
+ # :timeout
98
+ #
99
+ # @return [Integer, nil] Timeout duration in seconds, or nil if no timeout
100
+ # has been set.
101
+ def request_timeout(type, options)
102
+ key = TIMEOUT_KEYS.fetch(type) do
103
+ msg = "Expected :read, :write, :open. Got #{type.inspect} :("
104
+ raise ArgumentError, msg
105
+ end
106
+ options[key] || options[:timeout]
107
+ end
108
+
109
+ TIMEOUT_KEYS = {
110
+ read: :read_timeout,
111
+ open: :open_timeout,
112
+ write: :write_timeout
113
+ }.freeze
45
114
  end
46
115
  end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'monitor'
4
+
5
+ module Faraday
6
+ # AdapterRegistry registers adapter class names so they can be looked up by a
7
+ # String or Symbol name.
8
+ class AdapterRegistry
9
+ def initialize
10
+ @lock = Monitor.new
11
+ @constants = {}
12
+ end
13
+
14
+ def get(name)
15
+ klass = @constants[name]
16
+ return klass if klass
17
+
18
+ Object.const_get(name).tap { |c| set(c, name) }
19
+ end
20
+
21
+ def set(klass, name = nil)
22
+ name ||= klass.to_s
23
+ @lock.synchronize do
24
+ @constants[name] = klass
25
+ end
26
+ end
27
+ end
28
+ end