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 CHANGED
@@ -1 +1 @@
1
- 0.0.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: 31
4
+ hash: 27
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
+ - 1
8
9
  - 0
9
- - 0
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