stomp 1.2.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.rdoc +9 -0
- data/examples/logexamp_ssl.rb +66 -0
- data/examples/slogger.rb +17 -1
- data/examples/ssl_uc1.rb +19 -0
- data/examples/ssl_uc1_ciphers.rb +30 -0
- data/examples/ssl_uc2.rb +30 -0
- data/examples/ssl_uc2_ciphers.rb +38 -0
- data/examples/ssl_uc3.rb +29 -0
- data/examples/ssl_uc3_ciphers.rb +37 -0
- data/examples/ssl_uc4.rb +29 -0
- data/examples/ssl_uc4_ciphers.rb +38 -0
- data/examples/ssl_ucx_default_ciphers.rb +25 -0
- data/lib/stomp/client.rb +2 -7
- data/lib/stomp/connection.rb +157 -87
- data/lib/stomp/constants.rb +3 -0
- data/lib/stomp/errors.rb +30 -0
- data/lib/stomp/message.rb +1 -1
- data/lib/stomp/sslparams.rb +50 -0
- data/lib/stomp/version.rb +1 -1
- data/lib/stomp.rb +2 -1
- data/stomp.gemspec +20 -7
- data/test/test_connection.rb +7 -0
- data/test/test_connection1p.rb +8 -0
- data/test/test_helper.rb +15 -0
- data/test/test_ssl.rb +51 -0
- metadata +67 -33
data/lib/stomp/connection.rb
CHANGED
@@ -21,7 +21,7 @@ module Stomp
|
|
21
21
|
def self.default_port(ssl)
|
22
22
|
ssl ? 61612 : 61613
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
# A new Connection object accepts the following parameters:
|
26
26
|
#
|
27
27
|
# login (String, default : '')
|
@@ -87,23 +87,24 @@ module Stomp
|
|
87
87
|
@parse_timeout = 5 # To override, use hashed parameters
|
88
88
|
@connect_timeout = 0 # To override, use hashed parameters
|
89
89
|
@logger = nil # To override, use hashed parameters
|
90
|
+
warn "login looks like a URL, do you have the correct parameters?" if @login =~ /:\/\//
|
90
91
|
end
|
91
|
-
|
92
|
+
|
92
93
|
# Use Mutexes: only one lock per each thread
|
93
94
|
# Revert to original implementation attempt
|
94
95
|
@transmit_semaphore = Mutex.new
|
95
96
|
@read_semaphore = Mutex.new
|
96
97
|
@socket_semaphore = Mutex.new
|
97
|
-
|
98
|
+
|
98
99
|
@subscriptions = {}
|
99
100
|
@failure = nil
|
100
101
|
@connection_attempts = 0
|
101
|
-
|
102
|
+
|
102
103
|
socket
|
103
104
|
end
|
104
|
-
|
105
|
+
|
105
106
|
def hashed_initialize(params)
|
106
|
-
|
107
|
+
|
107
108
|
@parameters = refine_params(params)
|
108
109
|
@reliable = @parameters[:reliable]
|
109
110
|
@reconnect_delay = @parameters[:initial_reconnect_delay]
|
@@ -113,11 +114,8 @@ module Stomp
|
|
113
114
|
@logger = @parameters[:logger]
|
114
115
|
#sets the first host to connect
|
115
116
|
change_host
|
116
|
-
if @logger && @logger.respond_to?(:on_connecting)
|
117
|
-
@logger.on_connecting(log_params)
|
118
|
-
end
|
119
117
|
end
|
120
|
-
|
118
|
+
|
121
119
|
# Syntactic sugar for 'Connection.new' See 'initialize' for usage.
|
122
120
|
def Connection.open(login = '', passcode = '', host = 'localhost', port = 61613, reliable = false, reconnect_delay = 5, connect_headers = {})
|
123
121
|
Connection.new(login, passcode, host, port, reliable, reconnect_delay, connect_headers)
|
@@ -127,33 +125,33 @@ module Stomp
|
|
127
125
|
@socket_semaphore.synchronize do
|
128
126
|
used_socket = @socket
|
129
127
|
used_socket = nil if closed?
|
130
|
-
|
128
|
+
|
131
129
|
while used_socket.nil? || !@failure.nil?
|
132
130
|
@failure = nil
|
133
131
|
begin
|
134
132
|
used_socket = open_socket
|
135
133
|
# Open complete
|
136
|
-
|
134
|
+
|
137
135
|
connect(used_socket)
|
138
136
|
if @logger && @logger.respond_to?(:on_connected)
|
139
|
-
@logger.on_connected(log_params)
|
137
|
+
@logger.on_connected(log_params)
|
140
138
|
end
|
141
139
|
@connection_attempts = 0
|
142
140
|
rescue
|
143
141
|
@failure = $!
|
144
142
|
used_socket = nil
|
145
143
|
raise unless @reliable
|
146
|
-
if @logger && @logger.respond_to?(:on_connectfail)
|
147
|
-
@logger.on_connectfail(log_params)
|
144
|
+
if @logger && @logger.respond_to?(:on_connectfail)
|
145
|
+
@logger.on_connectfail(log_params)
|
148
146
|
else
|
149
147
|
$stderr.print "connect to #{@host} failed: #{$!} will retry(##{@connection_attempts}) in #{@reconnect_delay}\n"
|
150
148
|
end
|
151
149
|
raise Stomp::Error::MaxReconnectAttempts if max_reconnect_attempts?
|
152
150
|
|
153
151
|
sleep(@reconnect_delay)
|
154
|
-
|
152
|
+
|
155
153
|
@connection_attempts += 1
|
156
|
-
|
154
|
+
|
157
155
|
if @parameters
|
158
156
|
change_host
|
159
157
|
increase_reconnect_delay
|
@@ -163,10 +161,10 @@ module Stomp
|
|
163
161
|
@socket = used_socket
|
164
162
|
end
|
165
163
|
end
|
166
|
-
|
164
|
+
|
167
165
|
def refine_params(params)
|
168
166
|
params = params.uncamelize_and_symbolize_keys
|
169
|
-
|
167
|
+
|
170
168
|
default_params = {
|
171
169
|
:connect_headers => {},
|
172
170
|
:reliable => true,
|
@@ -182,35 +180,35 @@ module Stomp
|
|
182
180
|
# Parse Timeout
|
183
181
|
:parse_timeout => 5
|
184
182
|
}
|
185
|
-
|
183
|
+
|
186
184
|
default_params.merge(params)
|
187
|
-
|
185
|
+
|
188
186
|
end
|
189
|
-
|
187
|
+
|
190
188
|
def change_host
|
191
189
|
@parameters[:hosts] = @parameters[:hosts].sort_by { rand } if @parameters[:randomize]
|
192
|
-
|
190
|
+
|
193
191
|
# Set first as master and send it to the end of array
|
194
192
|
current_host = @parameters[:hosts].shift
|
195
193
|
@parameters[:hosts] << current_host
|
196
|
-
|
194
|
+
|
197
195
|
@ssl = current_host[:ssl]
|
198
196
|
@host = current_host[:host]
|
199
197
|
@port = current_host[:port] || Connection::default_port(@ssl)
|
200
198
|
@login = current_host[:login] || ""
|
201
199
|
@passcode = current_host[:passcode] || ""
|
202
|
-
|
200
|
+
|
203
201
|
end
|
204
|
-
|
202
|
+
|
205
203
|
def max_reconnect_attempts?
|
206
204
|
!(@parameters.nil? || @parameters[:max_reconnect_attempts].nil?) && @parameters[:max_reconnect_attempts] != 0 && @connection_attempts >= @parameters[:max_reconnect_attempts]
|
207
205
|
end
|
208
|
-
|
206
|
+
|
209
207
|
def increase_reconnect_delay
|
210
208
|
|
211
|
-
@reconnect_delay *= @parameters[:back_off_multiplier] if @parameters[:use_exponential_back_off]
|
209
|
+
@reconnect_delay *= @parameters[:back_off_multiplier] if @parameters[:use_exponential_back_off]
|
212
210
|
@reconnect_delay = @parameters[:max_reconnect_delay] if @reconnect_delay > @parameters[:max_reconnect_delay]
|
213
|
-
|
211
|
+
|
214
212
|
@reconnect_delay
|
215
213
|
end
|
216
214
|
|
@@ -289,7 +287,7 @@ module Stomp
|
|
289
287
|
headers[:id] = subId if headers[:id].nil?
|
290
288
|
end
|
291
289
|
_headerCheck(headers)
|
292
|
-
if @logger && @logger.respond_to?(:on_subscribe)
|
290
|
+
if @logger && @logger.respond_to?(:on_subscribe)
|
293
291
|
@logger.on_subscribe(log_params, headers)
|
294
292
|
end
|
295
293
|
|
@@ -328,21 +326,16 @@ module Stomp
|
|
328
326
|
headers = headers.symbolize_keys
|
329
327
|
headers[:destination] = destination
|
330
328
|
_headerCheck(headers)
|
331
|
-
if @logger && @logger.respond_to?(:on_publish)
|
329
|
+
if @logger && @logger.respond_to?(:on_publish)
|
332
330
|
@logger.on_publish(log_params, message, headers)
|
333
331
|
end
|
334
332
|
transmit(Stomp::CMD_SEND, headers, message)
|
335
333
|
end
|
336
|
-
|
334
|
+
|
337
335
|
def obj_send(*args)
|
338
336
|
__send__(*args)
|
339
337
|
end
|
340
|
-
|
341
|
-
def send(*args)
|
342
|
-
warn("This method is deprecated and will be removed on the next release. Use 'publish' instead")
|
343
|
-
publish(*args)
|
344
|
-
end
|
345
|
-
|
338
|
+
|
346
339
|
# Send a message back to the source or to the dead letter queue
|
347
340
|
#
|
348
341
|
# Accepts a dead letter queue option ( :dead_letter_queue => "/queue/DLQ" )
|
@@ -353,19 +346,19 @@ module Stomp
|
|
353
346
|
options = { :dead_letter_queue => "/queue/DLQ", :max_redeliveries => 6 }.merge options
|
354
347
|
# Lets make sure all keys are symbols
|
355
348
|
message.headers = message.headers.symbolize_keys
|
356
|
-
|
349
|
+
|
357
350
|
retry_count = message.headers[:retry_count].to_i || 0
|
358
351
|
message.headers[:retry_count] = retry_count + 1
|
359
352
|
transaction_id = "transaction-#{message.headers[:'message-id']}-#{retry_count}"
|
360
353
|
message_id = message.headers.delete(:'message-id')
|
361
|
-
|
354
|
+
|
362
355
|
begin
|
363
356
|
self.begin transaction_id
|
364
|
-
|
357
|
+
|
365
358
|
if client_ack?(message) || options[:force_client_ack]
|
366
359
|
self.ack(message_id, :transaction => transaction_id)
|
367
360
|
end
|
368
|
-
|
361
|
+
|
369
362
|
if retry_count <= options[:max_redeliveries]
|
370
363
|
self.publish(message.headers[:destination], message.body, message.headers.merge(:transaction => transaction_id))
|
371
364
|
else
|
@@ -378,7 +371,7 @@ module Stomp
|
|
378
371
|
raise exception
|
379
372
|
end
|
380
373
|
end
|
381
|
-
|
374
|
+
|
382
375
|
def client_ack?(message)
|
383
376
|
headers = @subscriptions[message.headers[:destination]]
|
384
377
|
!headers.nil? && headers[:ack] == "client"
|
@@ -445,7 +438,7 @@ module Stomp
|
|
445
438
|
super_result = __old_receive
|
446
439
|
end
|
447
440
|
#
|
448
|
-
if @logger && @logger.respond_to?(:on_receive)
|
441
|
+
if @logger && @logger.respond_to?(:on_receive)
|
449
442
|
@logger.on_receive(log_params, super_result)
|
450
443
|
end
|
451
444
|
return super_result
|
@@ -481,7 +474,7 @@ module Stomp
|
|
481
474
|
b[6] = (b[6] & 0x0F) | 0x40
|
482
475
|
b[8] = (b[8] & 0xbf) | 0x80
|
483
476
|
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
484
|
-
rs = sprintf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x",
|
477
|
+
rs = sprintf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x",
|
485
478
|
b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15])
|
486
479
|
rs
|
487
480
|
end
|
@@ -490,31 +483,17 @@ module Stomp
|
|
490
483
|
|
491
484
|
def _receive( read_socket )
|
492
485
|
@read_semaphore.synchronize do
|
493
|
-
|
494
|
-
|
495
|
-
# heartbeat.
|
496
|
-
begin
|
497
|
-
last_char = read_socket.getc
|
498
|
-
return nil if last_char.nil?
|
499
|
-
if @protocol >= Stomp::SPL_11
|
500
|
-
plc = parse_char(last_char)
|
501
|
-
if plc == "\n" # Server Heartbeat
|
502
|
-
@lr = Time.now.to_f if @hbr
|
503
|
-
end
|
504
|
-
end
|
505
|
-
end until parse_char(last_char) != "\n"
|
506
|
-
read_socket.ungetc(last_char)
|
507
|
-
|
486
|
+
line = read_socket.gets
|
487
|
+
return nil if line.nil?
|
508
488
|
# If the reading hangs for more than X seconds, abort the parsing process.
|
509
489
|
# X defaults to 5. Override allowed in connection hash parameters.
|
510
490
|
Timeout::timeout(@parse_timeout, Stomp::Error::PacketParsingTimeout) do
|
511
491
|
# Reads the beginning of the message until it runs into a empty line
|
512
492
|
message_header = ''
|
513
|
-
line = ''
|
514
493
|
begin
|
515
|
-
message_header
|
494
|
+
message_header += line
|
516
495
|
line = read_socket.gets
|
517
|
-
|
496
|
+
raise Stomp::Error::StompServerError if line.nil?
|
518
497
|
end until line =~ /^\s?\n$/
|
519
498
|
|
520
499
|
# Checks if it includes content_length header
|
@@ -528,13 +507,34 @@ module Stomp
|
|
528
507
|
raise Stomp::Error::InvalidMessageLength unless parse_char(read_socket.getc) == "\0"
|
529
508
|
# Else reads, the rest of the message until the first \0
|
530
509
|
else
|
531
|
-
message_body
|
510
|
+
message_body += char while (char = parse_char(read_socket.getc)) != "\0"
|
532
511
|
end
|
533
512
|
|
513
|
+
# If the buffer isn't empty, reads trailing new lines.
|
514
|
+
#
|
515
|
+
# Note: experiments with JRuby seem to show that .ready? never
|
516
|
+
# returns true. This means that this code to drain trailing new
|
517
|
+
# lines never runs using JRuby.
|
518
|
+
#
|
519
|
+
# Note 2: the draining of new lines mmust be done _after_ a message
|
520
|
+
# is read. Do _not_ leave them on the wire and attempt to drain them
|
521
|
+
# at the start of the next read. Attempting to do that breaks the
|
522
|
+
# asynchronous nature of the 'poll' method.
|
523
|
+
while read_socket.ready?
|
524
|
+
last_char = read_socket.getc
|
525
|
+
break unless last_char
|
526
|
+
if parse_char(last_char) != "\n"
|
527
|
+
read_socket.ungetc(last_char)
|
528
|
+
break
|
529
|
+
end
|
530
|
+
end
|
531
|
+
# And so, a JRuby hack. Remove any new lines at the start of the
|
532
|
+
# next buffer.
|
533
|
+
message_header.gsub!(/^\n?/, "")
|
534
|
+
|
534
535
|
if @protocol >= Stomp::SPL_11
|
535
536
|
@lr = Time.now.to_f if @hbr
|
536
537
|
end
|
537
|
-
|
538
538
|
# Adds the excluded \n and \0 and tries to create a new message with it
|
539
539
|
msg = Message.new(message_header + "\n" + message_body + "\0", @protocol >= Stomp::SPL_11)
|
540
540
|
#
|
@@ -583,16 +583,16 @@ module Stomp
|
|
583
583
|
# Ruby 1.8: String#length => # of bytes; Ruby 1.9: String#length => # of characters
|
584
584
|
# With Unicode strings, # of bytes != # of characters. So, use String#bytesize when available.
|
585
585
|
body_length_bytes = body.respond_to?(:bytesize) ? body.bytesize : body.length
|
586
|
-
|
587
|
-
# ActiveMQ interprets every message as a BinaryMessage
|
588
|
-
# if content_length header is included.
|
586
|
+
|
587
|
+
# ActiveMQ interprets every message as a BinaryMessage
|
588
|
+
# if content_length header is included.
|
589
589
|
# Using :suppress_content_length => true will suppress this behaviour
|
590
590
|
# and ActiveMQ will interpret the message as a TextMessage.
|
591
591
|
# For more information refer to http://juretta.com/log/2009/05/24/activemq-jms-stomp/
|
592
592
|
# Lets send this header in the message, so it can maintain state when using unreceive
|
593
593
|
headers['content-length'] = "#{body_length_bytes}" unless headers[:suppress_content_length]
|
594
594
|
headers['content-type'] = "text/plain; charset=UTF-8" unless headers['content-type']
|
595
|
-
used_socket.puts command
|
595
|
+
used_socket.puts command
|
596
596
|
headers.each do |k,v|
|
597
597
|
if v.is_a?(Array)
|
598
598
|
v.each do |e|
|
@@ -612,9 +612,14 @@ module Stomp
|
|
612
612
|
|
613
613
|
end
|
614
614
|
end
|
615
|
-
|
615
|
+
|
616
616
|
def open_tcp_socket
|
617
617
|
tcp_socket = nil
|
618
|
+
|
619
|
+
if @logger && @logger.respond_to?(:on_connecting)
|
620
|
+
@logger.on_connecting(log_params)
|
621
|
+
end
|
622
|
+
|
618
623
|
Timeout::timeout(@connect_timeout, Stomp::Error::SocketOpenTimeout) do
|
619
624
|
tcp_socket = TCPSocket.open @host, @port
|
620
625
|
end
|
@@ -625,20 +630,72 @@ module Stomp
|
|
625
630
|
def open_ssl_socket
|
626
631
|
require 'openssl' unless defined?(OpenSSL)
|
627
632
|
ctx = OpenSSL::SSL::SSLContext.new
|
633
|
+
ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE # Assume for now
|
634
|
+
#
|
635
|
+
# Note: if a client uses :ssl => true this results in the gem using
|
636
|
+
# the _default_ Ruby ciphers list. This is _known_ to fail in later
|
637
|
+
# Ruby releases. The gem provides a default cipher list that may
|
638
|
+
# function in these cases. To use this connect with:
|
639
|
+
# * :ssl => Stomp::SSLParams.new
|
640
|
+
# * :ssl => Stomp::SSLParams.new(..., :ciphers => Stomp::DEFAULT_CIPHERS)
|
641
|
+
#
|
642
|
+
# If connecting with an SSLParams instance, and the _default_ Ruby
|
643
|
+
# ciphers list is required, use:
|
644
|
+
# * :ssl => Stomp::SSLParams.new(..., :use_ruby_ciphers => true)
|
645
|
+
#
|
646
|
+
# If a custom ciphers list is required, connect with:
|
647
|
+
# * :ssl => Stomp::SSLParams.new(..., :ciphers => custom_ciphers_list)
|
648
|
+
#
|
649
|
+
if @ssl != true
|
650
|
+
#
|
651
|
+
# Here @ssl is:
|
652
|
+
# * an instance of Stomp::SSLParams
|
653
|
+
# Control would not be here if @ssl == false or @ssl.nil?.
|
654
|
+
#
|
628
655
|
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
656
|
+
# Back reference the SSLContext
|
657
|
+
@ssl.ctx = ctx
|
658
|
+
|
659
|
+
# Server authentication parameters if required
|
660
|
+
if @ssl.ts_files
|
661
|
+
ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
662
|
+
truststores = OpenSSL::X509::Store.new
|
663
|
+
fl = @ssl.ts_files.split(",")
|
664
|
+
fl.each do |fn|
|
665
|
+
# Add next cert file listed
|
666
|
+
raise Stomp::Error::SSLNoTruststoreFileError if !File::exists?(fn)
|
667
|
+
truststores.add_file(fn)
|
668
|
+
end
|
669
|
+
ctx.cert_store = truststores
|
670
|
+
end
|
671
|
+
|
672
|
+
# Client authentication parameters
|
673
|
+
# Both cert file and key file must be present or not, it can not be a mix
|
674
|
+
raise Stomp::Error::SSLClientParamsError if @ssl.cert_file.nil? && !@ssl.key_file.nil?
|
675
|
+
raise Stomp::Error::SSLClientParamsError if !@ssl.cert_file.nil? && @ssl.key_file.nil?
|
676
|
+
if @ssl.cert_file # Any check will do here
|
677
|
+
raise Stomp::Error::SSLNoCertFileError if !File::exists?(@ssl.cert_file)
|
678
|
+
ctx.cert = OpenSSL::X509::Certificate.new(File.open(@ssl.cert_file))
|
679
|
+
raise Stomp::Error::SSLNoKeyFileError if !File::exists?(@ssl.key_file)
|
680
|
+
ctx.key = OpenSSL::PKey::RSA.new(File.open(@ssl.key_file))
|
681
|
+
end
|
682
|
+
|
683
|
+
# Cipher list
|
684
|
+
if !@ssl.use_ruby_ciphers # No Ruby ciphers (the default)
|
685
|
+
if @ssl.ciphers # User ciphers list?
|
686
|
+
ctx.ciphers = @ssl.ciphers # Accept user supplied ciphers
|
687
|
+
else
|
688
|
+
ctx.ciphers = Stomp::DEFAULT_CIPHERS # Just use Stomp defaults
|
689
|
+
end
|
690
|
+
end
|
691
|
+
end
|
633
692
|
|
634
|
-
#
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
693
|
+
#
|
694
|
+
ssl = nil
|
695
|
+
if @logger && @logger.respond_to?(:on_ssl_connecting)
|
696
|
+
@logger.on_ssl_connecting(log_params)
|
697
|
+
end
|
639
698
|
|
640
|
-
ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
641
|
-
ssl = nil
|
642
699
|
Timeout::timeout(@connect_timeout, Stomp::Error::SocketOpenTimeout) do
|
643
700
|
ssl = OpenSSL::SSL::SSLSocket.new(open_tcp_socket, ctx)
|
644
701
|
end
|
@@ -646,6 +703,18 @@ module Stomp
|
|
646
703
|
! @rbuffer.empty? || @io.ready?
|
647
704
|
end
|
648
705
|
ssl.connect
|
706
|
+
if @ssl != true
|
707
|
+
# Pass back results if possible
|
708
|
+
if RUBY_VERSION =~ /1\.8\.[56]/
|
709
|
+
@ssl.verify_result = "N/A for Ruby #{RUBY_VERSION}"
|
710
|
+
else
|
711
|
+
@ssl.verify_result = ssl.verify_result
|
712
|
+
end
|
713
|
+
@ssl.peer_cert = ssl.peer_cert
|
714
|
+
end
|
715
|
+
if @logger && @logger.respond_to?(:on_ssl_connected)
|
716
|
+
@logger.on_ssl_connected(log_params)
|
717
|
+
end
|
649
718
|
ssl
|
650
719
|
end
|
651
720
|
|
@@ -667,13 +736,13 @@ module Stomp
|
|
667
736
|
used_socket = @ssl ? open_ssl_socket : open_tcp_socket
|
668
737
|
# try to close the old connection if any
|
669
738
|
close_socket
|
670
|
-
|
739
|
+
|
671
740
|
@closed = false
|
672
741
|
# Use keepalive
|
673
742
|
used_socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true)
|
674
743
|
used_socket
|
675
744
|
end
|
676
|
-
|
745
|
+
|
677
746
|
def connect(used_socket)
|
678
747
|
@connect_headers = {} unless @connect_headers # Caller said nil/false
|
679
748
|
headers = @connect_headers.clone
|
@@ -817,7 +886,7 @@ module Stomp
|
|
817
886
|
@hb_sent = false # Set the warning flag
|
818
887
|
if @logger && @logger.respond_to?(:on_hbwrite_fail)
|
819
888
|
@logger.on_hbwrite_fail(log_params, {"ticker_interval" => @sti,
|
820
|
-
"exception" => sendex})
|
889
|
+
"exception" => sendex})
|
821
890
|
end
|
822
891
|
raise # Re-raise. What else could be done here?
|
823
892
|
end
|
@@ -858,7 +927,7 @@ module Stomp
|
|
858
927
|
# Shrug. Have not received one. Just set warning flag.
|
859
928
|
@hb_received = false
|
860
929
|
if @logger && @logger.respond_to?(:on_hbread_fail)
|
861
|
-
@logger.on_hbread_fail(log_params, {"ticker_interval" => @rti})
|
930
|
+
@logger.on_hbread_fail(log_params, {"ticker_interval" => @rti})
|
862
931
|
end
|
863
932
|
end
|
864
933
|
else
|
@@ -904,7 +973,7 @@ module Stomp
|
|
904
973
|
# * handles all occurrences of valid single byte characters i.e., the ASCII character set
|
905
974
|
# * provides state transition logic for start bytes of valid characters with 2-4 bytes
|
906
975
|
# * signals a validation failure for all other single bytes
|
907
|
-
#
|
976
|
+
#
|
908
977
|
when "start"
|
909
978
|
# puts "state: start" if DEBUG
|
910
979
|
case next_byte
|
@@ -1095,7 +1164,8 @@ module Stomp
|
|
1095
1164
|
raise Stomp::Error::UTF8ValidationError unless valid_utf8?(e)
|
1096
1165
|
end
|
1097
1166
|
else
|
1098
|
-
vs = v.to_s # Values are usually Strings, but could be TrueClass or Symbol
|
1167
|
+
vs = v.to_s + "" # Values are usually Strings, but could be TrueClass or Symbol
|
1168
|
+
# The + "" forces an 'unfreeze' if necessary
|
1099
1169
|
vs.force_encoding(Stomp::UTF8) if vs.respond_to?(:force_encoding)
|
1100
1170
|
raise Stomp::Error::UTF8ValidationError unless valid_utf8?(vs)
|
1101
1171
|
end
|
data/lib/stomp/constants.rb
CHANGED
@@ -75,4 +75,7 @@ module Stomp
|
|
75
75
|
"\\c", ":",
|
76
76
|
]
|
77
77
|
|
78
|
+
DEFAULT_CIPHERS = [["DHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["DHE-DSS-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["AES256-SHA", "TLSv1/SSLv3", 256, 256], ["EDH-RSA-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["EDH-DSS-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DHE-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["DHE-DSS-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["AES128-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-MD5", "TLSv1/SSLv3", 128, 128], ["EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56],
|
79
|
+
["DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EXP-EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-RC2-CBC-MD5", "TLSv1/SSLv3", 40, 128], ["EXP-RC4-MD5", "TLSv1/SSLv3", 40, 128]]
|
80
|
+
|
78
81
|
end
|
data/lib/stomp/errors.rb
CHANGED
@@ -86,6 +86,36 @@ module Stomp
|
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
89
|
+
class SSLClientParamsError < RuntimeError
|
90
|
+
def message
|
91
|
+
"certificate and key files are both required"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class StompServerError < RuntimeError
|
96
|
+
def message
|
97
|
+
"Connected, header read is nil, is this really a Stomp Server?"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class SSLNoKeyFileError < RuntimeError
|
102
|
+
def message
|
103
|
+
"client key file does not exist"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
class SSLNoCertFileError < RuntimeError
|
108
|
+
def message
|
109
|
+
"client cert file does not exist"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
class SSLNoTruststoreFileError < RuntimeError
|
114
|
+
def message
|
115
|
+
"a client truststore file does not exist"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
89
119
|
end # module Error
|
90
120
|
end # module Stomp
|
91
121
|
|
data/lib/stomp/message.rb
CHANGED
@@ -6,7 +6,7 @@ module Stomp
|
|
6
6
|
class Message
|
7
7
|
attr_accessor :command, :headers, :body, :original
|
8
8
|
|
9
|
-
@@allowed_commands = [
|
9
|
+
@@allowed_commands = [ Stomp::CMD_CONNECTED, Stomp::CMD_MESSAGE, Stomp::CMD_RECEIPT, Stomp::CMD_ERROR ]
|
10
10
|
|
11
11
|
def initialize(frame, protocol11p = false)
|
12
12
|
# p [ "00", frame, frame.encoding ]
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module Stomp
|
4
|
+
#
|
5
|
+
# == Purpose
|
6
|
+
#
|
7
|
+
# Parameters for STOMP ssl connections.
|
8
|
+
#
|
9
|
+
class SSLParams
|
10
|
+
# The trust store files. Normally the certificate of the CA that signed
|
11
|
+
# the server's certificate. One file name, or a CSV list of file names.
|
12
|
+
attr_accessor :ts_files
|
13
|
+
# The client certificate file.
|
14
|
+
attr_accessor :cert_file
|
15
|
+
# The client private key file.
|
16
|
+
attr_accessor :key_file
|
17
|
+
# SSL Connect Verify Result. The result of the handshake.
|
18
|
+
attr_accessor :verify_result
|
19
|
+
# The certificate of the connection peer (the server), received during
|
20
|
+
# the handshake.
|
21
|
+
attr_accessor :peer_cert
|
22
|
+
# Optional list of SSL ciphers to be used. In the format documented for
|
23
|
+
# Ruby's OpenSSL.
|
24
|
+
attr_accessor :ciphers
|
25
|
+
# Abcolute command to use Ruby default ciphers
|
26
|
+
attr_reader :use_ruby_ciphers
|
27
|
+
# Back reference to the OpenSSL::SSL::SSLContext instance, gem sets before connect
|
28
|
+
attr_accessor :ctx # Set by the gem during connect, before the callbacks
|
29
|
+
#
|
30
|
+
def initialize(opts={})
|
31
|
+
|
32
|
+
# Server authentication parameters
|
33
|
+
@ts_files = opts[:ts_files] # A trust store file, normally a CA's cert
|
34
|
+
# or a CSV list of cert file names
|
35
|
+
|
36
|
+
# Client authentication parameters
|
37
|
+
@cert_file = opts[:cert_file] # Client cert
|
38
|
+
@key_file = opts[:key_file] # Client key
|
39
|
+
#
|
40
|
+
raise Stomp::Error::SSLClientParamsError if @cert_file.nil? && !@key_file.nil?
|
41
|
+
raise Stomp::Error::SSLClientParamsError if !@cert_file.nil? && @key_file.nil?
|
42
|
+
#
|
43
|
+
@ciphers = opts[:ciphers]
|
44
|
+
@use_ruby_ciphers = opts[:use_ruby_ciphers] ? opts[:use_ruby_ciphers] : false
|
45
|
+
#
|
46
|
+
end
|
47
|
+
end # of class SSLParams
|
48
|
+
|
49
|
+
end # of module Stomp
|
50
|
+
|
data/lib/stomp/version.rb
CHANGED
data/lib/stomp.rb
CHANGED
@@ -15,14 +15,15 @@
|
|
15
15
|
# See the License for the specific language governing permissions and
|
16
16
|
# limitations under the License.
|
17
17
|
|
18
|
+
require 'stomp/constants' # Constants first
|
18
19
|
require 'stomp/ext/hash'
|
19
20
|
require 'stomp/connection'
|
20
21
|
require 'stomp/client'
|
21
22
|
require 'stomp/message'
|
22
23
|
require 'stomp/version'
|
23
24
|
require 'stomp/errors'
|
24
|
-
require 'stomp/constants'
|
25
25
|
require 'stomp/codec'
|
26
|
+
require 'stomp/sslparams'
|
26
27
|
|
27
28
|
module Stomp
|
28
29
|
end
|