bunny 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1fc5878c28d1164882b924bba6452f035780026c
4
- data.tar.gz: ba690c50d70f94994cc5ae29a5668a9d956cc89a
3
+ metadata.gz: 0836f4aa9086b7ac58dcfc0f2aa21e65580fca67
4
+ data.tar.gz: e15d6b9d8a1cb73e1bf686eb0fd2dd0c59741452
5
5
  SHA512:
6
- metadata.gz: 43a7f6f137bde88a7b7af3e5ec240ba1e8eafafd819eba044b634570fe15d2ba1f88dcb8c0119df493f5a681ca0e7a4e006809164bd1f20044a8654765015cad
7
- data.tar.gz: a784125f41292894f6003ab1f06b23dbec5077e66e916b027aafc89f169ba8b0f109a5dec2cb555f0effbdd5d124aa0d6b1bf923935087b3eb74eaeb6c293202
6
+ metadata.gz: f63f5f0e9646746806cb21a5a1dc57e11f85bb23f5655937dd30136054996dd518cb91c296262569b6b92be83c5a32b503c6b0ff88f8788a3481d4f1f722891c
7
+ data.tar.gz: 41d514a852463368e4c37a63bda65d8d98308d42fa62f4d4eb925e65554d8e552d29aa8e2b4c1d4386127a34c2f512ee9810a99aeea2793188b5189a586e71c4
@@ -1,3 +1,22 @@
1
+ ## Changes between Bunny 1.0.0 and 1.0.1
2
+
3
+ ### Default CA's Paths Are Disabled on JRuby
4
+
5
+ Bunny uses OpenSSL provided CA certificate paths. This
6
+ caused problems on some platforms on JRuby (see [jruby/jruby#155](https://github.com/jruby/jruby/issues/1055)).
7
+
8
+ To avoid these issues, Bunny no longer uses default CA certificate paths on JRuby
9
+ (there are no changes for other Rubies), so it's necessary to provide
10
+ CA certificate explicitly.
11
+
12
+ ### Fixes CPU Burn on JRuby
13
+
14
+ Bunny now uses slightly different ways of continuously reading from the socket
15
+ on CRuby and JRuby, to prevent abnormally high CPU usage on JRuby after a
16
+ certain period of time (the frequency of `EWOULDBLOCK` being raised spiked
17
+ sharply).
18
+
19
+
1
20
  ## Changes between Bunny 1.0.0.rc2 and 1.0.0.rc3
2
21
 
3
22
  ### [Authentication Failure Notification](http://www.rabbitmq.com/auth-notification.html) Support
@@ -8,7 +8,9 @@ require "amq/protocol/extensions"
8
8
 
9
9
  require "bunny/framing"
10
10
  require "bunny/exceptions"
11
+
11
12
  require "bunny/socket"
13
+
12
14
  require "bunny/timeout"
13
15
 
14
16
  begin
@@ -0,0 +1,83 @@
1
+ require "socket"
2
+
3
+ module Bunny
4
+ # TCP socket extension that uses TCP_NODELAY and supports reading
5
+ # fully.
6
+ #
7
+ # Heavily inspired by Dalli by Mike Perham.
8
+ # @private
9
+ class Socket < TCPSocket
10
+ attr_accessor :options
11
+
12
+ # IO::WaitReadable is 1.9+ only
13
+ READ_RETRY_EXCEPTION_CLASSES = [Errno::EAGAIN, Errno::EWOULDBLOCK]
14
+ READ_RETRY_EXCEPTION_CLASSES << IO::WaitReadable if IO.const_defined?(:WaitReadable)
15
+
16
+ def self.open(host, port, options = {})
17
+ Timeout.timeout(options[:socket_timeout], ClientTimeout) do
18
+ sock = new(host, port)
19
+ if Socket.constants.include?('TCP_NODELAY') || Socket.constants.include?(:TCP_NODELAY)
20
+ sock.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, true)
21
+ end
22
+ sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_KEEPALIVE, true) if options.fetch(:keepalive, true)
23
+ sock.options = {:host => host, :port => port}.merge(options)
24
+ sock
25
+ end
26
+ end
27
+
28
+ # Reads given number of bytes with an optional timeout
29
+ #
30
+ # @param [Integer] count How many bytes to read
31
+ # @param [Integer] timeout Timeout
32
+ #
33
+ # @return [String] Data read from the socket
34
+ # @api public
35
+ def read_fully(count, timeout = nil)
36
+ return nil if @__bunny_socket_eof_flag__
37
+
38
+ value = ''
39
+ begin
40
+ loop do
41
+ value << read_nonblock(count - value.bytesize)
42
+ break if value.bytesize >= count
43
+ end
44
+ rescue EOFError
45
+ # @eof will break Rubinius' TCPSocket implementation. MK.
46
+ @__bunny_socket_eof_flag__ = true
47
+ rescue *READ_RETRY_EXCEPTION_CLASSES
48
+ if IO.select([self], nil, nil, timeout)
49
+ retry
50
+ else
51
+ raise Timeout::Error, "IO timeout when reading #{count} bytes"
52
+ end
53
+ end
54
+ value
55
+ end # read_fully
56
+
57
+ # Writes provided data using IO#write_nonblock, taking care of handling
58
+ # of exceptions it raises when writing would fail (e.g. due to socket buffer
59
+ # being full).
60
+ #
61
+ # IMPORTANT: this method will mutate (slice) the argument. Pass in duplicates
62
+ # if this is not appropriate in your case.
63
+ #
64
+ # @param [String] data Data to write
65
+ #
66
+ # @api public
67
+ def write_nonblock_fully(data)
68
+ return nil if @__bunny_socket_eof_flag__
69
+
70
+ begin
71
+ while !data.empty?
72
+ written = self.write_nonblock(data)
73
+ data.slice!(0, written)
74
+ end
75
+ rescue Errno::EWOULDBLOCK, Errno::EAGAIN
76
+ IO.select([], [self])
77
+ retry
78
+ end
79
+
80
+ data.bytesize
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,57 @@
1
+ require "socket"
2
+
3
+ module Bunny
4
+ begin
5
+ require "openssl"
6
+
7
+ # TLS-enabled TCP socket that implements convenience
8
+ # methods found in Bunny::Socket.
9
+ class SSLSocket < OpenSSL::SSL::SSLSocket
10
+
11
+ # IO::WaitReadable is 1.9+ only
12
+ READ_RETRY_EXCEPTION_CLASSES = [Errno::EAGAIN, Errno::EWOULDBLOCK]
13
+ READ_RETRY_EXCEPTION_CLASSES << IO::WaitReadable if IO.const_defined?(:WaitReadable)
14
+
15
+
16
+ # Reads given number of bytes with an optional timeout
17
+ #
18
+ # @param [Integer] count How many bytes to read
19
+ # @param [Integer] timeout Timeout
20
+ #
21
+ # @return [String] Data read from the socket
22
+ # @api public
23
+ def read_fully(count, timeout = nil)
24
+ return nil if @__bunny_socket_eof_flag__
25
+
26
+ value = ''
27
+ begin
28
+ loop do
29
+ value << read_nonblock(count - value.bytesize)
30
+ break if value.bytesize >= count
31
+ end
32
+ rescue EOFError => e
33
+ @__bunny_socket_eof_flag__ = true
34
+ rescue OpenSSL::SSL::SSLError => e
35
+ if e.message == "read would block"
36
+ if IO.select([self], nil, nil, timeout)
37
+ retry
38
+ else
39
+ raise Timeout::Error, "IO timeout when reading #{count} bytes"
40
+ end
41
+ else
42
+ raise e
43
+ end
44
+ rescue *READ_RETRY_EXCEPTION_CLASSES => e
45
+ if IO.select([self], nil, nil, timeout)
46
+ retry
47
+ else
48
+ raise Timeout::Error, "IO timeout when reading #{count} bytes"
49
+ end
50
+ end
51
+ value
52
+ end
53
+ end
54
+ rescue LoadError => le
55
+ puts "Could not load OpenSSL"
56
+ end
57
+ end
@@ -0,0 +1,40 @@
1
+ require "bunny/cruby/socket"
2
+
3
+ module Bunny
4
+ module JRuby
5
+ # TCP socket extension that uses Socket#readpartial to avoid excessive CPU
6
+ # burn after some time. See issue #165.
7
+ # @private
8
+ class Socket < Bunny::Socket
9
+
10
+ # Reads given number of bytes with an optional timeout
11
+ #
12
+ # @param [Integer] count How many bytes to read
13
+ # @param [Integer] timeout Timeout
14
+ #
15
+ # @return [String] Data read from the socket
16
+ # @api public
17
+ def read_fully(count, timeout = nil)
18
+ return nil if @__bunny_socket_eof_flag__
19
+
20
+ value = ''
21
+ begin
22
+ loop do
23
+ value << readpartial(count - value.bytesize)
24
+ break if value.bytesize >= count
25
+ end
26
+ rescue EOFError
27
+ # @eof will break Rubinius' TCPSocket implementation. MK.
28
+ @__bunny_socket_eof_flag__ = true
29
+ rescue *READ_RETRY_EXCEPTION_CLASSES
30
+ if IO.select([self], nil, nil, timeout)
31
+ retry
32
+ else
33
+ raise Timeout::Error, "IO timeout when reading #{count} bytes"
34
+ end
35
+ end
36
+ value
37
+ end # read_fully
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,53 @@
1
+ module Bunny
2
+ module JRuby
3
+ begin
4
+ require "bunny/cruby/ssl_socket"
5
+ require "openssl"
6
+
7
+ # TLS-enabled TCP socket that implements convenience
8
+ # methods found in Bunny::Socket.
9
+ class SSLSocket < Bunny::SSLSocket
10
+
11
+ # Reads given number of bytes with an optional timeout
12
+ #
13
+ # @param [Integer] count How many bytes to read
14
+ # @param [Integer] timeout Timeout
15
+ #
16
+ # @return [String] Data read from the socket
17
+ # @api public
18
+ def read_fully(count, timeout = nil)
19
+ return nil if @__bunny_socket_eof_flag__
20
+
21
+ value = ''
22
+ begin
23
+ loop do
24
+ value << read_nonblock(count - value.bytesize)
25
+ break if value.bytesize >= count
26
+ end
27
+ rescue EOFError => e
28
+ @__bunny_socket_eof_flag__ = true
29
+ rescue OpenSSL::SSL::SSLError => e
30
+ if e.message == "read would block"
31
+ if IO.select([self], nil, nil, timeout)
32
+ retry
33
+ else
34
+ raise Timeout::Error, "IO timeout when reading #{count} bytes"
35
+ end
36
+ else
37
+ raise e
38
+ end
39
+ rescue *READ_RETRY_EXCEPTION_CLASSES => e
40
+ if IO.select([self], nil, nil, timeout)
41
+ retry
42
+ else
43
+ raise Timeout::Error, "IO timeout when reading #{count} bytes"
44
+ end
45
+ end
46
+ value
47
+ end
48
+ end
49
+ rescue LoadError => le
50
+ puts "Could not load OpenSSL"
51
+ end
52
+ end
53
+ end
@@ -1,83 +1,14 @@
1
- require "socket"
1
+ # See #165. MK.
2
+ if defined?(JRUBY_VERSION)
3
+ require "bunny/jruby/socket"
2
4
 
3
- module Bunny
4
- # TCP socket extension that uses TCP_NODELAY and supports reading
5
- # fully.
6
- #
7
- # Heavily inspired by Dalli by Mike Perham.
8
- # @private
9
- class Socket < TCPSocket
10
- attr_accessor :options
11
-
12
- # IO::WaitReadable is 1.9+ only
13
- READ_RETRY_EXCEPTION_CLASSES = [Errno::EAGAIN, Errno::EWOULDBLOCK]
14
- READ_RETRY_EXCEPTION_CLASSES << IO::WaitReadable if IO.const_defined?(:WaitReadable)
15
-
16
- def self.open(host, port, options = {})
17
- Timeout.timeout(options[:socket_timeout], ClientTimeout) do
18
- sock = new(host, port)
19
- if Socket.constants.include?('TCP_NODELAY') || Socket.constants.include?(:TCP_NODELAY)
20
- sock.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, true)
21
- end
22
- sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_KEEPALIVE, true) if options.fetch(:keepalive, true)
23
- sock.options = {:host => host, :port => port}.merge(options)
24
- sock
25
- end
26
- end
27
-
28
- # Reads given number of bytes with an optional timeout
29
- #
30
- # @param [Integer] count How many bytes to read
31
- # @param [Integer] timeout Timeout
32
- #
33
- # @return [String] Data read from the socket
34
- # @api public
35
- def read_fully(count, timeout = nil)
36
- return nil if @__bunny_socket_eof_flag__
37
-
38
- value = ''
39
- begin
40
- loop do
41
- value << read_nonblock(count - value.bytesize)
42
- break if value.bytesize >= count
43
- end
44
- rescue EOFError
45
- # @eof will break Rubinius' TCPSocket implementation. MK.
46
- @__bunny_socket_eof_flag__ = true
47
- rescue *READ_RETRY_EXCEPTION_CLASSES
48
- if IO.select([self], nil, nil, timeout)
49
- retry
50
- else
51
- raise Timeout::Error, "IO timeout when reading #{count} bytes"
52
- end
53
- end
54
- value
55
- end # read_fully
56
-
57
- # Writes provided data using IO#write_nonblock, taking care of handling
58
- # of exceptions it raises when writing would fail (e.g. due to socket buffer
59
- # being full).
60
- #
61
- # IMPORTANT: this method will mutate (slice) the argument. Pass in duplicates
62
- # if this is not appropriate in your case.
63
- #
64
- # @param [String] data Data to write
65
- #
66
- # @api public
67
- def write_nonblock_fully(data)
68
- return nil if @__bunny_socket_eof_flag__
69
-
70
- begin
71
- while !data.empty?
72
- written = self.write_nonblock(data)
73
- data.slice!(0, written)
74
- end
75
- rescue Errno::EWOULDBLOCK, Errno::EAGAIN
76
- IO.select([], [self])
77
- retry
78
- end
5
+ module Bunny
6
+ SocketImpl = Socket #JRuby::Socket
7
+ end
8
+ else
9
+ require "bunny/cruby/socket"
79
10
 
80
- data.bytesize
81
- end
11
+ module Bunny
12
+ SocketImpl = Socket
82
13
  end
83
14
  end
@@ -1,57 +1,14 @@
1
- require "socket"
1
+ # See #165. MK.
2
+ if defined?(JRUBY_VERSION)
3
+ require "bunny/jruby/ssl_socket"
2
4
 
3
- module Bunny
4
- begin
5
- require "openssl"
6
-
7
- # TLS-enabled TCP socket that implements convenience
8
- # methods found in Bunny::Socket.
9
- class SSLSocket < OpenSSL::SSL::SSLSocket
10
-
11
- # IO::WaitReadable is 1.9+ only
12
- READ_RETRY_EXCEPTION_CLASSES = [Errno::EAGAIN, Errno::EWOULDBLOCK]
13
- READ_RETRY_EXCEPTION_CLASSES << IO::WaitReadable if IO.const_defined?(:WaitReadable)
14
-
15
-
16
- # Reads given number of bytes with an optional timeout
17
- #
18
- # @param [Integer] count How many bytes to read
19
- # @param [Integer] timeout Timeout
20
- #
21
- # @return [String] Data read from the socket
22
- # @api public
23
- def read_fully(count, timeout = nil)
24
- return nil if @__bunny_socket_eof_flag__
5
+ module Bunny
6
+ SSLSocketImpl = JRuby::SSLSocket
7
+ end
8
+ else
9
+ require "bunny/cruby/ssl_socket"
25
10
 
26
- value = ''
27
- begin
28
- loop do
29
- value << read_nonblock(count - value.bytesize)
30
- break if value.bytesize >= count
31
- end
32
- rescue EOFError => e
33
- @__bunny_socket_eof_flag__ = true
34
- rescue OpenSSL::SSL::SSLError => e
35
- if e.message == "read would block"
36
- if IO.select([self], nil, nil, timeout)
37
- retry
38
- else
39
- raise Timeout::Error, "IO timeout when reading #{count} bytes"
40
- end
41
- else
42
- raise e
43
- end
44
- rescue *READ_RETRY_EXCEPTION_CLASSES => e
45
- if IO.select([self], nil, nil, timeout)
46
- retry
47
- else
48
- raise Timeout::Error, "IO timeout when reading #{count} bytes"
49
- end
50
- end
51
- value
52
- end
53
- end
54
- rescue LoadError => le
55
- puts "Could not load OpenSSL"
11
+ module Bunny
12
+ SSLSocketImpl = SSLSocket
56
13
  end
57
14
  end
@@ -219,7 +219,7 @@ module Bunny
219
219
 
220
220
  def self.reacheable?(host, port, timeout)
221
221
  begin
222
- s = Bunny::Socket.open(host, port,
222
+ s = Bunny::SocketImpl.open(host, port,
223
223
  :socket_timeout => timeout)
224
224
 
225
225
  true
@@ -237,7 +237,7 @@ module Bunny
237
237
  def initialize_socket
238
238
  begin
239
239
  @socket = Bunny::Timeout.timeout(@connect_timeout, ClientTimeout) do
240
- Bunny::Socket.open(@host, @port,
240
+ Bunny::SocketImpl.open(@host, @port,
241
241
  :keepalive => @opts[:keepalive],
242
242
  :socket_timeout => @connect_timeout)
243
243
  end
@@ -309,14 +309,7 @@ module Bunny
309
309
  @tls_key = tls_key_from(opts)
310
310
  @tls_certificate_store = opts[:tls_certificate_store]
311
311
 
312
- default_ca_file = ENV[OpenSSL::X509::DEFAULT_CERT_FILE_ENV] || OpenSSL::X509::DEFAULT_CERT_FILE
313
- default_ca_path = ENV[OpenSSL::X509::DEFAULT_CERT_DIR_ENV] || OpenSSL::X509::DEFAULT_CERT_DIR
314
- @tls_ca_certificates = opts.fetch(:tls_ca_certificates, [
315
- default_ca_file,
316
- File.join(default_ca_path, 'ca-certificates.crt'), # Ubuntu/Debian
317
- File.join(default_ca_path, 'ca-bundle.crt'), # Amazon Linux & Fedora/RHEL
318
- File.join(default_ca_path, 'ca-bundle.pem') # OpenSUSE
319
- ])
312
+ @tls_ca_certificates = opts.fetch(:tls_ca_certificates, default_tls_certificates)
320
313
  @verify_peer = opts[:verify_ssl] || opts[:verify_peer]
321
314
 
322
315
  @tls_context = initialize_tls_context(OpenSSL::SSL::SSLContext.new)
@@ -326,7 +319,7 @@ module Bunny
326
319
  raise ArgumentError, "cannot wrap nil into TLS socket, @tls_context is nil. This is a Bunny bug." unless socket
327
320
  raise "cannot wrap a socket into TLS socket, @tls_context is nil. This is a Bunny bug." unless @tls_context
328
321
 
329
- s = Bunny::SSLSocket.new(socket, @tls_context)
322
+ s = Bunny::SSLSocketImpl.new(socket, @tls_context)
330
323
  s.sync_close = true
331
324
  s
332
325
  end
@@ -380,12 +373,30 @@ module Bunny
380
373
  ctx
381
374
  end
382
375
 
376
+ def default_tls_certificates
377
+ if defined?(JRUBY_VERSION)
378
+ # see https://github.com/jruby/jruby/issues/1055. MK.
379
+ []
380
+ else
381
+ default_ca_file = ENV[OpenSSL::X509::DEFAULT_CERT_FILE_ENV] || OpenSSL::X509::DEFAULT_CERT_FILE
382
+ default_ca_path = ENV[OpenSSL::X509::DEFAULT_CERT_DIR_ENV] || OpenSSL::X509::DEFAULT_CERT_DIR
383
+
384
+ [
385
+ default_ca_file,
386
+ File.join(default_ca_path, 'ca-certificates.crt'), # Ubuntu/Debian
387
+ File.join(default_ca_path, 'ca-bundle.crt'), # Amazon Linux & Fedora/RHEL
388
+ File.join(default_ca_path, 'ca-bundle.pem') # OpenSUSE
389
+ ].uniq
390
+ end
391
+ end
392
+
383
393
  def initialize_tls_certificate_store(certs)
384
394
  certs = certs.select { |path| File.readable? path }
385
395
  @logger.debug "Using CA certificates at #{certs.join(', ')}"
386
396
  if certs.empty?
387
397
  @logger.error "No CA certificates found, add one with :tls_ca_certificates"
388
398
  end
399
+ puts certs.inspect
389
400
  OpenSSL::X509::Store.new.tap do |store|
390
401
  certs.each { |path| store.add_file(path) }
391
402
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Bunny
4
4
  # @return [String] Version of the library
5
- VERSION = "1.0.0"
5
+ VERSION = "1.0.1"
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bunny
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Duncan
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2013-10-29 00:00:00.000000000 Z
15
+ date: 2013-11-06 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: amq-protocol
@@ -110,11 +110,15 @@ files:
110
110
  - lib/bunny/consumer.rb
111
111
  - lib/bunny/consumer_tag_generator.rb
112
112
  - lib/bunny/consumer_work_pool.rb
113
+ - lib/bunny/cruby/socket.rb
114
+ - lib/bunny/cruby/ssl_socket.rb
113
115
  - lib/bunny/delivery_info.rb
114
116
  - lib/bunny/exceptions.rb
115
117
  - lib/bunny/exchange.rb
116
118
  - lib/bunny/framing.rb
117
119
  - lib/bunny/heartbeat_sender.rb
120
+ - lib/bunny/jruby/socket.rb
121
+ - lib/bunny/jruby/ssl_socket.rb
118
122
  - lib/bunny/message_properties.rb
119
123
  - lib/bunny/queue.rb
120
124
  - lib/bunny/reader_loop.rb