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