Saturday, January 26, 2013

Simple HTTP Server Programming



Simple HTTP Server

Prerequisites : Socket and thread programming

HTTP is a protocol used for communication between a browser and a web server.

How HTTP works : When you type in  a URL in the browser and click GO the browser extracts the host-name section and uses DNS to obtain the IP address of the web server that host the web site. The browser then uses this IP address to form a TCP connection to the web server. The browser sends HTTP request to retrieve a specific page. If the page exist the server responds by sending the copy of the page in the HTTP response (response code - 400). If the file doesn't exists in the server, the server send  HTTP response containing a response code 404 (Not Found Error Message).


HTTP Request

  The request message syntax:
  • Request line, for eg :  GET /images/logo.png HTTP/1.1
  • Headers
  • An empty line.
  • An optional message body.
  Example of a simple HTTP request:
    GET / HTTP/1.1
    Host: 127.0.0.1:2003

Explanation:
Line 1 : "GET" indicates the request method used . Other methods are PUT, POST etc
     "/" indicates the requested page, here its the root page i.e index.html
     "HTTP/1.1" version of HTTP used
Line 2 : "HOST" host to which request is send
"127.0.0.1" IP address of host
"2003" is the port used

More about HTTP request and headers can be found at
http://en.wikipedia.org/wiki/HTTP_request


HTTP Response
The response message consists of the following:
  • A Status-Line
  • Headers
  • An empty line
  • An optional message body
Example:
HTTP/1.1 200 OK
  Content-type: text/html
<html>
<head></head>
<body>
 <h1>Header</h1>
 <p>Congrats !! your HTTP server is working.</p>
</body>
</html>

Explanation :
Line 1 : "HTTP/1.1" HTTP version used
"200" status code
"OK" description of status code
Line 2 : "Content-type: text/html" indicates type of the file.
Line 3 : HTML code of the page

More about HTTP response and headers
http://en.wikipedia.org/wiki/HTTP_response

HTTP status code
                http://en.wikipedia.org/wiki/List_of_HTTP_status_codes




/*------------------------------Simple HTTP Server----------------------------*/


#include<sys/socket.h>
#include<sys/stat.h>  
#include<sys/types.h>  
#include<netinet/in.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<pthread.h>
#include <netdb.h>

#define BUFF_LEN 1028

pthread_t c;

/* HTTP response and header for a successful request.  */
static char* ok_response =
  "HTTP/1.1 200 OK\n"
  "Content-type: text/html\n"
  "\n"
  "<html>\n"
  "<head></head>\n"
  " <body>\n"
  "  <h1>Header</h1>\n"
  "  <p>Congrats !! your HTTP server is working.</p>\n"
  " </body>\n"
  "</html>\n";

void * serve_client(int tsd)
{
int k;
char buff[BUFF_LEN]; //used to store the HTTP request
printf("[Server : %d].\n",tsd);
k=recv(tsd,buff,BUFF_LEN,0);
if(k==-1)
printf("[Server : %d] recv() failed.\n",tsd);
else printf("[Server : %d] recv() OK .\n",tsd);

// Printing the HTTP request recieved
printf("[Server : %d] Recieved : %s\n",tsd,buff);

/* Actual HTTP server does some processing and responds accordingly.
* Here I have just send a HTTP response.
*/

//Sending the HTTP response
write (tsd, ok_response, strlen (ok_response));

close(tsd);
printf("[Server : %d] going to pthread_exit().\n\n",tsd);
pthread_exit(NULL);
}


int main(int argc,char *argv[])
{ char buff[100];
int k;
socklen_t len;
int sock_desc,temp_sock_desc;
short port;
struct sockaddr_in server,client;

printf("[Server] Start . Next memset()\n");
memset(&server,0,sizeof(server));
memset(&client,0,sizeof(client));

printf("[Server] memset() OK . Next socket()\n");
sock_desc=socket(AF_INET,SOCK_STREAM,0);
printf("[Server] socket() OK . Next bind()\n");
server.sin_family=AF_INET;
server.sin_addr.s_addr=INADDR_ANY;
port = (argc > 1) ? atoi(argv[1]) : 3001; //default port : 3001
server.sin_port=htons(port);

k=bind(sock_desc,(struct sockaddr*)&server,sizeof(server));
if(k==-1)
printf("[Server] bind() failed.\n");
else printf("[Server] bind() OK . Next listen()\n");

k=listen(sock_desc,10);
if(k==-1)
printf("[Server] listen() failed.\n");
else printf("[Server] listen() OK . Next accept()\n");

len=sizeof(client);

while(1)
{
temp_sock_desc=accept(sock_desc,(struct sockaddr*)&client,&len);
printf("\n[Server] accept() OK .\n");

printf("[Server] Client IP : %s.\n",(char*)inet_ntoa(client.sin_addr));
printf("[Server] sock_desc : %d.\n",sock_desc);
printf("[Server] temp_sock_desc : %d.\n",temp_sock_desc);

/*
* Start a thread to server each client.
*/
pthread_create( &c,NULL,(void *)serve_client, (int *) temp_sock_desc);

}

close(temp_sock_desc);
close(sock_desc);
exit(0);
return 0;
}

/*------------------------------End Of Program----------------------------*/



Working :

This programs waits for a client to connect and then starts a thread to serve the client.
This thread recieves a message(HTTP request) from the client and sends a HTTP response
to the client.

A real HTTP server does more than this. It includes

  • checking if the requested file exist and send response accordingly.
  • Integration of Server side scripting languages like PHP,ASP,JSP.etc
  • status code based actions
  • caching
  • and so on


By parsing through the HTTP request the requirements of the client can be understood and
required output can be generated.


Compiling and running :

  1. Copy the code and paste it in a file,say "server.c"
  2. compile : gcc server.c -lpthread
  3. run : ./a.out 2001
  4. In browser : http://127.0.0.1:2001/