faraday 0.17.6 → 1.0.0.pre.rc1
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/LICENSE.md +1 -1
- data/README.md +18 -358
- data/lib/faraday/adapter/em_http.rb +142 -99
- data/lib/faraday/adapter/em_http_ssl_patch.rb +23 -17
- data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +18 -15
- data/lib/faraday/adapter/em_synchrony.rb +104 -60
- data/lib/faraday/adapter/excon.rb +97 -57
- data/lib/faraday/adapter/httpclient.rb +61 -39
- data/lib/faraday/adapter/net_http.rb +103 -51
- data/lib/faraday/adapter/net_http_persistent.rb +49 -28
- data/lib/faraday/adapter/patron.rb +54 -35
- data/lib/faraday/adapter/rack.rb +28 -12
- data/lib/faraday/adapter/test.rb +86 -53
- data/lib/faraday/adapter/typhoeus.rb +4 -1
- data/lib/faraday/adapter.rb +36 -22
- data/lib/faraday/adapter_registry.rb +28 -0
- data/lib/faraday/autoload.rb +47 -36
- data/lib/faraday/connection.rb +321 -179
- data/lib/faraday/dependency_loader.rb +37 -0
- data/lib/faraday/encoders/flat_params_encoder.rb +94 -0
- data/lib/faraday/encoders/nested_params_encoder.rb +171 -0
- data/lib/faraday/error.rb +21 -79
- data/lib/faraday/logging/formatter.rb +92 -0
- data/lib/faraday/middleware.rb +4 -28
- data/lib/faraday/middleware_registry.rb +129 -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 +28 -0
- data/lib/faraday/options/request_options.rb +21 -0
- data/lib/faraday/options/ssl_options.rb +59 -0
- data/lib/faraday/options.rb +33 -184
- data/lib/faraday/parameters.rb +4 -197
- data/lib/faraday/rack_builder.rb +66 -55
- data/lib/faraday/request/authorization.rb +42 -30
- data/lib/faraday/request/basic_authentication.rb +14 -7
- data/lib/faraday/request/instrumentation.rb +45 -27
- data/lib/faraday/request/multipart.rb +72 -49
- data/lib/faraday/request/retry.rb +197 -171
- data/lib/faraday/request/token_authentication.rb +15 -10
- data/lib/faraday/request/url_encoded.rb +41 -23
- data/lib/faraday/request.rb +68 -38
- data/lib/faraday/response/logger.rb +22 -69
- data/lib/faraday/response/raise_error.rb +36 -18
- data/lib/faraday/response.rb +22 -15
- data/lib/faraday/upload_io.rb +31 -30
- data/lib/faraday/utils/headers.rb +139 -0
- data/lib/faraday/utils/params_hash.rb +61 -0
- data/lib/faraday/utils.rb +28 -245
- data/lib/faraday.rb +93 -174
- data/spec/external_adapters/faraday_specs_setup.rb +14 -0
- metadata +25 -51
- data/CHANGELOG.md +0 -232
- data/Rakefile +0 -13
- data/lib/faraday/deprecate.rb +0 -109
- data/spec/faraday/deprecate_spec.rb +0 -147
- data/spec/faraday/error_spec.rb +0 -102
- data/spec/faraday/response/raise_error_spec.rb +0 -106
- data/spec/spec_helper.rb +0 -105
- 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,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Faraday
|
4
|
+
# DependencyLoader helps Faraday adapters and middleware load dependencies.
|
5
|
+
module DependencyLoader
|
6
|
+
attr_reader :load_error
|
7
|
+
|
8
|
+
# Executes a block which should try to require and reference dependent
|
9
|
+
# libraries
|
10
|
+
def dependency(lib = nil)
|
11
|
+
lib ? require(lib) : yield
|
12
|
+
rescue LoadError, NameError => e
|
13
|
+
self.load_error = e
|
14
|
+
end
|
15
|
+
|
16
|
+
def new(*)
|
17
|
+
unless loaded?
|
18
|
+
raise "missing dependency for #{self}: #{load_error.message}"
|
19
|
+
end
|
20
|
+
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
def loaded?
|
25
|
+
load_error.nil?
|
26
|
+
end
|
27
|
+
|
28
|
+
def inherited(subclass)
|
29
|
+
super
|
30
|
+
subclass.send(:load_error=, load_error)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
attr_writer :load_error
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,94 @@
|
|
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
|
+
# Useful default for OAuth and caching.
|
37
|
+
# Only to be used for non-Array inputs. Arrays should preserve order.
|
38
|
+
params.sort!
|
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
|
+
value.each do |sub_value|
|
49
|
+
encoded_value = escape(sub_value)
|
50
|
+
buffer << "#{encoded_key}=#{encoded_value}&"
|
51
|
+
end
|
52
|
+
else
|
53
|
+
encoded_value = escape(value)
|
54
|
+
buffer << "#{encoded_key}=#{encoded_value}&"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
buffer.chop
|
58
|
+
end
|
59
|
+
|
60
|
+
# Decode converts the given URI querystring into a hash.
|
61
|
+
#
|
62
|
+
# @param query [String] query arguments to parse.
|
63
|
+
#
|
64
|
+
# @example
|
65
|
+
#
|
66
|
+
# decode('a=one&a=two&a=three&b=true&c=C')
|
67
|
+
# # => {"a"=>["one", "two", "three"], "b"=>"true", "c"=>"C"}
|
68
|
+
#
|
69
|
+
# @return [Hash] parsed keys and value strings from the querystring.
|
70
|
+
def self.decode(query)
|
71
|
+
return nil if query.nil?
|
72
|
+
|
73
|
+
empty_accumulator = {}
|
74
|
+
|
75
|
+
split_query = (query.split('&').map do |pair|
|
76
|
+
pair.split('=', 2) if pair && !pair.empty?
|
77
|
+
end).compact
|
78
|
+
split_query.each_with_object(empty_accumulator.dup) do |pair, accu|
|
79
|
+
pair[0] = unescape(pair[0])
|
80
|
+
pair[1] = true if pair[1].nil?
|
81
|
+
if pair[1].respond_to?(:to_str)
|
82
|
+
pair[1] = unescape(pair[1].to_str.tr('+', ' '))
|
83
|
+
end
|
84
|
+
if accu[pair[0]].is_a?(Array)
|
85
|
+
accu[pair[0]] << pair[1]
|
86
|
+
elsif accu[pair[0]]
|
87
|
+
accu[pair[0]] = [accu[pair[0]], pair[1]]
|
88
|
+
else
|
89
|
+
accu[pair[0]] = pair[1]
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,171 @@
|
|
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
|
+
# Useful default for OAuth and caching.
|
25
|
+
# Only to be used for non-Array inputs. Arrays should preserve order.
|
26
|
+
params.sort!
|
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
|
+
new_parent = "#{parent}%5B%5D"
|
66
|
+
return new_parent if value.empty?
|
67
|
+
|
68
|
+
buffer = +''
|
69
|
+
value.each { |val| buffer << "#{encode_pair(new_parent, val)}&" }
|
70
|
+
buffer.chop
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Sub-module for decoding query-string into parameters.
|
75
|
+
module DecodeMethods
|
76
|
+
# @param query [nil, String]
|
77
|
+
#
|
78
|
+
# @return [Array<Array, String>] the decoded params
|
79
|
+
#
|
80
|
+
# @raise [TypeError] if the nesting is incorrect
|
81
|
+
def decode(query)
|
82
|
+
return nil if query.nil?
|
83
|
+
|
84
|
+
params = {}
|
85
|
+
query.split('&').each do |pair|
|
86
|
+
next if pair.empty?
|
87
|
+
|
88
|
+
key, value = pair.split('=', 2)
|
89
|
+
key = unescape(key)
|
90
|
+
value = unescape(value.tr('+', ' ')) if value
|
91
|
+
decode_pair(key, value, params)
|
92
|
+
end
|
93
|
+
|
94
|
+
dehash(params, 0)
|
95
|
+
end
|
96
|
+
|
97
|
+
protected
|
98
|
+
|
99
|
+
SUBKEYS_REGEX = /[^\[\]]+(?:\]?\[\])?/.freeze
|
100
|
+
|
101
|
+
def decode_pair(key, value, context)
|
102
|
+
subkeys = key.scan(SUBKEYS_REGEX)
|
103
|
+
subkeys.each_with_index do |subkey, i|
|
104
|
+
is_array = subkey =~ /[\[\]]+\Z/
|
105
|
+
subkey = $` if is_array
|
106
|
+
last_subkey = i == subkeys.length - 1
|
107
|
+
|
108
|
+
context = prepare_context(context, subkey, is_array, last_subkey)
|
109
|
+
add_to_context(is_array, context, value, subkey) if last_subkey
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def prepare_context(context, subkey, is_array, last_subkey)
|
114
|
+
if !last_subkey || is_array
|
115
|
+
context = new_context(subkey, is_array, context)
|
116
|
+
end
|
117
|
+
if context.is_a?(Array) && !is_array
|
118
|
+
context = match_context(context, subkey)
|
119
|
+
end
|
120
|
+
context
|
121
|
+
end
|
122
|
+
|
123
|
+
def new_context(subkey, is_array, context)
|
124
|
+
value_type = is_array ? Array : Hash
|
125
|
+
if context[subkey] && !context[subkey].is_a?(value_type)
|
126
|
+
raise TypeError, "expected #{value_type.name} " \
|
127
|
+
"(got #{context[subkey].class.name}) for param `#{subkey}'"
|
128
|
+
end
|
129
|
+
|
130
|
+
context[subkey] ||= value_type.new
|
131
|
+
end
|
132
|
+
|
133
|
+
def match_context(context, subkey)
|
134
|
+
context << {} if !context.last.is_a?(Hash) || context.last.key?(subkey)
|
135
|
+
context.last
|
136
|
+
end
|
137
|
+
|
138
|
+
def add_to_context(is_array, context, value, subkey)
|
139
|
+
is_array ? context << value : context[subkey] = value
|
140
|
+
end
|
141
|
+
|
142
|
+
# Internal: convert a nested hash with purely numeric keys into an array.
|
143
|
+
# FIXME: this is not compatible with Rack::Utils.parse_nested_query
|
144
|
+
# @!visibility private
|
145
|
+
def dehash(hash, depth)
|
146
|
+
hash.each do |key, value|
|
147
|
+
hash[key] = dehash(value, depth + 1) if value.is_a?(Hash)
|
148
|
+
end
|
149
|
+
|
150
|
+
if depth.positive? && !hash.empty? && hash.keys.all? { |k| k =~ /^\d+$/ }
|
151
|
+
hash.sort.map(&:last)
|
152
|
+
else
|
153
|
+
hash
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# This is the default encoder for Faraday requests.
|
159
|
+
# Using this encoder, parameters will be encoded respecting their structure,
|
160
|
+
# so you can send objects such as Arrays or Hashes as parameters
|
161
|
+
# for your requests.
|
162
|
+
module NestedParamsEncoder
|
163
|
+
class << self
|
164
|
+
extend Forwardable
|
165
|
+
def_delegators :'Faraday::Utils', :escape, :unescape
|
166
|
+
end
|
167
|
+
|
168
|
+
extend EncodeMethods
|
169
|
+
extend DecodeMethods
|
170
|
+
end
|
171
|
+
end
|
data/lib/faraday/error.rb
CHANGED
@@ -1,17 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'faraday/deprecate'
|
4
|
-
|
5
|
-
# Faraday namespace.
|
6
3
|
module Faraday
|
7
4
|
# Faraday error base class.
|
8
5
|
class Error < StandardError
|
9
6
|
attr_reader :response, :wrapped_exception
|
10
7
|
|
11
8
|
def initialize(exc, response = nil)
|
12
|
-
@wrapped_exception = nil
|
13
|
-
@response =
|
14
|
-
|
9
|
+
@wrapped_exception = nil
|
10
|
+
@response = response
|
11
|
+
|
12
|
+
if exc.respond_to?(:backtrace)
|
13
|
+
super(exc.message)
|
14
|
+
@wrapped_exception = exc
|
15
|
+
elsif exc.respond_to?(:each_key)
|
16
|
+
super("the server responded with status #{exc[:status]}")
|
17
|
+
@response = exc
|
18
|
+
else
|
19
|
+
super(exc.to_s)
|
20
|
+
end
|
15
21
|
end
|
16
22
|
|
17
23
|
def backtrace
|
@@ -23,44 +29,12 @@ module Faraday
|
|
23
29
|
end
|
24
30
|
|
25
31
|
def inspect
|
26
|
-
inner = ''
|
27
|
-
inner
|
28
|
-
inner
|
29
|
-
inner
|
32
|
+
inner = +''
|
33
|
+
inner << " wrapped=#{@wrapped_exception.inspect}" if @wrapped_exception
|
34
|
+
inner << " response=#{@response.inspect}" if @response
|
35
|
+
inner << " #{super}" if inner.empty?
|
30
36
|
%(#<#{self.class}#{inner}>)
|
31
37
|
end
|
32
|
-
|
33
|
-
protected
|
34
|
-
|
35
|
-
# Pulls out potential parent exception and response hash, storing them in
|
36
|
-
# instance variables.
|
37
|
-
# exc - Either an Exception, a string message, or a response hash.
|
38
|
-
# response - Hash
|
39
|
-
# :status - Optional integer HTTP response status
|
40
|
-
# :headers - String key/value hash of HTTP response header
|
41
|
-
# values.
|
42
|
-
# :body - Optional string HTTP response body.
|
43
|
-
#
|
44
|
-
# If a subclass has to call this, then it should pass a string message
|
45
|
-
# to `super`. See NilStatusError.
|
46
|
-
def exc_msg_and_response!(exc, response = nil)
|
47
|
-
if @response.nil? && @wrapped_exception.nil?
|
48
|
-
@wrapped_exception, msg, @response = exc_msg_and_response(exc, response)
|
49
|
-
return msg
|
50
|
-
end
|
51
|
-
|
52
|
-
exc.to_s
|
53
|
-
end
|
54
|
-
|
55
|
-
# Pulls out potential parent exception and response hash.
|
56
|
-
def exc_msg_and_response(exc, response = nil)
|
57
|
-
return [exc, exc.message, response] if exc.respond_to?(:backtrace)
|
58
|
-
|
59
|
-
return [nil, "the server responded with status #{exc[:status]}", exc] \
|
60
|
-
if exc.respond_to?(:each_key)
|
61
|
-
|
62
|
-
[nil, exc.to_s, response]
|
63
|
-
end
|
64
38
|
end
|
65
39
|
|
66
40
|
# Faraday client error class. Represents 4xx status responses.
|
@@ -100,59 +74,27 @@ module Faraday
|
|
100
74
|
end
|
101
75
|
|
102
76
|
# A unified client error for timeouts.
|
103
|
-
class TimeoutError <
|
77
|
+
class TimeoutError < ServerError
|
104
78
|
def initialize(exc = 'timeout', response = nil)
|
105
79
|
super(exc, response)
|
106
80
|
end
|
107
81
|
end
|
108
82
|
|
109
|
-
# Raised by Faraday::Response::RaiseError in case of a nil status in response.
|
110
|
-
class NilStatusError < ServerError
|
111
|
-
def initialize(exc, response = nil)
|
112
|
-
exc_msg_and_response!(exc, response)
|
113
|
-
@response = unwrap_resp!(@response)
|
114
|
-
super('http status could not be derived from the server response')
|
115
|
-
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
|
-
end
|
132
|
-
|
133
83
|
# A unified error for failed connections.
|
134
|
-
class ConnectionFailed <
|
84
|
+
class ConnectionFailed < Error
|
135
85
|
end
|
136
86
|
|
137
87
|
# A unified client error for SSL errors.
|
138
|
-
class SSLError <
|
88
|
+
class SSLError < Error
|
139
89
|
end
|
140
90
|
|
141
91
|
# Raised by FaradayMiddleware::ResponseMiddleware
|
142
|
-
class ParsingError <
|
92
|
+
class ParsingError < Error
|
143
93
|
end
|
144
94
|
|
145
95
|
# Exception used to control the Retry middleware.
|
146
96
|
#
|
147
97
|
# @see Faraday::Request::Retry
|
148
|
-
class RetriableResponse <
|
149
|
-
end
|
150
|
-
|
151
|
-
[:ClientError, :ConnectionFailed, :ResourceNotFound,
|
152
|
-
:ParsingError, :TimeoutError, :SSLError, :RetriableResponse].each do |const|
|
153
|
-
Error.const_set(
|
154
|
-
const,
|
155
|
-
DeprecatedClass.proxy_class(Faraday.const_get(const))
|
156
|
-
)
|
98
|
+
class RetriableResponse < Error
|
157
99
|
end
|
158
100
|
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pp'
|
4
|
+
module Faraday
|
5
|
+
module Logging
|
6
|
+
# Serves as an integration point to customize logging
|
7
|
+
class Formatter
|
8
|
+
extend Forwardable
|
9
|
+
|
10
|
+
DEFAULT_OPTIONS = { headers: true, bodies: false }.freeze
|
11
|
+
|
12
|
+
def initialize(logger:, options:)
|
13
|
+
@logger = logger
|
14
|
+
@filter = []
|
15
|
+
@options = DEFAULT_OPTIONS.merge(options)
|
16
|
+
end
|
17
|
+
|
18
|
+
def_delegators :@logger, :debug, :info, :warn, :error, :fatal
|
19
|
+
|
20
|
+
def request(env)
|
21
|
+
info('request') do
|
22
|
+
"#{env.method.upcase} #{apply_filters(env.url.to_s)}"
|
23
|
+
end
|
24
|
+
if log_headers?(:request)
|
25
|
+
debug('request') { apply_filters(dump_headers(env.request_headers)) }
|
26
|
+
end
|
27
|
+
return unless env[:body] && log_body?(:request)
|
28
|
+
|
29
|
+
debug('request') { apply_filters(dump_body(env[:body])) }
|
30
|
+
end
|
31
|
+
|
32
|
+
def response(env)
|
33
|
+
info('response') { "Status #{env.status}" }
|
34
|
+
if log_headers?(:response)
|
35
|
+
debug('response') do
|
36
|
+
apply_filters(dump_headers(env.response_headers))
|
37
|
+
end
|
38
|
+
end
|
39
|
+
return unless env[:body] && log_body?(:response)
|
40
|
+
|
41
|
+
debug('response') { apply_filters(dump_body(env[:body])) }
|
42
|
+
end
|
43
|
+
|
44
|
+
def filter(filter_word, filter_replacement)
|
45
|
+
@filter.push([filter_word, filter_replacement])
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def dump_headers(headers)
|
51
|
+
headers.map { |k, v| "#{k}: #{v.inspect}" }.join("\n")
|
52
|
+
end
|
53
|
+
|
54
|
+
def dump_body(body)
|
55
|
+
if body.respond_to?(:to_str)
|
56
|
+
body.to_str
|
57
|
+
else
|
58
|
+
pretty_inspect(body)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def pretty_inspect(body)
|
63
|
+
body.pretty_inspect
|
64
|
+
end
|
65
|
+
|
66
|
+
def log_headers?(type)
|
67
|
+
case @options[:headers]
|
68
|
+
when Hash
|
69
|
+
@options[:headers][type]
|
70
|
+
else
|
71
|
+
@options[:headers]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def log_body?(type)
|
76
|
+
case @options[:bodies]
|
77
|
+
when Hash
|
78
|
+
@options[:bodies][type]
|
79
|
+
else
|
80
|
+
@options[:bodies]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def apply_filters(output)
|
85
|
+
@filter.each do |pattern, replacement|
|
86
|
+
output = output.to_s.gsub(pattern, replacement)
|
87
|
+
end
|
88
|
+
output
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/lib/faraday/middleware.rb
CHANGED
@@ -1,34 +1,10 @@
|
|
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
|
-
|
5
|
-
class << self
|
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
|
18
|
-
|
19
|
-
def self.new(*)
|
20
|
-
raise "missing dependency for #{self}: #{load_error.message}" unless loaded?
|
21
|
-
super
|
22
|
-
end
|
23
|
-
|
24
|
-
def self.loaded?
|
25
|
-
load_error.nil?
|
26
|
-
end
|
27
|
-
|
28
|
-
def self.inherited(subclass)
|
29
|
-
super
|
30
|
-
subclass.send(:load_error=, self.load_error)
|
31
|
-
end
|
7
|
+
extend DependencyLoader
|
32
8
|
|
33
9
|
def initialize(app = nil)
|
34
10
|
@app = app
|
@@ -0,0 +1,129 @@
|
|
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
|
+
# Register middleware class(es) on the current module.
|
10
|
+
#
|
11
|
+
# @param autoload_path [String] Middleware autoload path
|
12
|
+
# @param mapping [Hash{
|
13
|
+
# Symbol => Module,
|
14
|
+
# Symbol => Array<Module, Symbol, String>,
|
15
|
+
# }] Middleware mapping from a lookup symbol to a reference to the
|
16
|
+
# middleware.
|
17
|
+
# Classes can be expressed as:
|
18
|
+
# - a fully qualified constant
|
19
|
+
# - a Symbol
|
20
|
+
# - a Proc that will be lazily called to return the former
|
21
|
+
# - an array is given, its first element is the constant or symbol,
|
22
|
+
# and its second is a file to `require`.
|
23
|
+
# @return [void]
|
24
|
+
#
|
25
|
+
# @example Lookup by a constant
|
26
|
+
#
|
27
|
+
# module Faraday
|
28
|
+
# class Whatever
|
29
|
+
# # Middleware looked up by :foo returns Faraday::Whatever::Foo.
|
30
|
+
# register_middleware foo: Foo
|
31
|
+
# end
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# @example Lookup by a symbol
|
35
|
+
#
|
36
|
+
# module Faraday
|
37
|
+
# class Whatever
|
38
|
+
# # Middleware looked up by :bar returns
|
39
|
+
# # Faraday::Whatever.const_get(:Bar)
|
40
|
+
# register_middleware bar: :Bar
|
41
|
+
# end
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# @example Lookup by a symbol and string in an array
|
45
|
+
#
|
46
|
+
# module Faraday
|
47
|
+
# class Whatever
|
48
|
+
# # Middleware looked up by :baz requires 'baz' and returns
|
49
|
+
# # Faraday::Whatever.const_get(:Baz)
|
50
|
+
# register_middleware baz: [:Baz, 'baz']
|
51
|
+
# end
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
def register_middleware(autoload_path = nil, mapping = nil)
|
55
|
+
if mapping.nil?
|
56
|
+
mapping = autoload_path
|
57
|
+
autoload_path = nil
|
58
|
+
end
|
59
|
+
middleware_mutex do
|
60
|
+
@middleware_autoload_path = autoload_path if autoload_path
|
61
|
+
(@registered_middleware ||= {}).update(mapping)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Unregister a previously registered middleware class.
|
66
|
+
#
|
67
|
+
# @param key [Symbol] key for the registered middleware.
|
68
|
+
def unregister_middleware(key)
|
69
|
+
@registered_middleware.delete(key)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Lookup middleware class with a registered Symbol shortcut.
|
73
|
+
#
|
74
|
+
# @param key [Symbol] key for the registered middleware.
|
75
|
+
# @return [Class] a middleware Class.
|
76
|
+
# @raise [Faraday::Error] if given key is not registered
|
77
|
+
#
|
78
|
+
# @example
|
79
|
+
#
|
80
|
+
# module Faraday
|
81
|
+
# class Whatever
|
82
|
+
# register_middleware foo: Foo
|
83
|
+
# end
|
84
|
+
# end
|
85
|
+
#
|
86
|
+
# Faraday::Whatever.lookup_middleware(:foo)
|
87
|
+
# # => Faraday::Whatever::Foo
|
88
|
+
#
|
89
|
+
def lookup_middleware(key)
|
90
|
+
load_middleware(key) ||
|
91
|
+
raise(Faraday::Error, "#{key.inspect} is not registered on #{self}")
|
92
|
+
end
|
93
|
+
|
94
|
+
def middleware_mutex(&block)
|
95
|
+
@middleware_mutex ||= Monitor.new
|
96
|
+
@middleware_mutex.synchronize(&block)
|
97
|
+
end
|
98
|
+
|
99
|
+
def fetch_middleware(key)
|
100
|
+
defined?(@registered_middleware) && @registered_middleware[key]
|
101
|
+
end
|
102
|
+
|
103
|
+
def load_middleware(key)
|
104
|
+
value = fetch_middleware(key)
|
105
|
+
case value
|
106
|
+
when Module
|
107
|
+
value
|
108
|
+
when Symbol, String
|
109
|
+
middleware_mutex do
|
110
|
+
@registered_middleware[key] = const_get(value)
|
111
|
+
end
|
112
|
+
when Proc
|
113
|
+
middleware_mutex do
|
114
|
+
@registered_middleware[key] = value.call
|
115
|
+
end
|
116
|
+
when Array
|
117
|
+
middleware_mutex do
|
118
|
+
const, path = value
|
119
|
+
if (root = @middleware_autoload_path)
|
120
|
+
path = "#{root}/#{path}"
|
121
|
+
end
|
122
|
+
require(path)
|
123
|
+
@registered_middleware[key] = const
|
124
|
+
end
|
125
|
+
load_middleware(key)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|