faraday 0.15.4 → 1.10.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.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +380 -0
  3. data/LICENSE.md +1 -1
  4. data/README.md +16 -344
  5. data/Rakefile +7 -0
  6. data/examples/client_spec.rb +97 -0
  7. data/examples/client_test.rb +118 -0
  8. data/lib/faraday/adapter/test.rb +118 -69
  9. data/lib/faraday/adapter/typhoeus.rb +4 -1
  10. data/lib/faraday/adapter.rb +72 -22
  11. data/lib/faraday/adapter_registry.rb +30 -0
  12. data/lib/faraday/autoload.rb +39 -36
  13. data/lib/faraday/connection.rb +343 -185
  14. data/lib/faraday/dependency_loader.rb +37 -0
  15. data/lib/faraday/encoders/flat_params_encoder.rb +105 -0
  16. data/lib/faraday/encoders/nested_params_encoder.rb +176 -0
  17. data/lib/faraday/error.rb +118 -38
  18. data/lib/faraday/logging/formatter.rb +105 -0
  19. data/lib/faraday/methods.rb +6 -0
  20. data/lib/faraday/middleware.rb +19 -25
  21. data/lib/faraday/middleware_registry.rb +129 -0
  22. data/lib/faraday/options/connection_options.rb +22 -0
  23. data/lib/faraday/options/env.rb +181 -0
  24. data/lib/faraday/options/proxy_options.rb +32 -0
  25. data/lib/faraday/options/request_options.rb +22 -0
  26. data/lib/faraday/options/ssl_options.rb +59 -0
  27. data/lib/faraday/options.rb +39 -194
  28. data/lib/faraday/parameters.rb +4 -197
  29. data/lib/faraday/rack_builder.rb +77 -65
  30. data/lib/faraday/request/authorization.rb +51 -30
  31. data/lib/faraday/request/basic_authentication.rb +14 -7
  32. data/lib/faraday/request/instrumentation.rb +45 -27
  33. data/lib/faraday/request/json.rb +55 -0
  34. data/lib/faraday/request/token_authentication.rb +15 -10
  35. data/lib/faraday/request/url_encoded.rb +43 -23
  36. data/lib/faraday/request.rb +83 -42
  37. data/lib/faraday/response/json.rb +54 -0
  38. data/lib/faraday/response/logger.rb +20 -69
  39. data/lib/faraday/response/raise_error.rb +49 -14
  40. data/lib/faraday/response.rb +29 -23
  41. data/lib/faraday/utils/headers.rb +139 -0
  42. data/lib/faraday/utils/params_hash.rb +61 -0
  43. data/lib/faraday/utils.rb +38 -247
  44. data/lib/faraday/version.rb +5 -0
  45. data/lib/faraday.rb +134 -189
  46. data/spec/external_adapters/faraday_specs_setup.rb +14 -0
  47. data/spec/faraday/adapter/em_http_spec.rb +49 -0
  48. data/spec/faraday/adapter/em_synchrony_spec.rb +18 -0
  49. data/spec/faraday/adapter/excon_spec.rb +49 -0
  50. data/spec/faraday/adapter/httpclient_spec.rb +73 -0
  51. data/spec/faraday/adapter/net_http_spec.rb +64 -0
  52. data/spec/faraday/adapter/patron_spec.rb +18 -0
  53. data/spec/faraday/adapter/rack_spec.rb +8 -0
  54. data/spec/faraday/adapter/test_spec.rb +377 -0
  55. data/spec/faraday/adapter/typhoeus_spec.rb +7 -0
  56. data/spec/faraday/adapter_registry_spec.rb +28 -0
  57. data/spec/faraday/adapter_spec.rb +55 -0
  58. data/spec/faraday/composite_read_io_spec.rb +80 -0
  59. data/spec/faraday/connection_spec.rb +736 -0
  60. data/spec/faraday/error_spec.rb +60 -0
  61. data/spec/faraday/middleware_spec.rb +52 -0
  62. data/spec/faraday/options/env_spec.rb +70 -0
  63. data/spec/faraday/options/options_spec.rb +297 -0
  64. data/spec/faraday/options/proxy_options_spec.rb +44 -0
  65. data/spec/faraday/options/request_options_spec.rb +19 -0
  66. data/spec/faraday/params_encoders/flat_spec.rb +42 -0
  67. data/spec/faraday/params_encoders/nested_spec.rb +142 -0
  68. data/spec/faraday/rack_builder_spec.rb +345 -0
  69. data/spec/faraday/request/authorization_spec.rb +96 -0
  70. data/spec/faraday/request/instrumentation_spec.rb +76 -0
  71. data/spec/faraday/request/json_spec.rb +111 -0
  72. data/spec/faraday/request/url_encoded_spec.rb +83 -0
  73. data/spec/faraday/request_spec.rb +120 -0
  74. data/spec/faraday/response/json_spec.rb +119 -0
  75. data/spec/faraday/response/logger_spec.rb +220 -0
  76. data/spec/faraday/response/middleware_spec.rb +68 -0
  77. data/spec/faraday/response/raise_error_spec.rb +169 -0
  78. data/spec/faraday/response_spec.rb +75 -0
  79. data/spec/faraday/utils/headers_spec.rb +82 -0
  80. data/spec/faraday/utils_spec.rb +56 -0
  81. data/spec/faraday_spec.rb +37 -0
  82. data/spec/spec_helper.rb +132 -0
  83. data/spec/support/disabling_stub.rb +14 -0
  84. data/spec/support/fake_safe_buffer.rb +15 -0
  85. data/spec/support/helper_methods.rb +133 -0
  86. data/spec/support/shared_examples/adapter.rb +105 -0
  87. data/spec/support/shared_examples/params_encoder.rb +18 -0
  88. data/spec/support/shared_examples/request_method.rb +262 -0
  89. data/spec/support/streaming_response_checker.rb +35 -0
  90. data/spec/support/webmock_rack_app.rb +68 -0
  91. metadata +222 -29
  92. data/lib/faraday/adapter/em_http.rb +0 -243
  93. data/lib/faraday/adapter/em_http_ssl_patch.rb +0 -56
  94. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +0 -66
  95. data/lib/faraday/adapter/em_synchrony.rb +0 -106
  96. data/lib/faraday/adapter/excon.rb +0 -82
  97. data/lib/faraday/adapter/httpclient.rb +0 -128
  98. data/lib/faraday/adapter/net_http.rb +0 -152
  99. data/lib/faraday/adapter/net_http_persistent.rb +0 -68
  100. data/lib/faraday/adapter/patron.rb +0 -95
  101. data/lib/faraday/adapter/rack.rb +0 -58
  102. data/lib/faraday/request/multipart.rb +0 -68
  103. data/lib/faraday/request/retry.rb +0 -210
  104. data/lib/faraday/upload_io.rb +0 -67
@@ -1,68 +0,0 @@
1
- require File.expand_path("../url_encoded", __FILE__)
2
- require 'securerandom'
3
-
4
- 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
8
-
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)
14
- end
15
- @app.call env
16
- end
17
-
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
25
-
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))
31
- end
32
- end
33
- false
34
- end
35
-
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)
40
- end
41
- parts << Faraday::Parts::EpiloguePart.new(boundary)
42
-
43
- body = Faraday::CompositeReadIO.new(parts)
44
- env.request_headers[Faraday::Env::ContentLength] = body.length.to_s
45
- return body
46
- end
47
-
48
- def unique_boundary
49
- "#{DEFAULT_BOUNDARY_PREFIX}-#{SecureRandom.hex}"
50
- end
51
-
52
- def process_params(params, prefix = nil, pieces = nil, &block)
53
- params.inject(pieces || []) do |all, (key, value)|
54
- key = "#{prefix}[#{key}]" if prefix
55
-
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)
64
- end
65
- end
66
- end
67
- end
68
- end
@@ -1,210 +0,0 @@
1
- module Faraday
2
- # Catches exceptions and retries each request a limited number of times.
3
- #
4
- # By default, it retries 2 times and handles only timeout exceptions. It can
5
- # be configured with an arbitrary number of retries, a list of exceptions to
6
- # handle, a retry interval, a percentage of randomness to add to the retry
7
- # interval, and a backoff factor.
8
- #
9
- # Examples
10
- #
11
- # Faraday.new do |conn|
12
- # conn.request :retry, max: 2, interval: 0.05,
13
- # interval_randomness: 0.5, backoff_factor: 2,
14
- # exceptions: [CustomException, 'Timeout::Error']
15
- # conn.adapter ...
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
- #
21
- class Request::Retry < Faraday::Middleware
22
-
23
- DEFAULT_EXCEPTIONS = [Errno::ETIMEDOUT, 'Timeout::Error', Error::TimeoutError, Faraday::Error::RetriableResponse].freeze
24
- IDEMPOTENT_METHODS = [:delete, :get, :head, :options, :put]
25
-
26
- class Options < Faraday::Options.new(:max, :interval, :max_interval, :interval_randomness,
27
- :backoff_factor, :exceptions, :methods, :retry_if, :retry_block,
28
- :retry_statuses)
29
-
30
- DEFAULT_CHECK = lambda { |env,exception| false }
31
-
32
- def self.from(value)
33
- if Integer === value
34
- new(value)
35
- else
36
- super(value)
37
- end
38
- end
39
-
40
- def max
41
- (self[:max] ||= 2).to_i
42
- end
43
-
44
- def interval
45
- (self[:interval] ||= 0).to_f
46
- end
47
-
48
- def max_interval
49
- (self[:max_interval] ||= Float::MAX).to_f
50
- end
51
-
52
- def interval_randomness
53
- (self[:interval_randomness] ||= 0).to_f
54
- end
55
-
56
- def backoff_factor
57
- (self[:backoff_factor] ||= 1).to_f
58
- end
59
-
60
- def exceptions
61
- Array(self[:exceptions] ||= DEFAULT_EXCEPTIONS)
62
- end
63
-
64
- def methods
65
- Array(self[:methods] ||= IDEMPOTENT_METHODS)
66
- end
67
-
68
- def retry_if
69
- self[:retry_if] ||= DEFAULT_CHECK
70
- end
71
-
72
- def retry_block
73
- self[:retry_block] ||= Proc.new {}
74
- end
75
-
76
- def retry_statuses
77
- Array(self[:retry_statuses] ||= [])
78
- end
79
- end
80
-
81
- # Public: Initialize middleware
82
- #
83
- # Options:
84
- # max - Maximum number of retries (default: 2)
85
- # interval - Pause in seconds between retries (default: 0)
86
- # interval_randomness - The maximum random interval amount expressed
87
- # as a float between 0 and 1 to use in addition to the
88
- # interval. (default: 0)
89
- # max_interval - An upper limit for the interval (default: Float::MAX)
90
- # backoff_factor - The amount to multiple each successive retry's
91
- # interval amount by in order to provide backoff
92
- # (default: 1)
93
- # exceptions - The list of exceptions to handle. Exceptions can be
94
- # given as Class, Module, or String. (default:
95
- # [Errno::ETIMEDOUT, 'Timeout::Error',
96
- # Error::TimeoutError, Faraday::Error::RetriableResponse])
97
- # methods - A list of HTTP methods to retry without calling retry_if. Pass
98
- # an empty Array to call retry_if for all exceptions.
99
- # (defaults to the idempotent HTTP methods in IDEMPOTENT_METHODS)
100
- # retry_if - block that will receive the env object and the exception raised
101
- # and should decide if the code should retry still the action or
102
- # not independent of the retry count. This would be useful
103
- # if the exception produced is non-recoverable or if the
104
- # the HTTP method called is not idempotent.
105
- # (defaults to return false)
106
- # retry_block - block that is executed after every retry. Request environment, middleware options,
107
- # current number of retries and the exception is passed to the block as parameters.
108
- def initialize(app, options = nil)
109
- super(app)
110
- @options = Options.from(options)
111
- @errmatch = build_exception_matcher(@options.exceptions)
112
- end
113
-
114
- def calculate_sleep_amount(retries, env)
115
- retry_after = calculate_retry_after(env)
116
- retry_interval = calculate_retry_interval(retries)
117
-
118
- return if retry_after && retry_after > @options.max_interval
119
-
120
- retry_after && retry_after >= retry_interval ? retry_after : retry_interval
121
- end
122
-
123
- def call(env)
124
- retries = @options.max
125
- request_body = env[:body]
126
- begin
127
- env[:body] = request_body # after failure env[:body] is set to the response body
128
- @app.call(env).tap do |resp|
129
- raise Faraday::Error::RetriableResponse.new(nil, resp) if @options.retry_statuses.include?(resp.status)
130
- end
131
- rescue @errmatch => exception
132
- if retries > 0 && retry_request?(env, exception)
133
- retries -= 1
134
- rewind_files(request_body)
135
- @options.retry_block.call(env, @options, retries, exception)
136
- if (sleep_amount = calculate_sleep_amount(retries + 1, env))
137
- sleep sleep_amount
138
- retry
139
- end
140
- end
141
-
142
- if exception.is_a?(Faraday::Error::RetriableResponse)
143
- exception.response
144
- else
145
- raise
146
- end
147
- end
148
- end
149
-
150
- # Private: construct an exception matcher object.
151
- #
152
- # An exception matcher for the rescue clause can usually be any object that
153
- # responds to `===`, but for Ruby 1.8 it has to be a Class or Module.
154
- def build_exception_matcher(exceptions)
155
- matcher = Module.new
156
- (class << matcher; self; end).class_eval do
157
- define_method(:===) do |error|
158
- exceptions.any? do |ex|
159
- if ex.is_a? Module
160
- error.is_a? ex
161
- else
162
- error.class.to_s == ex.to_s
163
- end
164
- end
165
- end
166
- end
167
- matcher
168
- end
169
-
170
- private
171
-
172
- def retry_request?(env, exception)
173
- @options.methods.include?(env[:method]) || @options.retry_if.call(env, exception)
174
- end
175
-
176
- def rewind_files(body)
177
- return unless body.is_a?(Hash)
178
- body.each do |_, value|
179
- if value.is_a? UploadIO
180
- value.rewind
181
- end
182
- end
183
- end
184
-
185
- # MDN spec for Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
186
- def calculate_retry_after(env)
187
- response_headers = env[:response_headers]
188
- return unless response_headers
189
-
190
- retry_after_value = env[:response_headers]["Retry-After"]
191
-
192
- # Try to parse date from the header value
193
- begin
194
- datetime = DateTime.rfc2822(retry_after_value)
195
- datetime.to_time - Time.now.utc
196
- rescue ArgumentError
197
- retry_after_value.to_f
198
- end
199
- end
200
-
201
- def calculate_retry_interval(retries)
202
- retry_index = @options.max - retries
203
- current_interval = @options.interval * (@options.backoff_factor ** retry_index)
204
- current_interval = [current_interval, @options.max_interval].min
205
- random_interval = rand * @options.interval_randomness.to_f * @options.interval
206
-
207
- current_interval + random_interval
208
- end
209
- end
210
- end
@@ -1,67 +0,0 @@
1
- begin
2
- require 'composite_io'
3
- require 'parts'
4
- require 'stringio'
5
- rescue LoadError
6
- $stderr.puts "Install the multipart-post gem."
7
- raise
8
- end
9
-
10
- module Faraday
11
- # Similar but not compatible with ::CompositeReadIO provided by multipart-post.
12
- class CompositeReadIO
13
- def initialize(*parts)
14
- @parts = parts.flatten
15
- @ios = @parts.map { |part| part.to_io }
16
- @index = 0
17
- end
18
-
19
- def length
20
- @parts.inject(0) { |sum, part| sum + part.length }
21
- end
22
-
23
- def rewind
24
- @ios.each { |io| io.rewind }
25
- @index = 0
26
- end
27
-
28
- # Read from IOs in order until `length` bytes have been received.
29
- def read(length = nil, outbuf = nil)
30
- got_result = false
31
- outbuf = outbuf ? outbuf.replace("") : ""
32
-
33
- while io = current_io
34
- if result = io.read(length)
35
- got_result ||= !result.nil?
36
- result.force_encoding("BINARY") if result.respond_to?(:force_encoding)
37
- outbuf << result
38
- length -= result.length if length
39
- break if length == 0
40
- end
41
- advance_io
42
- end
43
- (!got_result && length) ? nil : outbuf
44
- end
45
-
46
- def close
47
- @ios.each { |io| io.close }
48
- end
49
-
50
- def ensure_open_and_readable
51
- # Rubinius compatibility
52
- end
53
-
54
- private
55
-
56
- def current_io
57
- @ios[@index]
58
- end
59
-
60
- def advance_io
61
- @index += 1
62
- end
63
- end
64
-
65
- UploadIO = ::UploadIO
66
- Parts = ::Parts
67
- end