faraday 0.17.5 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +350 -8
- data/LICENSE.md +1 -1
- data/README.md +24 -364
- data/Rakefile +1 -7
- data/examples/client_spec.rb +97 -0
- data/examples/client_test.rb +118 -0
- data/lib/faraday/adapter/test.rb +127 -72
- data/lib/faraday/adapter.rb +69 -22
- data/lib/faraday/adapter_registry.rb +30 -0
- data/lib/faraday/connection.rb +309 -232
- data/lib/faraday/encoders/flat_params_encoder.rb +105 -0
- data/lib/faraday/encoders/nested_params_encoder.rb +183 -0
- data/lib/faraday/error.rb +31 -42
- data/lib/faraday/logging/formatter.rb +106 -0
- data/lib/faraday/methods.rb +6 -0
- data/lib/faraday/middleware.rb +18 -25
- data/lib/faraday/middleware_registry.rb +83 -0
- data/lib/faraday/options/connection_options.rb +22 -0
- data/lib/faraday/options/env.rb +181 -0
- data/lib/faraday/options/proxy_options.rb +32 -0
- data/lib/faraday/options/request_options.rb +22 -0
- data/lib/faraday/options/ssl_options.rb +59 -0
- data/lib/faraday/options.rb +38 -193
- data/lib/faraday/parameters.rb +4 -197
- data/lib/faraday/rack_builder.rb +91 -76
- data/lib/faraday/request/authorization.rb +37 -29
- data/lib/faraday/request/instrumentation.rb +47 -27
- data/lib/faraday/request/json.rb +55 -0
- data/lib/faraday/request/url_encoded.rb +48 -24
- data/lib/faraday/request.rb +64 -44
- data/lib/faraday/response/json.rb +54 -0
- data/lib/faraday/response/logger.rb +22 -69
- data/lib/faraday/response/raise_error.rb +57 -18
- data/lib/faraday/response.rb +25 -32
- data/lib/faraday/utils/headers.rb +139 -0
- data/lib/faraday/utils/params_hash.rb +61 -0
- data/lib/faraday/utils.rb +47 -251
- data/lib/faraday/version.rb +5 -0
- data/lib/faraday.rb +108 -198
- data/spec/external_adapters/faraday_specs_setup.rb +14 -0
- data/spec/faraday/adapter/test_spec.rb +377 -0
- data/spec/faraday/adapter_registry_spec.rb +28 -0
- data/spec/faraday/adapter_spec.rb +55 -0
- data/spec/faraday/connection_spec.rb +787 -0
- data/spec/faraday/error_spec.rb +12 -54
- data/spec/faraday/middleware_registry_spec.rb +31 -0
- data/spec/faraday/middleware_spec.rb +52 -0
- data/spec/faraday/options/env_spec.rb +70 -0
- data/spec/faraday/options/options_spec.rb +297 -0
- data/spec/faraday/options/proxy_options_spec.rb +44 -0
- data/spec/faraday/options/request_options_spec.rb +19 -0
- data/spec/faraday/params_encoders/flat_spec.rb +42 -0
- data/spec/faraday/params_encoders/nested_spec.rb +150 -0
- data/spec/faraday/rack_builder_spec.rb +317 -0
- data/spec/faraday/request/authorization_spec.rb +83 -0
- data/spec/faraday/request/instrumentation_spec.rb +74 -0
- data/spec/faraday/request/json_spec.rb +111 -0
- data/spec/faraday/request/url_encoded_spec.rb +93 -0
- data/spec/faraday/request_spec.rb +109 -0
- data/spec/faraday/response/json_spec.rb +117 -0
- data/spec/faraday/response/logger_spec.rb +220 -0
- data/spec/faraday/response/raise_error_spec.rb +81 -15
- data/spec/faraday/response_spec.rb +75 -0
- data/spec/faraday/utils/headers_spec.rb +82 -0
- data/spec/faraday/utils_spec.rb +117 -0
- data/spec/faraday_spec.rb +37 -0
- data/spec/spec_helper.rb +63 -36
- data/spec/support/disabling_stub.rb +14 -0
- data/spec/support/fake_safe_buffer.rb +15 -0
- data/spec/support/helper_methods.rb +96 -0
- data/spec/support/shared_examples/adapter.rb +104 -0
- data/spec/support/shared_examples/params_encoder.rb +18 -0
- data/spec/support/shared_examples/request_method.rb +249 -0
- data/spec/support/streaming_response_checker.rb +35 -0
- metadata +74 -63
- data/lib/faraday/adapter/em_http.rb +0 -243
- data/lib/faraday/adapter/em_http_ssl_patch.rb +0 -56
- data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +0 -66
- data/lib/faraday/adapter/em_synchrony.rb +0 -106
- data/lib/faraday/adapter/excon.rb +0 -82
- data/lib/faraday/adapter/httpclient.rb +0 -128
- data/lib/faraday/adapter/net_http.rb +0 -153
- data/lib/faraday/adapter/net_http_persistent.rb +0 -68
- data/lib/faraday/adapter/patron.rb +0 -95
- data/lib/faraday/adapter/rack.rb +0 -58
- data/lib/faraday/adapter/typhoeus.rb +0 -12
- data/lib/faraday/autoload.rb +0 -84
- data/lib/faraday/deprecate.rb +0 -109
- data/lib/faraday/request/basic_authentication.rb +0 -13
- data/lib/faraday/request/multipart.rb +0 -68
- data/lib/faraday/request/retry.rb +0 -213
- data/lib/faraday/request/token_authentication.rb +0 -15
- data/lib/faraday/upload_io.rb +0 -67
- data/spec/faraday/deprecate_spec.rb +0 -147
- data/test/adapters/default_test.rb +0 -14
- data/test/adapters/em_http_test.rb +0 -30
- data/test/adapters/em_synchrony_test.rb +0 -32
- data/test/adapters/excon_test.rb +0 -30
- data/test/adapters/httpclient_test.rb +0 -34
- data/test/adapters/integration.rb +0 -263
- data/test/adapters/logger_test.rb +0 -136
- data/test/adapters/net_http_persistent_test.rb +0 -114
- data/test/adapters/net_http_test.rb +0 -79
- data/test/adapters/patron_test.rb +0 -40
- data/test/adapters/rack_test.rb +0 -38
- data/test/adapters/test_middleware_test.rb +0 -157
- data/test/adapters/typhoeus_test.rb +0 -38
- data/test/authentication_middleware_test.rb +0 -65
- data/test/composite_read_io_test.rb +0 -109
- data/test/connection_test.rb +0 -738
- data/test/env_test.rb +0 -268
- data/test/helper.rb +0 -75
- data/test/live_server.rb +0 -67
- data/test/middleware/instrumentation_test.rb +0 -88
- data/test/middleware/retry_test.rb +0 -282
- data/test/middleware_stack_test.rb +0 -260
- data/test/multibyte.txt +0 -1
- data/test/options_test.rb +0 -333
- data/test/parameters_test.rb +0 -157
- data/test/request_middleware_test.rb +0 -126
- data/test/response_middleware_test.rb +0 -72
- data/test/strawberry.rb +0 -2
- data/test/utils_test.rb +0 -98
@@ -0,0 +1,105 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Faraday
|
4
|
+
# FlatParamsEncoder manages URI params as a flat hash. Any Array values repeat
|
5
|
+
# the parameter multiple times.
|
6
|
+
module FlatParamsEncoder
|
7
|
+
class << self
|
8
|
+
extend Forwardable
|
9
|
+
def_delegators :'Faraday::Utils', :escape, :unescape
|
10
|
+
end
|
11
|
+
|
12
|
+
# Encode converts the given param into a URI querystring. Keys and values
|
13
|
+
# will converted to strings and appropriately escaped for the URI.
|
14
|
+
#
|
15
|
+
# @param params [Hash] query arguments to convert.
|
16
|
+
#
|
17
|
+
# @example
|
18
|
+
#
|
19
|
+
# encode({a: %w[one two three], b: true, c: "C"})
|
20
|
+
# # => 'a=one&a=two&a=three&b=true&c=C'
|
21
|
+
#
|
22
|
+
# @return [String] the URI querystring (without the leading '?')
|
23
|
+
def self.encode(params)
|
24
|
+
return nil if params.nil?
|
25
|
+
|
26
|
+
unless params.is_a?(Array)
|
27
|
+
unless params.respond_to?(:to_hash)
|
28
|
+
raise TypeError,
|
29
|
+
"Can't convert #{params.class} into Hash."
|
30
|
+
end
|
31
|
+
params = params.to_hash
|
32
|
+
params = params.map do |key, value|
|
33
|
+
key = key.to_s if key.is_a?(Symbol)
|
34
|
+
[key, value]
|
35
|
+
end
|
36
|
+
|
37
|
+
# Only to be used for non-Array inputs. Arrays should preserve order.
|
38
|
+
params.sort! if @sort_params
|
39
|
+
end
|
40
|
+
|
41
|
+
# The params have form [['key1', 'value1'], ['key2', 'value2']].
|
42
|
+
buffer = +''
|
43
|
+
params.each do |key, value|
|
44
|
+
encoded_key = escape(key)
|
45
|
+
if value.nil?
|
46
|
+
buffer << "#{encoded_key}&"
|
47
|
+
elsif value.is_a?(Array)
|
48
|
+
if value.empty?
|
49
|
+
buffer << "#{encoded_key}=&"
|
50
|
+
else
|
51
|
+
value.each do |sub_value|
|
52
|
+
encoded_value = escape(sub_value)
|
53
|
+
buffer << "#{encoded_key}=#{encoded_value}&"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
else
|
57
|
+
encoded_value = escape(value)
|
58
|
+
buffer << "#{encoded_key}=#{encoded_value}&"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
buffer.chop
|
62
|
+
end
|
63
|
+
|
64
|
+
# Decode converts the given URI querystring into a hash.
|
65
|
+
#
|
66
|
+
# @param query [String] query arguments to parse.
|
67
|
+
#
|
68
|
+
# @example
|
69
|
+
#
|
70
|
+
# decode('a=one&a=two&a=three&b=true&c=C')
|
71
|
+
# # => {"a"=>["one", "two", "three"], "b"=>"true", "c"=>"C"}
|
72
|
+
#
|
73
|
+
# @return [Hash] parsed keys and value strings from the querystring.
|
74
|
+
def self.decode(query)
|
75
|
+
return nil if query.nil?
|
76
|
+
|
77
|
+
empty_accumulator = {}
|
78
|
+
|
79
|
+
split_query = (query.split('&').map do |pair|
|
80
|
+
pair.split('=', 2) if pair && !pair.empty?
|
81
|
+
end).compact
|
82
|
+
split_query.each_with_object(empty_accumulator.dup) do |pair, accu|
|
83
|
+
pair[0] = unescape(pair[0])
|
84
|
+
pair[1] = true if pair[1].nil?
|
85
|
+
if pair[1].respond_to?(:to_str)
|
86
|
+
pair[1] = unescape(pair[1].to_str.tr('+', ' '))
|
87
|
+
end
|
88
|
+
if accu[pair[0]].is_a?(Array)
|
89
|
+
accu[pair[0]] << pair[1]
|
90
|
+
elsif accu[pair[0]]
|
91
|
+
accu[pair[0]] = [accu[pair[0]], pair[1]]
|
92
|
+
else
|
93
|
+
accu[pair[0]] = pair[1]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
class << self
|
99
|
+
attr_accessor :sort_params
|
100
|
+
end
|
101
|
+
|
102
|
+
# Useful default for OAuth and caching.
|
103
|
+
@sort_params = true
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Faraday
|
4
|
+
# Sub-module for encoding parameters into query-string.
|
5
|
+
module EncodeMethods
|
6
|
+
# @param params [nil, Array, #to_hash] parameters to be encoded
|
7
|
+
#
|
8
|
+
# @return [String] the encoded params
|
9
|
+
#
|
10
|
+
# @raise [TypeError] if params can not be converted to a Hash
|
11
|
+
def encode(params)
|
12
|
+
return nil if params.nil?
|
13
|
+
|
14
|
+
unless params.is_a?(Array)
|
15
|
+
unless params.respond_to?(:to_hash)
|
16
|
+
raise TypeError, "Can't convert #{params.class} into Hash."
|
17
|
+
end
|
18
|
+
|
19
|
+
params = params.to_hash
|
20
|
+
params = params.map do |key, value|
|
21
|
+
key = key.to_s if key.is_a?(Symbol)
|
22
|
+
[key, value]
|
23
|
+
end
|
24
|
+
|
25
|
+
# Only to be used for non-Array inputs. Arrays should preserve order.
|
26
|
+
params.sort! if @sort_params
|
27
|
+
end
|
28
|
+
|
29
|
+
# The params have form [['key1', 'value1'], ['key2', 'value2']].
|
30
|
+
buffer = +''
|
31
|
+
params.each do |parent, value|
|
32
|
+
encoded_parent = escape(parent)
|
33
|
+
buffer << "#{encode_pair(encoded_parent, value)}&"
|
34
|
+
end
|
35
|
+
buffer.chop
|
36
|
+
end
|
37
|
+
|
38
|
+
protected
|
39
|
+
|
40
|
+
def encode_pair(parent, value)
|
41
|
+
if value.is_a?(Hash)
|
42
|
+
encode_hash(parent, value)
|
43
|
+
elsif value.is_a?(Array)
|
44
|
+
encode_array(parent, value)
|
45
|
+
elsif value.nil?
|
46
|
+
parent
|
47
|
+
else
|
48
|
+
encoded_value = escape(value)
|
49
|
+
"#{parent}=#{encoded_value}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def encode_hash(parent, value)
|
54
|
+
value = value.map { |key, val| [escape(key), val] }.sort
|
55
|
+
|
56
|
+
buffer = +''
|
57
|
+
value.each do |key, val|
|
58
|
+
new_parent = "#{parent}%5B#{key}%5D"
|
59
|
+
buffer << "#{encode_pair(new_parent, val)}&"
|
60
|
+
end
|
61
|
+
buffer.chop
|
62
|
+
end
|
63
|
+
|
64
|
+
def encode_array(parent, value)
|
65
|
+
return "#{parent}%5B%5D" if value.empty?
|
66
|
+
|
67
|
+
buffer = +''
|
68
|
+
value.each_with_index do |val, index|
|
69
|
+
new_parent = if @array_indices
|
70
|
+
"#{parent}%5B#{index}%5D"
|
71
|
+
else
|
72
|
+
"#{parent}%5B%5D"
|
73
|
+
end
|
74
|
+
buffer << "#{encode_pair(new_parent, val)}&"
|
75
|
+
end
|
76
|
+
buffer.chop
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Sub-module for decoding query-string into parameters.
|
81
|
+
module DecodeMethods
|
82
|
+
# @param query [nil, String]
|
83
|
+
#
|
84
|
+
# @return [Array<Array, String>] the decoded params
|
85
|
+
#
|
86
|
+
# @raise [TypeError] if the nesting is incorrect
|
87
|
+
def decode(query)
|
88
|
+
return nil if query.nil?
|
89
|
+
|
90
|
+
params = {}
|
91
|
+
query.split('&').each do |pair|
|
92
|
+
next if pair.empty?
|
93
|
+
|
94
|
+
key, value = pair.split('=', 2)
|
95
|
+
key = unescape(key)
|
96
|
+
value = unescape(value.tr('+', ' ')) if value
|
97
|
+
decode_pair(key, value, params)
|
98
|
+
end
|
99
|
+
|
100
|
+
dehash(params, 0)
|
101
|
+
end
|
102
|
+
|
103
|
+
protected
|
104
|
+
|
105
|
+
SUBKEYS_REGEX = /[^\[\]]+(?:\]?\[\])?/.freeze
|
106
|
+
|
107
|
+
def decode_pair(key, value, context)
|
108
|
+
subkeys = key.scan(SUBKEYS_REGEX)
|
109
|
+
subkeys.each_with_index do |subkey, i|
|
110
|
+
is_array = subkey =~ /[\[\]]+\Z/
|
111
|
+
subkey = Regexp.last_match.pre_match if is_array
|
112
|
+
last_subkey = i == subkeys.length - 1
|
113
|
+
|
114
|
+
context = prepare_context(context, subkey, is_array, last_subkey)
|
115
|
+
add_to_context(is_array, context, value, subkey) if last_subkey
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def prepare_context(context, subkey, is_array, last_subkey)
|
120
|
+
if !last_subkey || is_array
|
121
|
+
context = new_context(subkey, is_array, context)
|
122
|
+
end
|
123
|
+
if context.is_a?(Array) && !is_array
|
124
|
+
context = match_context(context, subkey)
|
125
|
+
end
|
126
|
+
context
|
127
|
+
end
|
128
|
+
|
129
|
+
def new_context(subkey, is_array, context)
|
130
|
+
value_type = is_array ? Array : Hash
|
131
|
+
if context[subkey] && !context[subkey].is_a?(value_type)
|
132
|
+
raise TypeError, "expected #{value_type.name} " \
|
133
|
+
"(got #{context[subkey].class.name}) for param `#{subkey}'"
|
134
|
+
end
|
135
|
+
|
136
|
+
context[subkey] ||= value_type.new
|
137
|
+
end
|
138
|
+
|
139
|
+
def match_context(context, subkey)
|
140
|
+
context << {} if !context.last.is_a?(Hash) || context.last.key?(subkey)
|
141
|
+
context.last
|
142
|
+
end
|
143
|
+
|
144
|
+
def add_to_context(is_array, context, value, subkey)
|
145
|
+
is_array ? context << value : context[subkey] = value
|
146
|
+
end
|
147
|
+
|
148
|
+
# Internal: convert a nested hash with purely numeric keys into an array.
|
149
|
+
# FIXME: this is not compatible with Rack::Utils.parse_nested_query
|
150
|
+
# @!visibility private
|
151
|
+
def dehash(hash, depth)
|
152
|
+
hash.each do |key, value|
|
153
|
+
hash[key] = dehash(value, depth + 1) if value.is_a?(Hash)
|
154
|
+
end
|
155
|
+
|
156
|
+
if depth.positive? && !hash.empty? && hash.keys.all? { |k| k =~ /^\d+$/ }
|
157
|
+
hash.sort.map(&:last)
|
158
|
+
else
|
159
|
+
hash
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# This is the default encoder for Faraday requests.
|
165
|
+
# Using this encoder, parameters will be encoded respecting their structure,
|
166
|
+
# so you can send objects such as Arrays or Hashes as parameters
|
167
|
+
# for your requests.
|
168
|
+
module NestedParamsEncoder
|
169
|
+
class << self
|
170
|
+
attr_accessor :sort_params, :array_indices
|
171
|
+
|
172
|
+
extend Forwardable
|
173
|
+
def_delegators :'Faraday::Utils', :escape, :unescape
|
174
|
+
end
|
175
|
+
|
176
|
+
# Useful default for OAuth and caching.
|
177
|
+
@sort_params = true
|
178
|
+
@array_indices = false
|
179
|
+
|
180
|
+
extend EncodeMethods
|
181
|
+
extend DecodeMethods
|
182
|
+
end
|
183
|
+
end
|
data/lib/faraday/error.rb
CHANGED
@@ -1,14 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'faraday/deprecate'
|
4
|
-
|
5
3
|
# Faraday namespace.
|
6
4
|
module Faraday
|
7
5
|
# Faraday error base class.
|
8
6
|
class Error < StandardError
|
9
7
|
attr_reader :response, :wrapped_exception
|
10
8
|
|
11
|
-
def initialize(exc, response = nil)
|
9
|
+
def initialize(exc = nil, response = nil)
|
12
10
|
@wrapped_exception = nil unless defined?(@wrapped_exception)
|
13
11
|
@response = nil unless defined?(@response)
|
14
12
|
super(exc_msg_and_response!(exc, response))
|
@@ -23,13 +21,25 @@ module Faraday
|
|
23
21
|
end
|
24
22
|
|
25
23
|
def inspect
|
26
|
-
inner = ''
|
27
|
-
inner
|
28
|
-
inner
|
29
|
-
inner
|
24
|
+
inner = +''
|
25
|
+
inner << " wrapped=#{@wrapped_exception.inspect}" if @wrapped_exception
|
26
|
+
inner << " response=#{@response.inspect}" if @response
|
27
|
+
inner << " #{super}" if inner.empty?
|
30
28
|
%(#<#{self.class}#{inner}>)
|
31
29
|
end
|
32
30
|
|
31
|
+
def response_status
|
32
|
+
@response[:status] if @response
|
33
|
+
end
|
34
|
+
|
35
|
+
def response_headers
|
36
|
+
@response[:headers] if @response
|
37
|
+
end
|
38
|
+
|
39
|
+
def response_body
|
40
|
+
@response[:body] if @response
|
41
|
+
end
|
42
|
+
|
33
43
|
protected
|
34
44
|
|
35
45
|
# Pulls out potential parent exception and response hash, storing them in
|
@@ -40,6 +50,15 @@ module Faraday
|
|
40
50
|
# :headers - String key/value hash of HTTP response header
|
41
51
|
# values.
|
42
52
|
# :body - Optional string HTTP response body.
|
53
|
+
# :request - Hash
|
54
|
+
# :method - Symbol with the request HTTP method.
|
55
|
+
# :url - URI object with the url requested.
|
56
|
+
# :url_path - String with the url path requested.
|
57
|
+
# :params - String key/value hash of query params
|
58
|
+
# present in the request.
|
59
|
+
# :headers - String key/value hash of HTTP request
|
60
|
+
# header values.
|
61
|
+
# :body - String HTTP request body.
|
43
62
|
#
|
44
63
|
# If a subclass has to call this, then it should pass a string message
|
45
64
|
# to `super`. See NilStatusError.
|
@@ -100,7 +119,7 @@ module Faraday
|
|
100
119
|
end
|
101
120
|
|
102
121
|
# A unified client error for timeouts.
|
103
|
-
class TimeoutError <
|
122
|
+
class TimeoutError < ServerError
|
104
123
|
def initialize(exc = 'timeout', response = nil)
|
105
124
|
super(exc, response)
|
106
125
|
end
|
@@ -110,49 +129,19 @@ module Faraday
|
|
110
129
|
class NilStatusError < ServerError
|
111
130
|
def initialize(exc, response = nil)
|
112
131
|
exc_msg_and_response!(exc, response)
|
113
|
-
@response = unwrap_resp!(@response)
|
114
132
|
super('http status could not be derived from the server response')
|
115
133
|
end
|
116
|
-
|
117
|
-
private
|
118
|
-
|
119
|
-
extend Faraday::Deprecate
|
120
|
-
|
121
|
-
def unwrap_resp(resp)
|
122
|
-
if inner = (resp.keys.size == 1 && resp[:response])
|
123
|
-
return unwrap_resp(inner)
|
124
|
-
end
|
125
|
-
|
126
|
-
resp
|
127
|
-
end
|
128
|
-
|
129
|
-
alias_method :unwrap_resp!, :unwrap_resp
|
130
|
-
deprecate('unwrap_resp', nil, '1.0')
|
131
134
|
end
|
132
135
|
|
133
136
|
# A unified error for failed connections.
|
134
|
-
class ConnectionFailed <
|
137
|
+
class ConnectionFailed < Error
|
135
138
|
end
|
136
139
|
|
137
140
|
# A unified client error for SSL errors.
|
138
|
-
class SSLError <
|
139
|
-
end
|
140
|
-
|
141
|
-
# Raised by FaradayMiddleware::ResponseMiddleware
|
142
|
-
class ParsingError < ClientError
|
143
|
-
end
|
144
|
-
|
145
|
-
# Exception used to control the Retry middleware.
|
146
|
-
#
|
147
|
-
# @see Faraday::Request::Retry
|
148
|
-
class RetriableResponse < ClientError
|
141
|
+
class SSLError < Error
|
149
142
|
end
|
150
143
|
|
151
|
-
|
152
|
-
|
153
|
-
Error.const_set(
|
154
|
-
const,
|
155
|
-
DeprecatedClass.proxy_class(Faraday.const_get(const))
|
156
|
-
)
|
144
|
+
# Raised by middlewares that parse the response, like the JSON response middleware.
|
145
|
+
class ParsingError < Error
|
157
146
|
end
|
158
147
|
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
module Faraday
|
6
|
+
module Logging
|
7
|
+
# Serves as an integration point to customize logging
|
8
|
+
class Formatter
|
9
|
+
extend Forwardable
|
10
|
+
|
11
|
+
DEFAULT_OPTIONS = { headers: true, bodies: false,
|
12
|
+
log_level: :info }.freeze
|
13
|
+
|
14
|
+
def initialize(logger:, options:)
|
15
|
+
@logger = logger
|
16
|
+
@filter = []
|
17
|
+
@options = DEFAULT_OPTIONS.merge(options)
|
18
|
+
end
|
19
|
+
|
20
|
+
def_delegators :@logger, :debug, :info, :warn, :error, :fatal
|
21
|
+
|
22
|
+
def request(env)
|
23
|
+
request_log = proc do
|
24
|
+
"#{env.method.upcase} #{apply_filters(env.url.to_s)}"
|
25
|
+
end
|
26
|
+
public_send(log_level, 'request', &request_log)
|
27
|
+
|
28
|
+
log_headers('request', env.request_headers) if log_headers?(:request)
|
29
|
+
log_body('request', env[:body]) if env[:body] && log_body?(:request)
|
30
|
+
end
|
31
|
+
|
32
|
+
def response(env)
|
33
|
+
status = proc { "Status #{env.status}" }
|
34
|
+
public_send(log_level, 'response', &status)
|
35
|
+
|
36
|
+
log_headers('response', env.response_headers) if log_headers?(:response)
|
37
|
+
log_body('response', env[:body]) if env[:body] && log_body?(:response)
|
38
|
+
end
|
39
|
+
|
40
|
+
def filter(filter_word, filter_replacement)
|
41
|
+
@filter.push([filter_word, filter_replacement])
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def dump_headers(headers)
|
47
|
+
headers.map { |k, v| "#{k}: #{v.inspect}" }.join("\n")
|
48
|
+
end
|
49
|
+
|
50
|
+
def dump_body(body)
|
51
|
+
if body.respond_to?(:to_str)
|
52
|
+
body.to_str
|
53
|
+
else
|
54
|
+
pretty_inspect(body)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def pretty_inspect(body)
|
59
|
+
body.pretty_inspect
|
60
|
+
end
|
61
|
+
|
62
|
+
def log_headers?(type)
|
63
|
+
case @options[:headers]
|
64
|
+
when Hash
|
65
|
+
@options[:headers][type]
|
66
|
+
else
|
67
|
+
@options[:headers]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def log_body?(type)
|
72
|
+
case @options[:bodies]
|
73
|
+
when Hash
|
74
|
+
@options[:bodies][type]
|
75
|
+
else
|
76
|
+
@options[:bodies]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def apply_filters(output)
|
81
|
+
@filter.each do |pattern, replacement|
|
82
|
+
output = output.to_s.gsub(pattern, replacement)
|
83
|
+
end
|
84
|
+
output
|
85
|
+
end
|
86
|
+
|
87
|
+
def log_level
|
88
|
+
unless %i[debug info warn error fatal].include?(@options[:log_level])
|
89
|
+
return :info
|
90
|
+
end
|
91
|
+
|
92
|
+
@options[:log_level]
|
93
|
+
end
|
94
|
+
|
95
|
+
def log_headers(type, headers)
|
96
|
+
headers_log = proc { apply_filters(dump_headers(headers)) }
|
97
|
+
public_send(log_level, type, &headers_log)
|
98
|
+
end
|
99
|
+
|
100
|
+
def log_body(type, body)
|
101
|
+
body_log = proc { apply_filters(dump_body(body)) }
|
102
|
+
public_send(log_level, type, &body_log)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
data/lib/faraday/middleware.rb
CHANGED
@@ -1,37 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Faraday
|
4
|
+
# Middleware is the basic base class of any Faraday middleware.
|
2
5
|
class Middleware
|
3
6
|
extend MiddlewareRegistry
|
4
7
|
|
5
|
-
|
6
|
-
attr_accessor :load_error
|
7
|
-
private :load_error=
|
8
|
-
end
|
9
|
-
|
10
|
-
self.load_error = nil
|
11
|
-
|
12
|
-
# Executes a block which should try to require and reference dependent libraries
|
13
|
-
def self.dependency(lib = nil)
|
14
|
-
lib ? require(lib) : yield
|
15
|
-
rescue LoadError, NameError => error
|
16
|
-
self.load_error = error
|
17
|
-
end
|
8
|
+
attr_reader :app, :options
|
18
9
|
|
19
|
-
def
|
20
|
-
|
21
|
-
|
22
|
-
end
|
23
|
-
|
24
|
-
def self.loaded?
|
25
|
-
load_error.nil?
|
10
|
+
def initialize(app = nil, options = {})
|
11
|
+
@app = app
|
12
|
+
@options = options
|
26
13
|
end
|
27
14
|
|
28
|
-
def
|
29
|
-
|
30
|
-
|
15
|
+
def call(env)
|
16
|
+
on_request(env) if respond_to?(:on_request)
|
17
|
+
app.call(env).on_complete do |environment|
|
18
|
+
on_complete(environment) if respond_to?(:on_complete)
|
19
|
+
end
|
31
20
|
end
|
32
21
|
|
33
|
-
def
|
34
|
-
|
22
|
+
def close
|
23
|
+
if app.respond_to?(:close)
|
24
|
+
app.close
|
25
|
+
else
|
26
|
+
warn "#{app} does not implement \#close!"
|
27
|
+
end
|
35
28
|
end
|
36
29
|
end
|
37
30
|
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'monitor'
|
4
|
+
|
5
|
+
module Faraday
|
6
|
+
# Adds the ability for other modules to register and lookup
|
7
|
+
# middleware classes.
|
8
|
+
module MiddlewareRegistry
|
9
|
+
def registered_middleware
|
10
|
+
@registered_middleware ||= {}
|
11
|
+
end
|
12
|
+
|
13
|
+
# Register middleware class(es) on the current module.
|
14
|
+
#
|
15
|
+
# @param mappings [Hash] Middleware mappings from a lookup symbol to a middleware class.
|
16
|
+
# @return [void]
|
17
|
+
#
|
18
|
+
# @example Lookup by a constant
|
19
|
+
#
|
20
|
+
# module Faraday
|
21
|
+
# class Whatever < Middleware
|
22
|
+
# # Middleware looked up by :foo returns Faraday::Whatever::Foo.
|
23
|
+
# register_middleware(foo: Whatever)
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
def register_middleware(**mappings)
|
27
|
+
middleware_mutex do
|
28
|
+
registered_middleware.update(mappings)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Unregister a previously registered middleware class.
|
33
|
+
#
|
34
|
+
# @param key [Symbol] key for the registered middleware.
|
35
|
+
def unregister_middleware(key)
|
36
|
+
registered_middleware.delete(key)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Lookup middleware class with a registered Symbol shortcut.
|
40
|
+
#
|
41
|
+
# @param key [Symbol] key for the registered middleware.
|
42
|
+
# @return [Class] a middleware Class.
|
43
|
+
# @raise [Faraday::Error] if given key is not registered
|
44
|
+
#
|
45
|
+
# @example
|
46
|
+
#
|
47
|
+
# module Faraday
|
48
|
+
# class Whatever < Middleware
|
49
|
+
# register_middleware(foo: Whatever)
|
50
|
+
# end
|
51
|
+
# end
|
52
|
+
#
|
53
|
+
# Faraday::Middleware.lookup_middleware(:foo)
|
54
|
+
# # => Faraday::Whatever
|
55
|
+
def lookup_middleware(key)
|
56
|
+
load_middleware(key) ||
|
57
|
+
raise(Faraday::Error, "#{key.inspect} is not registered on #{self}")
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def middleware_mutex(&block)
|
63
|
+
@middleware_mutex ||= Monitor.new
|
64
|
+
@middleware_mutex.synchronize(&block)
|
65
|
+
end
|
66
|
+
|
67
|
+
def load_middleware(key)
|
68
|
+
value = registered_middleware[key]
|
69
|
+
case value
|
70
|
+
when Module
|
71
|
+
value
|
72
|
+
when Symbol, String
|
73
|
+
middleware_mutex do
|
74
|
+
@registered_middleware[key] = const_get(value)
|
75
|
+
end
|
76
|
+
when Proc
|
77
|
+
middleware_mutex do
|
78
|
+
@registered_middleware[key] = value.call
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Faraday
|
4
|
+
# ConnectionOptions contains the configurable properties for a Faraday
|
5
|
+
# connection object.
|
6
|
+
class ConnectionOptions < Options.new(:request, :proxy, :ssl, :builder, :url,
|
7
|
+
:parallel_manager, :params, :headers,
|
8
|
+
:builder_class)
|
9
|
+
|
10
|
+
options request: RequestOptions, ssl: SSLOptions
|
11
|
+
|
12
|
+
memoized(:request) { self.class.options_for(:request).new }
|
13
|
+
|
14
|
+
memoized(:ssl) { self.class.options_for(:ssl).new }
|
15
|
+
|
16
|
+
memoized(:builder_class) { RackBuilder }
|
17
|
+
|
18
|
+
def new_builder(block)
|
19
|
+
builder_class.new(&block)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|