eventmachine 0.8.0 → 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +9 -5
- data/ext/autoscan.log +0 -0
- data/ext/cmain.cpp +76 -1
- data/ext/cplusplus.cpp +175 -0
- data/ext/ed.cpp +27 -2
- data/ext/ed.h +4 -1
- data/ext/eventmachine.h +3 -1
- data/ext/eventmachine_cpp.h +94 -0
- data/ext/extconf.rb +7 -1
- data/ext/project.h +9 -3
- data/ext/rubymain.cpp +44 -1
- data/lib/em/deferrable.rb +30 -5
- data/lib/em/streamer.rb +114 -0
- data/lib/eventmachine.rb +50 -2
- data/lib/eventmachine_version.rb +2 -2
- data/lib/jeventmachine.rb +106 -0
- data/lib/protocols/linetext2.rb +145 -0
- data/lib/protocols/stomp.rb +127 -0
- data/tests/test_basic.rb +10 -8
- data/tests/test_epoll.rb +8 -5
- data/tests/test_ltp.rb +7 -1
- data/tests/test_ltp2.rb +260 -0
- data/tests/test_send_file.rb +236 -0
- data/tests/test_servers.rb +87 -0
- metadata +12 -2
@@ -0,0 +1,145 @@
|
|
1
|
+
# $Id: linetext2.rb 486 2007-07-29 17:15:12Z blackhedd $
|
2
|
+
#
|
3
|
+
# Author:: Francis Cianfrocca (gmail: blackhedd)
|
4
|
+
# Homepage:: http://rubyeventmachine.com
|
5
|
+
# Date:: 15 November 2006
|
6
|
+
#
|
7
|
+
# See EventMachine and EventMachine::Connection for documentation and
|
8
|
+
# usage examples.
|
9
|
+
#
|
10
|
+
#----------------------------------------------------------------------------
|
11
|
+
#
|
12
|
+
# Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
|
13
|
+
# Gmail: blackhedd
|
14
|
+
#
|
15
|
+
# This program is free software; you can redistribute it and/or modify
|
16
|
+
# it under the terms of either: 1) the GNU General Public License
|
17
|
+
# as published by the Free Software Foundation; either version 2 of the
|
18
|
+
# License, or (at your option) any later version; or 2) Ruby's License.
|
19
|
+
#
|
20
|
+
# See the file COPYING for complete licensing information.
|
21
|
+
#
|
22
|
+
#---------------------------------------------------------------------------
|
23
|
+
#
|
24
|
+
#
|
25
|
+
#
|
26
|
+
|
27
|
+
|
28
|
+
# In the grand, time-honored tradition of re-inventing the wheel, we offer
|
29
|
+
# here YET ANOTHER protocol that handles line-oriented data with interspersed
|
30
|
+
# binary text. This one trades away some of the performance optimizations of
|
31
|
+
# EventMachine::Protocols::LineAndTextProtocol in order to get better correctness
|
32
|
+
# with regard to binary text blocks that can switch back to line mode. It also
|
33
|
+
# permits the line-delimiter to change in midstream.
|
34
|
+
# This was originally written to support Stomp.
|
35
|
+
|
36
|
+
# TODO! We're not enforcing the limits on header lengths and text-lengths.
|
37
|
+
# When we get around to that, call #receive_error if the user defined it, otherwise
|
38
|
+
# throw exceptions.
|
39
|
+
|
40
|
+
module EventMachine
|
41
|
+
module Protocols
|
42
|
+
module LineText2
|
43
|
+
MaxLineLength = 16*1024
|
44
|
+
MaxBinaryLength = 32*1024*1024
|
45
|
+
|
46
|
+
#--
|
47
|
+
# Will be called recursively until there's no data to read.
|
48
|
+
# That way the user-defined handlers we call can modify the
|
49
|
+
# handling characteristics on a per-token basis.
|
50
|
+
#
|
51
|
+
def receive_data data
|
52
|
+
return unless (data and data.length > 0)
|
53
|
+
|
54
|
+
# Do this stuff in lieu of a constructor.
|
55
|
+
@lt2_mode ||= :lines
|
56
|
+
@lt2_delimiter ||= "\n"
|
57
|
+
@lt2_linebuffer ||= []
|
58
|
+
|
59
|
+
if @lt2_mode == :lines
|
60
|
+
if ix = data.index( @lt2_delimiter )
|
61
|
+
@lt2_linebuffer << data[0...ix]
|
62
|
+
ln = @lt2_linebuffer.join
|
63
|
+
@lt2_linebuffer.clear
|
64
|
+
if @lt2_delimiter == "\n"
|
65
|
+
ln.chomp!
|
66
|
+
end
|
67
|
+
receive_line ln
|
68
|
+
receive_data data[(ix+@lt2_delimiter.length)..-1]
|
69
|
+
else
|
70
|
+
@lt2_linebuffer << data
|
71
|
+
end
|
72
|
+
elsif @lt2_mode == :text
|
73
|
+
if @lt2_textsize
|
74
|
+
needed = @lt2_textsize - @lt2_textpos
|
75
|
+
will_take = if data.length > needed
|
76
|
+
needed
|
77
|
+
else
|
78
|
+
data.length
|
79
|
+
end
|
80
|
+
|
81
|
+
@lt2_textbuffer << data[0...will_take]
|
82
|
+
tail = data[will_take..-1]
|
83
|
+
|
84
|
+
@lt2_textpos += will_take
|
85
|
+
if @lt2_textpos >= @lt2_textsize
|
86
|
+
receive_binary_data @lt2_textbuffer.join
|
87
|
+
set_line_mode
|
88
|
+
end
|
89
|
+
|
90
|
+
receive_data tail
|
91
|
+
else
|
92
|
+
receive_binary_data data
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
def set_delimiter delim
|
99
|
+
@lt2_delimiter = delim.to_s
|
100
|
+
end
|
101
|
+
|
102
|
+
# Called internally but also exposed to user code, for the case in which
|
103
|
+
# processing of binary data creates a need to transition back to line mode.
|
104
|
+
# We support an optional parameter to "throw back" some data, which might
|
105
|
+
# be an umprocessed chunk of the transmitted binary data, or something else
|
106
|
+
# entirely.
|
107
|
+
def set_line_mode data=""
|
108
|
+
@lt2_mode = :lines
|
109
|
+
(@lt2_linebuffer ||= []).clear
|
110
|
+
receive_data data.to_s
|
111
|
+
end
|
112
|
+
|
113
|
+
def set_text_mode size=nil
|
114
|
+
if size == 0
|
115
|
+
set_line_mode
|
116
|
+
else
|
117
|
+
@lt2_mode = :text
|
118
|
+
(@lt2_textbuffer ||= []).clear
|
119
|
+
@lt2_textsize = size # which can be nil, signifying no limit
|
120
|
+
@lt2_textpos = 0
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# In case of a dropped connection, we'll send a partial buffer to user code
|
125
|
+
# when in sized text mode. User overrides of #receive_binary_data need to
|
126
|
+
# be aware that they may get a short buffer.
|
127
|
+
def unbind
|
128
|
+
if @lt2_mode == :text and @lt2_textpos > 0
|
129
|
+
receive_binary_data @lt2_textbuffer.join
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# Stub. Should be subclassed by user code.
|
134
|
+
def receive_line ln
|
135
|
+
# no-op
|
136
|
+
end
|
137
|
+
|
138
|
+
# Stub. Should be subclassed by user code.
|
139
|
+
def receive_binary_data data
|
140
|
+
# no-op
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# $Id: stomp.rb 488 2007-07-30 05:09:40Z blackhedd $
|
2
|
+
#
|
3
|
+
# Author:: Francis Cianfrocca (gmail: blackhedd)
|
4
|
+
# Homepage:: http://rubyeventmachine.com
|
5
|
+
# Date:: 15 November 2006
|
6
|
+
#
|
7
|
+
# See EventMachine and EventMachine::Connection for documentation and
|
8
|
+
# usage examples.
|
9
|
+
#
|
10
|
+
#----------------------------------------------------------------------------
|
11
|
+
#
|
12
|
+
# Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
|
13
|
+
# Gmail: blackhedd
|
14
|
+
#
|
15
|
+
# This program is free software; you can redistribute it and/or modify
|
16
|
+
# it under the terms of either: 1) the GNU General Public License
|
17
|
+
# as published by the Free Software Foundation; either version 2 of the
|
18
|
+
# License, or (at your option) any later version; or 2) Ruby's License.
|
19
|
+
#
|
20
|
+
# See the file COPYING for complete licensing information.
|
21
|
+
#
|
22
|
+
#---------------------------------------------------------------------------
|
23
|
+
#
|
24
|
+
#
|
25
|
+
#
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
module EventMachine
|
30
|
+
module Protocols
|
31
|
+
|
32
|
+
# Implements Stomp (http://docs.codehaus.org/display/STOMP/Protocol).
|
33
|
+
#
|
34
|
+
module Stomp
|
35
|
+
include LineText2
|
36
|
+
|
37
|
+
class Message
|
38
|
+
attr_accessor :command, :header, :body
|
39
|
+
def initialize
|
40
|
+
@header = {}
|
41
|
+
@state = :precommand
|
42
|
+
@content_length = nil
|
43
|
+
end
|
44
|
+
def consume_line line
|
45
|
+
if @state == :precommand
|
46
|
+
unless line =~ /\A\s*\Z/
|
47
|
+
@command = line
|
48
|
+
@state = :headers
|
49
|
+
end
|
50
|
+
elsif @state == :headers
|
51
|
+
if line == ""
|
52
|
+
if @content_length
|
53
|
+
yield( [:sized_text, @content_length+1] )
|
54
|
+
else
|
55
|
+
@state = :body
|
56
|
+
yield( [:unsized_text] )
|
57
|
+
end
|
58
|
+
elsif line =~ /\A([^:]+):(.+)\Z/
|
59
|
+
k = $1.dup.strip
|
60
|
+
v = $2.dup.strip
|
61
|
+
@header[k] = v
|
62
|
+
if k == "content-length"
|
63
|
+
@content_length = v.to_i
|
64
|
+
end
|
65
|
+
else
|
66
|
+
# This is a protocol error. How to signal it?
|
67
|
+
end
|
68
|
+
elsif @state == :body
|
69
|
+
@body = line
|
70
|
+
yield( [:dispatch] )
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def send_frame verb, headers={}, body=""
|
76
|
+
ary = [verb, "\n"]
|
77
|
+
headers.each {|k,v| ary << "#{k}:#{v}\n" }
|
78
|
+
ary << "content-length: #{body.to_s.length}\n"
|
79
|
+
ary << "content-type: text/plain; charset=UTF-8\n"
|
80
|
+
ary << "\n"
|
81
|
+
ary << body.to_s
|
82
|
+
ary << "\0"
|
83
|
+
send_data ary.join
|
84
|
+
end
|
85
|
+
|
86
|
+
def receive_line line
|
87
|
+
@stomp_initialized || init_message_reader
|
88
|
+
@stomp_message.consume_line(line) {|outcome|
|
89
|
+
if outcome.first == :sized_text
|
90
|
+
set_text_mode outcome[1]
|
91
|
+
elsif outcome.first == :unsized_text
|
92
|
+
set_delimiter "\0"
|
93
|
+
elsif outcome.first == :dispatch
|
94
|
+
receive_msg(@stomp_message) if respond_to?(:receive_msg)
|
95
|
+
init_message_reader
|
96
|
+
end
|
97
|
+
}
|
98
|
+
end
|
99
|
+
def receive_binary_data data
|
100
|
+
@stomp_message.body = data[0..-2]
|
101
|
+
receive_msg(@stomp_message) if respond_to?(:receive_msg)
|
102
|
+
init_message_reader
|
103
|
+
end
|
104
|
+
|
105
|
+
def init_message_reader
|
106
|
+
@stomp_initialized = true
|
107
|
+
set_delimiter "\n"
|
108
|
+
set_line_mode
|
109
|
+
@stomp_message = Message.new
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
# STOMP verbs
|
114
|
+
def connect parms={}
|
115
|
+
send_frame "CONNECT", parms
|
116
|
+
end
|
117
|
+
def send destination, body, parms={}
|
118
|
+
send_frame "SEND", parms.merge( :destination=>destination ), body.to_s
|
119
|
+
end
|
120
|
+
def subscribe dest, ack=false
|
121
|
+
send_frame "SUBSCRIBE", {:destination=>dest, :ack=>(ack ? "client" : "auto")}
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
data/tests/test_basic.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# $Id: test_basic.rb
|
1
|
+
# $Id: test_basic.rb 452 2007-07-21 13:35:16Z blackhedd $
|
2
2
|
#
|
3
3
|
# Author:: Francis Cianfrocca (gmail: blackhedd)
|
4
4
|
# Homepage:: http://rubyeventmachine.com
|
@@ -44,6 +44,8 @@ class TestBasic < Test::Unit::TestCase
|
|
44
44
|
assert_equal( :pure_ruby, lt )
|
45
45
|
when :extension
|
46
46
|
assert_equal( :extension, lt )
|
47
|
+
when :java
|
48
|
+
assert_equal( :java, lt )
|
47
49
|
else
|
48
50
|
assert_equal( :extension, lt )
|
49
51
|
end
|
@@ -74,19 +76,19 @@ class TestBasic < Test::Unit::TestCase
|
|
74
76
|
|
75
77
|
#-------------------------------------
|
76
78
|
|
77
|
-
# This test
|
79
|
+
# This test once threw an already-running exception.
|
78
80
|
module Trivial
|
79
81
|
def post_init
|
80
|
-
|
82
|
+
EventMachine.stop
|
81
83
|
end
|
82
84
|
end
|
83
85
|
|
84
86
|
def test_server
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
87
|
+
EventMachine.run {
|
88
|
+
EventMachine.start_server "localhost", 9000, Trivial
|
89
|
+
EventMachine.connect "localhost", 9000
|
90
|
+
}
|
91
|
+
assert( true ) # make sure it halts
|
90
92
|
end
|
91
93
|
|
92
94
|
#--------------------------------------
|
data/tests/test_epoll.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# $Id: test_epoll.rb
|
1
|
+
# $Id: test_epoll.rb 449 2007-07-21 00:15:30Z blackhedd $
|
2
2
|
#
|
3
3
|
# Author:: Francis Cianfrocca (gmail: blackhedd)
|
4
4
|
# Homepage:: http://rubyeventmachine.com
|
@@ -67,11 +67,14 @@ class TestEpoll < Test::Unit::TestCase
|
|
67
67
|
# We can set the rlimit/nofile of a process but we can only set it
|
68
68
|
# higher if we're running as root.
|
69
69
|
# On most systems, the default value is 1024.
|
70
|
+
# Java doesn't (currently) implement this.
|
70
71
|
def test_rlimit
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
72
|
+
unless RUBY_PLATFORM =~ /java/
|
73
|
+
a = EM.set_descriptor_table_size
|
74
|
+
assert( a <= 1024 )
|
75
|
+
a = EM.set_descriptor_table_size( 1024 )
|
76
|
+
assert( a == 1024 )
|
77
|
+
end
|
75
78
|
end
|
76
79
|
|
77
80
|
# Run a high-volume version of this test by kicking the number of connections
|
data/tests/test_ltp.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# $Id: test_ltp.rb
|
1
|
+
# $Id: test_ltp.rb 448 2007-07-21 00:15:05Z blackhedd $
|
2
2
|
#
|
3
3
|
# Author:: Francis Cianfrocca (gmail: blackhedd)
|
4
4
|
# Homepage:: http://rubyeventmachine.com
|
@@ -43,6 +43,9 @@ class TestLineAndTextProtocol < Test::Unit::TestCase
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def test_simple_lines
|
46
|
+
# THIS TEST CURRENTLY FAILS IN JRUBY.
|
47
|
+
assert( RUBY_PLATFORM !~ /java/ )
|
48
|
+
|
46
49
|
lines_received = []
|
47
50
|
Thread.abort_on_exception = true
|
48
51
|
EventMachine.run {
|
@@ -72,6 +75,9 @@ class TestLineAndTextProtocol < Test::Unit::TestCase
|
|
72
75
|
end
|
73
76
|
|
74
77
|
def test_overlength_lines
|
78
|
+
# THIS TEST CURRENTLY FAILS IN JRUBY.
|
79
|
+
assert( RUBY_PLATFORM !~ /java/ )
|
80
|
+
|
75
81
|
lines_received = []
|
76
82
|
Thread.abort_on_exception = true
|
77
83
|
EventMachine.run {
|
data/tests/test_ltp2.rb
ADDED
@@ -0,0 +1,260 @@
|
|
1
|
+
# $Id: test_ltp2.rb 486 2007-07-29 17:15:12Z blackhedd $
|
2
|
+
#
|
3
|
+
# Author:: Francis Cianfrocca (gmail: blackhedd)
|
4
|
+
# Homepage:: http://rubyeventmachine.com
|
5
|
+
# Date:: 8 April 2006
|
6
|
+
#
|
7
|
+
# See EventMachine and EventMachine::Connection for documentation and
|
8
|
+
# usage examples.
|
9
|
+
#
|
10
|
+
#----------------------------------------------------------------------------
|
11
|
+
#
|
12
|
+
# Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
|
13
|
+
# Gmail: blackhedd
|
14
|
+
#
|
15
|
+
# This program is free software; you can redistribute it and/or modify
|
16
|
+
# it under the terms of either: 1) the GNU General Public License
|
17
|
+
# as published by the Free Software Foundation; either version 2 of the
|
18
|
+
# License, or (at your option) any later version; or 2) Ruby's License.
|
19
|
+
#
|
20
|
+
# See the file COPYING for complete licensing information.
|
21
|
+
#
|
22
|
+
#---------------------------------------------------------------------------
|
23
|
+
#
|
24
|
+
#
|
25
|
+
#
|
26
|
+
#
|
27
|
+
|
28
|
+
$:.unshift "../lib"
|
29
|
+
require 'eventmachine'
|
30
|
+
|
31
|
+
# TODO!!! Need tests for overlength headers and text bodies.
|
32
|
+
|
33
|
+
class TestLineText2 < Test::Unit::TestCase
|
34
|
+
|
35
|
+
# Run each of these tests two ways: passing in the whole test-dataset in one chunk,
|
36
|
+
# and passing it in one character at a time.
|
37
|
+
|
38
|
+
class Basic
|
39
|
+
include EM::Protocols::LineText2
|
40
|
+
attr_reader :lines
|
41
|
+
def receive_line line
|
42
|
+
(@lines ||= []) << line
|
43
|
+
end
|
44
|
+
end
|
45
|
+
def test_basic
|
46
|
+
testdata = "Line 1\nLine 2\r\nLine 3\n"
|
47
|
+
|
48
|
+
a = Basic.new
|
49
|
+
a.receive_data testdata
|
50
|
+
assert_equal( ["Line 1", "Line 2", "Line 3"], a.lines )
|
51
|
+
|
52
|
+
a = Basic.new
|
53
|
+
testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) }
|
54
|
+
assert_equal( ["Line 1", "Line 2", "Line 3"], a.lines )
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
class ChangeDelimiter
|
59
|
+
include EM::Protocols::LineText2
|
60
|
+
attr_reader :lines
|
61
|
+
def initialize *args
|
62
|
+
super
|
63
|
+
@delim = "A"
|
64
|
+
set_delimiter @delim
|
65
|
+
end
|
66
|
+
def receive_line line
|
67
|
+
(@lines ||= []) << line
|
68
|
+
set_delimiter( @delim.succ! )
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_change_delimiter
|
73
|
+
testdata = %Q(LineaALinebBLinecCLinedD)
|
74
|
+
|
75
|
+
a = ChangeDelimiter.new
|
76
|
+
a.receive_data testdata
|
77
|
+
assert_equal( ["Linea", "Lineb", "Linec", "Lined"], a.lines )
|
78
|
+
|
79
|
+
a = ChangeDelimiter.new
|
80
|
+
testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) }
|
81
|
+
assert_equal( ["Linea", "Lineb", "Linec", "Lined"], a.lines )
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
#--
|
86
|
+
# Test two lines followed by an empty line, ten bytes of binary data, then
|
87
|
+
# two more lines.
|
88
|
+
|
89
|
+
class Binary
|
90
|
+
include EM::Protocols::LineText2
|
91
|
+
attr_reader :lines, :body
|
92
|
+
def initialize *args
|
93
|
+
super
|
94
|
+
@lines = []
|
95
|
+
@body = nil
|
96
|
+
end
|
97
|
+
def receive_line ln
|
98
|
+
if ln == ""
|
99
|
+
set_text_mode 10
|
100
|
+
else
|
101
|
+
@lines << ln
|
102
|
+
end
|
103
|
+
end
|
104
|
+
def receive_binary_data data
|
105
|
+
@body = data
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_binary
|
110
|
+
testdata = %Q(Line 1
|
111
|
+
Line 2
|
112
|
+
|
113
|
+
0000000000Line 3
|
114
|
+
Line 4
|
115
|
+
)
|
116
|
+
|
117
|
+
a = Binary.new
|
118
|
+
a.receive_data testdata
|
119
|
+
assert_equal( ["Line 1", "Line 2", "Line 3", "Line 4"], a.lines)
|
120
|
+
assert_equal( "0000000000", a.body )
|
121
|
+
|
122
|
+
a = Binary.new
|
123
|
+
testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) }
|
124
|
+
assert_equal( ["Line 1", "Line 2", "Line 3", "Line 4"], a.lines)
|
125
|
+
assert_equal( "0000000000", a.body )
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
# Test unsized binary data. The expectation is that each chunk of it
|
130
|
+
# will be passed to us as it it received.
|
131
|
+
class UnsizedBinary
|
132
|
+
include EM::Protocols::LineText2
|
133
|
+
attr_reader :n_calls, :body
|
134
|
+
def initialize *args
|
135
|
+
super
|
136
|
+
set_text_mode
|
137
|
+
end
|
138
|
+
def receive_binary_data data
|
139
|
+
@n_calls ||= 0
|
140
|
+
@n_calls += 1
|
141
|
+
(@body ||= "") << data
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_unsized_binary
|
146
|
+
testdata = "X\0" * 1000
|
147
|
+
|
148
|
+
a = UnsizedBinary.new
|
149
|
+
a.receive_data testdata
|
150
|
+
assert_equal( 1, a.n_calls )
|
151
|
+
assert_equal( testdata, a.body )
|
152
|
+
|
153
|
+
a = UnsizedBinary.new
|
154
|
+
testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) }
|
155
|
+
assert_equal( 2000, a.n_calls )
|
156
|
+
assert_equal( testdata, a.body )
|
157
|
+
end
|
158
|
+
|
159
|
+
|
160
|
+
# Test binary data with a "throw back" into line-mode.
|
161
|
+
class ThrowBack
|
162
|
+
include EM::Protocols::LineText2
|
163
|
+
attr_reader :headers
|
164
|
+
def initialize *args
|
165
|
+
super
|
166
|
+
@headers = []
|
167
|
+
@n_bytes = 0
|
168
|
+
set_text_mode
|
169
|
+
end
|
170
|
+
def receive_binary_data data
|
171
|
+
wanted = 25 - @n_bytes
|
172
|
+
will_take = if data.length > wanted
|
173
|
+
data.length - wanted
|
174
|
+
else
|
175
|
+
data.length
|
176
|
+
end
|
177
|
+
@n_bytes += will_take
|
178
|
+
|
179
|
+
if @n_bytes == 25
|
180
|
+
set_line_mode( data[will_take..-1] )
|
181
|
+
end
|
182
|
+
end
|
183
|
+
def receive_line ln
|
184
|
+
@headers << ln
|
185
|
+
end
|
186
|
+
end
|
187
|
+
def test_throw_back
|
188
|
+
testdata = "Line\n" * 10
|
189
|
+
|
190
|
+
a = ThrowBack.new
|
191
|
+
a.receive_data testdata
|
192
|
+
assert_equal( ["Line"] * 5, a.headers )
|
193
|
+
|
194
|
+
a = ThrowBack.new
|
195
|
+
testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) }
|
196
|
+
assert_equal( ["Line"] * 5, a.headers )
|
197
|
+
end
|
198
|
+
|
199
|
+
# Test multi-character line delimiters.
|
200
|
+
# Also note that the test data has a "tail" with no delimiter, that will be
|
201
|
+
# discarded, but cf. the BinaryTail test.
|
202
|
+
# TODO!!! This test doesn't work in the byte-by-byte case.
|
203
|
+
class Multichar
|
204
|
+
include EM::Protocols::LineText2
|
205
|
+
attr_reader :lines
|
206
|
+
def initialize *args
|
207
|
+
super
|
208
|
+
@lines = []
|
209
|
+
set_delimiter "012"
|
210
|
+
end
|
211
|
+
def receive_line ln
|
212
|
+
@lines << ln
|
213
|
+
end
|
214
|
+
end
|
215
|
+
def test_multichar
|
216
|
+
testdata = "Line012Line012Line012Line"
|
217
|
+
|
218
|
+
a = Multichar.new
|
219
|
+
a.receive_data testdata
|
220
|
+
assert_equal( ["Line"]*3, a.lines )
|
221
|
+
|
222
|
+
a = Multichar.new
|
223
|
+
testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) }
|
224
|
+
# DOESN'T WORK in this case. Multi-character delimiters are broken.
|
225
|
+
#assert_equal( ["Line"]*3, a.lines )
|
226
|
+
end
|
227
|
+
|
228
|
+
# Test a binary "tail," when a sized binary transfer doesn't complete because
|
229
|
+
# of an unbind. We get a partial result.
|
230
|
+
class BinaryTail
|
231
|
+
include EM::Protocols::LineText2
|
232
|
+
attr_reader :data
|
233
|
+
def initialize *args
|
234
|
+
super
|
235
|
+
@data = ""
|
236
|
+
set_text_mode 1000
|
237
|
+
end
|
238
|
+
def receive_binary_data data
|
239
|
+
# we expect to get all the data in one chunk, even in the byte-by-byte case,
|
240
|
+
# because sized transfers by definition give us exactly one call to
|
241
|
+
# #receive_binary_data.
|
242
|
+
@data = data
|
243
|
+
end
|
244
|
+
end
|
245
|
+
def test_binary_tail
|
246
|
+
testdata = "0" * 500
|
247
|
+
|
248
|
+
a = BinaryTail.new
|
249
|
+
a.receive_data testdata
|
250
|
+
a.unbind
|
251
|
+
assert_equal( "0" * 500, a.data )
|
252
|
+
|
253
|
+
a = BinaryTail.new
|
254
|
+
testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) }
|
255
|
+
a.unbind
|
256
|
+
assert_equal( "0" * 500, a.data )
|
257
|
+
end
|
258
|
+
|
259
|
+
end
|
260
|
+
|