-
Notifications
You must be signed in to change notification settings - Fork 113
Expand file tree
/
Copy pathcgihandler.rb
More file actions
132 lines (116 loc) · 4.19 KB
/
cgihandler.rb
File metadata and controls
132 lines (116 loc) · 4.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# frozen_string_literal: true
#
# cgihandler.rb -- CGIHandler Class
#
# Author: IPR -- Internet Programming with Ruby -- writers
# Copyright (c) 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
# reserved.
#
# $IPR: cgihandler.rb,v 1.27 2003/03/21 19:56:01 gotoyuzo Exp $
require 'rbconfig'
require 'tempfile'
require_relative '../config'
require_relative 'abstract'
module WEBrick
module HTTPServlet
##
# Servlet for handling CGI scripts
#
# Example:
#
# server.mount('/cgi/my_script', WEBrick::HTTPServlet::CGIHandler,
# '/path/to/my_script')
class CGIHandler < AbstractServlet
Ruby = RbConfig.ruby # :nodoc:
CGIRunner = "\"#{Ruby}\" \"#{WEBrick::Config::LIBDIR}/httpservlet/cgi_runner.rb\"" # :nodoc:
CGIRunnerArray = [Ruby, "#{WEBrick::Config::LIBDIR}/httpservlet/cgi_runner.rb".freeze].freeze # :nodoc:
##
# Creates a new CGI script servlet for the script at +name+
def initialize(server, name)
super(server, name)
@script_filename = name
@tempdir = server[:TempDir]
interpreter = server[:CGIInterpreter]
if interpreter.is_a?(Array)
@cgicmd = CGIRunnerArray + interpreter
else
@cgicmd = "#{CGIRunner} #{interpreter}"
end
end
# :stopdoc:
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,
header_line_regexp: REGEXP_CGI_HEADER_LINE ,
continued_header_line_regexp: REGEXP_CONTINUED_CGI_HEADER_LINE)
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
alias do_POST do_GET
REGEXP_CGI_HEADER_LINE = /^([A-Za-z0-9!\#$%&'*+\-.^_`|~]+):([^\r\n\0]*?)\r?\n\z/m
REGEXP_CONTINUED_CGI_HEADER_LINE = /^[ \t]+([^\r\n\0]*?)\r?\n/m
private_constant :REGEXP_CGI_HEADER_LINE, :REGEXP_CONTINUED_CGI_HEADER_LINE
# :startdoc:
end
end
end