Guest User

Untitled

a guest
Mar 5th, 2015
283
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 15.00 KB | None | 0 0
  1. =begin
  2.  
  3. fcgi.rb 0.9.2 - fcgi.so compatible pure-ruby FastCGI library
  4.  
  5. fastcgi.rb Copyright (C) 2001 Eli Green
  6. fcgi.rb    Copyright (C) 2002-2003 MoonWolf <[email protected]>
  7. fcgi.rb    Copyright (C) 2004 Minero Aoki
  8. fcgi.rb    Copyright (C) 2011 saks and Julik Tarkhanov
  9. fcgi.rb    Copyright (C) 2012-2013 mva
  10.  
  11. =end
  12. trap('SIGTERM') { exit }
  13. trap('SIGPIPE','IGNORE')
  14.  
  15. begin
  16.   raise LoadError if ENV["USE_PURE_RUBY_FCGI"]
  17.   require "fcgi.so"
  18. rescue LoadError # Load the pure ruby version instead
  19.   # At this point we do have STDERR so put it to some good use
  20.   $stderr.puts "Your FCGI gem does not contain the FCGI shared library, running pure ruby instead"
  21.  
  22.   require 'socket'
  23.   require 'stringio'
  24.  
  25.   class FCGI
  26.  
  27.     def self.is_cgi?
  28.       begin
  29.         s = Socket.for_fd($stdin.fileno)
  30.         s.getpeername
  31.         false
  32.       rescue Errno::ENOTCONN
  33.         false
  34.       rescue Errno::ENOTSOCK, Errno::EINVAL
  35.         true
  36.       end
  37.     end
  38.  
  39.     def self.each(&block)
  40.       f = default_connection()
  41.       Server.new(f).each_request(&block)
  42.     ensure
  43.       f.close if f
  44.     end
  45.  
  46.     def self.each_request(&block)
  47.       f = default_connection()
  48.       Server.new(f).each_request(&block)
  49.     ensure
  50.       f.close if f
  51.     end
  52.  
  53.     def self.default_connection
  54.       ::Socket.for_fd($stdin.fileno)
  55.     end
  56.  
  57.  
  58.  
  59.     ProtocolVersion = 1
  60.  
  61.     # Record types
  62.     FCGI_BEGIN_REQUEST = 1
  63.     FCGI_ABORT_REQUEST = 2
  64.     FCGI_END_REQUEST = 3
  65.     FCGI_PARAMS = 4
  66.     FCGI_STDIN = 5
  67.     FCGI_STDOUT = 6
  68.     FCGI_STDERR = 7
  69.     FCGI_DATA = 8
  70.     FCGI_GET_VALUES = 9
  71.     FCGI_GET_VALUES_RESULT = 10
  72.     FCGI_UNKNOWN_TYPE = 11
  73.     FCGI_MAXTYPE = FCGI_UNKNOWN_TYPE
  74.  
  75.     FCGI_NULL_REQUEST_ID = 0
  76.  
  77.     # FCGI_BEGIN_REQUSET.role
  78.     FCGI_RESPONDER = 1
  79.     FCGI_AUTHORIZER = 2
  80.     FCGI_FILTER = 3
  81.  
  82.     # FCGI_BEGIN_REQUEST.flags
  83.     FCGI_KEEP_CONN = 1
  84.  
  85.     # FCGI_END_REQUEST.protocolStatus
  86.     FCGI_REQUEST_COMPLETE = 0
  87.     FCGI_CANT_MPX_CONN = 1
  88.     FCGI_OVERLOADED = 2
  89.     FCGI_UNKNOWN_ROLE = 3
  90.  
  91.  
  92.     class Server
  93.  
  94.       def initialize(server)
  95.         @server = server
  96.         @buffers = {}
  97.         @default_parameters = {
  98.           "FCGI_MAX_CONNS" => 1,
  99.           "FCGI_MAX_REQS"  => 1,
  100.           "FCGI_MPX_CONNS" => true
  101.         }
  102.       end
  103.  
  104.       def each_request(&block)
  105.         graceful = false
  106.         trap("SIGUSR1") { graceful = true }
  107.         while true
  108.           begin
  109.             session(&block)
  110.           rescue Errno::EPIPE, EOFError
  111.             # HTTP request is canceled by the remote user
  112.           end
  113.           exit 0 if graceful
  114.         end
  115.       end
  116.  
  117.       def session
  118.         sock, addr = *@server.accept
  119.         return unless sock
  120.         fsock = FastCGISocket.new(sock)
  121.         req = next_request(fsock)
  122.         yield req
  123.         respond_to req, fsock, FCGI_REQUEST_COMPLETE
  124.       ensure
  125.         sock.close if sock and not sock.closed?
  126.       end
  127.  
  128.       private
  129.  
  130.       def next_request(sock)
  131.         while rec = sock.read_record
  132.           if rec.management_record?
  133.             case rec.type
  134.             when FCGI_GET_VALUES
  135.               sock.send_record handle_GET_VALUES(rec)
  136.             else
  137.               sock.send_record UnknownTypeRecord.new(rec.request_id, rec.type)
  138.             end
  139.           else
  140.             case rec.type
  141.             when FCGI_BEGIN_REQUEST
  142.               @buffers[rec.request_id] = RecordBuffer.new(rec)
  143.             when FCGI_ABORT_REQUEST
  144.               raise "got ABORT_REQUEST"   # FIXME
  145.             else
  146.               buf = @buffers[rec.request_id]   or next # inactive request
  147.               buf.push rec
  148.               if buf.ready?
  149.                 @buffers.delete rec.request_id
  150.                 return buf.new_request
  151.               end
  152.             end
  153.           end
  154.         end
  155.         raise "must not happen: FCGI socket unexpected EOF"
  156.       end
  157.  
  158.       def handle_GET_VALUES(rec)
  159.         h = {}
  160.         rec.values.each_key do |name|
  161.           h[name] = @default_parameters[name]
  162.         end
  163.         ValuesRecord.new(FCGI_GET_VALUES_RESULT, rec.request_id, h)
  164.       end
  165.  
  166.       def respond_to(req, sock, status)
  167.         split_data(FCGI_STDOUT, req.id, req.out) do |rec|
  168.           sock.send_record rec
  169.         end
  170.         split_data(FCGI_STDERR, req.id, req.err) do |rec|
  171.           sock.send_record rec
  172.         end if req.err.length > 0
  173.         sock.send_record EndRequestRecord.new(req.id, 0, status)
  174.       end
  175.  
  176.       DATA_UNIT = 16384
  177.  
  178.       def split_data(type, id, f)
  179.         unless f.length == 0
  180.           f.rewind
  181.           while s = f.read(DATA_UNIT)
  182.             yield GenericDataRecord.new(type, id, s)
  183.           end
  184.         end
  185.         yield GenericDataRecord.new(type, id, '')
  186.       end
  187.  
  188.     end
  189.  
  190.  
  191.     class FastCGISocket
  192.       def initialize(sock)
  193.         @socket = sock
  194.       end
  195.  
  196.       def read_record
  197.         header = @socket.read(Record::HEADER_LENGTH) or return nil
  198.         return nil unless header.size == Record::HEADER_LENGTH
  199.         version, type, reqid, clen, padlen, reserved = *Record.parse_header(header)
  200.         Record.class_for(type).parse(reqid, read_record_body(clen, padlen))
  201.       end
  202.  
  203.       def read_record_body(clen, padlen)
  204.         buf = ''
  205.         while buf.length < clen
  206.           buf << @socket.read([1024, clen - buf.length].min)
  207.         end
  208.         @socket.read padlen if padlen
  209.         buf
  210.       end
  211.       private :read_record_body
  212.  
  213.       def send_record(rec)
  214.         @socket.write rec.serialize
  215.         @socket.flush
  216.       end
  217.     end
  218.  
  219.  
  220.     class RecordBuffer
  221.       def initialize(rec)
  222.         @begin_request = rec
  223.         @envs = []
  224.         @stdins = []
  225.         @datas = []
  226.       end
  227.  
  228.       def push(rec)
  229.         case rec
  230.         when ParamsRecord
  231.           @envs.push rec
  232.         when StdinDataRecord
  233.           @stdins.push rec
  234.         when DataRecord
  235.           @datas.push rec
  236.         else
  237.           raise "got unknown record: #{rec.class}"
  238.         end
  239.       end
  240.  
  241.       def ready?
  242.         case @begin_request.role
  243.         when FCGI_RESPONDER
  244.           completed?(@envs) and
  245.           completed?(@stdins)
  246.         when FCGI_AUTHORIZER
  247.           completed?(@envs)
  248.         when FCGI_FILTER
  249.           completed?(@envs) and
  250.           completed?(@stdins) and
  251.           completed?(@datas)
  252.         else
  253.           raise "unknown role: #{@begin_request.role}"
  254.         end
  255.       end
  256.  
  257.       def completed?(records)
  258.         records.last and records.last.empty?
  259.       end
  260.       private :completed?
  261.  
  262.       def new_request
  263.         Request.new(@begin_request.request_id, env(), stdin(), nil, nil, data())
  264.       end
  265.  
  266.       def env
  267.         h = {}
  268.         @envs.each {|rec| h.update rec.values }
  269.         h
  270.       end
  271.  
  272.       def stdin
  273.         StringIO.new(@stdins.inject('') {|buf, rec| buf << rec.flagment })
  274.       end
  275.  
  276.       def data
  277.         StringIO.new(@datas.inject('') {|buf, rec| buf << rec.flagment })
  278.       end
  279.     end
  280.  
  281.  
  282.     class Request
  283.       def initialize(id, env, stdin, stdout = nil, stderr = nil, data = nil)
  284.         @id = id
  285.         @env = env
  286.         @in = stdin
  287.         @out = stdout || StringIO.new
  288.         @err = stderr || StringIO.new
  289.         @data = data || StringIO.new
  290.       end
  291.  
  292.       attr_reader :id
  293.       attr_reader :env
  294.       attr_reader :in
  295.       attr_reader :out
  296.       attr_reader :err
  297.       attr_reader :data
  298.  
  299.       def finish   # for backword compatibility
  300.       end
  301.     end
  302.  
  303.  
  304.     class Record
  305.       # uint8_t  protocol_version;
  306.       # uint8_t  record_type;
  307.       # uint16_t request_id;     (big endian)
  308.       # uint16_t content_length; (big endian)
  309.       # uint8_t  padding_length;
  310.       # uint8_t  reserved;
  311.       HEADER_FORMAT = 'CCnnCC'
  312.       HEADER_LENGTH = 8
  313.  
  314.       def self.parse_header(buf)
  315.         return *buf.unpack(HEADER_FORMAT)
  316.       end
  317.  
  318.       def self.class_for(type)
  319.         RECORD_CLASS[type]
  320.       end
  321.  
  322.       def initialize(type, reqid)
  323.         @type = type
  324.         @request_id = reqid
  325.       end
  326.  
  327.       def version
  328.         ::FCGI::ProtocolVersion
  329.       end
  330.  
  331.       attr_reader :type
  332.       attr_reader :request_id
  333.  
  334.       def management_record?
  335.         @request_id == FCGI_NULL_REQUEST_ID
  336.       end
  337.  
  338.       def serialize
  339.         body = make_body()
  340.         padlen = body.length % 8
  341.         header = make_header(body.length, padlen)
  342.         header + body + "\000" * padlen
  343.       end
  344.  
  345.       private
  346.  
  347.       def make_header(clen, padlen)
  348.         [version(), @type, @request_id, clen, padlen, 0].pack(HEADER_FORMAT)
  349.       end
  350.     end
  351.  
  352.     class BeginRequestRecord < Record
  353.       # uint16_t role; (big endian)
  354.       # uint8_t  flags;
  355.       # uint8_t  reserved[5];
  356.       BODY_FORMAT = 'nCC5'
  357.  
  358.       def BeginRequestRecord.parse(id, body)
  359.         role, flags, *reserved = *body.unpack(BODY_FORMAT)
  360.         new(id, role, flags)
  361.       end
  362.  
  363.       def initialize(id, role, flags)
  364.         super FCGI_BEGIN_REQUEST, id
  365.         @role = role
  366.         @flags = flags
  367.       end
  368.  
  369.       attr_reader :role
  370.       attr_reader :flags
  371.  
  372.       def make_body
  373.         [@role, @flags, 0, 0, 0, 0, 0].pack(BODY_FORMAT)
  374.       end
  375.     end
  376.  
  377.     class AbortRequestRecord < Record
  378.       def AbortRequestRecord.parse(id, body)
  379.         new(id)
  380.       end
  381.  
  382.       def initialize(id)
  383.         super FCGI_ABORT_REQUEST, id
  384.       end
  385.     end
  386.  
  387.     class EndRequestRecord < Record
  388.       # uint32_t appStatus; (big endian)
  389.       # uint8_t  protocolStatus;
  390.       # uint8_t  reserved[3];
  391.       BODY_FORMAT = 'NCC3'
  392.  
  393.       def self.parse(id, body)
  394.         appstatus, protostatus, *reserved = *body.unpack(BODY_FORMAT)
  395.         new(id, appstatus, protostatus)
  396.       end
  397.  
  398.       def initialize(id, appstatus, protostatus)
  399.         super FCGI_END_REQUEST, id
  400.         @application_status = appstatus
  401.         @protocol_status = protostatus
  402.       end
  403.  
  404.       attr_reader :application_status
  405.       attr_reader :protocol_status
  406.  
  407.       private
  408.  
  409.       def make_body
  410.         [@application_status, @protocol_status, 0, 0, 0].pack(BODY_FORMAT)
  411.       end
  412.     end
  413.  
  414.     class UnknownTypeRecord < Record
  415.       # uint8_t type;
  416.       # uint8_t reserved[7];
  417.       BODY_FORMAT = 'CC7'
  418.  
  419.       def self.parse(id, body)
  420.         type, *reserved = *body.unpack(BODY_FORMAT)
  421.         new(id, type)
  422.       end
  423.  
  424.       def initialize(id, t)
  425.         super FCGI_UNKNOWN_TYPE, id
  426.         @unknown_type = t
  427.       end
  428.  
  429.       attr_reader :unknown_type
  430.  
  431.       private
  432.  
  433.       def make_body
  434.         [@unknown_type, 0, 0, 0, 0, 0, 0, 0].pack(BODY_FORMAT)
  435.       end
  436.     end
  437.  
  438.     class ValuesRecord < Record
  439.       def self.parse(id, body)
  440.         new(id, parse_values(body))
  441.       end
  442.  
  443.       def self.parse_values(buf)
  444.         result = {}
  445.         until buf.empty?
  446.           name, value = *read_pair(buf)
  447.           result[name] = value
  448.         end
  449.         result
  450.       end
  451.  
  452.       def self.read_pair(buf)
  453.         nlen = read_length(buf)
  454.         vlen = read_length(buf)
  455.         [buf.slice!(0, nlen), buf.slice!(0, vlen)]
  456.       end
  457.  
  458.  
  459.       if "".respond_to?(:bytes) # Ruby 1.9 string semantics
  460.         def self.read_length(buf)
  461.           if buf[0].bytes.first >> 7 == 0
  462.             buf.slice!(0,1)[0].bytes.first
  463.           else
  464.             buf.slice!(0,4).unpack('N')[0] & ((1<<31) - 1)
  465.           end
  466.         end
  467.       else # Ruby 1.8 string
  468.         def self.read_length(buf)
  469.           if buf[0] >> 7 == 0
  470.             buf.slice!(0,1)[0].bytes.first
  471.           else
  472.             buf.slice!(0,4).unpack('N')[0] & ((1<<31) - 1)
  473.           end
  474.         end
  475.       end
  476.  
  477.       def initialize(type, id, values)
  478.         super type, id
  479.         @values = values
  480.       end
  481.  
  482.       attr_reader :values
  483.  
  484.       private
  485.  
  486.       def make_body
  487.         buf = ''
  488.         @values.each do |name, value|
  489.           buf << serialize_length(name.length)
  490.           buf << serialize_length(value.length)
  491.           buf << name
  492.           buf << value
  493.         end
  494.         buf
  495.       end
  496.  
  497.       def serialize_length(len)
  498.         if len < 0x80
  499.         then len.chr
  500.         else [len | (1<<31)].pack('N')
  501.         end
  502.       end
  503.     end
  504.  
  505.     class GetValuesRecord < ValuesRecord
  506.       def initialize(id, values)
  507.         super FCGI_GET_VALUES, id, values
  508.       end
  509.     end
  510.  
  511.     class ParamsRecord < ValuesRecord
  512.       def initialize(id, values)
  513.         super FCGI_PARAMS, id, values
  514.       end
  515.  
  516.       def empty?
  517.         @values.empty?
  518.       end
  519.     end
  520.  
  521.     class GenericDataRecord < Record
  522.       def self.parse(id, body)
  523.         new(id, body)
  524.       end
  525.  
  526.       def initialize(type, id, flagment)
  527.         super type, id
  528.         @flagment = flagment
  529.       end
  530.  
  531.       attr_reader :flagment
  532.  
  533.       def empty?
  534.         @flagment.empty?
  535.       end
  536.  
  537.       private
  538.  
  539.       def make_body
  540.         if @flagment.respond_to? 'force_encoding' then
  541.           return @flagment.dup.force_encoding('BINARY')
  542.         else
  543.           return @flagment
  544.         end
  545.       end
  546.     end
  547.  
  548.     class StdinDataRecord < GenericDataRecord
  549.       def initialize(id, flagment)
  550.         super FCGI_STDIN, id, flagment
  551.       end
  552.     end
  553.  
  554.     class StdoutDataRecord < GenericDataRecord
  555.       def initialize(id, flagment)
  556.         super FCGI_STDOUT, id, flagment
  557.       end
  558.     end
  559.  
  560.     class DataRecord < GenericDataRecord
  561.       def initialize(id, flagment)
  562.         super FCGI_DATA, id, flagment
  563.       end
  564.     end
  565.  
  566.     class Record   # redefine
  567.       RECORD_CLASS = {
  568.         FCGI_GET_VALUES    => GetValuesRecord,
  569.  
  570.         FCGI_BEGIN_REQUEST => BeginRequestRecord,
  571.         FCGI_ABORT_REQUEST => AbortRequestRecord,
  572.         FCGI_PARAMS        => ParamsRecord,
  573.         FCGI_STDIN         => StdinDataRecord,
  574.         FCGI_DATA          => DataRecord,
  575.         FCGI_STDOUT        => StdoutDataRecord,
  576.         FCGI_END_REQUEST   => EndRequestRecord
  577.       }
  578.     end
  579.  
  580.   end # FCGI class
  581. end # begin
  582.  
  583. # There is no C version of 'each_cgi'
  584. # Note: for ruby-1.6.8 at least, the constants CGI_PARAMS/CGI_COOKIES
  585. # are defined within module 'CGI', even if you have subclassed it
  586.  
  587. class FCGI
  588.   def self.each_cgi(*args)
  589.     require 'cgi'
  590.  
  591.     eval(<<-EOS,TOPLEVEL_BINDING)
  592.     class CGI
  593.       public :env_table
  594.       def self.remove_params
  595.         if (const_defined?(:CGI_PARAMS))
  596.           remove_const(:CGI_PARAMS)
  597.           remove_const(:CGI_COOKIES)
  598.         end
  599.       end
  600.     end # ::CGI class
  601.  
  602.     class FCGI
  603.       class CGI < ::CGI
  604.         def initialize(request, *args)
  605.           ::CGI.remove_params
  606.           @request = request
  607.           super(*args)
  608.           @args = *args
  609.         end
  610.         def args
  611.           @args
  612.         end
  613.         def env_table
  614.           @request.env
  615.         end
  616.         def stdinput
  617.           @request.in
  618.         end
  619.         def stdoutput
  620.           @request.out
  621.         end
  622.       end # FCGI::CGI class
  623.     end # FCGI class
  624.     EOS
  625.  
  626.     if FCGI::is_cgi?
  627.       yield ::CGI.new(*args)
  628.     else
  629.       exit_requested = false
  630.       FCGI::each do |request|
  631.  
  632.         $stdout, $stderr = request.out, request.err
  633.  
  634.         yield CGI.new(request, *args)
  635.  
  636.         request.finish
  637.       end
  638.     end
  639.   end
  640. end
Advertisement
Add Comment
Please, Sign In to add comment