--- /dev/null
+#!/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)