129 lines
2.9 KiB
Ruby
129 lines
2.9 KiB
Ruby
require 'erb'
|
|
include ERB::Util
|
|
|
|
module Rex
|
|
module Proto
|
|
module Http
|
|
|
|
###
|
|
#
|
|
# This class implements a handler for ERB (.rhtml) template files. This is
|
|
# based off the webrick handler.
|
|
#
|
|
###
|
|
class Handler::Erb < Handler
|
|
|
|
#
|
|
# ERB handlers required a relative resource so that the full path name can
|
|
# be computed.
|
|
#
|
|
def self.relative_resource_required?
|
|
true
|
|
end
|
|
|
|
#
|
|
# Initializes the ERB handler
|
|
#
|
|
def initialize(server, root_path, opts = {})
|
|
super(server)
|
|
|
|
self.root_path = root_path
|
|
self.opts = opts
|
|
|
|
self.opts['MimeType'] = "text/html" unless self.opts['MimeType']
|
|
end
|
|
|
|
#
|
|
# Called when a request arrives.
|
|
#
|
|
def on_request(cli, req)
|
|
resource = req.relative_resource
|
|
|
|
# Make sure directory traversals aren't happening
|
|
if (resource =~ /\.\./)
|
|
wlog("Erb::on_request: Dangerous request performed: #{resource}",
|
|
LogSource)
|
|
return
|
|
# If the request is for the root directory, use the document index file.
|
|
elsif (resource == '/')
|
|
resource << opts['DocumentIndex'] || 'index.rhtml'
|
|
end
|
|
|
|
begin
|
|
resp = Response.new
|
|
|
|
# Calculate the actual file path on disk.
|
|
file_path = root_path + resource
|
|
|
|
# Serialize the contents of the file
|
|
data = ''
|
|
|
|
File.open(file_path, 'rb') { |f|
|
|
data = f.read
|
|
}
|
|
|
|
# Set the content-type to text/html by default. We do this before
|
|
# evaluation so that the script can change it.
|
|
resp['Content-Type'] = server ? server.mime_type(resource) : 'text/html'
|
|
|
|
# If the requested file is a ruby html file, evaluate it.
|
|
if (File.extname(file_path) == ".rhtml")
|
|
# Evaluate the data and set the output as the response body.
|
|
resp.body = evaluate(ERB.new(data), cli, req, resp)
|
|
# Otherwise, just set the body to the data that was read.
|
|
else
|
|
resp.body = data
|
|
end
|
|
rescue Errno::ENOENT
|
|
server.send_e404(cli, req)
|
|
rescue
|
|
elog("Erb::on_request: #{$!}\n#{$@.join("\n")}", LogSource)
|
|
|
|
resp.code = 500
|
|
resp.message = "Internal Server Error"
|
|
resp.body =
|
|
"<html><head>" +
|
|
"<title>Internal Server Error</title>" +
|
|
"</head><body> " +
|
|
"<h1>Internal Server Error</h1>" +
|
|
"The server encountered an error:<br/><br/> <b>" + html_escape($!) + "</b><br/><br/>" +
|
|
"Stack trace:<br/><br/>" +
|
|
$@.map { |e| html_escape(e.to_s) }.join("<br/>") +
|
|
"</body></html>"
|
|
end
|
|
|
|
# Send the response to the
|
|
if (cli and resp)
|
|
cli.send_response(resp)
|
|
end
|
|
|
|
resp
|
|
end
|
|
|
|
#
|
|
# Evaulates the ERB context in a specific binding context.
|
|
#
|
|
def evaluate(erb, cli, request, response)
|
|
# If the thing that created this handler wanted us to use a callback
|
|
# instead of the default behavior, then let's do that.
|
|
if (opts['ErbCallback'])
|
|
opts['ErbCallback'].call(erb, cli, request, response)
|
|
else
|
|
Module.new.module_eval {
|
|
query_string = request.qstring
|
|
meta_vars = request.meta_vars
|
|
erb.result(binding)
|
|
}
|
|
end
|
|
end
|
|
|
|
protected
|
|
|
|
attr_accessor :root_path, :opts # :nodoc:
|
|
|
|
end
|
|
|
|
end
|
|
end
|
|
end
|