Clone from Github, continuing devel here.
This commit is contained in:
commit
6bfc4ac1a2
26
Makefile
Normal file
26
Makefile
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# Makefile - (C) Chris Dorman, 2013 <cddo@riseup.net>
|
||||||
|
|
||||||
|
PREFIX = /usr/local
|
||||||
|
CC = gcc
|
||||||
|
|
||||||
|
CFLAGS = -O2 -Wall -Wextra
|
||||||
|
LDFLAGS =
|
||||||
|
|
||||||
|
BIN = chttpd
|
||||||
|
CONFIGFILE = inc/chttpd.conf
|
||||||
|
OBJECTS = src/chttpd.o src/functions.o src/cgi.o src/check.o src/log.o
|
||||||
|
|
||||||
|
all: main
|
||||||
|
|
||||||
|
fresh: clean all
|
||||||
|
|
||||||
|
main: $(OBJECTS)
|
||||||
|
$(CC) $(OBJECTS) -o $(BIN) $(LDFLAGS) $(CFLAGS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJECTS) $(BIN)
|
||||||
|
|
||||||
|
install:
|
||||||
|
cp $(BIN) $(PREFIX)/bin/$(BIN)
|
||||||
|
cp $(CONFIGFILE) /etc/chttpd.conf
|
||||||
|
cp inc/$(BIN) /etc/init.d/$(BIN)
|
49
doc/README.txt
Normal file
49
doc/README.txt
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
chttpd
|
||||||
|
======
|
||||||
|
|
||||||
|
chttpd is a simple web server that I'm currently working on. This is the
|
||||||
|
initial release of this web server, and its in working condition
|
||||||
|
|
||||||
|
Website: http://pentium44.github.io/projects/chttpd.html
|
||||||
|
License: GPLv2
|
||||||
|
|
||||||
|
Compiling chttpd:
|
||||||
|
~navigate to the chttpd directory
|
||||||
|
~run: make
|
||||||
|
~start the httpd
|
||||||
|
|
||||||
|
Changelog:
|
||||||
|
v1.3.1:
|
||||||
|
Fixed a major URI path bug.
|
||||||
|
|
||||||
|
v1.3.0:
|
||||||
|
Added CGI support.
|
||||||
|
CGI can be enabled / disabled within config
|
||||||
|
|
||||||
|
v1.2.6:
|
||||||
|
Added configuration parser
|
||||||
|
|
||||||
|
v1.2.5:
|
||||||
|
Added Content-Length to header
|
||||||
|
Added new mimetypes
|
||||||
|
Fixed old archive mimetypes
|
||||||
|
|
||||||
|
v1.2.4:
|
||||||
|
Fixed another bug in the directory listings, now working smooth
|
||||||
|
cleaned the code, added comments
|
||||||
|
|
||||||
|
v1.2.3:
|
||||||
|
Fixed directory listings bug
|
||||||
|
Added sys lable to error, and directory pages
|
||||||
|
Cleaned up logging system
|
||||||
|
|
||||||
|
v1.2.2:
|
||||||
|
Added directory listings (Thanks Lisa!)
|
||||||
|
Added index.html support
|
||||||
|
|
||||||
|
v1.2:
|
||||||
|
Added some small features
|
||||||
|
Development at a standstill
|
||||||
|
|
||||||
|
v1.1:
|
||||||
|
Initial release, works fine
|
13
inc/chttpd
Executable file
13
inc/chttpd
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Start / Stop chttpd (For unix)
|
||||||
|
|
||||||
|
CONFIG="/etc/chttpd.conf"
|
||||||
|
START_MSG="Starting CHTTPD"
|
||||||
|
STOP_MSG="Stopping CHTTPD Processes"
|
||||||
|
ERROR_MSG="Error, Usage: {start|stop}"
|
||||||
|
|
||||||
|
case $1 in
|
||||||
|
start) echo $START_MSG; chttpd ${CONFIG};;
|
||||||
|
stop) echo $STOP_MSG; killall chttpd;;
|
||||||
|
*) echo $ERROR_MSG;;
|
||||||
|
esac
|
15
inc/chttpd.conf
Normal file
15
inc/chttpd.conf
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# chttpd config file -
|
||||||
|
# HTML Documents directory, where the website or
|
||||||
|
# web server files are located.
|
||||||
|
# Make sure the path does NOT end with a forward slash
|
||||||
|
HTDOCS=/var/www
|
||||||
|
|
||||||
|
# The port the web server will listen on
|
||||||
|
PORT=80
|
||||||
|
|
||||||
|
# Enable cgi (yes / no)
|
||||||
|
ENABLE_CGI=yes
|
||||||
|
|
||||||
|
# Set throttling speed (0 for none) has to be
|
||||||
|
# more than 4096 and is read in units of bytes
|
||||||
|
MAX_SEND_SPEED=12128
|
40
src/cgi.c
Normal file
40
src/cgi.c
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// CTHTTPD - Simple Web Server - GPLv2
|
||||||
|
// Chris Dorman, 2012-2014 (cddo@riseup.net)
|
||||||
|
// Help from Nickolai Vurgaft (slipperygate@gmail.com)
|
||||||
|
|
||||||
|
// CGI base by Lisa 'darkrose' Milne
|
||||||
|
|
||||||
|
#include "dep.h"
|
||||||
|
#include "cgi.h"
|
||||||
|
#include "chttpd.h"
|
||||||
|
#include "functions.h"
|
||||||
|
|
||||||
|
void do_cgi(char fpath[], int fd, char *cgiroot)
|
||||||
|
{
|
||||||
|
static char buffer[BUFSIZE+1];
|
||||||
|
char *cgidir;
|
||||||
|
char *cgi_p;
|
||||||
|
|
||||||
|
cgi_p = malloc(strlen(cgiroot) + strlen(fpath) + 1);
|
||||||
|
strcpy(cgi_p, cgiroot);
|
||||||
|
strcat(cgi_p, fpath);
|
||||||
|
|
||||||
|
char *cgipath = dirname(fpath);
|
||||||
|
cgidir = malloc(strlen(cgiroot) + strlen(fpath) + 1);
|
||||||
|
strcpy(cgidir, cgiroot);
|
||||||
|
strcat(cgidir, cgipath);
|
||||||
|
|
||||||
|
// Write HTTP protocol to socket before executing cgi
|
||||||
|
sprintf(buffer,"HTTP/1.0 200 OK\r\n");
|
||||||
|
write(fd,buffer,strlen(buffer));
|
||||||
|
/*
|
||||||
|
start parsing the cgi code
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
fd = dup2(fd,STDOUT_FILENO);
|
||||||
|
chdir(cgidir);
|
||||||
|
|
||||||
|
execl("/bin/bash", cgi_p, NULL);
|
||||||
|
|
||||||
|
}
|
47
src/check.c
Normal file
47
src/check.c
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// CTHTTPD - Simple Web Server - GPLv2
|
||||||
|
// Chris Dorman, 2012-2014 (cddo@riseup.net)
|
||||||
|
// Help from Nickolai Vurgaft (slipperygate@gmail.com)
|
||||||
|
#include "check.h"
|
||||||
|
#include "dep.h"
|
||||||
|
|
||||||
|
// Check if a file exists (index.html)
|
||||||
|
int file_exists(char *fname) {
|
||||||
|
struct stat buffer;
|
||||||
|
if (stat (fname, &buffer) == 0)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the path is a directory (darklight)
|
||||||
|
int is_dir(char* p) {
|
||||||
|
char * stripslash;
|
||||||
|
struct stat st;
|
||||||
|
stripslash = p + 1; // strip the first forward 'slash' from the string
|
||||||
|
if (stat(stripslash, &st) == 0 && (st.st_mode & S_IFDIR)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (stat(stripslash, &st) == 0 && (st.st_mode & S_IFREG)) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ms_sleep(unsigned int ms)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct timespec elapsed;
|
||||||
|
struct timespec tv;
|
||||||
|
int was_error;
|
||||||
|
|
||||||
|
/* Set the timeout interval */
|
||||||
|
elapsed.tv_sec = ms/1000;
|
||||||
|
elapsed.tv_nsec = (ms%1000)*1000000;
|
||||||
|
|
||||||
|
do {
|
||||||
|
errno = 0;
|
||||||
|
tv.tv_sec = elapsed.tv_sec;
|
||||||
|
tv.tv_nsec = elapsed.tv_nsec;
|
||||||
|
was_error = nanosleep(&tv, &elapsed);
|
||||||
|
} while (was_error && (errno == EINTR));
|
||||||
|
}
|
7
src/check.h
Normal file
7
src/check.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// CTHTTPD - Simple Web Server - GPLv2
|
||||||
|
// Chris Dorman, 2012-2014 (cddo@riseup.net)
|
||||||
|
// Help from Nickolai Vurgaft (slipperygate@gmail.com)
|
||||||
|
|
||||||
|
int file_exists(char *fname);
|
||||||
|
int is_dir(char* p);
|
||||||
|
void ms_sleep(unsigned int ms);
|
443
src/chttpd.c
Normal file
443
src/chttpd.c
Normal file
@ -0,0 +1,443 @@
|
|||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
src/chttpd.h
Normal file
11
src/chttpd.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// CTHTTPD - Simple Web Server - GPLv2
|
||||||
|
// Chris Dorman, 2012-2014 (cddo@riseup.net)
|
||||||
|
// Help from Nickolai Vurgaft (slipperygate@gmail.com)
|
||||||
|
|
||||||
|
// definitions
|
||||||
|
#define BUFSIZE 4096
|
||||||
|
#define LIST_BUFSIZE 3068
|
||||||
|
#define ERROR 42
|
||||||
|
#define SORRY 43
|
||||||
|
#define LOG 44
|
||||||
|
#define SEND_ERROR 45
|
19
src/dep.h
Normal file
19
src/dep.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// CTHTTPD - Simple Web Server - GPLv2
|
||||||
|
// Chris Dorman, 2012-2014 (cddo@riseup.net)
|
||||||
|
// Help from Nickolai Vurgaft (slipperygate@gmail.com)
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <dirent.h> // For directory listings
|
||||||
|
|
||||||
|
#include <libgen.h> // for dirname
|
41
src/functions.c
Normal file
41
src/functions.c
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// CTHTTPD - Simple Web Server - GPLv2
|
||||||
|
// Chris Dorman, 2012-2014 (cddo@riseup.net)
|
||||||
|
// Help from Nickolai Vurgaft (slipperygate@gmail.com)
|
||||||
|
#include "dep.h"
|
||||||
|
#include "functions.h"
|
||||||
|
|
||||||
|
// Addition by OldCoder for replacing HEX values in GET paths.
|
||||||
|
// BEGINNING OF OLDCODER :P
|
||||||
|
int hexchartonum (char c)
|
||||||
|
{
|
||||||
|
if ((c >= '0') && (c <= '9')) return c - '0';
|
||||||
|
if ((c >= 'a') && (c <= 'f')) return c - 'a' + 10;
|
||||||
|
if ((c >= 'A') && (c <= 'F')) return c - 'A' + 10;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *fixpath (char *input)
|
||||||
|
{
|
||||||
|
static char xbuf [1024];
|
||||||
|
int ch;
|
||||||
|
int ii;
|
||||||
|
char *cp;
|
||||||
|
strcpy (xbuf, input);
|
||||||
|
|
||||||
|
while ((cp = strchr (xbuf, '%')) != NULL)
|
||||||
|
{
|
||||||
|
int h1 = hexchartonum (cp [1]);
|
||||||
|
if (h1 < 0) return "";
|
||||||
|
int h2 = hexchartonum (cp [2]);
|
||||||
|
if (h2 < 0) return "";
|
||||||
|
int hh = (h1 * 16) + h2;
|
||||||
|
|
||||||
|
*cp = hh;
|
||||||
|
for (ii = 0 ;; ii++)
|
||||||
|
{ cp [ii+1] = ch = cp [ii+3]; if (ch == '\0') break; }
|
||||||
|
}
|
||||||
|
|
||||||
|
return xbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
// END OF OLDCODER :P
|
6
src/functions.h
Normal file
6
src/functions.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// CTHTTPD - Simple Web Server - GPLv2
|
||||||
|
// Chris Dorman, 2012-2014 (cddo@riseup.net)
|
||||||
|
// Help from Nickolai Vurgaft (slipperygate@gmail.com)
|
||||||
|
|
||||||
|
int hexchartonum (char c);
|
||||||
|
char *fixpath (char *input);
|
42
src/log.c
Normal file
42
src/log.c
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// CTHTTPD - Simple Web Server - GPLv2
|
||||||
|
// Chris Dorman, 2012-2014 (cddo@riseup.net)
|
||||||
|
// Help from Nickolai Vurgaft (slipperygate@gmail.com)
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "dep.h"
|
||||||
|
#include "chttpd.h"
|
||||||
|
|
||||||
|
void do_chttpd_log(int type, char *s1, char *s2, int num)
|
||||||
|
{
|
||||||
|
// logs the local time of the event
|
||||||
|
time_t now = time(NULL);
|
||||||
|
struct tm* tm_info;
|
||||||
|
char timebuf[30];
|
||||||
|
memset(timebuf, 0, strlen(timebuf));
|
||||||
|
tm_info = localtime(&now);
|
||||||
|
strftime(timebuf, sizeof(timebuf), "%Y/%m/%d, %H:%M:%S", tm_info);
|
||||||
|
|
||||||
|
int fd ;
|
||||||
|
char logbuffer[BUFSIZE*2];
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case ERROR: sprintf(logbuffer,"chttpd - %s : Error: %s %s", timebuf, s1, s2); break;
|
||||||
|
case SORRY: sprintf(logbuffer, "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n<html><head><title>CHTTPD: Error</title>\n</head><body><h2>CHTTPD Error:</h2> %s %s <hr /><address>chttpd</address></body></html>\r\n", s1, s2);
|
||||||
|
write(num,logbuffer,strlen(logbuffer));
|
||||||
|
break;
|
||||||
|
case LOG: sprintf(logbuffer,"chttpd - %s : Info: %s:%s:5d", timebuf, s1, s2); break;
|
||||||
|
case SEND_ERROR: sprintf(logbuffer,"HTTP/1.0 500 Internal Server Error\r\nContent-Type: text/html\r\n\r\n<html><head><title>CHTTPD: Found error</title></head><body><h2>Index error</h2>%s<hr /><address>chttpd</address></body></html>\r\n", s1);
|
||||||
|
write(num,logbuffer,strlen(logbuffer));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(type == ERROR || type == LOG) { // Log important data
|
||||||
|
if((fd = open("server.log", O_CREAT| O_WRONLY | O_APPEND,0644)) >= 0) {
|
||||||
|
write(fd,logbuffer,strlen(logbuffer));
|
||||||
|
write(fd,"\n",1);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(type == ERROR || type == SORRY || type == SEND_ERROR) exit(3);
|
||||||
|
}
|
5
src/log.h
Normal file
5
src/log.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
// CTHTTPD - Simple Web Server - GPLv2
|
||||||
|
// Chris Dorman, 2012-2014 (cddo@riseup.net)
|
||||||
|
// Help from Nickolai Vurgaft (slipperygate@gmail.com)
|
||||||
|
|
||||||
|
void do_chttpd_log(int type, char *s1, char *s2, int num);
|
52
src/mimetypes.h
Normal file
52
src/mimetypes.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
struct {
|
||||||
|
char *ext;
|
||||||
|
char *filetype;
|
||||||
|
} extensions [] = {
|
||||||
|
{"gif", "image/gif" },
|
||||||
|
{"jpg", "image/jpeg"},
|
||||||
|
{"jpeg", "image/jpeg"},
|
||||||
|
{"png", "image/png" },
|
||||||
|
{"zip", "application/zip" },
|
||||||
|
{"gz", "application/gzip" },
|
||||||
|
{"tar", "application/tar" },
|
||||||
|
{"htm", "text/html" },
|
||||||
|
{"html", "text/html" },
|
||||||
|
{"php", "text/php" },
|
||||||
|
{"asp", "text/asp" },
|
||||||
|
{"jsp", "image/jsp" },
|
||||||
|
{"xml", "text/xml" },
|
||||||
|
{"js", "text/js" },
|
||||||
|
{"css", "text/css" },
|
||||||
|
{"c", "text/plain" },
|
||||||
|
{"h", "text/plain" },
|
||||||
|
{"txt", "text/plain"},
|
||||||
|
{"sh", "text/plain" },
|
||||||
|
{"ttf", "font/ttf" },
|
||||||
|
{"ogg", "audio/ogg" },
|
||||||
|
{"mp3", "audio/mpeg"},
|
||||||
|
{"woff", "application/font-woff"},
|
||||||
|
{"flv", "video/x-flv" },
|
||||||
|
{"mp4", "video/mp4" },
|
||||||
|
{"webm", "video/webm" },
|
||||||
|
{"swf", "application/x-shockwave-flash" },
|
||||||
|
{"iso", "application/octet-stream" },
|
||||||
|
{"exe", "application/octet-stream" },
|
||||||
|
{"cso", "application/octet-stream" },
|
||||||
|
{"xz", "application/x-xz" },
|
||||||
|
{"bz2", "application/bzip2" },
|
||||||
|
{"docx", "application/msword" },
|
||||||
|
{"avi", "video/avi" },
|
||||||
|
{"xhtml", "text/xhtml" },
|
||||||
|
{"pl", "text/plain" },
|
||||||
|
{"rar", "application/x-rar" },
|
||||||
|
{"7z", "application/x-7z" },
|
||||||
|
{"cpp", "text/plain" },
|
||||||
|
{"hpp", "text/plain" },
|
||||||
|
{"ogv", "video/ogg" },
|
||||||
|
{"patch", "text/plain" },
|
||||||
|
{"svg", "image/svg" },
|
||||||
|
{"ico", "image/x-icon" },
|
||||||
|
{"log", "serverlog"},
|
||||||
|
{"cgi", "servercgi"},
|
||||||
|
{0, 0}
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user