rack-mongrel2 0.0.0 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|