mongrel2 0.0.1

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 (70) hide show
  1. data.tar.gz.sig +0 -0
  2. data/.gemtest +0 -0
  3. data/History.rdoc +4 -0
  4. data/Manifest.txt +66 -0
  5. data/README.rdoc +169 -0
  6. data/Rakefile +77 -0
  7. data/bin/m2sh.rb +600 -0
  8. data/data/mongrel2/bootstrap.html +25 -0
  9. data/data/mongrel2/config.sql +84 -0
  10. data/data/mongrel2/mimetypes.sql +855 -0
  11. data/examples/README.txt +6 -0
  12. data/examples/config.rb +54 -0
  13. data/examples/helloworld-handler.rb +31 -0
  14. data/examples/request-dumper.rb +45 -0
  15. data/examples/request-dumper.tmpl +71 -0
  16. data/examples/run +17 -0
  17. data/lib/mongrel2.rb +62 -0
  18. data/lib/mongrel2/config.rb +212 -0
  19. data/lib/mongrel2/config/directory.rb +78 -0
  20. data/lib/mongrel2/config/dsl.rb +206 -0
  21. data/lib/mongrel2/config/handler.rb +124 -0
  22. data/lib/mongrel2/config/host.rb +88 -0
  23. data/lib/mongrel2/config/log.rb +48 -0
  24. data/lib/mongrel2/config/mimetype.rb +15 -0
  25. data/lib/mongrel2/config/proxy.rb +15 -0
  26. data/lib/mongrel2/config/route.rb +51 -0
  27. data/lib/mongrel2/config/server.rb +58 -0
  28. data/lib/mongrel2/config/setting.rb +15 -0
  29. data/lib/mongrel2/config/statistic.rb +23 -0
  30. data/lib/mongrel2/connection.rb +212 -0
  31. data/lib/mongrel2/constants.rb +159 -0
  32. data/lib/mongrel2/control.rb +165 -0
  33. data/lib/mongrel2/exceptions.rb +59 -0
  34. data/lib/mongrel2/handler.rb +309 -0
  35. data/lib/mongrel2/httprequest.rb +51 -0
  36. data/lib/mongrel2/httpresponse.rb +187 -0
  37. data/lib/mongrel2/jsonrequest.rb +43 -0
  38. data/lib/mongrel2/logging.rb +241 -0
  39. data/lib/mongrel2/mixins.rb +143 -0
  40. data/lib/mongrel2/request.rb +148 -0
  41. data/lib/mongrel2/response.rb +74 -0
  42. data/lib/mongrel2/table.rb +216 -0
  43. data/lib/mongrel2/xmlrequest.rb +36 -0
  44. data/spec/lib/constants.rb +237 -0
  45. data/spec/lib/helpers.rb +246 -0
  46. data/spec/lib/matchers.rb +50 -0
  47. data/spec/mongrel2/config/directory_spec.rb +91 -0
  48. data/spec/mongrel2/config/dsl_spec.rb +218 -0
  49. data/spec/mongrel2/config/handler_spec.rb +118 -0
  50. data/spec/mongrel2/config/host_spec.rb +30 -0
  51. data/spec/mongrel2/config/log_spec.rb +95 -0
  52. data/spec/mongrel2/config/proxy_spec.rb +30 -0
  53. data/spec/mongrel2/config/route_spec.rb +83 -0
  54. data/spec/mongrel2/config/server_spec.rb +84 -0
  55. data/spec/mongrel2/config/setting_spec.rb +30 -0
  56. data/spec/mongrel2/config/statistic_spec.rb +30 -0
  57. data/spec/mongrel2/config_spec.rb +111 -0
  58. data/spec/mongrel2/connection_spec.rb +172 -0
  59. data/spec/mongrel2/constants_spec.rb +32 -0
  60. data/spec/mongrel2/control_spec.rb +192 -0
  61. data/spec/mongrel2/handler_spec.rb +261 -0
  62. data/spec/mongrel2/httpresponse_spec.rb +232 -0
  63. data/spec/mongrel2/logging_spec.rb +76 -0
  64. data/spec/mongrel2/mixins_spec.rb +62 -0
  65. data/spec/mongrel2/request_spec.rb +157 -0
  66. data/spec/mongrel2/response_spec.rb +81 -0
  67. data/spec/mongrel2/table_spec.rb +176 -0
  68. data/spec/mongrel2_spec.rb +34 -0
  69. metadata +294 -0
  70. metadata.gz.sig +0 -0
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'etc'
4
+ require 'socket'
5
+
6
+ require 'mongrel2' unless defined?( Mongrel2 )
7
+ require 'mongrel2/config' unless defined?( Mongrel2::Config )
8
+
9
+ # Mongrel2 configuration Log class
10
+ class Mongrel2::Config::Log < Mongrel2::Config( :log )
11
+
12
+ ### As of Mongrel2/1.7.5:
13
+ # CREATE TABLE log(id INTEGER PRIMARY KEY,
14
+ # who TEXT,
15
+ # what TEXT,
16
+ # location TEXT,
17
+ # happened_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
18
+ # how TEXT,
19
+ # why TEXT);
20
+
21
+ ### Log an entry to the commit log with the given +what+, +why+, +where+, and +how+ values
22
+ ### and return it after it's saved.
23
+ def self::log_action( what, why=nil, where=nil, how=nil )
24
+ where ||= Socket.gethostname
25
+ how ||= File.basename( $0 )
26
+
27
+ who = Etc.getlogin
28
+
29
+ return self.create(
30
+ who: who,
31
+ what: what,
32
+ location: where,
33
+ how: how,
34
+ why: why
35
+ )
36
+ end
37
+
38
+
39
+ # :todo: Correct the happened_at, which is set in UTC, but fetched in localtime.
40
+
41
+
42
+ ### Stringify the log entry and return it.
43
+ def to_s
44
+ # 2011-09-09 19:35:40 [who] @where how: what (why)
45
+ return "%{happened_at} [%{who}] @%{location} %{how}: %{what} (%{why})" % self.values
46
+ end
47
+
48
+ end # class Mongrel2::Config::Log
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'mongrel2' unless defined?( Mongrel2 )
4
+ require 'mongrel2/config' unless defined?( Mongrel2::Config )
5
+
6
+ # Mongrel2 Mimetype configuration class
7
+ class Mongrel2::Config::Mimetype < Mongrel2::Config( :mimetype )
8
+
9
+ ### As of Mongrel2/1.7.5:
10
+ # CREATE TABLE mimetype (id INTEGER PRIMARY KEY,
11
+ # mimetype TEXT,
12
+ # extension TEXT);
13
+
14
+ end # class Mongrel2::Config::Mimetype
15
+
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'mongrel2' unless defined?( Mongrel2 )
4
+ require 'mongrel2/config' unless defined?( Mongrel2::Config )
5
+
6
+ # Mongrel2 Proxy configuration class
7
+ class Mongrel2::Config::Proxy < Mongrel2::Config( :proxy )
8
+
9
+ ### As of Mongrel2/1.7.5:
10
+ # CREATE TABLE proxy (id INTEGER PRIMARY KEY,
11
+ # addr TEXT,
12
+ # port INTEGER);
13
+
14
+ end # class Mongrel2::Config::Proxy
15
+
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'mongrel2' unless defined?( Mongrel2 )
4
+ require 'mongrel2/config' unless defined?( Mongrel2::Config )
5
+
6
+ # Mongrel2 Route configuration class
7
+ class Mongrel2::Config::Route < Mongrel2::Config( :route )
8
+
9
+ ### As of Mongrel2/1.7.5:
10
+ # CREATE TABLE route (id INTEGER PRIMARY KEY,
11
+ # path TEXT,
12
+ # reversed BOOLEAN DEFAULT 0,
13
+ # host_id INTEGER,
14
+ # target_id INTEGER,
15
+ # target_type TEXT);
16
+
17
+ ### Fetch the route's target, which is either a Mongrel2::Config::Directory,
18
+ ### Mongrel2::Config::Proxy, or Mongrel2::Config::Handler object.
19
+ def target
20
+ case self.target_type
21
+ when 'dir'
22
+ return Mongrel2::Config::Directory[ self.target_id ]
23
+ when 'proxy'
24
+ return Mongrel2::Config::Proxy[ self.target_id ]
25
+ when 'handler'
26
+ return Mongrel2::Config::Handler[ self.target_id ]
27
+ else
28
+ raise ArgumentError, "unknown target type %p" % [ self.target_type ]
29
+ end
30
+ end
31
+
32
+
33
+ ### Set the target of the route to +object+, which should be one of the classes
34
+ ### returned from #target.
35
+ def target=( object )
36
+ case object
37
+ when Mongrel2::Config::Directory
38
+ self.target_type = 'dir'
39
+ when Mongrel2::Config::Proxy
40
+ self.target_type = 'proxy'
41
+ when Mongrel2::Config::Handler
42
+ self.target_type = 'handler'
43
+ else
44
+ raise ArgumentError, "unknown target type %p" % [ object.class ]
45
+ end
46
+
47
+ self.target_id = object.id
48
+ end
49
+
50
+ end # class Mongrel2::Config::Route
51
+
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'mongrel2' unless defined?( Mongrel2 )
4
+ require 'mongrel2/config' unless defined?( Mongrel2::Config )
5
+
6
+
7
+ # Mongrel2 Server configuration class
8
+ class Mongrel2::Config::Server < Mongrel2::Config( :server )
9
+
10
+ ### As of Mongrel2/1.7.5:
11
+ # CREATE TABLE server (id INTEGER PRIMARY KEY,
12
+ # uuid TEXT,
13
+ # access_log TEXT,
14
+ # error_log TEXT,
15
+ # chroot TEXT DEFAULT '/var/www',
16
+ # pid_file TEXT,
17
+ # default_host TEXT,
18
+ # name TEXT DEFAULT '',
19
+ # bind_addr TEXT DEFAULT "0.0.0.0",
20
+ # port INTEGER,
21
+ # use_ssl INTEGER default 0);
22
+
23
+ one_to_many :hosts
24
+
25
+
26
+ #
27
+ # :section: Validation Callbacks
28
+ #
29
+
30
+ ### Sequel validation callback: add errors if the record is invalid.
31
+ def validate
32
+ self.validates_presence [ :access_log, :error_log, :pid_file, :default_host, :port ],
33
+ message: 'is missing or nil'
34
+ end
35
+
36
+
37
+
38
+ ### DSL methods for the Server context besides those automatically-generated from its
39
+ ### columns.
40
+ module DSLMethods
41
+
42
+ ### Add a Mongrel2::Config::Host to the Server object with the given +hostname+. If a
43
+ ### +block+ is specified, it can be used to further configure the Host.
44
+ def host( name, &block )
45
+ self.target.save( :validate => false )
46
+
47
+ Mongrel2.log.debug "Host [%s] (block: %p)" % [ name, block ]
48
+ adapter = Mongrel2::Config::DSL::Adapter.new( Mongrel2::Config::Host,
49
+ :name => name, :matching => name )
50
+ adapter.instance_eval( &block ) if block
51
+ self.target.add_host( adapter.target )
52
+ end
53
+
54
+
55
+ end # module DSLMethods
56
+
57
+ end # class Mongrel2::Config::Server
58
+
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'mongrel2' unless defined?( Mongrel2 )
4
+ require 'mongrel2/config' unless defined?( Mongrel2::Config )
5
+
6
+ # Mongrel2 Setting configuration class
7
+ class Mongrel2::Config::Setting < Mongrel2::Config( :setting )
8
+
9
+ ### As of Mongrel2/1.7.5:
10
+ # CREATE TABLE setting (id INTEGER PRIMARY KEY,
11
+ # key TEXT,
12
+ # value TEXT);
13
+
14
+ end # class Mongrel2::Config::Setting
15
+
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'mongrel2' unless defined?( Mongrel2 )
4
+ require 'mongrel2/config' unless defined?( Mongrel2::Config )
5
+
6
+ # Mongrel2 configuration statistic class
7
+ class Mongrel2::Config::Statistic < Mongrel2::Config( :statistic )
8
+
9
+ ### As of Mongrel2/1.7.5:
10
+ # CREATE TABLE statistic (id SERIAL,
11
+ # other_type TEXT,
12
+ # other_id INTEGER,
13
+ # name text,
14
+ # sum REAL,
15
+ # sumsq REAL,
16
+ # n INTEGER,
17
+ # min REAL,
18
+ # max REAL,
19
+ # mean REAL,
20
+ # sd REAL,
21
+ # primary key (other_type, other_id, name));
22
+
23
+ end # class Mongrel2::Config::Statistic
@@ -0,0 +1,212 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'zmq'
4
+ require 'yajl'
5
+
6
+ require 'mongrel2' unless defined?( Mongrel2 )
7
+ require 'mongrel2/mixins'
8
+
9
+
10
+ # The Mongrel2 connection class. Connection objects serve as a front end for
11
+ # the ZMQ sockets which talk to the mongrel2 server/s for your handler. It receives
12
+ # TNetString requests and wraps Mongrel2::Request objects around them, and
13
+ # then encodes and sends Mongrel2::Response objects back to the server.
14
+ #
15
+ # == References
16
+ # * http://mongrel2.org/static/mongrel2-manual.html#x1-700005.3
17
+ class Mongrel2::Connection
18
+ include Mongrel2::Loggable
19
+
20
+
21
+ ### Create a new Connection identified by +app_id+ (a UUID or other unique string) that
22
+ ### will connect to a Mongrel2 server on the +sub_addr+ and +pub_addr+ (e.g.,
23
+ ### 'tcp://127.0.0.1:9998').
24
+ def initialize( app_id, sub_addr, pub_addr )
25
+ @app_id = app_id
26
+ @sub_addr = sub_addr
27
+ @pub_addr = pub_addr
28
+
29
+ @request_sock = @response_sock = nil
30
+ @closed = false
31
+ end
32
+
33
+
34
+ ### Copy constructor -- don't keep the +original+'s sockets or closed state.
35
+ def initialize_copy( original )
36
+ @request_sock = @response_sock = nil
37
+ @closed = false
38
+ end
39
+
40
+
41
+
42
+ ######
43
+ public
44
+ ######
45
+
46
+ # The application's UUID that identifies it to Mongrel2
47
+ attr_reader :app_id
48
+
49
+ # The connection's subscription (request) socket address
50
+ attr_reader :sub_addr
51
+
52
+ # The connection's publication (response) socket address
53
+ attr_reader :pub_addr
54
+
55
+
56
+ ### Establish both connections to the Mongrel2 server.
57
+ def connect
58
+ ctx = Mongrel2.zmq_context
59
+ self.log.debug "0mq Context is: %p" % [ ctx ]
60
+
61
+ self.log.info "Connecting request socket (%s)" % [ @sub_addr ]
62
+ @request_sock = ctx.socket( ZMQ::PULL )
63
+ @request_sock.setsockopt( ZMQ::LINGER, 0 )
64
+ @request_sock.connect( @sub_addr )
65
+
66
+ self.log.info "Connecting response socket (%s)" % [ @pub_addr ]
67
+ @response_sock = ctx.socket( ZMQ::PUB )
68
+ @response_sock.setsockopt( ZMQ::LINGER, 0 )
69
+ @response_sock.setsockopt( ZMQ::IDENTITY, @app_id )
70
+ @response_sock.connect( @pub_addr )
71
+ end
72
+
73
+
74
+ ### Fetch the ZMQ::PULL socket for incoming requests, establishing the
75
+ ### connection to Mongrel if it hasn't been already.
76
+ def request_sock
77
+ self.check_closed
78
+ self.connect unless @request_sock
79
+ return @request_sock
80
+ end
81
+
82
+
83
+ ### Fetch the ZMQ::PUB socket for outgoing responses, establishing the
84
+ ### connection to Mongrel if it hasn't been already.
85
+ def response_sock
86
+ self.check_closed
87
+ self.connect unless @response_sock
88
+ return @response_sock
89
+ end
90
+
91
+
92
+ ### Fetch the next request from the server as raw TNetString data.
93
+ def recv
94
+ self.check_closed
95
+
96
+ self.log.debug "Fetching next request"
97
+ data = self.request_sock.recv
98
+ self.log.debug " got request data: %p" % [ data ]
99
+ return data
100
+ end
101
+
102
+
103
+ ### Fetch the next request from the server as a Mongrel2::Request object.
104
+ def receive
105
+ raw_req = self.recv
106
+ return Mongrel2::Request.parse( raw_req )
107
+ end
108
+
109
+
110
+ ### Write a raw +data+ to the given connection ID (+conn_id+) at the given +sender_id+.
111
+ def send( sender_id, conn_id, data )
112
+ self.check_closed
113
+ header = "%s %d:%s," % [ sender_id, conn_id.to_s.length, conn_id ]
114
+ buf = header + ' ' + data
115
+ self.log.debug "Sending response: %p" % [ buf ]
116
+ self.response_sock.send( buf )
117
+ end
118
+
119
+
120
+ ### Write the specified +response+ (Mongrel::Response object) to the requester.
121
+ def reply( response )
122
+ self.send( response.sender_id, response.conn_id, response.to_s )
123
+ end
124
+
125
+
126
+ ### Send the given +data+ to one or more connected clients identified by +client_ids+
127
+ ### via the server specified by +sender_id+. The +client_ids+ should be an Array of
128
+ ### Integer IDs no longer than Mongrel2::MAX_IDENTS.
129
+ def broadcast( sender_id, conn_ids, data )
130
+ idlist = conn_ids.map( &:to_s ).join( ' ' )
131
+ self.send( sender_id, idlist, data )
132
+ end
133
+
134
+
135
+ ### Tell the server to close the connection associated with the given +sender_id+ and
136
+ ### +conn_id+.
137
+ def send_close( sender_id, conn_id )
138
+ self.send( sender_id, conn_id, '' )
139
+ end
140
+
141
+
142
+ ### Tell the server to close the connection associated with the given +request_or_response+.
143
+ def reply_close( request_or_response )
144
+ self.send_close( request_or_response.sender_id, request_or_response.conn_id )
145
+ end
146
+
147
+
148
+ ### Tell the server associated with +sender_id+ to close the connections associated
149
+ ### with +conn_ids+.
150
+ def broadcast_close( sender_id, *conn_ids )
151
+ self.broadcast( sender_id, conn_ids.flatten, '' )
152
+ end
153
+
154
+
155
+ ### Close both of the sockets and mark the Connection as closed.
156
+ def close
157
+ return if self.closed?
158
+ self.closed = true
159
+ @request_sock.close if @request_sock
160
+ @response_sock.close if @response_sock
161
+ end
162
+
163
+
164
+ ### Returns +true+ if the connection to the Mongrel2 server has been closed.
165
+ def closed?
166
+ return @closed
167
+ end
168
+
169
+
170
+ ### Returns a string containing a human-readable representation of the Connection,
171
+ ### suitable for debugging.
172
+ def inspect
173
+ state = if @request_socket
174
+ if self.closed?
175
+ "closed"
176
+ else
177
+ "connected"
178
+ end
179
+ else
180
+ "not connected"
181
+ end
182
+
183
+ return "#<%p:0x%08x {%s} %s <-> %s (%s)>" % [
184
+ self.class,
185
+ self.object_id * 2,
186
+ self.app_id,
187
+ self.sub_addr,
188
+ self.pub_addr,
189
+ state,
190
+ ]
191
+ end
192
+
193
+
194
+
195
+ #########
196
+ protected
197
+ #########
198
+
199
+ # True if the Connection to the Mongrel2 server has been closed.
200
+ attr_writer :closed
201
+
202
+
203
+ ### Check to be sure the Connection hasn't been closed, raising a Mongrel2::ConnectionError
204
+ ### if it has.
205
+ def check_closed
206
+ raise Mongrel2::ConnectionError, "operation on closed Connection" if self.closed?
207
+ end
208
+
209
+ end # class Mongrel2::Connection
210
+
211
+ # vim: set nosta noet ts=4 sw=4:
212
+