1# 2# cgihandler.rb -- CGIHandler Class 3# 4# Author: IPR -- Internet Programming with Ruby -- writers 5# Copyright (c) 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou 6# Copyright (c) 2002 Internet Programming with Ruby writers. All rights 7# reserved. 8# 9# $IPR: cgihandler.rb,v 1.27 2003/03/21 19:56:01 gotoyuzo Exp $ 10 11require 'rbconfig' 12require 'tempfile' 13require 'webrick/config' 14require 'webrick/httpservlet/abstract' 15 16module WEBrick 17 module HTTPServlet 18 19 ## 20 # Servlet for handling CGI scripts 21 # 22 # Example: 23 # 24 # server.mount('/cgi/my_script', WEBrick::HTTPServlet::CGIHandler, 25 # '/path/to/my_script') 26 27 class CGIHandler < AbstractServlet 28 Ruby = RbConfig.ruby # :nodoc: 29 CGIRunner = "\"#{Ruby}\" \"#{WEBrick::Config::LIBDIR}/httpservlet/cgi_runner.rb\"" # :nodoc: 30 31 ## 32 # Creates a new CGI script servlet for the script at +name+ 33 34 def initialize(server, name) 35 super(server, name) 36 @script_filename = name 37 @tempdir = server[:TempDir] 38 @cgicmd = "#{CGIRunner} #{server[:CGIInterpreter]}" 39 end 40 41 # :stopdoc: 42 43 def do_GET(req, res) 44 data = nil 45 status = -1 46 47 cgi_in = IO::popen(@cgicmd, "wb") 48 cgi_out = Tempfile.new("webrick.cgiout.", @tempdir, mode: IO::BINARY) 49 cgi_out.set_encoding("ASCII-8BIT") 50 cgi_err = Tempfile.new("webrick.cgierr.", @tempdir, mode: IO::BINARY) 51 cgi_err.set_encoding("ASCII-8BIT") 52 begin 53 cgi_in.sync = true 54 meta = req.meta_vars 55 meta["SCRIPT_FILENAME"] = @script_filename 56 meta["PATH"] = @config[:CGIPathEnv] 57 if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM 58 meta["SystemRoot"] = ENV["SystemRoot"] 59 end 60 dump = Marshal.dump(meta) 61 62 cgi_in.write("%8d" % cgi_out.path.bytesize) 63 cgi_in.write(cgi_out.path) 64 cgi_in.write("%8d" % cgi_err.path.bytesize) 65 cgi_in.write(cgi_err.path) 66 cgi_in.write("%8d" % dump.bytesize) 67 cgi_in.write(dump) 68 69 if req.body and req.body.bytesize > 0 70 cgi_in.write(req.body) 71 end 72 ensure 73 cgi_in.close 74 status = $?.exitstatus 75 sleep 0.1 if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM 76 data = cgi_out.read 77 cgi_out.close(true) 78 if errmsg = cgi_err.read 79 if errmsg.bytesize > 0 80 @logger.error("CGIHandler: #{@script_filename}:\n" + errmsg) 81 end 82 end 83 cgi_err.close(true) 84 end 85 86 if status != 0 87 @logger.error("CGIHandler: #{@script_filename} exit with #{status}") 88 end 89 90 data = "" unless data 91 raw_header, body = data.split(/^[\xd\xa]+/, 2) 92 raise HTTPStatus::InternalServerError, 93 "Premature end of script headers: #{@script_filename}" if body.nil? 94 95 begin 96 header = HTTPUtils::parse_header(raw_header) 97 if /^(\d+)/ =~ header['status'][0] 98 res.status = $1.to_i 99 header.delete('status') 100 end 101 if header.has_key?('location') 102 # RFC 3875 6.2.3, 6.2.4 103 res.status = 302 unless (300...400) === res.status 104 end 105 if header.has_key?('set-cookie') 106 header['set-cookie'].each{|k| 107 res.cookies << Cookie.parse_set_cookie(k) 108 } 109 header.delete('set-cookie') 110 end 111 header.each{|key, val| res[key] = val.join(", ") } 112 rescue => ex 113 raise HTTPStatus::InternalServerError, ex.message 114 end 115 res.body = body 116 end 117 alias do_POST do_GET 118 119 # :startdoc: 120 end 121 122 end 123end 124