diff options
-rw-r--r-- | examples/git.ru | 13 | ||||
-rw-r--r-- | lib/unicorn/app/exec_cgi.rb | 154 | ||||
-rw-r--r-- | lib/unicorn/app/inetd.rb | 109 |
3 files changed, 0 insertions, 276 deletions
diff --git a/examples/git.ru b/examples/git.ru deleted file mode 100644 index 59a31c9..0000000 --- a/examples/git.ru +++ /dev/null @@ -1,13 +0,0 @@ -#\-E none - -# See http://thread.gmane.org/gmane.comp.web.curl.general/10473/raw on -# how to setup git for this. A better version of the above patch was -# accepted and committed on June 15, 2009, so you can pull the latest -# curl CVS snapshot to try this out. -require 'unicorn/app/inetd' - -use Rack::Lint -use Rack::Chunked # important! -run Unicorn::App::Inetd.new( - *%w(git daemon --verbose --inetd --export-all --base-path=/home/ew/unicorn) -) 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 diff --git a/lib/unicorn/app/inetd.rb b/lib/unicorn/app/inetd.rb deleted file mode 100644 index 13b6624..0000000 --- a/lib/unicorn/app/inetd.rb +++ /dev/null @@ -1,109 +0,0 @@ -# -*- encoding: binary -*- -# :enddoc: -# Copyright (c) 2009 Eric Wong -# You can redistribute it and/or modify it under the same terms as Ruby 1.8 or -# the GPLv2+ (GPLv3+ preferred) - -# this class *must* be used with Rack::Chunked -module Unicorn::App - class Inetd < Struct.new(:cmd) - - class CatBody < Struct.new(:errors, :err_rd, :out_rd, :pid_map) - def initialize(env, cmd) - self.errors = env['rack.errors'] - in_rd, in_wr = IO.pipe - self.err_rd, err_wr = IO.pipe - self.out_rd, out_wr = IO.pipe - - cmd_pid = fork { - inp, out, err = (0..2).map { |i| IO.new(i) } - inp.reopen(in_rd) - out.reopen(out_wr) - err.reopen(err_wr) - [ in_rd, in_wr, err_rd, err_wr, out_rd, out_wr ].each { |i| i.close } - exec(*cmd) - } - [ in_rd, err_wr, out_wr ].each { |io| io.close } - [ in_wr, err_rd, out_rd ].each { |io| io.binmode } - in_wr.sync = true - - # Unfortunately, input here must be processed inside a seperate - # thread/process using blocking I/O since env['rack.input'] is not - # IO.select-able and attempting to make it so would trip Rack::Lint - inp_pid = fork { - input = env['rack.input'] - [ err_rd, out_rd ].each { |io| io.close } - - # this is dependent on input.read having readpartial semantics: - buf = input.read(16384) - begin - in_wr.write(buf) - end while input.read(16384, buf) - } - in_wr.close - self.pid_map = { - inp_pid => 'input streamer', - cmd_pid => cmd.inspect, - } - end - - def each - begin - rd, = IO.select([err_rd, out_rd]) - rd && rd.first or next - - if rd.include?(err_rd) - begin - errors.write(err_rd.read_nonblock(16384)) - rescue Errno::EINTR - rescue Errno::EAGAIN - break - end while true - end - - rd.include?(out_rd) or next - - begin - yield out_rd.read_nonblock(16384) - rescue Errno::EINTR - rescue Errno::EAGAIN - break - end while true - rescue EOFError,Errno::EPIPE,Errno::EBADF,Errno::EINVAL - break - end while true - - self - end - - def close - pid_map.each { |pid, str| - begin - pid, status = Process.waitpid2(pid) - status.success? or - errors.write("#{str}: #{status.inspect} (PID:#{pid})\n") - rescue Errno::ECHILD - errors.write("Failed to reap #{str} (PID:#{pid})\n") - end - } - out_rd.close - err_rd.close - end - - end - - def initialize(*cmd) - self.cmd = cmd - end - - def call(env) - /\A100-continue\z/i =~ env[Unicorn::Const::HTTP_EXPECT] and - return [ 100, {} , [] ] - - [ 200, { 'Content-Type' => 'application/octet-stream' }, - CatBody.new(env, cmd) ] - end - - end - -end |