#!/usr/bin/ruby require 'webrick/httprequest' require 'webrick/httpresponse' require 'webrick/config' require 'stringio' module WEBrick class CGISocket private def initialize(env = ENV, stdin = $stdin, stdout = $stdout) @env = env @header_part = StringIO.new @body_part = stdin @out_port = stdout @server_addr = '0.0.0.0' @server_host = @env['SERVER_HOST'] || @server_addr @server_port = @env['SERVER_PORT'] || nil @remote_addr = @env['REMOTE_ADDR'] @remote_host = @env['REMOTE_HOST'] || @remote_addr begin setup_header rescue Exception raise Errno::EPIPE, 'invalid CGI environment' end @header_part << LF @header_part.rewind end def setup_header request_line = @env['REQUEST_METHOD'] + ' ' + @env['SCRIPT_NAME'] request_line << '?' + @env['QUERY_STRING'] if @env['QUERY_STRING'] request_line << ' ' + @env['SERVER_PROTOCOL'] if @env['SERVER_PROTOCOL'] @header_part << request_line + LF add_header('CONTENT_LENGTH', 'Content-Length') add_header('CONTENT_TYPE', 'Content-Type') add_header('SERVER_SOFTWARE', 'Server') if @env['AUTH_TYPE'] && !@env['AUTH_TYPE'].empty? @header_part << 'Authorization: ' + @env['AUTH_TYPE'] + ' ' + LF end ENV.each_key do |name| if /^HTTP_/ =~ name add_header(name, name.gsub(/_/, '-')) end end end def add_header(envname, hdrname) if @env[envname] && !@env[envname].empty? @header_part << hdrname + ': ' + @env[envname] + LF end end public def peeraddr [nil, nil, @remote_host, @remote_addr] end def addr [nil, @server_port, @server_host, @server_addr] end def gets(eol = LF) unless @header_part.eof? @header_part.gets(eol) else @body_part.gets(eol) end end def read(size = nil) unless @header_part.eof? @header_part.read(size) else @body_part.read(size) end end def <<(data) @out_port << data end def self.wrap(config = Config::HTTP, env = ENV, stdin = $stdin) cgisock = self.new(env, stdin) req = HTTPRequest.new(config) req.parse(cgisock) req.script_name = (ENV['SCRIPT_NAME'] || "").dup if ENV['PATH_INFO'] unless ENV['PATH_INFO'].empty? req.path_info = ENV['PATH_INFO'].dup else req.path_info = '' end else req.path_info = nil end config = config.dup config[:ServerSoftware] = req['server'] # XXX: res = HTTPResponse.new(config) class << res def status_line "" end 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? if block_given? yield(cgisock, req, res) req.fixup nil else [cgisock, req, res] end end end end if __FILE__ == $0 begin require 'logger' config = WEBrick::Config::HTTP.dup config[:Logger] = Logger.new(STDERR) WEBrick::CGISocket.wrap(config) do |sock, req, res| res['content-type'] = 'text/plain; charset=iso-8859-1' res.chunked = true if req.http_version > '1.0' res.body << "BEGIN: CGI environment -> HTTP request:\n" res.body << req.to_s res.body << "END\n\n" res.body << "BEGIN: WEBrick::HTTPRequest:\n" res.body << req.inspect res.body << "\nEND\n\n" t = '' res.setup_header # XXX: this is only for self-test. res.send_header(t) res.body << "BEGIN: WEBrick::HTTPResponse header:\n" res.body << t res.body << "\nEND\n\n" res.send_response(sock) end rescue Exception puts "Content-Type: text/plain; charset=iso-8859-1" puts puts "BEGIN: excpetion:" puts $! puts $@ puts "END" end end