123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444 |
- // CTHTTPD - Simple Web Server - GPLv2
- // Chris Dorman, 2012-2014 (cddo@riseup.net)
- // Help from Nickolai Vurgaft (slipperygate@gmail.com)
- #include "chttpd.h"
- #include "functions.h"
- #include "mimetypes.h"
- #include "check.h"
- #include "cgi.h"
- #include "dep.h"
- #include "log.h"
- const char *client = "chttpd";
- const char *version = "1.3.1b";
- const char *sys_lable = "Linux";
- int forward_slash = 47; // forward slash in ascii
- #define CONFBUF 1024
- char *equal = "=";
- struct config
- {
- char htdocs[CONFBUF];
- char port[CONFBUF];
- char status[CONFBUF];
- char cgi[CONFBUF];
- char maxspeed[CONFBUF];
- };
- // write to struct
- struct config get_config(char *filename)
- {
- struct config configstruct;
- // open config as readable
- FILE *file = fopen (filename, "r");
-
- // check if config opens successfully
- if( access( filename, F_OK ) == -1 ) {
- memcpy(configstruct.status,"1",1);
- }
- else
- {
- memcpy(configstruct.status,"0",1);
- }
-
- // if file is null, end
- if (file != NULL)
- {
- // line buffer for config
- char line[CONFBUF];
- // int used to track config line
- //int i = 0;
-
- // config while loop, loops fgets until end of file
- while(fgets(line, sizeof(line), file) != NULL)
- {
-
- char *cfline; // setup string
- cfline = strtok(line, equal);
-
-
- // if line is commented out, skip
- if (strncmp("#",line,1)==0)
- continue;
-
- if (strncmp("HTDOCS",cfline,6)==0 || strncmp("htdocs",cfline,6)==0) {
-
- cfline = strtok(NULL, equal); // call strtok to get value
- // if newline is found, remove newline from string
- if(cfline[strlen(cfline)-1] == '\n')
- cfline[strlen(cfline)-1] = 0;
- // write htdocs path to struct
- memcpy(configstruct.htdocs,cfline,strlen(cfline));
-
- } else if (strncmp("PORT",cfline,4)==0 || strncmp("port",cfline,4)==0){
-
- cfline = strtok(NULL, equal); // call strtok to get value
- // if newline is found, remove newline from string
- if(cfline[strlen(cfline)-1] == '\n')
- cfline[strlen(cfline)-1] = 0;
- // write port to struct
- memcpy(configstruct.port,cfline,strlen(cfline));
-
- } else if (strncmp("ENABLE_CGI",cfline,10)==0 || strncmp("enable_cgi",cfline,10)==0){
-
- cfline = strtok(NULL, equal); // call strtok to get value
- // if newline is found, remove newline from string
- if(cfline[strlen(cfline)-1] == '\n')
- cfline[strlen(cfline)-1] = 0;
- // write cgi status to struct
- memcpy(configstruct.cgi,cfline,strlen(cfline));
- } else if (strncmp("MAX_SEND_SPEED",cfline,14)==0 || strncmp("max_send_speed",cfline,10)==0){
-
- cfline = strtok(NULL, equal); // call strtok to get value
- // if newline is found, remove newline from string
- if(cfline[strlen(cfline)-1] == '\n')
- cfline[strlen(cfline)-1] = 0;
- // write cgi status to struct
- memcpy(configstruct.maxspeed,cfline,strlen(cfline));
- }
-
- } // End while
- } // End if file
-
- fclose(file);
-
- return configstruct;
-
- }
- void web(int fd, int hit, char *datadir, char *cgistatus, char *throttle_speed)
- {
- int j, file_fd, buflen, len, contentfs;
- long i, filesize;
- char *fstr;
- //char *exten;
- char *path;
- char *protocol;
- char *stripslash_index;
- char *stripslash_path;
- size_t pathlen;
- static char buffer[BUFSIZE+1];
- static char listbuffer[LIST_BUFSIZE*2];
- // Check to see if file is corrupted
- filesize = read(fd,buffer,BUFSIZE);
- if(filesize == 0 || filesize == -1) {
- do_chttpd_log(SORRY,"failed to read browser request","",fd);
- }
-
- if(filesize > 0 && filesize < BUFSIZE) {
- buffer[filesize]=0;
- } else {
- buffer[0]=0;
- }
-
- for(i=0;i<filesize;i++) {
- if(buffer[i] == '\r' || buffer[i] == '\n') {
- buffer[i]='*';
- }
- }
- do_chttpd_log(LOG,"request",buffer,hit);
- if(strncmp(buffer,"GET ",4) && strncmp(buffer,"get ",4)) {
- do_chttpd_log(SORRY,"Only simple GET operation supported",buffer,fd);
- }
-
- for(i=4;i<BUFSIZE;i++) {
- if(buffer[i] == ' ') {
- buffer[i] = 0;
- break;
- }
- }
- for(j=0;j<i-1;j++)
- if(buffer[j] == '.' && buffer[j+1] == '.')
- do_chttpd_log(SORRY,"Parent directory (..) path names not supported",buffer,fd);
-
- if(!strncmp(&buffer[0],"GET /\0",6) || !strncmp(&buffer[0],"get /\0",6)) {
- if(file_exists("index.html") == 0) {
- strcpy(buffer,"GET /index.html");
- } else {
- DIR *d = opendir(".");
- struct dirent* dirp; // struct dirp for directory listing
-
- sprintf(listbuffer,"HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n");
- write(fd,listbuffer,strlen(listbuffer)); // write header socket
-
- sprintf(listbuffer,"<!DOCTYPE html>\r\n"
- "<html>\r\n"
- "<head>\r\n"
- "\t<title>Directory listing of /</title>\r\n"
- "</head>\r\n"
- "<body>\r\n"
- "\t<h2>Directory listing of /</h2>\r\n"
- "\t<hr />\r\n<table>\r\n");
- write(fd,listbuffer,strlen(listbuffer)); // write list html to socket
-
- // There is no parent directory at the root of the web servers filesystem xD
- //sprintf(listbuffer,"\t<tr><td><a href=\"..\">Parent Directory</a></td></tr>\r\n");
- //write(fd,listbuffer,strlen(listbuffer));
-
- // Start listing files and directories
- while ((dirp = readdir(d)))
- {
- if (dirp->d_name[0] == '.')
- continue;
-
- sprintf(listbuffer,"\t<tr><td><a href=\"%s\">%s</a></td></tr>\r\n", dirp->d_name, dirp->d_name);
- write(fd,listbuffer,strlen(listbuffer));
- }
- sprintf(listbuffer,"\t</table>\r\n<hr /><address>%s %s (%s)</address>\r\n</body>\r\n</html>\r\n", client, version, sys_lable);
- write(fd,listbuffer,strlen(listbuffer));
- exit(0);
- }
-
- }
- // set uri path
- path = fixpath(strchr(buffer,' '));
- path++;
-
- // get protocol
- protocol = strchr(path,' ');
- protocol++;
-
- pathlen = strlen(path);
- if(is_dir(path) == 1) {
- if(path[pathlen - 1] != forward_slash) // if there is no "/" at the end of the url, add it
- {
- strcat(path,"/");
- sprintf(listbuffer,"HTTP/1.0 301 Moved Permanently\r\nLocation: %s\r\n\r\n", path); //header to buffer
- write(fd,listbuffer,strlen(listbuffer)); // write header to socket
- //sprintf(listbuffer,"<html><meta http-equiv=\"refresh\" content=\"0;url=%s\"></html>",path);
- //write(fd,listbuffer,strlen(listbuffer)); // write redirect
- exit(0); // stop here, let the browser reconnect with a new url
- }
- }
-
- // Check if directory was requested, if so, send index.html
- if (is_dir(path) == 1) {
- char getindex[PATH_MAX];
-
- strcpy(getindex,path);
- strcat(getindex,"index.html");
-
- stripslash_index = getindex + 1; // directory + index (for index redirection)
- stripslash_path = path + 1; // get full path
-
- if(file_exists(stripslash_index) != 0)
- {
- DIR *d = opendir(stripslash_path);
- struct dirent* dirp; // struct dirp for directory listing
-
- sprintf(listbuffer,"HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n");
- write(fd,listbuffer,strlen(listbuffer)); // write header socket
-
- sprintf(listbuffer,"<!DOCTYPE html>\r\n"
- "<html>\r\n"
- "<head>\r\n"
- "\t<title>Directory listing of %s</title>\r\n"
- "</head>\r\n"
- "<body>\r\n"
- "\t<h2>Directory listing of %s</h2>\r\n"
- "\t<hr />\r\n<table>\r\n", path, path);
- write(fd,listbuffer,strlen(listbuffer)); // write list html to socket
-
- sprintf(listbuffer,"\t<tr><td><a href=\"..\">Parent Directory</a></td></tr>\r\n");
- write(fd,listbuffer,strlen(listbuffer));
-
- // Start listing files and directories
- while ((dirp = readdir(d)))
- {
- if (dirp->d_name[0] == '.')
- continue;
- sprintf(listbuffer,"\t<tr><td><a href=\"%s\">%s</a></td></tr>\r\n", dirp->d_name, dirp->d_name);
- write(fd,listbuffer,strlen(listbuffer));
- }
- sprintf(listbuffer,"\t</table>\r\n<hr /><address>%s %s (%s)</address>\r\n</body>\r\n</html>\r\n", client, version, sys_lable);
- write(fd,listbuffer,strlen(listbuffer));
- exit(0);
- }
- else
- {
- strcat(path,"index.html");
- }
- }
-
- // Check file extensions and mime types before sending headers
- buflen=strlen(buffer);
- fstr = (char *)0;
- //exten = (char *)0;
- for(i=0;extensions[i].ext != 0;i++) {
- len = strlen(extensions[i].ext);
- if( !strncmp(&buffer[buflen-len], extensions[i].ext, len)) {
- fstr = extensions[i].filetype;
- //exten = extensions[i].ext;
- break;
- }
- }
-
- if(fstr == 0) {
- fstr = "application/octet-stream";
- }
-
- if(strncmp("serverlog",fstr,9)==0) do_chttpd_log(SORRY,"Cannot retrieve server logs, forbidden!",buffer,fd);
- if(( file_fd = open(&path[1],O_RDONLY)) == -1) {
- do_chttpd_log(SORRY, "failed to open file",&path[1],fd);
- }
-
- if(strncmp("yes",cgistatus,3)==0) {
- if(strncmp("servercgi",fstr,9)==0) {
- do_cgi(path,fd,datadir);
- exit(0);
- }
- }
- else
- {
- if(strncmp("servercgi",fstr,9)==0) {
- do_chttpd_log(SORRY, "CGI disabled - ", "Cannot access CGI script", fd);
- }
- }
-
- struct stat filesz;
- stat(&path[1], &filesz);
- contentfs = filesz.st_size;
- do_chttpd_log(LOG,"SEND",&path[1],hit);
- sprintf(buffer,"HTTP/1.0 200 OK\r\nContent-Type: %s\r\n", fstr);
- write(fd,buffer,strlen(buffer));
-
- // Add content length to http header
- sprintf(buffer,"Content-Length: %d\r\n\r\n", contentfs);
- write(fd,buffer,strlen(buffer));
-
- int time_ms, bufchunk, limit, dothrottle;
-
- if(strncmp("0",throttle_speed,1)!=0) {
-
- limit = atoi(throttle_speed);
- bufchunk = 4096;
- time_ms = 1000/(limit/bufchunk);
-
- if(time_ms<1) {
- dothrottle = 0;
- } else {
- dothrottle = 1;
- }
- } else {
- dothrottle = 0;
- }
-
- if(dothrottle == 1) {
- while((filesize = read(file_fd, buffer, BUFSIZE)) > 0) {
- ms_sleep(time_ms);
- write(fd,buffer,filesize);
- }
- }
- else
- {
- while((filesize = read(file_fd, buffer, BUFSIZE)) > 0) {
- write(fd,buffer,filesize);
- }
- }
-
- #ifdef LINUX
- sleep(1);
- #endif
- 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 struct sockaddr_in serv_addr;
-
- struct config configstruct; // config struct
- if(argc > 2 || argc < 2 || !strcmp(argv[1], "-?") || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
- printf("usage: chttpd [chttpd config] &\n"
- "Example: chttpd /path/to/config.conf &\n");
- exit(0); // give exit code error
- }
-
- if(argc == 2) {
- configstruct = get_config(argv[1]);
- if(atoi(configstruct.status) == 1) {
- printf("ERROR: Can't find configuration file at %s.\n", argv[1]);
- exit(1); // give exit code error
- }
- }
-
- //
- // Parse the config file
- //
-
- if(chdir(configstruct.htdocs) == -1) {
- printf("Warning: failed to chdir Errno: %d\n", errno);
- printf("Warning: Failed to set htdocs value: %s\n", configstruct.htdocs);
- exit(1);
- }
-
- if(fork() != 0)
- return 1;
-
- signal(SIGCLD, SIG_IGN);
- signal(SIGHUP, SIG_IGN);
- for(i=0;i<32;i++)
- close(i);
- setpgrp();
- port = (int) strtol(configstruct.port, NULL, 0);
- do_chttpd_log(LOG,"CHTTPD server starting",configstruct.port,getpid());
- if((listenfd = socket(AF_INET, SOCK_STREAM,0)) <0) {
- do_chttpd_log(ERROR, "system call","socket",0);
- }
-
- if(port < 0 || port > 60000) {
- do_chttpd_log(ERROR,"Invalid port number try [1,60000], tried starting on ",configstruct.port,0);
- }
-
- bzero(&serv_addr, sizeof(serv_addr));
- 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) {
- do_chttpd_log(ERROR,"Failed to ","bind",0);
- }
-
- if( listen(listenfd,64) <0) {
- do_chttpd_log(ERROR,"Failed to","listen",0);
- }
-
- for(hit=1; ;hit++) {
- length = sizeof(cli_addr);
- if((socketfd = accept(listenfd, (struct sockaddr *)&cli_addr, (socklen_t*) &length)) < 0) {
- do_chttpd_log(ERROR,"Failed to","accept",0);
- }
-
- if((pid = fork()) < 0) {
- do_chttpd_log(ERROR,"Failed to","fork",0);
- } else {
- if(pid == 0) {
- close(listenfd);
- web(socketfd,hit,configstruct.htdocs,configstruct.cgi,configstruct.maxspeed);
- } else {
- close(socketfd);
- }
- }
- }
- }
|