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 = ::IO.readlines(file_path).join # 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 = "" + "Internal Server Error" + " " + "

Internal Server Error

" + "The server encountered an error:

" + html_escape($!) + "

" + "Stack trace:

" + $@.map { |e| html_escape(e.to_s) }.join("
") + "" 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