User:Adeeshag/sandbox

Starting a HTTP server
In order to create a WEBrick HTTP server, we must first include the WEBrick library and use the following commands to start the WEBrick server and configure it such that it will listen on port 8000 and serve files from the ~/public_html path. require 'webrick' root = File.expand_path '~/public_html' server = WEBrick::HTTPServer.new :Port => 8000, :DocumentRoot => root

To run the server (and provide a proper shutdown hook so that it does not block the current thread), we use the following commands: trap 'INT' do server.shutdown end server.start

Mounting Servlets
In WEBrick, we may set up a servlet  so that we can service a request-URI. This is can be done by creating an instance of a subclass of WEBrick::HTTPServlet::AbstractServlet. The subclass AbstractServlet enables the reuse of multiple HTTP  server modules across various servers.

To avoid initializing a new servlet each request, we can reuse an exiting servlet by overriding the ::get_instance in the AbstractServlet.

An example of a Servlet is shown below: Class SimpleServlet < WEBrick::HTTPServlet::AbstractServlet def do_GET request, response //code to handle response end end

In order to mount the servlet on a server, we must specify the mount path and the class of the servlet, along with any parameters if required. An example to mount the above servlet is shown below: server.mount '/path/', SimpleServlet <, optional parameters> Note: do_GET is one of the public instance methods that can be used with the AbstractServlet class

Standard Servlets
Some of the standard servlets that come with WEBrick are:

WEBrick::HTTPServlet::FileHandler
A useful standard servlet that is used to help serve a directory using a number of different options such as fancy indexing. If the path points to a directory, it will serve the index file. When the FileHandler receives a request, it analyzes the request path. An example to mount a servlet sign the FileHandler is: server.mount '/directory1', WEBrick::HTTPServlet::FileHandler, '/path_to_be_served/'

When the FileHandler receives a request path that does not end with a .cgi or a .rhtml, then the DefaultFileHandler will be responsible to handle the request. This servlet is generally used to handle If-Modify-Since and Range HTTP/1.1RFC requests. server.mount '/my_page.txt', WEBrick::HTTPServlet::DefaultFileHandler, '/path/to/my_page.txt'
 * WEBrick::HTTPServlet::DefaultFileHandler

WEBrick::HTTPServlet::CGIHandler
This is a servlet that is used to enable the use of CGI scripts or programs without having to rewrite them as WEBrick servlets. We must make sure that we install a FileHandler to that directory containing all the CGI scripts and make sure the files are of the correct format. An example is given below: server.mount '/scripts/', WEBrick::HTTPServlet::CGIHandler, '/path/cgi_script.cgi'

WEBrick::HTTPServlet::ProcHandler
This is used to mount a proc at the specified path. If we do not require complex functionality for our servlet, we would not necessarily need to subclass the AbstractServlet, create new instances and threads for each servlet. We could make use of the ProcHandler to accept a request and response from the specified path. Let us take an example where the specified path is /proc_path/ and it only sends a response with the body: server.mount_proc '/proc_path/' do |request, response| response.body = "Proc Test, Success!" end

WEBrick::HTTPServlet::ERBHandler
This servlet is similar to the CGIHandler servlet with the main difference being that it services .rhtml files. If a directory is served by the FileHandler, i.e, if we install a Filehandler to the directory containing the .rthml files, then this handler will be automatically used. This handler supports the GET and POST methods. The ERB files are evaluated using the WEBrick::HTTPRequest and  WEBrick::HTTPResponse.

Creating Custom Servlets
We can write custom servlets where we can make them perform the functions we want or in other words, what we would do when we query a request object and how we can set the response object.

do_ methods
We would need to create a subclass WEBrick::HTTPServlet::AbstractServlet and then to that, add a do_GET, do_POST, do_HEAD and/or do_OPTIONS.
 * do_HEAD:  just calls a do_GET, which should be provided by the user.
 * do_OPTIONS:  just returns a list of all the do_ methods that are avaialable for use.
 * do_GET:  returns NotFound Exception if we don't have any method defined.

We can customize what a do_ method should do. WEBrick will call the custom do_ method with two parameters: request and response objects. Example code: class GreetingServlet < HTTPServlet::AbstractServlet def do_GET(req, resp) if req.query[’name’] resp.body = "#{@options[0]} #{req.query[’name’]}. #{@options[1]}" raise HTTPStatus::OK else raise HTTPStatus::PreconditionFailed.new("missing attribute: ’name’") end end alias do_POST, do_GET   # let’s accept POST request too. end start_webrick {|server| server.mount(’/greet’, GreetingServlet, ’Hi’, ’Are you having a nice day?’) }

Response
For every request, we can respond in one of two ways. We can:
 * Raise a HTTPStatus exception which would show an HTML filled page with a backtrace.
 * Provide a custom error page which involves:
 * Manually setting a response body and status; OR
 * Extend the HTTPResponse object with the set_error method which will create an error page and enable backtrace (optionally), in the event of an error.

Virtual Host
A virtual host allows to host multiple domain names on a server. WEBrick can act as a virtual host for multiple host names. Once you have created the listening host you can add multiple hosts that do not listen and can act as virtual hosts.

Virtual Host A virtual host allows to host multiple domain names on a server. WEBrick can act as a virtual host for multiple host names. Once you have created the listening host you can add multiple hosts that do not listen and can act as virtual hosts

server = WEBrick::HTTPServer.new # ... vhost = WEBrick::HTTPServer.new :ServerName => 'vhost.example', :DoNotListen => true, # ... vhost.mount '/', ... server.virtual_host vhost

vhost is the virtual host server defined and mounted in the above code snippet.

Note: If :DocumentRoot is not provided and servlets or procs are not mounted on the main server you will receive a 404 error message for all the URL’s.

Proxy Server
Proxy servers are intermediary servers between client and requested information hosted on other servers.



You can create a simple proxy server with the below code snippet:

require 'webrick' require 'webrick/httpproxy' proxy = WEBrick::HTTPProxyServer.new Port: 8000

Logging
WEBrick allows us to log both server operations and user access.

Server Operations
The operations done at server can logged through the log class available in WEBrick. Sample code : file_log = File.open '/abc/log/server_operations.log', 'a+' log = WEBrick::Log.new file_log

file_log is a File object defined with the name of the log file to be used as the parameter. The mode used for opening the file is a+ which allows to read and write in append mode. We assigned log as a new object of Log class in WEBrick and have passed file_log as the parameter.

User Access
Access log is used to log user requests for all the files they have requested from the website. As user logs are more likely to be accessed they are treated specially. Sample code for the log:-

user_log = [ [file_log, WEBrick::AccessLog::COMBINED_LOG_FORMAT], ] server = WEBrick::HTTPServer.new :Logger => log, :AccessLog => user_log

HTTP Authentication
HTTP authentication is supported by two mechanisms: basic and digest. Digest authentication communicates credentials in an encrypted format. Has functions are used for the purpose. Basic authentication uses an encrypted encoding. To implement authentication in WEBrick you will require a database  and an authenticator.

config = { :Realm => 'DigestAuth example realm' } htpasswd = WEBrick::HTTPAuth::Htpasswd.new 'my_password_file' htpasswd.auth_type = WEBrick::HTTPAuth::DigestAuth htpasswd.set_passwd config[:Realm], 'username', 'password' htpasswd.flush

Htpasswd database is used above a with a DigestAuth authenticator. Different access is provided to different groups using :Realm.

Authenticator is created using the database. config[:UserDB] = htpasswd digest_auth = WEBrick::HTTPAuth::DigestAuth.new config

Request call is authenticated with a request and response object in a servlet: def do_GET req, res @authenticator.authenticate req, res end

Basic Authentication
BasicAuth is the class used for basic Authentication. A sample example for authentication is provided below: config = { :Realm => 'BasicAuth example realm' } htpasswd = WEBrick::HTTPAuth::Htpasswd.new 'my_password_file' htpasswd.set_passwd config[:Realm], 'username', 'password' htpasswd.flush config[:UserDB] = htpasswd basic_auth = WEBrick::HTTPAuth::BasicAuth.new config

Digest Authentication
DigestAuth class is used for digest authentication. Sample code is provided below: config = { :Realm => 'DigestAuth example realm' } htdigest = WEBrick::HTTPAuth::Htdigest.new 'my_password_file' htdigest.set_passwd config[:Realm], 'username', 'password' htdigest.flush config[:UserDB] = htdigest digest_auth = WEBrick::HTTPAuth::DigestAuth.new config

Conclusion
WEBrick is a HTTPserver toolkit which can be configured in three different ways i.e. HTTPS server, proxy server and virtual host server. It provides us with tools for maintaining logs .It supports both user access and server operations logging. It also provides tool for authentication. Both basic and digest authentication is supported by WEBrick. Servlets are provided in WEBrick that can handle ERB pages, CGI scripts and Ruby blocks. Also WEBrick server can use any number of servlets or WEBrick servers. Despite the features WEBrick is generally used for development and not as a production web server as it not designed to handle heavy load.