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 class Configurator def log(msg) Logger.info msg end end end module Nitro class Mongrel class << self attr_accessor :mongrel attr_accessor :mongrel_config # Start the Mongrel adapter. def start(server) # TODO add logging. @mongrel_config = ::Mongrel::Configurator.new :host => server.address do listener :port => server.port do uri "/", :handler => MongrelAdapter.new(server) trap('INT') { Nitro::Mongrel.stop(server) } run end end @mongrel_config.log("Started Mongrel on " + server.address + ":" + server.port.to_s) @mongrel_config.join end # Stop the Mongrel adapter. def stop(server = nil) @mongrel_config.log("Stopped Mongrel on " + server.address + ":" + server.port.to_s) @mongrel_config.stop end # Override this method to perform customized mongrel # initialization. def initialize_mongrel(server) end end end # A Mongrel Adapter for Nitro. This is the prefered adapter to # use in production mode. Typically you will have a front-end # web server (for example apache) handle static content and # proxy dynamic content request to a cluster of mongrel servers. class MongrelAdapter < ::Mongrel::HttpHandler attr_accessor :server def initialize(server) @server = server @handle_static_files = Server.handle_static_files end def process(req, res) handle(req, res) end # Handle a static file. Also handles cached pages. def handle_file(req, res) rewrite(req) # gmosx, FIXME: this is a nasty hack that fixes a really # *nasty* caching bug. Find a better solution. When hitting # the backend server, if the index method takes parameters # the dispatcher considers all static files as parameters. # If you have output caching enabled for the index page, # all your static files get corrupted. if (@handle_static_files == false) and (req.path_info =~ /\.html$/) return false end # TODO: handle If-Modified-Since and add Last-Modified headers filename = File.join(@server.public_root, req.path_info).squeeze('/') File.open(filename, "rb") do |f| # TODO: check whether path circumvents public_root directory? res.status = 200 res.body << f.read # XXX inefficient for large files, may cause leaks end return true rescue Errno::ENOENT => ex # TODO: Lookup Win32 error for 'file missing' return false ensure unrewrite(req) end # Handle the request. #-- # TODO: recode this like the camping mongrel handler. #++ def handle(req, res) unless handle_file(req, res) begin path = req.path_info context = Context.new(@server) context.in = if req.body.is_a? String StringIO.new(req.body) else req.body end context.headers = {} req.params.each { |h, v| if h =~ /\AHTTP_(.*)\Z/ context.headers[$1.gsub("_", "-")] = v end context.headers[h] = v } # hackfix: make it behave like webrick and fcgi context.headers['REQUEST_URI'] << "?#{context.headers['QUERY_STRING']}" if context.headers['QUERY_STRING'] context.headers['QUERY_STRING'] ||= '' Cgi.parse_params(context) Cgi.parse_cookies(context) context.render(path) =begin res.start(context.status,true) do |head,out| out.write(Cgi.response_headers(context)) out.write(context.out) end =end # what is the error code if a request without a handler # is comming?! al 2006-Aug-05 res.start(context.status, true) do |head,out| context.response_headers.each do |key, value| head[key] = value end context.response_cookies.each do |cookie| head['Set-Cookie'] = cookie end if context.response_cookies out.write(context.out) end context.close ensure $autoreload_dirty = false Og.manager.put_store if defined?(Og) and Og.respond_to?(:manager) and Og.manager end end end # Try to rewrite the path to a filename. def rewrite(req) if req.path_info == '/' || req.path_info == '' req.path_info = '/index.html' elsif req.path_info =~ /^([^.]+)$/ req.path_info = "#{$1}.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 =~ /^([^.]+)\.html$/ req.path_info = $1 end end end end