faraday 0.16.2 → 0.17.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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.md +1 -1
  3. data/README.md +347 -18
  4. data/lib/faraday.rb +175 -93
  5. data/lib/faraday/adapter.rb +22 -36
  6. data/lib/faraday/adapter/em_http.rb +99 -142
  7. data/lib/faraday/adapter/em_http_ssl_patch.rb +17 -23
  8. data/lib/faraday/adapter/em_synchrony.rb +60 -104
  9. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +15 -18
  10. data/lib/faraday/adapter/excon.rb +55 -100
  11. data/lib/faraday/adapter/httpclient.rb +39 -61
  12. data/lib/faraday/adapter/net_http.rb +51 -104
  13. data/lib/faraday/adapter/net_http_persistent.rb +27 -48
  14. data/lib/faraday/adapter/patron.rb +35 -54
  15. data/lib/faraday/adapter/rack.rb +12 -28
  16. data/lib/faraday/adapter/test.rb +53 -86
  17. data/lib/faraday/adapter/typhoeus.rb +1 -4
  18. data/lib/faraday/autoload.rb +36 -47
  19. data/lib/faraday/connection.rb +179 -321
  20. data/lib/faraday/error.rb +32 -80
  21. data/lib/faraday/middleware.rb +28 -4
  22. data/lib/faraday/options.rb +186 -35
  23. data/lib/faraday/parameters.rb +197 -4
  24. data/lib/faraday/rack_builder.rb +56 -67
  25. data/lib/faraday/request.rb +36 -68
  26. data/lib/faraday/request/authorization.rb +30 -42
  27. data/lib/faraday/request/basic_authentication.rb +7 -14
  28. data/lib/faraday/request/instrumentation.rb +27 -45
  29. data/lib/faraday/request/multipart.rb +48 -79
  30. data/lib/faraday/request/retry.rb +170 -197
  31. data/lib/faraday/request/token_authentication.rb +10 -15
  32. data/lib/faraday/request/url_encoded.rb +23 -41
  33. data/lib/faraday/response.rb +16 -23
  34. data/lib/faraday/response/logger.rb +69 -22
  35. data/lib/faraday/response/raise_error.rb +14 -36
  36. data/lib/faraday/upload_io.rb +67 -0
  37. data/lib/faraday/utils.rb +245 -28
  38. metadata +5 -22
  39. data/lib/faraday/adapter_registry.rb +0 -28
  40. data/lib/faraday/dependency_loader.rb +0 -37
  41. data/lib/faraday/deprecated_class.rb +0 -28
  42. data/lib/faraday/encoders/flat_params_encoder.rb +0 -94
  43. data/lib/faraday/encoders/nested_params_encoder.rb +0 -171
  44. data/lib/faraday/file_part.rb +0 -128
  45. data/lib/faraday/logging/formatter.rb +0 -92
  46. data/lib/faraday/middleware_registry.rb +0 -129
  47. data/lib/faraday/options/connection_options.rb +0 -22
  48. data/lib/faraday/options/env.rb +0 -181
  49. data/lib/faraday/options/proxy_options.rb +0 -28
  50. data/lib/faraday/options/request_options.rb +0 -21
  51. data/lib/faraday/options/ssl_options.rb +0 -59
  52. data/lib/faraday/param_part.rb +0 -53
  53. data/lib/faraday/utils/headers.rb +0 -139
  54. data/lib/faraday/utils/params_hash.rb +0 -61
  55. data/spec/external_adapters/faraday_specs_setup.rb +0 -14
@@ -1,5 +1,198 @@
1
- # frozen_string_literal: true
1
+ require "forwardable"
2
2
 
3
- require 'forwardable'
4
- require 'faraday/encoders/nested_params_encoder'
5
- require 'faraday/encoders/flat_params_encoder'
3
+ module Faraday
4
+ module NestedParamsEncoder
5
+ class << self
6
+ extend Forwardable
7
+ def_delegators :'Faraday::Utils', :escape, :unescape
8
+ end
9
+
10
+ def self.encode(params)
11
+ return nil if params == nil
12
+
13
+ if !params.is_a?(Array)
14
+ if !params.respond_to?(:to_hash)
15
+ raise TypeError,
16
+ "Can't convert #{params.class} into Hash."
17
+ end
18
+ params = params.to_hash
19
+ params = params.map do |key, value|
20
+ key = key.to_s if key.kind_of?(Symbol)
21
+ [key, value]
22
+ end
23
+ # Useful default for OAuth and caching.
24
+ # Only to be used for non-Array inputs. Arrays should preserve order.
25
+ params.sort!
26
+ end
27
+
28
+ # Helper lambda
29
+ to_query = lambda do |parent, value|
30
+ if value.is_a?(Hash)
31
+ value = value.map do |key, val|
32
+ key = escape(key)
33
+ [key, val]
34
+ end
35
+ value.sort!
36
+ buffer = ""
37
+ value.each do |key, val|
38
+ new_parent = "#{parent}%5B#{key}%5D"
39
+ buffer << "#{to_query.call(new_parent, val)}&"
40
+ end
41
+ return buffer.chop
42
+ elsif value.is_a?(Array)
43
+ new_parent = "#{parent}%5B%5D"
44
+ return new_parent if value.empty?
45
+ buffer = ""
46
+ value.each_with_index do |val, i|
47
+ buffer << "#{to_query.call(new_parent, val)}&"
48
+ end
49
+ return buffer.chop
50
+ elsif value.nil?
51
+ return parent
52
+ else
53
+ encoded_value = escape(value)
54
+ return "#{parent}=#{encoded_value}"
55
+ end
56
+ end
57
+
58
+ # The params have form [['key1', 'value1'], ['key2', 'value2']].
59
+ buffer = ''
60
+ params.each do |parent, value|
61
+ encoded_parent = escape(parent)
62
+ buffer << "#{to_query.call(encoded_parent, value)}&"
63
+ end
64
+ return buffer.chop
65
+ end
66
+
67
+ def self.decode(query)
68
+ return nil if query == nil
69
+
70
+ params = {}
71
+ query.split("&").each do |pair|
72
+ next if pair.empty?
73
+ key, value = pair.split("=", 2)
74
+ key = unescape(key)
75
+ value = unescape(value.gsub(/\+/, ' ')) if value
76
+
77
+ subkeys = key.scan(/[^\[\]]+(?:\]?\[\])?/)
78
+ context = params
79
+ subkeys.each_with_index do |subkey, i|
80
+ is_array = subkey =~ /[\[\]]+\Z/
81
+ subkey = $` if is_array
82
+ last_subkey = i == subkeys.length - 1
83
+
84
+ if !last_subkey || is_array
85
+ value_type = is_array ? Array : Hash
86
+ if context[subkey] && !context[subkey].is_a?(value_type)
87
+ raise TypeError, "expected %s (got %s) for param `%s'" % [
88
+ value_type.name,
89
+ context[subkey].class.name,
90
+ subkey
91
+ ]
92
+ end
93
+ context = (context[subkey] ||= value_type.new)
94
+ end
95
+
96
+ if context.is_a?(Array) && !is_array
97
+ if !context.last.is_a?(Hash) || context.last.has_key?(subkey)
98
+ context << {}
99
+ end
100
+ context = context.last
101
+ end
102
+
103
+ if last_subkey
104
+ if is_array
105
+ context << value
106
+ else
107
+ context[subkey] = value
108
+ end
109
+ end
110
+ end
111
+ end
112
+
113
+ dehash(params, 0)
114
+ end
115
+
116
+ # Internal: convert a nested hash with purely numeric keys into an array.
117
+ # FIXME: this is not compatible with Rack::Utils.parse_nested_query
118
+ def self.dehash(hash, depth)
119
+ hash.each do |key, value|
120
+ hash[key] = dehash(value, depth + 1) if value.kind_of?(Hash)
121
+ end
122
+
123
+ if depth > 0 && !hash.empty? && hash.keys.all? { |k| k =~ /^\d+$/ }
124
+ hash.keys.sort.inject([]) { |all, key| all << hash[key] }
125
+ else
126
+ hash
127
+ end
128
+ end
129
+ end
130
+
131
+ module FlatParamsEncoder
132
+ class << self
133
+ extend Forwardable
134
+ def_delegators :'Faraday::Utils', :escape, :unescape
135
+ end
136
+
137
+ def self.encode(params)
138
+ return nil if params == nil
139
+
140
+ if !params.is_a?(Array)
141
+ if !params.respond_to?(:to_hash)
142
+ raise TypeError,
143
+ "Can't convert #{params.class} into Hash."
144
+ end
145
+ params = params.to_hash
146
+ params = params.map do |key, value|
147
+ key = key.to_s if key.kind_of?(Symbol)
148
+ [key, value]
149
+ end
150
+ # Useful default for OAuth and caching.
151
+ # Only to be used for non-Array inputs. Arrays should preserve order.
152
+ params.sort!
153
+ end
154
+
155
+ # The params have form [['key1', 'value1'], ['key2', 'value2']].
156
+ buffer = ''
157
+ params.each do |key, value|
158
+ encoded_key = escape(key)
159
+ value = value.to_s if value == true || value == false
160
+ if value == nil
161
+ buffer << "#{encoded_key}&"
162
+ elsif value.kind_of?(Array)
163
+ value.each do |sub_value|
164
+ encoded_value = escape(sub_value)
165
+ buffer << "#{encoded_key}=#{encoded_value}&"
166
+ end
167
+ else
168
+ encoded_value = escape(value)
169
+ buffer << "#{encoded_key}=#{encoded_value}&"
170
+ end
171
+ end
172
+ return buffer.chop
173
+ end
174
+
175
+ def self.decode(query)
176
+ empty_accumulator = {}
177
+ return nil if query == nil
178
+ split_query = (query.split('&').map do |pair|
179
+ pair.split('=', 2) if pair && !pair.empty?
180
+ end).compact
181
+ return split_query.inject(empty_accumulator.dup) do |accu, pair|
182
+ pair[0] = unescape(pair[0])
183
+ pair[1] = true if pair[1].nil?
184
+ if pair[1].respond_to?(:to_str)
185
+ pair[1] = unescape(pair[1].to_str.gsub(/\+/, " "))
186
+ end
187
+ if accu[pair[0]].kind_of?(Array)
188
+ accu[pair[0]] << pair[1]
189
+ elsif accu[pair[0]]
190
+ accu[pair[0]] = [accu[pair[0]], pair[1]]
191
+ else
192
+ accu[pair[0]] = pair[1]
193
+ end
194
+ accu
195
+ end
196
+ end
197
+ end
198
+ end
@@ -1,20 +1,12 @@
1
- # frozen_string_literal: true
2
-
3
- require 'faraday/adapter_registry'
4
-
5
1
  module Faraday
6
2
  # A Builder that processes requests into responses by passing through an inner
7
3
  # middleware stack (heavily inspired by Rack).
8
4
  #
9
- # @example
10
- # Faraday::Connection.new(url: 'http://sushi.com') do |builder|
5
+ # Faraday::Connection.new(:url => 'http://sushi.com') do |builder|
11
6
  # builder.request :url_encoded # Faraday::Request::UrlEncoded
12
7
  # builder.adapter :net_http # Faraday::Adapter::NetHttp
13
8
  # end
14
9
  class RackBuilder
15
- # Used to detect missing arguments
16
- NO_ARGUMENT = Object.new
17
-
18
10
  attr_accessor :handlers
19
11
 
20
12
  # Error raised when trying to modify the stack after calling `lock!`
@@ -23,28 +15,28 @@ module Faraday
23
15
  # borrowed from ActiveSupport::Dependencies::Reference &
24
16
  # ActionDispatch::MiddlewareStack::Middleware
25
17
  class Handler
26
- REGISTRY = Faraday::AdapterRegistry.new
18
+ @@constants_mutex = Mutex.new
19
+ @@constants = Hash.new { |h, k|
20
+ value = k.respond_to?(:constantize) ? k.constantize : Object.const_get(k)
21
+ @@constants_mutex.synchronize { h[k] = value }
22
+ }
27
23
 
28
24
  attr_reader :name
29
25
 
30
26
  def initialize(klass, *args, &block)
31
27
  @name = klass.to_s
32
- REGISTRY.set(klass) if klass.respond_to?(:name)
33
- @args = args
34
- @block = block
35
- end
36
-
37
- def klass
38
- REGISTRY.get(@name)
28
+ if klass.respond_to?(:name)
29
+ @@constants_mutex.synchronize { @@constants[@name] = klass }
30
+ end
31
+ @args, @block = args, block
39
32
  end
40
33
 
41
- def inspect
42
- @name
43
- end
34
+ def klass() @@constants[@name] end
35
+ def inspect() @name end
44
36
 
45
37
  def ==(other)
46
38
  if other.is_a? Handler
47
- name == other.name
39
+ self.name == other.name
48
40
  elsif other.respond_to? :name
49
41
  klass == other
50
42
  else
@@ -52,19 +44,18 @@ module Faraday
52
44
  end
53
45
  end
54
46
 
55
- def build(app = nil)
47
+ def build(app)
56
48
  klass.new(app, *@args, &@block)
57
49
  end
58
50
  end
59
51
 
60
- def initialize(handlers = [], adapter = nil, &block)
61
- @adapter = adapter
52
+ def initialize(handlers = [])
62
53
  @handlers = handlers
63
54
  if block_given?
64
- build(&block)
55
+ build(&Proc.new)
65
56
  elsif @handlers.empty?
66
57
  # default stack, if nothing else is configured
67
- request :url_encoded
58
+ self.request :url_encoded
68
59
  self.adapter Faraday.default_adapter
69
60
  end
70
61
  end
@@ -73,14 +64,13 @@ module Faraday
73
64
  raise_if_locked
74
65
  @handlers.clear unless options[:keep]
75
66
  yield(self) if block_given?
76
- adapter(Faraday.default_adapter) unless @adapter
77
67
  end
78
68
 
79
69
  def [](idx)
80
70
  @handlers[idx]
81
71
  end
82
72
 
83
- # Locks the middleware stack to ensure no further modifications are made.
73
+ # Locks the middleware stack to ensure no further modifications are possible.
84
74
  def lock!
85
75
  @handlers.freeze
86
76
  end
@@ -94,7 +84,7 @@ module Faraday
94
84
  use_symbol(Faraday::Middleware, klass, *args, &block)
95
85
  else
96
86
  raise_if_locked
97
- raise_if_adapter(klass)
87
+ warn_middleware_after_adapter if adapter_set?
98
88
  @handlers << self.class::Handler.new(klass, *args, &block)
99
89
  end
100
90
  end
@@ -107,11 +97,8 @@ module Faraday
107
97
  use_symbol(Faraday::Response, key, *args, &block)
108
98
  end
109
99
 
110
- def adapter(klass = NO_ARGUMENT, *args, &block)
111
- return @adapter if klass == NO_ARGUMENT
112
-
113
- klass = Faraday::Adapter.lookup_middleware(klass) if klass.is_a?(Symbol)
114
- @adapter = self.class::Handler.new(klass, *args, &block)
100
+ def adapter(key, *args, &block)
101
+ use_symbol(Faraday::Adapter, key, *args, &block)
115
102
  end
116
103
 
117
104
  ## methods to push onto the various positions in the stack:
@@ -119,11 +106,12 @@ module Faraday
119
106
  def insert(index, *args, &block)
120
107
  raise_if_locked
121
108
  index = assert_index(index)
109
+ warn_middleware_after_adapter if inserting_after_adapter?(index)
122
110
  handler = self.class::Handler.new(*args, &block)
123
111
  @handlers.insert(index, handler)
124
112
  end
125
113
 
126
- alias insert_before insert
114
+ alias_method :insert_before, :insert
127
115
 
128
116
  def insert_after(index, *args, &block)
129
117
  index = assert_index(index)
@@ -145,11 +133,13 @@ module Faraday
145
133
  # Processes a Request into a Response by passing it through this Builder's
146
134
  # middleware stack.
147
135
  #
148
- # @param connection [Faraday::Connection]
149
- # @param request [Faraday::Request]
136
+ # connection - Faraday::Connection
137
+ # request - Faraday::Request
150
138
  #
151
- # @return [Faraday::Response]
139
+ # Returns a Faraday::Response.
152
140
  def build_response(connection, request)
141
+ warn 'WARNING: No adapter was configured for this request' unless adapter_set?
142
+
153
143
  app.call(build_env(connection, request))
154
144
  end
155
145
 
@@ -163,26 +153,26 @@ module Faraday
163
153
  def app
164
154
  @app ||= begin
165
155
  lock!
166
- to_app
156
+ to_app(lambda { |env|
157
+ response = Response.new
158
+ env.response = response
159
+ response.finish(env) unless env.parallel?
160
+ response
161
+ })
167
162
  end
168
163
  end
169
164
 
170
- def to_app
165
+ def to_app(inner_app)
171
166
  # last added handler is the deepest and thus closest to the inner app
172
- # adapter is always the last one
173
- @handlers.reverse.inject(@adapter.build) do |app, handler|
174
- handler.build(app)
175
- end
167
+ @handlers.reverse.inject(inner_app) { |app, handler| handler.build(app) }
176
168
  end
177
169
 
178
170
  def ==(other)
179
- other.is_a?(self.class) &&
180
- @handlers == other.handlers &&
181
- @adapter == other.adapter
171
+ other.is_a?(self.class) && @handlers == other.handlers
182
172
  end
183
173
 
184
174
  def dup
185
- self.class.new(@handlers.dup, @adapter.dup)
175
+ self.class.new(@handlers.dup)
186
176
  end
187
177
 
188
178
  # ENV Keys
@@ -202,36 +192,36 @@ module Faraday
202
192
  # :password - Proxy server password
203
193
  # :ssl - Hash of options for configuring SSL requests.
204
194
  def build_env(connection, request)
205
- exclusive_url = connection.build_exclusive_url(
206
- request.path, request.params,
207
- request.options.params_encoder
208
- )
209
-
210
- Env.new(request.method, request.body, exclusive_url,
211
- request.options, request.headers, connection.ssl,
212
- connection.parallel_manager)
195
+ Env.new(request.method, request.body,
196
+ connection.build_exclusive_url(request.path, request.params, request.options.params_encoder),
197
+ request.options, request.headers, connection.ssl,
198
+ connection.parallel_manager)
213
199
  end
214
200
 
215
201
  private
216
202
 
217
- LOCK_ERR = "can't modify middleware stack after making a request"
218
-
219
203
  def raise_if_locked
220
- raise StackLocked, LOCK_ERR if locked?
204
+ raise StackLocked, "can't modify middleware stack after making a request" if locked?
221
205
  end
222
206
 
223
- def raise_if_adapter(klass)
224
- return unless is_adapter?(klass)
225
-
226
- raise 'Adapter should be set using the `adapter` method, not `use`'
207
+ def warn_middleware_after_adapter
208
+ warn "WARNING: Unexpected middleware set after the adapter. " \
209
+ "This won't be supported from Faraday 1.0."
227
210
  end
228
211
 
229
212
  def adapter_set?
230
- !@adapter.nil?
213
+ @handlers.any? { |handler| is_adapter?(handler) }
231
214
  end
232
215
 
233
- def is_adapter?(klass) # rubocop:disable Naming/PredicateName
234
- klass.ancestors.include?(Faraday::Adapter)
216
+ def inserting_after_adapter?(index)
217
+ adapter_index = @handlers.find_index { |handler| is_adapter?(handler) }
218
+ return false if adapter_index.nil?
219
+
220
+ index > adapter_index
221
+ end
222
+
223
+ def is_adapter?(handler)
224
+ handler.klass.ancestors.include? Faraday::Adapter
235
225
  end
236
226
 
237
227
  def use_symbol(mod, key, *args, &block)
@@ -241,7 +231,6 @@ module Faraday
241
231
  def assert_index(index)
242
232
  idx = index.is_a?(Integer) ? index : @handlers.index(index)
243
233
  raise "No such handler: #{index.inspect}" unless idx
244
-
245
234
  idx
246
235
  end
247
236
  end