faraday 0.14.0 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ff30e260051828899307875d73f5ccb1fdcdb4bb40fba3df707e2d6966675cb1
4
- data.tar.gz: 4bc5b5df30090ae639a937d180f0cc2d7b66a163dca438be8049eef0a5b2a483
3
+ metadata.gz: 3737507d92b48e4b98e891c5026210048ab70b2b1ee17ea20993b8ffc65eafb5
4
+ data.tar.gz: caaaa7f7ad1bdda848ac7bc70d4d1b9ba9d06bc85912a61b1ee4082086629a26
5
5
  SHA512:
6
- metadata.gz: 6edafc07bcf5c647f82ab5e50aa8cd7c319e5198559bd7350394fd3fb918e96f1a450fa4eb175ee3b7db9e03880cc2534c3b52b3a213cdc852fe094953603e13
7
- data.tar.gz: 9d2951f42b5e8ae17505bc92493ee8ef2814412de9ade880adf20c081a02e6437da7174a064ca68f37483793e48efdf67aeb145e07ca3a90c71ac80014926070
6
+ metadata.gz: 231b96efdd5b0399f204edaeba22d01661b9d301aff6cad7d097c27c1e95f0a0a8adc9184e88f089862fa9db9a833e50a3eb7bfb96034a2df7f1bdd93661f3fb
7
+ data.tar.gz: f19fca5f59454b7b620160c3e58339e0dff8049be29bda8e8f1a494455dac6c62a1c6cbe4b4e141e999ea3df25cbcdf3ef09d65e93d71a882c318c75c3070dec
data/README.md CHANGED
@@ -69,7 +69,7 @@ conn = Faraday.new(:url => 'http://sushi.com/api_key=s3cr3t') do |faraday|
69
69
  end
70
70
  ```
71
71
 
72
- Once you have the connection object, use it to make HTTP requests. You can pass paramters to it in a few different ways:
72
+ Once you have the connection object, use it to make HTTP requests. You can pass parameters to it in a few different ways:
73
73
 
74
74
  ```ruby
75
75
  ## GET ##
@@ -14,7 +14,7 @@ require 'forwardable'
14
14
  # conn.get '/'
15
15
  #
16
16
  module Faraday
17
- VERSION = "0.14.0"
17
+ VERSION = "0.15.0"
18
18
 
19
19
  class << self
20
20
  # Public: Gets or sets the root path that Faraday is being loaded from.
@@ -40,6 +40,8 @@ module Faraday
40
40
  env.clear_body if env.needs_body?
41
41
  end
42
42
 
43
+ private
44
+
43
45
  def save_response(env, status, body, headers = nil, reason_phrase = nil)
44
46
  env.status = status
45
47
  env.body = body
@@ -56,6 +56,8 @@ module Faraday
56
56
  raise Faraday::Error::TimeoutError, err
57
57
  end
58
58
 
59
+ private
60
+
59
61
  def create_request(env)
60
62
  request = Net::HTTPGenericRequest.new \
61
63
  env[:method].to_s.upcase, # request method
@@ -1,13 +1,23 @@
1
- # Rely on autoloading instead of explicit require; helps avoid the "already
2
- # initialized constant" warning on Ruby 1.8.7 when NetHttp is refereced below.
3
- # require 'faraday/adapter/net_http'
4
-
5
1
  module Faraday
6
2
  class Adapter
7
3
  class NetHttpPersistent < NetHttp
8
4
  dependency 'net/http/persistent'
9
5
 
6
+ private
7
+
10
8
  def net_http_connection(env)
9
+ proxy_uri = proxy_uri(env)
10
+
11
+ cached_connection env[:url], proxy_uri do
12
+ if Net::HTTP::Persistent.instance_method(:initialize).parameters.first == [:key, :name]
13
+ Net::HTTP::Persistent.new(name: 'Faraday', proxy: proxy_uri)
14
+ else
15
+ Net::HTTP::Persistent.new('Faraday', proxy_uri)
16
+ end
17
+ end
18
+ end
19
+
20
+ def proxy_uri(env)
11
21
  proxy_uri = nil
12
22
  if (proxy = env[:request][:proxy])
13
23
  proxy_uri = ::URI::HTTP === proxy[:uri] ? proxy[:uri].dup : ::URI.parse(proxy[:uri].to_s)
@@ -18,12 +28,7 @@ module Faraday
18
28
  define_method(:password) { proxy[:password] }
19
29
  end if proxy[:user]
20
30
  end
21
-
22
- if Net::HTTP::Persistent.instance_method(:initialize).parameters.first == [:key, :name]
23
- Net::HTTP::Persistent.new(name: 'Faraday', proxy: proxy_uri)
24
- else
25
- Net::HTTP::Persistent.new('Faraday', proxy_uri)
26
- end
31
+ proxy_uri
27
32
  end
28
33
 
29
34
  def perform_request(http, env)
@@ -49,6 +54,10 @@ module Faraday
49
54
  http.ca_file = ssl[:ca_file] if ssl[:ca_file]
50
55
  http.ssl_version = ssl[:version] if ssl[:version]
51
56
  end
57
+
58
+ def cached_connection(url, proxy_uri)
59
+ (@cached_connection ||= {})[[url.scheme, url.host, url.port, proxy_uri]] ||= yield
60
+ end
52
61
  end
53
62
  end
54
63
  end
@@ -1,6 +1,5 @@
1
1
  module Faraday
2
2
  class Error < StandardError; end
3
- class MissingDependency < Error; end
4
3
 
5
4
  class ClientError < Error
6
5
  attr_reader :response, :wrapped_exception
@@ -56,8 +55,12 @@ module Faraday
56
55
  class SSLError < ClientError
57
56
  end
58
57
 
59
- [:MissingDependency, :ClientError, :ConnectionFailed, :ResourceNotFound,
60
- :ParsingError, :TimeoutError, :SSLError].each do |const|
58
+ class RetriableResponse < ClientError; end
59
+
60
+ [:ClientError, :ConnectionFailed, :ResourceNotFound,
61
+ :ParsingError, :TimeoutError, :SSLError, :RetriableResponse].each do |const|
61
62
  Error.const_set(const, Faraday.const_get(const))
62
63
  end
64
+
65
+
63
66
  end
@@ -23,7 +23,9 @@ module Faraday
23
23
  IDEMPOTENT_METHODS = [:delete, :get, :head, :options, :put]
24
24
 
25
25
  class Options < Faraday::Options.new(:max, :interval, :max_interval, :interval_randomness,
26
- :backoff_factor, :exceptions, :methods, :retry_if)
26
+ :backoff_factor, :exceptions, :methods, :retry_if, :retry_block,
27
+ :retry_statuses)
28
+
27
29
  DEFAULT_CHECK = lambda { |env,exception| false }
28
30
 
29
31
  def self.from(value)
@@ -56,7 +58,8 @@ module Faraday
56
58
 
57
59
  def exceptions
58
60
  Array(self[:exceptions] ||= [Errno::ETIMEDOUT, 'Timeout::Error',
59
- Error::TimeoutError])
61
+ Error::TimeoutError,
62
+ Faraday::Error::RetriableResponse])
60
63
  end
61
64
 
62
65
  def methods
@@ -67,6 +70,13 @@ module Faraday
67
70
  self[:retry_if] ||= DEFAULT_CHECK
68
71
  end
69
72
 
73
+ def retry_block
74
+ self[:retry_block] ||= Proc.new {}
75
+ end
76
+
77
+ def retry_statuses
78
+ Array(self[:retry_statuses] ||= [])
79
+ end
70
80
  end
71
81
 
72
82
  # Public: Initialize middleware
@@ -83,8 +93,8 @@ module Faraday
83
93
  # (default: 1)
84
94
  # exceptions - The list of exceptions to handle. Exceptions can be
85
95
  # given as Class, Module, or String. (default:
86
- # [Errno::ETIMEDOUT, Timeout::Error,
87
- # Error::TimeoutError])
96
+ # [Errno::ETIMEDOUT, 'Timeout::Error',
97
+ # Error::TimeoutError, Faraday::Error::RetriableResponse])
88
98
  # methods - A list of HTTP methods to retry without calling retry_if. Pass
89
99
  # an empty Array to call retry_if for all exceptions.
90
100
  # (defaults to the idempotent HTTP methods in IDEMPOTENT_METHODS)
@@ -94,18 +104,21 @@ module Faraday
94
104
  # if the exception produced is non-recoverable or if the
95
105
  # the HTTP method called is not idempotent.
96
106
  # (defaults to return false)
107
+ # retry_block - block that is executed after every retry. Request environment, middleware options,
108
+ # current number of retries and the exception is passed to the block as parameters.
97
109
  def initialize(app, options = nil)
98
110
  super(app)
99
111
  @options = Options.from(options)
100
112
  @errmatch = build_exception_matcher(@options.exceptions)
101
113
  end
102
114
 
103
- def sleep_amount(retries)
104
- retry_index = @options.max - retries
105
- current_interval = @options.interval * (@options.backoff_factor ** retry_index)
106
- current_interval = [current_interval, @options.max_interval].min
107
- random_interval = rand * @options.interval_randomness.to_f * @options.interval
108
- current_interval + random_interval
115
+ def calculate_sleep_amount(retries, env)
116
+ retry_after = calculate_retry_after(env)
117
+ retry_interval = calculate_retry_interval(retries)
118
+
119
+ return if retry_after && retry_after > @options.max_interval
120
+
121
+ retry_after && retry_after >= retry_interval ? retry_after : retry_interval
109
122
  end
110
123
 
111
124
  def call(env)
@@ -113,15 +126,25 @@ module Faraday
113
126
  request_body = env[:body]
114
127
  begin
115
128
  env[:body] = request_body # after failure env[:body] is set to the response body
116
- @app.call(env)
129
+ @app.call(env).tap do |resp|
130
+ raise Faraday::Error::RetriableResponse.new(nil, resp) if @options.retry_statuses.include?(resp.status)
131
+ end
117
132
  rescue @errmatch => exception
118
133
  if retries > 0 && retry_request?(env, exception)
119
134
  retries -= 1
120
135
  rewind_files(request_body)
121
- sleep sleep_amount(retries + 1)
122
- retry
136
+ @options.retry_block.call(env, @options, retries, exception)
137
+ if (sleep_amount = calculate_sleep_amount(retries + 1, env))
138
+ sleep sleep_amount
139
+ retry
140
+ end
141
+ end
142
+
143
+ if exception.is_a?(Faraday::Error::RetriableResponse)
144
+ exception.response
145
+ else
146
+ raise
123
147
  end
124
- raise
125
148
  end
126
149
  end
127
150
 
@@ -160,5 +183,29 @@ module Faraday
160
183
  end
161
184
  end
162
185
 
186
+ # MDN spec for Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
187
+ def calculate_retry_after(env)
188
+ response_headers = env[:response_headers]
189
+ return unless response_headers
190
+
191
+ retry_after_value = env[:response_headers]["Retry-After"]
192
+
193
+ # Try to parse date from the header value
194
+ begin
195
+ datetime = DateTime.rfc2822(retry_after_value)
196
+ datetime.to_time - Time.now.utc
197
+ rescue ArgumentError
198
+ retry_after_value.to_f
199
+ end
200
+ end
201
+
202
+ def calculate_retry_interval(retries)
203
+ retry_index = @options.max - retries
204
+ current_interval = @options.interval * (@options.backoff_factor ** retry_index)
205
+ current_interval = [current_interval, @options.max_interval].min
206
+ random_interval = rand * @options.interval_randomness.to_f * @options.interval
207
+
208
+ current_interval + random_interval
209
+ end
163
210
  end
164
211
  end
@@ -20,14 +20,14 @@ module Faraday
20
20
  def_delegators :@logger, :debug, :info, :warn, :error, :fatal
21
21
 
22
22
  def call(env)
23
- info "#{env.method} #{apply_filters(env.url.to_s)}"
23
+ info('request') { "#{env.method.upcase} #{apply_filters(env.url.to_s)}" }
24
24
  debug('request') { apply_filters( dump_headers env.request_headers ) } if log_headers?(:request)
25
25
  debug('request') { apply_filters( dump_body(env[:body]) ) } if env[:body] && log_body?(:request)
26
26
  super
27
27
  end
28
28
 
29
29
  def on_complete(env)
30
- info('Status') { env.status.to_s }
30
+ info('response') { "Status #{env.status.to_s}" }
31
31
  debug('response') { apply_filters( dump_headers env.response_headers ) } if log_headers?(:response)
32
32
  debug('response') { apply_filters( dump_body env[:body] ) } if env[:body] && log_body?(:response)
33
33
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: faraday
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.0
4
+ version: 0.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rick Olson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-01-19 00:00:00.000000000 Z
11
+ date: 2018-04-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: multipart-post
@@ -92,7 +92,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
92
92
  version: '0'
93
93
  requirements: []
94
94
  rubyforge_project:
95
- rubygems_version: 2.7.4
95
+ rubygems_version: 2.7.6
96
96
  signing_key:
97
97
  specification_version: 4
98
98
  summary: HTTP/REST API client library.