Skip to content

Instantly share code, notes, and snippets.

@ankurs
Created December 16, 2009 19:58
Show Gist options
  • Save ankurs/258118 to your computer and use it in GitHub Desktop.
Save ankurs/258118 to your computer and use it in GitHub Desktop.
/*
* Initial implementation of a HTTP server, this is just a test which
* only manages GET request for file names
* Author: Ankur Shrivastava
* Licence: GPLv3+
*/
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/wait.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<netinet/in.h>
#include<errno.h>
#include<sys/sendfile.h>
#include<fcntl.h>
#define PORT_NUMBER 9090
#define BUF_LEN 1024
#define PROCESS_NUMBER 10
#define INDEX_FILE "index.html"
int readline(int soc, char *line, int len)
{
/*
* Reads a line from socket, line should be terminated by \n
* #TODO replace with a more efficient version
*/
char *ptr,c;
int num=0;
ptr = line;
while (1)
{
if ( (read(soc,&c,1) == 1 ) && ( len > num))
{
*ptr++ = c;
if (c == '\n')
{
*ptr = '\0';
return --num;
}
num++;
}
else
{
if (num >= len)
{
line = realloc(line,BUF_LEN * 2);
ptr = line + num;
len = BUF_LEN * 2;
}
if (errno != EINTR)
break;
}
}
return -1;
}
char * get_file(char* line)
{
if ( !strncmp(line,"GET",3))
{
char *lineptr;
lineptr = line + 5;
char name[40], *ptr;
ptr = name;
while (strncmp(lineptr," ",1))
{
*ptr = *lineptr;
ptr++;
lineptr++;
}
*ptr = '\0';
strcpy(line,name);
if (strlen(line) == 0)
{
return NULL;
}
return line;
}
return NULL;
}
int main(int argv, char **args)
{
struct sockaddr_in cliaddr, servaddr; // socket structure
int listenfd, connfd;
pid_t clipid;
if ( (listenfd = socket(AF_INET,SOCK_STREAM,0)) < 0 )
{
perror("socket");
exit(1);
}
memset( &servaddr, 0, sizeof(servaddr) ); // set serveraddr to zero
servaddr.sin_family = AF_INET; // internet socket
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // any host address
servaddr.sin_port = htons(PORT_NUMBER); // port
if ( bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0)
{
perror("bind");
exit(1);
}
if ( listen(listenfd, 10) < 0 ) // listen with wait queue of 10
{
perror("listen");
exit(1);
}
int i;
for(i=0;i<PROCESS_NUMBER;i++)
{
if ( (clipid = fork()) == 0) // fork processes
{
printf("Started PID -> %i\n",getpid());
while (1) // server infinitely
{
socklen_t clilen = sizeof(cliaddr);
/* accept blocks till we have new client connection*/
connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen);
// handle HTTP request here
// DIRTY Clean it
char *line;
line = (char *) malloc(BUF_LEN);
readline(connfd,line,BUF_LEN); // read the first request line
printf("%s", line );
char *filename;
filename = get_file(line); // get file to be opened
if (filename == NULL)
{ // if / then we send the index file
filename = malloc(sizeof(char)*strlen(INDEX_FILE));
strcpy(filename,"index.html\0");
}
// reply
char con_len[50];
char *head = "HTTP/1.1 200 OK\r\n"; // OK always #TODO handle all HTTP
char *head2 = "Content-type: text/html\r\n"; // #TODO get mime type of file
write(connfd,head,strlen(head));
write(connfd,head2,strlen(head2));
char *page_not_found = "<html><head><title>Server</title></head><body><h1>404 Not Found</h1></body></html>"; // page not found text
struct stat file_status;
if (!stat(filename,&file_status))
{ // if file exists
int fd = open(filename,O_RDONLY); // open file
size_t size = file_status.st_size; // get size
sprintf(con_len,"Content-length: %i \r\n\r\n",size); // set file size
write(connfd,con_len,strlen(con_len)); // send Content-length
sendfile(connfd,fd,NULL,size); // send file
}
else
{ // send file not found
sprintf(con_len,"Content-length: %i \r\n\r\n",strlen(page_not_found));
write(connfd,con_len,strlen(con_len));
write(connfd,page_not_found,strlen(page_not_found));
}
free(line);
// till here
close(connfd);
//exit(0);
}
}
}
int stat;
waitpid(-1,&stat,0); // #TODO handle signals
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment