Skip to content

Commit 580a849

Browse files
committed
Issue stompgem#66, failover URL regex should allow a single broker
1 parent 6854b68 commit 580a849

File tree

6 files changed

+141
-48
lines changed

6 files changed

+141
-48
lines changed

lib/client/utils.rb

+36-44
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def parse_hash_params(params)
2323
end
2424

2525
def parse_stomp_url(login)
26-
regexp = /^stomp:\/\/#{url_regex}/ # e.g. stomp://login:passcode@host:port or stomp://host:port
26+
regexp = /^stomp:\/\/#{URL_REPAT}/
2727
return false unless login =~ regexp
2828

2929
@login = $3 || ""
@@ -37,24 +37,26 @@ def parse_stomp_url(login)
3737

3838
# e.g. failover://(stomp://login1:passcode1@localhost:61616,stomp://login2:passcode2@remotehost:61617)?option1=param
3939
def parse_failover_url(login)
40-
regexp = /^failover:(\/\/)?\(stomp(\+ssl)?:\/\/#{url_regex}(,stomp(\+ssl)?:\/\/#{url_regex}\))+(\?(.*))?$/
41-
return false unless login =~ regexp
42-
43-
first_host = {}
44-
first_host[:ssl] = !$2.nil?
45-
@login = first_host[:login] = $4 || ""
46-
@passcode = first_host[:passcode] = $5 || ""
47-
@host = first_host[:host] = $6
48-
@port = first_host[:port] = $7.to_i || Connection::default_port(first_host[:ssl])
49-
options = $16 || ""
50-
parts = options.split(/&|=/)
51-
options = Hash[*parts]
52-
hosts = [first_host] + parse_hosts(login)
53-
@parameters = {}
54-
@parameters[:hosts] = hosts
55-
@parameters.merge! filter_options(options)
56-
@reliable = true
57-
true
40+
rval = nil
41+
if md = FAILOVER_REGEX.match(login)
42+
finhosts = parse_hosts(login)
43+
#
44+
@login = finhosts[0][:login] || ""
45+
@passcode = finhosts[0][:passcode] || ""
46+
@host = finhosts[0][:host] || ""
47+
@port = finhosts[0][:port] || ""
48+
#
49+
options = {}
50+
if md_last = md[md.size-1]
51+
parts = md_last.split(/&|=/)
52+
raise Stomp::Error::MalformedFailoverOptionsError unless (parts.size % 2 ) == 0
53+
options = Hash[*parts]
54+
end
55+
@parameters = {:hosts => finhosts}.merge! filter_options(options)
56+
@reliable = true
57+
rval = true
58+
end
59+
rval
5860
end
5961

6062
def parse_positional_params(login, passcode, host, port, reliable)
@@ -88,31 +90,21 @@ def register_receipt_listener(listener)
8890
id
8991
end
9092

91-
# url_regex defines a regex for e.g. login:passcode@host:port or host:port
92-
def url_regex
93-
'((([\w~!@#$%^&*()\-+=.?:<>,.]*\w):([\w~!@#$%^&*()\-+=.?:<>,.]*))?@)?([\w\.\-]+):(\d+)'
94-
end
95-
96-
# Parse a stomp URL.
97-
def parse_hosts(url)
98-
hosts = []
99-
100-
# TODO should change to use 'url_regex'. Deferred to later failover://
101-
# testing.
102-
host_match = /stomp(\+ssl)?:\/\/(([\w\.]*):(\w*)@)?([\w\.]+):(\d+)\)/
103-
url.scan(host_match).each do |match|
104-
host = {}
105-
host[:ssl] = !match[0].nil?
106-
host[:login] = match[2] || ""
107-
host[:passcode] = match[3] || ""
108-
host[:host] = match[4]
109-
host[:port] = match[5].to_i
110-
111-
hosts << host
112-
end
113-
114-
hosts
115-
end
93+
# Parse a stomp URL.
94+
def parse_hosts(url)
95+
hosts = []
96+
host_match = /stomp(\+ssl)?:\/\/#{URL_REPAT}/
97+
url.scan(host_match).each do |match|
98+
host = {}
99+
host[:ssl] = match[0] == "+ssl" ? true : false
100+
host[:login] = match[3] || ""
101+
host[:passcode] = match[4] || ""
102+
host[:host] = match[5]
103+
host[:port] = match[6].to_i
104+
hosts << host
105+
end
106+
hosts
107+
end
116108

117109
# A very basic check of required arguments.
118110
def check_arguments!()

lib/stomp/constants.rb

+7
Original file line numberDiff line numberDiff line change
@@ -111,4 +111,11 @@ module Stomp
111111
["EXP-RC4-MD5", "TLSv1/SSLv3", 40, 128],
112112
]
113113

114+
# stomp URL regex pattern, for e.g. login:passcode@host:port or host:port
115+
URL_REPAT = '((([\w~!@#$%^&*()\-+=.?:<>,.]*\w):([\w~!@#$%^&*()\-+=.?:<>,.]*))?@)?([\w\.\-]+):(\d+)'
116+
117+
# Failover URL regex, for e.g.
118+
#failover:(stomp+ssl://login1:passcode1@remotehost1:61612,stomp://login2:passcode2@remotehost2:61613)
119+
FAILOVER_REGEX = /^failover:(\/\/)?\(stomp(\+ssl)?:\/\/#{URL_REPAT}(,stomp(\+ssl)?:\/\/#{URL_REPAT})*\)(\?(.*))?$/
120+
114121
end # Module Stomp

lib/stomp/errors.rb

+8
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,14 @@ def message
205205
end
206206
end
207207

208+
# MalformedFailoverOptionsError is raised if failover URL
209+
# options can not be parsed
210+
class MalformedFailoverOptionsError < RuntimeError
211+
def message
212+
"failover options are malformed"
213+
end
214+
end
215+
208216
end # module Error
209217

210218
end # module Stomp

spec/client_spec.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@
254254
end
255255

256256
it "should properly parse a URL with failover:" do
257-
url = "failover:(stomp://login1:passcode1@localhost:61616,stomp://login2:passcode2@remotehost1:61617),stomp://login3:passcode3@remotehost2:61618)"
257+
url = "failover:(stomp://login1:passcode1@localhost:61616,stomp://login2:passcode2@remotehost1:61617,stomp://login3:passcode3@remotehost2:61618)"
258258

259259
@parameters[:hosts] = [
260260
{:login => "login1", :passcode => "passcode1", :host => "localhost", :port => 61616, :ssl => false},
@@ -283,7 +283,7 @@
283283
end
284284

285285
it "should properly parse a URL with user and/or password blank" do
286-
url = "failover:(stomp://:@localhost:61616,stomp://:@remotehost:61617)"
286+
url = "failover:(stomp://@localhost:61616,stomp://@remotehost:61617)"
287287

288288
@parameters[:hosts] = [
289289
{:login => "", :passcode => "", :host => "localhost", :port => 61616, :ssl => false},

test/test_urlogin.rb

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# -*- encoding: utf-8 -*-
2+
3+
if Kernel.respond_to?(:require_relative)
4+
require_relative("test_helper")
5+
else
6+
$:.unshift(File.dirname(__FILE__))
7+
require 'test_helper'
8+
end
9+
10+
=begin
11+
12+
Main class for testing Stomp::Client URL based Logins.
13+
14+
=end
15+
class TestURLLogins < Test::Unit::TestCase
16+
include TestBase
17+
18+
def setup
19+
hostname = host()
20+
portnum = port()
21+
sslpn = ssl_port()
22+
@tdstomp = [
23+
"stomp://guestl:guestp@#{hostname}:#{portnum}",
24+
"stomp://#{hostname}:#{portnum}",
25+
"stomp://@#{hostname}:#{portnum}",
26+
"stomp://f@#$$%^&*()_+=o.o:@#{hostname}:#{portnum}",
27+
'stomp://f@#$$%^&*()_+=o.o::b~!@#$%^&*()+-_=?:<>,.@@' + hostname + ":#{portnum}",
28+
]
29+
@tdfailover = [
30+
"failover://(stomp://#{hostname}:#{portnum})",
31+
"failover://(stomp+ssl://#{hostname}:#{sslpn})",
32+
"failover://(stomp://#{hostname}:#{portnum})",
33+
"failover://(stomp://#{hostname}:#{portnum})?whatup=doc&coyote=kaboom",
34+
"failover://(stomp://#{hostname}:#{portnum})?whatup=doc",
35+
"failover://(stomp://#{hostname}:#{portnum})?whatup=doc&coyote=kaboom&randomize=true",
36+
'failover://(stomp://f@#$$%^&*()_+=o.o::b~!@#$%^&*()+-_=?:<>,.@@' + "localhost" + ":#{portnum}" + ")",
37+
'failover://(stomp://f@#$$%^&*()_+=o.o::b~!@#$%^&*()+-_=:<>,.@@' + "localhost" + ":#{portnum}" + ")",
38+
'failover://(stomp://f@#$$%^&*()_+=o.o::b~!@#$%^&*()+-_=?:<>,.@@' + "localhost" + ":#{portnum}" + ")?a=b",
39+
'failover://(stomp://f@#$$%^&*()_+=o.o::b~!@#$%^&*()+-_=:<>,.@@' + "localhost" + ":#{portnum}" + ")?c=d&e=f",
40+
"failover://(stomp://usera:passa@#{hostname}:#{portnum})",
41+
"failover://(stomp+ssl://usera:passa@#{hostname}:#{sslpn})",
42+
"failover://(stomp://usera:@#{hostname}:#{portnum})",
43+
"failover://(stomp://#{hostname}:#{portnum},stomp://#{hostname}:#{portnum})",
44+
"failover://(stomp://usera:passa@#{hostname}:#{portnum},stomp://#{hostname}:#{portnum})",
45+
"failover://(stomp://usera:@#{hostname}:#{portnum},stomp://#{hostname}:#{portnum})",
46+
"failover://(stomp://usera:@#{hostname}:#{portnum},stomp+ssl://#{hostname}:#{sslpn})",
47+
"failover://(stomp://#{hostname}:#{portnum},stomp://#{hostname}:#{portnum})?a=b&c=d",
48+
"failover://(stomp://#{hostname}:#{portnum},stomp://#{hostname}:#{portnum})?a=b&c=d&connect_timeout=2020",
49+
]
50+
51+
@badparms = "failover://(stomp://#{hostname}:#{portnum})?a=b&noequal"
52+
end
53+
54+
def teardown
55+
@client.close if @client && @client.open? # allow tests to close
56+
end
57+
58+
# test stomp:// URLs
59+
def test_0010_stomp_urls()
60+
@tdstomp.each_with_index do |url, ndx|
61+
c = Stomp::Client.new(url)
62+
assert !c.nil?, url
63+
assert c.open?, url
64+
c.close
65+
end
66+
end
67+
68+
# test failover:// urls
69+
def test_0020_failover_urls()
70+
@tdfailover.each_with_index do |url, ndx|
71+
c = Stomp::Client.new(url)
72+
assert !c.nil?, url
73+
assert c.open?, url
74+
c.close
75+
end
76+
end
77+
78+
# test failover:// with bad parameters
79+
def test_0020_failover_badparms()
80+
assert_raise(Stomp::Error::MalformedFailoverOptionsError) {
81+
c = Stomp::Client.new(@badparms)
82+
}
83+
end
84+
85+
end unless ENV['STOMP_RABBIT']
86+

test/tlogger.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,11 @@ def on_hbread_fail(parms, ticker_data)
5151
end
5252

5353
# Stomp 1.1+ - heart beat thread fires
54-
def on_hbfire(parms, type, time)
54+
def on_hbfire(parms, type, firedata)
5555
begin
5656
@log.debug "HBfire #{type} " + "=" * 30
5757
@log.debug "HBfire #{type} Parms #{info(parms)}"
58-
@log.debug "HBfire #{type} Time #{time}"
58+
@log.debug "HBfire #{type} Firedata #{firedata.inspect}"
5959
rescue
6060
@log.debug "HBfire #{type} oops"
6161
end

0 commit comments

Comments
 (0)