A http-Web-server in C

lionaneesh's Avatar author of A http-Web-server in C
This is an article on A http-Web-server in C in C.
Rated 5.00 By 1 users
A simple code of Http-Web-Server in C done by a beginner level programmer. Please suggest if you liked it and lets make it better !! Hows that!!!

The Code



Code:
#include<stdio.h>
#include<string.h>
#include<arpa/inet.h>
#include<netdb.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<stdlib.h>

#define port "80"                
#define webroot "/home/aneesh/aniroot"            // Directory to put in your files you want to host.. This is the pathname the software uses to 
                                //    read files from


int get_file_size(int fd)
{
    struct stat stat_struct;
    if(fstat(fd, &stat_struct) == -1)
        return(1);
    return (int)stat_struct.st_size;
}

void send_new(int fd,char *msg)
{
    int len = strlen(msg);
    if(send(fd,msg,len,0) == -1)
    {
        printf("Error in send\n");
    }
}

int recv_new(int fd,char *buffer)        // This function recieves the buffer untill a "End of line" byte is recieved
{
    #define EOL "\r\n"
    #define EOL_SIZE 2

    char *p = buffer;            // we'll be using a pointer to the buffer than to mess with buffer directly
    int eol_matched=0;            // this is used to see that the recieved byte matched the buffer byte or not 

    while(recv(fd,p,1,0)!=0)        // start recv bytes 1 by 1
    {
        if( *p == EOL[eol_matched])    // if the byte matched the first eol byte that is '\r'
        {    
            ++eol_matched;        

            if(eol_matched==EOL_SIZE)    // if both the bytes matches the EOL
            {
                *(p+1-EOL_SIZE) = '\0';    // End the string
                return(strlen(buffer));    // return the bytes recieved 
            }
        }
        else
        {
            eol_matched=0;            
        }
        p++;                    // increment the pointer to recv next byte
    }
    return(0);
}
            
int connection(int fd)
{
    char request[500],resource[500],*ptr;        
    int fd1,length;

    if(recv_new(fd,request) == 0)
    {
        printf("Recieve failed\n");
    }

    // Checking for a valid browser request

    ptr = strstr(request," HTTP/");
    if(ptr == NULL)
    {
        printf("NOT HTTP!!\n");
    }
    else
    {
        *ptr=0;
        ptr=NULL;
    
        



        if( strncmp(request,"GET ",4) == 0)
        {
            ptr=request+4;
        }
        if(strncmp(request,"HEAD ",5) == 0)
            ptr=request+5;

        if(ptr==NULL)
        {
            printf("Unknown Request !!! \n");
        }
        else
        {
            if( ptr[strlen(ptr) - 1] == '/' )
            {
                strcat(ptr,"index.html");
            }
            strcpy(resource,webroot);
            strcat(resource,ptr);
            fd1 = open(resource,O_RDONLY,0);
            printf("Opening \"%s\"\n",resource);
            if(fd1 == -1)
            {
                printf("404 File not found Error\n");
                send_new(fd,"HTTP/1.0 404 Not Found\r\n");
                send_new(fd,"Server : Aneesh/Private\r\n\r\n");
                send_new(fd,"<html><head><title>404 not found error!! :( </head></title>");
                send_new(fd,"<body><h1>Url not found</h1><br><p>Sorry user the url you were searching for was not found on this server!!</p><br><br><br><h1>Aneesh's Server</h1></body></html>");
            }
            else
            {
                printf("200 OK!!!\n");
                send_new(fd,"HTTP/1.0 200 OK\r\n");
                send_new(fd,"Server : Aneesh/Private\r\n\r\n");
                if( ptr == request+4 ) // if it is a get request
                {
                    if( (length = get_file_size(fd1)) == -1 )
                        printf("Error getting size \n");
                    if( (ptr = (char *)malloc(length) ) == NULL )
                        printf("Error allocating memory!!\n");
                    read(fd1,ptr,length);
            
                    if(send(fd,ptr,length,0) == -1)
                    {
                        printf("Send err!!\n");
                    }
                    free(ptr);
                }
            }
            close(fd);
        }
    }
    shutdown(fd,SHUT_RDWR);
}            
int main()
{
    int sockfd,newfd;
    int err;
    struct addrinfo *res,*p,hints;
    struct sockaddr_storage their_addr;
    socklen_t addr_size;
    int yes=1;
    char ip[INET6_ADDRSTRLEN];

    memset(&hints,0,sizeof(hints));
    hints.ai_family=AF_UNSPEC;
    hints.ai_flags=AI_PASSIVE;
    hints.ai_socktype=SOCK_STREAM;

    printf("Server is open for listening on port 80\n");

    if( (err = getaddrinfo(NULL,port,&hints,&res) ) == -1)
    {
        printf("Err in getaddrinfo : %s\n",gai_strerror(err));
        return(1);
    }

    for(p=res;p!=NULL;p=p->ai_next)
    {        
        if( ( sockfd = socket(p->ai_family,p->ai_socktype,p->ai_protocol) ) == -1)
        {
            printf("Socket error !!!\n");
            continue;
        }
        if( setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1)
        {
            printf("Setsockopt err!!\n");
            return(1);
        }

        if( bind(sockfd,p->ai_addr,p->ai_addrlen) == -1)
        {
            printf("Binding err\n");
            close(sockfd);            
            continue;
        }
        
        break;
    }

    if( listen(sockfd,15) == -1)
    {
        printf("Error in listen\n");
        return(1);
    }
    
    while(1)
    {
    
        char y;    
        addr_size = sizeof(their_addr);
        if( ( newfd = accept(sockfd, (struct sockaddr *)&their_addr,&addr_size) ) == -1)
        {
            printf("Error in accept!\n");
            return(1);
        }
        for(p=res;p!=NULL;p=p->ai_next)
        {
            void *addr;
            
            if(p->ai_family == AF_INET)
            {
                struct sockaddr_in *ip;
                ip = (struct sockaddr_in *)p->ai_addr;
                addr = &(ip->sin_addr);
            }
            if(p->ai_family == AF_INET6)
            {
                struct sockaddr_in6 *ip;
                ip = (struct sockaddr_in6 *)p->ai_addr;
                addr = &(ip->sin6_addr);
            }
            
            inet_ntop(p->ai_family,addr,ip,sizeof(ip));
            printf("Got connection from %s\n",ip);
        }
        connection(newfd);
    }

    freeaddrinfo(res);
    close(newfd);
    close(sockfd);
    return(0);
}

Supported OS



I have made it on Ubuntu 9.10 ... and i think it will run on all linux system .... Windows is not supported

Compiler instructions



As this is a web server so it will host on port 80 to run this you need administrative rights i.e sudo rights ..

commands :-

compile : gcc "name" -o "o_name"
run : sudo ./name

Will comment my source completely for better understanding shortly ..
Thank you for reading my source..
0
shabbir's Avatar, Join Date: Jul 2004
Go4Expert Founder
Not bad stuff for and 8 month old programmer but I have changed your some wordings in the article
IT Fan like this
0
shabbir's Avatar, Join Date: Jul 2004
Go4Expert Founder
If you liked this article do nominate this article for Article of the month - May 2010
0
DevPro's Avatar
Go4Expert Member
Mh pretty good work. I didn't know that it would be possible to create a webserver with so few code in C. I actually work on a similar software in C# and its much much much more code. My suggestion would be that you should use mutli threading to support concurrent connections.
0
lionaneesh's Avatar, Join Date: Mar 2010
Invasive contributor
Yeah sure Sir .. Still learning that stuff They are not so easy for a self learner can you suggest me some good tutorials on selectors Except the BEEJ's One...
0
IT Fan's Avatar, Join Date: May 2010
Go4Expert Member
Not bad!! Go ahead! You must be a very smart guy.
0
lionaneesh's Avatar, Join Date: Mar 2010
Invasive contributor
Thanks a ton ... Sir
0
shabbir's Avatar, Join Date: Jul 2004
Go4Expert Founder
You can vote for this article for Article of the month - May 2010. Vote now.
0
lionaneesh's Avatar, Join Date: Mar 2010
Invasive contributor
A message to all the Viewers of this article :-

This source is now a Opensource project and being developed further...
If anybody want to trace the project or anybody who wanna join us programming it and adding new features
Visit the Official Project Page :-
https://sourceforge.net/projects/ani-server/
0
shabbir's Avatar, Join Date: Jul 2004
Go4Expert Founder
Quote:
Originally Posted by lionaneesh View Post
A message to all the Viewers of this article :-

This source is now a Opensource project and being developed further...
If anybody want to trace the project or anybody who wanna join us programming it and adding new features
Visit the Official Project Page :-
https://sourceforge.net/projects/ani-server/
Great move buddy and once you release your first version do let me know and we can look into making a donation under the Support Open Source campaign