faraday 0.14.0 → 0.15.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 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.