#!/usr/local/bin/ruby # # cgi.rb -- HTTPRequest/HTTPResponse for CGI environment # # Author: IPR -- Internet Programming with Ruby -- writers # Copyright (c) 2003 Internet Programming with Ruby writers. All rights # reserved. # # $IPR$ require "webrick/httprequest" require "webrick/httpresponse" require "webrick/config" require "stringio" module WEBrick module Config CGI = HTTP.dup.update( :ServerSoftware => ENV["SERVER_SOFTWARE"], :RunOnCGI => true, # to detect if it runs on CGI. :NPH => false # set true to run as NPH script. ) end class CGI class Socket include Enumerable private def initialize(config, env, stdin, stdout) @env = env @header_part = StringIO.new @body_part = stdin @out_port = stdout @server_addr = @env['SERVER_ADDR'] || "0.0.0.0" @server_name = @env['SERVER_NAME'] @server_port = @env['SERVER_PORT'] @remote_addr = @env['REMOTE_ADDR'] @remote_host = @env['REMOTE_HOST'] || @remote_addr @remote_port = @env['REMOTE_PORT'] || 0 begin setup_header rescue Exception => ex raise Errno::EPIPE, "invalid CGI environment" end @header_part << CRLF @header_part.rewind end def setup_header req_line = "" req_line << @env['REQUEST_METHOD'] << ' ' req_line << @env['SCRIPT_NAME'] req_line << @env['PATH_INFO'] if @env['PATH_INFO'] if @env['QUERY_STRING'] req_line << '?' << @env['QUERY_STRING'] end req_line << ' ' << @env['SERVER_PROTOCOL'] @header_part << req_line << CRLF add_header("CONTENT_TYPE", "Content-Type") add_header("CONTENT_LENGTH", "Content-length") @env.each_key do |name| if /^HTTP_(.*)/ =~ name add_header(name, $1.gsub(/_/, '-')) end end end def add_header(envname, hdrname) if @env[envname] && !@env[envname].empty? @header_part << hdrname << ': ' << @env[envname] << CRLF end end def input @header_part.eof? ? @body_part : @header_part end public def peeraddr [nil, @remote_port, @remote_host, @remote_addr] end def addr [nil, @server_port, @server_name, @server_addr] end def gets(eol=LF) input.gets(eol) end def read(size=nil) input.read(size) end def each input.each{|line| yield(line) } end def <<(data) @out_port << data end end def initialize(config, *options) @config = default_config.dup.update(config) @logger = @config[:Logger] @options = options end def default_config WEBrick::Config::CGI end def start sock = WEBrick::CGI::Socket.new(@config, ENV, $stdin, $stdout) req = HTTPRequest.new(@config) res = HTTPResponse.new(@config) unless @config[:NPH] or defined?(MOD_RUBY) def res.status_line "" end end begin req.parse(sock) req.script_name = (ENV['SCRIPT_NAME'] || "").dup if ENV['PATH_INFO'].nil? || ENV['PATH_INFO'].empty? req.path_info = nil else req.path_info = ENV['PATH_INFO'].dup end res.request_method = req.request_method res.request_uri = req.request_uri res.request_http_version = req.http_version res.keep_alive = req.keep_alive? self.service(req, res) rescue HTTPStatus::Error => ex res.set_error(ex) rescue HTTPStatus::Status => ex res.status = ex.code rescue Exception => ex @logger.error(ex) res.set_error(ex, true) ensure req.fixup res.send_response(sock) end end def service(req, res) method_name = "do_" + req.request_method.gsub(/-/, "_") if respond_to?(method_name) __send__(method_name, req, res) else raise HTTPStatus::MethodNotAllowed, "unsupported method `#{req.request_method}'." end end end end if $0 == __FILE__ require "pp" module MyApp def do_GET(req, res) res['content-type'] = 'text/html; charset=iso-8859-1' if req.path_info.nil? or req.path_info.empty? res["Status"] = WEBrick::HTTPStatus::Found.code res.set_redirect(WEBrick::HTTPStatus::Found, req.script_name + "/") end res.body =<<-_end_of_html_
text:
file:

Request

#{WEBrick::HTMLUtils::escape(PP::pp(req, "", 80))}

Response

#{WEBrick::HTMLUtils::escape(PP::pp(res, "", 80))}
_end_of_html_ end def do_POST(req, res) res['content-type'] = 'text/html; charset=iso-8859-1' if req["content-length"].to_i > 1024*10 raise WEBrick::HTTPStatus::Forbidden, "file size too large" end res.body =<<-_end_of_html_

Query Parameters

#{WEBrick::HTMLUtils::escape(req.query.inspect)}
return

Request

#{WEBrick::HTMLUtils::escape(PP::pp(req, "", 80))}

Response

#{WEBrick::HTMLUtils::escape(PP::pp(res, "", 80))}
_end_of_html_ end end if $stdin.tty? require "webrick" class MyServlet < WEBrick::HTTPServlet::AbstractServlet include MyApp end httpd = WEBrick::HTTPServer.new(:Port => 8080) httpd.mount("/", MyServlet) trap(:INT){ httpd.shutdown } httpd.start else class MyCGI < WEBrick::CGI include MyApp end cgi = MyCGI.new(:Logger => WEBrick::Log.new($stderr)) cgi.start end end