mongrel2 0.51.0 → 0.52.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 8df9f187481c62410559366443e0a498a75858cc
4
- data.tar.gz: d0b13dcd1f94d0835230fd2998c73aed4fbce747
2
+ SHA256:
3
+ metadata.gz: 2ed8340c773b16f74e9fdfba40baf608f96c13726fc7cdbe4649c414dcb489fc
4
+ data.tar.gz: 8079493638f14d5e7158687c9e6b0643934821ebb98af1be174704ae833d4cad
5
5
  SHA512:
6
- metadata.gz: 3a4149170b70e911f33b9e743d806138b1a48523298956c733cbc264cfb1cd0e20da45aae8985e302e1ef6648fd46f7c8f655894f338205e31c6e9777f22cdd8
7
- data.tar.gz: fa5ca2d024561d07898f15e2da168e2db884722780a75231998d9269ac990a63279dfa00e4055f870bb72e39ff0a5981ffe0d828611575b602ea86a1dec71b45
6
+ metadata.gz: 5f9a258f6eeda490594c2601d9b8f8e4b11473f69dc0cffd4cfb324c4c49f62db8b9d26d8c55153895259fbd773bce0547070613ca931f491efcd055960c3b5c
7
+ data.tar.gz: 899fddeca183837af436fd89aafbf5bfcf9a64a79f2ae51ba25e0c039a2089bd9b115f7a4add96190596c9cb1e70e46e125e2d166cfaf609ba8c559453429599
Binary file
data.tar.gz.sig CHANGED
Binary file
data/ChangeLog CHANGED
@@ -1,8 +1,99 @@
1
+ 2018-07-21 Michael Granger <ged@FaerieMUD.org>
2
+
3
+ * .gems, Rakefile, lib/mongrel2/handler.rb, lib/mongrel2/websocket.rb,
4
+ mongrel2.gemspec, spec/helpers.rb, spec/mongrel2/connection_spec.rb,
5
+ spec/mongrel2/handler_spec.rb:
6
+ Refactor IO code to use cztop-reactor
7
+ [d266df105426] [tip]
8
+
9
+ 2018-05-31 Mahlon E. Smith <mahlon@martini.nu>
10
+
11
+ * lib/mongrel2/constants.rb:
12
+ Update for changes to gem upstream.
13
+ [667013d5334c]
14
+
15
+ 2017-11-15 Michael Granger <ged@FaerieMUD.org>
16
+
17
+ * .hgtags:
18
+ Added tag v0.51.0 for changeset 89afed83e6e2
19
+ [1a6fcd8e3a52]
20
+
21
+ * .hgsigs:
22
+ Added signature for changeset 5c042cae7457
23
+ [89afed83e6e2] [v0.51.0]
24
+
25
+ * cert/ged.pem, certs/ged.pem:
26
+ Fix the name of and update my gem-signing cert
27
+ [5c042cae7457]
28
+
29
+ * History.rdoc, lib/mongrel2.rb:
30
+ Bump the minor version, update history.
31
+ [1a66a960918d]
32
+
33
+ * Rakefile, mongrel2.gemspec:
34
+ Update libxml-ruby dep to the latest
35
+ [9253c00b0a2f]
36
+
37
+ 2017-11-08 Michael Granger <ged@FaerieMUD.org>
38
+
39
+ * mongrel2.gemspec:
40
+ Update the gemspec
41
+ [f1817db64b7b]
42
+
43
+ * Manifest.txt:
44
+ Update the manifest
45
+ [f69cd800ac94]
46
+
47
+ * .ruby-version, .tm_properties, Rakefile, lib/mongrel2/config.rb,
48
+ lib/mongrel2/constants.rb, mongrel2.gemspec:
49
+ Support Sequel 5
50
+ [56a2daf04013]
51
+
52
+ * data/mongrel2/config.rb.in:
53
+ Add config input file
54
+ [19ce3acb3839]
55
+
56
+ 2017-07-05 Michael Granger <ged@FaerieMUD.org>
57
+
58
+ * .hgtags:
59
+ Added tag v0.50.2 for changeset 08baa3b61eea
60
+ [79f113fd0f93]
61
+
62
+ * .hgsigs:
63
+ Added signature for changeset 99ce0d32ae15
64
+ [08baa3b61eea] [v0.50.2]
65
+
66
+ * History.rdoc, lib/mongrel2.rb:
67
+ Bump the patch version, update history.
68
+ [99ce0d32ae15]
69
+
70
+ * lib/mongrel2/handler.rb:
71
+ Add missing require to Strelka::Handler.
72
+ [6ad07a7a7775]
73
+
74
+ 2017-05-31 Michael Granger <ged@FaerieMUD.org>
75
+
76
+ * .hgtags:
77
+ Added tag v0.50.1 for changeset 181a78ed2587
78
+ [af48c723c110]
79
+
80
+ * .hgsigs:
81
+ Added signature for changeset d7b71efe6141
82
+ [181a78ed2587] [v0.50.1]
83
+
84
+ * History.rdoc, lib/mongrel2.rb:
85
+ Bump the patch version, update history.
86
+ [d7b71efe6141]
87
+
88
+ * Rakefile, mongrel2.gemspec:
89
+ Pin Sequel to 4.45 to avoid breaking changes.
90
+ [e12627bad969]
91
+
1
92
  2017-05-31 Mahlon E. Smith <mahlon@martini.nu>
2
93
 
3
94
  * lib/mongrel2/handler.rb, spec/mongrel2/handler_spec.rb:
4
95
  Randomize the inproc selfpipe socket name.
5
- [6beef2396fd4] [github/master, tip]
96
+ [6beef2396fd4]
6
97
 
7
98
  2017-05-31 Mahlon E. Smith <mahlon@laika.com>
8
99
 
@@ -1,3 +1,11 @@
1
+ == v0.52.0 [2018-07-21] Michael Granger <ged@FaerieMUD.org>
2
+
3
+ Enhancements:
4
+
5
+ - Refactor IO code to use cztop-reactor
6
+ - Fix use of Gem.datadir for newer Rubygems.
7
+
8
+
1
9
  == v0.51.0 [2017-11-15] Michael Granger <ged@FaerieMUD.org>
2
10
 
3
11
  Enhancements:
data/Rakefile CHANGED
@@ -26,6 +26,7 @@ hoespec = Hoe.spec 'mongrel2' do
26
26
  self.developer 'Michael Granger', 'ged@FaerieMUD.org'
27
27
 
28
28
  self.dependency 'cztop', '~> 0.11'
29
+ self.dependency 'cztop-reactor', '~> 0.3'
29
30
  self.dependency 'libxml-ruby', '~> 3.0'
30
31
  self.dependency 'loggability', '~> 0.12'
31
32
  self.dependency 'sequel', '~> 5.2'
@@ -22,10 +22,10 @@ module Mongrel2
22
22
  abort "\n\n>>> Mongrel2 requires Ruby 2.2 or later. <<<\n\n" if RUBY_VERSION < '2.2.0'
23
23
 
24
24
  # Library version constant
25
- VERSION = '0.51.0'
25
+ VERSION = '0.52.0'
26
26
 
27
27
  # Version-control revision constant
28
- REVISION = %q$Revision: 1a66a960918d $
28
+ REVISION = %q$Revision: aa458f3f9ca9 $
29
29
 
30
30
 
31
31
  require 'mongrel2/constants'
@@ -11,8 +11,8 @@ module Mongrel2::Constants
11
11
  # The Pathname of the data directory
12
12
  DATA_DIR = if ENV['MONGREL2_DATADIR']
13
13
  Pathname( ENV['MONGREL2_DATADIR'] )
14
- elsif Gem.datadir( 'mongrel2' ) && File.directory?( Gem.datadir('mongrel2') )
15
- Pathname( Gem.datadir('mongrel2') )
14
+ elsif Gem.loaded_specs[ 'mongrel2' ] && File.exist?( Gem.loaded_specs['mongrel2'].datadir )
15
+ Pathname( Gem.loaded_specs['mongrel2'].datadir )
16
16
  else
17
17
  Pathname( __FILE__ ).dirname.parent.parent + 'data/mongrel2'
18
18
  end
@@ -2,6 +2,8 @@
2
2
  #encoding: utf-8
3
3
 
4
4
  require 'cztop'
5
+ require 'cztop/reactor'
6
+ require 'cztop/reactor/signal_handling'
5
7
  require 'securerandom'
6
8
  require 'loggability'
7
9
 
@@ -85,7 +87,8 @@ require 'mongrel2/websocket'
85
87
  #
86
88
  class Mongrel2::Handler
87
89
  extend Loggability
88
- include Mongrel2::Constants
90
+ include Mongrel2::Constants,
91
+ CZTop::Reactor::SignalHandling
89
92
 
90
93
 
91
94
  # Loggability API -- set up logging under the 'mongrel2' log host
@@ -96,7 +99,7 @@ class Mongrel2::Handler
96
99
  QUEUE_SIGS = [
97
100
  :INT, :TERM, :HUP, :USR1,
98
101
  # :TODO: :QUIT, :WINCH, :USR2, :TTIN, :TTOU
99
- ]
102
+ ] & Signal.list.keys.map( &:to_sym )
100
103
 
101
104
 
102
105
  ### Create an instance of the handler using the config from the database with
@@ -136,14 +139,12 @@ class Mongrel2::Handler
136
139
  ### Create a new instance of the handler with the specified +app_id+, +send_spec+,
137
140
  ### and +recv_spec+.
138
141
  def initialize( app_id, send_spec, recv_spec ) # :notnew:
142
+ super() # To the signal handler mixin
143
+
139
144
  @app_id = app_id
140
145
 
141
146
  @conn = Mongrel2::Connection.new( app_id, send_spec, recv_spec )
142
-
143
- @self_pipe = nil
144
- @poller = nil
145
-
146
- Thread.main[:signal_queue] = []
147
+ @reactor = CZTop::Reactor.new
147
148
  end
148
149
 
149
150
 
@@ -151,31 +152,30 @@ class Mongrel2::Handler
151
152
  public
152
153
  ######
153
154
 
155
+ ##
154
156
  # The handler's Mongrel2::Connection object.
155
157
  attr_reader :conn
156
158
 
159
+ ##
157
160
  # The app ID the app was created with
158
161
  attr_reader :app_id
159
162
 
163
+ ##
164
+ # The CZTop::Reactor that manages IO
165
+ attr_reader :reactor
166
+
160
167
 
161
168
  ### Run the handler.
162
169
  def run
163
170
  self.log.info "Starting up %p" % [ self ]
164
171
 
165
- rand_id = "%d-%s" % [ Process.pid, SecureRandom.hex(8) ]
166
- @self_pipe = {
167
- reader: CZTop::Socket::PAIR.new( "@inproc://signal-handler-#{rand_id}" ),
168
- writer: CZTop::Socket::PAIR.new( ">inproc://signal-handler-#{rand_id}" )
169
- }
170
-
171
- @poller = CZTop::Poller.new( @conn.request_sock, @self_pipe[:reader] )
172
-
173
- self.set_signal_handlers
174
- self.start_accepting_requests
172
+ self.reactor.register( @conn.request_sock, :read, &self.method(:on_socket_event) )
173
+ self.with_signal_handler( self.reactor, *QUEUE_SIGS ) do
174
+ self.start_accepting_requests
175
+ end
175
176
 
176
177
  return self # For chaining
177
178
  ensure
178
- self.restore_signal_handlers
179
179
  self.log.info "Done: %p" % [ self ]
180
180
  @conn.close if @conn
181
181
  end
@@ -224,7 +224,7 @@ class Mongrel2::Handler
224
224
  ### Shut down the handler.
225
225
  def shutdown
226
226
  self.log.info "Shutting down."
227
- self.ignore_signals
227
+ self.reactor.stop_polling
228
228
  @conn.close
229
229
  end
230
230
 
@@ -234,9 +234,9 @@ class Mongrel2::Handler
234
234
  def restart
235
235
  self.log.info "Restarting"
236
236
  if (( old_conn = @conn ))
237
+ self.reactor.unregister( old_conn.request_sock )
237
238
  @conn = @conn.dup
238
-
239
- @poller = CZTop::Poller.new( @conn.request_sock, @self_pipe[:reader] )
239
+ self.reactor.register( @conn.request_sock, :read, &self.method(:on_socket_event) )
240
240
 
241
241
  self.log.debug " conn %p -> %p" % [ old_conn, @conn ]
242
242
  old_conn.close
@@ -247,28 +247,20 @@ class Mongrel2::Handler
247
247
  ### Start a loop, accepting a request and handling it.
248
248
  def start_accepting_requests
249
249
  self.log.info "Starting the request loop."
250
- until @conn.closed?
251
- begin
252
- if event = @poller.wait
253
- case event.socket
254
- when @conn.request_sock
255
- req = @conn.receive
256
- self.accept_request( req ) unless @conn.closed?
257
- when @self_pipe[:reader]
258
- @self_pipe[:reader].wait
259
- self.process_signal_queue
260
- else
261
- self.log.warn "Got unhandled poller event: %p" % [ event ]
262
- end
263
- end
264
- rescue Errno::EAGAIN
265
- # self.log.debug "Got EAGAIN, retrying."
266
- rescue Interrupt
267
- # self.log.debug "Got an Interrupt; retrying."
268
- end
269
- end
250
+ self.reactor.start_polling( ignore_interrupts: true )
251
+ end
252
+
270
253
 
271
- self.log.debug "Done accepting requests."
254
+ ### Reactor callback -- handle an IO event.
255
+ def on_socket_event( event )
256
+ if event.readable?
257
+ req = self.conn.receive
258
+ self.accept_request( req )
259
+ elsif event.writable?
260
+ raise "Request socket became writable?!"
261
+ else
262
+ raise "Socket event was neither readable nor writable! (%s)" % [ event ]
263
+ end
272
264
  end
273
265
 
274
266
 
@@ -379,9 +371,9 @@ class Mongrel2::Handler
379
371
  def handle_websocket( request )
380
372
  self.log.warn "Unhandled WEBSOCKET frame (%p)" % [ request.headers.path ]
381
373
  res = request.response
382
- res.make_close_frame( WebSocket::CLOSE_POLICY_VIOLATION )
383
- self.conn.reply( res)
374
+ res.make_close_frame( Mongrel2::WebSocket::CLOSE_POLICY_VIOLATION )
384
375
 
376
+ self.conn.reply( res )
385
377
  self.conn.reply_close( request )
386
378
 
387
379
  return nil
@@ -391,8 +383,8 @@ class Mongrel2::Handler
391
383
  ### Handle a WebSocket handshake HTTP +request+. If not overridden, this method drops
392
384
  ### the connection.
393
385
  def handle_websocket_handshake( handshake )
394
- self.log.warn "Unhandled WEBSOCKET_HANDSHAKE request (%p)" % [ request.headers.path ]
395
- self.conn.reply_close( request )
386
+ self.log.warn "Unhandled WEBSOCKET_HANDSHAKE request (%p)" % [ handshake.headers.path ]
387
+ self.conn.reply_close( handshake )
396
388
 
397
389
  return nil
398
390
  end
@@ -401,7 +393,7 @@ class Mongrel2::Handler
401
393
  ### Handle a disconnect notice from Mongrel2 via the given +request+. Its return value
402
394
  ### is ignored.
403
395
  def handle_disconnect( request )
404
- self.log.info "Unhandled disconnect notice."
396
+ self.log.info "Connection %p closed." % [ request.conn_id ]
405
397
  return nil
406
398
  end
407
399
 
@@ -436,57 +428,9 @@ class Mongrel2::Handler
436
428
  # :section: Signal Handling
437
429
  # These methods set up some behavior for starting, restarting, and stopping
438
430
  # your application when a signal is received. If you don't want signals to
439
- # be handled, override #set_signal_handlers with an empty method.
431
+ # be handled, override #handle_signal with an empty method.
440
432
  #
441
433
 
442
- ### Wake up the handler when a signal needs to be processed.
443
- def wake_up
444
- $stderr.puts "Waking up the signal handler"
445
- @self_pipe[ :writer ].signal( 0 )
446
- $stderr.puts "Done sending the wakeup."
447
- end
448
-
449
-
450
- ### Set up signal handlers for common signals that will shut down, restart, etc.
451
- def set_signal_handlers
452
- self.log.debug "Setting up deferred signal handlers."
453
- QUEUE_SIGS.each do |sig|
454
- Signal.trap( sig ) do
455
- Thread.main[:signal_queue] << sig
456
- self.wake_up
457
- $stderr.puts "Done handling the signal."
458
- end
459
- end
460
- end
461
-
462
-
463
- ### Set all signal handlers to ignore.
464
- def ignore_signals
465
- self.log.debug "Ignoring signals."
466
- QUEUE_SIGS.each do |sig|
467
- Signal.trap( sig, :IGNORE )
468
- end
469
- end
470
-
471
-
472
- ### Set the signal handlers back to their defaults.
473
- def restore_signal_handlers
474
- self.log.debug "Restoring default signal handlers."
475
- QUEUE_SIGS.each do |sig|
476
- Signal.trap( sig, :DEFAULT )
477
- end
478
- end
479
-
480
-
481
- ### Handle any queued signals.
482
- def process_signal_queue
483
- # Look for any signals that arrived and handle them
484
- while sig = Thread.main[:signal_queue].shift
485
- self.handle_signal( sig )
486
- end
487
- end
488
-
489
-
490
434
  ### Handle signals.
491
435
  def handle_signal( sig )
492
436
  self.log.debug "Handling signal %s" % [ sig ]
@@ -463,6 +463,13 @@ module Mongrel2::WebSocket
463
463
  end
464
464
 
465
465
 
466
+ ### Set the :close opcode on this frame and set its status to +statuscode+.
467
+ def make_close_frame( statuscode=Mongrel2::WebSocket::CLOSE_NORMAL )
468
+ self.opcode = :close
469
+ self.set_status( statuscode )
470
+ end
471
+
472
+
466
473
  ### Overwrite the frame's payload with a status message based on
467
474
  ### +statuscode+.
468
475
  def set_status( statuscode )
@@ -622,6 +629,12 @@ module Mongrel2::WebSocket
622
629
  end
623
630
 
624
631
 
632
+ ### Compatibility with Mongrel2::Response.
633
+ def extended_reply? # :nodoc:
634
+ return false
635
+ end
636
+
637
+
625
638
  #########
626
639
  protected
627
640
  #########
@@ -91,6 +91,13 @@ module Mongrel2::SpecHelpers
91
91
  end
92
92
 
93
93
 
94
+ ### Make a Mongrel2::Request from the specified +opts+ and return it.
95
+ def make_request_object( opts={} )
96
+ data = make_request( opts )
97
+ return Mongrel2::Request.parse( data )
98
+ end
99
+
100
+
94
101
  ### Make a new-style (TNetstring headers) raw Mongrel2 request from the specified +opts+
95
102
  ### and return it as a String.
96
103
  def make_tn_request( opts={} )
@@ -135,6 +142,13 @@ module Mongrel2::SpecHelpers
135
142
  end
136
143
 
137
144
 
145
+ ### Make a Mongrel2::JSONRequest from the specified +opts+ and return it.
146
+ def make_json_request_object( opts={} )
147
+ data = make_json_request( opts )
148
+ return Mongrel2::Request.parse( data )
149
+ end
150
+
151
+
138
152
  ### Make a Mongrel2 request for an XML route.
139
153
  def make_xml_request( opts={} )
140
154
  opts = TEST_XML_REQUEST_OPTS.merge( opts )
@@ -158,6 +172,13 @@ module Mongrel2::SpecHelpers
158
172
  end
159
173
 
160
174
 
175
+ ### Make a Mongrel2::XMLRequest from the specified +opts+ and return it.
176
+ def make_xml_request_object( opts={} )
177
+ data = make_xml_request( opts )
178
+ return Mongrel2::Request.parse( data )
179
+ end
180
+
181
+
161
182
  ### Make a Mongrel2 handshake request for a WebSocket route.
162
183
  def make_websocket_handshake( opts={} )
163
184
  opts = TEST_WEBSOCKET_REQUEST_OPTS.merge( opts )
@@ -180,6 +201,14 @@ module Mongrel2::SpecHelpers
180
201
  end
181
202
 
182
203
 
204
+ ### Make a Mongrel2::WebSocket::ClientHandshake from the specified +opts+ and
205
+ ### return it.
206
+ def make_websocket_handshake_object( opts={} )
207
+ data = make_websocket_handshake( opts )
208
+ return Mongrel2::Request.parse( data )
209
+ end
210
+
211
+
183
212
  ### Make a Mongrel2 frame for a WebSocket route.
184
213
  def make_websocket_frame( opts={} )
185
214
  opts = TEST_WEBSOCKET_REQUEST_OPTS.merge( opts )
@@ -201,6 +230,13 @@ module Mongrel2::SpecHelpers
201
230
  return data.encode( 'binary' )
202
231
  end
203
232
 
233
+
234
+ ### Make a Mongrel2::WebSocket::Frame from the specified +opts+ and return it.
235
+ def make_websocket_frame_object( opts={} )
236
+ data = make_websocket_frame( opts )
237
+ return Mongrel2::Request.parse( data )
238
+ end
239
+
204
240
  end
205
241
 
206
242
 
@@ -14,9 +14,6 @@ require 'mongrel2/connection'
14
14
  describe Mongrel2::Connection do
15
15
  include Mongrel2::Config::DSL
16
16
 
17
- before( :all ) do
18
- end
19
-
20
17
  # Ensure 0MQ never actually gets called
21
18
  before( :each ) do
22
19
  @conn = Mongrel2::Connection.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC )
@@ -28,6 +25,7 @@ describe Mongrel2::Connection do
28
25
  expect( @conn.instance_variable_get( :@response_sock ) ).to be_nil()
29
26
  end
30
27
 
28
+
31
29
  it "connects to the endpoints specified on demand" do
32
30
  request_sock = double( "request socket", options: OpenStruct.new )
33
31
  response_sock = double( "response socket", options: OpenStruct.new )
@@ -45,10 +43,12 @@ describe Mongrel2::Connection do
45
43
  expect( @conn.response_sock ).to eq( response_sock )
46
44
  end
47
45
 
46
+
48
47
  it "stringifies as a description of the appid and both sockets" do
49
48
  expect( @conn.to_s ).to eq( "{#{TEST_UUID}} #{TEST_SEND_SPEC} <-> #{TEST_RECV_SPEC}" )
50
49
  end
51
50
 
51
+
52
52
  context "after a connection has been established" do
53
53
 
54
54
  before( :each ) do
@@ -69,6 +69,7 @@ describe Mongrel2::Connection do
69
69
  @conn.close
70
70
  end
71
71
 
72
+
72
73
  it "raises an exception if asked to fetch data after being closed" do
73
74
  allow( @request_sock ).to receive( :close )
74
75
  allow( @response_sock ).to receive( :close )
@@ -80,6 +81,7 @@ describe Mongrel2::Connection do
80
81
  }.to raise_error( Mongrel2::ConnectionError, /operation on closed connection/i )
81
82
  end
82
83
 
84
+
83
85
  it "doesn't keep its request and response sockets when duped" do
84
86
  request_sock2 = double( "request socket", :options => OpenStruct.new, :connect => nil )
85
87
  response_sock2 = double( "response socket", :options => OpenStruct.new, :connect => nil )
@@ -92,6 +94,7 @@ describe Mongrel2::Connection do
92
94
  expect( duplicate.response_sock ).to eq( response_sock2 )
93
95
  end
94
96
 
97
+
95
98
  it "doesn't keep its closed state when duped" do
96
99
  expect( @request_sock ).to receive( :close )
97
100
  expect( @response_sock ).to receive( :close )
@@ -102,22 +105,26 @@ describe Mongrel2::Connection do
102
105
  expect( duplicate ).to_not be_closed()
103
106
  end
104
107
 
108
+
105
109
  it "can read raw request messages off of the request_sock" do
106
110
  expect( @request_sock ).to receive( :receive ).and_return( CZTop::Message.new( "the data" ) )
107
111
  expect( @conn.recv ).to eq( "the data" )
108
112
  end
109
113
 
114
+
110
115
  it "can read request messages off of the request_sock as Mongrel2::Request objects" do
111
- msg = make_request()
112
- expect( @request_sock ).to receive( :receive ).and_return( CZTop::Message.new( msg ) )
116
+ req = make_request()
117
+ expect( @request_sock ).to receive( :receive ).and_return( CZTop::Message.new(req) )
113
118
  expect( @conn.receive ).to be_a( Mongrel2::Request )
114
119
  end
115
120
 
121
+
116
122
  it "can write raw response messages with a TNetString header onto the response_sock" do
117
123
  expect( @response_sock ).to receive( :<< ).with( "#{TEST_UUID} 1:8, the data" )
118
124
  @conn.send( TEST_UUID, 8, "the data" )
119
125
  end
120
126
 
127
+
121
128
  it "can write Mongrel2::Responses to the response_sock" do
122
129
  expect( @response_sock ).to receive( :<< ).with( "#{TEST_UUID} 1:8, the data" )
123
130
 
@@ -125,30 +132,35 @@ describe Mongrel2::Connection do
125
132
  @conn.reply( response )
126
133
  end
127
134
 
135
+
128
136
  it "can write raw response messages to more than one conn_id at the same time" do
129
137
  expect( @response_sock ).to receive( :<< ).
130
138
  with( "#{TEST_UUID} 15:8 16 44 45 1833, the data" )
131
139
  @conn.broadcast( TEST_UUID, [8, 16, 44, 45, 1833], 'the data' )
132
140
  end
133
141
 
142
+
134
143
  it "can write raw response messages to more than one conn_id at the same time" do
135
144
  expect( @response_sock ).to receive( :<< ).
136
145
  with( "#{TEST_UUID} 15:8 16 44 45 1833, the data" )
137
146
  @conn.broadcast( TEST_UUID, [8, 16, 44, 45, 1833], 'the data' )
138
147
  end
139
148
 
149
+
140
150
  it "can write an extended response message" do
141
151
  expect( @response_sock ).to receive( :<< ).
142
152
  with( "#{TEST_UUID} 3:X 8, 27:8:sendfile,12:the_data.txt,]" )
143
153
  @conn.send_extended( TEST_UUID, 8, :sendfile, "the_data.txt" )
144
154
  end
145
155
 
156
+
146
157
  it "can broadcast an extended response message" do
147
158
  expect( @response_sock ).to receive( :<< ).
148
159
  with( "#{TEST_UUID} 9:X 8 16 32, 27:8:sendfile,12:the_data.txt,]" )
149
160
  @conn.broadcast_extended( TEST_UUID, [8,16,32], :sendfile, "the_data.txt" )
150
161
  end
151
162
 
163
+
152
164
  it "can write a Mongrel2::Response with extended reply" do
153
165
  expect( @response_sock ).to receive( :<< ).
154
166
  with( "#{TEST_UUID} 1:8, " )
@@ -162,6 +174,7 @@ describe Mongrel2::Connection do
162
174
  @conn.reply( response )
163
175
  end
164
176
 
177
+
165
178
  it "can tell the connection a request or a response was from to close" do
166
179
  expect( @response_sock ).to receive( :<< ).with( "#{TEST_UUID} 1:8, " )
167
180
 
@@ -169,6 +182,7 @@ describe Mongrel2::Connection do
169
182
  @conn.reply_close( response )
170
183
  end
171
184
 
185
+
172
186
  it "can broadcast a close to multiple connection IDs" do
173
187
  expect( @response_sock ).to receive( :<< ).with( "#{TEST_UUID} 15:8 16 44 45 1833, " )
174
188
  @conn.broadcast_close( TEST_UUID, [8, 16, 44, 45, 1833] )
@@ -16,48 +16,9 @@ require 'mongrel2/handler'
16
16
 
17
17
  describe Mongrel2::Handler, :db do
18
18
 
19
- # Make a handler class for testing that only ever handles one request, and
20
- # keeps track of any requests it handles and their responses.
21
- class OneShotHandler < Mongrel2::Handler
22
- def initialize( * )
23
- @transactions = {}
24
- super
25
- end
26
-
27
- attr_reader :transactions
28
-
29
- # Overridden to accept one request and shut down
30
- def dispatch_request( request )
31
- response = super
32
- self.transactions[ request ] = response
33
- self.shutdown
34
- return response
35
- end
36
-
37
- end # class OneShotHandler
38
-
39
-
40
- # Ensure 0MQ never actually gets called
41
- before( :each ) do
42
- @request_sock = instance_double( CZTop::Socket::PULL, :options => OpenStruct.new, :connect => nil, :close => nil )
43
- @response_sock = instance_double( CZTop::Socket::PUB, :options => OpenStruct.new, :connect => nil, :close => nil )
44
- @selfpipe_reader = instance_double( CZTop::Socket::PAIR )
45
- @selfpipe_writer = instance_double( CZTop::Socket::PAIR )
46
- @poller = instance_double( CZTop::Poller )
47
- @poller_event = instance_double( CZTop::Poller::Event )
48
-
49
- allow( CZTop::Socket::PULL ).to receive( :new ).and_return( @request_sock )
50
- allow( CZTop::Socket::PUB ).to receive( :new ).and_return( @response_sock )
51
- allow( CZTop::Socket::PAIR ).to receive( :new ).with( %r|@inproc://signal-handler-\d+-\w{8}| ).
52
- and_return( @selfpipe_reader )
53
- allow( CZTop::Socket::PAIR ).to receive( :new ).with( %r|>inproc://signal-handler-\d+-\w{8}| ).
54
- and_return( @selfpipe_writer )
55
- allow( CZTop::Poller ).to receive( :new ).and_return( @poller )
56
-
57
- allow( @poller ).to receive( :wait ).and_return( @poller_event )
58
- allow( @poller_event ).to receive( :socket ).and_return( @request_sock )
59
- end
60
-
19
+ # Make a handler class for testing
20
+ class TestingHandler < Mongrel2::Handler
21
+ end # class TestingHandler
61
22
 
62
23
 
63
24
  context "with a Handler entry in the config database" do
@@ -85,30 +46,34 @@ describe Mongrel2::Handler, :db do
85
46
  end
86
47
 
87
48
 
88
- it "has a convenience method for instantiating and running a Handler given an " +
89
- "application ID" do
49
+ it "has a convenience method for instantiating and running a Handler given an application ID" do
50
+ reactor = instance_double( CZTop::Reactor )
51
+ expect( CZTop::Reactor ).to receive( :new ).and_return( reactor )
52
+ expect( reactor ).to receive( :register ).at_least( :once )
53
+ expect( reactor ).to receive( :unregister ).at_least( :once )
54
+ expect( reactor ).to receive( :start_polling ).with( ignore_interrupts: true )
90
55
 
91
- req = make_request()
92
- expect( @request_sock ).to receive( :receive ).and_return( CZTop::Message.new( req ) )
93
-
94
- res = OneShotHandler.run( TEST_UUID )
56
+ handler = TestingHandler.run( TEST_UUID )
95
57
 
96
58
  # It should have pulled its connection info from the Handler entry in the database
97
- expect( res.conn.app_id ).to eq( TEST_UUID )
98
- expect( res.conn.sub_addr ).to eq( TEST_SEND_SPEC )
99
- expect( res.conn.pub_addr ).to eq( TEST_RECV_SPEC )
59
+ expect( handler.conn.app_id ).to eq( TEST_UUID )
60
+ expect( handler.conn.sub_addr ).to eq( TEST_SEND_SPEC )
61
+ expect( handler.conn.pub_addr ).to eq( TEST_RECV_SPEC )
100
62
  end
101
63
 
102
64
 
103
- it "knows what handler config corresponds to its" do
104
- req = make_request()
105
- expect( @request_sock ).to receive( :receive ).and_return( CZTop::Message.new( req ) )
65
+ it "knows what handler config corresponds to its app UUID" do
66
+ reactor = instance_double( CZTop::Reactor )
67
+ expect( CZTop::Reactor ).to receive( :new ).and_return( reactor )
68
+ expect( reactor ).to receive( :register ).at_least( :once )
69
+ expect( reactor ).to receive( :unregister ).at_least( :once )
70
+ expect( reactor ).to receive( :start_polling ).with( ignore_interrupts: true )
106
71
 
107
- res = OneShotHandler.run( TEST_UUID )
72
+ handler = TestingHandler.run( TEST_UUID )
108
73
 
109
- expect( res.handler_config ).to be_a( Mongrel2::Config::Handler )
110
- expect( res.handler_config.send_spec ).to eq( TEST_SEND_SPEC )
111
- expect( res.handler_config.recv_spec ).to eq( TEST_RECV_SPEC )
74
+ expect( handler.handler_config ).to be_a( Mongrel2::Config::Handler )
75
+ expect( handler.handler_config.send_spec ).to eq( TEST_SEND_SPEC )
76
+ expect( handler.handler_config.recv_spec ).to eq( TEST_RECV_SPEC )
112
77
  end
113
78
 
114
79
  end
@@ -130,194 +95,189 @@ describe Mongrel2::Handler, :db do
130
95
  end
131
96
 
132
97
 
133
- it "dispatches HTTP requests to the #handle method" do
134
- req = make_request()
135
- expect( @request_sock ).to receive( :receive ).and_return( CZTop::Message.new( req ) )
98
+ it "responds to HTTP requests with a 204 No Content response by default" do
99
+ request = make_request_object()
100
+ handler = TestingHandler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC )
136
101
 
137
- res = OneShotHandler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC ).run
102
+ response = handler.dispatch_request( request )
138
103
 
139
- expect( res.transactions.size ).to eq( 1 )
140
- request, response = res.transactions.first
141
- expect( request ).to be_a( Mongrel2::HTTPRequest )
142
104
  expect( response ).to be_a( Mongrel2::HTTPResponse )
143
105
  expect( response.status ).to eq( 204 )
144
106
  end
145
107
 
146
108
 
147
109
  it "ignores JSON messages by default" do
148
- req = make_json_request()
149
- expect( @request_sock ).to receive( :receive ).and_return( CZTop::Message.new( req ) )
110
+ request = make_json_request_object()
111
+ handler = TestingHandler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC )
150
112
 
151
- res = OneShotHandler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC ).run
113
+ response = handler.dispatch_request( request )
152
114
 
153
- expect( res.transactions.size ).to eq( 1 )
154
- request, response = res.transactions.first
155
- expect( request ).to be_a( Mongrel2::JSONRequest )
156
- expect( response ).to be_nil()
115
+ expect( response ).to be_nil
157
116
  end
158
117
 
159
118
 
160
119
  it "dispatches JSON message to the #handle_json method" do
161
- json_handler = Class.new( OneShotHandler ) do
120
+ json_handler_class = Class.new( TestingHandler ) do
162
121
  def handle_json( request )
163
122
  return request.response
164
123
  end
165
124
  end
125
+ request = make_json_request_object()
126
+ handler = json_handler_class.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC )
166
127
 
167
- req = make_json_request()
168
- expect( @request_sock ).to receive( :receive ).and_return( CZTop::Message.new( req ) )
169
-
170
- res = json_handler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC ).run
128
+ response = handler.dispatch_request( request )
171
129
 
172
- expect( res.transactions.size ).to eq( 1 )
173
- request, response = res.transactions.first
174
- expect( request ).to be_a( Mongrel2::JSONRequest )
175
130
  expect( response ).to be_a( Mongrel2::Response )
176
131
  end
177
132
 
178
133
 
179
134
  it "ignores XML messages by default" do
180
- req = make_xml_request()
181
- expect( @request_sock ).to receive( :receive ).and_return( CZTop::Message.new( req ) )
135
+ request = make_xml_request_object()
136
+ handler = TestingHandler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC )
182
137
 
183
- res = OneShotHandler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC ).run
138
+ response = handler.dispatch_request( request )
184
139
 
185
- expect( res.transactions.size ).to eq( 1 )
186
- request, response = res.transactions.first
187
- expect( request ).to be_a( Mongrel2::XMLRequest )
188
- expect( response ).to be_nil()
140
+ expect( response ).to be_nil
189
141
  end
190
142
 
191
143
 
192
144
  it "dispatches XML message to the #handle_xml method" do
193
- xml_handler = Class.new( OneShotHandler ) do
145
+ xml_handler_class = Class.new( TestingHandler ) do
194
146
  def handle_xml( request )
195
147
  return request.response
196
148
  end
197
149
  end
150
+ request = make_xml_request_object()
151
+ handler = xml_handler_class.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC )
198
152
 
199
- req = make_xml_request()
200
- expect( @request_sock ).to receive( :receive ).and_return( CZTop::Message.new( req ) )
201
-
202
- res = xml_handler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC ).run
153
+ response = handler.dispatch_request( request )
203
154
 
204
- expect( res.transactions.size ).to eq( 1 )
205
- request, response = res.transactions.first
206
- expect( request ).to be_a( Mongrel2::XMLRequest )
207
155
  expect( response ).to be_a( Mongrel2::Response )
208
156
  end
209
157
 
210
158
 
159
+ it "drops the connection on websocket opening handshakes by default" do
160
+ request = make_websocket_handshake_object()
161
+ handler = TestingHandler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC )
162
+
163
+ expect( handler.conn ).to receive( :reply_close ).with( request )
164
+
165
+ response = handler.dispatch_request( request )
166
+
167
+ expect( response ).to be_nil
168
+ end
169
+
170
+
211
171
  it "dispatches WebSocket opening handshakes to the #handle_websocket_handshake method" do
212
- ws_handler = Class.new( OneShotHandler ) do
172
+ ws_handler_class = Class.new( TestingHandler ) do
213
173
  def handle_websocket_handshake( handshake )
214
174
  return handshake.response
215
175
  end
216
176
  end
177
+ request = make_websocket_handshake_object()
178
+ handler = ws_handler_class.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC )
217
179
 
218
- req = make_websocket_handshake()
219
- expect( @request_sock ).to receive( :receive ).and_return( CZTop::Message.new( req ) )
180
+ response = handler.dispatch_request( request )
220
181
 
221
- res = ws_handler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC ).run
222
-
223
- expect( res.transactions.size ).to eq( 1 )
224
- request, response = res.transactions.first
225
- expect( request ).to be_a( Mongrel2::WebSocket::ClientHandshake )
226
182
  expect( response ).to be_a( Mongrel2::WebSocket::ServerHandshake )
227
183
  end
228
184
 
229
185
 
230
- it "dispatches WebSocket protocol frames to the #handle_websocket method" do
231
- ws_handler = Class.new( OneShotHandler ) do
232
- def handle_websocket( frame )
233
- return frame.response
234
- end
235
- end
186
+ it "directly closes the connection on websocket frames with a protocol violation by default" do
187
+ request = make_websocket_frame_object()
188
+ handler = TestingHandler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC )
236
189
 
237
- req = make_websocket_frame()
238
- expect( @request_sock ).to receive( :receive ).and_return( CZTop::Message.new( req ) )
190
+ expect( handler.conn ).to receive( :reply_close ).with( request )
191
+ expect( handler.conn ).to receive( :reply ) do |reply|
192
+ expect( reply ).to be_a( Mongrel2::WebSocket::Frame )
193
+ expect( reply.opcode ).to eq( :close )
194
+ reply.payload.rewind
195
+ expect( reply.payload.read ).to start_with( '1008 ' )
196
+ end
239
197
 
240
- res = ws_handler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC ).run
198
+ response = handler.dispatch_request( request )
241
199
 
242
- expect( res.transactions.size ).to eq( 1 )
243
- request, response = res.transactions.first
244
- expect( request ).to be_a( Mongrel2::WebSocket::Frame )
245
- expect( response ).to be_a( Mongrel2::WebSocket::Frame )
200
+ expect( response ).to be_nil
246
201
  end
247
202
 
248
203
 
249
- it "continues when a SocketError is received but the connection remains open" do
250
- pending "Does this still apply?"
251
- req = make_request()
252
-
253
- expect( @request_sock ).to receive( :receive ).and_raise( SocketError.new("Interrupted system call.") )
254
- expect( @request_sock ).to receive( :receive ).and_return( CZTop::Message.new( req ) )
204
+ it "dispatches WebSocket protocol frames to the #handle_websocket method" do
205
+ ws_handler_class = Class.new( TestingHandler ) do
206
+ def handle_websocket( frame )
207
+ return frame.response
208
+ end
209
+ end
210
+ request = make_websocket_frame_object()
211
+ handler = ws_handler_class.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC )
255
212
 
256
- res = OneShotHandler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC ).run
213
+ response = handler.dispatch_request( request )
257
214
 
258
- expect( res.transactions.size ).to eq( 1 )
259
- request, response = res.transactions.first
260
- expect( request ).to be_a( Mongrel2::HTTPRequest )
261
- expect( response ).to be_a( Mongrel2::HTTPResponse )
262
- expect( response.status ).to eq( 204 )
215
+ expect( response ).to be_a( Mongrel2::WebSocket::Frame )
263
216
  end
264
217
 
265
218
 
266
219
  it "ignores disconnect notices by default" do
267
- req = make_json_request( :path => '@*', :body => {'type' => 'disconnect'} )
268
- expect( @request_sock ).to receive( :receive ).and_return( CZTop::Message.new( req ) )
220
+ request = make_json_request_object( :path => '@*', :body => {'type' => 'disconnect'} )
221
+ handler = TestingHandler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC )
269
222
 
270
- res = OneShotHandler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC ).run
223
+ response = handler.dispatch_request( request )
271
224
 
272
- expect( res.transactions.size ).to eq( 1 )
273
- request, response = res.transactions.first
274
- expect( request ).to be_a( Mongrel2::JSONRequest )
275
- expect( response ).to be_nil()
225
+ expect( response ).to be_nil
276
226
  end
277
227
 
278
228
 
279
229
  it "dispatches disconnect notices to the #handle_disconnect method" do
280
- disconnect_handler = Class.new( OneShotHandler ) do
230
+ disconnect_handler_class = Class.new( TestingHandler ) do
231
+ def initialize( * )
232
+ super
233
+ @handled_disconnect = false
234
+ end
235
+
236
+ attr_reader :handled_disconnect
237
+
281
238
  def handle_disconnect( request )
239
+ @handled_disconnect = true
282
240
  self.log.debug "Doing stuff for disconnected connection %d" % [ request.conn_id ]
283
241
  end
284
242
  end
243
+ request = make_json_request_object( :path => '@*', :body => {'type' => 'disconnect'} )
244
+ handler = disconnect_handler_class.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC )
285
245
 
286
- req = make_json_request( :path => '@*', :body => {'type' => 'disconnect'} )
287
- expect( @request_sock ).to receive( :receive ).and_return( CZTop::Message.new( req ) )
288
-
289
- res = disconnect_handler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC ).run
246
+ response = handler.dispatch_request( request )
290
247
 
291
- expect( res.transactions.size ).to eq( 1 )
292
- request, response = res.transactions.first
293
- expect( request ).to be_a( Mongrel2::JSONRequest )
294
- expect( response ).to be_nil()
248
+ expect( response ).to be_nil
249
+ expect( handler.handled_disconnect ).to eq( true )
295
250
  end
296
251
 
297
252
 
298
253
  it "cancels async upload notices by default" do
299
- req = make_request( 'METHOD' => 'POST', :headers => {'x-mongrel2-upload-start' => 'uploadfile.XXX'} )
300
- expect( @request_sock ).to receive( :receive ).and_return( CZTop::Message.new( req ) )
301
- expect( @response_sock ).to receive( :<< ).with( "#{TEST_UUID} 1:8, " )
254
+ request = make_request_object(
255
+ 'METHOD' => 'POST',
256
+ headers: {'x-mongrel2-upload-start' => 'uploadfile.XXX'}
257
+ )
258
+ handler = TestingHandler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC )
259
+ expect( handler.conn ).to receive( :reply_close ).with( request )
302
260
 
303
- res = OneShotHandler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC ).run
261
+ response = handler.dispatch_request( request )
304
262
 
305
- expect( res.transactions.size ).to eq( 1 )
306
- request, response = res.transactions.first
307
- expect( response ).to be_nil()
263
+ expect( response ).to be_nil
308
264
  end
309
265
 
310
266
 
311
267
  it "re-establishes its connection when told to restart" do
312
- res = OneShotHandler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC )
313
- pipe_reader = instance_double( CZTop::Socket::PAIR )
314
- pipe_writer = instance_double( CZTop::Socket::PAIR )
315
- res.instance_variable_set( :@self_pipe, {reader: pipe_reader, writer: pipe_writer} )
268
+ handler = TestingHandler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC )
269
+ original_conn = handler.conn
270
+
271
+ expect( handler.reactor ).to receive( :unregister ).with( original_conn.request_sock )
272
+ expect( handler.reactor ).to receive( :register ) do |request_sock, mode, &callback|
273
+ expect( request_sock ).to be_a( CZTop::Socket )
274
+ expect( request_sock ).to_not equal( original_conn.request_sock )
275
+ expect( mode ).to eq( :read )
276
+ end
316
277
 
317
- original_conn = res.conn
318
- res.restart
278
+ handler.restart
319
279
 
320
- expect( res.conn ).to_not equal( original_conn )
280
+ expect( handler.conn ).to_not equal( original_conn )
321
281
  end
322
282
 
323
283
 
@@ -325,14 +285,18 @@ describe Mongrel2::Handler, :db do
325
285
  spoolfile = Pathname.new( Dir.tmpdir + '/mongrel2.uskd8l1' )
326
286
  spoolfile.write( "Hi!" )
327
287
 
328
- req = make_request( 'METHOD' => 'POST', :headers => {
329
- 'x-mongrel2-upload-start' => spoolfile.basename,
330
- 'x-mongrel2-upload-done' => spoolfile.basename
331
- })
332
- expect( @request_sock ).to receive( :receive ).and_return( CZTop::Message.new( req ) )
288
+ request = make_request_object(
289
+ 'METHOD' => 'POST',
290
+ headers: {
291
+ 'x-mongrel2-upload-start' => spoolfile.basename,
292
+ 'x-mongrel2-upload-done' => spoolfile.basename
293
+ }
294
+ )
295
+ handler = TestingHandler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC )
296
+
297
+ expect( handler.conn ).to receive( :reply ).with( a_kind_of(Mongrel2::Response) )
298
+ response = handler.accept_request( request )
333
299
 
334
- res = OneShotHandler.new( TEST_UUID, TEST_SEND_SPEC, TEST_RECV_SPEC ).run
335
- request, response = res.transactions.first
336
300
  expect( request.body ).to be_closed
337
301
  expect( spoolfile ).to_not exist
338
302
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongrel2
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.51.0
4
+ version: 0.52.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Granger
@@ -35,7 +35,7 @@ cert_chain:
35
35
  X0qdrKi+2aZZ0NGuFj9AItBsVmAvkBGIpX4TEKQp5haEbPpmaqO5nIIhV26PXmyT
36
36
  OMKv6pWsoS81vw5KAGBmfX8nht/Py90DQrbRvakATGI=
37
37
  -----END CERTIFICATE-----
38
- date: 2017-11-15 00:00:00.000000000 Z
38
+ date: 2018-07-21 00:00:00.000000000 Z
39
39
  dependencies:
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: cztop
@@ -51,6 +51,20 @@ dependencies:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
53
  version: '0.11'
54
+ - !ruby/object:Gem::Dependency
55
+ name: cztop-reactor
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '0.3'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '0.3'
54
68
  - !ruby/object:Gem::Dependency
55
69
  name: libxml-ruby
56
70
  requirement: !ruby/object:Gem::Requirement
@@ -399,7 +413,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
399
413
  version: '0'
400
414
  requirements: []
401
415
  rubyforge_project:
402
- rubygems_version: 2.6.13
416
+ rubygems_version: 2.7.7
403
417
  signing_key:
404
418
  specification_version: 4
405
419
  summary: Ruby-Mongrel2 is a complete Ruby connector for Mongrel2[http://mongrel2.org/]
metadata.gz.sig CHANGED
Binary file