faraday 0.9.0.rc5 → 0.9.0.rc6
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +6 -5
- data/README.md +0 -22
- data/faraday.gemspec +2 -2
- data/lib/faraday.rb +6 -2
- data/lib/faraday/adapter/em_http.rb +34 -14
- data/lib/faraday/adapter/em_http_ssl_patch.rb +56 -0
- data/lib/faraday/adapter/em_synchrony.rb +21 -20
- data/lib/faraday/adapter/excon.rb +16 -0
- data/lib/faraday/adapter/httpclient.rb +14 -0
- data/lib/faraday/adapter/net_http.rb +6 -2
- data/lib/faraday/adapter/net_http_persistent.rb +15 -3
- data/lib/faraday/adapter/patron.rb +13 -11
- data/lib/faraday/adapter/typhoeus.rb +11 -0
- data/lib/faraday/autoload.rb +2 -4
- data/lib/faraday/connection.rb +30 -3
- data/lib/faraday/error.rb +4 -1
- data/lib/faraday/options.rb +117 -23
- data/lib/faraday/request/instrumentation.rb +1 -3
- data/lib/faraday/request/multipart.rb +1 -1
- data/lib/faraday/request/retry.rb +38 -9
- data/lib/faraday/response.rb +1 -2
- data/lib/faraday/response/raise_error.rb +3 -0
- data/lib/faraday/utils.rb +10 -4
- data/script/proxy-server +42 -0
- data/script/server +1 -3
- data/script/test +35 -7
- data/test/adapters/excon_test.rb +4 -0
- data/test/adapters/httpclient_test.rb +5 -0
- data/test/adapters/integration.rb +48 -2
- data/test/adapters/net_http_persistent_test.rb +10 -1
- data/test/adapters/patron_test.rb +3 -0
- data/test/adapters/rack_test.rb +5 -0
- data/test/adapters/typhoeus_test.rb +3 -13
- data/test/authentication_middleware_test.rb +6 -6
- data/test/connection_test.rb +123 -49
- data/test/env_test.rb +19 -1
- data/test/helper.rb +2 -4
- data/test/live_server.rb +4 -2
- data/test/middleware/instrumentation_test.rb +13 -0
- data/test/middleware/retry_test.rb +47 -0
- data/test/multibyte.txt +1 -0
- data/test/options_test.rb +93 -17
- data/test/request_middleware_test.rb +6 -6
- data/test/utils_test.rb +34 -13
- metadata +69 -44
@@ -56,6 +56,17 @@ module Faraday
|
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
|
+
case resp.curl_return_code
|
60
|
+
when 0
|
61
|
+
# everything OK
|
62
|
+
when 7
|
63
|
+
raise Error::ConnectionFailed, resp.curl_error_message
|
64
|
+
when 60
|
65
|
+
raise Faraday::SSLError, resp.curl_error_message
|
66
|
+
else
|
67
|
+
raise Error::ClientError, resp.curl_error_message
|
68
|
+
end
|
69
|
+
|
59
70
|
save_response(env, resp.code, resp.body) do |response_headers|
|
60
71
|
response_headers.parse resp.headers
|
61
72
|
end
|
data/lib/faraday/autoload.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'faraday'
|
2
|
-
|
3
1
|
module Faraday
|
4
2
|
# Internal: Adds the ability for other modules to manage autoloadable
|
5
3
|
# constants.
|
@@ -74,7 +72,8 @@ module Faraday
|
|
74
72
|
:Timeout => 'timeout',
|
75
73
|
:Authorization => 'authorization',
|
76
74
|
:BasicAuthentication => 'basic_authentication',
|
77
|
-
:TokenAuthentication => 'token_authentication'
|
75
|
+
:TokenAuthentication => 'token_authentication',
|
76
|
+
:Instrumentation => 'instrumentation'
|
78
77
|
end
|
79
78
|
|
80
79
|
class Response
|
@@ -84,4 +83,3 @@ module Faraday
|
|
84
83
|
:Logger => 'logger'
|
85
84
|
end
|
86
85
|
end
|
87
|
-
|
data/lib/faraday/connection.rb
CHANGED
@@ -79,7 +79,14 @@ module Faraday
|
|
79
79
|
@params.update(options.params) if options.params
|
80
80
|
@headers.update(options.headers) if options.headers
|
81
81
|
|
82
|
-
proxy
|
82
|
+
@proxy = nil
|
83
|
+
proxy(options.fetch(:proxy) {
|
84
|
+
uri = ENV['http_proxy']
|
85
|
+
if uri && !uri.empty?
|
86
|
+
uri = 'http://' + uri if uri !~ /^http/i
|
87
|
+
uri
|
88
|
+
end
|
89
|
+
})
|
83
90
|
|
84
91
|
yield self if block_given?
|
85
92
|
|
@@ -312,7 +319,7 @@ module Faraday
|
|
312
319
|
end
|
313
320
|
|
314
321
|
# Public: Sets the path prefix and ensures that it always has a leading
|
315
|
-
#
|
322
|
+
# slash.
|
316
323
|
#
|
317
324
|
# value - A String.
|
318
325
|
#
|
@@ -324,6 +331,27 @@ module Faraday
|
|
324
331
|
end
|
325
332
|
end
|
326
333
|
|
334
|
+
# Public: Takes a relative url for a request and combines it with the defaults
|
335
|
+
# set on the connection instance.
|
336
|
+
#
|
337
|
+
# conn = Faraday::Connection.new { ... }
|
338
|
+
# conn.url_prefix = "https://sushi.com/api?token=abc"
|
339
|
+
# conn.scheme # => https
|
340
|
+
# conn.path_prefix # => "/api"
|
341
|
+
#
|
342
|
+
# conn.build_url("nigiri?page=2") # => https://sushi.com/api/nigiri?token=abc&page=2
|
343
|
+
# conn.build_url("nigiri", :page => 2) # => https://sushi.com/api/nigiri?token=abc&page=2
|
344
|
+
#
|
345
|
+
def build_url(url = nil, extra_params = nil)
|
346
|
+
uri = build_exclusive_url(url)
|
347
|
+
|
348
|
+
query_values = params.dup.merge_query(uri.query, options.params_encoder)
|
349
|
+
query_values.update extra_params if extra_params
|
350
|
+
uri.query = query_values.empty? ? nil : query_values.to_query(options.params_encoder)
|
351
|
+
|
352
|
+
uri
|
353
|
+
end
|
354
|
+
|
327
355
|
# Builds and runs the Faraday::Request.
|
328
356
|
#
|
329
357
|
# method - The Symbol HTTP method.
|
@@ -400,4 +428,3 @@ module Faraday
|
|
400
428
|
end
|
401
429
|
end
|
402
430
|
end
|
403
|
-
|
data/lib/faraday/error.rb
CHANGED
@@ -38,8 +38,11 @@ module Faraday
|
|
38
38
|
class ParsingError < ClientError; end
|
39
39
|
class TimeoutError < ClientError; end
|
40
40
|
|
41
|
+
class SSLError < ClientError
|
42
|
+
end
|
43
|
+
|
41
44
|
[:MissingDependency, :ClientError, :ConnectionFailed, :ResourceNotFound,
|
42
|
-
:ParsingError, :TimeoutError].each do |const|
|
45
|
+
:ParsingError, :TimeoutError, :SSLError].each do |const|
|
43
46
|
Error.const_set(const, Faraday.const_get(const))
|
44
47
|
end
|
45
48
|
end
|
data/lib/faraday/options.rb
CHANGED
@@ -18,7 +18,7 @@ module Faraday
|
|
18
18
|
def update(obj)
|
19
19
|
obj.each do |key, value|
|
20
20
|
if sub_options = self.class.options_for(key)
|
21
|
-
value = sub_options.from(value)
|
21
|
+
value = sub_options.from(value) if value
|
22
22
|
elsif Hash === value
|
23
23
|
hash = {}
|
24
24
|
value.each do |hash_key, hash_value|
|
@@ -27,7 +27,7 @@ module Faraday
|
|
27
27
|
value = hash
|
28
28
|
end
|
29
29
|
|
30
|
-
self.send("#{key}=", value)
|
30
|
+
self.send("#{key}=", value) unless value.nil?
|
31
31
|
end
|
32
32
|
self
|
33
33
|
end
|
@@ -47,9 +47,20 @@ module Faraday
|
|
47
47
|
end
|
48
48
|
|
49
49
|
# Public
|
50
|
-
def fetch(key,
|
51
|
-
send(key)
|
52
|
-
|
50
|
+
def fetch(key, *args)
|
51
|
+
return send(key) if symbolized_key_set.include?(key.to_sym)
|
52
|
+
|
53
|
+
key_setter = "#{key}="
|
54
|
+
|
55
|
+
if args.size > 0
|
56
|
+
return send(key_setter, args.first)
|
57
|
+
end
|
58
|
+
|
59
|
+
if block_given?
|
60
|
+
return send(key_setter, Proc.new.call(key))
|
61
|
+
end
|
62
|
+
|
63
|
+
raise self.class.fetch_error_class, "key not found: #{key.inspect}"
|
53
64
|
end
|
54
65
|
|
55
66
|
# Public
|
@@ -98,6 +109,44 @@ module Faraday
|
|
98
109
|
def self.attribute_options
|
99
110
|
@attribute_options ||= {}
|
100
111
|
end
|
112
|
+
|
113
|
+
def self.memoized(key)
|
114
|
+
memoized_attributes[key.to_sym] = Proc.new
|
115
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
116
|
+
def #{key}() self[:#{key}]; end
|
117
|
+
RUBY
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.memoized_attributes
|
121
|
+
@memoized_attributes ||= {}
|
122
|
+
end
|
123
|
+
|
124
|
+
def [](key)
|
125
|
+
key = key.to_sym
|
126
|
+
if method = self.class.memoized_attributes[key]
|
127
|
+
super(key) || (self[key] = instance_eval(&method))
|
128
|
+
else
|
129
|
+
super
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def symbolized_key_set
|
134
|
+
@symbolized_key_set ||= Set.new(keys.map { |k| k.to_sym })
|
135
|
+
end
|
136
|
+
|
137
|
+
def self.inherited(subclass)
|
138
|
+
super
|
139
|
+
subclass.attribute_options.update(attribute_options)
|
140
|
+
subclass.memoized_attributes.update(memoized_attributes)
|
141
|
+
end
|
142
|
+
|
143
|
+
def self.fetch_error_class
|
144
|
+
@fetch_error_class ||= if Object.const_defined?(:KeyError)
|
145
|
+
::KeyError
|
146
|
+
else
|
147
|
+
::IndexError
|
148
|
+
end
|
149
|
+
end
|
101
150
|
end
|
102
151
|
|
103
152
|
class RequestOptions < Options.new(:params_encoder, :proxy, :bind,
|
@@ -114,7 +163,7 @@ module Faraday
|
|
114
163
|
end
|
115
164
|
|
116
165
|
class SSLOptions < Options.new(:verify, :ca_file, :ca_path, :verify_mode,
|
117
|
-
:cert_store, :client_cert, :client_key, :verify_depth, :version)
|
166
|
+
:cert_store, :client_cert, :client_key, :certificate, :private_key, :verify_depth, :version)
|
118
167
|
|
119
168
|
def verify?
|
120
169
|
verify != false
|
@@ -141,13 +190,8 @@ module Faraday
|
|
141
190
|
super(value)
|
142
191
|
end
|
143
192
|
|
144
|
-
|
145
|
-
|
146
|
-
end
|
147
|
-
|
148
|
-
def password
|
149
|
-
self[:password] ||= Utils.unescape(uri.password)
|
150
|
-
end
|
193
|
+
memoized(:user) { uri.user && Utils.unescape(uri.user) }
|
194
|
+
memoized(:password) { uri.password && Utils.unescape(uri.password) }
|
151
195
|
end
|
152
196
|
|
153
197
|
class ConnectionOptions < Options.new(:request, :proxy, :ssl, :builder, :url,
|
@@ -155,17 +199,11 @@ module Faraday
|
|
155
199
|
|
156
200
|
options :request => RequestOptions, :ssl => SSLOptions
|
157
201
|
|
158
|
-
|
159
|
-
self[:request] ||= self.class.options_for(:request).new
|
160
|
-
end
|
202
|
+
memoized(:request) { self.class.options_for(:request).new }
|
161
203
|
|
162
|
-
|
163
|
-
self[:ssl] ||= self.class.options_for(:ssl).new
|
164
|
-
end
|
204
|
+
memoized(:ssl) { self.class.options_for(:ssl).new }
|
165
205
|
|
166
|
-
|
167
|
-
self[:builder_class] ||= RackBuilder
|
168
|
-
end
|
206
|
+
memoized(:builder_class) { RackBuilder }
|
169
207
|
|
170
208
|
def new_builder(block)
|
171
209
|
builder_class.new(&block)
|
@@ -190,26 +228,82 @@ module Faraday
|
|
190
228
|
|
191
229
|
def_delegators :request, :params_encoder
|
192
230
|
|
231
|
+
# Public
|
232
|
+
def [](key)
|
233
|
+
if in_member_set?(key)
|
234
|
+
super(key)
|
235
|
+
else
|
236
|
+
custom_members[key]
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
# Public
|
241
|
+
def []=(key, value)
|
242
|
+
if in_member_set?(key)
|
243
|
+
super(key, value)
|
244
|
+
else
|
245
|
+
custom_members[key] = value
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
# Public
|
193
250
|
def success?
|
194
251
|
SuccessfulStatuses.include?(status)
|
195
252
|
end
|
196
253
|
|
254
|
+
# Public
|
197
255
|
def needs_body?
|
198
256
|
!body && MethodsWithBodies.include?(method)
|
199
257
|
end
|
200
258
|
|
259
|
+
# Public
|
201
260
|
def clear_body
|
202
261
|
request_headers[ContentLength] = '0'
|
203
262
|
self.body = ''
|
204
263
|
end
|
205
264
|
|
265
|
+
# Public
|
206
266
|
def parse_body?
|
207
267
|
!StatusesWithoutBody.include?(status)
|
208
268
|
end
|
209
269
|
|
270
|
+
# Public
|
210
271
|
def parallel?
|
211
272
|
!!parallel_manager
|
212
273
|
end
|
274
|
+
|
275
|
+
def inspect
|
276
|
+
attrs = [nil]
|
277
|
+
members.each do |mem|
|
278
|
+
if value = send(mem)
|
279
|
+
attrs << "@#{mem}=#{value.inspect}"
|
280
|
+
end
|
281
|
+
end
|
282
|
+
if !custom_members.empty?
|
283
|
+
attrs << "@custom=#{custom_members.inspect}"
|
284
|
+
end
|
285
|
+
%(#<#{self.class}#{attrs.join(" ")}>)
|
286
|
+
end
|
287
|
+
|
288
|
+
# Internal
|
289
|
+
def custom_members
|
290
|
+
@custom_members ||= {}
|
291
|
+
end
|
292
|
+
|
293
|
+
# Internal
|
294
|
+
if members.first.is_a?(Symbol)
|
295
|
+
def in_member_set?(key)
|
296
|
+
self.class.member_set.include?(key.to_sym)
|
297
|
+
end
|
298
|
+
else
|
299
|
+
def in_member_set?(key)
|
300
|
+
self.class.member_set.include?(key.to_s)
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
# Internal
|
305
|
+
def self.member_set
|
306
|
+
@member_set ||= Set.new(members)
|
307
|
+
end
|
213
308
|
end
|
214
309
|
end
|
215
|
-
|
@@ -24,7 +24,7 @@ module Faraday
|
|
24
24
|
# end
|
25
25
|
def initialize(app, options = nil)
|
26
26
|
super(app)
|
27
|
-
@name, @instrumenter = Options.from(options).
|
27
|
+
@name, @instrumenter = Options.from(options).values_at(:name, :instrumenter)
|
28
28
|
end
|
29
29
|
|
30
30
|
def call(env)
|
@@ -34,5 +34,3 @@ module Faraday
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
37
|
-
|
38
|
-
|
@@ -8,7 +8,7 @@ module Faraday
|
|
8
8
|
def call(env)
|
9
9
|
match_content_type(env) do |params|
|
10
10
|
env.request.boundary ||= DEFAULT_BOUNDARY
|
11
|
-
env.request_headers[CONTENT_TYPE] += ";boundary=#{env.request.boundary}"
|
11
|
+
env.request_headers[CONTENT_TYPE] += "; boundary=#{env.request.boundary}"
|
12
12
|
env.body = create_multipart(env, params)
|
13
13
|
end
|
14
14
|
@app.call env
|
@@ -3,17 +3,23 @@ module Faraday
|
|
3
3
|
#
|
4
4
|
# By default, it retries 2 times and handles only timeout exceptions. It can
|
5
5
|
# be configured with an arbitrary number of retries, a list of exceptions to
|
6
|
-
# handle
|
6
|
+
# handle, a retry interval, a percentage of randomness to add to the retry
|
7
|
+
# interval, and a backoff factor.
|
7
8
|
#
|
8
9
|
# Examples
|
9
10
|
#
|
10
11
|
# Faraday.new do |conn|
|
11
12
|
# conn.request :retry, max: 2, interval: 0.05,
|
13
|
+
# interval_randomness: 0.5, backoff_factor: 2
|
12
14
|
# exceptions: [CustomException, 'Timeout::Error']
|
13
15
|
# conn.adapter ...
|
14
16
|
# end
|
17
|
+
#
|
18
|
+
# This example will result in a first interval that is random between 0.05 and 0.075 and a second
|
19
|
+
# interval that is random between 0.1 and 0.15
|
20
|
+
#
|
15
21
|
class Request::Retry < Faraday::Middleware
|
16
|
-
class Options < Faraday::Options.new(:max, :interval, :exceptions)
|
22
|
+
class Options < Faraday::Options.new(:max, :interval, :interval_randomness, :backoff_factor, :exceptions)
|
17
23
|
def self.from(value)
|
18
24
|
if Fixnum === value
|
19
25
|
new(value)
|
@@ -30,6 +36,14 @@ module Faraday
|
|
30
36
|
(self[:interval] ||= 0).to_f
|
31
37
|
end
|
32
38
|
|
39
|
+
def interval_randomness
|
40
|
+
(self[:interval_randomness] ||= 0).to_i
|
41
|
+
end
|
42
|
+
|
43
|
+
def backoff_factor
|
44
|
+
(self[:backoff_factor] ||= 1).to_f
|
45
|
+
end
|
46
|
+
|
33
47
|
def exceptions
|
34
48
|
Array(self[:exceptions] ||= [Errno::ETIMEDOUT, 'Timeout::Error',
|
35
49
|
Error::TimeoutError])
|
@@ -40,25 +54,41 @@ module Faraday
|
|
40
54
|
# Public: Initialize middleware
|
41
55
|
#
|
42
56
|
# Options:
|
43
|
-
# max
|
44
|
-
# interval
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
57
|
+
# max - Maximum number of retries (default: 2)
|
58
|
+
# interval - Pause in seconds between retries (default: 0)
|
59
|
+
# interval_randomness - The maximum random interval amount expressed
|
60
|
+
# as a float between 0 and 1 to use in addition to the
|
61
|
+
# interval. (default: 0)
|
62
|
+
# backoff_factor - The amount to multiple each successive retry's
|
63
|
+
# interval amount by in order to provide backoff
|
64
|
+
# (default: 1)
|
65
|
+
# exceptions - The list of exceptions to handle. Exceptions can be
|
66
|
+
# given as Class, Module, or String. (default:
|
67
|
+
# [Errno::ETIMEDOUT, Timeout::Error,
|
68
|
+
# Error::TimeoutError])
|
48
69
|
def initialize(app, options = nil)
|
49
70
|
super(app)
|
50
71
|
@options = Options.from(options)
|
51
72
|
@errmatch = build_exception_matcher(@options.exceptions)
|
52
73
|
end
|
53
74
|
|
75
|
+
def sleep_amount(retries)
|
76
|
+
retry_index = @options.max - retries
|
77
|
+
current_interval = @options.interval * (@options.backoff_factor ** retry_index)
|
78
|
+
random_interval = rand * @options.interval_randomness.to_f * @options.interval
|
79
|
+
current_interval + random_interval
|
80
|
+
end
|
81
|
+
|
54
82
|
def call(env)
|
55
83
|
retries = @options.max
|
84
|
+
request_body = env[:body]
|
56
85
|
begin
|
86
|
+
env[:body] = request_body # after failure env[:body] is set to the response body
|
57
87
|
@app.call(env)
|
58
88
|
rescue @errmatch
|
59
89
|
if retries > 0
|
60
90
|
retries -= 1
|
61
|
-
sleep
|
91
|
+
sleep sleep_amount(retries + 1)
|
62
92
|
retry
|
63
93
|
end
|
64
94
|
raise
|
@@ -84,4 +114,3 @@ module Faraday
|
|
84
114
|
end
|
85
115
|
end
|
86
116
|
end
|
87
|
-
|
data/lib/faraday/response.rb
CHANGED
@@ -86,9 +86,8 @@ module Faraday
|
|
86
86
|
# Useful for applying request params after restoring a marshalled Response.
|
87
87
|
def apply_request(request_env)
|
88
88
|
raise "response didn't finish yet" unless finished?
|
89
|
-
@env = Env.from(request_env).
|
89
|
+
@env = Env.from(request_env).update(@env)
|
90
90
|
return self
|
91
91
|
end
|
92
92
|
end
|
93
93
|
end
|
94
|
-
|