bunny 2.7.4 → 2.22.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 +5 -5
- data/README.md +61 -35
- data/lib/bunny/channel.rb +186 -50
- data/lib/bunny/channel_id_allocator.rb +3 -1
- data/lib/bunny/consumer.rb +2 -2
- data/lib/bunny/consumer_work_pool.rb +2 -1
- data/lib/bunny/cruby/socket.rb +3 -0
- data/lib/bunny/cruby/ssl_socket.rb +6 -1
- data/lib/bunny/delivery_info.rb +1 -1
- data/lib/bunny/heartbeat_sender.rb +2 -1
- data/lib/bunny/jruby/ssl_socket.rb +5 -0
- data/lib/bunny/queue.rb +36 -8
- data/lib/bunny/reader_loop.rb +22 -10
- data/lib/bunny/session.rb +152 -65
- data/lib/bunny/test_kit.rb +14 -0
- data/lib/bunny/transport.rb +132 -49
- data/lib/bunny/version.rb +1 -1
- data/lib/bunny.rb +45 -4
- metadata +37 -225
- data/.github/ISSUE_TEMPLATE.md +0 -18
- data/.gitignore +0 -28
- data/.rspec +0 -1
- data/.travis.yml +0 -20
- data/.yardopts +0 -8
- data/CONTRIBUTING.md +0 -111
- data/ChangeLog.md +0 -1831
- data/Gemfile +0 -53
- data/LICENSE +0 -21
- data/Rakefile +0 -46
- data/benchmarks/basic_publish/with_128K_messages.rb +0 -35
- data/benchmarks/basic_publish/with_1k_messages.rb +0 -35
- data/benchmarks/basic_publish/with_4K_messages.rb +0 -35
- data/benchmarks/basic_publish/with_64K_messages.rb +0 -35
- data/benchmarks/channel_open.rb +0 -28
- data/benchmarks/mutex_and_monitor.rb +0 -42
- data/benchmarks/queue_declare.rb +0 -29
- data/benchmarks/queue_declare_and_bind.rb +0 -29
- data/benchmarks/queue_declare_bind_and_delete.rb +0 -29
- data/benchmarks/synchronized_sorted_set.rb +0 -53
- data/benchmarks/write_vs_write_nonblock.rb +0 -49
- data/bin/ci/before_build +0 -46
- data/bunny.gemspec +0 -35
- data/docker/Dockerfile +0 -16
- data/docker/docker-entrypoint.sh +0 -37
- data/docker-compose.yml +0 -18
- data/examples/connection/authentication_failure.rb +0 -16
- data/examples/connection/automatic_recovery_with_basic_get.rb +0 -40
- data/examples/connection/automatic_recovery_with_client_named_queues.rb +0 -36
- data/examples/connection/automatic_recovery_with_multiple_consumers.rb +0 -46
- data/examples/connection/automatic_recovery_with_republishing.rb +0 -109
- data/examples/connection/automatic_recovery_with_server_named_queues.rb +0 -35
- data/examples/connection/channel_level_exception.rb +0 -27
- data/examples/connection/disabled_automatic_recovery.rb +0 -34
- data/examples/connection/heartbeat.rb +0 -17
- data/examples/connection/manually_reconnecting_consumer.rb +0 -23
- data/examples/connection/manually_reconnecting_publisher.rb +0 -28
- data/examples/connection/unknown_host.rb +0 -16
- data/examples/consumers/high_and_low_priority.rb +0 -50
- data/examples/guides/exchanges/direct_exchange_routing.rb +0 -36
- data/examples/guides/exchanges/fanout_exchange_routing.rb +0 -28
- data/examples/guides/exchanges/headers_exchange_routing.rb +0 -31
- data/examples/guides/exchanges/mandatory_messages.rb +0 -30
- data/examples/guides/extensions/alternate_exchange.rb +0 -30
- data/examples/guides/extensions/basic_nack.rb +0 -33
- data/examples/guides/extensions/connection_blocked.rb +0 -35
- data/examples/guides/extensions/consumer_cancellation_notification.rb +0 -39
- data/examples/guides/extensions/dead_letter_exchange.rb +0 -32
- data/examples/guides/extensions/exchange_to_exchange_bindings.rb +0 -29
- data/examples/guides/extensions/per_message_ttl.rb +0 -36
- data/examples/guides/extensions/per_queue_message_ttl.rb +0 -36
- data/examples/guides/extensions/publisher_confirms.rb +0 -28
- data/examples/guides/extensions/queue_lease.rb +0 -26
- data/examples/guides/extensions/sender_selected_distribution.rb +0 -32
- data/examples/guides/getting_started/blabbr.rb +0 -27
- data/examples/guides/getting_started/hello_world.rb +0 -22
- data/examples/guides/getting_started/weathr.rb +0 -49
- data/examples/guides/queues/one_off_consumer.rb +0 -25
- data/examples/guides/queues/redeliveries.rb +0 -81
- data/profiling/basic_publish/with_4K_messages.rb +0 -33
- data/repl +0 -3
- data/spec/config/enabled_plugins +0 -1
- data/spec/config/rabbitmq.config +0 -19
- data/spec/higher_level_api/integration/basic_ack_spec.rb +0 -230
- data/spec/higher_level_api/integration/basic_cancel_spec.rb +0 -142
- data/spec/higher_level_api/integration/basic_consume_spec.rb +0 -349
- data/spec/higher_level_api/integration/basic_consume_with_objects_spec.rb +0 -54
- data/spec/higher_level_api/integration/basic_get_spec.rb +0 -80
- data/spec/higher_level_api/integration/basic_nack_spec.rb +0 -82
- data/spec/higher_level_api/integration/basic_publish_spec.rb +0 -74
- data/spec/higher_level_api/integration/basic_qos_spec.rb +0 -57
- data/spec/higher_level_api/integration/basic_reject_spec.rb +0 -152
- data/spec/higher_level_api/integration/basic_return_spec.rb +0 -33
- data/spec/higher_level_api/integration/channel_close_spec.rb +0 -25
- data/spec/higher_level_api/integration/channel_open_spec.rb +0 -57
- data/spec/higher_level_api/integration/connection_recovery_spec.rb +0 -471
- data/spec/higher_level_api/integration/connection_spec.rb +0 -559
- data/spec/higher_level_api/integration/connection_stop_spec.rb +0 -83
- data/spec/higher_level_api/integration/consumer_cancellation_notification_spec.rb +0 -128
- data/spec/higher_level_api/integration/dead_lettering_spec.rb +0 -75
- data/spec/higher_level_api/integration/exchange_bind_spec.rb +0 -31
- data/spec/higher_level_api/integration/exchange_declare_spec.rb +0 -237
- data/spec/higher_level_api/integration/exchange_delete_spec.rb +0 -105
- data/spec/higher_level_api/integration/exchange_unbind_spec.rb +0 -40
- data/spec/higher_level_api/integration/exclusive_queue_spec.rb +0 -28
- data/spec/higher_level_api/integration/heartbeat_spec.rb +0 -49
- data/spec/higher_level_api/integration/merry_go_round_spec.rb +0 -85
- data/spec/higher_level_api/integration/message_properties_access_spec.rb +0 -95
- data/spec/higher_level_api/integration/predeclared_exchanges_spec.rb +0 -24
- data/spec/higher_level_api/integration/publisher_confirms_spec.rb +0 -191
- data/spec/higher_level_api/integration/publishing_edge_cases_spec.rb +0 -87
- data/spec/higher_level_api/integration/queue_bind_spec.rb +0 -109
- data/spec/higher_level_api/integration/queue_declare_spec.rb +0 -221
- data/spec/higher_level_api/integration/queue_delete_spec.rb +0 -41
- data/spec/higher_level_api/integration/queue_purge_spec.rb +0 -30
- data/spec/higher_level_api/integration/queue_unbind_spec.rb +0 -54
- data/spec/higher_level_api/integration/read_only_consumer_spec.rb +0 -60
- data/spec/higher_level_api/integration/sender_selected_distribution_spec.rb +0 -36
- data/spec/higher_level_api/integration/tls_connection_spec.rb +0 -222
- data/spec/higher_level_api/integration/tx_commit_spec.rb +0 -21
- data/spec/higher_level_api/integration/tx_rollback_spec.rb +0 -21
- data/spec/higher_level_api/integration/with_channel_spec.rb +0 -25
- data/spec/issues/issue100_spec.rb +0 -42
- data/spec/issues/issue141_spec.rb +0 -43
- data/spec/issues/issue202_spec.rb +0 -15
- data/spec/issues/issue224_spec.rb +0 -40
- data/spec/issues/issue465_spec.rb +0 -32
- data/spec/issues/issue78_spec.rb +0 -72
- data/spec/issues/issue83_spec.rb +0 -30
- data/spec/issues/issue97_attachment.json +0 -1
- data/spec/issues/issue97_spec.rb +0 -175
- data/spec/lower_level_api/integration/basic_cancel_spec.rb +0 -83
- data/spec/lower_level_api/integration/basic_consume_spec.rb +0 -99
- data/spec/spec_helper.rb +0 -51
- data/spec/stress/channel_close_stress_spec.rb +0 -64
- data/spec/stress/channel_open_stress_spec.rb +0 -84
- data/spec/stress/channel_open_stress_with_single_threaded_connection_spec.rb +0 -28
- data/spec/stress/concurrent_consumers_stress_spec.rb +0 -71
- data/spec/stress/concurrent_publishers_stress_spec.rb +0 -54
- data/spec/stress/connection_open_close_spec.rb +0 -52
- data/spec/stress/long_running_consumer_spec.rb +0 -84
- data/spec/tls/ca_certificate.pem +0 -29
- data/spec/tls/ca_key.pem +0 -52
- data/spec/tls/client_certificate.pem +0 -29
- data/spec/tls/client_key.pem +0 -51
- data/spec/tls/generate-server-cert.sh +0 -8
- data/spec/tls/server-openssl.cnf +0 -10
- data/spec/tls/server.csr +0 -16
- data/spec/tls/server_certificate.pem +0 -29
- data/spec/tls/server_key.pem +0 -51
- data/spec/unit/bunny_spec.rb +0 -15
- data/spec/unit/concurrent/atomic_fixnum_spec.rb +0 -35
- data/spec/unit/concurrent/condition_spec.rb +0 -82
- data/spec/unit/concurrent/linked_continuation_queue_spec.rb +0 -35
- data/spec/unit/concurrent/synchronized_sorted_set_spec.rb +0 -73
- data/spec/unit/exchange_recovery_spec.rb +0 -39
- data/spec/unit/version_delivery_tag_spec.rb +0 -28
data/lib/bunny/test_kit.rb
CHANGED
@@ -1,9 +1,23 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require "timeout"
|
4
|
+
|
2
5
|
module Bunny
|
3
6
|
# Unit, integration and stress testing toolkit
|
4
7
|
class TestKit
|
5
8
|
class << self
|
6
9
|
|
10
|
+
def poll_while(timeout = 60, &probe)
|
11
|
+
Timeout.timeout(timeout) {
|
12
|
+
sleep 0.1 while probe.call
|
13
|
+
}
|
14
|
+
end
|
15
|
+
def poll_until(timeout = 60, &probe)
|
16
|
+
Timeout.timeout(timeout) {
|
17
|
+
sleep 0.1 until probe.call
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
7
21
|
# @return [Integer] Random integer in the range of [a, b]
|
8
22
|
# @api private
|
9
23
|
def random_in_range(a, b)
|
data/lib/bunny/transport.rb
CHANGED
@@ -25,14 +25,41 @@ module Bunny
|
|
25
25
|
DEFAULT_READ_TIMEOUT = 30.0
|
26
26
|
DEFAULT_WRITE_TIMEOUT = 30.0
|
27
27
|
|
28
|
+
# mimics METHODS_MAP in ssl.rb but also lists TLS 1.3
|
29
|
+
# and string constants
|
30
|
+
TLS_VERSION_ALIASES = {
|
31
|
+
TLSv1: OpenSSL::SSL::TLS1_VERSION,
|
32
|
+
TLSv1_1: OpenSSL::SSL::TLS1_1_VERSION,
|
33
|
+
TLSv1_2: OpenSSL::SSL::TLS1_2_VERSION,
|
34
|
+
"1.0": OpenSSL::SSL::TLS1_VERSION,
|
35
|
+
"1.1": OpenSSL::SSL::TLS1_1_VERSION,
|
36
|
+
"1.2": OpenSSL::SSL::TLS1_2_VERSION,
|
37
|
+
OpenSSL::SSL::TLS1_VERSION => OpenSSL::SSL::TLS1_VERSION,
|
38
|
+
OpenSSL::SSL::TLS1_1_VERSION => OpenSSL::SSL::TLS1_1_VERSION,
|
39
|
+
OpenSSL::SSL::TLS1_2_VERSION => OpenSSL::SSL::TLS1_2_VERSION
|
40
|
+
}
|
41
|
+
|
42
|
+
# older OpenSSL versions won't support for TLS 1.3 and won't
|
43
|
+
# have this constant defined.
|
44
|
+
if defined?(OpenSSL::SSL::TLS1_3_VERSION)
|
45
|
+
TLS_VERSION_ALIASES["1.3"] = OpenSSL::SSL::TLS1_3_VERSION
|
46
|
+
TLS_VERSION_ALIASES[:TLSv1_3] = OpenSSL::SSL::TLS1_3_VERSION
|
47
|
+
TLS_VERSION_ALIASES[OpenSSL::SSL::TLS1_3_VERSION] = OpenSSL::SSL::TLS1_3_VERSION
|
48
|
+
end
|
49
|
+
|
50
|
+
TLS_VERSION_ALIASES.freeze
|
51
|
+
|
28
52
|
attr_reader :session, :host, :port, :socket, :connect_timeout, :read_timeout, :write_timeout, :disconnect_timeout
|
29
|
-
attr_reader :tls_context
|
53
|
+
attr_reader :tls_context, :verify_peer, :tls_ca_certificates, :tls_certificate_path, :tls_key_path
|
30
54
|
|
31
|
-
|
55
|
+
def read_timeout=(v)
|
56
|
+
@read_timeout = v
|
57
|
+
@read_timeout = nil if @read_timeout == 0
|
58
|
+
end
|
32
59
|
|
33
60
|
def initialize(session, host, port, opts)
|
34
61
|
@session = session
|
35
|
-
@
|
62
|
+
@session_error_handler = opts[:session_error_handler]
|
36
63
|
@host = host
|
37
64
|
@port = port
|
38
65
|
@opts = opts
|
@@ -54,6 +81,8 @@ module Bunny
|
|
54
81
|
|
55
82
|
@writes_mutex = @session.mutex_impl.new
|
56
83
|
|
84
|
+
@socket = nil
|
85
|
+
|
57
86
|
prepare_tls_context(opts) if @tls_enabled
|
58
87
|
end
|
59
88
|
|
@@ -77,10 +106,29 @@ module Bunny
|
|
77
106
|
|
78
107
|
|
79
108
|
def connect
|
80
|
-
if
|
81
|
-
|
82
|
-
|
83
|
-
|
109
|
+
if uses_tls?
|
110
|
+
begin
|
111
|
+
@socket.connect
|
112
|
+
rescue OpenSSL::SSL::SSLError => e
|
113
|
+
@logger.error { "TLS connection failed: #{e.message}" }
|
114
|
+
raise e
|
115
|
+
end
|
116
|
+
|
117
|
+
log_peer_certificate_info(Logger::DEBUG, @socket.peer_cert)
|
118
|
+
log_peer_certificate_chain_info(Logger::DEBUG, @socket.peer_cert_chain)
|
119
|
+
|
120
|
+
begin
|
121
|
+
@socket.post_connection_check(host) if @verify_peer
|
122
|
+
rescue OpenSSL::SSL::SSLError => e
|
123
|
+
@logger.error do
|
124
|
+
msg = "Peer verification of target server failed: #{e.message}. "
|
125
|
+
msg += "Target hostname: #{hostname}, see peer certificate chain details below."
|
126
|
+
msg
|
127
|
+
end
|
128
|
+
log_peer_certificate_info(Logger::ERROR, @socket.peer_cert)
|
129
|
+
log_peer_certificate_chain_info(Logger::ERROR, @socket.peer_cert_chain)
|
130
|
+
|
131
|
+
raise e
|
84
132
|
end
|
85
133
|
|
86
134
|
@status = :connected
|
@@ -122,7 +170,7 @@ module Bunny
|
|
122
170
|
if @session.automatically_recover?
|
123
171
|
@session.handle_network_failure(e)
|
124
172
|
else
|
125
|
-
@
|
173
|
+
@session_error_handler.raise(Bunny::NetworkFailure.new("detected a network failure: #{e.message}", e))
|
126
174
|
end
|
127
175
|
end
|
128
176
|
end
|
@@ -146,24 +194,25 @@ module Bunny
|
|
146
194
|
if @session.automatically_recover?
|
147
195
|
@session.handle_network_failure(e)
|
148
196
|
else
|
149
|
-
@
|
197
|
+
@session_error_handler.raise(Bunny::NetworkFailure.new("detected a network failure: #{e.message}", e))
|
150
198
|
end
|
151
199
|
end
|
152
200
|
end
|
153
201
|
end
|
154
202
|
|
155
203
|
# Writes data to the socket without timeout checks
|
156
|
-
def write_without_timeout(data)
|
204
|
+
def write_without_timeout(data, raise_exceptions = false)
|
157
205
|
begin
|
158
206
|
@writes_mutex.synchronize { @socket.write(data) }
|
159
207
|
@socket.flush
|
160
208
|
rescue SystemCallError, Bunny::ConnectionError, IOError => e
|
161
209
|
close
|
210
|
+
raise e if raise_exceptions
|
162
211
|
|
163
212
|
if @session.automatically_recover?
|
164
213
|
@session.handle_network_failure(e)
|
165
214
|
else
|
166
|
-
@
|
215
|
+
@session_error_handler.raise(Bunny::NetworkFailure.new("detected a network failure: #{e.message}", e))
|
167
216
|
end
|
168
217
|
end
|
169
218
|
end
|
@@ -220,7 +269,7 @@ module Bunny
|
|
220
269
|
if @session.automatically_recover?
|
221
270
|
raise
|
222
271
|
else
|
223
|
-
@
|
272
|
+
@session_error_handler.raise(Bunny::NetworkFailure.new("detected a network failure: #{e.message}", e))
|
224
273
|
end
|
225
274
|
end
|
226
275
|
end
|
@@ -298,17 +347,21 @@ module Bunny
|
|
298
347
|
protected
|
299
348
|
|
300
349
|
def tls_enabled?(opts)
|
301
|
-
return opts[:tls] unless opts[:tls].nil?
|
302
|
-
return opts[:ssl] unless opts[:ssl].nil?
|
350
|
+
return !!opts[:tls] unless opts[:tls].nil?
|
351
|
+
return !!opts[:ssl] unless opts[:ssl].nil?
|
303
352
|
(opts[:port] == AMQ::Protocol::TLS_PORT) || false
|
304
353
|
end
|
305
354
|
|
355
|
+
def tls_ca_certificates_paths_from(opts)
|
356
|
+
Array(opts[:cacertfile] || opts[:tls_ca_certificates] || opts[:ssl_ca_certificates])
|
357
|
+
end
|
358
|
+
|
306
359
|
def tls_certificate_path_from(opts)
|
307
|
-
opts[:tls_cert] || opts[:ssl_cert] || opts[:tls_cert_path] || opts[:ssl_cert_path] || opts[:tls_certificate_path] || opts[:ssl_certificate_path]
|
360
|
+
opts[:certfile] || opts[:tls_cert] || opts[:ssl_cert] || opts[:tls_cert_path] || opts[:ssl_cert_path] || opts[:tls_certificate_path] || opts[:ssl_certificate_path]
|
308
361
|
end
|
309
362
|
|
310
363
|
def tls_key_path_from(opts)
|
311
|
-
opts[:tls_key] || opts[:ssl_key] || opts[:tls_key_path] || opts[:ssl_key_path]
|
364
|
+
opts[:keyfile] || opts[:tls_key] || opts[:ssl_key] || opts[:tls_key_path] || opts[:ssl_key_path]
|
312
365
|
end
|
313
366
|
|
314
367
|
def tls_certificate_from(opts)
|
@@ -327,6 +380,29 @@ module Bunny
|
|
327
380
|
end
|
328
381
|
end
|
329
382
|
|
383
|
+
def peer_certificate_info(peer_cert, prefix = "Peer's leaf certificate")
|
384
|
+
exts = peer_cert.extensions.map { |x| x.value }
|
385
|
+
# Subject Alternative Names
|
386
|
+
sans = exts.select { |s| s =~ /^DNS/ }.map { |s| s.gsub(/^DNS:/, "") }
|
387
|
+
|
388
|
+
msg = "#{prefix} subject: #{peer_cert.subject}, "
|
389
|
+
msg += "subject alternative names: #{sans.join(', ')}, "
|
390
|
+
msg += "issuer: #{peer_cert.issuer}, "
|
391
|
+
msg += "not valid after: #{peer_cert.not_after}, "
|
392
|
+
msg += "X.509 usage extensions: #{exts.join(', ')}"
|
393
|
+
|
394
|
+
msg
|
395
|
+
end
|
396
|
+
|
397
|
+
def log_peer_certificate_info(severity, peer_cert, prefix = "Peer's leaf certificate")
|
398
|
+
@logger.add(severity) { peer_certificate_info(peer_cert, prefix) }
|
399
|
+
end
|
400
|
+
|
401
|
+
def log_peer_certificate_chain_info(severity, chain)
|
402
|
+
chain.each do |cert|
|
403
|
+
self.log_peer_certificate_info(severity, cert, "Peer's certificate chain entry")
|
404
|
+
end
|
405
|
+
end
|
330
406
|
|
331
407
|
def inline_client_certificate_from(opts)
|
332
408
|
opts[:tls_certificate] || opts[:ssl_cert_string] || opts[:tls_cert]
|
@@ -337,7 +413,7 @@ module Bunny
|
|
337
413
|
end
|
338
414
|
|
339
415
|
def prepare_tls_context(opts)
|
340
|
-
if (
|
416
|
+
if opts.values_at(:verify_ssl, :verify_peer, :verify).all?(&:nil?)
|
341
417
|
opts[:verify_peer] = true
|
342
418
|
end
|
343
419
|
|
@@ -349,12 +425,22 @@ module Bunny
|
|
349
425
|
@tls_key = tls_key_from(opts)
|
350
426
|
@tls_certificate_store = opts[:tls_certificate_store]
|
351
427
|
|
352
|
-
@
|
353
|
-
@verify_peer = (opts[:verify_ssl] || opts[:verify_peer])
|
428
|
+
@verify_peer = as_boolean(opts[:verify_ssl] || opts[:verify_peer] || opts[:verify])
|
354
429
|
|
355
430
|
@tls_context = initialize_tls_context(OpenSSL::SSL::SSLContext.new, opts)
|
356
431
|
end
|
357
432
|
|
433
|
+
def as_boolean(val)
|
434
|
+
case val
|
435
|
+
when true then true
|
436
|
+
when false then false
|
437
|
+
when "true" then true
|
438
|
+
when "false" then false
|
439
|
+
else
|
440
|
+
!!val
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
358
444
|
def wrap_in_tls_socket(socket)
|
359
445
|
raise ArgumentError, "cannot wrap nil into TLS socket, @tls_context is nil. This is a Bunny bug." unless socket
|
360
446
|
raise "cannot wrap a socket into TLS socket, @tls_context is nil. This is a Bunny bug." unless @tls_context
|
@@ -391,19 +477,22 @@ module Bunny
|
|
391
477
|
end
|
392
478
|
end
|
393
479
|
|
394
|
-
def initialize_tls_context(ctx, opts={})
|
480
|
+
def initialize_tls_context(ctx, opts = {})
|
395
481
|
ctx.cert = OpenSSL::X509::Certificate.new(@tls_certificate) if @tls_certificate
|
396
|
-
ctx.key = OpenSSL::PKey
|
482
|
+
ctx.key = OpenSSL::PKey.read(@tls_key) if @tls_key
|
397
483
|
ctx.cert_store = if @tls_certificate_store
|
398
484
|
@tls_certificate_store
|
399
485
|
else
|
486
|
+
# this ivar exists so that this value can be exposed in the API
|
487
|
+
@tls_ca_certificates = tls_ca_certificates_paths_from(opts)
|
400
488
|
initialize_tls_certificate_store(@tls_ca_certificates)
|
401
489
|
end
|
490
|
+
should_silence_warnings = opts.fetch(:tls_silence_warnings, false)
|
402
491
|
|
403
|
-
if !@tls_certificate
|
492
|
+
if !@tls_certificate && !should_silence_warnings
|
404
493
|
@logger.warn <<-MSG
|
405
|
-
Using TLS but no client certificate is provided
|
406
|
-
certificate, connection
|
494
|
+
Using TLS but no client certificate is provided. If RabbitMQ is configured to require & verify peer
|
495
|
+
certificate, connection will be rejected. Learn more at https://www.rabbitmq.com/ssl.html
|
407
496
|
MSG
|
408
497
|
end
|
409
498
|
if @tls_certificate && !@tls_key
|
@@ -415,45 +504,33 @@ certificate, connection upgrade will fail!
|
|
415
504
|
else
|
416
505
|
OpenSSL::SSL::VERIFY_NONE
|
417
506
|
end
|
507
|
+
@logger.debug { "Will use peer verification mode #{verify_mode}" }
|
418
508
|
ctx.verify_mode = verify_mode
|
419
509
|
|
420
|
-
if !@verify_peer
|
510
|
+
if !@verify_peer && !should_silence_warnings
|
421
511
|
@logger.warn <<-MSG
|
422
512
|
Using TLS but peer hostname verification is disabled. This is convenient for local development
|
423
|
-
but prone to man-in-the-middle attacks. Please set verify_peer: true in production
|
513
|
+
but prone to man-in-the-middle attacks. Please set verify_peer: true in production. Learn more at https://www.rabbitmq.com/ssl.html
|
424
514
|
MSG
|
425
515
|
end
|
426
516
|
|
427
|
-
ssl_version = opts[:tls_protocol] || opts[:ssl_version]
|
428
|
-
|
517
|
+
ssl_version = opts[:tls_protocol] || opts[:ssl_version] || :TLSv1_2
|
518
|
+
if ssl_version
|
519
|
+
v = tls_version_constant(ssl_version)
|
520
|
+
ctx.min_version = v
|
521
|
+
ctx.max_version = v
|
522
|
+
end
|
429
523
|
|
430
524
|
ctx
|
431
525
|
end
|
432
526
|
|
433
|
-
def default_tls_certificates
|
434
|
-
if defined?(JRUBY_VERSION)
|
435
|
-
# see https://github.com/jruby/jruby/issues/1055. MK.
|
436
|
-
[]
|
437
|
-
else
|
438
|
-
default_ca_file = ENV[OpenSSL::X509::DEFAULT_CERT_FILE_ENV] || OpenSSL::X509::DEFAULT_CERT_FILE
|
439
|
-
default_ca_path = ENV[OpenSSL::X509::DEFAULT_CERT_DIR_ENV] || OpenSSL::X509::DEFAULT_CERT_DIR
|
440
|
-
|
441
|
-
[
|
442
|
-
default_ca_file,
|
443
|
-
File.join(default_ca_path, 'ca-certificates.crt'), # Ubuntu/Debian
|
444
|
-
File.join(default_ca_path, 'ca-bundle.crt'), # Amazon Linux & Fedora/RHEL
|
445
|
-
File.join(default_ca_path, 'ca-bundle.pem') # OpenSUSE
|
446
|
-
].uniq
|
447
|
-
end
|
448
|
-
end
|
449
|
-
|
450
527
|
def initialize_tls_certificate_store(certs)
|
451
528
|
cert_files = []
|
452
529
|
cert_inlines = []
|
453
530
|
certs.each do |cert|
|
454
531
|
# if it starts with / or C:/ then it's a file path that may or may not
|
455
532
|
# exist (e.g. a default OpenSSL path). MK.
|
456
|
-
if File.readable?(cert) || cert =~
|
533
|
+
if File.readable?(cert) || cert =~ /\A([a-z]:?)?\//i
|
457
534
|
cert_files.push(cert)
|
458
535
|
else
|
459
536
|
cert_inlines.push(cert)
|
@@ -461,10 +538,8 @@ but prone to man-in-the-middle attacks. Please set verify_peer: true in producti
|
|
461
538
|
end
|
462
539
|
@logger.debug { "Using CA certificates at #{cert_files.join(', ')}" }
|
463
540
|
@logger.debug { "Using #{cert_inlines.count} inline CA certificates" }
|
464
|
-
if certs.empty?
|
465
|
-
@logger.error "No CA certificates found, add one with :tls_ca_certificates"
|
466
|
-
end
|
467
541
|
OpenSSL::X509::Store.new.tap do |store|
|
542
|
+
store.set_default_paths
|
468
543
|
cert_files.select { |path| File.readable?(path) }.
|
469
544
|
each { |path| store.add_file(path) }
|
470
545
|
cert_inlines.
|
@@ -472,6 +547,14 @@ but prone to man-in-the-middle attacks. Please set verify_peer: true in producti
|
|
472
547
|
end
|
473
548
|
end
|
474
549
|
|
550
|
+
|
551
|
+
def tls_version_constant(value)
|
552
|
+
# OpenSSL::SSL::TLS1_3_VERSION and similar constants
|
553
|
+
# are just integers, so use the value itself as fallback since
|
554
|
+
# there is no class to case switch on
|
555
|
+
TLS_VERSION_ALIASES[value] || value
|
556
|
+
end
|
557
|
+
|
475
558
|
def timeout_from(options)
|
476
559
|
options[:connect_timeout] || options[:connection_timeout] || options[:timeout] || DEFAULT_CONNECTION_TIMEOUT
|
477
560
|
end
|
data/lib/bunny/version.rb
CHANGED
data/lib/bunny.rb
CHANGED
@@ -53,17 +53,58 @@ module Bunny
|
|
53
53
|
# Instantiates a new connection. The actual network
|
54
54
|
# connection is started with {Bunny::Session#start}
|
55
55
|
#
|
56
|
+
# @param [String, Hash] connection_string_or_opts Connection string or a hash of connection options
|
57
|
+
# @param [Hash] optz Extra options not related to connection
|
58
|
+
#
|
59
|
+
# @option connection_string_or_opts [String] :host ("127.0.0.1") Hostname or IP address to connect to
|
60
|
+
# @option connection_string_or_opts [Array<String>] :hosts (["127.0.0.1"]) list of hostname or IP addresses to select hostname from when connecting
|
61
|
+
# @option connection_string_or_opts [Array<String>] :addresses (["127.0.0.1:5672"]) list of addresses to select hostname and port from when connecting
|
62
|
+
# @option connection_string_or_opts [Integer] :port (5672) Port RabbitMQ listens on
|
63
|
+
# @option connection_string_or_opts [String] :username ("guest") Username
|
64
|
+
# @option connection_string_or_opts [String] :password ("guest") Password
|
65
|
+
# @option connection_string_or_opts [String] :vhost ("/") Virtual host to use
|
66
|
+
# @option connection_string_or_opts [Integer, Symbol] :heartbeat (:server) Heartbeat timeout to offer to the server. :server means use the value suggested by RabbitMQ. 0 means heartbeats and socket read timeouts will be disabled (not recommended).
|
67
|
+
# @option connection_string_or_opts [Integer] :network_recovery_interval (4) Recovery interval periodic network recovery will use. This includes initial pause after network failure.
|
68
|
+
# @option connection_string_or_opts [Boolean] :tls (false) Should TLS/SSL be used?
|
69
|
+
# @option connection_string_or_opts [String] :tls_cert (nil) Path to client TLS/SSL certificate file (.pem)
|
70
|
+
# @option connection_string_or_opts [String] :tls_key (nil) Path to client TLS/SSL private key file (.pem)
|
71
|
+
# @option connection_string_or_opts [Array<String>] :tls_ca_certificates Array of paths to TLS/SSL CA files (.pem), by default detected from OpenSSL configuration
|
72
|
+
# @option connection_string_or_opts [String] :verify_peer (true) Whether TLS peer verification should be performed
|
73
|
+
# @option connection_string_or_opts [Symbol] :tls_protocol (negotiated) What TLS version should be used (:TLSv1, :TLSv1_1, or :TLSv1_2)
|
74
|
+
# @option connection_string_or_opts [Integer] :channel_max (2047) Maximum number of channels allowed on this connection, minus 1 to account for the special channel 0.
|
75
|
+
# @option connection_string_or_opts [Integer] :continuation_timeout (15000) Timeout for client operations that expect a response (e.g. {Bunny::Queue#get}), in milliseconds.
|
76
|
+
# @option connection_string_or_opts [Integer] :connection_timeout (30) Timeout in seconds for connecting to the server.
|
77
|
+
# @option connection_string_or_opts [Integer] :read_timeout (30) TCP socket read timeout in seconds. If heartbeats are disabled this will be ignored.
|
78
|
+
# @option connection_string_or_opts [Integer] :write_timeout (30) TCP socket write timeout in seconds.
|
79
|
+
# @option connection_string_or_opts [Proc] :hosts_shuffle_strategy a callable that reorders a list of host strings, defaults to Array#shuffle
|
80
|
+
# @option connection_string_or_opts [Proc] :recovery_completed a callable that will be called when a network recovery is performed
|
81
|
+
# @option connection_string_or_opts [Logger] :logger The logger. If missing, one is created using :log_file and :log_level.
|
82
|
+
# @option connection_string_or_opts [IO, String] :log_file The file or path to use when creating a logger. Defaults to STDOUT.
|
83
|
+
# @option connection_string_or_opts [IO, String] :logfile DEPRECATED: use :log_file instead. The file or path to use when creating a logger. Defaults to STDOUT.
|
84
|
+
# @option connection_string_or_opts [Integer] :log_level The log level to use when creating a logger. Defaults to LOGGER::WARN
|
85
|
+
# @option connection_string_or_opts [Boolean] :automatically_recover (true) Should automatically recover from network failures?
|
86
|
+
# @option connection_string_or_opts [Integer] :recovery_attempts (nil) Max number of recovery attempts, nil means forever
|
87
|
+
# @option connection_string_or_opts [Integer] :reset_recovery_attempts_after_reconnection (true) Should recovery attempt counter be reset after successful reconnection? When set to false, the attempt counter will last through the entire lifetime of the connection object.
|
88
|
+
# @option connection_string_or_opts [Proc] :recovery_attempt_started (nil) Will be called before every connection recovery attempt
|
89
|
+
# @option connection_string_or_opts [Proc] :recovery_completed (nil) Will be called after successful connection recovery
|
90
|
+
# @option connection_string_or_opts [Boolean] :recover_from_connection_close (true) Should this connection recover after receiving a server-sent connection.close (e.g. connection was force closed)?
|
91
|
+
# @option connection_string_or_opts [Object] :session_error_handler (Thread.current) Object which responds to #raise that will act as a session error handler. Defaults to Thread.current, which will raise asynchronous exceptions in the thread that created the session.
|
92
|
+
#
|
93
|
+
# @option optz [String] :auth_mechanism ("PLAIN") Authentication mechanism, PLAIN or EXTERNAL
|
94
|
+
# @option optz [String] :locale ("PLAIN") Locale RabbitMQ should use
|
95
|
+
# @option optz [String] :connection_name (nil) Client-provided connection name, if any. Note that the value returned does not uniquely identify a connection and cannot be used as a connection identifier in HTTP API requests.
|
96
|
+
#
|
56
97
|
# @return [Bunny::Session]
|
57
98
|
# @see Bunny::Session#start
|
58
99
|
# @see http://rubybunny.info/articles/getting_started.html
|
59
100
|
# @see http://rubybunny.info/articles/connecting.html
|
60
101
|
# @api public
|
61
|
-
def self.new(connection_string_or_opts = ENV['RABBITMQ_URL'],
|
62
|
-
if connection_string_or_opts.respond_to?(:keys) &&
|
63
|
-
|
102
|
+
def self.new(connection_string_or_opts = ENV['RABBITMQ_URL'], optz = {})
|
103
|
+
if connection_string_or_opts.respond_to?(:keys) && optz.empty?
|
104
|
+
optz = connection_string_or_opts
|
64
105
|
end
|
65
106
|
|
66
|
-
conn = Session.new(connection_string_or_opts,
|
107
|
+
conn = Session.new(connection_string_or_opts, optz)
|
67
108
|
@default_connection ||= conn
|
68
109
|
|
69
110
|
conn
|