faraday 0.17.3 → 2.7.4

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 (124) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +350 -8
  3. data/LICENSE.md +1 -1
  4. data/README.md +27 -367
  5. data/Rakefile +1 -7
  6. data/examples/client_spec.rb +119 -0
  7. data/examples/client_test.rb +144 -0
  8. data/lib/faraday/adapter/test.rb +170 -72
  9. data/lib/faraday/adapter.rb +69 -23
  10. data/lib/faraday/adapter_registry.rb +30 -0
  11. data/lib/faraday/connection.rb +309 -233
  12. data/lib/faraday/encoders/flat_params_encoder.rb +105 -0
  13. data/lib/faraday/encoders/nested_params_encoder.rb +183 -0
  14. data/lib/faraday/error.rb +31 -42
  15. data/lib/faraday/logging/formatter.rb +122 -0
  16. data/lib/faraday/methods.rb +6 -0
  17. data/lib/faraday/middleware.rb +21 -25
  18. data/lib/faraday/middleware_registry.rb +83 -0
  19. data/lib/faraday/options/connection_options.rb +22 -0
  20. data/lib/faraday/options/env.rb +205 -0
  21. data/lib/faraday/options/proxy_options.rb +32 -0
  22. data/lib/faraday/options/request_options.rb +22 -0
  23. data/lib/faraday/options/ssl_options.rb +69 -0
  24. data/lib/faraday/options.rb +38 -193
  25. data/lib/faraday/parameters.rb +4 -197
  26. data/lib/faraday/rack_builder.rb +91 -76
  27. data/lib/faraday/request/authorization.rb +42 -29
  28. data/lib/faraday/request/instrumentation.rb +47 -27
  29. data/lib/faraday/request/json.rb +55 -0
  30. data/lib/faraday/request/url_encoded.rb +48 -24
  31. data/lib/faraday/request.rb +64 -42
  32. data/lib/faraday/response/json.rb +54 -0
  33. data/lib/faraday/response/logger.rb +24 -67
  34. data/lib/faraday/response/raise_error.rb +57 -18
  35. data/lib/faraday/response.rb +26 -32
  36. data/lib/faraday/utils/headers.rb +144 -0
  37. data/lib/faraday/utils/params_hash.rb +61 -0
  38. data/lib/faraday/utils.rb +47 -251
  39. data/lib/faraday/version.rb +5 -0
  40. data/lib/faraday.rb +108 -198
  41. data/spec/external_adapters/faraday_specs_setup.rb +14 -0
  42. data/spec/faraday/adapter/test_spec.rb +442 -0
  43. data/spec/faraday/adapter_registry_spec.rb +28 -0
  44. data/spec/faraday/adapter_spec.rb +55 -0
  45. data/spec/faraday/connection_spec.rb +808 -0
  46. data/spec/faraday/error_spec.rb +12 -54
  47. data/spec/faraday/middleware_registry_spec.rb +31 -0
  48. data/spec/faraday/middleware_spec.rb +70 -0
  49. data/spec/faraday/options/env_spec.rb +76 -0
  50. data/spec/faraday/options/options_spec.rb +297 -0
  51. data/spec/faraday/options/proxy_options_spec.rb +44 -0
  52. data/spec/faraday/options/request_options_spec.rb +19 -0
  53. data/spec/faraday/params_encoders/flat_spec.rb +42 -0
  54. data/spec/faraday/params_encoders/nested_spec.rb +150 -0
  55. data/spec/faraday/rack_builder_spec.rb +317 -0
  56. data/spec/faraday/request/authorization_spec.rb +118 -0
  57. data/spec/faraday/request/instrumentation_spec.rb +74 -0
  58. data/spec/faraday/request/json_spec.rb +111 -0
  59. data/spec/faraday/request/url_encoded_spec.rb +93 -0
  60. data/spec/faraday/request_spec.rb +110 -0
  61. data/spec/faraday/response/json_spec.rb +117 -0
  62. data/spec/faraday/response/logger_spec.rb +248 -0
  63. data/spec/faraday/response/raise_error_spec.rb +81 -15
  64. data/spec/faraday/response_spec.rb +77 -0
  65. data/spec/faraday/utils/headers_spec.rb +100 -0
  66. data/spec/faraday/utils_spec.rb +118 -0
  67. data/spec/faraday_spec.rb +37 -0
  68. data/spec/spec_helper.rb +63 -36
  69. data/spec/support/disabling_stub.rb +14 -0
  70. data/spec/support/fake_safe_buffer.rb +15 -0
  71. data/spec/support/helper_methods.rb +96 -0
  72. data/spec/support/shared_examples/adapter.rb +105 -0
  73. data/spec/support/shared_examples/params_encoder.rb +18 -0
  74. data/spec/support/shared_examples/request_method.rb +263 -0
  75. data/spec/support/streaming_response_checker.rb +35 -0
  76. metadata +76 -59
  77. data/lib/faraday/adapter/em_http.rb +0 -243
  78. data/lib/faraday/adapter/em_http_ssl_patch.rb +0 -56
  79. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +0 -66
  80. data/lib/faraday/adapter/em_synchrony.rb +0 -106
  81. data/lib/faraday/adapter/excon.rb +0 -82
  82. data/lib/faraday/adapter/httpclient.rb +0 -128
  83. data/lib/faraday/adapter/net_http.rb +0 -152
  84. data/lib/faraday/adapter/net_http_persistent.rb +0 -68
  85. data/lib/faraday/adapter/patron.rb +0 -95
  86. data/lib/faraday/adapter/rack.rb +0 -58
  87. data/lib/faraday/adapter/typhoeus.rb +0 -12
  88. data/lib/faraday/autoload.rb +0 -84
  89. data/lib/faraday/deprecate.rb +0 -107
  90. data/lib/faraday/request/basic_authentication.rb +0 -13
  91. data/lib/faraday/request/multipart.rb +0 -68
  92. data/lib/faraday/request/retry.rb +0 -213
  93. data/lib/faraday/request/token_authentication.rb +0 -15
  94. data/lib/faraday/upload_io.rb +0 -67
  95. data/spec/faraday/deprecate_spec.rb +0 -69
  96. data/test/adapters/default_test.rb +0 -14
  97. data/test/adapters/em_http_test.rb +0 -30
  98. data/test/adapters/em_synchrony_test.rb +0 -32
  99. data/test/adapters/excon_test.rb +0 -30
  100. data/test/adapters/httpclient_test.rb +0 -34
  101. data/test/adapters/integration.rb +0 -263
  102. data/test/adapters/logger_test.rb +0 -136
  103. data/test/adapters/net_http_persistent_test.rb +0 -114
  104. data/test/adapters/net_http_test.rb +0 -79
  105. data/test/adapters/patron_test.rb +0 -40
  106. data/test/adapters/rack_test.rb +0 -38
  107. data/test/adapters/test_middleware_test.rb +0 -157
  108. data/test/adapters/typhoeus_test.rb +0 -38
  109. data/test/authentication_middleware_test.rb +0 -65
  110. data/test/composite_read_io_test.rb +0 -109
  111. data/test/connection_test.rb +0 -738
  112. data/test/env_test.rb +0 -268
  113. data/test/helper.rb +0 -75
  114. data/test/live_server.rb +0 -67
  115. data/test/middleware/instrumentation_test.rb +0 -88
  116. data/test/middleware/retry_test.rb +0 -282
  117. data/test/middleware_stack_test.rb +0 -260
  118. data/test/multibyte.txt +0 -1
  119. data/test/options_test.rb +0 -333
  120. data/test/parameters_test.rb +0 -157
  121. data/test/request_middleware_test.rb +0 -126
  122. data/test/response_middleware_test.rb +0 -72
  123. data/test/strawberry.rb +0 -2
  124. data/test/utils_test.rb +0 -98
@@ -1,51 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'timeout'
4
+
1
5
  module Faraday
2
6
  class Adapter
3
- # Examples
4
- #
7
+ # @example
5
8
  # test = Faraday::Connection.new do
6
9
  # use Faraday::Adapter::Test do |stub|
7
- # # simply define matcher to match the request
10
+ # # Define matcher to match the request
8
11
  # stub.get '/resource.json' do
9
12
  # # return static content
10
13
  # [200, {'Content-Type' => 'application/json'}, 'hi world']
11
14
  # end
12
- #
15
+ #
13
16
  # # response with content generated based on request
14
17
  # stub.get '/showget' do |env|
15
18
  # [200, {'Content-Type' => 'text/plain'}, env[:method].to_s]
16
19
  # end
17
- #
18
- # # regular expression can be used as matching filter
20
+ #
21
+ # # A regular expression can be used as matching filter
19
22
  # stub.get /\A\/items\/(\d+)\z/ do |env, meta|
20
- # # in case regular expression is used an instance of MatchData can be received
21
- # [200, {'Content-Type' => 'text/plain'}, "showing item: #{meta[:match_data][1]}"]
23
+ # # in case regular expression is used, an instance of MatchData
24
+ # # can be received
25
+ # [200,
26
+ # {'Content-Type' => 'text/plain'},
27
+ # "showing item: #{meta[:match_data][1]}"
28
+ # ]
22
29
  # end
30
+ #
31
+ # # Test the request body is the same as the stubbed body
32
+ # stub.post('/bar', 'name=YK&word=call') { [200, {}, ''] }
33
+ #
34
+ # # You can pass a proc as a stubbed body and check the request body in your way.
35
+ # # In this case, the proc should return true or false.
36
+ # stub.post('/foo', ->(request_body) do
37
+ # JSON.parse(request_body).slice('name') == { 'name' => 'YK' } }) { [200, {}, '']
38
+ # end
39
+ #
40
+ # # You can set strict_mode to exactly match the stubbed requests.
41
+ # stub.strict_mode = true
23
42
  # end
24
43
  # end
25
- #
44
+ #
26
45
  # resp = test.get '/resource.json'
27
46
  # resp.body # => 'hi world'
28
- #
47
+ #
29
48
  # resp = test.get '/showget'
30
49
  # resp.body # => 'get'
31
- #
50
+ #
32
51
  # resp = test.get '/items/1'
33
52
  # resp.body # => 'showing item: 1'
34
- #
53
+ #
35
54
  # resp = test.get '/items/2'
36
55
  # resp.body # => 'showing item: 2'
37
56
  #
38
-
57
+ # resp = test.post '/bar', 'name=YK&word=call'
58
+ # resp.status # => 200
59
+ #
60
+ # resp = test.post '/foo', JSON.dump(name: 'YK', created_at: Time.now)
61
+ # resp.status # => 200
39
62
  class Test < Faraday::Adapter
40
63
  attr_accessor :stubs
41
64
 
65
+ # A stack of Stubs
42
66
  class Stubs
43
67
  class NotFound < StandardError
44
68
  end
45
69
 
46
- def initialize
47
- # {:get => [Stub, Stub]}
48
- @stack, @consumed = {}, {}
70
+ def initialize(strict_mode: false)
71
+ # { get: [Stub, Stub] }
72
+ @stack = {}
73
+ @consumed = {}
74
+ @strict_mode = strict_mode
75
+ @stubs_mutex = Monitor.new
49
76
  yield(self) if block_given?
50
77
  end
51
78
 
@@ -53,17 +80,23 @@ module Faraday
53
80
  @stack.empty?
54
81
  end
55
82
 
56
- def match(request_method, host, path, headers, body)
57
- return false if !@stack.key?(request_method)
83
+ # @param env [Faraday::Env]
84
+ def match(env)
85
+ request_method = env[:method]
86
+ return false unless @stack.key?(request_method)
87
+
58
88
  stack = @stack[request_method]
59
89
  consumed = (@consumed[request_method] ||= [])
60
90
 
61
- stub, meta = matches?(stack, host, path, headers, body)
62
- if stub
63
- consumed << stack.delete(stub)
64
- return stub, meta
91
+ @stubs_mutex.synchronize do
92
+ stub, meta = matches?(stack, env)
93
+ if stub
94
+ removed = stack.delete(stub)
95
+ consumed << removed unless removed.nil?
96
+ return stub, meta
97
+ end
65
98
  end
66
- matches?(consumed, host, path, headers, body)
99
+ matches?(consumed, env)
67
100
  end
68
101
 
69
102
  def get(path, headers = {}, &block)
@@ -74,15 +107,15 @@ module Faraday
74
107
  new_stub(:head, path, headers, &block)
75
108
  end
76
109
 
77
- def post(path, body=nil, headers = {}, &block)
110
+ def post(path, body = nil, headers = {}, &block)
78
111
  new_stub(:post, path, headers, body, &block)
79
112
  end
80
113
 
81
- def put(path, body=nil, headers = {}, &block)
114
+ def put(path, body = nil, headers = {}, &block)
82
115
  new_stub(:put, path, headers, body, &block)
83
116
  end
84
117
 
85
- def patch(path, body=nil, headers = {}, &block)
118
+ def patch(path, body = nil, headers = {}, &block)
86
119
  new_stub(:patch, path, headers, body, &block)
87
120
  end
88
121
 
@@ -98,87 +131,131 @@ module Faraday
98
131
  def verify_stubbed_calls
99
132
  failed_stubs = []
100
133
  @stack.each do |method, stubs|
101
- unless stubs.size == 0
102
- failed_stubs.concat(stubs.map {|stub|
134
+ next if stubs.empty?
135
+
136
+ failed_stubs.concat(
137
+ stubs.map do |stub|
103
138
  "Expected #{method} #{stub}."
104
- })
139
+ end
140
+ )
141
+ end
142
+ raise failed_stubs.join(' ') unless failed_stubs.empty?
143
+ end
144
+
145
+ # Set strict_mode. If the value is true, this adapter tries to find matched requests strictly,
146
+ # which means that all of a path, parameters, and headers must be the same as an actual request.
147
+ def strict_mode=(value)
148
+ @strict_mode = value
149
+ @stack.each do |_method, stubs|
150
+ stubs.each do |stub|
151
+ stub.strict_mode = value
105
152
  end
106
153
  end
107
- raise failed_stubs.join(" ") unless failed_stubs.size == 0
108
154
  end
109
155
 
110
156
  protected
111
157
 
112
- def new_stub(request_method, path, headers = {}, body=nil, &block)
158
+ def new_stub(request_method, path, headers = {}, body = nil, &block)
113
159
  normalized_path, host =
114
160
  if path.is_a?(Regexp)
115
161
  path
116
162
  else
117
- [Faraday::Utils.normalize_path(path), Faraday::Utils.URI(path).host]
163
+ [
164
+ Faraday::Utils.normalize_path(path),
165
+ Faraday::Utils.URI(path).host
166
+ ]
118
167
  end
168
+ path, query = normalized_path.respond_to?(:split) ? normalized_path.split('?') : normalized_path
169
+ headers = Utils::Headers.new(headers)
119
170
 
120
- (@stack[request_method] ||= []) << Stub.new(host, normalized_path, headers, body, block)
171
+ stub = Stub.new(host, path, query, headers, body, @strict_mode, block)
172
+ (@stack[request_method] ||= []) << stub
121
173
  end
122
174
 
123
- def matches?(stack, host, path, headers, body)
175
+ # @param stack [Hash]
176
+ # @param env [Faraday::Env]
177
+ def matches?(stack, env)
124
178
  stack.each do |stub|
125
- match_result, meta = stub.matches?(host, path, headers, body)
179
+ match_result, meta = stub.matches?(env)
126
180
  return stub, meta if match_result
127
181
  end
128
182
  nil
129
183
  end
130
184
  end
131
185
 
132
- class Stub < Struct.new(:host, :path, :params, :headers, :body, :block)
133
- def initialize(host, full, headers, body, block)
134
- path, query = full.respond_to?(:split) ? full.split("?") : full
135
- params = query ?
136
- Faraday::Utils.parse_nested_query(query) :
137
- {}
138
- super(host, path, params, headers, body, block)
139
- end
140
-
141
- def matches?(request_host, request_uri, request_headers, request_body)
142
- request_path, request_query = request_uri.split('?')
143
- request_params = request_query ?
144
- Faraday::Utils.parse_nested_query(request_query) :
145
- {}
146
- # meta is a hash use as carrier
186
+ # Stub request
187
+ class Stub < Struct.new(:host, :path, :query, :headers, :body, :strict_mode, :block) # rubocop:disable Style/StructInheritance
188
+ # @param env [Faraday::Env]
189
+ def matches?(env)
190
+ request_host = env[:url].host
191
+ request_path = Faraday::Utils.normalize_path(env[:url].path)
192
+ request_headers = env.request_headers
193
+ request_body = env[:body]
194
+
195
+ # meta is a hash used as carrier
147
196
  # that will be yielded to consumer block
148
197
  meta = {}
149
- return (host.nil? || host == request_host) &&
198
+ [(host.nil? || host == request_host) &&
150
199
  path_match?(request_path, meta) &&
151
- params_match?(request_params) &&
152
- (body.to_s.size.zero? || request_body == body) &&
153
- headers_match?(request_headers), meta
200
+ params_match?(env) &&
201
+ body_match?(request_body) &&
202
+ headers_match?(request_headers), meta]
154
203
  end
155
204
 
156
205
  def path_match?(request_path, meta)
157
- if path.is_a? Regexp
206
+ if path.is_a?(Regexp)
158
207
  !!(meta[:match_data] = path.match(request_path))
159
208
  else
160
209
  path == request_path
161
210
  end
162
211
  end
163
212
 
164
- def params_match?(request_params)
213
+ # @param env [Faraday::Env]
214
+ def params_match?(env)
215
+ request_params = env[:params]
216
+ params = env.params_encoder.decode(query) || {}
217
+
218
+ if strict_mode
219
+ return Set.new(params) == Set.new(request_params)
220
+ end
221
+
165
222
  params.keys.all? do |key|
166
223
  request_params[key] == params[key]
167
224
  end
168
225
  end
169
226
 
170
227
  def headers_match?(request_headers)
228
+ if strict_mode
229
+ headers_with_user_agent = headers.dup.tap do |hs|
230
+ # NOTE: Set User-Agent in case it's not set when creating Stubs.
231
+ # Users would not want to set Faraday's User-Agent explicitly.
232
+ hs[:user_agent] ||= Connection::USER_AGENT
233
+ end
234
+ return Set.new(headers_with_user_agent) == Set.new(request_headers)
235
+ end
236
+
171
237
  headers.keys.all? do |key|
172
238
  request_headers[key] == headers[key]
173
239
  end
174
240
  end
175
241
 
242
+ def body_match?(request_body)
243
+ return true if body.to_s.empty?
244
+
245
+ case body
246
+ when Proc
247
+ body.call(request_body)
248
+ else
249
+ request_body == body
250
+ end
251
+ end
252
+
176
253
  def to_s
177
254
  "#{path} #{body}"
178
255
  end
179
256
  end
180
257
 
181
- def initialize(app, stubs=nil, &block)
258
+ def initialize(app, stubs = nil, &block)
182
259
  super(app)
183
260
  @stubs = stubs || Stubs.new
184
261
  configure(&block) if block
@@ -188,26 +265,47 @@ module Faraday
188
265
  yield(stubs)
189
266
  end
190
267
 
268
+ # @param env [Faraday::Env]
191
269
  def call(env)
192
270
  super
193
- host = env[:url].host
194
- normalized_path = Faraday::Utils.normalize_path(env[:url])
195
- params_encoder = env.request.params_encoder || Faraday::Utils.default_params_encoder
196
-
197
- stub, meta = stubs.match(env[:method], host, normalized_path, env.request_headers, env[:body])
198
- if stub
199
- env[:params] = (query = env[:url].query) ?
200
- params_encoder.decode(query) : {}
201
- block_arity = stub.block.arity
202
- status, headers, body = (block_arity >= 0) ?
203
- stub.block.call(*[env, meta].take(block_arity)) :
204
- stub.block.call(env, meta)
205
- save_response(env, status, body, headers)
206
- else
207
- raise Stubs::NotFound, "no stubbed request for #{env[:method]} #{normalized_path} #{env[:body]}"
271
+
272
+ env.request.params_encoder ||= Faraday::Utils.default_params_encoder
273
+ env[:params] = env.params_encoder.decode(env[:url].query) || {}
274
+ stub, meta = stubs.match(env)
275
+
276
+ unless stub
277
+ raise Stubs::NotFound, "no stubbed request for #{env[:method]} " \
278
+ "#{env[:url]} #{env[:body]}"
208
279
  end
280
+
281
+ block_arity = stub.block.arity
282
+ params = if block_arity >= 0
283
+ [env, meta].take(block_arity)
284
+ else
285
+ [env, meta]
286
+ end
287
+
288
+ timeout = request_timeout(:open, env[:request])
289
+ timeout ||= request_timeout(:read, env[:request])
290
+
291
+ status, headers, body =
292
+ if timeout
293
+ ::Timeout.timeout(timeout, Faraday::TimeoutError) do
294
+ stub.block.call(*params)
295
+ end
296
+ else
297
+ stub.block.call(*params)
298
+ end
299
+
300
+ # We need to explicitly pass `reason_phrase = nil` here to avoid keyword args conflicts.
301
+ # See https://github.com/lostisland/faraday/issues/1444
302
+ # TODO: remove `nil` explicit reason_phrase once Ruby 3.0 becomes minimum req. version
303
+ save_response(env, status, body, headers, nil)
304
+
209
305
  @app.call(env)
210
306
  end
211
307
  end
212
308
  end
213
309
  end
310
+
311
+ Faraday::Adapter.register_middleware(test: Faraday::Adapter::Test)
@@ -1,55 +1,101 @@
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
+
9
+ CONTENT_LENGTH = 'Content-Length'
10
+
11
+ # This module marks an Adapter as supporting parallel requests.
20
12
  module Parallelism
21
13
  attr_writer :supports_parallel
22
- def supports_parallel?() @supports_parallel end
14
+
15
+ def supports_parallel?
16
+ @supports_parallel
17
+ end
23
18
 
24
19
  def inherited(subclass)
25
20
  super
26
- subclass.supports_parallel = self.supports_parallel?
21
+ subclass.supports_parallel = supports_parallel?
27
22
  end
28
23
  end
29
24
 
30
25
  extend Parallelism
31
26
  self.supports_parallel = false
32
27
 
33
- def initialize(app = nil, opts = {}, &block)
34
- super(app)
28
+ def initialize(_app = nil, opts = {}, &block)
29
+ @app = ->(env) { env.response }
35
30
  @connection_options = opts
36
31
  @config_block = block
37
32
  end
38
33
 
34
+ # Yields or returns an adapter's configured connection. Depends on
35
+ # #build_connection being defined on this adapter.
36
+ #
37
+ # @param env [Faraday::Env, Hash] The env object for a faraday request.
38
+ #
39
+ # @return The return value of the given block, or the HTTP connection object
40
+ # if no block is given.
41
+ def connection(env)
42
+ conn = build_connection(env)
43
+ return conn unless block_given?
44
+
45
+ yield conn
46
+ end
47
+
48
+ # Close any persistent connections. The adapter should still be usable
49
+ # after calling close.
50
+ def close
51
+ # Possible implementation:
52
+ # @app.close if @app.respond_to?(:close)
53
+ end
54
+
39
55
  def call(env)
40
56
  env.clear_body if env.needs_body?
57
+ env.response = Response.new
41
58
  end
42
59
 
43
60
  private
44
61
 
45
- def save_response(env, status, body, headers = nil, reason_phrase = nil)
62
+ def save_response(env, status, body, headers = nil, reason_phrase = nil, finished: true)
46
63
  env.status = status
47
64
  env.body = body
48
- env.reason_phrase = reason_phrase && reason_phrase.to_s.strip
65
+ env.reason_phrase = reason_phrase&.to_s&.strip
49
66
  env.response_headers = Utils::Headers.new.tap do |response_headers|
50
67
  response_headers.update headers unless headers.nil?
51
68
  yield(response_headers) if block_given?
52
69
  end
70
+
71
+ env.response.finish(env) unless env.parallel? || !finished
72
+ env.response
73
+ end
74
+
75
+ # Fetches either a read, write, or open timeout setting. Defaults to the
76
+ # :timeout value if a more specific one is not given.
77
+ #
78
+ # @param type [Symbol] Describes which timeout setting to get: :read,
79
+ # :write, or :open.
80
+ # @param options [Hash] Hash containing Symbol keys like :timeout,
81
+ # :read_timeout, :write_timeout, or :open_timeout
82
+ #
83
+ # @return [Integer, nil] Timeout duration in seconds, or nil if no timeout
84
+ # has been set.
85
+ def request_timeout(type, options)
86
+ key = TIMEOUT_KEYS.fetch(type) do
87
+ msg = "Expected :read, :write, :open. Got #{type.inspect} :("
88
+ raise ArgumentError, msg
89
+ end
90
+ options[key] || options[:timeout]
53
91
  end
92
+
93
+ TIMEOUT_KEYS = {
94
+ read: :read_timeout,
95
+ open: :open_timeout,
96
+ write: :write_timeout
97
+ }.freeze
54
98
  end
55
99
  end
100
+
101
+ require 'faraday/adapter/test'
@@ -0,0 +1,30 @@
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 = @lock.synchronize do
16
+ @constants[name]
17
+ end
18
+ return klass if klass
19
+
20
+ Object.const_get(name).tap { |c| set(c, name) }
21
+ end
22
+
23
+ def set(klass, name = nil)
24
+ name ||= klass.to_s
25
+ @lock.synchronize do
26
+ @constants[name] = klass
27
+ end
28
+ end
29
+ end
30
+ end