require 'stringio' require 'mongrel' require 'mongrel/handlers' require 'nitro/cgi' require 'nitro/context' require 'nitro/dispatcher' # Speeds things up, more comaptible with OSX. Socket.do_not_reverse_lookup = true #-- # Fix for Nitro. #++ module Mongrel # :nodoc: all class HttpRequest def method_missing(name, *args) if @params.has_key?(name.to_s.upcase) return @params[name.to_s.upcase] elsif name.to_s =~ /\A(.*)=\Z/ && @params.has_key?($1.upcase) @params[$1.upcase] = args[0] else super end end end end module Nitro class Mongrel class << self attr_accessor :mongrel # Start the Webrick adapter. def start(server) # TODO add logging. mongrel_options = server.options.dup mongrel_options.update( :BindAddress => server.address, :Port => server.port, :DocumentRoot => server.public_root ) @mongrel = ::Mongrel::HttpServer.new(mongrel_options[:BindAddress], mongrel_options[:Port]) trap('INT') { stop } # will this work? @mongrel.register('/', MongrelAdapter.new(server)) initialize_mongrel(server) @mongrel.run @mongrel_thread = @mongrel.acceptor @mongrel_thread.join end # Stop the Mongrel adapter. def stop @mongrel_thread.kill end # Override this method to perform customized mongrel # initialization. def initialize_mongrel(server) end end end # A special handler for Xhtml files. #class XhtmlFileHandler < WEBrick::HTTPServlet::DefaultFileHandler # def do_GET(req, res) # res['content-type'] = 'text/html' # res.body = '
Permission denied' # end #end # A Mongrel Adapter for Nitro. class MongrelAdapter < ::Mongrel::HttpHandler attr_accessor :server STATUS_CODES = { "200" => "OK", "304" => "Not Modified", "404" => "Not found", "500" => "Server Error" } def initialize(server) @server = server end def process(req, res) handle(req, res) end # Handle a static file. Also handles cached pages. def handle_file(req, res) begin rewrite(req) # TODO handle If-Modified-Since and add Last-Modified headers filename = [@server.public_root, req.path_info].join("/") ext = File.extname(filename) content_type = ::Mongrel::DirHandler::MIME_TYPES[ext] || "text/plain" File.open(filename, "rb") { |f| # TODO check whether path circumvents public_root directory? size = File.size(filename) res.socket << "HTTP/1.1 200 OK\r\n" res.socket << "Content-type: #{content_type}\r\n" res.socket << "Content-length: #{size}\r\n" res.socket << "\r\n" res.socket << f.read # XXX inefficient for large files, may cause leaks } return true rescue Object => ex return false ensure unrewrite(req) end end # Handle the request. def handle(req, res) unless handle_file(req, res) path = req.path_info begin context = Context.new(@server) context.in = StringIO.new(req.body || "") context.headers = {} req.params.each { |h, v| if h =~ /\AHTTP_(.*)\Z/ context.headers[$1.gsub("_", "-")] = v end context.headers[h] = v } # context.headers.update(req.meta_vars) context.headers['REQUEST_URI'] = context.headers['SCRIPT_NAME'] if context.headers['PATH_INFO'].blank? context.headers['REQUEST_URI'] = '/' else context.headers['REQUEST_URI'] = '/' + context.headers['PATH_INFO'] end # gmosx: make compatible with fastcgi. context.headers['REQUEST_URI'].slice!(/http:\/\/(.*?)\//) context.headers['REQUEST_URI'] = '/' + context.headers['REQUEST_URI'] Cgi.parse_params(context) Cgi.parse_cookies(context) context.render(path) res.socket << "HTTP/1.1 #{context.status.to_s} " if STATUS_CODES.has_key? context.status res.socket << STATUS_CODES[context.status] else res.socket << "Unknown Status Code" end res.socket << "\r\n" res.socket << Cgi.response_headers(context) res.socket << context.out context.close ensure Og.manager.put_store if defined?(Og) and Og.respond_to?(:manager) and Og.manager end end end def rewrite(req) if req.path_info == '/' || req.path_info == '' req.path_info = '/index.html' elsif req.path_info =~ /^([^.]+)$/ req.path_info = "#{$1}/index.html" end end # Rewrite back to the original path. def unrewrite(req) if req.path_info == '/index.html' req.path_info = '/' elsif req.path_info =~ /^([^.]+)\/index.html$/ req.path_info = $1 end end end end # * Joshua Hoke # * George Moschovitis