excon 0.62.0 → 0.63.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of excon might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/.github/stale.yml +17 -0
- data/.travis.yml +7 -19
- data/LICENSE.md +1 -1
- data/README.md +5 -4
- data/changelog.txt +25 -0
- data/data/cacert.pem +440 -994
- data/excon.gemspec +9 -0
- data/lib/excon.rb +9 -1
- data/lib/excon/connection.rb +52 -35
- data/lib/excon/constants.rb +33 -13
- data/lib/excon/error.rb +3 -0
- data/lib/excon/instrumentors/logging_instrumentor.rb +3 -14
- data/lib/excon/instrumentors/standard_instrumentor.rb +1 -8
- data/lib/excon/middlewares/base.rb +6 -0
- data/lib/excon/middlewares/expects.rb +6 -0
- data/lib/excon/middlewares/idempotent.rb +20 -3
- data/lib/excon/middlewares/instrumentor.rb +8 -0
- data/lib/excon/middlewares/mock.rb +8 -0
- data/lib/excon/middlewares/response_parser.rb +3 -0
- data/lib/excon/pretty_printer.rb +1 -8
- data/lib/excon/socket.rb +36 -10
- data/lib/excon/ssl_socket.rb +7 -0
- data/lib/excon/utils.rb +23 -4
- data/lib/excon/version.rb +1 -1
- data/spec/excon/test/server_spec.rb +2 -2
- data/spec/helpers/warning_helpers.rb +9 -0
- data/spec/requests/unix_socket_spec.rb +2 -10
- data/spec/requests/validation_spec.rb +80 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/support/shared_contexts/test_stub_context.rb +11 -0
- data/spec/support/shared_examples/shared_example_for_clients.rb +6 -4
- data/tests/authorization_header_tests.rb +19 -21
- data/tests/bad_tests.rb +22 -0
- data/tests/batch_requests.rb +1 -1
- data/tests/complete_responses.rb +1 -1
- data/tests/data/127.0.0.1.cert.crt +15 -18
- data/tests/data/127.0.0.1.cert.key +28 -27
- data/tests/data/excon.cert.crt +15 -18
- data/tests/data/excon.cert.key +28 -27
- data/tests/error_tests.rb +1 -1
- data/tests/instrumentors/logging_instrumentor_tests.rb +28 -0
- data/tests/middlewares/decompress_tests.rb +1 -1
- data/tests/middlewares/idempotent_tests.rb +56 -17
- data/tests/middlewares/mock_tests.rb +2 -2
- data/tests/pipeline_tests.rb +1 -1
- data/tests/request_tests.rb +5 -6
- data/tests/response_tests.rb +1 -1
- data/tests/servers/bad.rb +5 -0
- data/tests/servers/good.rb +0 -8
- data/tests/servers/good_ipv4.rb +8 -0
- data/tests/servers/good_ipv6.rb +8 -0
- data/tests/test_helper.rb +27 -36
- metadata +17 -5
data/excon.gemspec
CHANGED
@@ -26,4 +26,13 @@ Gem::Specification.new do |s|
|
|
26
26
|
s.add_development_dependency('sinatra-contrib')
|
27
27
|
s.add_development_dependency('json', '>= 1.8.5')
|
28
28
|
s.add_development_dependency('puma')
|
29
|
+
|
30
|
+
s.metadata = {
|
31
|
+
'homepage_uri' => 'https://github.com/excon/excon',
|
32
|
+
'bug_tracker_uri' => 'https://github.com/excon/excon/issues',
|
33
|
+
'changelog_uri' => 'https://github.com/excon/excon/blob/master/changelog.txt',
|
34
|
+
'documentation_uri' => 'https://github.com/excon/excon/blob/master/README.md',
|
35
|
+
'source_code_uri' => 'https://github.com/excon/excon',
|
36
|
+
'wiki_uri' => 'https://github.com/excon/excon/wiki'
|
37
|
+
}
|
29
38
|
end
|
data/lib/excon.rb
CHANGED
@@ -23,11 +23,11 @@ require 'excon/middlewares/instrumentor'
|
|
23
23
|
require 'excon/middlewares/mock'
|
24
24
|
require 'excon/middlewares/response_parser'
|
25
25
|
|
26
|
+
require 'excon/error'
|
26
27
|
require 'excon/constants'
|
27
28
|
require 'excon/utils'
|
28
29
|
|
29
30
|
require 'excon/connection'
|
30
|
-
require 'excon/error'
|
31
31
|
require 'excon/headers'
|
32
32
|
require 'excon/response'
|
33
33
|
require 'excon/middlewares/decompress'
|
@@ -61,6 +61,14 @@ module Excon
|
|
61
61
|
if $VERBOSE || ENV['EXCON_DEBUG']
|
62
62
|
$stderr.puts "[excon][WARNING] #{warning}\n#{ caller.join("\n") }"
|
63
63
|
end
|
64
|
+
|
65
|
+
if @raise_on_warnings
|
66
|
+
raise Error::Warning.new(warning)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def set_raise_on_warnings!(should_raise)
|
71
|
+
@raise_on_warnings = should_raise
|
64
72
|
end
|
65
73
|
|
66
74
|
# Status of mocking
|
data/lib/excon/connection.rb
CHANGED
@@ -38,8 +38,8 @@ module Excon
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
def logger=(logger)
|
41
|
-
Excon::LoggingInstrumentor.logger = logger
|
42
41
|
@data[:instrumentor] = Excon::LoggingInstrumentor
|
42
|
+
@data[:logger] = logger
|
43
43
|
end
|
44
44
|
|
45
45
|
# Initializes a new Connection instance
|
@@ -67,8 +67,13 @@ module Excon
|
|
67
67
|
# the same goes for :middlewares
|
68
68
|
@data[:middlewares] = @data[:middlewares].dup
|
69
69
|
|
70
|
-
params = validate_params(:connection, params)
|
71
70
|
@data.merge!(params)
|
71
|
+
validate_params(:connection, @data, @data[:middlewares])
|
72
|
+
|
73
|
+
if @data.key?(:host) && !@data.key?(:hostname)
|
74
|
+
Excon.display_warning('hostname is missing! For IPv6 support, provide both host and hostname: Excon::Connection#new(:host => uri.host, :hostname => uri.hostname, ...).')
|
75
|
+
@data[:hostname] = @data[:host]
|
76
|
+
end
|
72
77
|
|
73
78
|
setup_proxy
|
74
79
|
|
@@ -138,7 +143,13 @@ module Excon
|
|
138
143
|
|
139
144
|
# add headers to request
|
140
145
|
datum[:headers].each do |key, values|
|
146
|
+
if key.to_s.match(/[\r\n]/)
|
147
|
+
raise Excon::Errors::InvalidHeaderKey.new(key.to_s.inspect + ' contains forbidden "\r" or "\n"')
|
148
|
+
end
|
141
149
|
[values].flatten.each do |value|
|
150
|
+
if value.to_s.match(/[\r\n]/)
|
151
|
+
raise Excon::Errors::InvalidHeaderValue.new(value.to_s.inspect + ' contains forbidden "\r" or "\n"')
|
152
|
+
end
|
142
153
|
request << key.to_s << ': ' << value.to_s << CR_NL
|
143
154
|
end
|
144
155
|
end
|
@@ -150,9 +161,7 @@ module Excon
|
|
150
161
|
socket.write(request) # write out request + headers
|
151
162
|
while true # write out body with chunked encoding
|
152
163
|
chunk = datum[:request_block].call
|
153
|
-
|
154
|
-
chunk.force_encoding('BINARY')
|
155
|
-
end
|
164
|
+
binary_encode(chunk)
|
156
165
|
if chunk.length > 0
|
157
166
|
socket.write(chunk.length.to_s(16) << CR_NL << chunk << CR_NL)
|
158
167
|
else
|
@@ -171,14 +180,10 @@ module Excon
|
|
171
180
|
end
|
172
181
|
|
173
182
|
# if request + headers is less than chunk size, fill with body
|
174
|
-
|
175
|
-
request.force_encoding('BINARY')
|
176
|
-
end
|
183
|
+
binary_encode(request)
|
177
184
|
chunk = body.read([datum[:chunk_size] - request.length, 0].max)
|
178
185
|
if chunk
|
179
|
-
|
180
|
-
chunk.force_encoding('BINARY')
|
181
|
-
end
|
186
|
+
binary_encode(chunk)
|
182
187
|
socket.write(request << chunk)
|
183
188
|
else
|
184
189
|
socket.write(request) # write out request + headers
|
@@ -191,7 +196,7 @@ module Excon
|
|
191
196
|
end
|
192
197
|
rescue => error
|
193
198
|
case error
|
194
|
-
when Excon::Errors::StubNotFound, Excon::Errors::Timeout
|
199
|
+
when Excon::Errors::InvalidHeaderKey, Excon::Errors::InvalidHeaderValue, Excon::Errors::StubNotFound, Excon::Errors::Timeout
|
195
200
|
raise(error)
|
196
201
|
else
|
197
202
|
raise_socket_error(error)
|
@@ -223,11 +228,17 @@ module Excon
|
|
223
228
|
# @option params [String] :path appears after 'scheme://host:port/'
|
224
229
|
# @option params [Hash] :query appended to the 'scheme://host:port/path/' in the form of '?key=value'
|
225
230
|
def request(params={}, &block)
|
226
|
-
params = validate_params(:request, params)
|
227
231
|
# @data has defaults, merge in new params to override
|
228
232
|
datum = @data.merge(params)
|
229
233
|
datum[:headers] = @data[:headers].merge(datum[:headers] || {})
|
230
234
|
|
235
|
+
validate_params(:request, params, datum[:middlewares])
|
236
|
+
# If the user passed in new middleware, we want to validate that the original connection parameters
|
237
|
+
# are still valid with the provided middleware.
|
238
|
+
if params[:middlewares]
|
239
|
+
validate_params(:connection, @data, datum[:middlewares])
|
240
|
+
end
|
241
|
+
|
231
242
|
if datum[:user] || datum[:password]
|
232
243
|
user, pass = Utils.unescape_uri(datum[:user].to_s), Utils.unescape_uri(datum[:password].to_s)
|
233
244
|
datum[:headers]['Authorization'] ||= 'Basic ' + ["#{user}:#{pass}"].pack('m').delete(Excon::CR_NL)
|
@@ -238,7 +249,6 @@ module Excon
|
|
238
249
|
else
|
239
250
|
datum[:headers]['Host'] ||= datum[:host] + port_string(datum)
|
240
251
|
end
|
241
|
-
datum[:retries_remaining] ||= datum[:retry_limit]
|
242
252
|
|
243
253
|
# if path is empty or doesn't start with '/', insert one
|
244
254
|
unless datum[:path][0, 1] == '/'
|
@@ -278,6 +288,10 @@ module Excon
|
|
278
288
|
end
|
279
289
|
rescue => error
|
280
290
|
reset
|
291
|
+
|
292
|
+
# If we didn't get far enough to initialize datum and the middleware stack, just raise
|
293
|
+
raise error if !datum
|
294
|
+
|
281
295
|
datum[:error] = error
|
282
296
|
if datum[:stack]
|
283
297
|
datum[:stack].error_call(datum)
|
@@ -355,15 +369,7 @@ module Excon
|
|
355
369
|
vars = instance_variables.inject({}) do |accum, var|
|
356
370
|
accum.merge!(var.to_sym => instance_variable_get(var))
|
357
371
|
end
|
358
|
-
|
359
|
-
vars[:'@data'] = vars[:'@data'].dup
|
360
|
-
vars[:'@data'][:headers] = vars[:'@data'][:headers].dup
|
361
|
-
vars[:'@data'][:headers]['Authorization'] = REDACTED
|
362
|
-
end
|
363
|
-
if vars[:'@data'][:password]
|
364
|
-
vars[:'@data'] = vars[:'@data'].dup
|
365
|
-
vars[:'@data'][:password] = REDACTED
|
366
|
-
end
|
372
|
+
vars[:'@data'] = Utils.redact(vars[:'@data'])
|
367
373
|
inspection = '#<Excon::Connection:'
|
368
374
|
inspection += (object_id << 1).to_s(16)
|
369
375
|
vars.each do |key, value|
|
@@ -373,6 +379,10 @@ module Excon
|
|
373
379
|
inspection
|
374
380
|
end
|
375
381
|
|
382
|
+
def valid_request_keys(middlewares)
|
383
|
+
valid_middleware_keys(middlewares) + Excon::VALID_REQUEST_KEYS
|
384
|
+
end
|
385
|
+
|
376
386
|
private
|
377
387
|
|
378
388
|
def detect_content_length(body)
|
@@ -387,27 +397,34 @@ module Excon
|
|
387
397
|
end
|
388
398
|
end
|
389
399
|
|
390
|
-
def
|
400
|
+
def valid_middleware_keys(middlewares)
|
401
|
+
middlewares.flat_map(&:valid_parameter_keys)
|
402
|
+
end
|
403
|
+
|
404
|
+
def validate_params(validation, params, middlewares)
|
391
405
|
valid_keys = case validation
|
392
406
|
when :connection
|
393
|
-
Excon::VALID_CONNECTION_KEYS
|
407
|
+
valid_middleware_keys(middlewares) + Excon::VALID_CONNECTION_KEYS
|
394
408
|
when :request
|
395
|
-
|
409
|
+
valid_request_keys(middlewares)
|
410
|
+
else
|
411
|
+
raise ArgumentError.new("Invalid validation type '#{validation}'")
|
396
412
|
end
|
413
|
+
|
397
414
|
invalid_keys = params.keys - valid_keys
|
398
415
|
unless invalid_keys.empty?
|
399
416
|
Excon.display_warning("Invalid Excon #{validation} keys: #{invalid_keys.map(&:inspect).join(', ')}")
|
400
|
-
# FIXME: for now, just warn, don't mutate, give things (ie fog) a chance to catch up
|
401
|
-
#params = params.dup
|
402
|
-
#invalid_keys.each {|key| params.delete(key) }
|
403
|
-
end
|
404
417
|
|
405
|
-
|
406
|
-
|
407
|
-
|
418
|
+
if validation == :request
|
419
|
+
deprecated_keys = invalid_keys & Excon::DEPRECATED_VALID_REQUEST_KEYS.keys
|
420
|
+
mw_msg = deprecated_keys.map do |k|
|
421
|
+
"#{k}: #{Excon::DEPRECATED_VALID_REQUEST_KEYS[k]}"
|
422
|
+
end.join(', ')
|
423
|
+
Excon.display_warning(
|
424
|
+
"The following request keys are only valid with the associated middleware: #{mw_msg}"
|
425
|
+
)
|
426
|
+
end
|
408
427
|
end
|
409
|
-
|
410
|
-
params
|
411
428
|
end
|
412
429
|
|
413
430
|
def response(datum={})
|
data/lib/excon/constants.rb
CHANGED
@@ -14,6 +14,12 @@ module Excon
|
|
14
14
|
|
15
15
|
DEFAULT_RETRY_LIMIT = 4
|
16
16
|
|
17
|
+
DEFAULT_RETRY_ERRORS = [
|
18
|
+
Excon::Error::Timeout,
|
19
|
+
Excon::Error::Socket,
|
20
|
+
Excon::Error::HTTPStatus
|
21
|
+
]
|
22
|
+
|
17
23
|
FORCE_ENC = CR_NL.respond_to?(:force_encoding)
|
18
24
|
|
19
25
|
HTTP_1_1 = " HTTP/1.1\r\n"
|
@@ -33,19 +39,17 @@ module Excon
|
|
33
39
|
VERSIONS = "#{USER_AGENT} (#{RUBY_PLATFORM}) ruby/#{RUBY_VERSION}"
|
34
40
|
|
35
41
|
VALID_REQUEST_KEYS = [
|
42
|
+
:allow_unstubbed_requests,
|
36
43
|
:body,
|
37
|
-
:captures,
|
38
44
|
:chunk_size,
|
39
45
|
:debug_request,
|
40
46
|
:debug_response,
|
41
|
-
:expects,
|
42
47
|
:headers,
|
43
|
-
:
|
44
|
-
:
|
45
|
-
:instrumentor_name,
|
48
|
+
:instrumentor, # Used for setting logging within Connection
|
49
|
+
:logger,
|
46
50
|
:method,
|
47
51
|
:middlewares,
|
48
|
-
:
|
52
|
+
:password,
|
49
53
|
:path,
|
50
54
|
:persistent,
|
51
55
|
:pipeline,
|
@@ -53,9 +57,8 @@ module Excon
|
|
53
57
|
:read_timeout,
|
54
58
|
:request_block,
|
55
59
|
:response_block,
|
56
|
-
:
|
57
|
-
:
|
58
|
-
:retry_interval,
|
60
|
+
:stubs,
|
61
|
+
:user,
|
59
62
|
:versions,
|
60
63
|
:write_timeout
|
61
64
|
]
|
@@ -74,12 +77,12 @@ module Excon
|
|
74
77
|
:private_key_path,
|
75
78
|
:connect_timeout,
|
76
79
|
:family,
|
80
|
+
:keepalive,
|
77
81
|
:host,
|
78
82
|
:hostname,
|
79
83
|
:omit_default_port,
|
80
84
|
:nonblock,
|
81
85
|
:reuseaddr,
|
82
|
-
:password,
|
83
86
|
:port,
|
84
87
|
:proxy,
|
85
88
|
:scheme,
|
@@ -91,12 +94,26 @@ module Excon
|
|
91
94
|
:ssl_verify_peer,
|
92
95
|
:ssl_verify_peer_host,
|
93
96
|
:ssl_version,
|
97
|
+
:ssl_min_version,
|
98
|
+
:ssl_max_version,
|
99
|
+
:ssl_uri_schemes,
|
94
100
|
:tcp_nodelay,
|
95
101
|
:thread_safe_sockets,
|
96
102
|
:uri_parser,
|
97
|
-
:user
|
98
103
|
]
|
99
104
|
|
105
|
+
DEPRECATED_VALID_REQUEST_KEYS = {
|
106
|
+
:captures => 'Mock',
|
107
|
+
:expects => 'Expects',
|
108
|
+
:idempotent => 'Idempotent',
|
109
|
+
:instrumentor_name => 'Instrumentor',
|
110
|
+
:mock => 'Mock',
|
111
|
+
:retries_remaining => 'Idempotent', # referenced in Instrumentor, but only relevant with Idempotent
|
112
|
+
:retry_errors => 'Idempotent',
|
113
|
+
:retry_interval => 'Idempotent',
|
114
|
+
:retry_limit => 'Idempotent' # referenced in Instrumentor, but only relevant with Idempotent
|
115
|
+
}
|
116
|
+
|
100
117
|
unless ::IO.const_defined?(:WaitReadable)
|
101
118
|
class ::IO
|
102
119
|
module WaitReadable; end
|
@@ -112,12 +129,14 @@ module Excon
|
|
112
129
|
DEFAULTS = {
|
113
130
|
:chunk_size => CHUNK_SIZE || DEFAULT_CHUNK_SIZE,
|
114
131
|
# see https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28default.29
|
115
|
-
|
132
|
+
# list provided then had DES related things sorted to the end
|
133
|
+
:ciphers => 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:DES-CBC3-SHA:!DSS',
|
116
134
|
:connect_timeout => 60,
|
117
135
|
:debug_request => false,
|
118
136
|
:debug_response => false,
|
119
137
|
:headers => {
|
120
|
-
'User-Agent' => USER_AGENT
|
138
|
+
'User-Agent' => USER_AGENT,
|
139
|
+
'Accept' => '*/*'
|
121
140
|
},
|
122
141
|
:idempotent => false,
|
123
142
|
:instrumentor_name => 'excon',
|
@@ -133,6 +152,7 @@ module Excon
|
|
133
152
|
:omit_default_port => false,
|
134
153
|
:persistent => false,
|
135
154
|
:read_timeout => 60,
|
155
|
+
:retry_errors => DEFAULT_RETRY_ERRORS,
|
136
156
|
:retry_limit => DEFAULT_RETRY_LIMIT,
|
137
157
|
:ssl_verify_peer => true,
|
138
158
|
:ssl_uri_schemes => [HTTPS],
|
data/lib/excon/error.rb
CHANGED
@@ -6,6 +6,7 @@ module Excon
|
|
6
6
|
|
7
7
|
class StubNotFound < Error; end
|
8
8
|
class InvalidStub < Error; end
|
9
|
+
class Warning < Error; end
|
9
10
|
|
10
11
|
# Socket related errors
|
11
12
|
class Socket < Error
|
@@ -45,6 +46,8 @@ or:
|
|
45
46
|
end
|
46
47
|
end
|
47
48
|
|
49
|
+
class InvalidHeaderKey < Error; end
|
50
|
+
class InvalidHeaderValue < Error; end
|
48
51
|
class Timeout < Error; end
|
49
52
|
class ResponseParse < Error; end
|
50
53
|
class ProxyParse < Error; end
|
@@ -2,23 +2,12 @@ require 'logger'
|
|
2
2
|
|
3
3
|
module Excon
|
4
4
|
class LoggingInstrumentor
|
5
|
-
# Returns the Logger object for the LoggingInstrumentor. If one doesn't
|
6
|
-
# already exist, then one will be created using $stderr as the output
|
7
|
-
# stream.
|
8
|
-
#
|
9
|
-
def self.logger
|
10
|
-
@logger ||= Logger.new($stderr)
|
11
|
-
end
|
12
|
-
|
13
|
-
# Sets the logger object for the LoggingInstrumentor.
|
14
|
-
#
|
15
|
-
def self.logger=(logger)
|
16
|
-
@logger = logger
|
17
|
-
end
|
18
5
|
|
19
6
|
def self.instrument(name, params = {}, &block)
|
20
7
|
params = params.dup
|
21
8
|
|
9
|
+
logger = params[:logger] || Logger.new($stderr)
|
10
|
+
|
22
11
|
# reduce duplication/noise of output
|
23
12
|
params.delete(:connection)
|
24
13
|
params.delete(:stack)
|
@@ -51,7 +40,7 @@ module Excon
|
|
51
40
|
end
|
52
41
|
end
|
53
42
|
|
54
|
-
|
43
|
+
logger.log(Logger::INFO, info) if info
|
55
44
|
|
56
45
|
yield if block_given?
|
57
46
|
end
|
@@ -8,14 +8,7 @@ module Excon
|
|
8
8
|
params.delete(:connection)
|
9
9
|
params.delete(:stack)
|
10
10
|
|
11
|
-
|
12
|
-
params[:headers] = params[:headers].dup
|
13
|
-
params[:headers]['Authorization'] = REDACTED
|
14
|
-
end
|
15
|
-
|
16
|
-
if params.has_key?(:password)
|
17
|
-
params[:password] = REDACTED
|
18
|
-
end
|
11
|
+
params = Utils.redact(params)
|
19
12
|
|
20
13
|
$stderr.puts(name)
|
21
14
|
Excon::PrettyPrinter.pp($stderr, params)
|
@@ -2,6 +2,12 @@
|
|
2
2
|
module Excon
|
3
3
|
module Middleware
|
4
4
|
class Base
|
5
|
+
# Returns the list of parameters that this middleware uses that are valid
|
6
|
+
# as arguments to `Connection#request` or `Connection#new`.
|
7
|
+
def self.valid_parameter_keys
|
8
|
+
[]
|
9
|
+
end
|
10
|
+
|
5
11
|
def initialize(stack)
|
6
12
|
@stack = stack
|
7
13
|
end
|
@@ -2,6 +2,12 @@
|
|
2
2
|
module Excon
|
3
3
|
module Middleware
|
4
4
|
class Expects < Excon::Middleware::Base
|
5
|
+
def self.valid_parameter_keys
|
6
|
+
[
|
7
|
+
:expects
|
8
|
+
]
|
9
|
+
end
|
10
|
+
|
5
11
|
def response_call(datum)
|
6
12
|
if datum.has_key?(:expects) && ![*datum[:expects]].include?(datum[:response][:status])
|
7
13
|
raise(
|
@@ -1,7 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
require 'set'
|
3
|
+
|
2
4
|
module Excon
|
3
5
|
module Middleware
|
4
6
|
class Idempotent < Excon::Middleware::Base
|
7
|
+
def self.valid_parameter_keys
|
8
|
+
[
|
9
|
+
:idempotent,
|
10
|
+
:retries_remaining,
|
11
|
+
:retry_errors,
|
12
|
+
:retry_interval,
|
13
|
+
:retry_limit
|
14
|
+
]
|
15
|
+
end
|
16
|
+
|
17
|
+
def request_call(datum)
|
18
|
+
datum[:retries_remaining] ||= datum[:retry_limit]
|
19
|
+
@stack.request_call(datum)
|
20
|
+
end
|
21
|
+
|
5
22
|
def error_call(datum)
|
6
23
|
if datum[:idempotent]
|
7
24
|
if datum.has_key?(:request_block)
|
@@ -21,15 +38,15 @@ module Excon
|
|
21
38
|
end
|
22
39
|
end
|
23
40
|
|
24
|
-
if datum[:idempotent] && [
|
25
|
-
Excon::Errors::HTTPStatusError].any? {|ex| datum[:error].kind_of?(ex) } && datum[:retries_remaining] > 1
|
41
|
+
if datum[:idempotent] && datum[:retry_errors].any? {|ex| datum[:error].kind_of?(ex) } && datum[:retries_remaining] > 1
|
26
42
|
|
27
43
|
sleep(datum[:retry_interval]) if datum[:retry_interval]
|
28
44
|
|
29
45
|
# reduces remaining retries, reset connection, and restart request_call
|
30
46
|
datum[:retries_remaining] -= 1
|
31
47
|
connection = datum.delete(:connection)
|
32
|
-
|
48
|
+
valid_keys = Set.new(connection.valid_request_keys(datum[:middlewares]))
|
49
|
+
datum.select! {|key, _| valid_keys.include?(key) }
|
33
50
|
connection.request(datum)
|
34
51
|
else
|
35
52
|
@stack.error_call(datum)
|