faraday 0.9.2 → 1.0.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +276 -0
- data/LICENSE.md +1 -1
- data/README.md +27 -217
- data/Rakefile +7 -0
- data/UPGRADING.md +55 -0
- data/examples/client_spec.rb +65 -0
- data/examples/client_test.rb +79 -0
- data/lib/faraday/adapter/em_http.rb +149 -101
- data/lib/faraday/adapter/em_http_ssl_patch.rb +25 -19
- data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +18 -15
- data/lib/faraday/adapter/em_synchrony.rb +106 -56
- data/lib/faraday/adapter/excon.rb +98 -55
- data/lib/faraday/adapter/httpclient.rb +89 -55
- data/lib/faraday/adapter/net_http.rb +132 -53
- data/lib/faraday/adapter/net_http_persistent.rb +70 -28
- data/lib/faraday/adapter/patron.rb +92 -38
- data/lib/faraday/adapter/rack.rb +30 -13
- data/lib/faraday/adapter/test.rb +136 -52
- data/lib/faraday/adapter/typhoeus.rb +7 -115
- data/lib/faraday/adapter.rb +89 -20
- data/lib/faraday/adapter_registry.rb +28 -0
- data/lib/faraday/autoload.rb +47 -36
- data/lib/faraday/connection.rb +345 -168
- data/lib/faraday/dependency_loader.rb +37 -0
- data/lib/faraday/encoders/flat_params_encoder.rb +98 -0
- data/lib/faraday/encoders/nested_params_encoder.rb +171 -0
- data/lib/faraday/error.rb +108 -29
- data/lib/faraday/file_part.rb +128 -0
- data/lib/faraday/logging/formatter.rb +105 -0
- data/lib/faraday/middleware.rb +12 -28
- data/lib/faraday/middleware_registry.rb +129 -0
- data/lib/faraday/options/connection_options.rb +22 -0
- data/lib/faraday/options/env.rb +181 -0
- data/lib/faraday/options/proxy_options.rb +28 -0
- data/lib/faraday/options/request_options.rb +22 -0
- data/lib/faraday/options/ssl_options.rb +59 -0
- data/lib/faraday/options.rb +57 -194
- data/lib/faraday/param_part.rb +53 -0
- data/lib/faraday/parameters.rb +4 -196
- data/lib/faraday/rack_builder.rb +74 -39
- data/lib/faraday/request/authorization.rb +42 -31
- data/lib/faraday/request/basic_authentication.rb +14 -7
- data/lib/faraday/request/instrumentation.rb +45 -27
- data/lib/faraday/request/multipart.rb +81 -45
- data/lib/faraday/request/retry.rb +211 -126
- data/lib/faraday/request/token_authentication.rb +15 -10
- data/lib/faraday/request/url_encoded.rb +41 -23
- data/lib/faraday/request.rb +84 -30
- data/lib/faraday/response/logger.rb +22 -48
- data/lib/faraday/response/raise_error.rb +38 -14
- data/lib/faraday/response.rb +27 -16
- data/lib/faraday/utils/headers.rb +139 -0
- data/lib/faraday/utils/params_hash.rb +61 -0
- data/lib/faraday/utils.rb +28 -228
- data/lib/faraday.rb +102 -204
- data/spec/external_adapters/faraday_specs_setup.rb +14 -0
- data/spec/faraday/adapter/em_http_spec.rb +47 -0
- data/spec/faraday/adapter/em_synchrony_spec.rb +16 -0
- data/spec/faraday/adapter/excon_spec.rb +49 -0
- data/spec/faraday/adapter/httpclient_spec.rb +73 -0
- data/spec/faraday/adapter/net_http_persistent_spec.rb +57 -0
- data/spec/faraday/adapter/net_http_spec.rb +64 -0
- data/spec/faraday/adapter/patron_spec.rb +18 -0
- data/spec/faraday/adapter/rack_spec.rb +8 -0
- data/spec/faraday/adapter/typhoeus_spec.rb +7 -0
- data/spec/faraday/adapter_registry_spec.rb +28 -0
- data/spec/faraday/adapter_spec.rb +55 -0
- data/spec/faraday/composite_read_io_spec.rb +80 -0
- data/spec/faraday/connection_spec.rb +691 -0
- data/spec/faraday/error_spec.rb +45 -0
- data/spec/faraday/middleware_spec.rb +26 -0
- data/spec/faraday/options/env_spec.rb +70 -0
- data/spec/faraday/options/options_spec.rb +297 -0
- data/spec/faraday/options/proxy_options_spec.rb +37 -0
- data/spec/faraday/options/request_options_spec.rb +19 -0
- data/spec/faraday/params_encoders/flat_spec.rb +34 -0
- data/spec/faraday/params_encoders/nested_spec.rb +134 -0
- data/spec/faraday/rack_builder_spec.rb +196 -0
- data/spec/faraday/request/authorization_spec.rb +88 -0
- data/spec/faraday/request/instrumentation_spec.rb +76 -0
- data/spec/faraday/request/multipart_spec.rb +274 -0
- data/spec/faraday/request/retry_spec.rb +242 -0
- data/spec/faraday/request/url_encoded_spec.rb +70 -0
- data/spec/faraday/request_spec.rb +109 -0
- data/spec/faraday/response/logger_spec.rb +220 -0
- data/spec/faraday/response/middleware_spec.rb +52 -0
- data/spec/faraday/response/raise_error_spec.rb +106 -0
- data/spec/faraday/response_spec.rb +75 -0
- data/spec/faraday/utils/headers_spec.rb +82 -0
- data/spec/faraday/utils_spec.rb +56 -0
- data/spec/faraday_spec.rb +37 -0
- data/spec/spec_helper.rb +132 -0
- data/spec/support/disabling_stub.rb +14 -0
- data/spec/support/fake_safe_buffer.rb +15 -0
- data/spec/support/helper_methods.rb +133 -0
- data/spec/support/shared_examples/adapter.rb +104 -0
- data/spec/support/shared_examples/params_encoder.rb +18 -0
- data/spec/support/shared_examples/request_method.rb +234 -0
- data/spec/support/streaming_response_checker.rb +35 -0
- data/spec/support/webmock_rack_app.rb +68 -0
- metadata +110 -64
- data/lib/faraday/upload_io.rb +0 -67
data/lib/faraday/rack_builder.rb
CHANGED
|
@@ -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
|
-
#
|
|
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
|
-
|
|
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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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)
|
|
32
39
|
end
|
|
33
40
|
|
|
34
|
-
def
|
|
35
|
-
|
|
41
|
+
def inspect
|
|
42
|
+
@name
|
|
43
|
+
end
|
|
36
44
|
|
|
37
45
|
def ==(other)
|
|
38
46
|
if other.is_a? Handler
|
|
39
|
-
|
|
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 = [])
|
|
60
|
+
def initialize(handlers = [], adapter = nil, &block)
|
|
61
|
+
@adapter = adapter
|
|
53
62
|
@handlers = handlers
|
|
54
63
|
if block_given?
|
|
55
|
-
build(&
|
|
64
|
+
build(&block)
|
|
56
65
|
elsif @handlers.empty?
|
|
57
66
|
# default stack, if nothing else is configured
|
|
58
|
-
|
|
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
|
|
83
|
+
# Locks the middleware stack to ensure no further modifications are made.
|
|
74
84
|
def lock!
|
|
75
85
|
@handlers.freeze
|
|
76
86
|
end
|
|
@@ -84,6 +94,7 @@ module Faraday
|
|
|
84
94
|
use_symbol(Faraday::Middleware, klass, *args, &block)
|
|
85
95
|
else
|
|
86
96
|
raise_if_locked
|
|
97
|
+
raise_if_adapter(klass)
|
|
87
98
|
@handlers << self.class::Handler.new(klass, *args, &block)
|
|
88
99
|
end
|
|
89
100
|
end
|
|
@@ -96,8 +107,11 @@ module Faraday
|
|
|
96
107
|
use_symbol(Faraday::Response, key, *args, &block)
|
|
97
108
|
end
|
|
98
109
|
|
|
99
|
-
def adapter(
|
|
100
|
-
|
|
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)
|
|
101
115
|
end
|
|
102
116
|
|
|
103
117
|
## methods to push onto the various positions in the stack:
|
|
@@ -109,7 +123,7 @@ module Faraday
|
|
|
109
123
|
@handlers.insert(index, handler)
|
|
110
124
|
end
|
|
111
125
|
|
|
112
|
-
|
|
126
|
+
alias insert_before insert
|
|
113
127
|
|
|
114
128
|
def insert_after(index, *args, &block)
|
|
115
129
|
index = assert_index(index)
|
|
@@ -131,10 +145,10 @@ module Faraday
|
|
|
131
145
|
# Processes a Request into a Response by passing it through this Builder's
|
|
132
146
|
# middleware stack.
|
|
133
147
|
#
|
|
134
|
-
# connection
|
|
135
|
-
# request
|
|
148
|
+
# @param connection [Faraday::Connection]
|
|
149
|
+
# @param request [Faraday::Request]
|
|
136
150
|
#
|
|
137
|
-
#
|
|
151
|
+
# @return [Faraday::Response]
|
|
138
152
|
def build_response(connection, request)
|
|
139
153
|
app.call(build_env(connection, request))
|
|
140
154
|
end
|
|
@@ -149,26 +163,26 @@ module Faraday
|
|
|
149
163
|
def app
|
|
150
164
|
@app ||= begin
|
|
151
165
|
lock!
|
|
152
|
-
to_app
|
|
153
|
-
response = Response.new
|
|
154
|
-
env.response = response
|
|
155
|
-
response.finish(env) unless env.parallel?
|
|
156
|
-
response
|
|
157
|
-
})
|
|
166
|
+
to_app
|
|
158
167
|
end
|
|
159
168
|
end
|
|
160
169
|
|
|
161
|
-
def to_app
|
|
170
|
+
def to_app
|
|
162
171
|
# last added handler is the deepest and thus closest to the inner app
|
|
163
|
-
|
|
172
|
+
# adapter is always the last one
|
|
173
|
+
@handlers.reverse.inject(@adapter.build) do |app, handler|
|
|
174
|
+
handler.build(app)
|
|
175
|
+
end
|
|
164
176
|
end
|
|
165
177
|
|
|
166
178
|
def ==(other)
|
|
167
|
-
other.is_a?(self.class) &&
|
|
179
|
+
other.is_a?(self.class) &&
|
|
180
|
+
@handlers == other.handlers &&
|
|
181
|
+
@adapter == other.adapter
|
|
168
182
|
end
|
|
169
183
|
|
|
170
184
|
def dup
|
|
171
|
-
self.class.new(@handlers.dup)
|
|
185
|
+
self.class.new(@handlers.dup, @adapter.dup)
|
|
172
186
|
end
|
|
173
187
|
|
|
174
188
|
# ENV Keys
|
|
@@ -188,16 +202,36 @@ module Faraday
|
|
|
188
202
|
# :password - Proxy server password
|
|
189
203
|
# :ssl - Hash of options for configuring SSL requests.
|
|
190
204
|
def build_env(connection, request)
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
request.options
|
|
194
|
-
|
|
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
213
|
end
|
|
196
214
|
|
|
197
215
|
private
|
|
198
216
|
|
|
217
|
+
LOCK_ERR = "can't modify middleware stack after making a request"
|
|
218
|
+
|
|
199
219
|
def raise_if_locked
|
|
200
|
-
raise StackLocked,
|
|
220
|
+
raise StackLocked, LOCK_ERR if locked?
|
|
221
|
+
end
|
|
222
|
+
|
|
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`'
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def adapter_set?
|
|
230
|
+
!@adapter.nil?
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def is_adapter?(klass) # rubocop:disable Naming/PredicateName
|
|
234
|
+
klass.ancestors.include?(Faraday::Adapter)
|
|
201
235
|
end
|
|
202
236
|
|
|
203
237
|
def use_symbol(mod, key, *args, &block)
|
|
@@ -207,6 +241,7 @@ module Faraday
|
|
|
207
241
|
def assert_index(index)
|
|
208
242
|
idx = index.is_a?(Integer) ? index : @handlers.index(index)
|
|
209
243
|
raise "No such handler: #{index.inspect}" unless idx
|
|
244
|
+
|
|
210
245
|
idx
|
|
211
246
|
end
|
|
212
247
|
end
|
|
@@ -1,42 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Faraday
|
|
2
|
-
class Request
|
|
3
|
-
|
|
4
|
+
class Request
|
|
5
|
+
# Request middleware for the Authorization HTTP header
|
|
6
|
+
class Authorization < Faraday::Middleware
|
|
7
|
+
KEY = 'Authorization' unless defined? KEY
|
|
4
8
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
# @param type [String, Symbol]
|
|
10
|
+
# @param token [String, Symbol, Hash]
|
|
11
|
+
# @return [String] a header value
|
|
12
|
+
def self.header(type, token)
|
|
13
|
+
case token
|
|
14
|
+
when String, Symbol
|
|
15
|
+
"#{type} #{token}"
|
|
16
|
+
when Hash
|
|
17
|
+
build_hash(type.to_s, token)
|
|
18
|
+
else
|
|
19
|
+
raise ArgumentError,
|
|
20
|
+
"Can't build an Authorization #{type}" \
|
|
21
|
+
"header from #{token.inspect}"
|
|
22
|
+
end
|
|
14
23
|
end
|
|
15
|
-
end
|
|
16
24
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
values
|
|
25
|
+
# @param type [String]
|
|
26
|
+
# @param hash [Hash]
|
|
27
|
+
# @return [String] type followed by comma-separated key=value pairs
|
|
28
|
+
# @api private
|
|
29
|
+
def self.build_hash(type, hash)
|
|
30
|
+
comma = ', '
|
|
31
|
+
values = []
|
|
32
|
+
hash.each do |key, value|
|
|
33
|
+
values << "#{key}=#{value.to_s.inspect}"
|
|
34
|
+
end
|
|
35
|
+
"#{type} #{values * comma}"
|
|
24
36
|
end
|
|
25
|
-
"#{type} #{values * comma}"
|
|
26
|
-
end
|
|
27
37
|
|
|
28
|
-
|
|
29
|
-
@
|
|
30
|
-
|
|
31
|
-
|
|
38
|
+
# @param app [#call]
|
|
39
|
+
# @param type [String, Symbol] Type of Authorization
|
|
40
|
+
# @param token [String, Symbol, Hash] Token value for the Authorization
|
|
41
|
+
def initialize(app, type, token)
|
|
42
|
+
@header_value = self.class.header(type, token)
|
|
43
|
+
super(app)
|
|
44
|
+
end
|
|
32
45
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
env
|
|
46
|
+
# @param env [Faraday::Env]
|
|
47
|
+
def call(env)
|
|
48
|
+
env.request_headers[KEY] = @header_value unless env.request_headers[KEY]
|
|
49
|
+
@app.call(env)
|
|
37
50
|
end
|
|
38
|
-
@app.call(env)
|
|
39
51
|
end
|
|
40
52
|
end
|
|
41
53
|
end
|
|
42
|
-
|
|
@@ -1,13 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'base64'
|
|
2
4
|
|
|
3
5
|
module Faraday
|
|
4
|
-
class Request
|
|
5
|
-
#
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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
|
-
|
|
9
|
-
|
|
14
|
+
# @return [Class]
|
|
15
|
+
def instrumenter
|
|
16
|
+
self[:instrumenter] ||= ActiveSupport::Notifications
|
|
17
|
+
end
|
|
10
18
|
end
|
|
11
|
-
end
|
|
12
19
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
31
|
-
|
|
32
|
-
@
|
|
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,61 +1,97 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require File.expand_path('url_encoded', __dir__)
|
|
4
|
+
require 'securerandom'
|
|
2
5
|
|
|
3
6
|
module Faraday
|
|
4
|
-
class Request
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
class Request
|
|
8
|
+
# Middleware for supporting multi-part requests.
|
|
9
|
+
class Multipart < UrlEncoded
|
|
10
|
+
self.mime_type = 'multipart/form-data'
|
|
11
|
+
unless defined? DEFAULT_BOUNDARY_PREFIX
|
|
12
|
+
DEFAULT_BOUNDARY_PREFIX = '-----------RubyMultipartPost'
|
|
13
|
+
end
|
|
7
14
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
env
|
|
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
|
|
13
26
|
end
|
|
14
|
-
@app.call env
|
|
15
|
-
end
|
|
16
27
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
|
24
36
|
|
|
25
|
-
|
|
26
|
-
#
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
|
30
46
|
end
|
|
47
|
+
false
|
|
31
48
|
end
|
|
32
|
-
false
|
|
33
|
-
end
|
|
34
49
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
|
39
62
|
end
|
|
40
|
-
parts << Faraday::Parts::EpiloguePart.new(boundary)
|
|
41
63
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
|
71
|
+
|
|
72
|
+
# @return [String]
|
|
73
|
+
def unique_boundary
|
|
74
|
+
"#{DEFAULT_BOUNDARY_PREFIX}-#{SecureRandom.hex}"
|
|
75
|
+
end
|
|
46
76
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
|
50
83
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
|
59
95
|
end
|
|
60
96
|
end
|
|
61
97
|
end
|