Skip to content

Commit

Permalink
Merge branch '1.0' of https://github.com/lostisland/faraday into feat…
Browse files Browse the repository at this point in the history
…ure/#762-rspec

# Conflicts:
#	lib/faraday.rb
  • Loading branch information
iMacTia committed Sep 21, 2018
2 parents c4f03b7 + afe53e9 commit bac1da1
Show file tree
Hide file tree
Showing 14 changed files with 127 additions and 49 deletions.
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE.md
Expand Up @@ -12,7 +12,7 @@ If possible, please provide the steps to reproduce the issue.

## CHECKLIST (delete before creating the issue)
* If you're not reporting a bug/issue, you can ignore this whole template.
* Are you using the latest Farday version? If not, please check the [Releases](https://github.com/lostisland/faraday/releases) page to see if the issue has already been fixed.
* Are you using the latest Faraday version? If not, please check the [Releases](https://github.com/lostisland/faraday/releases) page to see if the issue has already been fixed.
* Provide the Faraday and Ruby Version you're using while experiencing the issue.
* Fill the `Issue description` and `Steps to Reproduce` sections.
* Delete this checklist before posting the issue.
3 changes: 2 additions & 1 deletion .travis.yml
Expand Up @@ -8,6 +8,7 @@ rvm:
- 2.3
- 2.4
- 2.5
- ruby-head
env:
matrix:
- SSL=no
Expand All @@ -20,6 +21,6 @@ deploy:
on:
tags: true
repo: lostisland/faraday
rvm: 2.4
rvm: 2.5
condition: '"$SSL" = "yes"'

4 changes: 2 additions & 2 deletions lib/faraday.rb
Expand Up @@ -16,7 +16,7 @@
# conn.get '/'
#
module Faraday
VERSION = "0.15.2"
VERSION = "0.15.3"
METHODS_WITH_QUERY = %w[get head delete]
METHODS_WITH_BODY = %w[post put patch]

Expand Down Expand Up @@ -204,7 +204,7 @@ def register_middleware(autoload_path = nil, mapping = nil)
#
# @param key [Symbol] key for the registered middleware.
# @return [Class] a middleware Class.
# @raise [Faraday::Error] if the {key} is not registered
# @raise [Faraday::Error] if given key is not registered
#
# @example
#
Expand Down
13 changes: 9 additions & 4 deletions lib/faraday/adapter/net_http.rb
Expand Up @@ -151,10 +151,15 @@ def configure_ssl(http, ssl)
end

def configure_request(http, req)
http.read_timeout = http.open_timeout = req[:timeout] if req[:timeout]
http.open_timeout = req[:open_timeout] if req[:open_timeout]
# Only set if Net::Http supports it, since Ruby 2.5.
http.max_retries = 0 if http.respond_to?(:max_retries=)
if req[:timeout]
http.read_timeout = req[:timeout]
http.open_timeout = req[:timeout]
http.write_timeout = req[:timeout] if http.respond_to?(:write_timeout=)
end
http.open_timeout = req[:open_timeout] if req[:open_timeout]
http.write_timeout = req[:write_timeout] if req[:write_timeout] && http.respond_to?(:write_timeout=)
# Only set if Net::Http supports it, since Ruby 2.5.
http.max_retries = 0 if http.respond_to?(:max_retries=)

@config_block.call(http) if @config_block
end
Expand Down
2 changes: 1 addition & 1 deletion lib/faraday/connection.rb
Expand Up @@ -47,7 +47,7 @@ class Connection
# @param url [URI, String] URI or String base URL to use as a prefix for all
# requests (optional).
# @param options [Hash, Faraday::ConnectionOptions]
# @option options [URI, String] :url URI or String base URL (default: "http:/").
# @option options [URI, String] :url ('http:/') URI or String base URL
# @option options [Hash<String => String>] :params URI query unencoded key/value pairs.
# @option options [Hash<String => String>] :headers Hash of unencoded HTTP header key/value pairs.
# @option options [Hash] :request Hash of request options.
Expand Down
12 changes: 12 additions & 0 deletions lib/faraday/error.rb
Expand Up @@ -44,19 +44,31 @@ def inspect
end
end

# A unified client error for failed connections.
class ConnectionFailed < ClientError; end

# A 404 error used in the RaiseError middleware
#
# @see Faraday::Response::RaiseError
class ResourceNotFound < ClientError; end

# Raised by FaradayMiddleware::ResponseMiddleware
class ParsingError < ClientError; end

# A unified client error for timeouts.
class TimeoutError < ClientError
def initialize(ex = nil)
super(ex || "timeout")
end
end

# A unified client error for SSL errors.
class SSLError < ClientError
end

# Exception used to control the Retry middleware.
#
# @see Faraday::Request::Retry
class RetriableResponse < ClientError; end

[:ClientError, :ConnectionFailed, :ResourceNotFound,
Expand Down
2 changes: 1 addition & 1 deletion lib/faraday/options.rb
Expand Up @@ -202,7 +202,7 @@ def self.fetch_error_class
end

class RequestOptions < Options.new(:params_encoder, :proxy, :bind,
:timeout, :open_timeout, :boundary,
:timeout, :open_timeout, :write_timeout, :boundary,
:oauth, :context, :on_data)

def []=(key, value)
Expand Down
15 changes: 12 additions & 3 deletions lib/faraday/request/authorization.rb
@@ -1,8 +1,11 @@
module Faraday
# Request middleware for the Authorization HTTP header
class Request::Authorization < Faraday::Middleware
KEY = "Authorization".freeze unless defined? KEY

# Public
# @param type [String, Symbol]
# @param token [String, Symbol, Hash]
# @return [String] a header value
def self.header(type, token)
case token
when String, Symbol
Expand All @@ -14,7 +17,10 @@ def self.header(type, token)
end
end

# Internal
# @param type [String]
# @param hash [Hash]
# @return [String] type followed by comma-separated key=value pairs
# @api private
def self.build_hash(type, hash)
comma = ", "
values = []
Expand All @@ -24,12 +30,15 @@ def self.build_hash(type, hash)
"#{type} #{values * comma}"
end

# @param app [#call]
# @param type [String, Symbol] Type of Authorization
# @param token [String, Symbol, Hash] Token value for the Authorization
def initialize(app, type, token)
@header_value = self.class.header(type, token)
super(app)
end

# Public
# @param env [Faraday::Env]
def call(env)
unless env.request_headers[KEY]
env.request_headers[KEY] = @header_value
Expand Down
6 changes: 5 additions & 1 deletion lib/faraday/request/basic_authentication.rb
@@ -1,8 +1,12 @@
require 'base64'

module Faraday
# Authorization middleware for Basic Authentication.
class Request::BasicAuthentication < Request.load_middleware(:authorization)
# Public
# @param login [String]
# @param pass [String]
#
# @return [String] a Basic Authentication header line
def self.header(login, pass)
value = Base64.encode64([login, pass].join(':'))
value.gsub!("\n", '')
Expand Down
14 changes: 11 additions & 3 deletions lib/faraday/request/instrumentation.rb
@@ -1,32 +1,40 @@
module Faraday
# Middleware for instrumenting Requests.
class Request::Instrumentation < Faraday::Middleware
# Options class used in Request::Instrumentation class.
class Options < Faraday::Options.new(:name, :instrumenter)
# @return [String]
def name
self[:name] ||= 'request.faraday'
end

# @return [Class]
def instrumenter
self[:instrumenter] ||= ActiveSupport::Notifications
end
end

# Public: Instruments requests using Active Support.
# Instruments requests using Active Support.
#
# Measures time spent only for synchronous requests.
#
# Examples
#
# @example Using ActiveSupport::Notifications to measure time spent for Faraday requests
# ActiveSupport::Notifications.subscribe('request.faraday') do |name, starts, ends, _, env|
# url = env[:url]
# http_method = env[:method].to_s.upcase
# duration = ends - starts
# $stderr.puts '[%s] %s %s (%.3f s)' % [url.host, http_method, url.request_uri, duration]
# end
# @param app [#call]
# @param options [nil, Hash] Options hash
# @option options [String] :name ('request.faraday') Name of the instrumenter
# @option options [Class] :instrumenter (ActiveSupport::Notifications) Active Support instrumenter class.
def initialize(app, options = nil)
super(app)
@name, @instrumenter = Options.from(options).values_at(:name, :instrumenter)
end

# @param env [Faraday::Env]
def call(env)
@instrumenter.instrument(@name, env) do
@app.call(env)
Expand Down
15 changes: 15 additions & 0 deletions lib/faraday/request/multipart.rb
Expand Up @@ -2,10 +2,14 @@
require 'securerandom'

module Faraday
# Middleware for supporting multi-part requests.
class Request::Multipart < Request::UrlEncoded
self.mime_type = 'multipart/form-data'.freeze
DEFAULT_BOUNDARY_PREFIX = "-----------RubyMultipartPost".freeze unless defined? DEFAULT_BOUNDARY_PREFIX

# Checks for files in the payload, otherwise leaves everything untouched.
#
# @param env [Faraday::Env]
def call(env)
match_content_type(env) do |params|
env.request.boundary ||= unique_boundary
Expand All @@ -15,6 +19,7 @@ def call(env)
@app.call env
end

# @param env [Faraday::Env]
def process_request?(env)
type = request_type(env)
env.body.respond_to?(:each_key) and !env.body.empty? and (
Expand All @@ -23,6 +28,10 @@ def process_request?(env)
)
end

# Returns true if obj is an enumerable with values that are multipart.
#
# @param obj [Object]
# @return [Boolean]
def has_multipart?(obj)
# string is an enum in 1.8, returning list of itself
if obj.respond_to?(:each) && !obj.is_a?(String)
Expand All @@ -33,6 +42,8 @@ def has_multipart?(obj)
false
end

# @param env [Faraday::Env]
# @param params [Hash]
def create_multipart(env, params)
boundary = env.request.boundary
parts = process_params(params) do |key, value|
Expand All @@ -45,10 +56,14 @@ def create_multipart(env, params)
return body
end

# @return [String]
def unique_boundary
"#{DEFAULT_BOUNDARY_PREFIX}-#{SecureRandom.hex}"
end

# @param params [Hash]
# @param prefix [String]
# @param pieces [Array]
def process_params(params, prefix = nil, pieces = nil, &block)
params.inject(pieces || []) do |all, (key, value)|
key = "#{prefix}[#{key}]" if prefix
Expand Down
63 changes: 31 additions & 32 deletions lib/faraday/request/retry.rb
Expand Up @@ -6,20 +6,22 @@ module Faraday
# handle, a retry interval, a percentage of randomness to add to the retry
# interval, and a backoff factor.
#
# Examples
#
# @example Configure Retry middleware using intervals
# Faraday.new do |conn|
# conn.request :retry, max: 2, interval: 0.05,
# interval_randomness: 0.5, backoff_factor: 2,
# exceptions: [CustomException, 'Timeout::Error']
# conn.adapter ...
# conn.request(:retry, max: 2,
# interval: 0.05,
# interval_randomness: 0.5,
# backoff_factor: 2,
# exceptions: [CustomException, 'Timeout::Error'])
#
# conn.adapter(:net_http) # NB: Last middleware must be the adapter
# end
#
# This example will result in a first interval that is random between 0.05 and 0.075 and a second
# interval that is random between 0.1 and 0.15
#
# interval that is random between 0.1 and 0.15.
class Request::Retry < Faraday::Middleware

DEFAULT_EXCEPTIONS = [Errno::ETIMEDOUT, 'Timeout::Error', Error::TimeoutError, Faraday::Error::RetriableResponse].freeze
IDEMPOTENT_METHODS = [:delete, :get, :head, :options, :put]

class Options < Faraday::Options.new(:max, :interval, :max_interval, :interval_randomness,
Expand Down Expand Up @@ -57,9 +59,7 @@ def backoff_factor
end

def exceptions
Array(self[:exceptions] ||= [Errno::ETIMEDOUT, 'Timeout::Error',
Error::TimeoutError,
Faraday::Error::RetriableResponse])
Array(self[:exceptions] ||= DEFAULT_EXCEPTIONS)
end

def methods
Expand All @@ -79,32 +79,28 @@ def retry_statuses
end
end

# Public: Initialize middleware
#
# Options:
# max - Maximum number of retries (default: 2)
# interval - Pause in seconds between retries (default: 0)
# interval_randomness - The maximum random interval amount expressed
# @param app [#call]
# @param options [Hash]
# @option options [Integer] :max (2) Maximum number of retries
# @option options [Integer] :interval (0) Pause in seconds between retries
# @option options [Integer] :interval_randomness (0) The maximum random interval amount expressed
# as a float between 0 and 1 to use in addition to the
# interval. (default: 0)
# max_interval - An upper limit for the interval (default: Float::MAX)
# backoff_factor - The amount to multiple each successive retry's
# interval.
# @option options [Integer] :max_interval (Float::MAX) An upper limit for the interval
# @option options [Integer] :backoff_factor (1) The amount to multiple each successive retry's
# interval amount by in order to provide backoff
# (default: 1)
# exceptions - The list of exceptions to handle. Exceptions can be
# given as Class, Module, or String. (default:
# [Errno::ETIMEDOUT, 'Timeout::Error',
# Error::TimeoutError, Faraday::Error::RetriableResponse])
# methods - A list of HTTP methods to retry without calling retry_if. Pass
# @option options [Array] :exceptions ([Errno::ETIMEDOUT, 'Timeout::Error',
# Error::TimeoutError, Faraday::Error::RetriableResponse]) The list of
# exceptions to handle. Exceptions can be given as Class, Module, or String.
# @option options [Array] :methods (the idempotent HTTP methods in IDEMPOTENT_METHODS) A list of
# HTTP methods to retry without calling retry_if. Pass
# an empty Array to call retry_if for all exceptions.
# (defaults to the idempotent HTTP methods in IDEMPOTENT_METHODS)
# retry_if - block that will receive the env object and the exception raised
# @option options [Block] :retry_if (false) block that will receive the env object and the exception raised
# and should decide if the code should retry still the action or
# not independent of the retry count. This would be useful
# if the exception produced is non-recoverable or if the
# the HTTP method called is not idempotent.
# (defaults to return false)
# retry_block - block that is executed after every retry. Request environment, middleware options,
# @option options [Block] :retry_block block that is executed after every retry. Request environment, middleware options,
# current number of retries and the exception is passed to the block as parameters.
def initialize(app, options = nil)
super(app)
Expand All @@ -121,6 +117,7 @@ def calculate_sleep_amount(retries, env)
retry_after && retry_after >= retry_interval ? retry_after : retry_interval
end

# @param env [Faraday::Env]
def call(env)
retries = @options.max
request_body = env[:body]
Expand Down Expand Up @@ -148,10 +145,12 @@ def call(env)
end
end

# Private: construct an exception matcher object.
#
# An exception matcher for the rescue clause can usually be any object that
# responds to `===`, but for Ruby 1.8 it has to be a Class or Module.
#
# @param exceptions [Array]
# @api private
# @return [Module] an exception matcher
def build_exception_matcher(exceptions)
matcher = Module.new
(class << matcher; self; end).class_eval do
Expand Down

0 comments on commit bac1da1

Please sign in to comment.