stompserver 0.9.5 → 0.9.6
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/History.txt +7 -0
- data/lib/queue_manager.rb +5 -5
- data/lib/stomp_frame.rb +5 -1
- data/lib/stomp_server.rb +14 -4
- data/test/test_queue_manager.rb +17 -1
- data/test/test_stomp_frame.rb +13 -1
- data/test/test_stomp_server.rb +21 -0
- metadata +2 -2
data/History.txt
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
== 0.9.6 / 31 Oct 2006
|
2
|
+
|
3
|
+
* Added simple code to handle denial of service attacks from large headers
|
4
|
+
* Fixed a multitude of bugs (and added tests) found by our small but growing
|
5
|
+
community of users
|
6
|
+
* more coming soom (thanks to snacktime)
|
7
|
+
|
1
8
|
== 0.9.5 / 18 Oct 2006
|
2
9
|
|
3
10
|
* Removed eventmachine dependency in the gem
|
data/lib/queue_manager.rb
CHANGED
@@ -41,20 +41,20 @@ class QueueManager
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def ack(user, frame)
|
44
|
-
pending_size = @pending[user]
|
44
|
+
pending_size = @pending[user].size
|
45
45
|
msgid = frame.headers['message-id']
|
46
46
|
@pending[user].delete_if { |pf| pf.headers['message-id'] == msgid }
|
47
|
-
raise "Message (#{msgid}) not found" if pending_size == @pending[user]
|
47
|
+
raise "Message (#{msgid}) not found" if pending_size == @pending[user].size
|
48
48
|
@journal.delete(msgid)
|
49
49
|
end
|
50
50
|
|
51
51
|
def disconnect(user)
|
52
|
-
@pending[user].each do |frame|
|
53
|
-
sendmsg(frame)
|
54
|
-
end
|
55
52
|
@queues.each do |dest, queue|
|
56
53
|
queue.delete_if { |qu| qu.user == user }
|
57
54
|
end
|
55
|
+
@pending[user].each do |frame|
|
56
|
+
sendmsg(frame)
|
57
|
+
end
|
58
58
|
end
|
59
59
|
|
60
60
|
def send_to_user(frame, user)
|
data/lib/stomp_frame.rb
CHANGED
@@ -54,7 +54,7 @@ class StompFrameRecognizer
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def parse_header
|
57
|
-
if match = @buffer.match(/^\s*(\S+)
|
57
|
+
if match = @buffer.match(/^\s*(\S+)$\r?\n((?:[ \t]*.*?[ \t]*:[ \t]*.*?[ \t]*$\r?\n)*)\r?\n/)
|
58
58
|
@frame.command, headers = match.captures
|
59
59
|
@buffer = match.post_match
|
60
60
|
headers.split(/\n/).each do |data|
|
@@ -65,6 +65,10 @@ class StompFrameRecognizer
|
|
65
65
|
|
66
66
|
# body_length is nil, if there is no content-length, otherwise it is the length (as in integer)
|
67
67
|
@body_length = @frame.headers['content-length'] && @frame.headers['content-length'].to_i
|
68
|
+
else
|
69
|
+
# saftey valve to dump bad (DOSA?) headers/frames
|
70
|
+
# this should be a constant or read out of a configuration file
|
71
|
+
raise RuntimeError.new("Invalid stompframe (possible DOSA)") if @buffer.length > 4096
|
68
72
|
end
|
69
73
|
end
|
70
74
|
|
data/lib/stomp_server.rb
CHANGED
@@ -6,7 +6,7 @@ require 'queue_manager'
|
|
6
6
|
require 'frame_journal'
|
7
7
|
|
8
8
|
module StompServer
|
9
|
-
VERSION = '0.9.
|
9
|
+
VERSION = '0.9.6'
|
10
10
|
VALID_COMMANDS = [:connect, :send, :subscribe, :unsubscribe, :begin, :commit, :abort, :ack, :disconnect]
|
11
11
|
|
12
12
|
def self.setup(j = FrameJournal.new, tm = TopicManager.new, qm = QueueManager.new(j))
|
@@ -43,6 +43,8 @@ module StompServer
|
|
43
43
|
raise "Unhandled frame: #{cmd}" unless VALID_COMMANDS.include?(cmd)
|
44
44
|
raise "Not connected" if !@connected && cmd != :connect
|
45
45
|
|
46
|
+
puts "process_frame #{cmd}" if $DEBUG
|
47
|
+
|
46
48
|
# I really like this code, but my needs are a little trickier
|
47
49
|
#
|
48
50
|
|
@@ -50,11 +52,18 @@ module StompServer
|
|
50
52
|
handle_transaction(frame, trans, cmd)
|
51
53
|
else
|
52
54
|
cmd = :sendmsg if cmd == :send
|
55
|
+
puts "Execute #{cmd}" if $DEBUG
|
53
56
|
send(cmd, frame)
|
54
57
|
end
|
55
58
|
|
56
59
|
send_receipt(frame.headers['receipt']) if frame.headers['receipt']
|
57
60
|
end
|
61
|
+
|
62
|
+
# here is how we can stop, of course there is currently no
|
63
|
+
# way to get here
|
64
|
+
def shutdown(msg)
|
65
|
+
EventMachine::stop_event_loop
|
66
|
+
end
|
58
67
|
|
59
68
|
def handle_transaction(frame, trans, cmd)
|
60
69
|
if [:begin, :commit, :abort].include?(cmd)
|
@@ -84,7 +93,8 @@ module StompServer
|
|
84
93
|
|
85
94
|
def subscribe(frame)
|
86
95
|
if frame.dest =~ %r|^/queue|
|
87
|
-
|
96
|
+
ack = frame.headers['ack'] == 'client'
|
97
|
+
@@queue_manager.subscribe(frame.dest, self, ack)
|
88
98
|
else
|
89
99
|
@@topic_manager.subscribe(frame.dest, self)
|
90
100
|
end
|
@@ -92,9 +102,9 @@ module StompServer
|
|
92
102
|
|
93
103
|
def unsubscribe(frame)
|
94
104
|
if frame.dest =~ %r|^/queue|
|
95
|
-
@@queue_manager.unsubscribe(self)
|
105
|
+
@@queue_manager.unsubscribe(frame.dest, self)
|
96
106
|
else
|
97
|
-
@@topic_manager.unsubscribe(self)
|
107
|
+
@@topic_manager.unsubscribe(frame.dest, self)
|
98
108
|
end
|
99
109
|
end
|
100
110
|
|
data/test/test_queue_manager.rb
CHANGED
@@ -17,6 +17,7 @@ class TestQueues < Test::Unit::TestCase
|
|
17
17
|
@headers = { 'destination' => dest, 'message-id' => id }
|
18
18
|
@data = msg
|
19
19
|
end
|
20
|
+
def body ; @data ; end
|
20
21
|
def to_s ; @data ; end
|
21
22
|
end
|
22
23
|
|
@@ -97,4 +98,19 @@ class TestQueues < Test::Unit::TestCase
|
|
97
98
|
assert_equal('', u2.data)
|
98
99
|
end
|
99
100
|
|
100
|
-
|
101
|
+
def test_sendmsg_ack
|
102
|
+
u = UserMock.new
|
103
|
+
t = 'fooack'
|
104
|
+
@t.subscribe(t, u, true)
|
105
|
+
|
106
|
+
m1 = MessageMock.new(t, 'foomsg')
|
107
|
+
@t.sendmsg(m1)
|
108
|
+
assert_equal(m1.data, u.data)
|
109
|
+
assert_equal('MESSAGE', m1.command)
|
110
|
+
@t.disconnect(u)
|
111
|
+
|
112
|
+
u2 = UserMock.new
|
113
|
+
@t.subscribe(t, u2)
|
114
|
+
assert_equal(m1.data, u2.data)
|
115
|
+
end
|
116
|
+
end
|
data/test/test_stomp_frame.rb
CHANGED
@@ -57,8 +57,20 @@ FRAME
|
|
57
57
|
assert_equal("bar2", f.headers["foo2"])
|
58
58
|
assert_equal("message body 2\n", f.body)
|
59
59
|
end
|
60
|
+
|
61
|
+
def test_double2
|
62
|
+
data = "SEND\ndestination:/queue/f\ncontent-length: 33\ncontent-type: text/plain; charset=UTF-8\n\n1: Tue Oct 24 12:19:52 -0400 2006\000SEND\ndestination:/queue/f\ncontent-length: 33\ncontent-type: text/plain; charset=UTF-8\n\n2: Tue Oct 24 12:19:52 -0400 2006\000"
|
63
|
+
|
64
|
+
@sfr << data
|
65
|
+
assert_equal(2, @sfr.frames.size)
|
66
|
+
f = @sfr.frames.shift
|
67
|
+
assert_equal(1, @sfr.frames.size)
|
68
|
+
assert_equal("SEND", f.command)
|
69
|
+
assert_equal("/queue/f", f.headers["destination"])
|
70
|
+
assert_match(/1: Tue/, f.body)
|
71
|
+
end
|
60
72
|
|
61
|
-
|
73
|
+
def test_partialframe
|
62
74
|
@sfr << <<FRAME
|
63
75
|
COMMAND
|
64
76
|
name:value
|
data/test/test_stomp_server.rb
CHANGED
@@ -238,4 +238,25 @@ class TestStompServer < Test::Unit::TestCase
|
|
238
238
|
ss2.stomp("SUBSCRIBE", {"destination" => '/queue/foo'})
|
239
239
|
assert_match(/Hi Pat/, ss2.sent)
|
240
240
|
end
|
241
|
+
|
242
|
+
def test_ack_queue_message
|
243
|
+
ss1 = MockStompServer.make_client
|
244
|
+
ss1.stomp("SEND", {'destination' => '/queue/taqm'},
|
245
|
+
'Hi Pat')
|
246
|
+
ss1.stomp("DISCONNECT")
|
247
|
+
|
248
|
+
ss2 = MockStompServer.make_client
|
249
|
+
ss2.stomp("SUBSCRIBE", {"destination" => '/queue/taqm', 'ack' => 'client'})
|
250
|
+
assert_match(/Hi Pat/, ss2.sent)
|
251
|
+
ss2.unbind
|
252
|
+
|
253
|
+
ss3 = MockStompServer.make_client
|
254
|
+
ss3.stomp("SUBSCRIBE", {"destination" => '/queue/taqm'})
|
255
|
+
assert_match(/Hi Pat/, ss3.sent)
|
256
|
+
|
257
|
+
assert_nothing_raised do
|
258
|
+
ss3.stomp("SUBSCRIBE", {"destination" => '/queue/taqm',
|
259
|
+
"message-id" => "msg-cmastomp-1"})
|
260
|
+
end
|
261
|
+
end
|
241
262
|
end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
|
|
3
3
|
specification_version: 1
|
4
4
|
name: stompserver
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.9.
|
7
|
-
date: 2006-10-
|
6
|
+
version: 0.9.6
|
7
|
+
date: 2006-10-31 00:00:00 -05:00
|
8
8
|
summary: A very light messaging server
|
9
9
|
require_paths:
|
10
10
|
- lib
|