#include #include #include #include #include #include #include #include #include #include #include #define VERSION 23 #define BUFSIZE 8096 #define ERROR 42 #define LOG 44 #define FORBIDDEN 403 #define NOTFOUND 404 struct { char *ext; char *filetype; } extensions [] = { {"gif", "image/gif" }, {"jpg", "image/jpg" }, {"jpeg","image/jpeg"}, {"png", "image/png" }, {"ico", "image/ico" }, {"zip", "image/zip" }, {"gz", "image/gz" }, {"tar", "image/tar" }, {"htm", "text/html" }, {"html","text/html" }, {"css", "text/css" }, {"js", "text/js" }, {"json","application/json" }, {0,0} }; void logger(int type, char *s1, char *s2, int socket_fd) { int fd ; char logbuffer[BUFSIZE*2]; switch (type) { case ERROR: (void)sprintf(logbuffer,"ERROR: %s:%s Errno=%d exiting pid=%d",s1, s2, errno,getpid()); break; case FORBIDDEN: (void)write(socket_fd, "HTTP/1.1 403 Forbidden\nContent-Length: 185\nConnection: close\nContent-Type: text/html\n\n\n403 Forbidden\n\n

Forbidden

\nThe requested URL, file type or operation is not allowed on this simple static file webserver.\n\n",271); (void)sprintf(logbuffer,"FORBIDDEN: %s:%s",s1, s2); break; case NOTFOUND: (void)write(socket_fd, "HTTP/1.1 404 Not Found\nContent-Length: 136\nConnection: close\nContent-Type: text/html\n\n\n404 Not Found\n\n

Not Found

\nThe requested URL was not found on this server.\n\n",224); (void)sprintf(logbuffer,"NOT FOUND: %s:%s",s1, s2); break; case LOG: (void)sprintf(logbuffer," INFO: %s:%s:%d",s1, s2,socket_fd); break; } /* No checks here, nothing can be done with a failure anyway */ if((fd = open("ittpd.log", O_CREAT| O_WRONLY | O_APPEND,0644)) >= 0) { (void)write(fd,logbuffer,strlen(logbuffer)); (void)write(fd,"\n",1); (void)close(fd); } if(type == ERROR || type == NOTFOUND || type == FORBIDDEN) exit(3); } /* this is a child web server process, so we can exit on errors */ void web(int fd, int hit) { int j, file_fd, buflen; long i, ret, len; char * fstr; static char buffer[BUFSIZE+1]; /* static so zero filled */ ret =read(fd,buffer,BUFSIZE); /* read Web request in one go */ if(ret == 0 || ret == -1) { /* read failure stop now */ logger(FORBIDDEN,"failed to read browser request","",fd); } if(ret > 0 && ret < BUFSIZE) /* return code is valid chars */ buffer[ret]=0; /* terminate the buffer */ else buffer[0]=0; for(i=0;i 0 ) { (void)write(fd,buffer,ret); } sleep(1); /* allow socket to drain before signalling the socket is closed */ close(fd); exit(1); } int main(int argc, char **argv) { int i, port, pid, listenfd, socketfd, hit; socklen_t length; static struct sockaddr_in cli_addr; /* static = initialised to zeros */ static struct sockaddr_in serv_addr; /* static = initialised to zeros */ if( argc < 3 || argc > 3 || !strcmp(argv[1], "-?") ) { (void)printf("hint: ittpd Port-Number Top-Directory\t\tversion %d\n\n" "ittpd is a very small web server\n" "\n" "example: ittpd 8181 /server/website\n" ); exit(0); } if( !strncmp(argv[2],"/" ,2 ) || !strncmp(argv[2],"/etc", 5 ) || !strncmp(argv[2],"/bin",5 ) || !strncmp(argv[2],"/lib", 5 ) || !strncmp(argv[2],"/tmp",5 ) || !strncmp(argv[2],"/usr", 5 ) || !strncmp(argv[2],"/dev",5 ) || !strncmp(argv[2],"/sbin",6) ){ (void)printf("ERROR: Bad top directory %s, see ittpd -?\n",argv[2]); exit(3); } if(chdir(argv[2]) == -1){ (void)printf("ERROR: Can't Change to directory %s\n",argv[2]); exit(4); } /* Become deamon + unstopable and no zombies children (= no wait()) */ if(fork() != 0) return 0; /* parent returns OK to shell */ (void)signal(SIGCHLD, SIG_IGN); /* ignore child death */ (void)signal(SIGHUP, SIG_IGN); /* ignore terminal hangups */ for(i=0;i<32;i++) (void)close(i); /* close open files */ (void)setpgrp(); /* break away from process group */ logger(LOG,"ittpd starting",argv[1],getpid()); /* setup the network socket */ if((listenfd = socket(AF_INET, SOCK_STREAM,0)) <0) logger(ERROR, "system call","socket",0); port = atoi(argv[1]); if(port < 0 || port >60000) logger(ERROR,"Invalid port number (try 1->60000)",argv[1],0); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); serv_addr.sin_port = htons(port); if(bind(listenfd, (struct sockaddr *)&serv_addr,sizeof(serv_addr)) <0) logger(ERROR,"system call","bind",0); if( listen(listenfd,64) <0) logger(ERROR,"system call","listen",0); for(hit=1; ;hit++) { length = sizeof(cli_addr); if((socketfd = accept(listenfd, (struct sockaddr *)&cli_addr, &length)) < 0) logger(ERROR,"system call","accept",0); if((pid = fork()) < 0) { logger(ERROR,"system call","fork",0); } else { if(pid == 0) { /* child */ (void)close(listenfd); web(socketfd,hit); /* never returns */ } else { /* parent */ (void)close(socketfd); } } } }