Monthly Archives: April 2014

Epoll feature and its use in Monkey HTTP server

There is a reason that I mentioned in my earlier post on Introduction to Monkey server runs only on Linux operating systems. It is because, the server depends on a set of non-portable Linux system calls for its performance. One among the most important of system calls is the epoll feature.

What is epoll ?

Epoll is a feature provided by Linux kernel to manage file descriptors. It monitors the file descriptors that have been added to an epoll instance to see if I/O event is possible on any one of them. They may be used either as edge-triggered or level-triggered.

Some of the functions used in this regard are :

  1. epoll_create1 – This creates an epoll instance. Each epoll instance has a file descriptor. epoll_create1 () returns the efd (epoll file descriptor) of the epoll instance created.
  2. epoll_ctl – This is used to perform specified operations on them. It may be adding a particular fd to the epoll instance.
  3. epoll_wait – This waits on the file descriptors to see if an I/O event is possible. If this is not possible on any of the file descriptors monitored by an epoll instance of efd, it blocks the calling thread.

Some of the data types used in this regards are :

  1. struct epoll_data – void *ptr, int fd, uint32_t u32, uint64_t u64.
  2. struct epoll_events – uint32_t events, epoll_data_t data.

Some of the actions whose occurrence the epoll instance looks for in a file descriptor are as follows :

  1. EPOLLIN – for a read operation
  2. EPOLLOUT – for a write operation
  3. EPOLLERR – indicates an error that happened on the file descriptor
  4. EPOLLHUP – indicates that a hangup occured on the fd
  5. EPOLLRDHUP – indicates that the connection was set down by a socket peer
  6. EPOLLET – sets Edge triggered behaviour for the file descriptor

Epoll component in Monkey server

The monkey server also makes use of the epoll feature provided by the Linux kernel to handle the innumerable file descriptors.

Implementation Details :

The epoll states of all the file descriptors that are being handled by a thread are stored in a red black tree in addition to being stored in an epoll queue. Besides this, each thread also has two lists – one for available and the other for busy slots. Further for each file descriptor, a set of data is to be maintained about the behaviour, events to be monitored, current mode, etc.The structures that are used to represent the various the epoll states for a file descriptor and for a thread are as follows :

  1. struct epoll_state_index – for each thread.
    1. size – number of requests that a thread can handle.
    2. red black tree for all the epoll state nodes in the thread.
    3. available list of those epoll state nodes that are free.
    4. busy list of those epoll state nodes being currently used.
  2. struct epoll_state – for each file descriptor.
    1. file descriptor – one whose epoll state this struct represents
    2. mode – current mode of the file descriptor (this is an element of events list)
    3. events – the list of events that should be monitored
    4. behaviour – denoting whether the events should be monitored on the basis of edge triggering or level triggering.
    5. A red black node so that it can be added to the red black tree that stores the epoll states for file descriptors for a particular thread.
    6. A list node so that it can be added to either the busy queue or available queue that is maintained for each thread.
  3. struct mk_epoll_handlers – this will be explained in another post.
    1. int (*read) (int);
    2. int (*write) (int);
    3. int (*close) (int);
Functions in src/mk_epoll.c :

In the source code for Monkey server, there are separate functions written for this very important component. The following is a brief description of the functions and what each function does :

  1. mk_epoll_create () – This creates an epoll instance for a thread, with the help of the system call epoll_create1, and returns the epoll file descriptor for the epoll instance of the thread. If due to some reason, the epoll instance was not created (that is, epoll_create1 returned -1), it prints an error.
  2. mk_epoll_init (int efd, int max_events) – This is the function where the epoll instance waits infinitely for on the events that occur on the file descriptors. It is done with the help of epoll_wait function. Depending on which event is occurring on the file descriptor, the corresponding method is called. It does this for all the file descriptors are present on the epoll instance.
  3. mk_epoll_state_get (int fd) – This function gets called  from two places – from function mk_epoll_add and mk_epoll_chage_mode. Given the file descriptor, this function gets the epoll state of the file descriptor from the red black tree that contains the epoll states of all file descriptors for the thread. If the epoll state of a file descriptor has not been found, it prints a message saying so and returns NULL.
  4. mk_epoll_state_set (int fd, uint8_t mode, unsigned int behaviour, uint32_t events) – Given the parameters, it searches the red black tree for this particular epoll state node with file descriptor = fd. If the node is already present, it just sets the mode, and if the mode is not SLEEP, the events and behaviour of the fd, with the values that have been passed to this function. This case will happen when it called from inside change_mode function (explained in the end). If the node is not present in the red black tree (which means that it is a new one), it is assigned the values that have been passed to this function, such as mode, behaviour, events, etc.. This node is then removed from the available queue and added to the busy queue. It is also inserted into the red black tree for the thread.
  5. mk_epoll_state_init () – This function initializes values for members of struct epoll_state_index.
  6. mk_epoll_add (int efd, int fd, int init_mode, unsigned int behaviour) – With the given parameters, it adds the initial mode to the events list of the file descriptor fd. It then calls epoll_ctl with operation EPOLL_CTL_ADD on fd, to add it to the epoll instance for the thread. At the end it calls state_set function to add it to the red black tree and the one of the lists of the thread.
  7. mk_epoll_del (int efd, int fd) – This removes the epoll state of fd from the epoll instance efd, with the help of EPOLL_CTL_DEL operation in epoll_ctl function. It then calls mk_epoll_del_state function to remove it from other places.
  8. mk_epoll_state_del (int fd) – This function removes it from the red black tree where the epoll states are stored, and deletes it from the list where it is present, adds the epoll state node to the available queue.
  9. mk_epoll_change_mode (int efd, int fd, int mode, unsigned int behaviour) – This function is used to change the mode of a particular file descriptor. Using a switch case, it checks the mode against possible modes. On finding the matching case, it appends that particular mode to the events list. If the mode is SLEEP, it disables all events in the event list for the file descriptor. If the mode is WAKEUP, it gets the node from red black tree, and (if the file descriptor is present ) reassigns events and behaviour for the node (which had been previously disabled when its mode was changed to SLEEP). After the changes made to the mode of the file descriptor, it calls epoll_ctl (efd, EPOLL_CTL_MOD, fd, events_list) for the descriptor in the epoll instance of the thread, with operation to modify the epoll event for fd. It then calls the state_get function again to reset the mode, events list and behaviour.
Workflow :

The workflow of where and when the epoll is used in the Monkey server has been explained, trying maximum to keep out other components of the server :

  1. When a thread is created that will be listening for incoming requests, an epoll instance is created using epoll_create.
  2. Now that an epoll instance has been created for the thread, this epoll instance is initialized with values for various fields of the instance.
  3. As soon as an incoming connection arrives, it is assigned the least loaded thread and soon after this, the file descriptor for this connection is added to the epoll instance of the thread.
  4. The epoll instance monitors the events that occur in each file descriptor that has been added to it.
  5. Depending on whether the event on a file descriptor is read or write or any of the events mentioned in the previous section, the corresponding method is called.
  6. After all the requests on a particular socket have been completed, it is removed from the epoll instance.

References :

  1. man pages for epoll

OAuth 2.0

OAuth 2.0 has been derived from OAuth 1.0. The OAuth 2.0 was introduced to remove the complexities involved with encryption of the requests for tokens that were present in OAuth 1.0 and also to make it more scalable. Some of the OAuth 2.0 providers are Facebook, Google, Amazon, Github, Microsoft, Paypal, etc. With the introduction of OAuth 2.0, OAuth 1.0 has become obsolete.

User and their roles in the system :

Here there are four users in the system, as opposed to only three in OAuth 1.0. They are follows :

  1. Resource server (same as OAuth 1.0) – A website that is capable of storing resources of users.
  2. Resource owner (same as OAuth 1.0) – An entity who wants to store his resources and can provide access to them to other entities.
  3. Client (same as OAuth 1.0) – A application or website that wants to access the resources of the resource owner, on his behalf.
  4. Authorization server – A server that provides temporary intermediate credentials  to the client, that are required in the complete process of providing authorization to the client.
How is it different from OAuth 1.0 ?

It is different in the sense that, while in OAuth 1.0 there was only one server, that is the resource server, wherein the end user (resource owner) could store his resources, in OAuth 2.0, there is one extra server in addition to the resource server – the authorization server. The authorization server is responsible for providing temporary credentials to the client that wants to access the protected resources of the resource owner. OAuth 2.0 provides for better organization and separation of responsibilities among the users of the system.

Workflow :

The following diagram that has been taken from RFC 6749 shows the workflow in the case of OAuth 2.0 .

     +--------+                               +---------------+
     |        |--(A)- Authorization Request ->|   Resource    |
     |        |                               |     Owner     |
     |        |<-(B)-- Authorization Grant ---|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(C)-- Authorization Grant -->| Authorization |
     | Client |                               |     Server    |
     |        |<-(D)----- Access Token -------|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(E)----- Access Token ------>|    Resource   |
     |        |                               |     Server    |
     |        |<-(F)--- Protected Resource ---|               |
     +--------+                               +---------------+

The steps are explained as follows :

  1. The client that wants to access the resource owner’s resources, sends an authorization request to the resource owner.
  2. Authorization is then granted to the client by the resource owner. The authorization can be of different types depending on whether the client contacted the resource owner directly or indirectly.
  3. The client then uses this authorization grant and requests for an access token after it authenticates with the authorization server.
  4. After the authorization server authenticates the client and checks if the authorization grant provided by the resource owner is valid, it provides an access token to the client.
  5. With the access token that it received from the authorization server, the client requests for access to the resources stored in the resource server.
  6. The resource server checks if the access token is valid or not and accordingly provides access to the token.
The concept of Refresh tokens :

The OAuth 2.0 introduces the concept of providing refresh tokens. Refresh tokens are used as a substitute for access tokens that have been issued by the authorization server to the client, when the access tokens expire. When the client makes an authorization grant to the authorization server for the access token, after authentication by the authorization server, it gets back two tokens – an access token and a refresh token. The refresh token can be used instead of the access token in circumstances where the resource server finds out that the access token has expired. This helps continue the process and avoids the issue of creating a fresh access token.

Under normal circumstances (in the absence of refresh tokens) when the access token expires, the process needs to start all over from the beginning. When the client tries to access the resources by providing the access token (that was issued to it by the authorization server) to the resource server, on checking if the resource server find the access token to have expired, the client needs to begin again with requesting authorization to the resource owner and then follow it up with authentication to the authorization server again, and requesting a new access token.

The following diagram, taken from RFC 6749 explains the workflow in the case of refresh tokens.

+--------+ +-------------+ | |--(A)------- Authorization Grant --------->| | | | | | | |<-(B)----------- Access Token -------------| | | | & Refresh Token | | | | | | | | +----------+ | | | |--(C)---- Access Token ---->| | | | | | | | | | | |<-(D)- Protected Resource --| Resource | |Authorization| | Client | | Server | | Server | | |--(E)---- Access Token ---->| | | | | | | | | | | |<-(F)- Invalid Token Error -| | | | | | +----------+ | | | | | | | |--(G)----------- Refresh Token ----------->| | | | | | | |<-(H)----------- Access Token -------------| | +--------+ & Optional Refresh Token +-------------+
 Advantages of OAuth 2.0 :
  1. There is a clear separation of roles and responsibilities among the different components of the system.
  2. OAuth 2.0 has support for both native and mobile applications.
  3. It supports various types of use cases depending on whether the client of confidential or public type.
  4. In OAuth 2.0, the client makes requests for tokens over HTTPS and does not require for the requests to be hashed using HMAC.
Disadvantages of OAuth 2.0 :
  1. OAuth is not backward compatible.
  2. Phishing attacks are possible.
  3. The server gets to know more information about the resources owners and clients.
  4. Denial of Service attack is possible on clients and servers.
  5. Replay attack is possible.
References :

OAuth 1.0

OAuth is an open standard for authorization and helps control access to resources that have been stored in a server, by third party users. OAuth is inspired by OpenID. On generalizing the concept of OpenID, we can see that while the OpenID is a special case of OAuth wherein the resources that are shared are only the username and password. Whereas in the case of OAuth, resources could be anything like files / photos.


Let us look at an example scenario. Suppose that Jane (resource owner) has uploaded some of her photos (protected resources) on a website – (server). She then wants to print them using another website – (client). However, she does not want to reveal her password to the server, to the client. Under such a circumstance, how does the client access her photos from the server so that it can print them for Jane ?

Naive method : A naive approach would be for Jane to reveal the password to her server, to the client so that the client can also login and access the photos. But that would mean that the client would be able to send request to change Jane’s password on the server. As the server wouldn’t know who sent the password request change, it would comply with the request.

Now this is a problem ! We need a different approach under such a situation. This is where the OAuth comes into play !

Terminology :

Some of the common terminologies used are :

  1. Server : An HTTP server capable of receiving HTTP requests from a client. In the above example, the is the server.
  2. Resource owner : The resource owner is the user who has stored some of his resources in a server and can access them using his credentials with which the server authenticates him. Jane is the resource owner, in the explained example.
  3. Protected resource : Something that has been stored in the server by its owner, and to which only limited access is allowed. The protected resource is Jane’s photos.
  4. Client : An HTTP client capable of making HTTP requests to the server. The client in the above example is
Workflow :

This is how an OAuth supporting website works in the example of Jane :

(Please note that and client, and and server, have been user interchangeably.)

  1. Jane (resource owner) has stored her resources in (server).
  2. The (client) has signed up for credentials to some of the commonly used servers (among which one is in order to provide better service to users.
  3. Jane wants to print the photos from, the client.
  4. The client needs to establish a set of temporary credentials with the server for which it sends a request for a temporary credential.
  5. The server validates the client request and sends it temporary credentials.
  6. The client redirects Jane to resource owner end of the server.
  7. The server requests Jane to sign in using her credentials that authenticate her with the server and asks her approval to grant permission to the client to access her resources.
  8. Jane approves giving access to client to access her resources.
  9. The client is informed when Jane finishes granting authorization to the client.
  10. The client requests for another pair of credentials to the server, making use of its temporary credentials.
  11. The server again validates the request and sends back a pair of credentials to the client.
  12. The client can now access Janes photos from the server, with this set of credentials recently given to it by the server.

Thus in this manner, the client is authorized to access Janes resources on the server, without Jane having to compromise her password with the client. OAuth workflow

The greatest advantage of OAuth is that it allows third party access to the resources of the user, without the user having to reveal the password. Only just enough permission is granted to the client, to access the user’s resources.

Having said that, the OAuth is not completely secure. A disadvantage of OAuth is that confidentiality is compromised. The tokens that are shared between the client and server are sometimes in plain text.

References :


What is it ?

OpenID is an open standard allows users to use existing credentials to sign in to many websites, without having to create separate usernames and passwords for each. In the system, there is an OpenID provider. The user may create OpenID account with any of the OpenID providers and use these credentials to identify themselves at different platforms. OpenID is decentralized and is not controlled by anyone.

A common example of where an OpenID is used is a passport. A person can use his passport to identify himself during the airport security check as well as to identify himself at the immigrations office or to identify himself at any other location.

Terminology :

There are three terms that used :

  1. Identity providers : They are the providers of the OpenID. A few examples of Identity providers today are Google, Facebook, Microsoft, etc.
  2. Identifiers : The number or sequence of characters (there could be other forms of identifiers too) that uniquely identify a user. In the case of the OpenID, it is a URL that uniquely identifies the user with the OpenID provider.
  3. Consumers : The parties who use the OpenID of the users to authenticate them.

 With respect to the example of the passport, the government of a country is the identity (OpenID) provider. The passport number on the passport is the identifier of the citizen, and the airport security control authorities are the consumers that check authenticate the user on the basis of his ID.

Workflow with an example :

Suppose that Alice wants to sign up in the website She already has an account with the OpenID provider Google.

  1. Alice visits the website
  2. She gets the option of either using her OpenID or creating a new username and password and she chooses to login using OpenID.
  3. The website searches for the OpenID provider that Alice specifies (which is Google in this case), and establishes an association handle with the provider.
  4. It then sends an authentication request to Google (essentially the website redirects Alice to sign into Google).
  5. Alice to signs into Google using her OpenID credentials.
  6. Google sends back the authentication response to
  7. If successfully authenticated, Alice is redirected to and has successfully logged into
Advantages :

Some of the advantages of the OpenID are :

  1. It accelerates the signup process as the user need not create a separate username and password.
  2. It saves users the headache of having to remember numerous passwords for different web sites as with the help of OpenID they can use their OpenID credentials for other websites. The users do not need to remember multiple passwords.
  3. The user can control the amount of information that is shared with OpenID supporting websites – whether they want to share only their username or their email id also.
  4. It minimize the risk when using same passwords for different websites. There are many users that use the same password for different websites. Thus if any one of these websites gets compromised, the password can be used to login into all the other websites that user has an account in. But with the help of OpenID, if the password gets compromised, it can simply be changed and the attacker would not be able to login to any other sites.
  5. The developer has advantages too. Not having to create usernames and passwords means that getting ridden from the worry of having to store them.
Disadvantages :

Some disadvantages of the OpenID standard are as follows :

  1. Decentralized : OpenID is decentralized and there is no global acceptance or standard for it.
  2. Privacy violation : Each time the user visits a site or carries out an online operation, the identity provider whose identity the user is using to identify himself, gets to know about it.
  3. Information shared : There is also the threat that your username and email id might get shared.
  4. Problem of trust : With OpenID, there is the problem of trust.
  5. Denial of Service attack : Without even having an OpenID, the user could try to log in with a fake OpenID credential. The website does not know that this is fake and sends a request to the OpenID provider. Of course the OpenID provider detects the non-existent account and denies access but already two requests have been sent – one from the user to the website and the other from the website to the OpenID provider. This in large numbers could get dangerous.

Reverse Proxy and its support by Monkey HTTP server

Reverse proxy is the process of routing client requests to backend servers. It sits in between the client and backend servers. It takes a request from the client and assigns it to one of the servers. It fetches the requested resource from the server and returns it to the client. Some of the advantages of using a reverse proxy are :

  1. Helps clients access servers that are configured beyond a firewall. Only the IP address of the proxy is publicized the outer world.
  2. Helps balance loads among different backend servers. It helps choose which server should take the load of the incoming request from the client.
  3. If one of the servers fails to deliver the content of the client request, the request can be assigned to another server.
  4. It is also possible to cache information that is requested frequently by clients. This reduces the load of having to fetch the resource from the server each time.

The following diagram gives a picture of the entire system.


Monkey plugin for reverse proxy :

The monkey server provides support for reverse proxy through the plugin proxy_reverse. You can read more about it here.

Workflow :

This is a brief workflow and where the reverse proxy plugin fits in :

  1. Incoming requests from clients
  2. The request URI is processed to check if it satisfies the regex rules
  3. Checked if a match is found on the basis of the previous search
  4. A balancing algorithm and a list of slave servers are decided on this basis
  5. The list of servers is passed to a balancing function.
  6. A balancing function determines which server should be used.
  7. A new socket is created to connect to the slave server
  8. The socket is set to non-blocking mode
  9. If a connection cannot be established, another slave server is selected and tried to connect
  10. If all servers return an error and cannot be connected to, then an error is returned.
Algorithms for balancing :

Some of balancing algorithms used for this purpose are as follows :

  1. Naive – first alive server from server
  2. First alive – first alive server from 0
  3. Round Robin
    1. with locking – uses mutexes
    2. without locking – does not use mutexes
  4. Least Connections
Some developments in future : Providing cache for reverse proxy plugin

Thanks to Sonny Karlsson, a developer of Monkey httpd server for the idea. He proposed the idea of developing a cache for reverse proxy plugin in the monkey server.

Exception case:
When Monkey server becomes one of the slave servers for reverse proxy plugin there is the possibility of a recursion happening. The following diagrams would show a normal case and the exceptional case. For this reason, it has to be identified if a request is coming from a client or a reverse proxy plugin. If it is found that the resource is not present in the cache, and the slave server to which the request is going to be redirected is Monkey server itself, this would be like an ordinary incoming request to the server, which would be processed and looked up the cache, to see if the resource is present. This will happen indefinitely. Thus, if the resource requested by a request from the proxy reverse plugin is not present in the cache and the slave server to which the request is going to be directed to is found to be Monkey, immediately the next slave server in the list is chosen and the request is sent to this server. The following diagram will show you a workflow of entire system.

Caching the reverse proxy plugin requests
Caching the reverse proxy plugin requests
References :
  1. Picture courtesy :

Virtual Hosting and its support by Monkey HTTP server

Virtual hosting is allowing one server to represent different machines. This basically for supporting multiple host names on one server. For example, there may be two websites – and that may be having the same IP address. For the two websites, even though their information is hosted on the same server, it is maintained in different directories.

There are two types of virtual hosting at the moment:
1. Name-based virtual hosting
2. IP based virtual hosting


What is its advantage ?

The advantage of virtual hosting is that a server shares its resources with multiple websites have the site content on the same server. It shares its resources like processor cycles and memory, etc. with different servers. In a server, virtual hosting is seen as a method to share the server content between different domains.

How to configure Monkey server with two virtual host ?

The following are the steps to be followed while configuring support for virtual hosts in Monkey server.

1. You need to change the /etc/hosts file to add multiple hosts to the same IP address. For example, monkey1 monkey2

So now we have two virtual hosts assigned to the same IP address.

2. Now both of these servers will have different directories under which their resources are shared, in monkey/htdocs/ directory. (monkey/htdocs/monkey1 and monkey/htdocs/monkey2)

3. Each will also need configuration file that states the Document root folder where its resources have been located and its ServerName. The example of a configuration file for one of these servers is as follows:

    Documentroot /home/savita/monkey/htdocs/monkey1
    ServerName monkey1

4. Now on typing the URL: https://monkey1:2001/monkey1/amma1.jpg this particular image which was stored in monkey1 folder is displayed on the browser. For virtual host monkey2, this resource will be present in monkey2/ directory. So if you were to type in the URL space, https://monkey2:2001/monkey2/amma2.jpg, the image that was placed in that location is obtained and displayed on the browser.

The process of having different virtual hosts. In each HTTP request, the host name and the resource URI are mentioned. Now, it checks if the particular virtual host exists and within the virtual host, a particular resource exists or not. If not, then an error is returned.

Sharing file descriptors among different requests :

Monkey follows a special method of sharing file descriptors among different requests that come to the same virtual host so that it avoids opening numerable file descriptors at the same time. This is called File Descriptor Table (FDT).

For each worker or thread, a hash table is maintained with 64 entries and each of these maintains a subarray of 8 chains. So when a request arrives at one of the virtual hosts, it hashes the name of the resource being requested (which can be obtained from the HTTP header) and looks up if the file descriptor for this resource is already present in the hash table for that particular worker. If present, instead of opening another file descriptor for the same file, the already open file descriptor is used. The number of users using that particular file descriptor is incremented. If a particular request stops using a particular file, it checks if the number of users of the file descriptor is greater than zero or not. If it is greater than 0, then a message is just returned that states that the file descriptor is still being used. Else, if the number of users of the file descriptor is zero, then the file descriptor is closed. <using close (2) system call>.

This improves the performance of the monkey server.

Under normal conditions, different virtual hosts do not share data with each other. The main reason that the sharing of file descriptors takes place between different requests within the same virtual host and not among different virtual hosts is to enable or disable such an option for various virtual hosts.

Reference :

  1. Picture Courtesy :

Monkey HTTP server

Monkey server is a lightweight Http server for Linux, written completely in C. It places immense importance on performance and consumes very less memory and for this reason, it is also favourable for embedded devices. It focuses strongly on Linux, the reason for this being that the server depends on the Linux kernel to perform operations that improve the performance of the server. It is HTTP/1.1 compliant. Some of the important features of the server are:

  1. Multi threaded architecture to handle incoming requests from clients: Each thread has the capability to handle 1000 client requests.
  2. Monkey server uses an event driven model to handle requests coming to a thread at the same time.
  3. It supports virtual hosting.
  4. Provides support for IPv4 and IPv6.

The major components of the monkey server are scheduler, threads, plugins. The monkey server has a variety of plugins that serve various functionalities.

  1. Auth – for basic HTTP authentication for users of different virtual hosts of the server.
  2. CGI – helps in enabling CGI support for monkey server.
  3. Cheetah – command line for the server.
  4. Dirlisting – showing the contents of the directory when a client requests a directory.
  5. FastCGI – for FastCGI proxy support. It acts as a proxy for Fastcgi application servers.
  6. Liana – provides the network layer support to the server.
  7. Logger – the log writer plugin that allows the server to keep track of frequently occurring issues and keep statistics.
  8. Mandril – security plugin that allows to filter incoming requests on the basis of URI or IP addresses.
  9. Polarssl – provides HTTPS support for the server
  10. Proxy reverse – provides support to the server for reverse proxying and routing back requests to backend servers.

Setting up and installation :

Follow the below steps to install and monkey from source code.

git clone 
cd monkey

Take localhost:2001 in your browser and lo ! You have successfully installed and run monkey server.


References :

You could read more about this server here :

  3. Image found here