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.
- data.tar.gz.sig +0 -0
- data/.gemtest +0 -0
- data/History.rdoc +4 -0
- data/Manifest.txt +66 -0
- data/README.rdoc +169 -0
- data/Rakefile +77 -0
- data/bin/m2sh.rb +600 -0
- data/data/mongrel2/bootstrap.html +25 -0
- data/data/mongrel2/config.sql +84 -0
- data/data/mongrel2/mimetypes.sql +855 -0
- data/examples/README.txt +6 -0
- data/examples/config.rb +54 -0
- data/examples/helloworld-handler.rb +31 -0
- data/examples/request-dumper.rb +45 -0
- data/examples/request-dumper.tmpl +71 -0
- data/examples/run +17 -0
- data/lib/mongrel2.rb +62 -0
- data/lib/mongrel2/config.rb +212 -0
- data/lib/mongrel2/config/directory.rb +78 -0
- data/lib/mongrel2/config/dsl.rb +206 -0
- data/lib/mongrel2/config/handler.rb +124 -0
- data/lib/mongrel2/config/host.rb +88 -0
- data/lib/mongrel2/config/log.rb +48 -0
- data/lib/mongrel2/config/mimetype.rb +15 -0
- data/lib/mongrel2/config/proxy.rb +15 -0
- data/lib/mongrel2/config/route.rb +51 -0
- data/lib/mongrel2/config/server.rb +58 -0
- data/lib/mongrel2/config/setting.rb +15 -0
- data/lib/mongrel2/config/statistic.rb +23 -0
- data/lib/mongrel2/connection.rb +212 -0
- data/lib/mongrel2/constants.rb +159 -0
- data/lib/mongrel2/control.rb +165 -0
- data/lib/mongrel2/exceptions.rb +59 -0
- data/lib/mongrel2/handler.rb +309 -0
- data/lib/mongrel2/httprequest.rb +51 -0
- data/lib/mongrel2/httpresponse.rb +187 -0
- data/lib/mongrel2/jsonrequest.rb +43 -0
- data/lib/mongrel2/logging.rb +241 -0
- data/lib/mongrel2/mixins.rb +143 -0
- data/lib/mongrel2/request.rb +148 -0
- data/lib/mongrel2/response.rb +74 -0
- data/lib/mongrel2/table.rb +216 -0
- data/lib/mongrel2/xmlrequest.rb +36 -0
- data/spec/lib/constants.rb +237 -0
- data/spec/lib/helpers.rb +246 -0
- data/spec/lib/matchers.rb +50 -0
- data/spec/mongrel2/config/directory_spec.rb +91 -0
- data/spec/mongrel2/config/dsl_spec.rb +218 -0
- data/spec/mongrel2/config/handler_spec.rb +118 -0
- data/spec/mongrel2/config/host_spec.rb +30 -0
- data/spec/mongrel2/config/log_spec.rb +95 -0
- data/spec/mongrel2/config/proxy_spec.rb +30 -0
- data/spec/mongrel2/config/route_spec.rb +83 -0
- data/spec/mongrel2/config/server_spec.rb +84 -0
- data/spec/mongrel2/config/setting_spec.rb +30 -0
- data/spec/mongrel2/config/statistic_spec.rb +30 -0
- data/spec/mongrel2/config_spec.rb +111 -0
- data/spec/mongrel2/connection_spec.rb +172 -0
- data/spec/mongrel2/constants_spec.rb +32 -0
- data/spec/mongrel2/control_spec.rb +192 -0
- data/spec/mongrel2/handler_spec.rb +261 -0
- data/spec/mongrel2/httpresponse_spec.rb +232 -0
- data/spec/mongrel2/logging_spec.rb +76 -0
- data/spec/mongrel2/mixins_spec.rb +62 -0
- data/spec/mongrel2/request_spec.rb +157 -0
- data/spec/mongrel2/response_spec.rb +81 -0
- data/spec/mongrel2/table_spec.rb +176 -0
- data/spec/mongrel2_spec.rb +34 -0
- metadata +294 -0
- 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
|
+
|