faraday 0.9.1 → 0.17.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 +5 -5
- data/LICENSE.md +1 -1
- data/README.md +192 -28
- data/lib/faraday/adapter/em_http.rb +8 -2
- data/lib/faraday/adapter/em_http_ssl_patch.rb +1 -1
- data/lib/faraday/adapter/em_synchrony.rb +16 -2
- data/lib/faraday/adapter/excon.rb +10 -8
- data/lib/faraday/adapter/httpclient.rb +27 -5
- data/lib/faraday/adapter/net_http.rb +34 -12
- data/lib/faraday/adapter/net_http_persistent.rb +35 -15
- data/lib/faraday/adapter/patron.rb +39 -16
- data/lib/faraday/adapter/test.rb +79 -28
- data/lib/faraday/adapter/typhoeus.rb +4 -115
- data/lib/faraday/adapter.rb +10 -1
- data/lib/faraday/autoload.rb +1 -1
- data/lib/faraday/connection.rb +72 -20
- data/lib/faraday/error.rb +18 -5
- data/lib/faraday/options.rb +42 -19
- data/lib/faraday/parameters.rb +56 -39
- data/lib/faraday/rack_builder.rb +27 -2
- data/lib/faraday/request/authorization.rb +1 -2
- data/lib/faraday/request/multipart.rb +7 -2
- data/lib/faraday/request/retry.rb +82 -18
- data/lib/faraday/request.rb +22 -0
- data/lib/faraday/response/logger.rb +29 -8
- data/lib/faraday/response.rb +6 -2
- data/lib/faraday/utils.rb +32 -3
- data/lib/faraday.rb +14 -34
- metadata +7 -94
- data/.document +0 -6
- data/CHANGELOG.md +0 -20
- data/CONTRIBUTING.md +0 -36
- data/Gemfile +0 -25
- data/Rakefile +0 -71
- data/faraday.gemspec +0 -34
- data/script/cached-bundle +0 -46
- data/script/console +0 -7
- data/script/generate_certs +0 -42
- data/script/package +0 -7
- data/script/proxy-server +0 -42
- data/script/release +0 -17
- data/script/s3-put +0 -71
- data/script/server +0 -36
- data/script/test +0 -172
- data/test/adapters/default_test.rb +0 -14
- data/test/adapters/em_http_test.rb +0 -20
- data/test/adapters/em_synchrony_test.rb +0 -20
- data/test/adapters/excon_test.rb +0 -20
- data/test/adapters/httpclient_test.rb +0 -21
- data/test/adapters/integration.rb +0 -254
- data/test/adapters/logger_test.rb +0 -82
- data/test/adapters/net_http_persistent_test.rb +0 -20
- data/test/adapters/net_http_test.rb +0 -14
- data/test/adapters/patron_test.rb +0 -20
- data/test/adapters/rack_test.rb +0 -31
- data/test/adapters/test_middleware_test.rb +0 -114
- data/test/adapters/typhoeus_test.rb +0 -28
- data/test/authentication_middleware_test.rb +0 -65
- data/test/composite_read_io_test.rb +0 -111
- data/test/connection_test.rb +0 -522
- data/test/env_test.rb +0 -218
- data/test/helper.rb +0 -81
- data/test/live_server.rb +0 -67
- data/test/middleware/instrumentation_test.rb +0 -88
- data/test/middleware/retry_test.rb +0 -177
- data/test/middleware_stack_test.rb +0 -173
- data/test/multibyte.txt +0 -1
- data/test/options_test.rb +0 -252
- data/test/parameters_test.rb +0 -64
- data/test/request_middleware_test.rb +0 -142
- data/test/response_middleware_test.rb +0 -72
- data/test/strawberry.rb +0 -2
- data/test/utils_test.rb +0 -58
    
        data/lib/faraday/error.rb
    CHANGED
    
    | @@ -1,9 +1,8 @@ | |
| 1 1 | 
             
            module Faraday
         | 
| 2 2 | 
             
              class Error < StandardError; end
         | 
| 3 | 
            -
              class MissingDependency < Error; end
         | 
| 4 3 |  | 
| 5 4 | 
             
              class ClientError < Error
         | 
| 6 | 
            -
                attr_reader :response
         | 
| 5 | 
            +
                attr_reader :response, :wrapped_exception
         | 
| 7 6 |  | 
| 8 7 | 
             
                def initialize(ex, response = nil)
         | 
| 9 8 | 
             
                  @wrapped_exception = nil
         | 
| @@ -29,7 +28,17 @@ module Faraday | |
| 29 28 | 
             
                end
         | 
| 30 29 |  | 
| 31 30 | 
             
                def inspect
         | 
| 32 | 
            -
                   | 
| 31 | 
            +
                  inner = ''
         | 
| 32 | 
            +
                  if @wrapped_exception
         | 
| 33 | 
            +
                    inner << " wrapped=#{@wrapped_exception.inspect}"
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
                  if @response
         | 
| 36 | 
            +
                    inner << " response=#{@response.inspect}"
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
                  if inner.empty?
         | 
| 39 | 
            +
                    inner << " #{super}"
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
                  %(#<#{self.class}#{inner}>)
         | 
| 33 42 | 
             
                end
         | 
| 34 43 | 
             
              end
         | 
| 35 44 |  | 
| @@ -46,8 +55,12 @@ module Faraday | |
| 46 55 | 
             
              class SSLError < ClientError
         | 
| 47 56 | 
             
              end
         | 
| 48 57 |  | 
| 49 | 
            -
               | 
| 50 | 
            -
             | 
| 58 | 
            +
              class RetriableResponse < ClientError; end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
              [:ClientError, :ConnectionFailed, :ResourceNotFound,
         | 
| 61 | 
            +
               :ParsingError, :TimeoutError, :SSLError, :RetriableResponse].each do |const|
         | 
| 51 62 | 
             
                Error.const_set(const, Faraday.const_get(const))
         | 
| 52 63 | 
             
              end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
             | 
| 53 66 | 
             
            end
         | 
    
        data/lib/faraday/options.rb
    CHANGED
    
    | @@ -18,23 +18,20 @@ module Faraday | |
| 18 18 | 
             
                # Public
         | 
| 19 19 | 
             
                def update(obj)
         | 
| 20 20 | 
             
                  obj.each do |key, value|
         | 
| 21 | 
            -
                     | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
                      value. | 
| 26 | 
            -
             | 
| 27 | 
            -
                       | 
| 28 | 
            -
                      value = hash
         | 
| 21 | 
            +
                    sub_options = self.class.options_for(key)
         | 
| 22 | 
            +
                    if sub_options
         | 
| 23 | 
            +
                      new_value = sub_options.from(value) if value
         | 
| 24 | 
            +
                    elsif value.is_a?(Hash)
         | 
| 25 | 
            +
                      new_value = value.dup
         | 
| 26 | 
            +
                    else
         | 
| 27 | 
            +
                      new_value = value
         | 
| 29 28 | 
             
                    end
         | 
| 30 29 |  | 
| 31 | 
            -
                    self.send("#{key}=",  | 
| 30 | 
            +
                    self.send("#{key}=", new_value) unless new_value.nil?
         | 
| 32 31 | 
             
                  end
         | 
| 33 32 | 
             
                  self
         | 
| 34 33 | 
             
                end
         | 
| 35 34 |  | 
| 36 | 
            -
                alias merge! update
         | 
| 37 | 
            -
             | 
| 38 35 | 
             
                # Public
         | 
| 39 36 | 
             
                def delete(key)
         | 
| 40 37 | 
             
                  value = send(key)
         | 
| @@ -48,8 +45,24 @@ module Faraday | |
| 48 45 | 
             
                end
         | 
| 49 46 |  | 
| 50 47 | 
             
                # Public
         | 
| 51 | 
            -
                def merge( | 
| 52 | 
            -
                   | 
| 48 | 
            +
                def merge!(other)
         | 
| 49 | 
            +
                  other.each do |key, other_value|
         | 
| 50 | 
            +
                    self_value = self.send(key)
         | 
| 51 | 
            +
                    sub_options = self.class.options_for(key)
         | 
| 52 | 
            +
                    new_value = (self_value && sub_options && other_value) ? self_value.merge(other_value) : other_value
         | 
| 53 | 
            +
                    self.send("#{key}=", new_value) unless new_value.nil?
         | 
| 54 | 
            +
                  end
         | 
| 55 | 
            +
                  self
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                # Public
         | 
| 59 | 
            +
                def merge(other)
         | 
| 60 | 
            +
                  dup.merge!(other)
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                # Public
         | 
| 64 | 
            +
                def deep_dup
         | 
| 65 | 
            +
                  self.class.from(self)
         | 
| 53 66 | 
             
                end
         | 
| 54 67 |  | 
| 55 68 | 
             
                # Public
         | 
| @@ -189,8 +202,7 @@ module Faraday | |
| 189 202 | 
             
              end
         | 
| 190 203 |  | 
| 191 204 | 
             
              class RequestOptions < Options.new(:params_encoder, :proxy, :bind,
         | 
| 192 | 
            -
                :timeout, :open_timeout, :boundary,
         | 
| 193 | 
            -
                :oauth)
         | 
| 205 | 
            +
                :timeout, :open_timeout, :write_timeout, :boundary, :oauth, :context)
         | 
| 194 206 |  | 
| 195 207 | 
             
                def []=(key, value)
         | 
| 196 208 | 
             
                  if key && key.to_sym == :proxy
         | 
| @@ -202,7 +214,8 @@ module Faraday | |
| 202 214 | 
             
              end
         | 
| 203 215 |  | 
| 204 216 | 
             
              class SSLOptions < Options.new(:verify, :ca_file, :ca_path, :verify_mode,
         | 
| 205 | 
            -
                :cert_store, :client_cert, :client_key, :certificate, :private_key, :verify_depth, | 
| 217 | 
            +
                :cert_store, :client_cert, :client_key, :certificate, :private_key, :verify_depth,
         | 
| 218 | 
            +
                :version, :min_version, :max_version)
         | 
| 206 219 |  | 
| 207 220 | 
             
                def verify?
         | 
| 208 221 | 
             
                  verify != false
         | 
| @@ -231,8 +244,8 @@ module Faraday | |
| 231 244 | 
             
                  super(value)
         | 
| 232 245 | 
             
                end
         | 
| 233 246 |  | 
| 234 | 
            -
                memoized(:user) { uri.user && Utils.unescape(uri.user) }
         | 
| 235 | 
            -
                memoized(:password) { uri.password && Utils.unescape(uri.password) }
         | 
| 247 | 
            +
                memoized(:user) { uri && uri.user && Utils.unescape(uri.user) }
         | 
| 248 | 
            +
                memoized(:password) { uri && uri.password && Utils.unescape(uri.password) }
         | 
| 236 249 | 
             
              end
         | 
| 237 250 |  | 
| 238 251 | 
             
              class ConnectionOptions < Options.new(:request, :proxy, :ssl, :builder, :url,
         | 
| @@ -252,7 +265,8 @@ module Faraday | |
| 252 265 | 
             
              end
         | 
| 253 266 |  | 
| 254 267 | 
             
              class Env < Options.new(:method, :body, :url, :request, :request_headers,
         | 
| 255 | 
            -
                :ssl, :parallel_manager, :params, :response, :response_headers, :status | 
| 268 | 
            +
                :ssl, :parallel_manager, :params, :response, :response_headers, :status,
         | 
| 269 | 
            +
                :reason_phrase)
         | 
| 256 270 |  | 
| 257 271 | 
             
                ContentLength = 'Content-Length'.freeze
         | 
| 258 272 | 
             
                StatusesWithoutBody = Set.new [204, 304]
         | 
| @@ -269,6 +283,15 @@ module Faraday | |
| 269 283 |  | 
| 270 284 | 
             
                def_delegators :request, :params_encoder
         | 
| 271 285 |  | 
| 286 | 
            +
                # Public
         | 
| 287 | 
            +
                def self.from(value)
         | 
| 288 | 
            +
                  env = super(value)
         | 
| 289 | 
            +
                  if value.respond_to?(:custom_members)
         | 
| 290 | 
            +
                    env.custom_members.update(value.custom_members)
         | 
| 291 | 
            +
                  end
         | 
| 292 | 
            +
                  env
         | 
| 293 | 
            +
                end
         | 
| 294 | 
            +
             | 
| 272 295 | 
             
                # Public
         | 
| 273 296 | 
             
                def [](key)
         | 
| 274 297 | 
             
                  if in_member_set?(key)
         | 
    
        data/lib/faraday/parameters.rb
    CHANGED
    
    | @@ -40,12 +40,15 @@ module Faraday | |
| 40 40 | 
             
                      end
         | 
| 41 41 | 
             
                      return buffer.chop
         | 
| 42 42 | 
             
                    elsif value.is_a?(Array)
         | 
| 43 | 
            +
                      new_parent = "#{parent}%5B%5D"
         | 
| 44 | 
            +
                      return new_parent if value.empty?
         | 
| 43 45 | 
             
                      buffer = ""
         | 
| 44 46 | 
             
                      value.each_with_index do |val, i|
         | 
| 45 | 
            -
                        new_parent = "#{parent}%5B%5D"
         | 
| 46 47 | 
             
                        buffer << "#{to_query.call(new_parent, val)}&"
         | 
| 47 48 | 
             
                      end
         | 
| 48 49 | 
             
                      return buffer.chop
         | 
| 50 | 
            +
                    elsif value.nil?
         | 
| 51 | 
            +
                      return parent
         | 
| 49 52 | 
             
                    else
         | 
| 50 53 | 
             
                      encoded_value = escape(value)
         | 
| 51 54 | 
             
                      return "#{parent}=#{encoded_value}"
         | 
| @@ -63,50 +66,64 @@ module Faraday | |
| 63 66 |  | 
| 64 67 | 
             
                def self.decode(query)
         | 
| 65 68 | 
             
                  return nil if query == nil
         | 
| 66 | 
            -
             | 
| 67 | 
            -
                   | 
| 68 | 
            -
             | 
| 69 | 
            -
             | 
| 70 | 
            -
             | 
| 69 | 
            +
             | 
| 70 | 
            +
                  params = {}
         | 
| 71 | 
            +
                  query.split("&").each do |pair|
         | 
| 72 | 
            +
                    next if pair.empty?
         | 
| 73 | 
            +
                    key, value = pair.split("=", 2)
         | 
| 74 | 
            +
                    key = unescape(key)
         | 
| 75 | 
            +
                    value = unescape(value.gsub(/\+/, ' ')) if value
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                    subkeys = key.scan(/[^\[\]]+(?:\]?\[\])?/)
         | 
| 78 | 
            +
                    context = params
         | 
| 79 | 
            +
                    subkeys.each_with_index do |subkey, i|
         | 
| 80 | 
            +
                      is_array = subkey =~ /[\[\]]+\Z/
         | 
| 81 | 
            +
                      subkey = $` if is_array
         | 
| 82 | 
            +
                      last_subkey = i == subkeys.length - 1
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                      if !last_subkey || is_array
         | 
| 85 | 
            +
                        value_type = is_array ? Array : Hash
         | 
| 86 | 
            +
                        if context[subkey] && !context[subkey].is_a?(value_type)
         | 
| 87 | 
            +
                          raise TypeError, "expected %s (got %s) for param `%s'" % [
         | 
| 88 | 
            +
                            value_type.name,
         | 
| 89 | 
            +
                            context[subkey].class.name,
         | 
| 90 | 
            +
                            subkey
         | 
| 91 | 
            +
                          ]
         | 
| 92 | 
            +
                        end
         | 
| 93 | 
            +
                        context = (context[subkey] ||= value_type.new)
         | 
| 71 94 | 
             
                      end
         | 
| 72 | 
            -
             | 
| 73 | 
            -
             | 
| 74 | 
            -
             | 
| 75 | 
            -
             | 
| 76 | 
            -
                         | 
| 95 | 
            +
             | 
| 96 | 
            +
                      if context.is_a?(Array) && !is_array
         | 
| 97 | 
            +
                        if !context.last.is_a?(Hash) || context.last.has_key?(subkey)
         | 
| 98 | 
            +
                          context << {}
         | 
| 99 | 
            +
                        end
         | 
| 100 | 
            +
                        context = context.last
         | 
| 101 | 
            +
                      end
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                      if last_subkey
         | 
| 104 | 
            +
                        if is_array
         | 
| 105 | 
            +
                          context << value
         | 
| 106 | 
            +
                        else
         | 
| 107 | 
            +
                          context[subkey] = value
         | 
| 108 | 
            +
                        end
         | 
| 77 109 | 
             
                      end
         | 
| 78 | 
            -
                    else
         | 
| 79 | 
            -
                      hash
         | 
| 80 110 | 
             
                    end
         | 
| 81 111 | 
             
                  end
         | 
| 82 112 |  | 
| 83 | 
            -
                   | 
| 84 | 
            -
             | 
| 85 | 
            -
                    pair.split('=', 2) if pair && !pair.empty?
         | 
| 86 | 
            -
                  end).compact.inject(empty_accumulator.dup) do |accu, (key, value)|
         | 
| 87 | 
            -
                    key = unescape(key)
         | 
| 88 | 
            -
                    if value.kind_of?(String)
         | 
| 89 | 
            -
                      value = unescape(value.gsub(/\+/, ' '))
         | 
| 90 | 
            -
                    end
         | 
| 113 | 
            +
                  dehash(params, 0)
         | 
| 114 | 
            +
                end
         | 
| 91 115 |  | 
| 92 | 
            -
             | 
| 93 | 
            -
             | 
| 94 | 
            -
             | 
| 95 | 
            -
             | 
| 96 | 
            -
             | 
| 97 | 
            -
             | 
| 98 | 
            -
             | 
| 99 | 
            -
             | 
| 100 | 
            -
                     | 
| 101 | 
            -
             | 
| 102 | 
            -
             | 
| 103 | 
            -
                    else
         | 
| 104 | 
            -
                      current_hash[subkeys.last] = value
         | 
| 105 | 
            -
                    end
         | 
| 106 | 
            -
                    accu
         | 
| 107 | 
            -
                  end).inject(empty_accumulator.dup) do |accu, (key, value)|
         | 
| 108 | 
            -
                    accu[key] = value.kind_of?(Hash) ? dehash.call(value) : value
         | 
| 109 | 
            -
                    accu
         | 
| 116 | 
            +
                # Internal: convert a nested hash with purely numeric keys into an array.
         | 
| 117 | 
            +
                # FIXME: this is not compatible with Rack::Utils.parse_nested_query
         | 
| 118 | 
            +
                def self.dehash(hash, depth)
         | 
| 119 | 
            +
                  hash.each do |key, value|
         | 
| 120 | 
            +
                    hash[key] = dehash(value, depth + 1) if value.kind_of?(Hash)
         | 
| 121 | 
            +
                  end
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                  if depth > 0 && !hash.empty? && hash.keys.all? { |k| k =~ /^\d+$/ }
         | 
| 124 | 
            +
                    hash.keys.sort.inject([]) { |all, key| all << hash[key] }
         | 
| 125 | 
            +
                  else
         | 
| 126 | 
            +
                    hash
         | 
| 110 127 | 
             
                  end
         | 
| 111 128 | 
             
                end
         | 
| 112 129 | 
             
              end
         | 
    
        data/lib/faraday/rack_builder.rb
    CHANGED
    
    | @@ -84,6 +84,7 @@ module Faraday | |
| 84 84 | 
             
                    use_symbol(Faraday::Middleware, klass, *args, &block)
         | 
| 85 85 | 
             
                  else
         | 
| 86 86 | 
             
                    raise_if_locked
         | 
| 87 | 
            +
                    warn_middleware_after_adapter if adapter_set?
         | 
| 87 88 | 
             
                    @handlers << self.class::Handler.new(klass, *args, &block)
         | 
| 88 89 | 
             
                  end
         | 
| 89 90 | 
             
                end
         | 
| @@ -105,6 +106,7 @@ module Faraday | |
| 105 106 | 
             
                def insert(index, *args, &block)
         | 
| 106 107 | 
             
                  raise_if_locked
         | 
| 107 108 | 
             
                  index = assert_index(index)
         | 
| 109 | 
            +
                  warn_middleware_after_adapter if inserting_after_adapter?(index)
         | 
| 108 110 | 
             
                  handler = self.class::Handler.new(*args, &block)
         | 
| 109 111 | 
             
                  @handlers.insert(index, handler)
         | 
| 110 112 | 
             
                end
         | 
| @@ -136,6 +138,8 @@ module Faraday | |
| 136 138 | 
             
                #
         | 
| 137 139 | 
             
                # Returns a Faraday::Response.
         | 
| 138 140 | 
             
                def build_response(connection, request)
         | 
| 141 | 
            +
                  warn 'WARNING: No adapter was configured for this request' unless adapter_set?
         | 
| 142 | 
            +
             | 
| 139 143 | 
             
                  app.call(build_env(connection, request))
         | 
| 140 144 | 
             
                end
         | 
| 141 145 |  | 
| @@ -151,8 +155,9 @@ module Faraday | |
| 151 155 | 
             
                    lock!
         | 
| 152 156 | 
             
                    to_app(lambda { |env|
         | 
| 153 157 | 
             
                      response = Response.new
         | 
| 154 | 
            -
                      response.finish(env) unless env.parallel?
         | 
| 155 158 | 
             
                      env.response = response
         | 
| 159 | 
            +
                      response.finish(env) unless env.parallel?
         | 
| 160 | 
            +
                      response
         | 
| 156 161 | 
             
                    })
         | 
| 157 162 | 
             
                  end
         | 
| 158 163 | 
             
                end
         | 
| @@ -188,7 +193,7 @@ module Faraday | |
| 188 193 | 
             
                # :ssl - Hash of options for configuring SSL requests.
         | 
| 189 194 | 
             
                def build_env(connection, request)
         | 
| 190 195 | 
             
                  Env.new(request.method, request.body,
         | 
| 191 | 
            -
                    connection.build_exclusive_url(request.path, request.params),
         | 
| 196 | 
            +
                    connection.build_exclusive_url(request.path, request.params, request.options.params_encoder),
         | 
| 192 197 | 
             
                    request.options, request.headers, connection.ssl,
         | 
| 193 198 | 
             
                    connection.parallel_manager)
         | 
| 194 199 | 
             
                end
         | 
| @@ -199,6 +204,26 @@ module Faraday | |
| 199 204 | 
             
                  raise StackLocked, "can't modify middleware stack after making a request" if locked?
         | 
| 200 205 | 
             
                end
         | 
| 201 206 |  | 
| 207 | 
            +
                def warn_middleware_after_adapter
         | 
| 208 | 
            +
                  warn "WARNING: Unexpected middleware set after the adapter. " \
         | 
| 209 | 
            +
                    "This won't be supported from Faraday 1.0."
         | 
| 210 | 
            +
                end
         | 
| 211 | 
            +
             | 
| 212 | 
            +
                def adapter_set?
         | 
| 213 | 
            +
                  @handlers.any? { |handler| is_adapter?(handler) }
         | 
| 214 | 
            +
                end
         | 
| 215 | 
            +
             | 
| 216 | 
            +
                def inserting_after_adapter?(index)
         | 
| 217 | 
            +
                  adapter_index = @handlers.find_index { |handler| is_adapter?(handler) }
         | 
| 218 | 
            +
                  return false if adapter_index.nil?
         | 
| 219 | 
            +
             | 
| 220 | 
            +
                  index > adapter_index
         | 
| 221 | 
            +
                end
         | 
| 222 | 
            +
             | 
| 223 | 
            +
                def is_adapter?(handler)
         | 
| 224 | 
            +
                  handler.klass.ancestors.include? Faraday::Adapter
         | 
| 225 | 
            +
                end
         | 
| 226 | 
            +
             | 
| 202 227 | 
             
                def use_symbol(mod, key, *args, &block)
         | 
| 203 228 | 
             
                  use(mod.lookup_middleware(key), *args, &block)
         | 
| 204 229 | 
             
                end
         | 
| @@ -1,13 +1,14 @@ | |
| 1 1 | 
             
            require File.expand_path("../url_encoded", __FILE__)
         | 
| 2 | 
            +
            require 'securerandom'
         | 
| 2 3 |  | 
| 3 4 | 
             
            module Faraday
         | 
| 4 5 | 
             
              class Request::Multipart < Request::UrlEncoded
         | 
| 5 6 | 
             
                self.mime_type = 'multipart/form-data'.freeze
         | 
| 6 | 
            -
                 | 
| 7 | 
            +
                DEFAULT_BOUNDARY_PREFIX = "-----------RubyMultipartPost".freeze unless defined? DEFAULT_BOUNDARY_PREFIX
         | 
| 7 8 |  | 
| 8 9 | 
             
                def call(env)
         | 
| 9 10 | 
             
                  match_content_type(env) do |params|
         | 
| 10 | 
            -
                    env.request.boundary ||=  | 
| 11 | 
            +
                    env.request.boundary ||= unique_boundary
         | 
| 11 12 | 
             
                    env.request_headers[CONTENT_TYPE] += "; boundary=#{env.request.boundary}"
         | 
| 12 13 | 
             
                    env.body = create_multipart(env, params)
         | 
| 13 14 | 
             
                  end
         | 
| @@ -44,6 +45,10 @@ module Faraday | |
| 44 45 | 
             
                  return body
         | 
| 45 46 | 
             
                end
         | 
| 46 47 |  | 
| 48 | 
            +
                def unique_boundary
         | 
| 49 | 
            +
                  "#{DEFAULT_BOUNDARY_PREFIX}-#{SecureRandom.hex}"
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 47 52 | 
             
                def process_params(params, prefix = nil, pieces = nil, &block)
         | 
| 48 53 | 
             
                  params.inject(pieces || []) do |all, (key, value)|
         | 
| 49 54 | 
             
                    key = "#{prefix}[#{key}]" if prefix
         | 
| @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            require 'date'
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module Faraday
         | 
| 2 4 | 
             
              # Catches exceptions and retries each request a limited number of times.
         | 
| 3 5 | 
             
              #
         | 
| @@ -10,7 +12,7 @@ module Faraday | |
| 10 12 | 
             
              #
         | 
| 11 13 | 
             
              #   Faraday.new do |conn|
         | 
| 12 14 | 
             
              #     conn.request :retry, max: 2, interval: 0.05,
         | 
| 13 | 
            -
              #                          interval_randomness: 0.5, backoff_factor: 2
         | 
| 15 | 
            +
              #                          interval_randomness: 0.5, backoff_factor: 2,
         | 
| 14 16 | 
             
              #                          exceptions: [CustomException, 'Timeout::Error']
         | 
| 15 17 | 
             
              #     conn.adapter ...
         | 
| 16 18 | 
             
              #   end
         | 
| @@ -20,14 +22,17 @@ module Faraday | |
| 20 22 | 
             
              #
         | 
| 21 23 | 
             
              class Request::Retry < Faraday::Middleware
         | 
| 22 24 |  | 
| 25 | 
            +
                DEFAULT_EXCEPTIONS = [Errno::ETIMEDOUT, 'Timeout::Error', Error::TimeoutError, Faraday::Error::RetriableResponse].freeze
         | 
| 23 26 | 
             
                IDEMPOTENT_METHODS = [:delete, :get, :head, :options, :put]
         | 
| 24 27 |  | 
| 25 | 
            -
                class Options < Faraday::Options.new(:max, :interval, : | 
| 26 | 
            -
                                                     :exceptions, :methods, :retry_if | 
| 28 | 
            +
                class Options < Faraday::Options.new(:max, :interval, :max_interval, :interval_randomness,
         | 
| 29 | 
            +
                                                     :backoff_factor, :exceptions, :methods, :retry_if, :retry_block,
         | 
| 30 | 
            +
                                                     :retry_statuses)
         | 
| 31 | 
            +
             | 
| 27 32 | 
             
                  DEFAULT_CHECK = lambda { |env,exception| false }
         | 
| 28 33 |  | 
| 29 34 | 
             
                  def self.from(value)
         | 
| 30 | 
            -
                    if  | 
| 35 | 
            +
                    if Integer === value
         | 
| 31 36 | 
             
                      new(value)
         | 
| 32 37 | 
             
                    else
         | 
| 33 38 | 
             
                      super(value)
         | 
| @@ -42,8 +47,12 @@ module Faraday | |
| 42 47 | 
             
                    (self[:interval] ||= 0).to_f
         | 
| 43 48 | 
             
                  end
         | 
| 44 49 |  | 
| 50 | 
            +
                  def max_interval
         | 
| 51 | 
            +
                    (self[:max_interval] ||= Float::MAX).to_f
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
             | 
| 45 54 | 
             
                  def interval_randomness
         | 
| 46 | 
            -
                    (self[:interval_randomness] ||= 0). | 
| 55 | 
            +
                    (self[:interval_randomness] ||= 0).to_f
         | 
| 47 56 | 
             
                  end
         | 
| 48 57 |  | 
| 49 58 | 
             
                  def backoff_factor
         | 
| @@ -51,8 +60,7 @@ module Faraday | |
| 51 60 | 
             
                  end
         | 
| 52 61 |  | 
| 53 62 | 
             
                  def exceptions
         | 
| 54 | 
            -
                    Array(self[:exceptions] ||=  | 
| 55 | 
            -
                                                 Error::TimeoutError])
         | 
| 63 | 
            +
                    Array(self[:exceptions] ||= DEFAULT_EXCEPTIONS)
         | 
| 56 64 | 
             
                  end
         | 
| 57 65 |  | 
| 58 66 | 
             
                  def methods
         | 
| @@ -63,6 +71,13 @@ module Faraday | |
| 63 71 | 
             
                    self[:retry_if] ||= DEFAULT_CHECK
         | 
| 64 72 | 
             
                  end
         | 
| 65 73 |  | 
| 74 | 
            +
                  def retry_block
         | 
| 75 | 
            +
                    self[:retry_block] ||= Proc.new {}
         | 
| 76 | 
            +
                  end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                  def retry_statuses
         | 
| 79 | 
            +
                    Array(self[:retry_statuses] ||= [])
         | 
| 80 | 
            +
                  end
         | 
| 66 81 | 
             
                end
         | 
| 67 82 |  | 
| 68 83 | 
             
                # Public: Initialize middleware
         | 
| @@ -73,13 +88,14 @@ module Faraday | |
| 73 88 | 
             
                # interval_randomness - The maximum random interval amount expressed
         | 
| 74 89 | 
             
                #                       as a float between 0 and 1 to use in addition to the
         | 
| 75 90 | 
             
                #                       interval. (default: 0)
         | 
| 91 | 
            +
                # max_interval        - An upper limit for the interval (default: Float::MAX)
         | 
| 76 92 | 
             
                # backoff_factor      - The amount to multiple each successive retry's
         | 
| 77 93 | 
             
                #                       interval amount by in order to provide backoff
         | 
| 78 94 | 
             
                #                       (default: 1)
         | 
| 79 95 | 
             
                # exceptions          - The list of exceptions to handle. Exceptions can be
         | 
| 80 96 | 
             
                #                       given as Class, Module, or String. (default:
         | 
| 81 | 
            -
                #                       [Errno::ETIMEDOUT, Timeout::Error,
         | 
| 82 | 
            -
                #                       Error::TimeoutError])
         | 
| 97 | 
            +
                #                       [Errno::ETIMEDOUT, 'Timeout::Error',
         | 
| 98 | 
            +
                #                       Error::TimeoutError, Faraday::Error::RetriableResponse])
         | 
| 83 99 | 
             
                # methods             - A list of HTTP methods to retry without calling retry_if.  Pass
         | 
| 84 100 | 
             
                #                       an empty Array to call retry_if for all exceptions.
         | 
| 85 101 | 
             
                #                       (defaults to the idempotent HTTP methods in IDEMPOTENT_METHODS)
         | 
| @@ -89,17 +105,21 @@ module Faraday | |
| 89 105 | 
             
                #                       if the exception produced is non-recoverable or if the
         | 
| 90 106 | 
             
                #                       the HTTP method called is not idempotent.
         | 
| 91 107 | 
             
                #                       (defaults to return false)
         | 
| 108 | 
            +
                # retry_block         - block that is executed after every retry. Request environment, middleware options,
         | 
| 109 | 
            +
                #                       current number of retries and the exception is passed to the block as parameters.
         | 
| 92 110 | 
             
                def initialize(app, options = nil)
         | 
| 93 111 | 
             
                  super(app)
         | 
| 94 112 | 
             
                  @options = Options.from(options)
         | 
| 95 113 | 
             
                  @errmatch = build_exception_matcher(@options.exceptions)
         | 
| 96 114 | 
             
                end
         | 
| 97 115 |  | 
| 98 | 
            -
                def  | 
| 99 | 
            -
                   | 
| 100 | 
            -
                   | 
| 101 | 
            -
             | 
| 102 | 
            -
                   | 
| 116 | 
            +
                def calculate_sleep_amount(retries, env)
         | 
| 117 | 
            +
                  retry_after     = calculate_retry_after(env)
         | 
| 118 | 
            +
                  retry_interval  = calculate_retry_interval(retries)
         | 
| 119 | 
            +
             | 
| 120 | 
            +
                  return if retry_after && retry_after > @options.max_interval
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                  retry_after && retry_after >= retry_interval ? retry_after : retry_interval
         | 
| 103 123 | 
             
                end
         | 
| 104 124 |  | 
| 105 125 | 
             
                def call(env)
         | 
| @@ -107,14 +127,25 @@ module Faraday | |
| 107 127 | 
             
                  request_body = env[:body]
         | 
| 108 128 | 
             
                  begin
         | 
| 109 129 | 
             
                    env[:body] = request_body # after failure env[:body] is set to the response body
         | 
| 110 | 
            -
                    @app.call(env)
         | 
| 130 | 
            +
                    @app.call(env).tap do |resp|
         | 
| 131 | 
            +
                      raise Faraday::Error::RetriableResponse.new(nil, resp) if @options.retry_statuses.include?(resp.status)
         | 
| 132 | 
            +
                    end
         | 
| 111 133 | 
             
                  rescue @errmatch => exception
         | 
| 112 134 | 
             
                    if retries > 0 && retry_request?(env, exception)
         | 
| 113 135 | 
             
                      retries -= 1
         | 
| 114 | 
            -
                       | 
| 115 | 
            -
                       | 
| 136 | 
            +
                      rewind_files(request_body)
         | 
| 137 | 
            +
                      @options.retry_block.call(env, @options, retries, exception)
         | 
| 138 | 
            +
                      if (sleep_amount = calculate_sleep_amount(retries + 1, env))
         | 
| 139 | 
            +
                        sleep sleep_amount
         | 
| 140 | 
            +
                        retry
         | 
| 141 | 
            +
                      end
         | 
| 142 | 
            +
                    end
         | 
| 143 | 
            +
             | 
| 144 | 
            +
                    if exception.is_a?(Faraday::Error::RetriableResponse)
         | 
| 145 | 
            +
                      exception.response
         | 
| 146 | 
            +
                    else
         | 
| 147 | 
            +
                      raise
         | 
| 116 148 | 
             
                    end
         | 
| 117 | 
            -
                    raise
         | 
| 118 149 | 
             
                  end
         | 
| 119 150 | 
             
                end
         | 
| 120 151 |  | 
| @@ -144,5 +175,38 @@ module Faraday | |
| 144 175 | 
             
                  @options.methods.include?(env[:method]) || @options.retry_if.call(env, exception)
         | 
| 145 176 | 
             
                end
         | 
| 146 177 |  | 
| 178 | 
            +
                def rewind_files(body)
         | 
| 179 | 
            +
                  return unless body.is_a?(Hash)
         | 
| 180 | 
            +
                  body.each do |_, value|
         | 
| 181 | 
            +
                    if value.is_a? UploadIO
         | 
| 182 | 
            +
                      value.rewind
         | 
| 183 | 
            +
                    end
         | 
| 184 | 
            +
                  end
         | 
| 185 | 
            +
                end
         | 
| 186 | 
            +
             | 
| 187 | 
            +
                # MDN spec for Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
         | 
| 188 | 
            +
                def calculate_retry_after(env)
         | 
| 189 | 
            +
                  response_headers = env[:response_headers]
         | 
| 190 | 
            +
                  return unless response_headers
         | 
| 191 | 
            +
             | 
| 192 | 
            +
                  retry_after_value = env[:response_headers]["Retry-After"]
         | 
| 193 | 
            +
             | 
| 194 | 
            +
                  # Try to parse date from the header value
         | 
| 195 | 
            +
                  begin
         | 
| 196 | 
            +
                    datetime = DateTime.rfc2822(retry_after_value)
         | 
| 197 | 
            +
                    datetime.to_time - Time.now.utc
         | 
| 198 | 
            +
                  rescue ArgumentError
         | 
| 199 | 
            +
                    retry_after_value.to_f
         | 
| 200 | 
            +
                  end
         | 
| 201 | 
            +
                end
         | 
| 202 | 
            +
             | 
| 203 | 
            +
                def calculate_retry_interval(retries)
         | 
| 204 | 
            +
                  retry_index = @options.max - retries
         | 
| 205 | 
            +
                  current_interval = @options.interval * (@options.backoff_factor ** retry_index)
         | 
| 206 | 
            +
                  current_interval = [current_interval, @options.max_interval].min
         | 
| 207 | 
            +
                  random_interval  = rand * @options.interval_randomness.to_f * @options.interval
         | 
| 208 | 
            +
             | 
| 209 | 
            +
                  current_interval + random_interval
         | 
| 210 | 
            +
                end
         | 
| 147 211 | 
             
              end
         | 
| 148 212 | 
             
            end
         | 
    
        data/lib/faraday/request.rb
    CHANGED
    
    | @@ -52,6 +52,8 @@ module Faraday | |
| 52 52 | 
             
                      path.query = nil
         | 
| 53 53 | 
             
                    end
         | 
| 54 54 | 
             
                  else
         | 
| 55 | 
            +
                    anchor_index = path.index('#')
         | 
| 56 | 
            +
                    path = path.slice(0, anchor_index) unless anchor_index.nil?
         | 
| 55 57 | 
             
                    path, query = path.split('?', 2)
         | 
| 56 58 | 
             
                  end
         | 
| 57 59 | 
             
                  self.path = path
         | 
| @@ -67,6 +69,26 @@ module Faraday | |
| 67 69 | 
             
                  headers[key] = value
         | 
| 68 70 | 
             
                end
         | 
| 69 71 |  | 
| 72 | 
            +
                def marshal_dump
         | 
| 73 | 
            +
                  {
         | 
| 74 | 
            +
                    :method  => method,
         | 
| 75 | 
            +
                    :body    => body,
         | 
| 76 | 
            +
                    :headers => headers,
         | 
| 77 | 
            +
                    :path    => path,
         | 
| 78 | 
            +
                    :params  => params,
         | 
| 79 | 
            +
                    :options => options
         | 
| 80 | 
            +
                  }
         | 
| 81 | 
            +
                end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                def marshal_load(serialised)
         | 
| 84 | 
            +
                  self.method  = serialised[:method]
         | 
| 85 | 
            +
                  self.body    = serialised[:body]
         | 
| 86 | 
            +
                  self.headers = serialised[:headers]
         | 
| 87 | 
            +
                  self.path    = serialised[:path]
         | 
| 88 | 
            +
                  self.params  = serialised[:params]
         | 
| 89 | 
            +
                  self.options = serialised[:options]
         | 
| 90 | 
            +
                end
         | 
| 91 | 
            +
             | 
| 70 92 | 
             
                # ENV Keys
         | 
| 71 93 | 
             
                # :method - a symbolized request method (:get, :post)
         | 
| 72 94 | 
             
                # :body   - the request body that will eventually be converted to a string.
         | 
| @@ -4,30 +4,36 @@ module Faraday | |
| 4 4 | 
             
              class Response::Logger < Response::Middleware
         | 
| 5 5 | 
             
                extend Forwardable
         | 
| 6 6 |  | 
| 7 | 
            -
                DEFAULT_OPTIONS = { :bodies => false }
         | 
| 7 | 
            +
                DEFAULT_OPTIONS = { :headers => true, :bodies => false }
         | 
| 8 8 |  | 
| 9 9 | 
             
                def initialize(app, logger = nil, options = {})
         | 
| 10 10 | 
             
                  super(app)
         | 
| 11 11 | 
             
                  @logger = logger || begin
         | 
| 12 12 | 
             
                    require 'logger'
         | 
| 13 | 
            -
                    ::Logger.new( | 
| 13 | 
            +
                    ::Logger.new($stdout)
         | 
| 14 14 | 
             
                  end
         | 
| 15 | 
            +
                  @filter = []
         | 
| 15 16 | 
             
                  @options = DEFAULT_OPTIONS.merge(options)
         | 
| 17 | 
            +
                  yield self if block_given?
         | 
| 16 18 | 
             
                end
         | 
| 17 19 |  | 
| 18 20 | 
             
                def_delegators :@logger, :debug, :info, :warn, :error, :fatal
         | 
| 19 21 |  | 
| 20 22 | 
             
                def call(env)
         | 
| 21 | 
            -
                  info "#{env.method} #{env.url.to_s}"
         | 
| 22 | 
            -
                  debug('request') { dump_headers env.request_headers }
         | 
| 23 | 
            -
                  debug('request') { dump_body(env[:body]) } if env[:body] && log_body?(:request)
         | 
| 23 | 
            +
                  info('request')  { "#{env.method.upcase} #{apply_filters(env.url.to_s)}" }
         | 
| 24 | 
            +
                  debug('request') { apply_filters( dump_headers env.request_headers ) } if log_headers?(:request)
         | 
| 25 | 
            +
                  debug('request') { apply_filters( dump_body(env[:body]) ) } if env[:body] && log_body?(:request)
         | 
| 24 26 | 
             
                  super
         | 
| 25 27 | 
             
                end
         | 
| 26 28 |  | 
| 27 29 | 
             
                def on_complete(env)
         | 
| 28 | 
            -
                  info(' | 
| 29 | 
            -
                  debug('response') { dump_headers env.response_headers }
         | 
| 30 | 
            -
                  debug('response') { dump_body env[:body] } if env[:body] && log_body?(:response)
         | 
| 30 | 
            +
                  info('response')  { "Status #{env.status.to_s}" }
         | 
| 31 | 
            +
                  debug('response') { apply_filters( dump_headers env.response_headers ) } if log_headers?(:response)
         | 
| 32 | 
            +
                  debug('response') { apply_filters( dump_body env[:body] ) } if env[:body] && log_body?(:response)
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                def filter(filter_word, filter_replacement)
         | 
| 36 | 
            +
                  @filter.push([ filter_word, filter_replacement ])
         | 
| 31 37 | 
             
                end
         | 
| 32 38 |  | 
| 33 39 | 
             
                private
         | 
| @@ -49,11 +55,26 @@ module Faraday | |
| 49 55 | 
             
                  body.pretty_inspect
         | 
| 50 56 | 
             
                end
         | 
| 51 57 |  | 
| 58 | 
            +
                def log_headers?(type)
         | 
| 59 | 
            +
                  case @options[:headers]
         | 
| 60 | 
            +
                  when Hash then @options[:headers][type]
         | 
| 61 | 
            +
                  else @options[:headers]
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
             | 
| 52 65 | 
             
                def log_body?(type)
         | 
| 53 66 | 
             
                  case @options[:bodies]
         | 
| 54 67 | 
             
                  when Hash then @options[:bodies][type]
         | 
| 55 68 | 
             
                  else @options[:bodies]
         | 
| 56 69 | 
             
                  end
         | 
| 57 70 | 
             
                end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                def apply_filters(output)
         | 
| 73 | 
            +
                  @filter.each do |pattern, replacement|
         | 
| 74 | 
            +
                    output = output.to_s.gsub(pattern, replacement)
         | 
| 75 | 
            +
                  end
         | 
| 76 | 
            +
                  output
         | 
| 77 | 
            +
                end
         | 
| 78 | 
            +
             | 
| 58 79 | 
             
              end
         | 
| 59 80 | 
             
            end
         |