faraday 0.15.4 → 0.16.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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.md +1 -1
  3. data/README.md +18 -344
  4. data/lib/faraday.rb +93 -175
  5. data/lib/faraday/adapter.rb +36 -22
  6. data/lib/faraday/adapter/em_http.rb +142 -99
  7. data/lib/faraday/adapter/em_http_ssl_patch.rb +23 -17
  8. data/lib/faraday/adapter/em_synchrony.rb +104 -60
  9. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +18 -15
  10. data/lib/faraday/adapter/excon.rb +100 -55
  11. data/lib/faraday/adapter/httpclient.rb +61 -39
  12. data/lib/faraday/adapter/net_http.rb +104 -51
  13. data/lib/faraday/adapter/net_http_persistent.rb +48 -27
  14. data/lib/faraday/adapter/patron.rb +54 -35
  15. data/lib/faraday/adapter/rack.rb +28 -12
  16. data/lib/faraday/adapter/test.rb +86 -53
  17. data/lib/faraday/adapter/typhoeus.rb +4 -1
  18. data/lib/faraday/adapter_registry.rb +28 -0
  19. data/lib/faraday/autoload.rb +47 -36
  20. data/lib/faraday/connection.rb +321 -179
  21. data/lib/faraday/dependency_loader.rb +37 -0
  22. data/lib/faraday/encoders/flat_params_encoder.rb +94 -0
  23. data/lib/faraday/encoders/nested_params_encoder.rb +171 -0
  24. data/lib/faraday/error.rb +67 -33
  25. data/lib/faraday/file_part.rb +128 -0
  26. data/lib/faraday/logging/formatter.rb +92 -0
  27. data/lib/faraday/middleware.rb +4 -28
  28. data/lib/faraday/middleware_registry.rb +129 -0
  29. data/lib/faraday/options.rb +35 -186
  30. data/lib/faraday/options/connection_options.rb +22 -0
  31. data/lib/faraday/options/env.rb +181 -0
  32. data/lib/faraday/options/proxy_options.rb +28 -0
  33. data/lib/faraday/options/request_options.rb +21 -0
  34. data/lib/faraday/options/ssl_options.rb +59 -0
  35. data/lib/faraday/param_part.rb +53 -0
  36. data/lib/faraday/parameters.rb +4 -197
  37. data/lib/faraday/rack_builder.rb +67 -56
  38. data/lib/faraday/request.rb +68 -36
  39. data/lib/faraday/request/authorization.rb +42 -30
  40. data/lib/faraday/request/basic_authentication.rb +14 -7
  41. data/lib/faraday/request/instrumentation.rb +45 -27
  42. data/lib/faraday/request/multipart.rb +79 -48
  43. data/lib/faraday/request/retry.rb +198 -169
  44. data/lib/faraday/request/token_authentication.rb +15 -10
  45. data/lib/faraday/request/url_encoded.rb +41 -23
  46. data/lib/faraday/response.rb +23 -16
  47. data/lib/faraday/response/logger.rb +22 -69
  48. data/lib/faraday/response/raise_error.rb +36 -14
  49. data/lib/faraday/utils.rb +28 -245
  50. data/lib/faraday/utils/headers.rb +139 -0
  51. data/lib/faraday/utils/params_hash.rb +61 -0
  52. data/spec/external_adapters/faraday_specs_setup.rb +14 -0
  53. metadata +21 -5
  54. data/lib/faraday/upload_io.rb +0 -67
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pp'
4
+ module Faraday
5
+ module Logging
6
+ # Serves as an integration point to customize logging
7
+ class Formatter
8
+ extend Forwardable
9
+
10
+ DEFAULT_OPTIONS = { headers: true, bodies: false }.freeze
11
+
12
+ def initialize(logger:, options:)
13
+ @logger = logger
14
+ @filter = []
15
+ @options = DEFAULT_OPTIONS.merge(options)
16
+ end
17
+
18
+ def_delegators :@logger, :debug, :info, :warn, :error, :fatal
19
+
20
+ def request(env)
21
+ info('request') do
22
+ "#{env.method.upcase} #{apply_filters(env.url.to_s)}"
23
+ end
24
+ if log_headers?(:request)
25
+ debug('request') { apply_filters(dump_headers(env.request_headers)) }
26
+ end
27
+ return unless env[:body] && log_body?(:request)
28
+
29
+ debug('request') { apply_filters(dump_body(env[:body])) }
30
+ end
31
+
32
+ def response(env)
33
+ info('response') { "Status #{env.status}" }
34
+ if log_headers?(:response)
35
+ debug('response') do
36
+ apply_filters(dump_headers(env.response_headers))
37
+ end
38
+ end
39
+ return unless env[:body] && log_body?(:response)
40
+
41
+ debug('response') { apply_filters(dump_body(env[:body])) }
42
+ end
43
+
44
+ def filter(filter_word, filter_replacement)
45
+ @filter.push([filter_word, filter_replacement])
46
+ end
47
+
48
+ private
49
+
50
+ def dump_headers(headers)
51
+ headers.map { |k, v| "#{k}: #{v.inspect}" }.join("\n")
52
+ end
53
+
54
+ def dump_body(body)
55
+ if body.respond_to?(:to_str)
56
+ body.to_str
57
+ else
58
+ pretty_inspect(body)
59
+ end
60
+ end
61
+
62
+ def pretty_inspect(body)
63
+ body.pretty_inspect
64
+ end
65
+
66
+ def log_headers?(type)
67
+ case @options[:headers]
68
+ when Hash
69
+ @options[:headers][type]
70
+ else
71
+ @options[:headers]
72
+ end
73
+ end
74
+
75
+ def log_body?(type)
76
+ case @options[:bodies]
77
+ when Hash
78
+ @options[:bodies][type]
79
+ else
80
+ @options[:bodies]
81
+ end
82
+ end
83
+
84
+ def apply_filters(output)
85
+ @filter.each do |pattern, replacement|
86
+ output = output.to_s.gsub(pattern, replacement)
87
+ end
88
+ output
89
+ end
90
+ end
91
+ end
92
+ end
@@ -1,34 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Faraday
4
+ # Middleware is the basic base class of any Faraday middleware.
2
5
  class Middleware
3
6
  extend MiddlewareRegistry
4
-
5
- class << self
6
- attr_accessor :load_error
7
- private :load_error=
8
- end
9
-
10
- self.load_error = nil
11
-
12
- # Executes a block which should try to require and reference dependent libraries
13
- def self.dependency(lib = nil)
14
- lib ? require(lib) : yield
15
- rescue LoadError, NameError => error
16
- self.load_error = error
17
- end
18
-
19
- def self.new(*)
20
- raise "missing dependency for #{self}: #{load_error.message}" unless loaded?
21
- super
22
- end
23
-
24
- def self.loaded?
25
- load_error.nil?
26
- end
27
-
28
- def self.inherited(subclass)
29
- super
30
- subclass.send(:load_error=, self.load_error)
31
- end
7
+ extend DependencyLoader
32
8
 
33
9
  def initialize(app = nil)
34
10
  @app = app
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'monitor'
4
+
5
+ module Faraday
6
+ # Adds the ability for other modules to register and lookup
7
+ # middleware classes.
8
+ module MiddlewareRegistry
9
+ # Register middleware class(es) on the current module.
10
+ #
11
+ # @param autoload_path [String] Middleware autoload path
12
+ # @param mapping [Hash{
13
+ # Symbol => Module,
14
+ # Symbol => Array<Module, Symbol, String>,
15
+ # }] Middleware mapping from a lookup symbol to a reference to the
16
+ # middleware.
17
+ # Classes can be expressed as:
18
+ # - a fully qualified constant
19
+ # - a Symbol
20
+ # - a Proc that will be lazily called to return the former
21
+ # - an array is given, its first element is the constant or symbol,
22
+ # and its second is a file to `require`.
23
+ # @return [void]
24
+ #
25
+ # @example Lookup by a constant
26
+ #
27
+ # module Faraday
28
+ # class Whatever
29
+ # # Middleware looked up by :foo returns Faraday::Whatever::Foo.
30
+ # register_middleware foo: Foo
31
+ # end
32
+ # end
33
+ #
34
+ # @example Lookup by a symbol
35
+ #
36
+ # module Faraday
37
+ # class Whatever
38
+ # # Middleware looked up by :bar returns
39
+ # # Faraday::Whatever.const_get(:Bar)
40
+ # register_middleware bar: :Bar
41
+ # end
42
+ # end
43
+ #
44
+ # @example Lookup by a symbol and string in an array
45
+ #
46
+ # module Faraday
47
+ # class Whatever
48
+ # # Middleware looked up by :baz requires 'baz' and returns
49
+ # # Faraday::Whatever.const_get(:Baz)
50
+ # register_middleware baz: [:Baz, 'baz']
51
+ # end
52
+ # end
53
+ #
54
+ def register_middleware(autoload_path = nil, mapping = nil)
55
+ if mapping.nil?
56
+ mapping = autoload_path
57
+ autoload_path = nil
58
+ end
59
+ middleware_mutex do
60
+ @middleware_autoload_path = autoload_path if autoload_path
61
+ (@registered_middleware ||= {}).update(mapping)
62
+ end
63
+ end
64
+
65
+ # Unregister a previously registered middleware class.
66
+ #
67
+ # @param key [Symbol] key for the registered middleware.
68
+ def unregister_middleware(key)
69
+ @registered_middleware.delete(key)
70
+ end
71
+
72
+ # Lookup middleware class with a registered Symbol shortcut.
73
+ #
74
+ # @param key [Symbol] key for the registered middleware.
75
+ # @return [Class] a middleware Class.
76
+ # @raise [Faraday::Error] if given key is not registered
77
+ #
78
+ # @example
79
+ #
80
+ # module Faraday
81
+ # class Whatever
82
+ # register_middleware foo: Foo
83
+ # end
84
+ # end
85
+ #
86
+ # Faraday::Whatever.lookup_middleware(:foo)
87
+ # # => Faraday::Whatever::Foo
88
+ #
89
+ def lookup_middleware(key)
90
+ load_middleware(key) ||
91
+ raise(Faraday::Error, "#{key.inspect} is not registered on #{self}")
92
+ end
93
+
94
+ def middleware_mutex(&block)
95
+ @middleware_mutex ||= Monitor.new
96
+ @middleware_mutex.synchronize(&block)
97
+ end
98
+
99
+ def fetch_middleware(key)
100
+ defined?(@registered_middleware) && @registered_middleware[key]
101
+ end
102
+
103
+ def load_middleware(key)
104
+ value = fetch_middleware(key)
105
+ case value
106
+ when Module
107
+ value
108
+ when Symbol, String
109
+ middleware_mutex do
110
+ @registered_middleware[key] = const_get(value)
111
+ end
112
+ when Proc
113
+ middleware_mutex do
114
+ @registered_middleware[key] = value.call
115
+ end
116
+ when Array
117
+ middleware_mutex do
118
+ const, path = value
119
+ if (root = @middleware_autoload_path)
120
+ path = "#{root}/#{path}"
121
+ end
122
+ require(path)
123
+ @registered_middleware[key] = const
124
+ end
125
+ load_middleware(key)
126
+ end
127
+ end
128
+ end
129
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Faraday
2
4
  # Subclasses Struct with some special helpers for converting from a Hash to
3
5
  # a Struct.
@@ -10,6 +12,7 @@ module Faraday
10
12
  # Public
11
13
  def each
12
14
  return to_enum(:each) unless block_given?
15
+
13
16
  members.each do |key|
14
17
  yield(key.to_sym, send(key))
15
18
  end
@@ -27,7 +30,7 @@ module Faraday
27
30
  new_value = value
28
31
  end
29
32
 
30
- self.send("#{key}=", new_value) unless new_value.nil?
33
+ send("#{key}=", new_value) unless new_value.nil?
31
34
  end
32
35
  self
33
36
  end
@@ -47,10 +50,14 @@ module Faraday
47
50
  # Public
48
51
  def merge!(other)
49
52
  other.each do |key, other_value|
50
- self_value = self.send(key)
53
+ self_value = send(key)
51
54
  sub_options = self.class.options_for(key)
52
- new_value = (self_value && sub_options && other_value) ? self_value.merge(other_value) : other_value
53
- self.send("#{key}=", new_value) unless new_value.nil?
55
+ new_value = if self_value && sub_options && other_value
56
+ self_value.merge(other_value)
57
+ else
58
+ other_value
59
+ end
60
+ send("#{key}=", new_value) unless new_value.nil?
54
61
  end
55
62
  self
56
63
  end
@@ -69,10 +76,10 @@ module Faraday
69
76
  def fetch(key, *args)
70
77
  unless symbolized_key_set.include?(key.to_sym)
71
78
  key_setter = "#{key}="
72
- if args.size > 0
79
+ if !args.empty?
73
80
  send(key_setter, args.first)
74
81
  elsif block_given?
75
- send(key_setter, Proc.new.call(key))
82
+ send(key_setter, yield(key))
76
83
  else
77
84
  raise self.class.fetch_error_class, "key not found: #{key.inspect}"
78
85
  end
@@ -98,6 +105,7 @@ module Faraday
98
105
  # Public
99
106
  def each_key
100
107
  return to_enum(:each_key) unless block_given?
108
+
101
109
  keys.each do |key|
102
110
  yield(key)
103
111
  end
@@ -113,6 +121,7 @@ module Faraday
113
121
  # Public
114
122
  def each_value
115
123
  return to_enum(:each_value) unless block_given?
124
+
116
125
  values.each do |value|
117
126
  yield(value)
118
127
  end
@@ -142,9 +151,9 @@ module Faraday
142
151
  value = send(member)
143
152
  values << "#{member}=#{value.inspect}" if value
144
153
  end
145
- values = values.empty? ? ' (empty)' : (' ' << values.join(", "))
154
+ values = values.empty? ? '(empty)' : values.join(', ')
146
155
 
147
- %(#<#{self.class}#{values}>)
156
+ %(#<#{self.class} #{values}>)
148
157
  end
149
158
 
150
159
  # Internal
@@ -162,8 +171,12 @@ module Faraday
162
171
  @attribute_options ||= {}
163
172
  end
164
173
 
165
- def self.memoized(key)
166
- memoized_attributes[key.to_sym] = Proc.new
174
+ def self.memoized(key, &block)
175
+ unless block_given?
176
+ raise ArgumentError, '#memoized must be called with a block'
177
+ end
178
+
179
+ memoized_attributes[key.to_sym] = block
167
180
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
168
181
  def #{key}() self[:#{key}]; end
169
182
  RUBY
@@ -175,7 +188,7 @@ module Faraday
175
188
 
176
189
  def [](key)
177
190
  key = key.to_sym
178
- if method = self.class.memoized_attributes[key]
191
+ if (method = self.class.memoized_attributes[key])
179
192
  super(key) || (self[key] = instance_eval(&method))
180
193
  else
181
194
  super
@@ -183,7 +196,7 @@ module Faraday
183
196
  end
184
197
 
185
198
  def symbolized_key_set
186
- @symbolized_key_set ||= Set.new(keys.map { |k| k.to_sym })
199
+ @symbolized_key_set ||= Set.new(keys.map(&:to_sym))
187
200
  end
188
201
 
189
202
  def self.inherited(subclass)
@@ -194,180 +207,16 @@ module Faraday
194
207
 
195
208
  def self.fetch_error_class
196
209
  @fetch_error_class ||= if Object.const_defined?(:KeyError)
197
- ::KeyError
198
- else
199
- ::IndexError
200
- end
201
- end
202
- end
203
-
204
- class RequestOptions < Options.new(:params_encoder, :proxy, :bind,
205
- :timeout, :open_timeout, :write_timeout, :boundary, :oauth, :context)
206
-
207
- def []=(key, value)
208
- if key && key.to_sym == :proxy
209
- super(key, value ? ProxyOptions.from(value) : nil)
210
- else
211
- super(key, value)
212
- end
213
- end
214
- end
215
-
216
- class SSLOptions < Options.new(:verify, :ca_file, :ca_path, :verify_mode,
217
- :cert_store, :client_cert, :client_key, :certificate, :private_key, :verify_depth,
218
- :version, :min_version, :max_version)
219
-
220
- def verify?
221
- verify != false
222
- end
223
-
224
- def disable?
225
- !verify?
226
- end
227
- end
228
-
229
- class ProxyOptions < Options.new(:uri, :user, :password)
230
- extend Forwardable
231
- def_delegators :uri, :scheme, :scheme=, :host, :host=, :port, :port=, :path, :path=
232
-
233
- def self.from(value)
234
- case value
235
- when String
236
- value = {:uri => Utils.URI(value)}
237
- when URI
238
- value = {:uri => value}
239
- when Hash, Options
240
- if uri = value.delete(:uri)
241
- value[:uri] = Utils.URI(uri)
242
- end
243
- end
244
- super(value)
245
- end
246
-
247
- memoized(:user) { uri && uri.user && Utils.unescape(uri.user) }
248
- memoized(:password) { uri && uri.password && Utils.unescape(uri.password) }
249
- end
250
-
251
- class ConnectionOptions < Options.new(:request, :proxy, :ssl, :builder, :url,
252
- :parallel_manager, :params, :headers, :builder_class)
253
-
254
- options :request => RequestOptions, :ssl => SSLOptions
255
-
256
- memoized(:request) { self.class.options_for(:request).new }
257
-
258
- memoized(:ssl) { self.class.options_for(:ssl).new }
259
-
260
- memoized(:builder_class) { RackBuilder }
261
-
262
- def new_builder(block)
263
- builder_class.new(&block)
264
- end
265
- end
266
-
267
- class Env < Options.new(:method, :body, :url, :request, :request_headers,
268
- :ssl, :parallel_manager, :params, :response, :response_headers, :status,
269
- :reason_phrase)
270
-
271
- ContentLength = 'Content-Length'.freeze
272
- StatusesWithoutBody = Set.new [204, 304]
273
- SuccessfulStatuses = 200..299
274
-
275
- # A Set of HTTP verbs that typically send a body. If no body is set for
276
- # these requests, the Content-Length header is set to 0.
277
- MethodsWithBodies = Set.new [:post, :put, :patch, :options]
278
-
279
- options :request => RequestOptions,
280
- :request_headers => Utils::Headers, :response_headers => Utils::Headers
281
-
282
- extend Forwardable
283
-
284
- def_delegators :request, :params_encoder
285
-
286
- # Public
287
- def self.from(value)
288
- env = super(value)
289
- if value.respond_to?(:custom_members)
290
- env.custom_members.update(value.custom_members)
291
- end
292
- env
293
- end
294
-
295
- # Public
296
- def [](key)
297
- if in_member_set?(key)
298
- super(key)
299
- else
300
- custom_members[key]
301
- end
302
- end
303
-
304
- # Public
305
- def []=(key, value)
306
- if in_member_set?(key)
307
- super(key, value)
308
- else
309
- custom_members[key] = value
310
- end
311
- end
312
-
313
- # Public
314
- def success?
315
- SuccessfulStatuses.include?(status)
316
- end
317
-
318
- # Public
319
- def needs_body?
320
- !body && MethodsWithBodies.include?(method)
321
- end
322
-
323
- # Public
324
- def clear_body
325
- request_headers[ContentLength] = '0'
326
- self.body = ''
327
- end
328
-
329
- # Public
330
- def parse_body?
331
- !StatusesWithoutBody.include?(status)
332
- end
333
-
334
- # Public
335
- def parallel?
336
- !!parallel_manager
337
- end
338
-
339
- def inspect
340
- attrs = [nil]
341
- members.each do |mem|
342
- if value = send(mem)
343
- attrs << "@#{mem}=#{value.inspect}"
344
- end
345
- end
346
- if !custom_members.empty?
347
- attrs << "@custom=#{custom_members.inspect}"
348
- end
349
- %(#<#{self.class}#{attrs.join(" ")}>)
350
- end
351
-
352
- # Internal
353
- def custom_members
354
- @custom_members ||= {}
355
- end
356
-
357
- # Internal
358
- if members.first.is_a?(Symbol)
359
- def in_member_set?(key)
360
- self.class.member_set.include?(key.to_sym)
361
- end
362
- else
363
- def in_member_set?(key)
364
- self.class.member_set.include?(key.to_s)
365
- end
366
- end
367
-
368
- # Internal
369
- def self.member_set
370
- @member_set ||= Set.new(members)
210
+ ::KeyError
211
+ else
212
+ ::IndexError
213
+ end
371
214
  end
372
215
  end
373
216
  end
217
+
218
+ require 'faraday/options/request_options'
219
+ require 'faraday/options/ssl_options'
220
+ require 'faraday/options/proxy_options'
221
+ require 'faraday/options/connection_options'
222
+ require 'faraday/options/env'