A http-Web-server in C..

lionaneesh 0 Tallied Votes 2K Views Share

This is a simple-web-server made in C..

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


Note: See i am just 15 yrs old and a beginner in C and doing C since 8 months
so please tell me how did you guys like this project and lets make it better !! Hows that!!!

Will comment my source completely for better understanding shortly ..
Thank you for reading my source ..

#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);
}

Dani AI

Generated

Nice work, . A few small changes will make this little HTTP server safer and more useful on a LAN. First, do not run the whole process as root just to bind a low port. Bind once, then drop privileges (setgid/setuid) or grant only the bind capability to the binary: sudo setcap cap_net_bind_service=+ep ./your_server. Also add SO_REUSEADDR and ignore SIGPIPE to avoid crashes when clients disconnect mid-transfer.

, for simple file sharing, serve a single document root and strictly map URLs to files. Always normalize the requested path, block .., and reply with 403/404 when appropriate. Headers must use CRLF and end with a blank line. A tiny, safe-ish static file handler looks like this:

// after parsing "GET /path HTTP/1.1"
const char *docroot = "/srv/www";
char candidate[PATH_MAX], resolved[PATH_MAX];
const char *p = (url_path[0] == '/') ? url_path + 1 : url_path;
snprintf(candidate, sizeof(candidate), "%s/%s", docroot, *p ? p : "index.html");

if (!realpath(candidate, resolved) ||
    strncmp(resolved, docroot, strlen(docroot)) != 0) { send_403(client); return; }

int fd = open(resolved, O_RDONLY);
struct stat st; if (fd < 0 || fstat(fd, &st) < 0) { send_404(client); return; }

dprintf(client,
    "HTTP/1.1 200 OK\r\nContent-Length: %ld\r\nContent-Type: %s\r\nConnection: close\r\n\r\n",
    (long)st.st_size, mime_from_ext(resolved));
sendfile(client, fd, NULL, st.st_size);

A few more tips:

  • Parse only what you need (method, path, version). Cap request line and header size to avoid abuse.
  • Default to Connection: close until you implement keep-alive.
  • Start with a single-threaded loop; then scale using select/poll for multiple clients.
  • Consider an optional directory listing for convenience, but keep it confined to the docroot.
Tellalca 19 Posting Whiz in Training

Good job but if you dont have any questions you should send this thread to "Show off your projects".

challarao 0 Junior Poster in Training

Please tell me how to do file sharing on local network with this program

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.