123456789_123456789_123456789_123456789_123456789_

Class: WEBrick::HTTPServlet::CGIHandler

Relationships & Source Files
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
Instance Chain:
Inherits: WEBrick::HTTPServlet::AbstractServlet
Defined in: lib/webrick/httpservlet/cgihandler.rb

Overview

Servlet for handling ::WEBrick::CGI scripts

Example:

server.mount('/cgi/my_script', WEBrick::HTTPServlet::CGIHandler,
             '/path/to/my_script')

Constant Summary

Class Method Summary

AbstractServlet - Inherited

.get_instance

Factory for servlet instances that will handle a request from server using options from the mount point.

.new

Initializes a new servlet for server using options which are stored as-is in @options.

Instance Method Summary

AbstractServlet - Inherited

#do_GET

Raises a NotFound exception.

#do_HEAD

Dispatches to do_GET.

#do_OPTIONS

Returns the allowed HTTP request methods.

#service

Dispatches to a do_ method based on req if such a method is available.

#redirect_to_directory_uri

Redirects to a path ending in /.

Constructor Details

.new(server, name) ⇒ CGIHandler

Creates a new ::WEBrick::CGI script servlet for the script at name

[ GitHub ]

  
# File 'lib/webrick/httpservlet/cgihandler.rb', line 35

def initialize(server, name)
  super(server, name)
  @script_filename = name
  @tempdir = server[:TempDir]
  @cgicmd = "#{CGIRunner} #{server[:CGIInterpreter]}"
end

Instance Method Details

#do_GET(req, res) Also known as: #do_POST

This method is for internal use only.

Raises:

  • (HTTPStatus::InternalServerError)
[ GitHub ]

  
# File 'lib/webrick/httpservlet/cgihandler.rb', line 44

def do_GET(req, res)
  cgi_in = IO::popen(@cgicmd, "wb")
  cgi_out = Tempfile.new("webrick.cgiout.", @tempdir, mode: IO::BINARY)
  cgi_out.set_encoding("ASCII-8BIT")
  cgi_err = Tempfile.new("webrick.cgierr.", @tempdir, mode: IO::BINARY)
  cgi_err.set_encoding("ASCII-8BIT")
  begin
    cgi_in.sync = true
    meta = req.meta_vars
    meta["SCRIPT_FILENAME"] = @script_filename
    meta["PATH"] = @config[:CGIPathEnv]
    meta.delete("HTTP_PROXY")
    if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
      meta["SystemRoot"] = ENV["SystemRoot"]
    end
    dump = Marshal.dump(meta)

    cgi_in.write("%8d" % cgi_out.path.bytesize)
    cgi_in.write(cgi_out.path)
    cgi_in.write("%8d" % cgi_err.path.bytesize)
    cgi_in.write(cgi_err.path)
    cgi_in.write("%8d" % dump.bytesize)
    cgi_in.write(dump)

    req.body { |chunk| cgi_in.write(chunk) }
  ensure
    cgi_in.close
    status = $?.exitstatus
    sleep 0.1 if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
    data = cgi_out.read
    cgi_out.close(true)
    if errmsg = cgi_err.read
      if errmsg.bytesize > 0
        @logger.error("CGIHandler: #{@script_filename}:\n" + errmsg)
      end
    end
    cgi_err.close(true)
  end

  if status != 0
    @logger.error("CGIHandler: #{@script_filename} exit with #{status}")
  end

  data = "" unless data
  raw_header, body = data.split(/^[\xd\xa]+/, 2)
  raise HTTPStatus::InternalServerError,
    "Premature end of script headers: #{@script_filename}" if body.nil?

  begin
    header = HTTPUtils::parse_header(raw_header)
    if /^(\d+)/ =~ header['status'][0]
      res.status = $1.to_i
      header.delete('status')
    end
    if header.has_key?('location')
      # RFC 3875 6.2.3, 6.2.4
      res.status = 302 unless (300...400) === res.status
    end
    if header.has_key?('set-cookie')
      header['set-cookie'].each{|k|
        res.cookies << Cookie.parse_set_cookie(k)
      }
      header.delete('set-cookie')
    end
    header.each{|key, val| res[key] = val.join(", ") }
  rescue => ex
    raise HTTPStatus::InternalServerError, ex.message
  end
  res.body = body
end

#do_POST(req, res)

This method is for internal use only.

Alias for #do_GET.

[ GitHub ]

  
# File 'lib/webrick/httpservlet/cgihandler.rb', line 114

alias do_POST do_GET