mirror of
https://github.com/lostisland/faraday.git
synced 2025-12-15 00:03:17 -05:00
chore: rubocop lint Metrics/LineLength (#938)
This commit is contained in:
parent
4102f3add4
commit
bd322bba6b
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
5
Gemfile
5
Gemfile
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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'],
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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=)
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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]} "\
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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]]
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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?
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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) +
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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'
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user