class Pione::Util::CGIExecutor

CGIExecutor is a execution helper for CGI programs.

Public Class Methods

new(cgi_path, cgi_info, chdir, timeout) click to toggle source

@param [Pathname] cgi_path

path of the CGI program

@param [CGIInfo] cgi_info

various informations for CGI program
# File lib/pione/util/cgi.rb, line 144
def initialize(cgi_path, cgi_info, chdir, timeout)
  @cgi_path = cgi_path
  @cgi_info = cgi_info
  @chdir = chdir
  @timeout = timeout
  @umask = 077
  @cgi_stdin = Temppath.create
  @cgi_stdout = Temppath.create
  @pid = nil
end

Public Instance Methods

exec() click to toggle source

Execute the CGI program.

# File lib/pione/util/cgi.rb, line 156
def exec
  unless @cgi_path.exist?
    raise CGIError.not_exist(@cgi_path)
  end

  env = @cgi_info.create_env
  options = create_options
  args = @cgi_info.create_arguments

  Timeout.timeout(@timeout) do
    @pid = Kernel.spawn(env, @cgi_path.to_s, *args, options)
    Process.waitpid(@pid)
    if @cgi_stdout.exist?
      return analyze_response(Location[@cgi_stdout].read)
    else
      raise CGIError.response_not_found
    end
  end
rescue Timeout::Error
  if @pid
    begin
      Process.kill(15, @pid)
    rescue
    ensure
      CGIError.timeouted
    end
  end
rescue Errno::EACCES => e
  CGIError.cannot_execute_cgi(@cgi_path)
end

Private Instance Methods

analyze_response(stdout) click to toggle source
# File lib/pione/util/cgi.rb, line 205
def analyze_response(stdout)
  cgi_response = CGIResponse.new

  if nph?
    cgi_response.nph = true
    cgi_response.body = stdout
  else
    cgi_response.nph = false

    # parse headers
    headers, body = stdout.split(/\r\n\r\n|\r\r|\n\n/, 2)
    header = headers.split(/\r\n|\r|\n/).each_with_object(Hash.new) do |line, table|
      name, value = line.split(/:[\s\t]*/, 2)
      if name.nil? or name.size == 0 or /\s/.match(name) or value.nil?
        raise CGIError.invalid_response_header(line)
      else
        table[name.downcase] = value
      end
    end

    # content-type
    if header.has_key?("content-type")
      cgi_response.content_type = header["content-type"]
    else
      raise CGIError.content_type_not_found
    end

    # location
    if header["location"]
      begin
        uri = URI.parse(header["location"])
        cgi_response.location = header["location"]
      rescue
        raise CGIError.invalid_location(header["location"])
      end
    end

    # status
    if header["status"]
      code, reason_phrase = status.split(/\s+/, 2)
      if /\d\d\d/.match(code)
        cgi_response.status_code = code
        cgi_response.reason_phrase = reason_phrase
      else
        raise CGIError.invalid_status(code)
      end
    end

    # body
    cgi_response.body = body
  end

  return cgi_response
end
create_options() click to toggle source
# File lib/pione/util/cgi.rb, line 193
def create_options
  options = Hash.new
  options[:chdir] = @chdir.path.to_s
  options[:umask] = @umask
  if @cgi_info.body
    Location[@cgi_stdin].write(@cgi_info.body)
    options[:in] = @cgi_stdin.to_s
  end
  options[:out] = @cgi_stdout.to_s
  return options
end
nph?() click to toggle source
# File lib/pione/util/cgi.rb, line 189
def nph?
  Pathname.new(@cgi_path).basename.to_s.start_with?("nph-")
end