diff options
Diffstat (limited to 'lib/unicorn/app/exec_cgi.rb')
-rw-r--r-- | lib/unicorn/app/exec_cgi.rb | 154 |
1 files changed, 0 insertions, 154 deletions
diff --git a/lib/unicorn/app/exec_cgi.rb b/lib/unicorn/app/exec_cgi.rb deleted file mode 100644 index 232b681..0000000 --- a/lib/unicorn/app/exec_cgi.rb +++ /dev/null @@ -1,154 +0,0 @@ -# -*- encoding: binary -*- -# :enddoc: -require 'unicorn' - -module Unicorn::App - - # This class is highly experimental (even more so than the rest of Unicorn) - # and has never run anything other than cgit. - class ExecCgi < Struct.new(:args) - - CHUNK_SIZE = 16384 - PASS_VARS = %w( - CONTENT_LENGTH - CONTENT_TYPE - GATEWAY_INTERFACE - AUTH_TYPE - PATH_INFO - PATH_TRANSLATED - QUERY_STRING - REMOTE_ADDR - REMOTE_HOST - REMOTE_IDENT - REMOTE_USER - REQUEST_METHOD - SERVER_NAME - SERVER_PORT - SERVER_PROTOCOL - SERVER_SOFTWARE - ).map { |x| x.freeze } # frozen strings are faster for Hash assignments - - class Body < Unicorn::TmpIO - def body_offset=(n) - sysseek(@body_offset = n) - end - - def each - sysseek @body_offset - # don't use a preallocated buffer for sysread since we can't - # guarantee an actual socket is consuming the yielded string - # (or if somebody is pushing to an array for eventual concatenation - begin - yield sysread(CHUNK_SIZE) - rescue EOFError - break - end while true - end - end - - # Intializes the app, example of usage in a config.ru - # map "/cgit" do - # run Unicorn::App::ExecCgi.new("/path/to/cgit.cgi") - # end - def initialize(*args) - self.args = args - first = args[0] or - raise ArgumentError, "need path to executable" - first[0] == ?/ or args[0] = ::File.expand_path(first) - File.executable?(args[0]) or - raise ArgumentError, "#{args[0]} is not executable" - end - - # Calls the app - def call(env) - out, err = Body.new, Unicorn::TmpIO.new - inp = force_file_input(env) - pid = fork { run_child(inp, out, err, env) } - inp.close - pid, status = Process.waitpid2(pid) - write_errors(env, err, status) if err.stat.size > 0 - err.close - - return parse_output!(out) if status.success? - out.close - [ 500, { 'Content-Length' => '0', 'Content-Type' => 'text/plain' }, [] ] - end - - private - - def run_child(inp, out, err, env) - PASS_VARS.each do |key| - val = env[key] or next - ENV[key] = val - end - ENV['SCRIPT_NAME'] = args[0] - ENV['GATEWAY_INTERFACE'] = 'CGI/1.1' - env.keys.grep(/^HTTP_/) { |key| ENV[key] = env[key] } - - $stdin.reopen(inp) - $stdout.reopen(out) - $stderr.reopen(err) - exec(*args) - end - - # Extracts headers from CGI out, will change the offset of out. - # This returns a standard Rack-compatible return value: - # [ 200, HeadersHash, body ] - def parse_output!(out) - size = out.stat.size - out.sysseek(0) - head = out.sysread(CHUNK_SIZE) - offset = 2 - head, body = head.split(/\n\n/, 2) - if body.nil? - head, body = head.split(/\r\n\r\n/, 2) - offset = 4 - end - offset += head.length - out.body_offset = offset - size -= offset - prev = nil - headers = Rack::Utils::HeaderHash.new - head.split(/\r?\n/).each do |line| - case line - when /^([A-Za-z0-9-]+):\s*(.*)$/ then headers[prev = $1] = $2 - when /^[ \t]/ then headers[prev] << "\n#{line}" if prev - end - end - status = headers.delete("Status") || 200 - headers['Content-Length'] = size.to_s - [ status, headers, out ] - end - - # ensures rack.input is a file handle that we can redirect stdin to - def force_file_input(env) - inp = env['rack.input'] - # inp could be a StringIO or StringIO-like object - if inp.respond_to?(:size) && inp.size == 0 - ::File.open('/dev/null', 'rb') - else - tmp = Unicorn::TmpIO.new - - buf = inp.read(CHUNK_SIZE) - begin - tmp.syswrite(buf) - end while inp.read(CHUNK_SIZE, buf) - tmp.sysseek(0) - tmp - end - end - - # rack.errors this may not be an IO object, so we couldn't - # just redirect the CGI executable to that earlier. - def write_errors(env, err, status) - err.seek(0) - dst = env['rack.errors'] - pid = status.pid - dst.write("#{pid}: #{args.inspect} status=#{status} stderr:\n") - err.each_line { |line| dst.write("#{pid}: #{line}") } - dst.flush - end - - end - -end |