#!/usr/bin/env ruby require 'stringio' require 'fileutils' require 'fcgi_handler' def message(s) $stderr.puts "listener: #{s}" if ENV && ENV["DEBUG_GATEWAY"] end class RemoteCGI < CGI attr_accessor :stdinput, :stdoutput, :env_table def initialize(env_table, input = nil, output = nil) self.env_table = env_table self.stdinput = input || StringIO.new self.stdoutput = output || StringIO.new super() end def out(stream) # Ignore the requested output stream super(stdoutput) end end class Listener include DRbUndumped def initialize(timeout, socket_path) @socket = File.expand_path(socket_path) @mutex = Mutex.new @active = false @timeout = timeout @handler = RailsFCGIHandler.new @handler.extend DRbUndumped message 'opening socket' DRb.start_service("drbunix:#{@socket}", self) message 'entering process loop' @handler.process! self end def each_cgi(&cgi_block) @cgi_block = cgi_block message 'entering idle loop' loop do sleep @timeout rescue nil die! unless @active @active = false end end def process(env, input) message 'received request' @mutex.synchronize do @active = true message 'creating input stream' input_stream = StringIO.new(input) message 'building CGI instance' cgi = RemoteCGI.new(eval(env), input_stream) message 'yielding to fcgi handler' @cgi_block.call cgi message 'yield finished -- sending output' cgi.stdoutput.seek(0) output = cgi.stdoutput.read return output end end def die! message 'shutting down' DRb.stop_service FileUtils.rm_f @socket Kernel.exit 0 end end socket_path = ARGV.shift timeout = (ARGV.shift || 90).to_i Listener.new(timeout, socket_path)