faraday 2.9.2 → 2.14.1
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 +1 -1
- data/lib/faraday/connection.rb +14 -5
- data/lib/faraday/encoders/flat_params_encoder.rb +2 -2
- data/lib/faraday/error.rb +46 -5
- data/lib/faraday/logging/formatter.rb +7 -7
- data/lib/faraday/middleware.rb +40 -1
- data/lib/faraday/options/env.rb +1 -1
- data/lib/faraday/options/proxy_options.rb +4 -2
- data/lib/faraday/options/ssl_options.rb +8 -2
- data/lib/faraday/rack_builder.rb +21 -24
- data/lib/faraday/response/logger.rb +5 -3
- data/lib/faraday/response/raise_error.rb +17 -17
- data/lib/faraday/response.rb +7 -3
- data/lib/faraday/version.rb +1 -1
- data/lib/faraday.rb +2 -1
- data/spec/faraday/connection_spec.rb +33 -0
- data/spec/faraday/error_spec.rb +93 -3
- data/spec/faraday/middleware_spec.rb +143 -0
- data/spec/faraday/options/proxy_options_spec.rb +27 -0
- data/spec/faraday/response/logger_spec.rb +45 -4
- data/spec/faraday/response/raise_error_spec.rb +97 -22
- data/spec/faraday/response_spec.rb +7 -0
- data/spec/faraday/utils_spec.rb +3 -1
- data/spec/support/faraday_middleware_subclasses.rb +18 -0
- metadata +36 -10
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8d5ef64533c80aaabadd55b5ea342b102fd652f5918039c7deff3b26c4ad4a67
|
|
4
|
+
data.tar.gz: 81ebbac6eb08b7f85ee7d8673e3274bbe110c0a865604a3df7294814ba469eb8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 50080c6a64a9c7b0775da8c3d63ece38a3e0946f36500665ee9be6fc547fc1a5313897ffe87fb1f08f802b6a69b8b11f46fb3a2a751ba8c00aab6910cebadbb4
|
|
7
|
+
data.tar.gz: '093b793d6b3f0ca6951a4c71ffd1f4b2603a1ea7d6efce304b165ae8124dd7cb64f7aa46b455a0ee5c9ba8e0f91ec931484dcdd7d2082dbae64448ee7aa6b2d7'
|
data/CHANGELOG.md
CHANGED
|
@@ -517,7 +517,7 @@ Breaking changes:
|
|
|
517
517
|
- Drop support for Ruby 1.8
|
|
518
518
|
|
|
519
519
|
Features:
|
|
520
|
-
- Include wrapped exception/
|
|
520
|
+
- Include wrapped exception/response in ClientErrors
|
|
521
521
|
- Add `response.reason_phrase`
|
|
522
522
|
- Provide option to selectively skip logging request/response headers
|
|
523
523
|
- Add regex support for pattern matching in `test` adapter
|
data/lib/faraday/connection.rb
CHANGED
|
@@ -314,15 +314,23 @@ module Faraday
|
|
|
314
314
|
#
|
|
315
315
|
# @yield a block to execute multiple requests.
|
|
316
316
|
# @return [void]
|
|
317
|
-
def in_parallel(manager = nil)
|
|
317
|
+
def in_parallel(manager = nil, &block)
|
|
318
318
|
@parallel_manager = manager || default_parallel_manager do
|
|
319
319
|
warn 'Warning: `in_parallel` called but no parallel-capable adapter ' \
|
|
320
320
|
'on Faraday stack'
|
|
321
321
|
warn caller[2, 10].join("\n")
|
|
322
322
|
nil
|
|
323
323
|
end
|
|
324
|
-
yield
|
|
325
|
-
|
|
324
|
+
return yield unless @parallel_manager
|
|
325
|
+
|
|
326
|
+
if @parallel_manager.respond_to?(:execute)
|
|
327
|
+
# Execute is the new method that is responsible for executing the block.
|
|
328
|
+
@parallel_manager.execute(&block)
|
|
329
|
+
else
|
|
330
|
+
# TODO: Old behaviour, deprecate and remove in 3.0
|
|
331
|
+
yield
|
|
332
|
+
@parallel_manager.run
|
|
333
|
+
end
|
|
326
334
|
ensure
|
|
327
335
|
@parallel_manager = nil
|
|
328
336
|
end
|
|
@@ -473,8 +481,9 @@ module Faraday
|
|
|
473
481
|
if url && !base.path.end_with?('/')
|
|
474
482
|
base.path = "#{base.path}/" # ensure trailing slash
|
|
475
483
|
end
|
|
476
|
-
# Ensure relative url will be parsed correctly (such as `service:search` )
|
|
477
|
-
url = "./#{url}" if url.respond_to?(:start_with?) &&
|
|
484
|
+
# Ensure relative url will be parsed correctly (such as `service:search` or `//evil.com`)
|
|
485
|
+
url = "./#{url}" if url.respond_to?(:start_with?) &&
|
|
486
|
+
(!url.start_with?('http://', 'https://', '/', './', '../') || url.start_with?('//'))
|
|
478
487
|
uri = url ? base + url : base
|
|
479
488
|
if params
|
|
480
489
|
uri.query = params.to_query(params_encoder || options.params_encoder)
|
|
@@ -76,9 +76,9 @@ module Faraday
|
|
|
76
76
|
|
|
77
77
|
empty_accumulator = {}
|
|
78
78
|
|
|
79
|
-
split_query =
|
|
79
|
+
split_query = query.split('&').filter_map do |pair|
|
|
80
80
|
pair.split('=', 2) if pair && !pair.empty?
|
|
81
|
-
end
|
|
81
|
+
end
|
|
82
82
|
split_query.each_with_object(empty_accumulator.dup) do |pair, accu|
|
|
83
83
|
pair[0] = unescape(pair[0])
|
|
84
84
|
pair[1] = true if pair[1].nil?
|
data/lib/faraday/error.rb
CHANGED
|
@@ -79,12 +79,46 @@ module Faraday
|
|
|
79
79
|
|
|
80
80
|
# Pulls out potential parent exception and response hash.
|
|
81
81
|
def exc_msg_and_response(exc, response = nil)
|
|
82
|
-
|
|
82
|
+
case exc
|
|
83
|
+
when Exception
|
|
84
|
+
[exc, exc.message, response]
|
|
85
|
+
when Hash
|
|
86
|
+
[nil, build_error_message_from_hash(exc), exc]
|
|
87
|
+
when Faraday::Env
|
|
88
|
+
[nil, build_error_message_from_env(exc), exc]
|
|
89
|
+
else
|
|
90
|
+
[nil, exc.to_s, response]
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
private
|
|
95
|
+
|
|
96
|
+
def build_error_message_from_hash(hash)
|
|
97
|
+
# Be defensive with external Hash objects - they might be missing keys
|
|
98
|
+
status = hash.fetch(:status, nil)
|
|
99
|
+
request = hash.fetch(:request, nil)
|
|
100
|
+
|
|
101
|
+
return fallback_error_message(status) if request.nil?
|
|
102
|
+
|
|
103
|
+
method = request.fetch(:method, nil)
|
|
104
|
+
url = request.fetch(:url, nil)
|
|
105
|
+
build_status_error_message(status, method, url)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def build_error_message_from_env(env)
|
|
109
|
+
# Faraday::Env is internal - we can make reasonable assumptions about its structure
|
|
110
|
+
build_status_error_message(env.status, env.method, env.url)
|
|
111
|
+
end
|
|
83
112
|
|
|
84
|
-
|
|
85
|
-
|
|
113
|
+
def build_status_error_message(status, method, url)
|
|
114
|
+
method_str = method ? method.to_s.upcase : ''
|
|
115
|
+
url_str = url ? url.to_s : ''
|
|
116
|
+
"the server responded with status #{status} for #{method_str} #{url_str}"
|
|
117
|
+
end
|
|
86
118
|
|
|
87
|
-
|
|
119
|
+
def fallback_error_message(status)
|
|
120
|
+
"the server responded with status #{status} - method and url are not available " \
|
|
121
|
+
'due to include_request: false on Faraday::Response::RaiseError middleware'
|
|
88
122
|
end
|
|
89
123
|
end
|
|
90
124
|
|
|
@@ -121,9 +155,12 @@ module Faraday
|
|
|
121
155
|
end
|
|
122
156
|
|
|
123
157
|
# Raised by Faraday::Response::RaiseError in case of a 422 response.
|
|
124
|
-
class
|
|
158
|
+
class UnprocessableContentError < ClientError
|
|
125
159
|
end
|
|
126
160
|
|
|
161
|
+
# Used to provide compatibility with legacy error name.
|
|
162
|
+
UnprocessableEntityError = UnprocessableContentError
|
|
163
|
+
|
|
127
164
|
# Raised by Faraday::Response::RaiseError in case of a 429 response.
|
|
128
165
|
class TooManyRequestsError < ClientError
|
|
129
166
|
end
|
|
@@ -158,4 +195,8 @@ module Faraday
|
|
|
158
195
|
# Raised by middlewares that parse the response, like the JSON response middleware.
|
|
159
196
|
class ParsingError < Error
|
|
160
197
|
end
|
|
198
|
+
|
|
199
|
+
# Raised by Faraday::Middleware and subclasses when invalid default_options are used
|
|
200
|
+
class InitializationError < Error
|
|
201
|
+
end
|
|
161
202
|
end
|
|
@@ -23,8 +23,8 @@ module Faraday
|
|
|
23
23
|
def_delegators :@logger, :debug, :info, :warn, :error, :fatal
|
|
24
24
|
|
|
25
25
|
def request(env)
|
|
26
|
-
public_send(log_level
|
|
27
|
-
"#{env.method.upcase} #{apply_filters(env.url.to_s)}"
|
|
26
|
+
public_send(log_level) do
|
|
27
|
+
"request: #{env.method.upcase} #{apply_filters(env.url.to_s)}"
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
log_headers('request', env.request_headers) if log_headers?(:request)
|
|
@@ -32,7 +32,7 @@ module Faraday
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def response(env)
|
|
35
|
-
public_send(log_level
|
|
35
|
+
public_send(log_level) { "response: Status #{env.status}" }
|
|
36
36
|
|
|
37
37
|
log_headers('response', env.response_headers) if log_headers?(:response)
|
|
38
38
|
log_body('response', env[:body]) if env[:body] && log_body?(:response)
|
|
@@ -41,7 +41,7 @@ module Faraday
|
|
|
41
41
|
def exception(exc)
|
|
42
42
|
return unless log_errors?
|
|
43
43
|
|
|
44
|
-
public_send(log_level
|
|
44
|
+
public_send(log_level) { "error: #{exc.full_message}" }
|
|
45
45
|
|
|
46
46
|
log_headers('error', exc.response_headers) if exc.respond_to?(:response_headers) && log_headers?(:error)
|
|
47
47
|
return unless exc.respond_to?(:response_body) && exc.response_body && log_body?(:error)
|
|
@@ -63,7 +63,7 @@ module Faraday
|
|
|
63
63
|
|
|
64
64
|
def dump_body(body)
|
|
65
65
|
if body.respond_to?(:to_str)
|
|
66
|
-
body.to_str
|
|
66
|
+
body.to_str.encode(::Encoding::UTF_8, undef: :replace, invalid: :replace)
|
|
67
67
|
else
|
|
68
68
|
pretty_inspect(body)
|
|
69
69
|
end
|
|
@@ -107,11 +107,11 @@ module Faraday
|
|
|
107
107
|
end
|
|
108
108
|
|
|
109
109
|
def log_headers(type, headers)
|
|
110
|
-
public_send(log_level
|
|
110
|
+
public_send(log_level) { "#{type}: #{apply_filters(dump_headers(headers))}" }
|
|
111
111
|
end
|
|
112
112
|
|
|
113
113
|
def log_body(type, body)
|
|
114
|
-
public_send(log_level
|
|
114
|
+
public_send(log_level) { "#{type}: #{apply_filters(dump_body(body))}" }
|
|
115
115
|
end
|
|
116
116
|
end
|
|
117
117
|
end
|
data/lib/faraday/middleware.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'monitor'
|
|
4
|
+
|
|
3
5
|
module Faraday
|
|
4
6
|
# Middleware is the basic base class of any Faraday middleware.
|
|
5
7
|
class Middleware
|
|
@@ -7,9 +9,46 @@ module Faraday
|
|
|
7
9
|
|
|
8
10
|
attr_reader :app, :options
|
|
9
11
|
|
|
12
|
+
DEFAULT_OPTIONS = {}.freeze
|
|
13
|
+
LOCK = Mutex.new
|
|
14
|
+
|
|
10
15
|
def initialize(app = nil, options = {})
|
|
11
16
|
@app = app
|
|
12
|
-
@options = options
|
|
17
|
+
@options = self.class.default_options.merge(options)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class << self
|
|
21
|
+
# Faraday::Middleware::default_options= allows user to set default options at the Faraday::Middleware
|
|
22
|
+
# class level.
|
|
23
|
+
#
|
|
24
|
+
# @example Set the Faraday::Response::RaiseError option, `include_request` to `false`
|
|
25
|
+
# my_app/config/initializers/my_faraday_middleware.rb
|
|
26
|
+
#
|
|
27
|
+
# Faraday::Response::RaiseError.default_options = { include_request: false }
|
|
28
|
+
#
|
|
29
|
+
def default_options=(options = {})
|
|
30
|
+
validate_default_options(options)
|
|
31
|
+
LOCK.synchronize do
|
|
32
|
+
@default_options = default_options.merge(options)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# default_options attr_reader that initializes class instance variable
|
|
37
|
+
# with the values of any Faraday::Middleware defaults, and merges with
|
|
38
|
+
# subclass defaults
|
|
39
|
+
def default_options
|
|
40
|
+
@default_options ||= DEFAULT_OPTIONS.merge(self::DEFAULT_OPTIONS)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def validate_default_options(options)
|
|
46
|
+
invalid_keys = options.keys.reject { |opt| self::DEFAULT_OPTIONS.key?(opt) }
|
|
47
|
+
return unless invalid_keys.any?
|
|
48
|
+
|
|
49
|
+
raise(Faraday::InitializationError,
|
|
50
|
+
"Invalid options provided. Keys not found in #{self}::DEFAULT_OPTIONS: #{invalid_keys.join(', ')}")
|
|
51
|
+
end
|
|
13
52
|
end
|
|
14
53
|
|
|
15
54
|
def call(env)
|
data/lib/faraday/options/env.rb
CHANGED
|
@@ -60,7 +60,7 @@ module Faraday
|
|
|
60
60
|
:reason_phrase, :response_body) do
|
|
61
61
|
const_set(:ContentLength, 'Content-Length')
|
|
62
62
|
const_set(:StatusesWithoutBody, Set.new([204, 304]))
|
|
63
|
-
const_set(:SuccessfulStatuses,
|
|
63
|
+
const_set(:SuccessfulStatuses, 200..299)
|
|
64
64
|
|
|
65
65
|
# A Set of HTTP verbs that typically send a body. If no body is set for
|
|
66
66
|
# these requests, the Content-Length header is set to 0.
|
|
@@ -22,8 +22,10 @@ module Faraday
|
|
|
22
22
|
when URI
|
|
23
23
|
value = { uri: value }
|
|
24
24
|
when Hash, Options
|
|
25
|
-
if
|
|
26
|
-
value
|
|
25
|
+
if value[:uri]
|
|
26
|
+
value = value.dup.tap do |duped|
|
|
27
|
+
duped[:uri] = Utils.URI(duped[:uri])
|
|
28
|
+
end
|
|
27
29
|
end
|
|
28
30
|
end
|
|
29
31
|
|
|
@@ -11,6 +11,9 @@ module Faraday
|
|
|
11
11
|
# # @return [Boolean] whether to enable hostname verification on server certificates
|
|
12
12
|
# # during the handshake or not (see https://github.com/ruby/openssl/pull/60)
|
|
13
13
|
# #
|
|
14
|
+
# # @!attribute hostname
|
|
15
|
+
# # @return [String] Server hostname used for SNI (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL/SSLSocket.html#method-i-hostname-3D)
|
|
16
|
+
# #
|
|
14
17
|
# # @!attribute ca_file
|
|
15
18
|
# # @return [String] CA file
|
|
16
19
|
# #
|
|
@@ -46,12 +49,15 @@ module Faraday
|
|
|
46
49
|
# #
|
|
47
50
|
# # @!attribute max_version
|
|
48
51
|
# # @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)
|
|
52
|
+
# #
|
|
53
|
+
# # @!attribute ciphers
|
|
54
|
+
# # @return [String] cipher list in OpenSSL format (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html#method-i-ciphers-3D)
|
|
49
55
|
# class SSLOptions < Options; end
|
|
50
|
-
SSLOptions = Options.new(:verify, :verify_hostname,
|
|
56
|
+
SSLOptions = Options.new(:verify, :verify_hostname, :hostname,
|
|
51
57
|
:ca_file, :ca_path, :verify_mode,
|
|
52
58
|
:cert_store, :client_cert, :client_key,
|
|
53
59
|
:certificate, :private_key, :verify_depth,
|
|
54
|
-
:version, :min_version, :max_version) do
|
|
60
|
+
:version, :min_version, :max_version, :ciphers) do
|
|
55
61
|
# @return [Boolean] true if should verify
|
|
56
62
|
def verify?
|
|
57
63
|
verify != false
|
data/lib/faraday/rack_builder.rb
CHANGED
|
@@ -27,10 +27,11 @@ module Faraday
|
|
|
27
27
|
|
|
28
28
|
attr_reader :name
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
def initialize(klass, *args, **kwargs, &block)
|
|
31
31
|
@name = klass.to_s
|
|
32
32
|
REGISTRY.set(klass) if klass.respond_to?(:name)
|
|
33
33
|
@args = args
|
|
34
|
+
@kwargs = kwargs
|
|
34
35
|
@block = block
|
|
35
36
|
end
|
|
36
37
|
|
|
@@ -53,7 +54,7 @@ module Faraday
|
|
|
53
54
|
end
|
|
54
55
|
|
|
55
56
|
def build(app = nil)
|
|
56
|
-
klass.new(app, *@args, &@block)
|
|
57
|
+
klass.new(app, *@args, **@kwargs, &@block)
|
|
57
58
|
end
|
|
58
59
|
end
|
|
59
60
|
|
|
@@ -88,52 +89,52 @@ module Faraday
|
|
|
88
89
|
@handlers.frozen?
|
|
89
90
|
end
|
|
90
91
|
|
|
91
|
-
|
|
92
|
+
def use(klass, ...)
|
|
92
93
|
if klass.is_a? Symbol
|
|
93
|
-
use_symbol(Faraday::Middleware, klass,
|
|
94
|
+
use_symbol(Faraday::Middleware, klass, ...)
|
|
94
95
|
else
|
|
95
96
|
raise_if_locked
|
|
96
97
|
raise_if_adapter(klass)
|
|
97
|
-
@handlers << self.class::Handler.new(klass,
|
|
98
|
+
@handlers << self.class::Handler.new(klass, ...)
|
|
98
99
|
end
|
|
99
100
|
end
|
|
100
101
|
|
|
101
|
-
|
|
102
|
-
use_symbol(Faraday::Request, key,
|
|
102
|
+
def request(key, ...)
|
|
103
|
+
use_symbol(Faraday::Request, key, ...)
|
|
103
104
|
end
|
|
104
105
|
|
|
105
|
-
|
|
106
|
-
use_symbol(Faraday::Response,
|
|
106
|
+
def response(...)
|
|
107
|
+
use_symbol(Faraday::Response, ...)
|
|
107
108
|
end
|
|
108
109
|
|
|
109
|
-
|
|
110
|
+
def adapter(klass = NO_ARGUMENT, *args, **kwargs, &block)
|
|
110
111
|
return @adapter if klass == NO_ARGUMENT || klass.nil?
|
|
111
112
|
|
|
112
113
|
klass = Faraday::Adapter.lookup_middleware(klass) if klass.is_a?(Symbol)
|
|
113
|
-
@adapter = self.class::Handler.new(klass, *args, &block)
|
|
114
|
+
@adapter = self.class::Handler.new(klass, *args, **kwargs, &block)
|
|
114
115
|
end
|
|
115
116
|
|
|
116
117
|
## methods to push onto the various positions in the stack:
|
|
117
118
|
|
|
118
|
-
|
|
119
|
+
def insert(index, ...)
|
|
119
120
|
raise_if_locked
|
|
120
121
|
index = assert_index(index)
|
|
121
|
-
handler = self.class::Handler.new(
|
|
122
|
+
handler = self.class::Handler.new(...)
|
|
122
123
|
@handlers.insert(index, handler)
|
|
123
124
|
end
|
|
124
125
|
|
|
125
126
|
alias insert_before insert
|
|
126
127
|
|
|
127
|
-
|
|
128
|
+
def insert_after(index, ...)
|
|
128
129
|
index = assert_index(index)
|
|
129
|
-
insert(index + 1,
|
|
130
|
+
insert(index + 1, ...)
|
|
130
131
|
end
|
|
131
132
|
|
|
132
|
-
|
|
133
|
+
def swap(index, ...)
|
|
133
134
|
raise_if_locked
|
|
134
135
|
index = assert_index(index)
|
|
135
136
|
@handlers.delete_at(index)
|
|
136
|
-
insert(index,
|
|
137
|
+
insert(index, ...)
|
|
137
138
|
end
|
|
138
139
|
|
|
139
140
|
def delete(handler)
|
|
@@ -220,7 +221,7 @@ module Faraday
|
|
|
220
221
|
end
|
|
221
222
|
|
|
222
223
|
def raise_if_adapter(klass)
|
|
223
|
-
return unless
|
|
224
|
+
return unless klass <= Faraday::Adapter
|
|
224
225
|
|
|
225
226
|
raise 'Adapter should be set using the `adapter` method, not `use`'
|
|
226
227
|
end
|
|
@@ -233,12 +234,8 @@ module Faraday
|
|
|
233
234
|
!@adapter.nil?
|
|
234
235
|
end
|
|
235
236
|
|
|
236
|
-
def
|
|
237
|
-
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
ruby2_keywords def use_symbol(mod, key, *args, &block)
|
|
241
|
-
use(mod.lookup_middleware(key), *args, &block)
|
|
237
|
+
def use_symbol(mod, key, ...)
|
|
238
|
+
use(mod.lookup_middleware(key), ...)
|
|
242
239
|
end
|
|
243
240
|
|
|
244
241
|
def assert_index(index)
|
|
@@ -10,11 +10,13 @@ module Faraday
|
|
|
10
10
|
# lifecycle to a given Logger object. By default, this logs to STDOUT. See
|
|
11
11
|
# Faraday::Logging::Formatter to see specifically what is logged.
|
|
12
12
|
class Logger < Middleware
|
|
13
|
+
DEFAULT_OPTIONS = { formatter: Logging::Formatter }.merge(Logging::Formatter::DEFAULT_OPTIONS).freeze
|
|
14
|
+
|
|
13
15
|
def initialize(app, logger = nil, options = {})
|
|
14
|
-
super(app)
|
|
16
|
+
super(app, options)
|
|
15
17
|
logger ||= ::Logger.new($stdout)
|
|
16
|
-
formatter_class = options.delete(:formatter)
|
|
17
|
-
@formatter = formatter_class.new(logger: logger, options: options)
|
|
18
|
+
formatter_class = @options.delete(:formatter)
|
|
19
|
+
@formatter = formatter_class.new(logger: logger, options: @options)
|
|
18
20
|
yield @formatter if block_given?
|
|
19
21
|
end
|
|
20
22
|
|
|
@@ -8,30 +8,30 @@ module Faraday
|
|
|
8
8
|
# rubocop:disable Naming/ConstantName
|
|
9
9
|
ClientErrorStatuses = (400...500)
|
|
10
10
|
ServerErrorStatuses = (500...600)
|
|
11
|
+
ClientErrorStatusesWithCustomExceptions = {
|
|
12
|
+
400 => Faraday::BadRequestError,
|
|
13
|
+
401 => Faraday::UnauthorizedError,
|
|
14
|
+
403 => Faraday::ForbiddenError,
|
|
15
|
+
404 => Faraday::ResourceNotFound,
|
|
16
|
+
408 => Faraday::RequestTimeoutError,
|
|
17
|
+
409 => Faraday::ConflictError,
|
|
18
|
+
422 => Faraday::UnprocessableContentError,
|
|
19
|
+
429 => Faraday::TooManyRequestsError
|
|
20
|
+
}.freeze
|
|
11
21
|
# rubocop:enable Naming/ConstantName
|
|
12
22
|
|
|
23
|
+
DEFAULT_OPTIONS = { include_request: true, allowed_statuses: [] }.freeze
|
|
24
|
+
|
|
13
25
|
def on_complete(env)
|
|
26
|
+
return if Array(options[:allowed_statuses]).include?(env[:status])
|
|
27
|
+
|
|
14
28
|
case env[:status]
|
|
15
|
-
when
|
|
16
|
-
raise
|
|
17
|
-
when 401
|
|
18
|
-
raise Faraday::UnauthorizedError, response_values(env)
|
|
19
|
-
when 403
|
|
20
|
-
raise Faraday::ForbiddenError, response_values(env)
|
|
21
|
-
when 404
|
|
22
|
-
raise Faraday::ResourceNotFound, response_values(env)
|
|
29
|
+
when *ClientErrorStatusesWithCustomExceptions.keys
|
|
30
|
+
raise ClientErrorStatusesWithCustomExceptions[env[:status]], response_values(env)
|
|
23
31
|
when 407
|
|
24
32
|
# mimic the behavior that we get with proxy requests with HTTPS
|
|
25
33
|
msg = %(407 "Proxy Authentication Required")
|
|
26
34
|
raise Faraday::ProxyAuthError.new(msg, response_values(env))
|
|
27
|
-
when 408
|
|
28
|
-
raise Faraday::RequestTimeoutError, response_values(env)
|
|
29
|
-
when 409
|
|
30
|
-
raise Faraday::ConflictError, response_values(env)
|
|
31
|
-
when 422
|
|
32
|
-
raise Faraday::UnprocessableEntityError, response_values(env)
|
|
33
|
-
when 429
|
|
34
|
-
raise Faraday::TooManyRequestsError, response_values(env)
|
|
35
35
|
when ClientErrorStatuses
|
|
36
36
|
raise Faraday::ClientError, response_values(env)
|
|
37
37
|
when ServerErrorStatuses
|
|
@@ -58,7 +58,7 @@ module Faraday
|
|
|
58
58
|
|
|
59
59
|
# Include the request data by default. If the middleware was explicitly
|
|
60
60
|
# configured to _not_ include request data, then omit it.
|
|
61
|
-
return response unless options
|
|
61
|
+
return response unless options[:include_request]
|
|
62
62
|
|
|
63
63
|
response.merge(
|
|
64
64
|
request: {
|
data/lib/faraday/response.rb
CHANGED
|
@@ -33,6 +33,10 @@ module Faraday
|
|
|
33
33
|
finished? ? env.body : nil
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
+
def url
|
|
37
|
+
finished? ? env.url : nil
|
|
38
|
+
end
|
|
39
|
+
|
|
36
40
|
def finished?
|
|
37
41
|
!!env
|
|
38
42
|
end
|
|
@@ -60,9 +64,9 @@ module Faraday
|
|
|
60
64
|
|
|
61
65
|
def to_hash
|
|
62
66
|
{
|
|
63
|
-
status:
|
|
64
|
-
response_headers:
|
|
65
|
-
url:
|
|
67
|
+
status: status, body: body,
|
|
68
|
+
response_headers: headers,
|
|
69
|
+
url: url
|
|
66
70
|
}
|
|
67
71
|
end
|
|
68
72
|
|
data/lib/faraday/version.rb
CHANGED
data/lib/faraday.rb
CHANGED
|
@@ -311,6 +311,39 @@ RSpec.describe Faraday::Connection do
|
|
|
311
311
|
end
|
|
312
312
|
end
|
|
313
313
|
|
|
314
|
+
context 'with protocol-relative URL (GHSA-33mh-2634-fwr2)' do
|
|
315
|
+
it 'does not allow host override with //evil.com/path' do
|
|
316
|
+
conn.url_prefix = 'http://httpbingo.org/api'
|
|
317
|
+
uri = conn.build_exclusive_url('//evil.com/path')
|
|
318
|
+
expect(uri.host).to eq('httpbingo.org')
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
it 'does not allow host override with //evil.com:8080/path' do
|
|
322
|
+
conn.url_prefix = 'http://httpbingo.org/api'
|
|
323
|
+
uri = conn.build_exclusive_url('//evil.com:8080/path')
|
|
324
|
+
expect(uri.host).to eq('httpbingo.org')
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
it 'does not allow host override with //user:pass@evil.com/path' do
|
|
328
|
+
conn.url_prefix = 'http://httpbingo.org/api'
|
|
329
|
+
uri = conn.build_exclusive_url('//user:pass@evil.com/path')
|
|
330
|
+
expect(uri.host).to eq('httpbingo.org')
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
it 'does not allow host override with ///evil.com' do
|
|
334
|
+
conn.url_prefix = 'http://httpbingo.org/api'
|
|
335
|
+
uri = conn.build_exclusive_url('///evil.com')
|
|
336
|
+
expect(uri.host).to eq('httpbingo.org')
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
it 'still allows single-slash absolute paths' do
|
|
340
|
+
conn.url_prefix = 'http://httpbingo.org/api'
|
|
341
|
+
uri = conn.build_exclusive_url('/safe/path')
|
|
342
|
+
expect(uri.host).to eq('httpbingo.org')
|
|
343
|
+
expect(uri.path).to eq('/safe/path')
|
|
344
|
+
end
|
|
345
|
+
end
|
|
346
|
+
|
|
314
347
|
context 'with a custom `default_uri_parser`' do
|
|
315
348
|
let(:url) { 'http://httpbingo.org' }
|
|
316
349
|
let(:parser) { Addressable::URI }
|