mongrel2 0.51.0 → 0.52.0

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.
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