Skip to content

Instantly share code, notes, and snippets.

@ender672
Created April 13, 2012 17:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ender672/2378417 to your computer and use it in GitHub Desktop.
Save ender672/2378417 to your computer and use it in GitHub Desktop.
Single-threaded, single-process, non-evented rack handler using the mongrel http parser
require 'rack/handler'
require 'socket'
require 'puma/puma_http11'
module Rack::Handler
module Qute
READ_SIZE = 500000
module NullIO
def self.gets; end
def self.each; end
def self.read(n); end
def self.rewind; end
def self.close; end
end
PROTO_ENV = {
"rack.version" => [1, 1],
"rack.errors" => $stderr,
"rack.multithread" => false,
"rack.multiprocess" => false,
"rack.run_once" => false,
"rack.input" => NullIO,
"SCRIPT_NAME" => "",
"QUERY_STRING" => "",
"SERVER_NAME" => 'qute'
}
def self.run(app, options = {})
PROTO_ENV["SERVER_PORT"] = options[:Port]
unix_socket = options[:Host][0] == ?/
sock = if unix_socket
unix_server(options[:Host])
else
TCPServer.new(options[:Host], options[:Port])
end
begin
server_loop(sock, app)
ensure
File.unlink(options[:Host]) if unix_socket
end
end
private
def self.server_loop(sock, app)
parser = Puma::HttpParser.new
loop do
begin
client = sock.accept
data = client.readpartial(READ_SIZE)
next if data.empty?
request = PROTO_ENV.dup
parser.reset
parser.execute(request, data, 0)
next unless parser.finished?
request['PATH_INFO'] = request['REQUEST_PATH']
request['rack.input'] = parser.body unless parser.body.empty?
send_response client, *app.call(request)
ensure
client.close
end
end
end
def self.send_response(client, status, headers, body)
client.write "HTTP/1.1 #{status}\r\n"
headers.each do |k, vs|
vs.split("\n").each{ |v| client.write "#{k}: #{v}\r\n" }
end
client.write "Connection: close\r\n\r\n"
body.each{ |part| client.write part }
ensure
body.close if body.respond_to?(:close)
end
def self.unix_server(path)
old_umask = File.umask(0)
begin
UNIXServer.new(path)
ensure
File.umask(old_umask)
end
end
end
register :qute, Qute
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment