bunny 2.7.4 → 2.22.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|