faraday 0.15.4 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
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'