rack-mongrel2 0.0.0 → 0.1.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.
- data/VERSION +1 -1
- data/lib/mongrel2/connection.rb +35 -0
- data/lib/mongrel2/request.rb +34 -0
- data/lib/mongrel2/response.rb +66 -0
- data/lib/rack/handler/mongrel2.rb +64 -0
- data/rack-mongrel2.gemspec +74 -0
- metadata +8 -3
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.1.0
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'zmq'
|
2
|
+
require 'mongrel2/request'
|
3
|
+
require 'mongrel2/response'
|
4
|
+
|
5
|
+
module Mongrel2
|
6
|
+
class Connection
|
7
|
+
CTX = ZMQ::Context.new(1)
|
8
|
+
|
9
|
+
def initialize(ident, sub, pub, block = true)
|
10
|
+
@ident, @sub, @pub, @block = ident, sub, pub, block
|
11
|
+
|
12
|
+
# Connect to receive requests
|
13
|
+
@reqs = CTX.socket(ZMQ::UPSTREAM)
|
14
|
+
@reqs.connect(sub)
|
15
|
+
|
16
|
+
# Connect to send responses
|
17
|
+
@resp = CTX.socket(ZMQ::PUB)
|
18
|
+
@resp.connect(pub)
|
19
|
+
@resp.setsockopt(ZMQ::IDENTITY, ident)
|
20
|
+
end
|
21
|
+
|
22
|
+
def recv
|
23
|
+
Request.parse(@reqs.recv)
|
24
|
+
end
|
25
|
+
|
26
|
+
def reply(req, body, status = 200, headers = {})
|
27
|
+
Response.new(@resp).send_http(req, body, status, headers)
|
28
|
+
end
|
29
|
+
|
30
|
+
def close
|
31
|
+
@reqs.close rescue nil
|
32
|
+
@resp.close rescue nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Mongrel2
|
2
|
+
class Request
|
3
|
+
attr_reader :headers, :body, :uuid, :conn_id
|
4
|
+
|
5
|
+
class << self
|
6
|
+
def parse(msg)
|
7
|
+
# UUID CONN_ID PATH SIZE:HEADERS,SIZE:BODY,
|
8
|
+
uuid, conn_id, path, rest = msg.split(' ', 4)
|
9
|
+
headers, rest = parse_netstring(rest)
|
10
|
+
body, _ = parse_netstring(rest)
|
11
|
+
headers = Yajl::Parser.parse(headers)
|
12
|
+
new(uuid, conn_id, path, headers, body)
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse_netstring(ns)
|
16
|
+
# SIZE:HEADERS,
|
17
|
+
|
18
|
+
len, rest = ns.split(':', 2)
|
19
|
+
len = len.to_i
|
20
|
+
raise "Netstring did not end in ','" unless rest[len].chr == ','
|
21
|
+
[rest[0, len], rest[(len + 1)..-1]]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize(uuid, conn_id, path, headers, body)
|
26
|
+
@uuid, @conn_id, @path, @headers, @body = uuid, conn_id, path, headers, body
|
27
|
+
@data = headers['METHOD'] == 'JSON' ? Yajl::Parser.parse(body) : {}
|
28
|
+
end
|
29
|
+
|
30
|
+
def disconnect?
|
31
|
+
headers['METHOD'] == 'JSON' && @data['type'] == 'disconnect'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Mongrel2
|
2
|
+
class Response
|
3
|
+
StatusMessage = {
|
4
|
+
100 => 'Continue',
|
5
|
+
101 => 'Switching Protocols',
|
6
|
+
200 => 'OK',
|
7
|
+
201 => 'Created',
|
8
|
+
202 => 'Accepted',
|
9
|
+
203 => 'Non-Authoritative Information',
|
10
|
+
204 => 'No Content',
|
11
|
+
205 => 'Reset Content',
|
12
|
+
206 => 'Partial Content',
|
13
|
+
300 => 'Multiple Choices',
|
14
|
+
301 => 'Moved Permanently',
|
15
|
+
302 => 'Found',
|
16
|
+
303 => 'See Other',
|
17
|
+
304 => 'Not Modified',
|
18
|
+
305 => 'Use Proxy',
|
19
|
+
307 => 'Temporary Redirect',
|
20
|
+
400 => 'Bad Request',
|
21
|
+
401 => 'Unauthorized',
|
22
|
+
402 => 'Payment Required',
|
23
|
+
403 => 'Forbidden',
|
24
|
+
404 => 'Not Found',
|
25
|
+
405 => 'Method Not Allowed',
|
26
|
+
406 => 'Not Acceptable',
|
27
|
+
407 => 'Proxy Authentication Required',
|
28
|
+
408 => 'Request Timeout',
|
29
|
+
409 => 'Conflict',
|
30
|
+
410 => 'Gone',
|
31
|
+
411 => 'Length Required',
|
32
|
+
412 => 'Precondition Failed',
|
33
|
+
413 => 'Request Entity Too Large',
|
34
|
+
414 => 'Request-URI Too Large',
|
35
|
+
415 => 'Unsupported Media Type',
|
36
|
+
416 => 'Request Range Not Satisfiable',
|
37
|
+
417 => 'Expectation Failed',
|
38
|
+
500 => 'Internal Server Error',
|
39
|
+
501 => 'Not Implemented',
|
40
|
+
502 => 'Bad Gateway',
|
41
|
+
503 => 'Service Unavailable',
|
42
|
+
504 => 'Gateway Timeout',
|
43
|
+
505 => 'HTTP Version Not Supported'
|
44
|
+
}
|
45
|
+
|
46
|
+
def initialize(resp)
|
47
|
+
@resp = resp
|
48
|
+
end
|
49
|
+
|
50
|
+
def send_http(req, body, status, headers)
|
51
|
+
send_resp(req.uuid, req.conn_id, build_http_response(body, status, headers))
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def send_resp(uuid, conn_id, data)
|
57
|
+
@resp.send('%s %d:%s, %s' % [uuid, conn_id.size, conn_id, data])
|
58
|
+
end
|
59
|
+
|
60
|
+
def build_http_response(body, status, headers)
|
61
|
+
headers['Content-Length'] = body.size.to_s
|
62
|
+
headers = headers.map{ |k, v| '%s: %s' % [k,v] }.join("\r\n")
|
63
|
+
"HTTP/1.1 #{status} #{StatusMessage[status.to_i]}\r\n#{headers}\r\n\r\n#{body}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'mongrel2/connection'
|
2
|
+
require 'stringio'
|
3
|
+
|
4
|
+
module Rack
|
5
|
+
module Handler
|
6
|
+
class Mongrel2
|
7
|
+
class << self
|
8
|
+
def run(app, options = {})
|
9
|
+
options = {
|
10
|
+
:recv => 'tcp://127.0.0.1:9997' || ENV['RACK_MONGREL2_RECV'],
|
11
|
+
:send => 'tcp://127.0.0.1:9996' || ENV['RACK_MONGREL2_SEND'],
|
12
|
+
:uuid => ENV['RACK_MONGREL2_UUID']
|
13
|
+
}.merge(options)
|
14
|
+
raise ArgumentError.new('Must specify an :uuid or set RACK_MONGREL2_UUID') if options[:uuid].nil?
|
15
|
+
|
16
|
+
conn = ::Mongrel2::Connection.new(options[:uuid], options[:recv], options[:send])
|
17
|
+
|
18
|
+
running = true
|
19
|
+
trap('SIGINT') do
|
20
|
+
running = false
|
21
|
+
conn.close
|
22
|
+
end
|
23
|
+
|
24
|
+
while running
|
25
|
+
req = conn.recv
|
26
|
+
next if req.disconnect?
|
27
|
+
return unless running
|
28
|
+
|
29
|
+
script_name = ENV['RACK_RELATIVE_URL_ROOT'] || req.headers['PATTERN'].split('(', 2).first.gsub(/\/$/, '')
|
30
|
+
env = {
|
31
|
+
'rack.version' => Rack::VERSION,
|
32
|
+
'rack.url_scheme' => 'http', # Only HTTP for now
|
33
|
+
'rack.input' => StringIO.new(req.body),
|
34
|
+
'rack.errors' => $stderr,
|
35
|
+
'rack.multithread' => true,
|
36
|
+
'rack.multiprocess' => true,
|
37
|
+
'rack.run_once' => false,
|
38
|
+
'mongrel2.pattern' => req.headers['PATTERN'],
|
39
|
+
'REQUEST_METHOD' => req.headers['METHOD'],
|
40
|
+
'SCRIPT_NAME' => script_name,
|
41
|
+
'PATH_INFO' => req.headers['PATH'].gsub(script_name, ''),
|
42
|
+
'QUERY_STRING' => req.headers['QUERY']
|
43
|
+
}
|
44
|
+
|
45
|
+
env['SERVER_NAME'], env['SERVER_PORT'] = req.headers['host'].split(':', 2)
|
46
|
+
req.headers.each do |key, val|
|
47
|
+
unless key =~ /content_(type|length)/i
|
48
|
+
key = "HTTP_#{key.upcase}"
|
49
|
+
end
|
50
|
+
env[key] = val
|
51
|
+
end
|
52
|
+
|
53
|
+
status, headers, rack_response = app.call(env)
|
54
|
+
body = ''
|
55
|
+
rack_response.each { |b| body << b }
|
56
|
+
conn.reply(req, body, status, headers)
|
57
|
+
end
|
58
|
+
ensure
|
59
|
+
conn.close if conn.respond_to?(:close)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{rack-mongrel2}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Daniel Huckstep"]
|
12
|
+
s.date = %q{2010-10-23}
|
13
|
+
s.description = %q{A Rack handler for the Mongrel2 web server, by Zed Shaw. http://mongrel2.org/}
|
14
|
+
s.email = %q{darkhelmet@darkhelmetlive.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
".rvmrc",
|
23
|
+
"Gemfile",
|
24
|
+
"Gemfile.lock",
|
25
|
+
"LICENSE",
|
26
|
+
"README.rdoc",
|
27
|
+
"Rakefile",
|
28
|
+
"VERSION",
|
29
|
+
"lib/mongrel2/connection.rb",
|
30
|
+
"lib/mongrel2/request.rb",
|
31
|
+
"lib/mongrel2/response.rb",
|
32
|
+
"lib/rack-mongrel2.rb",
|
33
|
+
"lib/rack/handler/mongrel2.rb",
|
34
|
+
"rack-mongrel2.gemspec",
|
35
|
+
"spec/rack-mongrel2_spec.rb",
|
36
|
+
"spec/spec.opts",
|
37
|
+
"spec/spec_helper.rb"
|
38
|
+
]
|
39
|
+
s.homepage = %q{http://github.com/darkhelmet/rack-mongrel2}
|
40
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
41
|
+
s.require_paths = ["lib"]
|
42
|
+
s.rubygems_version = %q{1.3.7}
|
43
|
+
s.summary = %q{The only Mongrel2 Rack handler you'll ever need.}
|
44
|
+
s.test_files = [
|
45
|
+
"spec/rack-mongrel2_spec.rb",
|
46
|
+
"spec/spec_helper.rb"
|
47
|
+
]
|
48
|
+
|
49
|
+
if s.respond_to? :specification_version then
|
50
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
51
|
+
s.specification_version = 3
|
52
|
+
|
53
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
54
|
+
s.add_runtime_dependency(%q<yajl-ruby>, ["~> 0.7.8"])
|
55
|
+
s.add_runtime_dependency(%q<zmq>, ["~> 2.0.9"])
|
56
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.4.0"])
|
57
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.0.1"])
|
58
|
+
s.add_development_dependency(%q<yard>, ["~> 0.6.1"])
|
59
|
+
else
|
60
|
+
s.add_dependency(%q<yajl-ruby>, ["~> 0.7.8"])
|
61
|
+
s.add_dependency(%q<zmq>, ["~> 2.0.9"])
|
62
|
+
s.add_dependency(%q<jeweler>, ["~> 1.4.0"])
|
63
|
+
s.add_dependency(%q<rspec>, ["~> 2.0.1"])
|
64
|
+
s.add_dependency(%q<yard>, ["~> 0.6.1"])
|
65
|
+
end
|
66
|
+
else
|
67
|
+
s.add_dependency(%q<yajl-ruby>, ["~> 0.7.8"])
|
68
|
+
s.add_dependency(%q<zmq>, ["~> 2.0.9"])
|
69
|
+
s.add_dependency(%q<jeweler>, ["~> 1.4.0"])
|
70
|
+
s.add_dependency(%q<rspec>, ["~> 2.0.1"])
|
71
|
+
s.add_dependency(%q<yard>, ["~> 0.6.1"])
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-mongrel2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
+
- 1
|
8
9
|
- 0
|
9
|
-
|
10
|
-
version: 0.0.0
|
10
|
+
version: 0.1.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Daniel Huckstep
|
@@ -117,7 +117,12 @@ files:
|
|
117
117
|
- README.rdoc
|
118
118
|
- Rakefile
|
119
119
|
- VERSION
|
120
|
+
- lib/mongrel2/connection.rb
|
121
|
+
- lib/mongrel2/request.rb
|
122
|
+
- lib/mongrel2/response.rb
|
120
123
|
- lib/rack-mongrel2.rb
|
124
|
+
- lib/rack/handler/mongrel2.rb
|
125
|
+
- rack-mongrel2.gemspec
|
121
126
|
- spec/rack-mongrel2_spec.rb
|
122
127
|
- spec/spec.opts
|
123
128
|
- spec/spec_helper.rb
|