lib/rack-cgi.rb in rack-cgi-0.2.3 vs lib/rack-cgi.rb in rack-cgi-0.3.0

- old
+ new

@@ -1,165 +2 @@ -require 'childprocess' - -module Rack - class CGI - class Executable - def self.=~ rhs - ::File.executable? rhs - end - end - - def initialize app, args = {} - @app = app - @opts = args.select {|k, _| k.is_a? Symbol} - @rules = args.select {|k, _| !k.is_a? Symbol} - - @root = @opts[:cgi_path] - if @root !~ /^\// - @root = ::File.join(Dir.pwd, @root) - end - - @index = @opts[:index] || [] - @index = [@index] if not @index.is_a? Hash - end - - def solve_path path - path = ::File.join(@root, path) - if ::File.directory? path - @index.each do |f| - path2 = ::File.join(path, f) - return path2 if ::File.file? path2 - end - else - return path if ::File.file? path - end - nil - end - - def cgi_env env, path - env = env.select {|k, _| k =~ /^[A-Z]/} - env['SCRIPT_FILENAME'] = path - env['DOCUMENT_ROOT'] = @root - env['REDIRECT_STATUS'] = "200" - env - end - - def match_cgi_rule path - @rules.each do |m, r| - if m =~ path - return r - end - end - return nil - end - - def run_cgi rule, path, env - if rule.empty? - args = [path] - else - args = [rule, path] - end - - process = ChildProcess.build(*args) - process.io.stdout = Tempfile.new('rack-cgi-stdout') - process.io.stderr = Tempfile.new('rack-cgi-stderr') - env.each do |k, v| - process.environment[k] = v - end - process.cwd = Dir.pwd - process.start - process.wait - - cont_out = ::File.read(process.io.stdout.path) - cont_err = ::File.read(process.io.stderr.path) - process.io.stdout.unlink - process.io.stderr.unlink - - [process.exit_code, cont_out, cont_err] - end - - def split_header_content output - lines = output.lines.to_a - header = [] - - until lines.empty? - l = lines.shift - if l == "\n" or l == "\r\n" - # find break line between header and content - return header.join, lines.join - elsif l =~ /:/ - header << l - else - # content break header ruler, so deal as no header - return "", output - end - end - - # deal all content as header - return output, "" - end - - def parse_output output - header, content = split_header_content output - - h = {} - header.each_line do |l| - k, v = l.split ':', 2 - k.strip! - v.strip! - h[k.downcase] = [k, v] - end - - if h['status'] - status = h['status'][1].to_i - h.delete 'status' - else - status = 200 - end - - header_hash = Hash[h.values] - - [status, header_hash, [content]] - end - - def report_error code, out, err, cgi_env - h = {'Content-Type' => 'text/plain'} - status = 500 - reports = [] - - reports << "CGI Error!\n\n" - reports << "stdout output:\n" - reports << out - reports << "\n" - reports << "stderr output:\n" - reports << err - reports << "\n" - reports << "environments:\n" - cgi_env.each do |k, v| - reports << "#{k} => #{v}\n" - end - - [status, h, reports] - end - - def call(env) - path = solve_path env["PATH_INFO"] - if not path - return @app.call(env) - end - - rule = match_cgi_rule path - if not rule - return @app.call(env) - end - - cgi_env = cgi_env(env, path) - code, out, err = run_cgi rule, path, cgi_env - if code == 0 - parse_output out - else - report_error code, out, err, cgi_env - end - end - end -end - +require_relative 'rack/cgi'