Hi! I have to make a tiny webserver in C in Unix. I have the first part of the code given by my teacher, and i have to add some extra tasks to it . I dont know why when i compile my code i have some errors. I post now the codes:
1. teacher's first part of the code
[spoiler]
Code:
// skeleton version of a tiny webserver, minimal error handling
// by U. Willers - 07.11.2013
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <strings.h>
#include <stdlib.h>
#include <errno.h> // size_t, pid_t
// accept, bind, listen
// sockaddr_in, htons
// printf
// bzero, strncmp
// exit
// strerror
#define BUFSIZE 8096 // size of request buffer
// Prototypes, maybe outsource to webserver.h
void handle_request( int s1 );
size_t strlen( const char *s );
int setup_webserver( void );
int respectRequests(char *request);
int SplitTheRequest(char *request);
int main( void )
{
int server_socket, client_socket, addrlen;
struct sockaddr_in client_addr;
printf( "Starting webserver...\n" );
server_socket = setup_webserver(); // create socket and listen on it
while( 1 ) // infinite loop
{
addrlen = sizeof( client_addr ); // wait for client requests
client_socket = accept( server_socket, (struct sockaddr*) &client_addr, &addrlen ); // process request
handle_request( client_socket );
}
}
int setup_webserver( void )
{
int s, ret;
struct sockaddr_in s_addr; // create TCP/IP socket
s = socket( AF_INET, SOCK_STREAM, 0 ); // listen on port 80 (http) at localhost for client requests
bzero( &s_addr, sizeof( s_addr ) ); // clear data structure
s_addr.sin_family = AF_INET; // IP address
s_addr.sin_port = htons( 80 ); // port is 80
s_addr.sin_addr.s_addr = INADDR_ANY; // addr. is 127.0.0.1
// bind port and addr. to socket
ret = bind( s, (struct sockaddr*) &s_addr, sizeof( s_addr ) );
if( ret < 0 ) // error?
{
// Yes, convert into error message
printf( "Bind Error: %s\n", strerror( errno ) );
exit( 1 ); // terminate program and return error code
}
listen( s, 5 ); // wait for requests, max. 5 requests in queue
return( s ); // return server socket descriptor
} // Entry: cs is client socket descriptor
void handle_request( int cs )
{
char request[BUFSIZE]; // buffer for first line of client request
int i = 0;
char c; // buffer for one input character
// read client request and terminate it with 0
printf( "Annalize & Getting request: " );
while( read( cs, &c, 1 ) == 1 && c != '\n' && c != '\r' && i < sizeof( request ) -1 )
request[i++] = c;
request[i] = '\0'; // terminate string
if(respectRequests(request)==0)
{
printf( "%s\n", request ); // print request
SplitTheRequest(request);
}
if (respectRequests(request)==-1)
{
printf( " INCORRECT!!!\n"); // print request
}
close( cs );
}
[/spoiler]
Tasks:
[spoiler]Enhance the web server so that only GET requests will be processed. Extract the file name from the GET request and sent the contents of that file to the client. Map GET / to GET index.html. Prevent absolute paths and the relative path .. being used in the request. This restricts the webserver to the chosen document root folder.[/spoiler]
[spoiler]Update your web server program to use child processes for each client request. Print all error messages to stderr.[/spoiler]
[spoiler]Check if the client request ask for valid file extension. Supply the correct MIME type in the HTTP header of your answer to the client.[/spoiler]
My new code made with my colleague's help:
[spoiler]
Code:
// skeleton version of a tiny webserver, minimal error handling
// by U. Willers - 07.11.2013
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <string.h>
#include <strings.h>
#include <sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#define BUFSIZE 8096
// Prototypes, maybe outsource to webserver.h
void handle_request( int client_socket, int server_socket);
int setup_webserver( void );
void makeHeader(int type, char * request,int client_socket);
void * openFile(char *request, int client_socket, char * read);
char * readFile(char *uri);
int prevent(char *request);
char *withoutBar ( char * uri );
char * checkUri (char * request);
int main( void )
{
int server_socket, client_socket, addrlen;
struct sockaddr_in server_addr, client_addr;
printf( "Starting webserver...\n" );
server_socket = setup_webserver(); // create socket and listen on it
while( 1 )
{
addrlen = sizeof( server_addr ); // wait for client requests
client_socket = accept( server_socket, (struct sockaddr*) &server_addr, &addrlen ); // process request
printf("Client connected ...\n");
handle_request( client_socket, server_socket);
}
}
int setup_webserver( void )
{
int server_socket;
int on = 1;
struct sockaddr_in server_addr;
server_socket = socket( AF_INET, SOCK_STREAM, 0 );
setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int));
bzero( &server_addr, sizeof( server_addr ) );
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons( 80 );
if(bind(server_socket, (struct sockaddr *) &server_addr, sizeof(server_addr)) == -1)
{
perror("bind");
close(server_socket);
exit(1);
}
if(listen(server_socket,5) == -1 )
{
perror("listen");
close(server_socket);
exit(1);
}
return( server_socket );
}
void handle_request( int client_socket , int server_socket)
{
char request[2048]; // buffer for first line of client request
int i = 0;
int status;
char c; // buffer for one input character
// read client request and terminate it with 0
printf( "Getting request: \n" );
read(client_socket,request,2047);
//printf( "Client request: %s\n", request );
waitpid(-1,&status,WNOHANG);
if(!fork())
{
// child process
if(prevent(request) == 0)
{
close(server_socket);
makeHeader ( 200, request, client_socket );
exit(0);
}
else
{
makeHeader( 403, request, client_socket );
}
}
//parent process
waitpid(-1,&status,WNOHANG);
close( client_socket );
}
void * openFile(char *request, int client_socket, char * read)
{
int fdimg;
if(!strncmp(request,"GET /favicon.ico", 16))
{
fdimg = open("icon.png", O_RDONLY);
sendfile(client_socket, fdimg, NULL, 4000);
close(fdimg);
}
else if(!strncmp(request,"GET /image.jpg", 14))
{
fdimg = open("image.jpg", O_RDONLY);
sendfile(client_socket, fdimg, NULL, 50000);
close(fdimg);
}
else
{
write(client_socket, read, strlen(read));
}
}
void makeHeader(int type, char * request,int client_socket)
{
if(type == 200)// ok
{
if(!strncmp(request,"GET / ",5))
{
char * read;
read = readFile("index.html");
openFile( request, client_socket, read );
}
else
{
char * file;
char * read;
file = withoutBar(checkUri(request));
read = readFile(file);
openFile( request, client_socket, read );
}
}
else if(type == 403) // forbbiden
{
char *read;
read = readFile("forbidden.html");
openFile( request, client_socket, read );
}
else if(type == 404) // not found
{
char *read;
read = readFile("notfound.html");
}
}
char * readFile(char *uri)
{
FILE *fp;
fp = fopen(uri,"r");
char *out = NULL;
char arquivo[1024], buffer[1024] = {""};
if(fp != NULL)
{
while(fgets(arquivo, sizeof(arquivo), (FILE*)fp) != NULL)
strcat(buffer, arquivo);
fclose(fp);
out = buffer;
return out;
}
else
return NULL;
}
int prevent(char *request)
{
char verifica[4];
int i;
if(strncmp(request, "GET ", 4) == 0)
{
for(i = 0; i < strlen(request) - 1; i++)
{
verifica[0] = request[i];
verifica[1] = request[i+1];
if(strncmp(verifica, "..", 2) == 0)
return -1;
}
return 0;
}
else
{
return -1;
}
}
char * checkUri (char * request)
{
char aux[256];
char *out;
int i;
for(i = 5; strlen (request); i++)
{
if(request[i] != ' ')
{
aux[i-5] = request[i];
}
else
{
out = aux;
return out;
}
}
return out;
}
char *withoutBar ( char * uri )
{
int i;
char aux[256];
char * out;
for(i =1; i<strlen(uri);i++)
{
aux[i-1] = uri[i];
}
out = aux;
return out;
}
[/spoiler]
IF somebody has any ideeas how to solve this i am waiting for it !
Thanks !!!