stomp 1.2.4 → 1.2.5

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.
Files changed (56) hide show
  1. data/CHANGELOG.rdoc +11 -0
  2. data/README.rdoc +38 -26
  3. data/Rakefile +3 -0
  4. data/bin/catstomp +34 -34
  5. data/bin/stompcat +36 -36
  6. data/examples/client11_ex1.rb +64 -55
  7. data/examples/client11_putget1.rb +47 -35
  8. data/examples/conn11_ex1.rb +59 -51
  9. data/examples/conn11_ex2.rb +59 -50
  10. data/examples/conn11_hb1.rb +35 -26
  11. data/examples/consumer.rb +25 -12
  12. data/examples/get11conn_ex1.rb +97 -89
  13. data/examples/get11conn_ex2.rb +55 -47
  14. data/examples/logexamp.rb +66 -52
  15. data/examples/logexamp_ssl.rb +66 -52
  16. data/examples/publisher.rb +21 -10
  17. data/examples/put11conn_ex1.rb +35 -24
  18. data/examples/putget11_rh1.rb +66 -56
  19. data/examples/slogger.rb +65 -52
  20. data/examples/ssl_uc1.rb +24 -13
  21. data/examples/ssl_uc1_ciphers.rb +28 -15
  22. data/examples/ssl_uc2.rb +26 -16
  23. data/examples/ssl_uc2_ciphers.rb +31 -18
  24. data/examples/ssl_uc3.rb +25 -14
  25. data/examples/ssl_uc3_ciphers.rb +31 -18
  26. data/examples/ssl_uc4.rb +26 -15
  27. data/examples/ssl_uc4_ciphers.rb +32 -19
  28. data/examples/ssl_ucx_default_ciphers.rb +25 -12
  29. data/examples/stomp11_common.rb +16 -15
  30. data/examples/topic_consumer.rb +23 -10
  31. data/examples/topic_publisher.rb +22 -8
  32. data/lib/client/utils.rb +116 -0
  33. data/lib/connection/heartbeats.rb +173 -0
  34. data/lib/connection/netio.rb +322 -0
  35. data/lib/connection/utf8.rb +294 -0
  36. data/lib/connection/utils.rb +104 -0
  37. data/lib/stomp/client.rb +127 -179
  38. data/lib/stomp/codec.rb +5 -2
  39. data/lib/stomp/connection.rb +109 -865
  40. data/lib/stomp/constants.rb +52 -33
  41. data/lib/stomp/errors.rb +56 -5
  42. data/lib/stomp/ext/hash.rb +4 -0
  43. data/lib/stomp/message.rb +49 -29
  44. data/lib/stomp/sslparams.rb +83 -71
  45. data/lib/stomp/version.rb +3 -1
  46. data/lib/stomp.rb +18 -9
  47. data/stomp.gemspec +58 -3
  48. data/test/test_client.rb +28 -1
  49. data/test/test_codec.rb +8 -2
  50. data/test/test_connection.rb +29 -0
  51. data/test/test_connection1p.rb +31 -16
  52. data/test/test_helper.rb +20 -3
  53. data/test/test_message.rb +8 -3
  54. data/test/test_ssl.rb +10 -4
  55. data/test/tlogger.rb +16 -15
  56. metadata +59 -4
data/examples/logexamp.rb CHANGED
@@ -4,64 +4,78 @@ require 'rubygems'
4
4
  require 'stomp'
5
5
  require 'logger' # for the 'local' logger
6
6
  #
7
- $:.unshift(File.dirname(__FILE__))
7
+ if Kernel.respond_to?(:require_relative)
8
+ require_relative("./slogger")
9
+ else
10
+ $LOAD_PATH << File.dirname(__FILE__)
11
+ require "slogger"
12
+ end
8
13
  #
9
- require 'slogger'
14
+ # == A STOMP::Connection program which uses the callback logging facility.
10
15
  #
11
- # A STOMP::Connection program which uses the callback logging facility.
12
- #
13
- llog = Logger::new(STDOUT)
14
- llog.level = Logger::DEBUG
15
- llog.debug "LE Starting"
16
+ class LoggerExample
17
+ # Initialize.
18
+ def initialize
19
+ end
20
+ # Run example.
21
+ def run
22
+ llog = Logger::new(STDOUT)
23
+ llog.level = Logger::DEBUG
24
+ llog.debug "LE Starting"
16
25
 
17
- # //////////////////////////////////////////////////////////////////////////////
18
- mylog = Slogger::new # The client provided STOMP callback logger
26
+ # //////////////////////////////////////////////////////////////////////////////
27
+ mylog = Slogger::new # The client provided STOMP callback logger
19
28
 
20
- # //////////////////////////////////////////////////////////////////////////////
21
- user = ENV['STOMP_USER'] ? ENV['STOMP_USER'] : 'guest'
22
- password = ENV['STOMP_PASSWORD'] ? ENV['STOMP_PASSWORD'] : 'guest'
23
- host = ENV['STOMP_HOST'] ? ENV['STOMP_HOST'] : 'localhost'
24
- port = ENV['STOMP_PORT'] ? ENV['STOMP_PORT'].to_i : 61613
25
- # //////////////////////////////////////////////////////////////////////////////
26
- # A hash type connect *MUST* be used to enable callback logging.
27
- # //////////////////////////////////////////////////////////////////////////////
28
- hash = { :hosts => [
29
- {:login => user, :passcode => password, :host => 'noonehome', :port => 2525},
30
- {:login => user, :passcode => password, :host => host, :port => port},
31
- ],
32
- :logger => mylog, # This enables callback logging!
33
- :max_reconnect_attempts => 5,
34
- }
29
+ # //////////////////////////////////////////////////////////////////////////////
30
+ user = ENV['STOMP_USER'] ? ENV['STOMP_USER'] : 'guest'
31
+ password = ENV['STOMP_PASSWORD'] ? ENV['STOMP_PASSWORD'] : 'guest'
32
+ host = ENV['STOMP_HOST'] ? ENV['STOMP_HOST'] : 'localhost'
33
+ port = ENV['STOMP_PORT'] ? ENV['STOMP_PORT'].to_i : 61613
34
+ # //////////////////////////////////////////////////////////////////////////////
35
+ # A hash type connect *MUST* be used to enable callback logging.
36
+ # //////////////////////////////////////////////////////////////////////////////
37
+ hash = { :hosts => [
38
+ {:login => user, :passcode => password, :host => 'noonehome', :port => 2525},
39
+ {:login => user, :passcode => password, :host => host, :port => port},
40
+ ],
41
+ :logger => mylog, # This enables callback logging!
42
+ :max_reconnect_attempts => 5,
43
+ }
35
44
 
36
- # //////////////////////////////////////////////////////////////////////////////
37
- # For a Connection:
38
- llog.debug "LE Connection processing starts"
39
- conn = Stomp::Connection.new(hash)
40
- conn.disconnect
41
- # //////////////////////////////////////////////////////////////////////////////
42
- llog.debug "LE Connection processing complete"
45
+ # //////////////////////////////////////////////////////////////////////////////
46
+ # For a Connection:
47
+ llog.debug "LE Connection processing starts"
48
+ conn = Stomp::Connection.new(hash)
49
+ conn.disconnect
50
+ # //////////////////////////////////////////////////////////////////////////////
51
+ llog.debug "LE Connection processing complete"
43
52
 
44
- # //////////////////////////////////////////////////////////////////////////////
45
- # For a Client:
46
- llog.debug "LE Client processing starts"
47
- conn = Stomp::Client.new(hash)
48
- conn.close
49
- # //////////////////////////////////////////////////////////////////////////////
50
- llog.debug "LE Client processing complete"
53
+ # //////////////////////////////////////////////////////////////////////////////
54
+ # For a Client:
55
+ llog.debug "LE Client processing starts"
56
+ conn = Stomp::Client.new(hash)
57
+ conn.close
58
+ # //////////////////////////////////////////////////////////////////////////////
59
+ llog.debug "LE Client processing complete"
51
60
 
52
- # //////////////////////////////////////////////////////////////////////////////
53
- # For a Connection with other calls:
54
- llog.debug "LE Connection Enhanced processing starts"
55
- conn = Stomp::Connection.new(hash)
56
- #
57
- dest = "/queue/loggerq1"
58
- conn.publish dest, "a logger message"
59
- conn.subscribe dest
60
- msg = conn.receive
61
- conn.disconnect
62
- # //////////////////////////////////////////////////////////////////////////////
63
- llog.debug "LE Connection Enhanced processing complete"
61
+ # //////////////////////////////////////////////////////////////////////////////
62
+ # For a Connection with other calls:
63
+ llog.debug "LE Connection Enhanced processing starts"
64
+ conn = Stomp::Connection.new(hash)
65
+ #
66
+ dest = "/queue/loggerq1"
67
+ conn.publish dest, "a logger message"
68
+ conn.subscribe dest
69
+ msg = conn.receive
70
+ conn.disconnect
71
+ # //////////////////////////////////////////////////////////////////////////////
72
+ llog.debug "LE Connection Enhanced processing complete"
73
+
74
+ # //////////////////////////////////////////////////////////////////////////////
75
+ llog.debug "LE Ending"
76
+ end
77
+ end
78
+ e = LoggerExample.new
79
+ e.run
64
80
 
65
- # //////////////////////////////////////////////////////////////////////////////
66
- llog.debug "LE Ending"
67
81
 
@@ -4,64 +4,78 @@ require 'rubygems'
4
4
  require 'stomp'
5
5
  require 'logger' # for the 'local' logger
6
6
  #
7
- $:.unshift(File.dirname(__FILE__))
7
+ if Kernel.respond_to?(:require_relative)
8
+ require_relative("./slogger")
9
+ else
10
+ $LOAD_PATH << File.dirname(__FILE__)
11
+ require "slogger"
12
+ end
8
13
  #
9
- require 'slogger'
14
+ # == A STOMP::Connection program which uses the callback logging facility.
10
15
  #
11
- # A STOMP::Connection program which uses the callback logging facility.
12
- #
13
- llog = Logger::new(STDOUT)
14
- llog.level = Logger::DEBUG
15
- llog.debug "LESSL Starting"
16
+ class SSLLoggerExample
17
+ # Initialize.
18
+ def initialize
19
+ end
20
+ # Run example.
21
+ def run
22
+ llog = Logger::new(STDOUT)
23
+ llog.level = Logger::DEBUG
24
+ llog.debug "LESSL Starting"
16
25
 
17
- # //////////////////////////////////////////////////////////////////////////////
18
- mylog = Slogger::new # The client provided STOMP callback logger
26
+ # //////////////////////////////////////////////////////////////////////////////
27
+ mylog = Slogger::new # The client provided STOMP callback logger
19
28
 
20
- # //////////////////////////////////////////////////////////////////////////////
21
- user = ENV['STOMP_USER'] ? ENV['STOMP_USER'] : 'guest'
22
- password = ENV['STOMP_PASSWORD'] ? ENV['STOMP_PASSWORD'] : 'guest'
23
- host = ENV['STOMP_HOST'] ? ENV['STOMP_HOST'] : 'localhost'
24
- port = ENV['STOMP_PORT'] ? ENV['STOMP_PORT'].to_i : 61612
25
- # //////////////////////////////////////////////////////////////////////////////
26
- # A hash type connect *MUST* be used to enable callback logging.
27
- # //////////////////////////////////////////////////////////////////////////////
28
- hash = { :hosts => [
29
- {:login => user, :passcode => password, :host => host, :port => port,
30
- :ssl => true}, # Or provide your insance of SSLParams instead
31
- ],
32
- :logger => mylog, # This enables callback logging!
33
- :max_reconnect_attempts => 2,
34
- }
29
+ # //////////////////////////////////////////////////////////////////////////////
30
+ user = ENV['STOMP_USER'] ? ENV['STOMP_USER'] : 'guest'
31
+ password = ENV['STOMP_PASSWORD'] ? ENV['STOMP_PASSWORD'] : 'guest'
32
+ host = ENV['STOMP_HOST'] ? ENV['STOMP_HOST'] : 'localhost'
33
+ port = ENV['STOMP_PORT'] ? ENV['STOMP_PORT'].to_i : 61612
34
+ # //////////////////////////////////////////////////////////////////////////////
35
+ # A hash type connect *MUST* be used to enable callback logging.
36
+ # //////////////////////////////////////////////////////////////////////////////
37
+ hash = { :hosts => [
38
+ {:login => user, :passcode => password, :host => host, :port => port,
39
+ :ssl => true}, # Or provide your insance of SSLParams instead
40
+ ],
41
+ :logger => mylog, # This enables callback logging!
42
+ :max_reconnect_attempts => 2,
43
+ }
35
44
 
36
- # //////////////////////////////////////////////////////////////////////////////
37
- # For a Connection:
38
- llog.debug "LESSL Connection processing starts"
39
- conn = Stomp::Connection.new(hash)
40
- conn.disconnect
41
- # //////////////////////////////////////////////////////////////////////////////
42
- llog.debug "LESSL Connection processing complete"
45
+ # //////////////////////////////////////////////////////////////////////////////
46
+ # For a Connection:
47
+ llog.debug "LESSL Connection processing starts"
48
+ conn = Stomp::Connection.new(hash)
49
+ conn.disconnect
50
+ # //////////////////////////////////////////////////////////////////////////////
51
+ llog.debug "LESSL Connection processing complete"
43
52
 
44
- # //////////////////////////////////////////////////////////////////////////////
45
- # For a Client:
46
- llog.debug "LESSL Client processing starts"
47
- conn = Stomp::Client.new(hash)
48
- conn.close
49
- # //////////////////////////////////////////////////////////////////////////////
50
- llog.debug "LESSL Client processing complete"
53
+ # //////////////////////////////////////////////////////////////////////////////
54
+ # For a Client:
55
+ llog.debug "LESSL Client processing starts"
56
+ conn = Stomp::Client.new(hash)
57
+ conn.close
58
+ # //////////////////////////////////////////////////////////////////////////////
59
+ llog.debug "LESSL Client processing complete"
51
60
 
52
- # //////////////////////////////////////////////////////////////////////////////
53
- # For a Connection with other calls:
54
- llog.debug "LESSL Connection Enhanced processing starts"
55
- conn = Stomp::Connection.new(hash)
56
- #
57
- dest = "/queue/loggerq1"
58
- conn.publish dest, "a logger message"
59
- conn.subscribe dest
60
- msg = conn.receive
61
- conn.disconnect
62
- # //////////////////////////////////////////////////////////////////////////////
63
- llog.debug "LESSL Connection Enhanced processing complete"
61
+ # //////////////////////////////////////////////////////////////////////////////
62
+ # For a Connection with other calls:
63
+ llog.debug "LESSL Connection Enhanced processing starts"
64
+ conn = Stomp::Connection.new(hash)
65
+ #
66
+ dest = "/queue/loggerq1"
67
+ conn.publish dest, "a logger message"
68
+ conn.subscribe dest
69
+ msg = conn.receive
70
+ conn.disconnect
71
+ # //////////////////////////////////////////////////////////////////////////////
72
+ llog.debug "LESSL Connection Enhanced processing complete"
64
73
 
65
- # //////////////////////////////////////////////////////////////////////////////
66
- llog.debug "LESSL Ending"
74
+ # //////////////////////////////////////////////////////////////////////////////
75
+ llog.debug "LESSL Ending"
76
+ end
77
+ end
78
+ #
79
+ e = SSLLoggerExample.new
80
+ e.run
67
81
 
@@ -2,18 +2,29 @@
2
2
 
3
3
  require 'rubygems'
4
4
  require 'stomp'
5
+ #
6
+ # == Example message publisher
7
+ #
8
+ class ExamplePublisher
9
+ # Initialize.
10
+ def initialize
11
+ end
12
+ # Run example.
13
+ def run
14
+ client = Stomp::Client.new("failover://(stomp://:@localhost:61613,stomp://:@remotehost:61613)?initialReconnectDelay=5000&randomize=false&useExponentialBackOff=false")
15
+ message = "ronaldo #{ARGV[0]}"
5
16
 
6
- #client = Stomp::Client.new("", "", "localhost", 61613)
7
-
8
- client = Stomp::Client.new("failover://(stomp://:@localhost:61613,stomp://:@remotehost:61613)?initialReconnectDelay=5000&randomize=false&useExponentialBackOff=false")
9
- message = "ronaldo #{ARGV[0]}"
10
-
11
- for i in (1..300)
12
- puts "Sending message"
13
- client.send("/queue/ronaldo", "#{i}: #{message}", {:persistent => true})
14
- puts "(#{Time.now})Message sent: #{i}"
15
- sleep 1
17
+ for i in (1..50)
18
+ puts "Sending message"
19
+ client.publish("/queue/ronaldo", "#{i}: #{message}", {:persistent => true})
20
+ puts "(#{Time.now})Message sent: #{i}"
21
+ sleep 0.2
22
+ end
23
+ end
16
24
  end
25
+ #
26
+ e = ExamplePublisher.new
27
+ e.run
17
28
 
18
29
 
19
30
 
@@ -11,35 +11,46 @@ else
11
11
  require "stomp11_common"
12
12
  end
13
13
  include Stomp11Common
14
+
14
15
  #
15
- # Stomp 1.1 Publish Example
16
- # =========================
16
+ # == Stomp 1.1 Publish Example
17
17
  #
18
18
  # Purpose: to demonstrate sending messages using Stomp 1.1.
19
19
  #
20
- conn = get_connection() # Use helper method to obtain a Stomp#connection
21
- raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
22
- #
23
- # Publishing simple data is as it was with Stomp 1.0.
24
- #
25
- # Note: Stomp 1.1 brokers seem to prefer using '.' as delimiters in queue
26
- # name spaces. Hence, the queue name used here.
27
- #
28
- qname = "/queue/nodea.nodeb.nodec"
29
- data = "message payload"
30
- headers = {}
31
- #
32
- # The 'data' and 'headers' may be omitted, as with Stomp 1.0
33
- #
34
- 1.upto(nmsgs()) do |i|
35
- msg = "#{data}: #{i}"
36
- conn.publish qname, msg , headers
37
- puts "Sent data: #{msg}"
20
+ class Publish11Example1
21
+ # Initialize.
22
+ def initialize
23
+ end
24
+ # Run example.
25
+ def run
26
+ conn = get_connection() # Use helper method to obtain a Stomp#connection
27
+ raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
28
+ #
29
+ # Publishing simple data is as it was with Stomp 1.0.
30
+ #
31
+ # Note: Stomp 1.1 brokers seem to prefer using '.' as delimiters in queue
32
+ # name spaces. Hence, the queue name used here.
33
+ #
34
+ qname = "/queue/nodea.nodeb.nodec"
35
+ data = "message payload"
36
+ headers = {}
37
+ #
38
+ # The 'data' and 'headers' may be omitted, as with Stomp 1.0
39
+ #
40
+ puts "Writing #{nmsgs()} messages."
41
+ 1.upto(nmsgs()) do |i|
42
+ msg = "#{data}: #{i}"
43
+ conn.publish qname, msg , headers
44
+ puts "Sent data: #{msg}"
45
+ end
46
+ #
47
+ # And finally, disconnect.
48
+ #
49
+ conn.disconnect
50
+ end
38
51
  end
39
52
  #
40
- # And finally, disconnect.
41
- #
42
- conn.disconnect
43
-
53
+ e = Publish11Example1.new
54
+ e.run
44
55
 
45
56
 
@@ -12,72 +12,82 @@ else
12
12
  end
13
13
  include Stomp11Common
14
14
  #
15
- # Stomp 1.1 Send/Receive Example - Repeated Headers
16
- # =================================================
15
+ # == Stomp 1.1 Send/Receive Example - Repeated Headers
17
16
  #
18
17
  # Purpose: to demonstrate sending and receiving using Stomp 1.1, and an unusual
19
18
  # aspect of the specification. What is demonstrated here is the use of
20
19
  # 'repeated headers'. Note that brokers MAY support repeated headers as
21
- # demonstrated, but are not required to provide this support. This example
22
- # should run against the Apollo broker. It will *not* currently run against
20
+ # demonstrated, but are not required to provide this support. This example
21
+ # should run against the Apollo broker. It will *not* currently run against
23
22
  # RabbitMQ. YMMV depending on your broker.
24
23
  #
25
24
  # See: http://stomp.github.com/stomp-specification-1.1.html#Repeated_Header_Entries
26
25
  #
27
- conn = get_connection() # Use helper method to obtain a Stomp#connection
28
- raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
29
- #
30
- # The gem supports repeated headers by allowing the 'value' part of a header
31
- # to be an Array instance.
32
- #
33
- # On 'publish', all values in the Array are placed on the wire and sent to the
34
- # broker in order.
35
- #
36
- # On 'receive', if repeated headers are detected, an Array instance is created
37
- # to hold the repeated values. This is presented the the calling client to
38
- # be processed per client requirements.
39
- #
40
- qname = "/queue/nodea.nodeb.nodec"
41
- data = "message payload: #{Time.now.to_f}"
42
- key2_repeats = ["key2val3", "key2val2", "key2val1" ]
43
- headers = {"key1" => "value1", # A normal header
44
- "key2" => key2_repeats, # A repeated header
45
- "key3" => "value3", # Another normal header
46
- }
47
- #
48
- # Ship it.
49
- #
50
- conn.publish qname, data , headers
51
- puts "Sent data: #{data}"
52
- #
53
- # Receive phase.
54
- #
55
- uuid = conn.uuid()
56
- conn.subscribe qname, {"id" => uuid}
57
- received = conn.receive
58
- conn.unsubscribe qname, {"id" => uuid}
59
- #
60
- # Check that we received what we sent.
61
- #
62
- raise "Unexpected payload" unless data == received.body
63
- raise "Missing key" unless received.headers["key2"]
64
- raise "Repeats not present" unless received.headers.has_value?(key2_repeats)
65
- raise "Unexpected repeat values" unless key2_repeats == received.headers["key2"]
66
- #
67
- # Demonstrate how to process repeated headers received by display of those
68
- # received headers for a visual check.
69
- #
70
- received.headers.each_pair do |k,v|
71
- if v.is_a?(Array)
72
- v.each do |e|
73
- puts "#{k}:#{e}"
26
+ class RepeatedHeadersExample
27
+ # Initialize.
28
+ def initialize
29
+ end
30
+ # Run example.
31
+ def run
32
+ conn = get_connection() # Use helper method to obtain a Stomp#connection
33
+ raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
34
+ #
35
+ # The gem supports repeated headers by allowing the 'value' part of a header
36
+ # to be an Array instance.
37
+ #
38
+ # On 'publish', all values in the Array are placed on the wire and sent to the
39
+ # broker in order.
40
+ #
41
+ # On 'receive', if repeated headers are detected, an Array instance is created
42
+ # to hold the repeated values. This is presented the the calling client to
43
+ # be processed per client requirements.
44
+ #
45
+ qname = "/queue/nodea.nodeb.nodec"
46
+ data = "message payload: #{Time.now.to_f}"
47
+ key2_repeats = ["key2val3", "key2val2", "key2val1" ]
48
+ headers = {"key1" => "value1", # A normal header
49
+ "key2" => key2_repeats, # A repeated header
50
+ "key3" => "value3", # Another normal header
51
+ }
52
+ #
53
+ # Ship it.
54
+ #
55
+ conn.publish qname, data , headers
56
+ puts "Sent data: #{data}"
57
+ #
58
+ # Receive phase.
59
+ #
60
+ uuid = conn.uuid()
61
+ conn.subscribe qname, {"id" => uuid}
62
+ received = conn.receive
63
+ conn.unsubscribe qname, {"id" => uuid}
64
+ #
65
+ # Check that we received what we sent.
66
+ #
67
+ raise "Unexpected payload" unless data == received.body
68
+ raise "Missing key" unless received.headers["key2"]
69
+ raise "Repeats not present" unless received.headers.has_value?(key2_repeats)
70
+ raise "Unexpected repeat values" unless key2_repeats == received.headers["key2"]
71
+ #
72
+ # Demonstrate how to process repeated headers received by display of those
73
+ # received headers for a visual check.
74
+ #
75
+ received.headers.each_pair do |k,v|
76
+ if v.is_a?(Array)
77
+ v.each do |e|
78
+ puts "#{k}:#{e}"
79
+ end
80
+ else
81
+ puts "#{k}:#{v}"
82
+ end
74
83
  end
75
- else
76
- puts "#{k}:#{v}"
84
+ #
85
+ # And finally, disconnect.
86
+ #
87
+ conn.disconnect
77
88
  end
78
89
  end
79
90
  #
80
- # And finally, disconnect.
81
- #
82
- conn.disconnect
91
+ e = RepeatedHeadersExample.new
92
+ e.run
83
93