class Rex::Proto::Http::Server
Acts as an HTTP server, processing requests and dispatching them to registered procs. Some of this server was modeled after webrick.
Constants
- DefaultServer
The default server name that will be returned in the
Server
attribute of a response.- ExtensionMimeTypes
A hash that associated a file extension with a mime type for use as the content type of responses.
Attributes
Public Class Methods
Returns the hardcore alias for the HTTP service
# File lib/rex/proto/http/server.rb, line 125 def self.hardcore_alias(*args) "#{(args[0] || '')}#{(args[1] || '')}" end
Initializes an HTTP server as listening on the provided port and hostname.
# File lib/rex/proto/http/server.rb, line 101 def initialize(port = 80, listen_host = '0.0.0.0', ssl = false, context = {}, comm = nil, ssl_cert = nil, ssl_compression = false) self.listen_host = listen_host self.listen_port = port self.ssl = ssl self.context = context self.comm = comm self.ssl_cert = ssl_cert self.ssl_compression = ssl_compression self.listener = nil self.resources = {} self.server_name = DefaultServer end
Public Instance Methods
Adds a resource handler, such as one for /, which will be called whenever the resource is requested. The “opts'' parameter can have any of the following:
Proc (proc) - The procedure to call when a request comes in for this resource. LongCall (bool) - Hints to the server that this resource may have long
request processing times.
# File lib/rex/proto/http/server.rb, line 208 def add_resource(name, opts) if (resources[name]) raise RuntimeError, "The supplied resource '#{name}' is already added.", caller end # If a procedure was passed, mount the resource with it. if (opts['Proc']) mount(name, Handler::Proc, false, opts['Proc'], opts['VirtualDirectory']) else raise ArgumentError, "You must specify a procedure." end end
Adds Server
headers and stuff.
# File lib/rex/proto/http/server.rb, line 232 def add_response_headers(resp) resp['Server'] = self.server_name if not resp['Server'] end
HTTP server.
# File lib/rex/proto/http/server.rb, line 132 def alias super || "HTTP Server" end
Closes the supplied client, if valid.
# File lib/rex/proto/http/server.rb, line 181 def close_client(cli) listener.close_client(cli) end
More readable inspect that only shows the url and resources @return [String]
# File lib/rex/proto/http/server.rb, line 116 def inspect resources_str = resources.keys.map{|r| r.inspect }.join ", " "#<#{self.class} http#{ssl ? "s" : ""}://#{listen_host}:#{listen_port} [ #{resources_str} ]>" end
Returns the mime type associated with the supplied file. Right now the set of mime types is fairly limited.
# File lib/rex/proto/http/server.rb, line 240 def mime_type(file) type = nil if (file =~ /\.(.+?)$/) type = ExtensionMimeTypes[$1.downcase] end type || "text/plain" end
Mounts a directory or resource as being serviced by the supplied handler.
# File lib/rex/proto/http/server.rb, line 188 def mount(root, handler, long_call = false, *args) resources[root] = [ handler, long_call, args ] end
Removes the supplied resource handler.
# File lib/rex/proto/http/server.rb, line 225 def remove_resource(name) self.resources.delete(name) end
Sends a 404 error to the client for a given request.
# File lib/rex/proto/http/server.rb, line 253 def send_e404(cli, request) resp = Response::E404.new resp['Content-Type'] = 'text/html' resp.body = "<html><head>" + "<title>404 Not Found</title>" + "</head><body>" + "<h1>Not found</h1>" + "The requested URL #{html_escape(request.resource)} was not found on this server.<p><hr>" + "</body></html>" # Send the response to the client like what cli.send_response(resp) end
Listens on the defined port and host and starts monitoring for clients.
# File lib/rex/proto/http/server.rb, line 139 def start self.listener = Rex::Socket::TcpServer.create( 'LocalHost' => self.listen_host, 'LocalPort' => self.listen_port, 'Context' => self.context, 'SSL' => self.ssl, 'SSLCert' => self.ssl_cert, 'SSLCompression' => self.ssl_compression, 'Comm' => self.comm ) # Register callbacks self.listener.on_client_connect_proc = Proc.new { |cli| on_client_connect(cli) } self.listener.on_client_data_proc = Proc.new { |cli| on_client_data(cli) } self.listener.start end
Terminates the monitor thread and turns off the listener.
# File lib/rex/proto/http/server.rb, line 165 def stop self.listener.stop self.listener.close end
Remove the mount point.
# File lib/rex/proto/http/server.rb, line 195 def unmount(root) resources.delete(root) end
Waits for the HTTP service to terminate
# File lib/rex/proto/http/server.rb, line 174 def wait self.listener.wait if self.listener end
Protected Instance Methods
Dispatches the supplied request for a given connection.
# File lib/rex/proto/http/server.rb, line 322 def dispatch_request(cli, request) # Is the client requesting keep-alive? if ((request['Connection']) and (request['Connection'].downcase == 'Keep-Alive'.downcase)) cli.keepalive = true end # Search for the resource handler for the requested URL. This is pretty # inefficient right now, but we can spruce it up later. p = nil len = 0 root = nil resources.each_pair { |k, val| if (request.resource =~ /^#{k}/ and k.length > len) p = val len = k.length root = k end } if (p) # Create an instance of the handler for this resource handler = p[0].new(self, *p[2]) # If the handler class requires a relative resource... if (handler.relative_resource_required?) # Substituted the mount point root in the request to make things # relative to the mount point. request.relative_resource = request.resource.gsub(/^#{root}/, '') request.relative_resource = '/' + request.relative_resource if (request.relative_resource !~ /^\//) end # If we found the resource handler for this resource, call its # procedure. if (p[1] == true) Rex::ThreadFactory.spawn("HTTPServerRequestHandler", false) { handler.on_request(cli, request) } else handler.on_request(cli, request) end else elog("Failed to find handler for resource: #{request.resource}", LogSource) send_e404(cli, request) end # If keep-alive isn't enabled for this client, close the connection if (cli.keepalive == false) close_client(cli) end end
Extends new clients with the ServerClient
module and initializes them.
# File lib/rex/proto/http/server.rb, line 279 def on_client_connect(cli) cli.extend(ServerClient) cli.init_cli(self) end
Processes data coming in from a client.
# File lib/rex/proto/http/server.rb, line 288 def on_client_data(cli) begin data = cli.read(65535) raise ::EOFError if not data raise ::EOFError if data.empty? case cli.request.parse(data) when Packet::ParseCode::Completed dispatch_request(cli, cli.request) cli.reset_cli when Packet::ParseCode::Partial # Return and wait for the on_client_data handler to be called again # The Request object tracks the state of the request for us return when Packet::ParseCode::Error close_client(cli) end rescue EOFError if (cli.request.completed?) dispatch_request(cli, cli.request) cli.reset_cli end close_client(cli) end end