chore: rubocop lint Metrics/LineLength (#938)

This commit is contained in:
risk danger olson 2019-03-08 10:45:12 -07:00 committed by Mattia
parent 4102f3add4
commit bd322bba6b
42 changed files with 660 additions and 356 deletions

View File

@ -5,15 +5,14 @@ AllCops:
DisplayStyleGuide: true
TargetRubyVersion: 2.3
Naming/MethodName:
Exclude:
- test/adapters/integration.rb
- test/adapters/rack_test.rb
Metrics/BlockLength:
Exclude:
- spec/**/*.rb
Metrics/LineLength:
Exclude:
- spec/**/*.rb
Style/DoubleNegation:
Enabled: false

View File

@ -13,7 +13,7 @@ Metrics/AbcSize:
# Offense count: 5
# Configuration parameters: CountComments.
Metrics/ClassLength:
Max: 211
Max: 233
# Offense count: 16
Metrics/CyclomaticComplexity:
@ -58,9 +58,3 @@ Style/GlobalVars:
Style/MultipleComparison:
Exclude:
- 'lib/faraday/encoders/flat_params_encoder.rb'
# Offense count: 298
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
# URISchemes: http, https
Metrics/LineLength:
Max: 213

View File

@ -15,7 +15,7 @@ end
group :test do
gem 'coveralls', require: false
gem 'em-http-request', '>= 1.1', require: 'em-http'
gem 'em-synchrony', '>= 1.0.3', require: ['em-synchrony', 'em-synchrony/em-http']
gem 'em-synchrony', '>= 1.0.3', require: %w[em-synchrony em-synchrony/em-http]
gem 'excon', '>= 0.27.4'
gem 'httpclient', '>= 2.2'
gem 'minitest', '>= 5.0.5'
@ -26,7 +26,8 @@ group :test do
gem 'rubocop', '~> 0.65.0'
gem 'simplecov'
gem 'sinatra', '~> 1.3'
gem 'typhoeus', '~> 1.3', git: 'https://github.com/typhoeus/typhoeus.git', require: 'typhoeus'
gem 'typhoeus', '~> 1.3', git: 'https://github.com/typhoeus/typhoeus.git',
require: 'typhoeus'
gem 'webmock', '~> 3.4'
end

View File

@ -47,20 +47,21 @@ module Faraday
# Documented below, see default_connection
attr_writer :default_connection
# Tells Faraday to ignore the environment proxy (http_proxy). Defaults to `false`.
# Tells Faraday to ignore the environment proxy (http_proxy).
# Defaults to `false`.
# @return [Boolean]
attr_accessor :ignore_env_proxy
# Initializes a new {Connection}.
#
# @param url [String,Hash] The optional String base URL to use as a prefix for all
# requests. Can also be the options Hash. Any of these values
# will be set on every request made, unless overridden for a
# specific request.
# @param url [String,Hash] The optional String base URL to use as a prefix
# for all requests. Can also be the options Hash. Any of these
# values will be set on every request made, unless overridden
# for a specific request.
# @param options [Hash]
# @option options [String] :url Base URL
# @option options [Hash] :params Hash of URI query unencoded key/value pairs.
# @option options [Hash] :headers Hash of unencoded HTTP header key/value pairs.
# @option options [Hash] :params Hash of unencoded URI query params.
# @option options [Hash] :headers Hash of unencoded HTTP headers.
# @option options [Hash] :request Hash of request options.
# @option options [Hash] :ssl Hash of SSL options.
# @option options [Hash] :proxy Hash of Proxy options.
@ -78,8 +79,8 @@ module Faraday
# Faraday.new url: 'http://faraday.com',
# params: { page: 1 }
# # => Faraday::Connection to http://faraday.com?page=1
def new(url = nil, options = nil, &block)
options = options ? default_connection_options.merge(options) : default_connection_options
def new(url = nil, options = {}, &block)
options = default_connection_options.merge(options)
Faraday::Connection.new(url, options, &block)
end
@ -126,11 +127,13 @@ module Faraday
# @overload default_connection
# Gets the default connection used for simple scripts.
# @return [Faraday::Connection] a connection configured with the {.default_adapter}.
# @return [Faraday::Connection] a connection configured with
# the default_adapter.
# @overload default_connection=(connection)
# @param connection [Faraday::Connection]
# Sets the default {Faraday::Connection} for simple scripts that
# access the Faraday constant directly, such as <code>Faraday.get "https://faraday.com"</code>.
# access the Faraday constant directly, such as
# <code>Faraday.get "https://faraday.com"</code>.
def self.default_connection
@default_connection ||= Connection.new(default_connection_options)
end
@ -156,7 +159,8 @@ module Faraday
end
require_libs 'utils', 'options', 'connection', 'rack_builder', 'parameters',
'middleware', 'adapter', 'request', 'response', 'upload_io', 'error'
'middleware', 'adapter', 'request', 'response', 'upload_io',
'error'
require_lib 'autoload' unless ENV['FARADAY_NO_AUTOLOAD']
end

View File

@ -12,7 +12,10 @@ module Faraday
register_middleware File.expand_path('adapter', __dir__),
test: [:Test, 'test'],
net_http: [:NetHttp, 'net_http'],
net_http_persistent: [:NetHttpPersistent, 'net_http_persistent'],
net_http_persistent: [
:NetHttpPersistent,
'net_http_persistent'
],
typhoeus: [:Typhoeus, 'typhoeus'],
patron: [:Patron, 'patron'],
em_synchrony: [:EMSynchrony, 'em_synchrony'],

View File

@ -68,14 +68,18 @@ module Faraday
# Reads out timeout settings from env into options
def configure_timeout(options, env)
timeout, open_timeout = request_options(env).values_at(:timeout, :open_timeout)
timeout, open_timeout = request_options(env)
.values_at(:timeout, :open_timeout)
options[:connect_timeout] = options[:inactivity_timeout] = timeout
options[:connect_timeout] = open_timeout if open_timeout
end
# Reads out compression header settings from env into options
def configure_compression(options, env)
options[:head]['accept-encoding'] = 'gzip, compressed' if (env[:method] == :get) && !options[:head].key?('accept-encoding')
return unless (env[:method] == :get) &&
!options[:head].key?('accept-encoding')
options[:head]['accept-encoding'] = 'gzip, compressed'
end
def request_options(env)
@ -130,11 +134,16 @@ module Faraday
raise_error(error) if error
end
rescue EventMachine::Connectify::CONNECTError => err
raise Faraday::ConnectionFailed, %(407 "Proxy Authentication Required ") if err.message.include?('Proxy Authentication Required')
if err.message.include?('Proxy Authentication Required')
raise Faraday::ConnectionFailed,
%(407 "Proxy Authentication Required ")
end
raise Faraday::ConnectionFailed, err
rescue StandardError => err
raise Faraday::SSLError, err if defined?(OpenSSL) && err.is_a?(OpenSSL::SSL::SSLError)
if defined?(OpenSSL) && err.is_a?(OpenSSL::SSL::SSLError)
raise Faraday::SSLError, err
end
raise
end
@ -142,23 +151,30 @@ module Faraday
# TODO: reuse the connection to support pipelining
def perform_single_request(env)
req = create_request(env)
req.setup_request(env[:method], request_config(env)).callback do |client|
req = req.setup_request(env[:method], request_config(env))
req.callback do |client|
if env[:request].stream_response?
warn "Streaming downloads for #{self.class.name} are not yet implemented."
env[:request].on_data.call(client.response, client.response.bytesize)
warn "Streaming downloads for #{self.class.name} " \
'are not yet implemented.'
env[:request].on_data.call(
client.response,
client.response.bytesize
)
end
status = client.response_header.status
reason = client.response_header.http_reason
save_response(env, status, client.response, nil, reason) do |resp_headers|
save_response(env, status, client.response, nil, reason) do |headers|
client.response_header.each do |name, value|
resp_headers[name.to_sym] = value
headers[name.to_sym] = value
end
end
end
end
def create_request(env)
EventMachine::HttpRequest.new(env[:url], connection_config(env).merge(@connection_options))
EventMachine::HttpRequest.new(
env[:url], connection_config(env).merge(@connection_options)
)
end
def error_message(client)
@ -167,7 +183,7 @@ module Faraday
def raise_error(msg)
error_class = Faraday::ClientError
if msg == Errno::ETIMEDOUT || (msg.is_a?(String) && msg.include?('timeout error'))
if timeout_message?(msg)
error_class = Faraday::TimeoutError
msg = 'request timed out'
elsif msg == Errno::ECONNREFUSED
@ -179,6 +195,11 @@ module Faraday
raise error_class, msg
end
def timeout_message?(msg)
msg == Errno::ETIMEDOUT ||
(msg.is_a?(String) && msg.include?('timeout error'))
end
# @return [Boolean]
def parallel?(env)
!!env[:parallel_manager]
@ -223,7 +244,9 @@ module Faraday
perform_request(&proc)
end
end
raise Faraday::ClientError, @errors.first || 'connection failed' unless @errors.empty?
unless @errors.empty?
raise Faraday::ClientError, @errors.first || 'connection failed'
end
end
ensure
reset
@ -253,7 +276,8 @@ if Faraday::Adapter::EMHttp.loaded?
begin
require 'openssl'
rescue LoadError
warn 'Warning: no such file to load -- openssl. Make sure it is installed if you want HTTPS support'
warn 'Warning: no such file to load -- openssl. ' \
'Make sure it is installed if you want HTTPS support'
else
require 'faraday/adapter/em_http_ssl_patch'
end

View File

@ -12,7 +12,10 @@ module EmHttpSslPatch
return false
end
raise OpenSSL::SSL::SSLError, %(unable to verify the server certificate for "#{host}") unless certificate_store.verify(@last_seen_cert)
unless certificate_store.verify(@last_seen_cert)
raise OpenSSL::SSL::SSLError,
%(unable to verify the server certificate for "#{host}")
end
begin
certificate_store.add_cert(@last_seen_cert)
@ -25,7 +28,10 @@ module EmHttpSslPatch
def ssl_handshake_completed
return true unless verify_peer?
raise OpenSSL::SSL::SSLError, %(host "#{host}" does not match the server certificate) unless verified_cert_identity?
unless verified_cert_identity?
raise OpenSSL::SSL::SSLError,
%(host "#{host}" does not match the server certificate)
end
true
end

View File

@ -27,78 +27,112 @@ module Faraday
http_method = env[:method].to_s.downcase.to_sym
# Queue requests for parallel execution.
if env[:parallel_manager]
env[:parallel_manager].add(request, http_method, request_config(env)) do |resp|
if (req = env[:request]).stream_response?
warn "Streaming downloads for #{self.class.name} are not yet implemented."
req.on_data.call(resp.response, resp.response.bytesize)
end
save_response(env, resp.response_header.status, resp.response) do |resp_headers|
resp.response_header.each do |name, value|
resp_headers[name.to_sym] = value
end
end
# Finalize the response object with values from `env`.
env[:response].finish(env)
end
# Execute single request.
# Queue requests for parallel execution.
execute_parallel_request(env, request, http_method)
else
client = nil
block = -> { request.send(http_method, request_config(env)) }
if !EM.reactor_running?
EM.run do
Fiber.new do
client = block.call
EM.stop
end.resume
end
else
client = block.call
end
raise client.error if client.error
if env[:request].stream_response?
warn "Streaming downloads for #{self.class.name} are not yet implemented."
env[:request].on_data.call(client.response, client.response.bytesize)
end
status = client.response_header.status
reason = client.response_header.http_reason
save_response(env, status, client.response, nil, reason) do |resp_headers|
client.response_header.each do |name, value|
resp_headers[name.to_sym] = value
end
end
# Execute single request.
execute_single_request(env, request, http_method)
end
@app.call env
rescue Errno::ECONNREFUSED
raise Faraday::ConnectionFailed, $ERROR_INFO
rescue EventMachine::Connectify::CONNECTError => err
raise Faraday::ConnectionFailed, %(407 "Proxy Authentication Required ") if err.message.include?('Proxy Authentication Required')
if err.message.include?('Proxy Authentication Required')
raise Faraday::ConnectionFailed,
%(407 "Proxy Authentication Required")
end
raise Faraday::ConnectionFailed, err
rescue Errno::ETIMEDOUT => err
raise Faraday::TimeoutError, err
rescue RuntimeError => err
raise Faraday::ConnectionFailed, err if err.message == 'connection closed by server'
if err.message == 'connection closed by server'
raise Faraday::ConnectionFailed, err
end
raise Faraday::TimeoutError, err if err.message.include?('timeout error')
if err.message.include?('timeout error')
raise Faraday::TimeoutError, err
end
raise
rescue StandardError => err
raise Faraday::SSLError, err if defined?(OpenSSL) && err.is_a?(OpenSSL::SSL::SSLError)
if defined?(OpenSSL) && err.is_a?(OpenSSL::SSL::SSLError)
raise Faraday::SSLError, err
end
raise
end
def create_request(env)
EventMachine::HttpRequest.new(Utils::URI(env[:url].to_s), connection_config(env).merge(@connection_options))
EventMachine::HttpRequest.new(
Utils::URI(env[:url].to_s),
connection_config(env).merge(@connection_options)
)
end
private
def execute_parallel_request(env, request, http_method)
env[:parallel_manager].add(request, http_method,
request_config(env)) do |resp|
if (req = env[:request]).stream_response?
warn "Streaming downloads for #{self.class.name} " \
'are not yet implemented.'
req.on_data.call(resp.response, resp.response.bytesize)
end
save_response(env, resp.response_header.status,
resp.response) do |resp_headers|
resp.response_header.each do |name, value|
resp_headers[name.to_sym] = value
end
end
# Finalize the response object with values from `env`.
env[:response].finish(env)
end
end
def execute_single_request(env, request, http_method)
block = -> { request.send(http_method, request_config(env)) }
client = call_block(block)
raise client.error if client&.error
if env[:request].stream_response?
warn "Streaming downloads for #{self.class.name} " \
'are not yet implemented.'
env[:request].on_data.call(
client.response,
client.response.bytesize
)
end
status = client.response_header.status
reason = client.response_header.http_reason
save_response(env, status, client.response, nil, reason) do |headers|
client.response_header.each do |name, value|
headers[name.to_sym] = value
end
end
end
def call_block(block)
client = nil
if EM.reactor_running?
client = block.call
else
EM.run do
Fiber.new do
client = block.call
EM.stop
end.resume
end
end
client
end
end
end
@ -110,7 +144,8 @@ if Faraday::Adapter::EMSynchrony.loaded?
begin
require 'openssl'
rescue LoadError
warn 'Warning: no such file to load -- openssl. Make sure it is installed if you want HTTPS support'
warn 'Warning: no such file to load -- openssl. ' \
'Make sure it is installed if you want HTTPS support'
else
require 'faraday/adapter/em_http_ssl_patch'
end

View File

@ -44,7 +44,8 @@ module Faraday
header: env[:request_headers]
if (req = env[:request]).stream_response?
warn "Streaming downloads for #{self.class.name} are not yet implemented."
warn "Streaming downloads for #{self.class.name} " \
'are not yet implemented.'
req.on_data.call(resp.body, resp.body.bytesize)
end
save_response env, resp.status, resp.body, resp.headers, resp.reason
@ -53,13 +54,18 @@ module Faraday
rescue ::HTTPClient::TimeoutError, Errno::ETIMEDOUT
raise Faraday::TimeoutError, $ERROR_INFO
rescue ::HTTPClient::BadResponseError => err
raise Faraday::ConnectionFailed, %(407 "Proxy Authentication Required ") if err.message.include?('status 407')
if err.message.include?('status 407')
raise Faraday::ConnectionFailed,
%(407 "Proxy Authentication Required ")
end
raise Faraday::ClientError, $ERROR_INFO
rescue Errno::ECONNREFUSED, IOError, SocketError
raise Faraday::ConnectionFailed, $ERROR_INFO
rescue StandardError => err
raise Faraday::SSLError, err if defined?(OpenSSL) && err.is_a?(OpenSSL::SSL::SSLError)
if defined?(OpenSSL) && err.is_a?(OpenSSL::SSL::SSLError)
raise Faraday::SSLError, err
end
raise
end
@ -75,7 +81,9 @@ module Faraday
# @param proxy [Hash]
def configure_proxy(proxy)
client.proxy = proxy[:uri]
client.set_proxy_auth(proxy[:user], proxy[:password]) if proxy[:user] && proxy[:password]
return unless proxy[:user] && proxy[:password]
client.set_proxy_auth(proxy[:user], proxy[:password])
end
# @param ssl [Hash]
@ -130,7 +138,8 @@ module Faraday
def ssl_verify_mode(ssl)
ssl[:verify_mode] || begin
if ssl.fetch(:verify, true)
OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
OpenSSL::SSL::VERIFY_PEER |
OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
else
OpenSSL::SSL::VERIFY_NONE
end

View File

@ -3,7 +3,8 @@
begin
require 'net/https'
rescue LoadError
warn 'Warning: no such file to load -- net/https. Make sure openssl is installed if you want ssl support'
warn 'Warning: no such file to load -- net/https. ' \
'Make sure openssl is installed if you want ssl support'
require 'net/http'
end
require 'zlib'
@ -41,18 +42,24 @@ module Faraday
def call(env)
super
with_net_http_connection(env) do |http|
configure_ssl(http, env[:ssl]) if (env[:url].scheme == 'https') && env[:ssl]
if (env[:url].scheme == 'https') && env[:ssl]
configure_ssl(http, env[:ssl])
end
configure_request(http, env[:request])
begin
http_response = perform_request(http, env)
rescue *NET_HTTP_EXCEPTIONS => err
raise Faraday::SSLError, err if defined?(OpenSSL) && err.is_a?(OpenSSL::SSL::SSLError)
if defined?(OpenSSL) && err.is_a?(OpenSSL::SSL::SSLError)
raise Faraday::SSLError, err
end
raise Faraday::ConnectionFailed, err
end
save_response(env, http_response.code.to_i, http_response.body || '', nil, http_response.message) do |response_headers|
save_response(env, http_response.code.to_i,
http_response.body || '', nil,
http_response.message) do |response_headers|
http_response.each_header do |key, value|
response_headers[key] = value
end
@ -68,11 +75,11 @@ module Faraday
def create_request(env)
request = Net::HTTPGenericRequest.new \
env[:method].to_s.upcase, # request method
!!env[:body], # is there request body
env[:method] != :head, # is there response body
env[:url].request_uri, # request uri path
env[:request_headers] # request headers
env[:method].to_s.upcase, # request method
!!env[:body], # is there request body
env[:method] != :head, # is there response body
env[:url].request_uri, # request uri path
env[:request_headers] # request headers
if env[:body].respond_to?(:read)
request.body_stream = env[:body]
@ -86,7 +93,7 @@ module Faraday
if env[:request].stream_response?
size = 0
yielded = false
http_response = perform_request_with_wrapped_block(http, env) do |chunk|
http_response = request_with_wrapped_block(http, env) do |chunk|
if chunk.bytesize.positive? || size.positive?
yielded = true
size += chunk.bytesize
@ -94,15 +101,16 @@ module Faraday
end
end
env[:request].on_data.call('', 0) unless yielded
# Net::HTTP returns something, but it's not meaningful according to the docs.
# Net::HTTP returns something,
# but it's not meaningful according to the docs.
http_response.body = nil
http_response
else
perform_request_with_wrapped_block(http, env)
request_with_wrapped_block(http, env)
end
end
def perform_request_with_wrapped_block(http, env, &block)
def request_with_wrapped_block(http, env, &block)
if (env[:method] == :get) && !env[:body]
# prefer `get` to `request` because the former handles gzip (ruby 1.9)
request_via_get_method(http, env, &block)
@ -130,36 +138,43 @@ module Faraday
end
def net_http_connection(env)
if (proxy = env[:request][:proxy])
Net::HTTP::Proxy(proxy[:uri].hostname, proxy[:uri].port, proxy[:user], proxy[:password])
else
Net::HTTP
end.new(env[:url].hostname, env[:url].port || (env[:url].scheme == 'https' ? 443 : 80))
klass = if (proxy = env[:request][:proxy])
Net::HTTP::Proxy(proxy[:uri].hostname, proxy[:uri].port,
proxy[:user], proxy[:password])
else
Net::HTTP
end
port = env[:url].port || (env[:url].scheme == 'https' ? 443 : 80)
klass.new(env[:url].hostname, port)
end
def configure_ssl(http, ssl)
http.use_ssl = true
http.verify_mode = ssl_verify_mode(ssl)
http.cert_store = ssl_cert_store(ssl)
http.use_ssl = true
http.verify_mode = ssl_verify_mode(ssl)
http.cert_store = ssl_cert_store(ssl)
http.cert = ssl[:client_cert] if ssl[:client_cert]
http.key = ssl[:client_key] if ssl[:client_key]
http.ca_file = ssl[:ca_file] if ssl[:ca_file]
http.ca_path = ssl[:ca_path] if ssl[:ca_path]
http.cert = ssl[:client_cert] if ssl[:client_cert]
http.key = ssl[:client_key] if ssl[:client_key]
http.ca_file = ssl[:ca_file] if ssl[:ca_file]
http.ca_path = ssl[:ca_path] if ssl[:ca_path]
http.verify_depth = ssl[:verify_depth] if ssl[:verify_depth]
http.ssl_version = ssl[:version] if ssl[:version]
http.min_version = ssl[:min_version] if ssl[:min_version]
http.max_version = ssl[:max_version] if ssl[:max_version]
http.ssl_version = ssl[:version] if ssl[:version]
http.min_version = ssl[:min_version] if ssl[:min_version]
http.max_version = ssl[:max_version] if ssl[:max_version]
end
def configure_request(http, req)
if req[:timeout]
http.read_timeout = req[:timeout]
http.open_timeout = req[:timeout]
http.write_timeout = req[:timeout] if http.respond_to?(:write_timeout=)
http.read_timeout = req[:timeout]
http.open_timeout = req[:timeout]
if http.respond_to?(:write_timeout=)
http.write_timeout = req[:timeout]
end
end
http.open_timeout = req[:open_timeout] if req[:open_timeout]
if req[:write_timeout] && http.respond_to?(:write_timeout=)
http.write_timeout = req[: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=)

View File

@ -10,25 +10,35 @@ module Faraday
def net_http_connection(env)
@cached_connection ||=
if Net::HTTP::Persistent.instance_method(:initialize).parameters.first == %i[key name]
if Net::HTTP::Persistent.instance_method(:initialize)
.parameters.first == %i[key name]
options = { name: 'Faraday' }
options[:pool_size] = @connection_options[:pool_size] if @connection_options.key?(:pool_size)
if @connection_options.key?(:pool_size)
options[:pool_size] = @connection_options[:pool_size]
end
Net::HTTP::Persistent.new(options)
else
Net::HTTP::Persistent.new('Faraday')
end
proxy_uri = proxy_uri(env)
@cached_connection.proxy = proxy_uri if @cached_connection.proxy_uri != proxy_uri
if @cached_connection.proxy_uri != proxy_uri
@cached_connection.proxy = proxy_uri
end
@cached_connection
end
def proxy_uri(env)
proxy_uri = nil
if (proxy = env[:request][:proxy])
proxy_uri = proxy[:uri].is_a?(::URI::HTTP) ? proxy[:uri].dup : ::URI.parse(proxy[:uri].to_s)
proxy_uri = if proxy[:uri].is_a?(::URI::HTTP)
proxy[:uri].dup
else
::URI.parse(proxy[:uri].to_s)
end
proxy_uri.user = proxy_uri.password = nil
# awful patch for net-http-persistent 2.8 not unescaping user/password
# awful patch for net-http-persistent 2.8
# not unescaping user/password
if proxy[:user]
(class << proxy_uri; self; end).class_eval do
define_method(:user) { proxy[:user] }
@ -46,7 +56,9 @@ module Faraday
rescue Net::HTTP::Persistent::Error => error
raise Faraday::TimeoutError, error if error.message.include? 'Timeout'
raise Faraday::ConnectionFailed, error if error.message.include? 'connection refused'
if error.message.include? 'connection refused'
raise Faraday::ConnectionFailed, error
end
raise
end

View File

@ -13,43 +13,57 @@ module Faraday
session = ::Patron::Session.new
@config_block&.call(session)
configure_ssl(session, env[:ssl]) if (env[:url].scheme == 'https') && env[:ssl]
if (env[:url].scheme == 'https') && env[:ssl]
configure_ssl(session, env[:ssl])
end
if (req = env[:request])
session.timeout = session.connect_timeout = req[:timeout] if req[:timeout]
session.connect_timeout = req[:open_timeout] if req[:open_timeout]
if req[:timeout]
session.timeout = session.connect_timeout = req[:timeout]
end
session.connect_timeout = req[:open_timeout] if req[:open_timeout]
if (proxy = req[:proxy])
proxy_uri = proxy[:uri].dup
proxy_uri.user = proxy[:user] && Utils.escape(proxy[:user]).gsub('+', '%20')
proxy_uri.password = proxy[:password] && Utils.escape(proxy[:password]).gsub('+', '%20')
proxy_uri.user = proxy[:user] &&
Utils.escape(proxy[:user]).gsub('+', '%20')
proxy_uri.password = proxy[:password] &&
Utils.escape(proxy[:password]).gsub('+', '%20')
session.proxy = proxy_uri.to_s
end
end
response = begin
data = env[:body] ? env[:body].to_s : nil
session.request(env[:method], env[:url].to_s, env[:request_headers], data: data)
session.request(env[:method], env[:url].to_s,
env[:request_headers], data: data)
rescue Errno::ECONNREFUSED, ::Patron::ConnectionFailed
raise Faraday::ConnectionFailed, $ERROR_INFO
end
if (req = env[:request]).stream_response?
warn "Streaming downloads for #{self.class.name} are not yet implemented."
warn "Streaming downloads for #{self.class.name} " \
'are not yet implemented.'
req.on_data.call(response.body, response.body.bytesize)
end
# Remove the "HTTP/1.1 200", leaving just the reason phrase
reason_phrase = response.status_line.gsub(/^.* \d{3} /, '')
save_response(env, response.status, response.body, response.headers, reason_phrase)
save_response(env, response.status, response.body,
response.headers, reason_phrase)
@app.call env
rescue ::Patron::TimeoutError => err
raise Faraday::ConnectionFailed, err if connection_timed_out_message?(err.message)
if connection_timed_out_message?(err.message)
raise Faraday::ConnectionFailed, err
end
raise Faraday::TimeoutError, err
rescue ::Patron::Error => err
raise Faraday::ConnectionFailed, %(407 "Proxy Authentication Required ") if err.message.include?('code 407')
if err.message.include?('code 407')
raise Faraday::ConnectionFailed,
%(407 "Proxy Authentication Required ")
end
raise Faraday::ConnectionFailed, err
end
@ -91,7 +105,9 @@ module Faraday
].freeze
def connection_timed_out_message?(message)
CURL_TIMEOUT_MESSAGES.any? { |curl_message| message.include?(curl_message) }
CURL_TIMEOUT_MESSAGES.any? do |curl_message|
message.include?(curl_message)
end
end
end
end

View File

@ -29,11 +29,7 @@ module Faraday
def call(env)
super
rack_env = {
method: env[:method],
input: env[:body].respond_to?(:read) ? env[:body].read : env[:body],
'rack.url_scheme' => env[:url].scheme
}
rack_env = build_rack_env(env)
env[:request_headers]&.each do |name, value|
name = name.upcase.tr('-', '_')
@ -43,13 +39,16 @@ module Faraday
timeout = env[:request][:timeout] || env[:request][:open_timeout]
response = if timeout
Timer.timeout(timeout, Faraday::TimeoutError) { execute_request(env, rack_env) }
Timer.timeout(timeout, Faraday::TimeoutError) do
execute_request(env, rack_env)
end
else
execute_request(env, rack_env)
end
if (req = env[:request]).stream_response?
warn "Streaming downloads for #{self.class.name} are not yet implemented."
warn "Streaming downloads for #{self.class.name} " \
'are not yet implemented.'
req.on_data.call(response.body, response.body.bytesize)
end
@ -57,9 +56,19 @@ module Faraday
@app.call env
end
private
def execute_request(env, rack_env)
@session.request(env[:url].to_s, rack_env)
end
def build_rack_env(env)
{
method: env[:method],
input: env[:body].respond_to?(:read) ? env[:body].read : env[:body],
'rack.url_scheme' => env[:url].scheme
}
end
end
end
end

View File

@ -122,10 +122,14 @@ module Faraday
if path.is_a?(Regexp)
path
else
[Faraday::Utils.normalize_path(path), Faraday::Utils.URI(path).host]
[
Faraday::Utils.normalize_path(path),
Faraday::Utils.URI(path).host
]
end
(@stack[request_method] ||= []) << Stub.new(host, normalized_path, headers, body, block)
stub = Stub.new(host, normalized_path, headers, body, block)
(@stack[request_method] ||= []) << stub
end
def matches?(stack, host, path, headers, body)
@ -138,7 +142,9 @@ module Faraday
end
# Stub request
class Stub < Struct.new(:host, :path, :params, :headers, :body, :block) # rubocop:disable Style/StructInheritance
# rubocop:disable Style/StructInheritance
class Stub < Struct.new(:host, :path, :params, :headers, :body, :block)
# rubocop:enable Style/StructInheritance
def initialize(host, full, headers, body, block)
path, query = full.respond_to?(:split) ? full.split('?') : full
params =
@ -208,9 +214,11 @@ module Faraday
super
host = env[:url].host
normalized_path = Faraday::Utils.normalize_path(env[:url])
params_encoder = env.request.params_encoder || Faraday::Utils.default_params_encoder
params_encoder = env.request.params_encoder ||
Faraday::Utils.default_params_encoder
stub, meta = stubs.match(env[:method], host, normalized_path, env.request_headers, env[:body])
stub, meta = stubs.match(env[:method], host, normalized_path,
env.request_headers, env[:body])
unless stub
raise Stubs::NotFound, "no stubbed request for #{env[:method]} "\

View File

@ -2,7 +2,8 @@
module Faraday
class Adapter
# Typhoeus adapter. This class is just a stub, the real adapter is in https://github.com/philsturgeon/typhoeus/blob/master/lib/typhoeus/adapters/faraday.rb
# Typhoeus adapter. This class is just a stub, the real adapter is in
# https://github.com/philsturgeon/typhoeus/blob/master/lib/typhoeus/adapters/faraday.rb
class Typhoeus < Faraday::Adapter
# Needs to define this method in order to support Typhoeus <= 1.3.0
def call; end

View File

@ -8,9 +8,9 @@ module Faraday
module AutoloadHelper
# Registers the constants to be auto loaded.
#
# @param prefix [String] The require prefix. If the path is inside Faraday, then
# it will be prefixed with the root path of this loaded Faraday
# version.
# @param prefix [String] The require prefix. If the path is inside Faraday,
# then it will be prefixed with the root path of this loaded
# Faraday version.
# @param options [{ Symbol => String }] library names.
#
# @example
@ -24,7 +24,10 @@ module Faraday
#
# @return [void]
def autoload_all(prefix, options)
prefix = File.join(Faraday.root_path, prefix) if prefix =~ %r{^faraday(/|$)}i
if prefix =~ %r{^faraday(/|$)}i
prefix = File.join(Faraday.root_path, prefix)
end
options.each do |const_name, path|
autoload const_name, File.join(prefix, path)
end

View File

@ -47,11 +47,14 @@ module Faraday
# requests (optional).
# @param options [Hash, Faraday::ConnectionOptions]
# @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<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.
# @option options [Hash] :ssl Hash of SSL options.
# @option options [Hash, URI, String] :proxy proxy options, either as a URL or as a Hash
# @option options [Hash, URI, String] :proxy proxy options, either as a URL
# or as a Hash
# @option options [URI, String] :proxy[:uri]
# @option options [String] :proxy[:user]
# @option options [String] :proxy[:password]
@ -81,15 +84,24 @@ module Faraday
@params.update(options.params) if options.params
@headers.update(options.headers) if options.headers
@manual_proxy = !!options.proxy
@proxy = options.proxy ? ProxyOptions.from(options.proxy) : proxy_from_env(url)
@temp_proxy = @proxy
initialize_proxy(url, options)
yield(self) if block_given?
@headers[:user_agent] ||= "Faraday v#{VERSION}"
end
def initialize_proxy(url, options)
@manual_proxy = !!options.proxy
@proxy =
if options.proxy
ProxyOptions.from(options.proxy)
else
proxy_from_env(url)
end
@temp_proxy = @proxy
end
# Sets the Hash of URI query unencoded key/value pairs.
# @param hash [Hash]
def params=(hash)
@ -110,8 +122,8 @@ module Faraday
# Makes a GET HTTP request without a body.
# @!scope class
#
# @param url [String] The optional String base URL to use as a prefix for all
# requests. Can also be the options Hash.
# @param url [String] The optional String base URL to use as a prefix for
# all requests. Can also be the options Hash.
# @param params [Hash] Hash of URI query unencoded key/value pairs.
# @param headers [Hash] unencoded HTTP header key/value pairs.
#
@ -132,8 +144,8 @@ module Faraday
# Makes a HEAD HTTP request without a body.
# @!scope class
#
# @param url [String] The optional String base URL to use as a prefix for all
# requests. Can also be the options Hash.
# @param url [String] The optional String base URL to use as a prefix for
# all requests. Can also be the options Hash.
# @param params [Hash] Hash of URI query unencoded key/value pairs.
# @param headers [Hash] unencoded HTTP header key/value pairs.
#
@ -147,8 +159,8 @@ module Faraday
# Makes a DELETE HTTP request without a body.
# @!scope class
#
# @param url [String] The optional String base URL to use as a prefix for all
# requests. Can also be the options Hash.
# @param url [String] The optional String base URL to use as a prefix for
# all requests. Can also be the options Hash.
# @param params [Hash] Hash of URI query unencoded key/value pairs.
# @param headers [Hash] unencoded HTTP header key/value pairs.
#
@ -162,8 +174,8 @@ module Faraday
# Makes a CONNECT HTTP request without a body.
# @!scope class
#
# @param url [String] The optional String base URL to use as a prefix for all
# requests. Can also be the options Hash.
# @param url [String] The optional String base URL to use as a prefix for
# all requests. Can also be the options Hash.
# @param params [Hash] Hash of URI query unencoded key/value pairs.
# @param headers [Hash] unencoded HTTP header key/value pairs.
#
@ -177,8 +189,8 @@ module Faraday
# Makes a TRACE HTTP request without a body.
# @!scope class
#
# @param url [String] The optional String base URL to use as a prefix for all
# requests. Can also be the options Hash.
# @param url [String] The optional String base URL to use as a prefix for
# all requests. Can also be the options Hash.
# @param params [Hash] Hash of URI query unencoded key/value pairs.
# @param headers [Hash] unencoded HTTP header key/value pairs.
#
@ -204,8 +216,8 @@ module Faraday
# Makes an OPTIONS HTTP request without a body.
# @!scope class
#
# @param url [String] The optional String base URL to use as a prefix for all
# requests. Can also be the options Hash.
# @param url [String] The optional String base URL to use as a prefix for
# all requests. Can also be the options Hash.
# @param params [Hash] Hash of URI query unencoded key/value pairs.
# @param headers [Hash] unencoded HTTP header key/value pairs.
#
@ -228,8 +240,8 @@ module Faraday
# Makes a POST HTTP request with a body.
# @!scope class
#
# @param url [String] The optional String base URL to use as a prefix for all
# requests. Can also be the options Hash.
# @param url [String] The optional String base URL to use as a prefix for
# all requests. Can also be the options Hash.
# @param body [String] body for the request.
# @param headers [Hash] unencoded HTTP header key/value pairs.
#
@ -250,8 +262,8 @@ module Faraday
# Makes a PUT HTTP request with a body.
# @!scope class
#
# @param url [String] The optional String base URL to use as a prefix for all
# requests. Can also be the options Hash.
# @param url [String] The optional String base URL to use as a prefix for
# all requests. Can also be the options Hash.
# @param body [String] body for the request.
# @param headers [Hash] unencoded HTTP header key/value pairs.
#
@ -344,7 +356,7 @@ module Faraday
@default_parallel_manager ||= begin
adapter = @builder.adapter.klass if @builder.adapter
if adapter&.respond_to?(:supports_parallel?) && adapter&.supports_parallel?
if support_parallel?(adapter)
adapter.setup_parallel_manager
elsif block_given?
yield
@ -361,13 +373,15 @@ module Faraday
# Sets up the parallel manager to make a set of requests.
#
# @param manager [Object] The parallel manager that this Connection's Adapter uses.
# @param manager [Object] The parallel manager that this Connection's
# Adapter uses.
#
# @yield a block to execute multiple requests.
# @return [void]
def in_parallel(manager = nil)
@parallel_manager = manager || default_parallel_manager do
warn 'Warning: `in_parallel` called but no parallel-capable adapter on Faraday stack'
warn 'Warning: `in_parallel` called but no parallel-capable adapter ' \
'on Faraday stack'
warn caller[2, 10].join("\n")
nil
end
@ -441,15 +455,23 @@ module Faraday
# conn.scheme # => https
# conn.path_prefix # => "/api"
#
# conn.build_url("nigiri?page=2") # => https://sushi.com/api/nigiri?token=abc&page=2
# conn.build_url("nigiri", page: 2) # => https://sushi.com/api/nigiri?token=abc&page=2
# conn.build_url("nigiri?page=2")
# # => https://sushi.com/api/nigiri?token=abc&page=2
#
# conn.build_url("nigiri", page: 2)
# # => https://sushi.com/api/nigiri?token=abc&page=2
#
def build_url(url = nil, extra_params = nil)
uri = build_exclusive_url(url)
query_values = params.dup.merge_query(uri.query, options.params_encoder)
query_values.update extra_params if extra_params
uri.query = query_values.empty? ? nil : query_values.to_query(options.params_encoder)
query_values.update(extra_params) if extra_params
uri.query =
if query_values.empty?
nil
else
query_values.to_query(options.params_encoder)
end
uri
end
@ -458,12 +480,15 @@ module Faraday
#
# @param method [Symbol] HTTP method.
# @param url [String, URI] String or URI to access.
# @param body [Object] The request body that will eventually be converted to a string.
# @param body [Object] The request body that will eventually be converted to
# a string.
# @param headers [Hash] unencoded HTTP header key/value pairs.
#
# @return [Faraday::Response]
def run_request(method, url, body, headers)
raise ArgumentError, "unknown http method: #{method}" unless METHODS.include?(method)
unless METHODS.include?(method)
raise ArgumentError, "unknown http method: #{method}"
end
# Resets temp_proxy
@temp_proxy = proxy_for_request(url)
@ -497,7 +522,8 @@ module Faraday
# Build an absolute URL based on url_prefix.
#
# @param url [String, URI]
# @param params [Faraday::Utils::ParamsHash] A Faraday::Utils::ParamsHash to replace the query values
# @param params [Faraday::Utils::ParamsHash] A Faraday::Utils::ParamsHash to
# replace the query values
# of the resulting url (default: nil).
#
# @return [URI]
@ -509,7 +535,9 @@ module Faraday
base.path = base.path + '/' # ensure trailing slash
end
uri = url ? base + url : base
uri.query = params.to_query(params_encoder || options.params_encoder) if params
if params
uri.query = params.to_query(params_encoder || options.params_encoder)
end
uri.query = nil if uri.query&.empty?
uri
end
@ -537,7 +565,9 @@ module Faraday
# @return [void]
# @api private
def with_uri_credentials(uri)
yield(Utils.unescape(uri.user), Utils.unescape(uri.password)) if uri.user && uri.password
return unless uri.user && uri.password
yield(Utils.unescape(uri.user), Utils.unescape(uri.password))
end
def set_authorization_header(header_type, *args)
@ -586,5 +616,9 @@ module Faraday
proxy
end
end
def support_parallel?(adapter)
adapter&.respond_to?(:supports_parallel?) && adapter&.supports_parallel?
end
end
end

View File

@ -4,7 +4,8 @@ module Faraday
module DependencyLoader
attr_reader :load_error
# Executes a block which should try to require and reference dependent libraries
# Executes a block which should try to require and reference dependent
# libraries
def dependency(lib = nil)
lib ? require(lib) : yield
rescue LoadError, NameError => error
@ -12,7 +13,9 @@ module Faraday
end
def new(*)
raise "missing dependency for #{self}: #{load_error.message}" unless loaded?
unless loaded?
raise "missing dependency for #{self}: #{load_error.message}"
end
super
end

View File

@ -56,7 +56,9 @@ module Faraday
split_query.each_with_object(empty_accumulator.dup) do |pair, accu|
pair[0] = unescape(pair[0])
pair[1] = true if pair[1].nil?
pair[1] = unescape(pair[1].to_str.tr('+', ' ')) if pair[1].respond_to?(:to_str)
if pair[1].respond_to?(:to_str)
pair[1] = unescape(pair[1].to_str.tr('+', ' '))
end
if accu[pair[0]].is_a?(Array)
accu[pair[0]] << pair[1]
elsif accu[pair[0]]

View File

@ -1,17 +1,8 @@
# frozen_string_literal: true
module Faraday
# This is the default encoder for Faraday requests.
# Using this encoder, parameters will be encoded respecting their structure,
# so you can send objects such as Arrays or Hashes as parameters for your requests.
module NestedParamsEncoder
class << self
extend Forwardable
def_delegators :'Faraday::Utils', :escape, :unescape
end
extend self
# Sub-module for encoding parameters into query-string.
module EncodeMethods
# @param params [nil, Array, #to_hash] parameters to be encoded
#
# @return [String] the encoded params
@ -21,7 +12,9 @@ module Faraday
return nil if params.nil?
unless params.is_a?(Array)
raise TypeError, "Can't convert #{params.class} into Hash." unless params.respond_to?(:to_hash)
unless params.respond_to?(:to_hash)
raise TypeError, "Can't convert #{params.class} into Hash."
end
params = params.to_hash
params = params.map do |key, value|
@ -42,43 +35,7 @@ module Faraday
buffer.chop
end
# @param query [nil, String]
#
# @return [Array<Array, String>] the decoded params
#
# @raise [TypeError] if the nesting is incorrect
def decode(query)
return nil if query.nil?
params = {}
query.split('&').each do |pair|
next if pair.empty?
key, value = pair.split('=', 2)
key = unescape(key)
value = unescape(value.tr('+', ' ')) if value
decode_pair(key, value, params)
end
dehash(params, 0)
end
private
SUBKEYS_REGEX = /[^\[\]]+(?:\]?\[\])?/.freeze
# Internal: convert a nested hash with purely numeric keys into an array.
# FIXME: this is not compatible with Rack::Utils.parse_nested_query
# @!visibility private
def dehash(hash, depth)
hash.each { |key, value| hash[key] = dehash(value, depth + 1) if value.is_a?(Hash) }
if depth.positive? && !hash.empty? && hash.keys.all? { |k| k =~ /^\d+$/ }
hash.sort.map(&:last)
else
hash
end
end
protected
def encode_pair(parent, value)
if value.is_a?(Hash)
@ -112,6 +69,34 @@ module Faraday
value.each { |val| buffer << "#{encode_pair(new_parent, val)}&" }
buffer.chop
end
end
# Sub-module for decoding query-string into parameters.
module DecodeMethods
# @param query [nil, String]
#
# @return [Array<Array, String>] the decoded params
#
# @raise [TypeError] if the nesting is incorrect
def decode(query)
return nil if query.nil?
params = {}
query.split('&').each do |pair|
next if pair.empty?
key, value = pair.split('=', 2)
key = unescape(key)
value = unescape(value.tr('+', ' ')) if value
decode_pair(key, value, params)
end
dehash(params, 0)
end
protected
SUBKEYS_REGEX = /[^\[\]]+(?:\]?\[\])?/.freeze
def decode_pair(key, value, context)
subkeys = key.scan(SUBKEYS_REGEX)
@ -126,14 +111,21 @@ module Faraday
end
def prepare_context(context, subkey, is_array, last_subkey)
context = new_context(subkey, is_array, context) if !last_subkey || is_array
context = match_context(context, subkey) if context.is_a?(Array) && !is_array
if !last_subkey || is_array
context = new_context(subkey, is_array, context)
end
if context.is_a?(Array) && !is_array
context = match_context(context, subkey)
end
context
end
def new_context(subkey, is_array, context)
value_type = is_array ? Array : Hash
raise TypeError, "expected #{value_type.name} (got #{context[subkey].class.name}) for param `#{subkey}'" if context[subkey] && !context[subkey].is_a?(value_type)
if context[subkey] && !context[subkey].is_a?(value_type)
raise TypeError, "expected #{value_type.name} " \
"(got #{context[subkey].class.name}) for param `#{subkey}'"
end
context[subkey] ||= value_type.new
end
@ -146,5 +138,34 @@ module Faraday
def add_to_context(is_array, context, value, subkey)
is_array ? context << value : context[subkey] = value
end
# Internal: convert a nested hash with purely numeric keys into an array.
# FIXME: this is not compatible with Rack::Utils.parse_nested_query
# @!visibility private
def dehash(hash, depth)
hash.each do |key, value|
hash[key] = dehash(value, depth + 1) if value.is_a?(Hash)
end
if depth.positive? && !hash.empty? && hash.keys.all? { |k| k =~ /^\d+$/ }
hash.sort.map(&:last)
else
hash
end
end
end
# This is the default encoder for Faraday requests.
# Using this encoder, parameters will be encoded respecting their structure,
# so you can send objects such as Arrays or Hashes as parameters
# for your requests.
module NestedParamsEncoder
class << self
extend Forwardable
def_delegators :'Faraday::Utils', :escape, :unescape
end
extend EncodeMethods
extend DecodeMethods
end
end

View File

@ -18,15 +18,27 @@ module Faraday
def_delegators :@logger, :debug, :info, :warn, :error, :fatal
def request(env)
info('request') { "#{env.method.upcase} #{apply_filters(env.url.to_s)}" }
debug('request') { apply_filters(dump_headers(env.request_headers)) } if log_headers?(:request)
debug('request') { apply_filters(dump_body(env[:body])) } if env[:body] && log_body?(:request)
info('request') do
"#{env.method.upcase} #{apply_filters(env.url.to_s)}"
end
if log_headers?(:request)
debug('request') { apply_filters(dump_headers(env.request_headers)) }
end
return unless env[:body] && log_body?(:request)
debug('request') { apply_filters(dump_body(env[:body])) }
end
def response(env)
info('response') { "Status #{env.status}" }
debug('response') { apply_filters(dump_headers(env.response_headers)) } if log_headers?(:response)
debug('response') { apply_filters(dump_body(env[:body])) } if env[:body] && log_body?(:response)
info('response') { "Status #{env.status}" }
if log_headers?(:response)
debug('response') do
apply_filters(dump_headers(env.response_headers))
end
end
return unless env[:body] && log_body?(:response)
debug('response') { apply_filters(dump_body(env[:body])) }
end
def filter(filter_word, filter_replacement)
@ -53,15 +65,19 @@ module Faraday
def log_headers?(type)
case @options[:headers]
when Hash then @options[:headers][type]
else @options[:headers]
when Hash
@options[:headers][type]
else
@options[:headers]
end
end
def log_body?(type)
case @options[:bodies]
when Hash then @options[:bodies][type]
else @options[:bodies]
when Hash
@options[:bodies][type]
else
@options[:bodies]
end
end

View File

@ -9,12 +9,17 @@ module Faraday
# Register middleware class(es) on the current module.
#
# @param autoload_path [String] Middleware autoload path
# @param mapping [Hash{Symbol => Module, Symbol, Array<Module, Symbol, String>}] Middleware mapping from a lookup symbol to a reference to the middleware. - Classes can be expressed as:
# - a fully qualified constant
# - a Symbol
# - a Proc that will be lazily called to return the former
# - an array is given, its first element is the constant or symbol,
# and its second is a file to `require`.
# @param mapping [Hash{
# Symbol => Module,
# Symbol => Array<Module, Symbol, String>,
# }] Middleware mapping from a lookup symbol to a reference to the
# middleware.
# Classes can be expressed as:
# - a fully qualified constant
# - a Symbol
# - a Proc that will be lazily called to return the former
# - an array is given, its first element is the constant or symbol,
# and its second is a file to `require`.
# @return [void]
#
# @example Lookup by a constant
@ -30,7 +35,8 @@ module Faraday
#
# module Faraday
# class Whatever
# # Middleware looked up by :bar returns Faraday::Whatever.const_get(:Bar)
# # Middleware looked up by :bar returns
# # Faraday::Whatever.const_get(:Bar)
# register_middleware bar: :Bar
# end
# end
@ -39,7 +45,8 @@ module Faraday
#
# module Faraday
# class Whatever
# # Middleware looked up by :baz requires 'baz' and returns Faraday::Whatever.const_get(:Baz)
# # Middleware looked up by :baz requires 'baz' and returns
# # Faraday::Whatever.const_get(:Baz)
# register_middleware baz: [:Baz, 'baz']
# end
# end

View File

@ -52,7 +52,11 @@ module Faraday
other.each do |key, other_value|
self_value = send(key)
sub_options = self.class.options_for(key)
new_value = self_value && sub_options && other_value ? self_value.merge(other_value) : other_value
new_value = if self_value && sub_options && other_value
self_value.merge(other_value)
else
other_value
end
send("#{key}=", new_value) unless new_value.nil?
end
self

View File

@ -2,7 +2,8 @@
module Faraday
class ConnectionOptions < Options.new(:request, :proxy, :ssl, :builder, :url,
:parallel_manager, :params, :headers, :builder_class)
:parallel_manager, :params, :headers,
:builder_class)
options request: RequestOptions, ssl: SSLOptions

View File

@ -5,7 +5,8 @@ module Faraday
# @return [Symbol] HTTP method (`:get`, `:post`)
#
# @!attribute body
# @return [String] The request body that will eventually be converted to a string.
# @return [String] The request body that will eventually be converted to a
# string.
#
# @!attribute url
# @return [URI] URI instance for the current request.
@ -45,8 +46,9 @@ module Faraday
#
# @!attribute reason_phrase
# @return [String]
class Env < Options.new(:method, :request_body, :url, :request, :request_headers,
:ssl, :parallel_manager, :params, :response, :response_headers, :status,
class Env < Options.new(:method, :request_body, :url, :request,
:request_headers, :ssl, :parallel_manager, :params,
:response, :response_headers, :status,
:reason_phrase, :response_body)
# rubocop:disable Naming/ConstantName
@ -72,7 +74,9 @@ module Faraday
# @return [Env] from given value
def self.from(value)
env = super(value)
env.custom_members.update(value.custom_members) if value.respond_to?(:custom_members)
if value.respond_to?(:custom_members)
env.custom_members.update(value.custom_members)
end
env
end
@ -119,7 +123,8 @@ module Faraday
SuccessfulStatuses.include?(status)
end
# @return [Boolean] true if there's no body yet, and the method is in the set of {MethodsWithBodies}.
# @return [Boolean] true if there's no body yet, and the method is in the
# set of {MethodsWithBodies}.
def needs_body?
!body && MethodsWithBodies.include?(method)
end
@ -130,7 +135,8 @@ module Faraday
self.body = ''
end
# @return [Boolean] true if the status isn't in the set of {StatusesWithoutBody}.
# @return [Boolean] true if the status isn't in the set of
# {StatusesWithoutBody}.
def parse_body?
!StatusesWithoutBody.include?(status)
end

View File

@ -3,7 +3,8 @@
module Faraday
class ProxyOptions < Options.new(:uri, :user, :password)
extend Forwardable
def_delegators :uri, :scheme, :scheme=, :host, :host=, :port, :port=, :path, :path=
def_delegators :uri, :scheme, :scheme=, :host, :host=, :port, :port=,
:path, :path=
def self.from(value)
case value

View File

@ -2,8 +2,8 @@
module Faraday
class RequestOptions < Options.new(:params_encoder, :proxy, :bind,
:timeout, :open_timeout, :write_timeout, :boundary,
:oauth, :context, :on_data)
:timeout, :open_timeout, :write_timeout,
:boundary, :oauth, :context, :on_data)
def []=(key, value)
if key && key.to_sym == :proxy

View File

@ -42,7 +42,8 @@ module Faraday
# @!attribute max_version
# @return [String, Symbol] maximum SSL version (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html#method-i-max_version-3D)
class SSLOptions < Options.new(:verify, :ca_file, :ca_path, :verify_mode,
:cert_store, :client_cert, :client_key, :certificate, :private_key, :verify_depth,
:cert_store, :client_cert, :client_key,
:certificate, :private_key, :verify_depth,
:version, :min_version, :max_version)
# @return [Boolean] true if should verify

View File

@ -79,7 +79,7 @@ module Faraday
@handlers[idx]
end
# Locks the middleware stack to ensure no further modifications are possible.
# Locks the middleware stack to ensure no further modifications are made.
def lock!
@handlers.freeze
end
@ -169,11 +169,15 @@ module Faraday
def to_app
# last added handler is the deepest and thus closest to the inner app
# adapter is always the last one
@handlers.reverse.inject(@adapter.build) { |app, handler| handler.build(app) }
@handlers.reverse.inject(@adapter.build) do |app, handler|
handler.build(app)
end
end
def ==(other)
other.is_a?(self.class) && @handlers == other.handlers && @adapter == other.adapter
other.is_a?(self.class) &&
@handlers == other.handlers &&
@adapter == other.adapter
end
def dup
@ -197,20 +201,28 @@ module Faraday
# :password - Proxy server password
# :ssl - Hash of options for configuring SSL requests.
def build_env(connection, request)
Env.new(request.method, request.body,
connection.build_exclusive_url(request.path, request.params, request.options.params_encoder),
exclusive_url = connection.build_exclusive_url(
request.path, request.params,
request.options.params_encoder
)
Env.new(request.method, request.body, exclusive_url,
request.options, request.headers, connection.ssl,
connection.parallel_manager)
end
private
LOCK_ERR = "can't modify middleware stack after making a request"
def raise_if_locked
raise StackLocked, "can't modify middleware stack after making a request" if locked?
raise StackLocked, LOCK_ERR if locked?
end
def raise_if_adapter(klass)
raise 'Adapter should be set using the `adapter` method, not `use`' if is_adapter?(klass)
return unless is_adapter?(klass)
raise 'Adapter should be set using the `adapter` method, not `use`'
end
def adapter_set?

View File

@ -36,8 +36,14 @@ module Faraday
multipart: [:Multipart, 'multipart'],
retry: [:Retry, 'retry'],
authorization: [:Authorization, 'authorization'],
basic_auth: [:BasicAuthentication, 'basic_authentication'],
token_auth: [:TokenAuthentication, 'token_authentication'],
basic_auth: [
:BasicAuthentication,
'basic_authentication'
],
token_auth: [
:TokenAuthentication,
'token_authentication'
],
instrumentation: [:Instrumentation, 'instrumentation']
# @param request_method [String]

View File

@ -16,7 +16,9 @@ module Faraday
when Hash
build_hash(type.to_s, token)
else
raise ArgumentError, "Can't build an Authorization #{type} header from #{token.inspect}"
raise ArgumentError,
"Can't build an Authorization #{type}" \
"header from #{token.inspect}"
end
end

View File

@ -21,20 +21,26 @@ module Faraday
#
# Measures time spent only for synchronous requests.
#
# @example Using ActiveSupport::Notifications to measure time spent for Faraday requests
# ActiveSupport::Notifications.subscribe('request.faraday') do |name, starts, ends, _, env|
# @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]
# $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.
# @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)
@name, @instrumenter = Options.from(options)
.values_at(:name, :instrumenter)
end
# @param env [Faraday::Env]

View File

@ -8,7 +8,9 @@ module Faraday
# Middleware for supporting multi-part requests.
class Multipart < UrlEncoded
self.mime_type = 'multipart/form-data'
DEFAULT_BOUNDARY_PREFIX = '-----------RubyMultipartPost' unless defined? DEFAULT_BOUNDARY_PREFIX
unless defined? DEFAULT_BOUNDARY_PREFIX
DEFAULT_BOUNDARY_PREFIX = '-----------RubyMultipartPost'
end
# Checks for files in the payload, otherwise leaves everything untouched.
#
@ -16,7 +18,8 @@ module Faraday
def call(env)
match_content_type(env) do |params|
env.request.boundary ||= unique_boundary
env.request_headers[CONTENT_TYPE] += "; boundary=#{env.request.boundary}"
env.request_headers[CONTENT_TYPE] +=
"; boundary=#{env.request.boundary}"
env.body = create_multipart(env, params)
end
@app.call env

View File

@ -20,14 +20,19 @@ module Faraday
# 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.
# 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.
class Retry < Faraday::Middleware
DEFAULT_EXCEPTIONS = [Errno::ETIMEDOUT, 'Timeout::Error', Faraday::TimeoutError, Faraday::RetriableResponse].freeze
DEFAULT_EXCEPTIONS = [
Errno::ETIMEDOUT, 'Timeout::Error',
Faraday::TimeoutError, Faraday::RetriableResponse
].freeze
IDEMPOTENT_METHODS = %i[delete get head options put].freeze
class Options < Faraday::Options.new(:max, :interval, :max_interval, :interval_randomness,
:backoff_factor, :exceptions, :methods, :retry_if, :retry_block,
class Options < Faraday::Options.new(:max, :interval, :max_interval,
:interval_randomness,
:backoff_factor, :exceptions,
:methods, :retry_if, :retry_block,
:retry_statuses)
DEFAULT_CHECK = ->(_env, _exception) { false }
@ -85,25 +90,30 @@ module Faraday
# @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.
# @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
# @option options [Array] :exceptions ([Errno::ETIMEDOUT, 'Timeout::Error',
# Faraday::TimeoutError, Faraday::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.
# @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.
# @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.
# @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.
# @option options [Integer] :max_interval (Float::MAX) An upper limit
# for the interval
# @option options [Integer] :backoff_factor (1) The amount to multiply
# each successive retry's interval amount by in order to provide backoff
# @option options [Array] :exceptions ([ Errno::ETIMEDOUT,
# 'Timeout::Error', Faraday::TimeoutError, Faraday::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.
# @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.
# @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)
@options = Options.from(options)
@ -111,12 +121,16 @@ module Faraday
end
def calculate_sleep_amount(retries, env)
retry_after = calculate_retry_after(env)
retry_interval = calculate_retry_interval(retries)
retry_after = calculate_retry_after(env)
retry_interval = calculate_retry_interval(retries)
return if retry_after && retry_after > @options.max_interval
retry_after && retry_after >= retry_interval ? retry_after : retry_interval
if retry_after && retry_after >= retry_interval
retry_after
else
retry_interval
end
end
# @param env [Faraday::Env]
@ -124,9 +138,12 @@ module Faraday
retries = @options.max
request_body = env[:body]
begin
env[:body] = request_body # after failure env[:body] is set to the response body
# after failure env[:body] is set to the response body
env[:body] = request_body
@app.call(env).tap do |resp|
raise Faraday::RetriableResponse.new(nil, resp) if @options.retry_statuses.include?(resp.status)
if @options.retry_statuses.include?(resp.status)
raise Faraday::RetriableResponse.new(nil, resp)
end
end
rescue @errmatch => exception
if retries.positive? && retry_request?(env, exception)
@ -145,15 +162,18 @@ module Faraday
end
end
# 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.
# 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
(
class << matcher
self
end).class_eval do
define_method(:===) do |error|
exceptions.any? do |ex|
if ex.is_a? Module
@ -170,7 +190,8 @@ module Faraday
private
def retry_request?(env, exception)
@options.methods.include?(env[:method]) || @options.retry_if.call(env, exception)
@options.methods.include?(env[:method]) ||
@options.retry_if.call(env, exception)
end
def rewind_files(body)
@ -181,7 +202,8 @@ module Faraday
end
end
# MDN spec for Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
# MDN spec for Retry-After header:
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
def calculate_retry_after(env)
response_headers = env[:response_headers]
return unless response_headers
@ -199,9 +221,11 @@ module Faraday
def calculate_retry_interval(retries)
retry_index = @options.max - retries
current_interval = @options.interval * (@options.backoff_factor**retry_index)
current_interval = @options.interval *
(@options.backoff_factor**retry_index)
current_interval = [current_interval, @options.max_interval].min
random_interval = rand * @options.interval_randomness.to_f * @options.interval
random_interval = rand * @options.interval_randomness.to_f *
@options.interval
current_interval + random_interval
end

View File

@ -18,7 +18,8 @@ module Faraday
raise Faraday::ResourceNotFound, response_values(env)
when 407
# mimic the behavior that we get with proxy requests with HTTPS
raise Faraday::ProxyAuthError.new(%(407 "Proxy Authentication Required"), response_values(env))
msg = %(407 "Proxy Authentication Required")
raise Faraday::ProxyAuthError.new(msg, response_values(env))
when 422
raise Faraday::UnprocessableEntityError, response_values(env)
when ClientErrorStatuses

View File

@ -7,7 +7,9 @@ require 'composite_io'
require 'parts'
module Faraday
# Similar to, but not compatible with [::CompositeReadIO](https://github.com/nicksieger/multipart-post/blob/master/lib/composite_io.rb) provided by [multipart-post](https://github.com/nicksieger/multipart-post).
# Similar to, but not compatible with CompositeReadIO provided by the
# multipart-post gem.
# https://github.com/nicksieger/multipart-post/blob/master/lib/composite_io.rb
class CompositeReadIO
def initialize(*parts)
@parts = parts.flatten

View File

@ -76,7 +76,8 @@ module Faraday
end
end
# Receives a String or URI and returns just the path with the query string sorted.
# Receives a String or URI and returns just
# the path with the query string sorted.
def normalize_path(url)
url = URI(url)
(url.path.start_with?('/') ? url.path : '/' + url.path) +

View File

@ -118,10 +118,10 @@ module Faraday
last_response = headers.slice(start_index, headers.size)
last_response
.tap { |a| a.shift if a.first.start_with?('HTTP/') } # drop the HTTP status line
.tap { |a| a.shift if a.first.start_with?('HTTP/') }
.map { |h| h.split(/:\s*/, 2) } # split key and value
.reject { |p| p[0].nil? } # ignore blank lines
.each { |key, value| add_parsed(key, value) } # join multiple values with a comma
.each { |key, value| add_parsed(key, value) }
end
protected
@ -130,6 +130,7 @@ module Faraday
private
# Join multiple values with a comma.
def add_parsed(key, value)
self[key] ? self[key] << ', ' << value : self[key] = value
end

View File

@ -42,8 +42,9 @@ module Faraday
end
def merge_query(query, encoder = nil)
update((encoder || Utils.default_params_encoder).decode(query)) if query && !query.empty?
self
return self unless query && !query.empty?
update((encoder || Utils.default_params_encoder).decode(query))
end
def to_query(encoder = nil)

View File

@ -33,11 +33,15 @@ def write(file, contents, env_var)
end
# One cert / CA for ease of testing when ignoring verification
cert, key = create_self_signed_cert(1024, [%w[CN localhost]], 'Faraday Test CA')
cert, key = create_self_signed_cert(1024, [%w[CN localhost]],
'Faraday Test CA')
write 'tmp/faraday-cert.key', key, 'SSL_KEY'
write 'tmp/faraday-cert.crt', cert, 'SSL_FILE'
# And a second CA to prove that verification can fail
cert, key = create_self_signed_cert(1024, [['CN', 'real-ca.com']], 'A different CA')
cert, key = create_self_signed_cert(1024, [%w[CN real-ca.com]],
'A different CA')
write 'tmp/faraday-different-ca-cert.key', key, 'SSL_KEY_ALT'
write 'tmp/faraday-different-ca-cert.crt', cert, 'SSL_FILE_ALT'

View File

@ -27,7 +27,8 @@ webrick_opts = {
AccessLog: [[log_io, '[%{X-Faraday-Adapter}i] %m %U -> %s %b']],
ProxyAuthProc: lambda { |req, res|
if username
type, credentials = req.header['proxy-authorization'].first.to_s.split(/\s+/, 2)
type, credentials = req.header['proxy-authorization']
.first.to_s.split(/\s+/, 2)
unless type == 'Basic' && match_credentials.call(credentials)
res['proxy-authenticate'] = %(Basic realm="testing")
raise WEBrick::HTTPStatus::ProxyAuthenticationRequired

View File

@ -5,14 +5,17 @@
# the registered response.
class WebmockRackApp
def call(env)
req_signature = WebMock::RequestSignature.new(req_method(env),
req_uri(env),
body: req_body(env),
headers: req_headers(env))
req_signature = WebMock::RequestSignature.new(
req_method(env),
req_uri(env),
body: req_body(env),
headers: req_headers(env)
)
WebMock::RequestRegistry.instance
.requested_signatures
.put(req_signature)
WebMock::RequestRegistry
.instance
.requested_signatures
.put(req_signature)
process_response(req_signature)
end
@ -52,7 +55,9 @@ class WebmockRackApp
def process_response(req_signature)
res = WebMock::StubRegistry.instance.response_for_request(req_signature)
raise Faraday::ConnectionFailed, 'Trying to connect to localhost' if res.nil? && req_signature.uri.host == 'localhost'
if res.nil? && req_signature.uri.host == 'localhost'
raise Faraday::ConnectionFailed, 'Trying to connect to localhost'
end
raise WebMock::NetConnectNotAllowedError, req_signature unless res