faraday 0.17.6 → 1.0.1

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 (133) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +52 -8
  3. data/LICENSE.md +1 -1
  4. data/README.md +18 -358
  5. data/Rakefile +1 -7
  6. data/examples/client_spec.rb +65 -0
  7. data/examples/client_test.rb +79 -0
  8. data/lib/faraday/adapter/em_http.rb +142 -99
  9. data/lib/faraday/adapter/em_http_ssl_patch.rb +24 -18
  10. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +18 -15
  11. data/lib/faraday/adapter/em_synchrony.rb +104 -60
  12. data/lib/faraday/adapter/excon.rb +98 -56
  13. data/lib/faraday/adapter/httpclient.rb +83 -59
  14. data/lib/faraday/adapter/net_http.rb +129 -63
  15. data/lib/faraday/adapter/net_http_persistent.rb +50 -27
  16. data/lib/faraday/adapter/patron.rb +80 -43
  17. data/lib/faraday/adapter/rack.rb +30 -13
  18. data/lib/faraday/adapter/test.rb +86 -53
  19. data/lib/faraday/adapter/typhoeus.rb +4 -1
  20. data/lib/faraday/adapter.rb +82 -22
  21. data/lib/faraday/adapter_registry.rb +30 -0
  22. data/lib/faraday/autoload.rb +47 -36
  23. data/lib/faraday/connection.rb +312 -182
  24. data/lib/faraday/dependency_loader.rb +37 -0
  25. data/lib/faraday/encoders/flat_params_encoder.rb +98 -0
  26. data/lib/faraday/encoders/nested_params_encoder.rb +171 -0
  27. data/lib/faraday/error.rb +9 -35
  28. data/lib/faraday/file_part.rb +128 -0
  29. data/lib/faraday/logging/formatter.rb +105 -0
  30. data/lib/faraday/middleware.rb +12 -28
  31. data/lib/faraday/middleware_registry.rb +129 -0
  32. data/lib/faraday/options/connection_options.rb +22 -0
  33. data/lib/faraday/options/env.rb +181 -0
  34. data/lib/faraday/options/proxy_options.rb +28 -0
  35. data/lib/faraday/options/request_options.rb +22 -0
  36. data/lib/faraday/options/ssl_options.rb +59 -0
  37. data/lib/faraday/options.rb +32 -183
  38. data/lib/faraday/param_part.rb +53 -0
  39. data/lib/faraday/parameters.rb +4 -197
  40. data/lib/faraday/rack_builder.rb +66 -55
  41. data/lib/faraday/request/authorization.rb +44 -30
  42. data/lib/faraday/request/basic_authentication.rb +14 -7
  43. data/lib/faraday/request/instrumentation.rb +45 -27
  44. data/lib/faraday/request/multipart.rb +79 -48
  45. data/lib/faraday/request/retry.rb +197 -171
  46. data/lib/faraday/request/token_authentication.rb +15 -10
  47. data/lib/faraday/request/url_encoded.rb +43 -23
  48. data/lib/faraday/request.rb +68 -38
  49. data/lib/faraday/response/logger.rb +22 -69
  50. data/lib/faraday/response/raise_error.rb +38 -18
  51. data/lib/faraday/response.rb +24 -14
  52. data/lib/faraday/utils/headers.rb +139 -0
  53. data/lib/faraday/utils/params_hash.rb +61 -0
  54. data/lib/faraday/utils.rb +36 -245
  55. data/lib/faraday.rb +94 -175
  56. data/spec/external_adapters/faraday_specs_setup.rb +14 -0
  57. data/spec/faraday/adapter/em_http_spec.rb +47 -0
  58. data/spec/faraday/adapter/em_synchrony_spec.rb +16 -0
  59. data/spec/faraday/adapter/excon_spec.rb +49 -0
  60. data/spec/faraday/adapter/httpclient_spec.rb +73 -0
  61. data/spec/faraday/adapter/net_http_persistent_spec.rb +57 -0
  62. data/spec/faraday/adapter/net_http_spec.rb +64 -0
  63. data/spec/faraday/adapter/patron_spec.rb +18 -0
  64. data/spec/faraday/adapter/rack_spec.rb +8 -0
  65. data/spec/faraday/adapter/typhoeus_spec.rb +7 -0
  66. data/spec/faraday/adapter_registry_spec.rb +28 -0
  67. data/spec/faraday/adapter_spec.rb +55 -0
  68. data/spec/faraday/composite_read_io_spec.rb +80 -0
  69. data/spec/faraday/connection_spec.rb +691 -0
  70. data/spec/faraday/error_spec.rb +0 -57
  71. data/spec/faraday/middleware_spec.rb +26 -0
  72. data/spec/faraday/options/env_spec.rb +70 -0
  73. data/spec/faraday/options/options_spec.rb +297 -0
  74. data/spec/faraday/options/proxy_options_spec.rb +37 -0
  75. data/spec/faraday/options/request_options_spec.rb +19 -0
  76. data/spec/faraday/params_encoders/flat_spec.rb +34 -0
  77. data/spec/faraday/params_encoders/nested_spec.rb +134 -0
  78. data/spec/faraday/rack_builder_spec.rb +196 -0
  79. data/spec/faraday/request/authorization_spec.rb +88 -0
  80. data/spec/faraday/request/instrumentation_spec.rb +76 -0
  81. data/spec/faraday/request/multipart_spec.rb +274 -0
  82. data/spec/faraday/request/retry_spec.rb +242 -0
  83. data/spec/faraday/request/url_encoded_spec.rb +83 -0
  84. data/spec/faraday/request_spec.rb +109 -0
  85. data/spec/faraday/response/logger_spec.rb +220 -0
  86. data/spec/faraday/response/middleware_spec.rb +68 -0
  87. data/spec/faraday/response/raise_error_spec.rb +15 -15
  88. data/spec/faraday/response_spec.rb +75 -0
  89. data/spec/faraday/utils/headers_spec.rb +82 -0
  90. data/spec/faraday/utils_spec.rb +56 -0
  91. data/spec/faraday_spec.rb +37 -0
  92. data/spec/spec_helper.rb +63 -36
  93. data/spec/support/disabling_stub.rb +14 -0
  94. data/spec/support/fake_safe_buffer.rb +15 -0
  95. data/spec/support/helper_methods.rb +133 -0
  96. data/spec/support/shared_examples/adapter.rb +104 -0
  97. data/spec/support/shared_examples/params_encoder.rb +18 -0
  98. data/spec/support/shared_examples/request_method.rb +234 -0
  99. data/spec/support/streaming_response_checker.rb +35 -0
  100. data/spec/support/webmock_rack_app.rb +68 -0
  101. metadata +66 -38
  102. data/lib/faraday/deprecate.rb +0 -109
  103. data/lib/faraday/upload_io.rb +0 -77
  104. data/spec/faraday/deprecate_spec.rb +0 -147
  105. data/test/adapters/default_test.rb +0 -14
  106. data/test/adapters/em_http_test.rb +0 -30
  107. data/test/adapters/em_synchrony_test.rb +0 -32
  108. data/test/adapters/excon_test.rb +0 -30
  109. data/test/adapters/httpclient_test.rb +0 -34
  110. data/test/adapters/integration.rb +0 -263
  111. data/test/adapters/logger_test.rb +0 -136
  112. data/test/adapters/net_http_persistent_test.rb +0 -114
  113. data/test/adapters/net_http_test.rb +0 -79
  114. data/test/adapters/patron_test.rb +0 -40
  115. data/test/adapters/rack_test.rb +0 -38
  116. data/test/adapters/test_middleware_test.rb +0 -157
  117. data/test/adapters/typhoeus_test.rb +0 -38
  118. data/test/authentication_middleware_test.rb +0 -65
  119. data/test/composite_read_io_test.rb +0 -109
  120. data/test/connection_test.rb +0 -738
  121. data/test/env_test.rb +0 -268
  122. data/test/helper.rb +0 -75
  123. data/test/live_server.rb +0 -67
  124. data/test/middleware/instrumentation_test.rb +0 -88
  125. data/test/middleware/retry_test.rb +0 -282
  126. data/test/middleware_stack_test.rb +0 -260
  127. data/test/multibyte.txt +0 -1
  128. data/test/options_test.rb +0 -333
  129. data/test/parameters_test.rb +0 -157
  130. data/test/request_middleware_test.rb +0 -126
  131. data/test/response_middleware_test.rb +0 -72
  132. data/test/strawberry.rb +0 -2
  133. data/test/utils_test.rb +0 -98
@@ -1,12 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday/adapter_registry'
4
+
1
5
  module Faraday
2
6
  # A Builder that processes requests into responses by passing through an inner
3
7
  # middleware stack (heavily inspired by Rack).
4
8
  #
5
- # Faraday::Connection.new(:url => 'http://sushi.com') do |builder|
9
+ # @example
10
+ # Faraday::Connection.new(url: 'http://sushi.com') do |builder|
6
11
  # builder.request :url_encoded # Faraday::Request::UrlEncoded
7
12
  # builder.adapter :net_http # Faraday::Adapter::NetHttp
8
13
  # end
9
14
  class RackBuilder
15
+ # Used to detect missing arguments
16
+ NO_ARGUMENT = Object.new
17
+
10
18
  attr_accessor :handlers
11
19
 
12
20
  # Error raised when trying to modify the stack after calling `lock!`
@@ -15,28 +23,28 @@ module Faraday
15
23
  # borrowed from ActiveSupport::Dependencies::Reference &
16
24
  # ActionDispatch::MiddlewareStack::Middleware
17
25
  class Handler
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
- }
26
+ REGISTRY = Faraday::AdapterRegistry.new
23
27
 
24
28
  attr_reader :name
25
29
 
26
30
  def initialize(klass, *args, &block)
27
31
  @name = klass.to_s
28
- if klass.respond_to?(:name)
29
- @@constants_mutex.synchronize { @@constants[@name] = klass }
30
- end
31
- @args, @block = args, block
32
+ REGISTRY.set(klass) if klass.respond_to?(:name)
33
+ @args = args
34
+ @block = block
32
35
  end
33
36
 
34
- def klass() @@constants[@name] end
35
- def inspect() @name end
37
+ def klass
38
+ REGISTRY.get(@name)
39
+ end
40
+
41
+ def inspect
42
+ @name
43
+ end
36
44
 
37
45
  def ==(other)
38
46
  if other.is_a? Handler
39
- self.name == other.name
47
+ name == other.name
40
48
  elsif other.respond_to? :name
41
49
  klass == other
42
50
  else
@@ -44,18 +52,19 @@ module Faraday
44
52
  end
45
53
  end
46
54
 
47
- def build(app)
55
+ def build(app = nil)
48
56
  klass.new(app, *@args, &@block)
49
57
  end
50
58
  end
51
59
 
52
- def initialize(handlers = [], &block)
60
+ def initialize(handlers = [], adapter = nil, &block)
61
+ @adapter = adapter
53
62
  @handlers = handlers
54
63
  if block_given?
55
64
  build(&block)
56
65
  elsif @handlers.empty?
57
66
  # default stack, if nothing else is configured
58
- self.request :url_encoded
67
+ request :url_encoded
59
68
  self.adapter Faraday.default_adapter
60
69
  end
61
70
  end
@@ -64,13 +73,14 @@ module Faraday
64
73
  raise_if_locked
65
74
  @handlers.clear unless options[:keep]
66
75
  yield(self) if block_given?
76
+ adapter(Faraday.default_adapter) unless @adapter
67
77
  end
68
78
 
69
79
  def [](idx)
70
80
  @handlers[idx]
71
81
  end
72
82
 
73
- # Locks the middleware stack to ensure no further modifications are possible.
83
+ # Locks the middleware stack to ensure no further modifications are made.
74
84
  def lock!
75
85
  @handlers.freeze
76
86
  end
@@ -84,7 +94,7 @@ module Faraday
84
94
  use_symbol(Faraday::Middleware, klass, *args, &block)
85
95
  else
86
96
  raise_if_locked
87
- warn_middleware_after_adapter if adapter_set?
97
+ raise_if_adapter(klass)
88
98
  @handlers << self.class::Handler.new(klass, *args, &block)
89
99
  end
90
100
  end
@@ -97,8 +107,11 @@ module Faraday
97
107
  use_symbol(Faraday::Response, key, *args, &block)
98
108
  end
99
109
 
100
- def adapter(key, *args, &block)
101
- use_symbol(Faraday::Adapter, key, *args, &block)
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)
102
115
  end
103
116
 
104
117
  ## methods to push onto the various positions in the stack:
@@ -106,12 +119,11 @@ module Faraday
106
119
  def insert(index, *args, &block)
107
120
  raise_if_locked
108
121
  index = assert_index(index)
109
- warn_middleware_after_adapter if inserting_after_adapter?(index)
110
122
  handler = self.class::Handler.new(*args, &block)
111
123
  @handlers.insert(index, handler)
112
124
  end
113
125
 
114
- alias_method :insert_before, :insert
126
+ alias insert_before insert
115
127
 
116
128
  def insert_after(index, *args, &block)
117
129
  index = assert_index(index)
@@ -133,13 +145,11 @@ module Faraday
133
145
  # Processes a Request into a Response by passing it through this Builder's
134
146
  # middleware stack.
135
147
  #
136
- # connection - Faraday::Connection
137
- # request - Faraday::Request
148
+ # @param connection [Faraday::Connection]
149
+ # @param request [Faraday::Request]
138
150
  #
139
- # Returns a Faraday::Response.
151
+ # @return [Faraday::Response]
140
152
  def build_response(connection, request)
141
- warn 'WARNING: No adapter was configured for this request' unless adapter_set?
142
-
143
153
  app.call(build_env(connection, request))
144
154
  end
145
155
 
@@ -153,26 +163,26 @@ module Faraday
153
163
  def app
154
164
  @app ||= begin
155
165
  lock!
156
- to_app(lambda { |env|
157
- response = Response.new
158
- env.response = response
159
- response.finish(env) unless env.parallel?
160
- response
161
- })
166
+ to_app
162
167
  end
163
168
  end
164
169
 
165
- def to_app(inner_app)
170
+ def to_app
166
171
  # last added handler is the deepest and thus closest to the inner app
167
- @handlers.reverse.inject(inner_app) { |app, handler| handler.build(app) }
172
+ # adapter is always the last one
173
+ @handlers.reverse.inject(@adapter.build) do |app, handler|
174
+ handler.build(app)
175
+ end
168
176
  end
169
177
 
170
178
  def ==(other)
171
- other.is_a?(self.class) && @handlers == other.handlers
179
+ other.is_a?(self.class) &&
180
+ @handlers == other.handlers &&
181
+ @adapter == other.adapter
172
182
  end
173
183
 
174
184
  def dup
175
- self.class.new(@handlers.dup)
185
+ self.class.new(@handlers.dup, @adapter.dup)
176
186
  end
177
187
 
178
188
  # ENV Keys
@@ -192,36 +202,36 @@ module Faraday
192
202
  # :password - Proxy server password
193
203
  # :ssl - Hash of options for configuring SSL requests.
194
204
  def build_env(connection, request)
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)
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)
199
213
  end
200
214
 
201
215
  private
202
216
 
217
+ LOCK_ERR = "can't modify middleware stack after making a request"
218
+
203
219
  def raise_if_locked
204
- raise StackLocked, "can't modify middleware stack after making a request" if locked?
220
+ raise StackLocked, LOCK_ERR if locked?
205
221
  end
206
222
 
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."
210
- end
223
+ def raise_if_adapter(klass)
224
+ return unless is_adapter?(klass)
211
225
 
212
- def adapter_set?
213
- @handlers.any? { |handler| is_adapter?(handler) }
226
+ raise 'Adapter should be set using the `adapter` method, not `use`'
214
227
  end
215
228
 
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
229
+ def adapter_set?
230
+ !@adapter.nil?
221
231
  end
222
232
 
223
- def is_adapter?(handler)
224
- handler.klass.ancestors.include? Faraday::Adapter
233
+ def is_adapter?(klass) # rubocop:disable Naming/PredicateName
234
+ klass.ancestors.include?(Faraday::Adapter)
225
235
  end
226
236
 
227
237
  def use_symbol(mod, key, *args, &block)
@@ -231,6 +241,7 @@ module Faraday
231
241
  def assert_index(index)
232
242
  idx = index.is_a?(Integer) ? index : @handlers.index(index)
233
243
  raise "No such handler: #{index.inspect}" unless idx
244
+
234
245
  idx
235
246
  end
236
247
  end
@@ -1,41 +1,55 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Faraday
2
- class Request::Authorization < Faraday::Middleware
3
- KEY = "Authorization".freeze unless defined? KEY
4
+ class Request
5
+ # Request middleware for the Authorization HTTP header
6
+ class Authorization < Faraday::Middleware
7
+ unless defined?(::Faraday::Request::Authorization::KEY)
8
+ KEY = 'Authorization'
9
+ end
4
10
 
5
- # Public
6
- def self.header(type, token)
7
- case token
8
- when String, Symbol
9
- "#{type} #{token}"
10
- when Hash
11
- build_hash(type.to_s, token)
12
- else
13
- raise ArgumentError, "Can't build an Authorization #{type} header from #{token.inspect}"
11
+ # @param type [String, Symbol]
12
+ # @param token [String, Symbol, Hash]
13
+ # @return [String] a header value
14
+ def self.header(type, token)
15
+ case token
16
+ when String, Symbol
17
+ "#{type} #{token}"
18
+ when Hash
19
+ build_hash(type.to_s, token)
20
+ else
21
+ raise ArgumentError,
22
+ "Can't build an Authorization #{type}" \
23
+ "header from #{token.inspect}"
24
+ end
14
25
  end
15
- end
16
26
 
17
- # Internal
18
- def self.build_hash(type, hash)
19
- comma = ", "
20
- values = []
21
- hash.each do |key, value|
22
- values << "#{key}=#{value.to_s.inspect}"
27
+ # @param type [String]
28
+ # @param hash [Hash]
29
+ # @return [String] type followed by comma-separated key=value pairs
30
+ # @api private
31
+ def self.build_hash(type, hash)
32
+ comma = ', '
33
+ values = []
34
+ hash.each do |key, value|
35
+ values << "#{key}=#{value.to_s.inspect}"
36
+ end
37
+ "#{type} #{values * comma}"
23
38
  end
24
- "#{type} #{values * comma}"
25
- end
26
39
 
27
- def initialize(app, type, token)
28
- @header_value = self.class.header(type, token)
29
- super(app)
30
- end
40
+ # @param app [#call]
41
+ # @param type [String, Symbol] Type of Authorization
42
+ # @param token [String, Symbol, Hash] Token value for the Authorization
43
+ def initialize(app, type, token)
44
+ @header_value = self.class.header(type, token)
45
+ super(app)
46
+ end
31
47
 
32
- # Public
33
- def call(env)
34
- unless env.request_headers[KEY]
35
- env.request_headers[KEY] = @header_value
48
+ # @param env [Faraday::Env]
49
+ def call(env)
50
+ env.request_headers[KEY] = @header_value unless env.request_headers[KEY]
51
+ @app.call(env)
36
52
  end
37
- @app.call(env)
38
53
  end
39
54
  end
40
55
  end
41
-
@@ -1,13 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'base64'
2
4
 
3
5
  module Faraday
4
- class Request::BasicAuthentication < Request.load_middleware(:authorization)
5
- # Public
6
- def self.header(login, pass)
7
- value = Base64.encode64([login, pass].join(':'))
8
- value.gsub!("\n", '')
9
- super(:Basic, value)
6
+ class Request
7
+ # Authorization middleware for Basic Authentication.
8
+ class BasicAuthentication < load_middleware(:authorization)
9
+ # @param login [String]
10
+ # @param pass [String]
11
+ #
12
+ # @return [String] a Basic Authentication header line
13
+ def self.header(login, pass)
14
+ value = Base64.encode64([login, pass].join(':'))
15
+ value.delete!("\n")
16
+ super(:Basic, value)
17
+ end
10
18
  end
11
19
  end
12
20
  end
13
-
@@ -1,35 +1,53 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Faraday
2
- class Request::Instrumentation < Faraday::Middleware
3
- class Options < Faraday::Options.new(:name, :instrumenter)
4
- def name
5
- self[:name] ||= 'request.faraday'
6
- end
4
+ class Request
5
+ # Middleware for instrumenting Requests.
6
+ class Instrumentation < Faraday::Middleware
7
+ # Options class used in Request::Instrumentation class.
8
+ class Options < Faraday::Options.new(:name, :instrumenter)
9
+ # @return [String]
10
+ def name
11
+ self[:name] ||= 'request.faraday'
12
+ end
7
13
 
8
- def instrumenter
9
- self[:instrumenter] ||= ActiveSupport::Notifications
14
+ # @return [Class]
15
+ def instrumenter
16
+ self[:instrumenter] ||= ActiveSupport::Notifications
17
+ end
10
18
  end
11
- end
12
19
 
13
- # Public: Instruments requests using Active Support.
14
- #
15
- # Measures time spent only for synchronous requests.
16
- #
17
- # Examples
18
- #
19
- # ActiveSupport::Notifications.subscribe('request.faraday') do |name, starts, ends, _, env|
20
- # url = env[:url]
21
- # http_method = env[:method].to_s.upcase
22
- # duration = ends - starts
23
- # $stderr.puts '[%s] %s %s (%.3f s)' % [url.host, http_method, url.request_uri, duration]
24
- # end
25
- def initialize(app, options = nil)
26
- super(app)
27
- @name, @instrumenter = Options.from(options).values_at(:name, :instrumenter)
28
- end
20
+ # Instruments requests using Active Support.
21
+ #
22
+ # Measures time spent only for synchronous requests.
23
+ #
24
+ # @example Using ActiveSupport::Notifications to measure time spent
25
+ # for Faraday requests.
26
+ # ActiveSupport::Notifications
27
+ # .subscribe('request.faraday') do |name, starts, ends, _, env|
28
+ # url = env[:url]
29
+ # http_method = env[:method].to_s.upcase
30
+ # duration = ends - starts
31
+ # $stderr.puts '[%s] %s %s (%.3f s)' %
32
+ # [url.host, http_method, url.request_uri, duration]
33
+ # end
34
+ # @param app [#call]
35
+ # @param options [nil, Hash] Options hash
36
+ # @option options [String] :name ('request.faraday')
37
+ # Name of the instrumenter
38
+ # @option options [Class] :instrumenter (ActiveSupport::Notifications)
39
+ # Active Support instrumenter class.
40
+ def initialize(app, options = nil)
41
+ super(app)
42
+ @name, @instrumenter = Options.from(options)
43
+ .values_at(:name, :instrumenter)
44
+ end
29
45
 
30
- def call(env)
31
- @instrumenter.instrument(@name, env) do
32
- @app.call(env)
46
+ # @param env [Faraday::Env]
47
+ def call(env)
48
+ @instrumenter.instrument(@name, env) do
49
+ @app.call(env)
50
+ end
33
51
  end
34
52
  end
35
53
  end
@@ -1,66 +1,97 @@
1
- require File.expand_path("../url_encoded", __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path('url_encoded', __dir__)
2
4
  require 'securerandom'
3
5
 
4
6
  module Faraday
5
- class Request::Multipart < Request::UrlEncoded
6
- self.mime_type = 'multipart/form-data'.freeze
7
- DEFAULT_BOUNDARY_PREFIX = "-----------RubyMultipartPost".freeze unless defined? DEFAULT_BOUNDARY_PREFIX
7
+ class Request
8
+ # Middleware for supporting multi-part requests.
9
+ class Multipart < UrlEncoded
10
+ self.mime_type = 'multipart/form-data'
11
+ unless defined?(::Faraday::Request::Multipart::DEFAULT_BOUNDARY_PREFIX)
12
+ DEFAULT_BOUNDARY_PREFIX = '-----------RubyMultipartPost'
13
+ end
8
14
 
9
- def call(env)
10
- match_content_type(env) do |params|
11
- env.request.boundary ||= unique_boundary
12
- env.request_headers[CONTENT_TYPE] += "; boundary=#{env.request.boundary}"
13
- env.body = create_multipart(env, params)
15
+ # Checks for files in the payload, otherwise leaves everything untouched.
16
+ #
17
+ # @param env [Faraday::Env]
18
+ def call(env)
19
+ match_content_type(env) do |params|
20
+ env.request.boundary ||= unique_boundary
21
+ env.request_headers[CONTENT_TYPE] +=
22
+ "; boundary=#{env.request.boundary}"
23
+ env.body = create_multipart(env, params)
24
+ end
25
+ @app.call env
14
26
  end
15
- @app.call env
16
- end
17
27
 
18
- def process_request?(env)
19
- type = request_type(env)
20
- env.body.respond_to?(:each_key) and !env.body.empty? and (
21
- (type.empty? and has_multipart?(env.body)) or
22
- type == self.class.mime_type
23
- )
24
- end
28
+ # @param env [Faraday::Env]
29
+ def process_request?(env)
30
+ type = request_type(env)
31
+ env.body.respond_to?(:each_key) && !env.body.empty? && (
32
+ (type.empty? && has_multipart?(env.body)) ||
33
+ (type == self.class.mime_type)
34
+ )
35
+ end
25
36
 
26
- def has_multipart?(obj)
27
- # string is an enum in 1.8, returning list of itself
28
- if obj.respond_to?(:each) && !obj.is_a?(String)
29
- (obj.respond_to?(:values) ? obj.values : obj).each do |val|
30
- return true if (val.respond_to?(:content_type) || has_multipart?(val))
37
+ # Returns true if obj is an enumerable with values that are multipart.
38
+ #
39
+ # @param obj [Object]
40
+ # @return [Boolean]
41
+ def has_multipart?(obj) # rubocop:disable Naming/PredicateName
42
+ if obj.respond_to?(:each)
43
+ (obj.respond_to?(:values) ? obj.values : obj).each do |val|
44
+ return true if val.respond_to?(:content_type) || has_multipart?(val)
45
+ end
31
46
  end
47
+ false
32
48
  end
33
- false
34
- end
35
49
 
36
- def create_multipart(env, params)
37
- boundary = env.request.boundary
38
- parts = process_params(params) do |key, value|
39
- Faraday::Parts::Part.new(boundary, key, value)
50
+ # @param env [Faraday::Env]
51
+ # @param params [Hash]
52
+ def create_multipart(env, params)
53
+ boundary = env.request.boundary
54
+ parts = process_params(params) do |key, value|
55
+ part(boundary, key, value)
56
+ end
57
+ parts << Faraday::Parts::EpiloguePart.new(boundary)
58
+
59
+ body = Faraday::CompositeReadIO.new(parts)
60
+ env.request_headers[Faraday::Env::ContentLength] = body.length.to_s
61
+ body
40
62
  end
41
- parts << Faraday::Parts::EpiloguePart.new(boundary)
42
63
 
43
- body = Faraday::CompositeReadIO.new(parts)
44
- env.request_headers[Faraday::Env::ContentLength] = body.length.to_s
45
- return body
46
- end
64
+ def part(boundary, key, value)
65
+ if value.respond_to?(:to_part)
66
+ value.to_part(boundary, key)
67
+ else
68
+ Faraday::Parts::Part.new(boundary, key, value)
69
+ end
70
+ end
47
71
 
48
- def unique_boundary
49
- "#{DEFAULT_BOUNDARY_PREFIX}-#{SecureRandom.hex}"
50
- end
72
+ # @return [String]
73
+ def unique_boundary
74
+ "#{DEFAULT_BOUNDARY_PREFIX}-#{SecureRandom.hex}"
75
+ end
51
76
 
52
- def process_params(params, prefix = nil, pieces = nil, &block)
53
- params.inject(pieces || []) do |all, (key, value)|
54
- key = "#{prefix}[#{key}]" if prefix
77
+ # @param params [Hash]
78
+ # @param prefix [String]
79
+ # @param pieces [Array]
80
+ def process_params(params, prefix = nil, pieces = nil, &block)
81
+ params.inject(pieces || []) do |all, (key, value)|
82
+ key = "#{prefix}[#{key}]" if prefix
55
83
 
56
- case value
57
- when Array
58
- values = value.inject([]) { |a,v| a << [nil, v] }
59
- process_params(values, key, all, &block)
60
- when Hash
61
- process_params(value, key, all, &block)
62
- else
63
- all << block.call(key, value)
84
+ case value
85
+ when Array
86
+ values = value.inject([]) { |a, v| a << [nil, v] }
87
+ process_params(values, key, all, &block)
88
+ when Hash
89
+ process_params(value, key, all, &block)
90
+ else
91
+ # rubocop:disable Performance/RedundantBlockCall
92
+ all << block.call(key, value)
93
+ # rubocop:enable Performance/RedundantBlockCall
94
+ end
64
95
  end
65
96
  end
66
97
  end