about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2015-01-22 05:02:11 +0000
committerEric Wong <e@80x24.org>2015-02-04 19:33:53 +0000
commitfd937863d67d5a886df2a53f1736d643fbb91e4a (patch)
treed90e36492578823dc3c03a2a8bb5b7d928bb6cc2
parent6f0236fff6c1026562479a42228b30a5e5d95bba (diff)
downloadunicorn-fd937863d67d5a886df2a53f1736d643fbb91e4a.tar.gz
While it was technically interesting and fun to tunnel arbitrary
protocols over a semi-compliant Rack interface, nobody actually does
it (and anybody who does can look in our git history).  This was
from back in 2009 when this was one of the few servers that could
handle chunked uploads,were one of the few users of chunked uploads,
nowadays everyone does it! (or do they? :)

A newer version of exec_cgi.rb still lives on in the repository of
yet another horribly-named server, but there's no point in bloating
the installation footprint of somewhat popular server such as unicorn.
-rw-r--r--examples/git.ru13
-rw-r--r--lib/unicorn/app/exec_cgi.rb154
-rw-r--r--lib/unicorn/app/inetd.rb109
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