mirror of
https://github.com/esp8266/Arduino.git
synced 2025-08-05 13:16:13 +03:00
lots of changes for axhttpd
git-svn-id: svn://svn.code.sf.net/p/axtls/code/trunk@53 9a5d90b5-6617-0410-8a86-bb477d3ed2e3
This commit is contained in:
@@ -57,7 +57,6 @@ OBJ= \
|
||||
conn.o \
|
||||
main.o \
|
||||
proc.o \
|
||||
misc.o \
|
||||
mime_types.o
|
||||
|
||||
ifndef CONFIG_PLATFORM_WIN32
|
||||
@@ -71,6 +70,10 @@ endif
|
||||
endif
|
||||
else # Win32
|
||||
|
||||
OBJ:=$(OBJ:.o=.obj)
|
||||
%.obj : %.c
|
||||
$(CC) $(CFLAGS) $<
|
||||
|
||||
$(TARGET): $(OBJ)
|
||||
$(LD) $(LDFLAGS) $(LIBS) /out:$@ $(OBJ)
|
||||
endif
|
||||
|
@@ -1,6 +1,6 @@
|
||||
|
||||
axhttpd is a small embedded web server using the axTLS library.
|
||||
axhttpd is a small embedded web server using the axTLS library.
|
||||
|
||||
It is based quite closely on the web server written by Doug Currie (original
|
||||
version is here: http://www.hcsw.org/awhttpd).
|
||||
It is based originally on the web server written by Doug Currie and is at:
|
||||
http://www.hcsw.org/awhttpd).
|
||||
|
||||
|
@@ -74,9 +74,9 @@ struct connstruct
|
||||
int numbytes;
|
||||
char databuf[BLOCKSIZE];
|
||||
|
||||
unsigned char is_ssl;
|
||||
unsigned char close_when_done;
|
||||
unsigned char modified_since;
|
||||
uint8_t is_ssl;
|
||||
uint8_t close_when_done;
|
||||
uint8_t modified_since;
|
||||
};
|
||||
|
||||
struct serverstruct
|
||||
@@ -95,12 +95,6 @@ struct cgiextstruct
|
||||
};
|
||||
#endif
|
||||
|
||||
struct indexstruct
|
||||
{
|
||||
struct indexstruct *next;
|
||||
char *name;
|
||||
};
|
||||
|
||||
// Global prototypes
|
||||
extern struct serverstruct *servers;
|
||||
extern struct connstruct *usedconns;
|
||||
@@ -108,49 +102,25 @@ extern struct connstruct *freeconns;
|
||||
#if defined(CONFIG_HTTP_HAS_CGI)
|
||||
extern struct cgiextstruct *cgiexts;
|
||||
#endif
|
||||
extern struct indexstruct *indexlist;
|
||||
|
||||
// Conf global prototypes
|
||||
extern char *webroot;
|
||||
extern int allowdirectorylisting;
|
||||
extern int allowcgi;
|
||||
extern int permcheck;
|
||||
|
||||
// conn.c prototypes
|
||||
void addconnection(int sd, char *ip, int is_ssl);
|
||||
void removeconnection(struct connstruct *cn);
|
||||
|
||||
// proc.c prototypes
|
||||
int procheadelem(struct connstruct *cn, char *buf);
|
||||
void procdirlisting(struct connstruct *cn);
|
||||
void procdodir(struct connstruct *cn);
|
||||
void procreadhead(struct connstruct *cn);
|
||||
void procsendhead(struct connstruct *cn);
|
||||
void procreadfile(struct connstruct *cn);
|
||||
void procsendfile(struct connstruct *cn);
|
||||
int special_write(struct connstruct *cn, const uint8_t *buf, size_t count);
|
||||
|
||||
// misc.c prototypes
|
||||
void nada(int sigtype);
|
||||
void die(int sigtype);
|
||||
void reaper(int sigtype);
|
||||
void stripcrlf(char *p);
|
||||
char *my_strncpy(char *dest, const char *src, size_t n);
|
||||
#ifndef __HAVE_ARCH_STRNLEN
|
||||
size_t strnlen ( const char * str, size_t maxlen );
|
||||
#endif
|
||||
int iscgi(char *fn);
|
||||
void split(char *tp, char *sp[], int maxwords, char sc);
|
||||
int sanitizefile(char *buf);
|
||||
int sanitizehost(char *buf);
|
||||
void buildactualfile(struct connstruct *cn);
|
||||
int issockwriteable(int sd);
|
||||
int isdir(char *name);
|
||||
int trycgi_withpathinfo(struct connstruct *cn);
|
||||
int isdir(const char *name);
|
||||
|
||||
// mime_types.c prototypes
|
||||
void mime_init(void);
|
||||
const char *getmimetype(const char *fn);
|
||||
|
||||
// main.c prototypes
|
||||
void initlists(void);
|
||||
|
26
httpd/conn.c
26
httpd/conn.c
@@ -27,9 +27,7 @@ void addconnection(int sd, char *ip, int is_ssl)
|
||||
|
||||
// Get ourselves a connstruct
|
||||
if (freeconns == NULL)
|
||||
{
|
||||
tp = (struct connstruct *) malloc(sizeof(struct connstruct));
|
||||
}
|
||||
tp = (struct connstruct *)malloc(sizeof(struct connstruct));
|
||||
else
|
||||
{
|
||||
tp = freeconns;
|
||||
@@ -39,23 +37,21 @@ void addconnection(int sd, char *ip, int is_ssl)
|
||||
// Attach it to the used list
|
||||
tp->next = usedconns;
|
||||
usedconns = tp;
|
||||
|
||||
tp->networkdesc = sd;
|
||||
|
||||
if (is_ssl)
|
||||
ssl_server_new(servers->ssl_ctx, sd);
|
||||
tp->is_ssl = is_ssl;
|
||||
tp->filedesc = -1;
|
||||
#if defined(CONFIG_HTTP_HAS_DIRECTORIES)
|
||||
tp->dirp = NULL;
|
||||
#endif
|
||||
tp->is_ssl = is_ssl;
|
||||
|
||||
*(tp->actualfile) = '\0';
|
||||
*(tp->filereq) = '\0';
|
||||
#if defined(CONFIG_HTTP_HAS_CGI)
|
||||
*(tp->cgiargs) = '\0';
|
||||
#endif
|
||||
*(tp->virtualhostreq) = '\0';
|
||||
|
||||
tp->state = STATE_WANT_TO_READ_HEAD;
|
||||
tp->reqtype = TYPE_GET;
|
||||
my_strncpy(tp->ip, ip, MAXIPLEN);
|
||||
@@ -67,27 +63,27 @@ void addconnection(int sd, char *ip, int is_ssl)
|
||||
void removeconnection(struct connstruct *cn)
|
||||
{
|
||||
struct connstruct *tp;
|
||||
int shouldret=0;
|
||||
int shouldret = 0;
|
||||
|
||||
tp = usedconns;
|
||||
|
||||
if (tp == NULL || cn == NULL)
|
||||
shouldret=1;
|
||||
shouldret = 1;
|
||||
else if (tp == cn)
|
||||
usedconns = tp->next;
|
||||
else
|
||||
{
|
||||
while(tp != NULL)
|
||||
while (tp != NULL)
|
||||
{
|
||||
if (tp->next == cn)
|
||||
{
|
||||
tp->next = (tp->next)->next;
|
||||
shouldret=0;
|
||||
shouldret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
tp = tp->next;
|
||||
shouldret=1;
|
||||
shouldret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,14 +98,14 @@ void removeconnection(struct connstruct *cn)
|
||||
if (cn->networkdesc != -1)
|
||||
{
|
||||
if (cn->is_ssl)
|
||||
{
|
||||
ssl_free(ssl_find(servers->ssl_ctx, cn->networkdesc));
|
||||
}
|
||||
|
||||
SOCKET_CLOSE(cn->networkdesc);
|
||||
}
|
||||
|
||||
if (cn->filedesc != -1) close(cn->filedesc);
|
||||
if (cn->filedesc != -1)
|
||||
close(cn->filedesc);
|
||||
|
||||
#if defined(CONFIG_HTTP_HAS_DIRECTORIES)
|
||||
if (cn->dirp != NULL)
|
||||
#ifdef WIN32
|
||||
|
523
httpd/main.c
523
httpd/main.c
@@ -27,23 +27,25 @@
|
||||
struct serverstruct *servers;
|
||||
struct connstruct *usedconns;
|
||||
struct connstruct *freeconns;
|
||||
#if defined(CONFIG_HTTP_HAS_CGI)
|
||||
struct cgiextstruct *cgiexts;
|
||||
#endif
|
||||
struct indexstruct *indexlist;
|
||||
|
||||
char *webroot = CONFIG_HTTP_WEBROOT;
|
||||
|
||||
static void addindex(char *tp);
|
||||
static void addtoservers(int sd);
|
||||
static void selectloop(void);
|
||||
static int openlistener(int port);
|
||||
static void handlenewconnection(int listenfd, int is_ssl);
|
||||
#if defined(CONFIG_HTTP_PERM_CHECK)
|
||||
static void procpermcheck(char *pathtocheck);
|
||||
static void procpermcheck(const char *pathtocheck);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_HTTP_HAS_CGI)
|
||||
struct cgiextstruct *cgiexts;
|
||||
static void addcgiext(char *tp);
|
||||
|
||||
#if !defined(WIN32)
|
||||
static void reaper(int sigtype)
|
||||
{
|
||||
wait3(NULL, WNOHANG, NULL);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* clean up memory for valgrind */
|
||||
@@ -53,7 +55,7 @@ static void sigint_cleanup(int sig)
|
||||
struct connstruct *tp;
|
||||
int i;
|
||||
|
||||
while(servers != NULL)
|
||||
while (servers != NULL)
|
||||
{
|
||||
if (servers->is_ssl)
|
||||
ssl_ctx_free(servers->ssl_ctx);
|
||||
@@ -63,9 +65,6 @@ static void sigint_cleanup(int sig)
|
||||
servers = sp;
|
||||
}
|
||||
|
||||
free(indexlist->name);
|
||||
free(indexlist);
|
||||
|
||||
for (i = 0; i < INITIAL_CONNECTION_SLOTS; i++)
|
||||
{
|
||||
if (freeconns == NULL)
|
||||
@@ -79,46 +78,52 @@ static void sigint_cleanup(int sig)
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void initlists()
|
||||
static void die(int sigtype)
|
||||
{
|
||||
int i;
|
||||
struct connstruct *tp;
|
||||
|
||||
servers = NULL;
|
||||
usedconns = NULL;
|
||||
freeconns = NULL;
|
||||
#if defined(CONFIG_HTTP_HAS_CGI)
|
||||
cgiexts = NULL;
|
||||
#endif
|
||||
indexlist = NULL;
|
||||
|
||||
for (i=0; i<INITIAL_CONNECTION_SLOTS; i++)
|
||||
{
|
||||
tp = freeconns;
|
||||
freeconns = (struct connstruct *) calloc(1, sizeof(struct connstruct));
|
||||
freeconns->next = tp;
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int tp;
|
||||
#if defined(CONFIG_HTTP_IS_DAEMON)
|
||||
int pid;
|
||||
#endif
|
||||
fd_set rfds, wfds;
|
||||
struct connstruct *tp, *to;
|
||||
struct serverstruct *sp;
|
||||
int rnum, wnum, active;
|
||||
int webrootlen, i;
|
||||
time_t currtime;
|
||||
|
||||
#ifdef WIN32
|
||||
WORD wVersionRequested = MAKEWORD(2,2);
|
||||
WORD wVersionRequested = MAKEWORD(2, 2);
|
||||
WSADATA wsaData;
|
||||
WSAStartup(wVersionRequested,&wsaData);
|
||||
#else
|
||||
if (getuid() == 0) // change our uid if we are root
|
||||
{
|
||||
setgid(32767);
|
||||
setuid(32767);
|
||||
}
|
||||
|
||||
signal(SIGQUIT, die);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#if defined(CONFIG_HTTP_HAS_CGI)
|
||||
signal(SIGCHLD, reaper);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
signal(SIGINT, sigint_cleanup);
|
||||
signal(SIGTERM, die);
|
||||
mime_init();
|
||||
initlists();
|
||||
tp = strlen(webroot);
|
||||
|
||||
if (webroot[tp-1] == '/')
|
||||
webroot[tp-1] = '\0';
|
||||
for (i = 0; i < INITIAL_CONNECTION_SLOTS; i++)
|
||||
{
|
||||
tp = freeconns;
|
||||
freeconns = (struct connstruct *)calloc(1, sizeof(struct connstruct));
|
||||
freeconns->next = tp;
|
||||
}
|
||||
|
||||
webrootlen = strlen(webroot);
|
||||
|
||||
if (webroot[webrootlen-1] == '/')
|
||||
webroot[webrootlen-1] = '\0';
|
||||
|
||||
if (isdir(webroot) == 0)
|
||||
{
|
||||
@@ -128,38 +133,29 @@ int main(int argc, char *argv[])
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((tp = openlistener(CONFIG_HTTP_PORT)) == -1)
|
||||
if ((active = openlistener(CONFIG_HTTP_PORT)) == -1)
|
||||
{
|
||||
#ifdef CONFIG_HTTP_VERBOSE
|
||||
fprintf(stderr, "ERR: Couldn't bind to port %d (IPv4)\n",
|
||||
fprintf(stderr, "ERR: Couldn't bind to port %d\n",
|
||||
CONFIG_HTTP_PORT);
|
||||
#endif
|
||||
exit(1);
|
||||
}
|
||||
|
||||
addindex("index.html");
|
||||
addtoservers(tp);
|
||||
addtoservers(active);
|
||||
|
||||
#ifndef WIN32
|
||||
if (getuid() == 0)
|
||||
{
|
||||
setgid(32767);
|
||||
setuid(32767);
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((tp = openlistener(CONFIG_HTTP_HTTPS_PORT)) == -1)
|
||||
if ((active = openlistener(CONFIG_HTTP_HTTPS_PORT)) == -1)
|
||||
{
|
||||
#ifdef CONFIG_HTTP_VERBOSE
|
||||
fprintf(stderr, "ERR: Couldn't bind to port %d (IPv4)\n",
|
||||
fprintf(stderr, "ERR: Couldn't bind to port %d\n",
|
||||
CONFIG_HTTP_HTTPS_PORT);
|
||||
#endif
|
||||
exit(1);
|
||||
}
|
||||
|
||||
addtoservers(tp);
|
||||
addtoservers(active);
|
||||
servers->ssl_ctx = ssl_ctx_new(CONFIG_HTTP_DEFAULT_SSL_OPTIONS,
|
||||
CONFIG_HTTP_SESSION_CACHE_SIZE);
|
||||
CONFIG_HTTP_SESSION_CACHE_SIZE);
|
||||
servers->is_ssl = 1;
|
||||
|
||||
#if defined(CONFIG_HTTP_PERM_CHECK)
|
||||
@@ -173,53 +169,152 @@ int main(int argc, char *argv[])
|
||||
CONFIG_HTTP_PORT, CONFIG_HTTP_HTTPS_PORT);
|
||||
TTY_FLUSH();
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_HTTP_IS_DAEMON)
|
||||
pid = fork();
|
||||
|
||||
if (pid > 0)
|
||||
{
|
||||
if (fork() > 0) /* parent will die */
|
||||
exit(0);
|
||||
}
|
||||
else if(pid == -1)
|
||||
{
|
||||
#ifdef CONFIG_HTTP_VERBOSE
|
||||
fprintf(stderr,"axhttpd: Sorry, fork failed... Tough dice.\n");
|
||||
#endif
|
||||
exit(1);
|
||||
}
|
||||
|
||||
setsid();
|
||||
#endif
|
||||
|
||||
/* SIGNALS */
|
||||
signal(SIGINT, sigint_cleanup);
|
||||
signal(SIGTERM, die);
|
||||
#if defined(CONFIG_HTTP_HAS_CGI)
|
||||
#ifndef WIN32
|
||||
signal(SIGCHLD, reaper);
|
||||
#endif
|
||||
#endif
|
||||
#ifndef WIN32
|
||||
signal(SIGQUIT, die);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
// main loop
|
||||
while (1)
|
||||
{
|
||||
FD_ZERO(&rfds);
|
||||
FD_ZERO(&wfds);
|
||||
rnum = wnum = -1;
|
||||
sp = servers;
|
||||
|
||||
while (sp != NULL) // read each server port
|
||||
{
|
||||
FD_SET(sp->sd, &rfds);
|
||||
|
||||
if (sp->sd > rnum)
|
||||
rnum = sp->sd;
|
||||
sp = sp->next;
|
||||
}
|
||||
|
||||
// Add the established sockets
|
||||
tp = usedconns;
|
||||
currtime = time(NULL);
|
||||
|
||||
while (tp != NULL)
|
||||
{
|
||||
if (currtime > tp->timeout) // timed out? Kill it.
|
||||
{
|
||||
to = tp;
|
||||
tp = tp->next;
|
||||
removeconnection(to);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tp->state == STATE_WANT_TO_READ_HEAD)
|
||||
{
|
||||
FD_SET(tp->networkdesc, &rfds);
|
||||
if (tp->networkdesc > rnum)
|
||||
rnum = tp->networkdesc;
|
||||
}
|
||||
|
||||
if (tp->state == STATE_WANT_TO_SEND_HEAD)
|
||||
{
|
||||
FD_SET(tp->networkdesc, &wfds);
|
||||
if (tp->networkdesc > wnum)
|
||||
wnum = tp->networkdesc;
|
||||
}
|
||||
|
||||
if (tp->state == STATE_WANT_TO_READ_FILE)
|
||||
{
|
||||
FD_SET(tp->filedesc, &rfds);
|
||||
if (tp->filedesc > rnum)
|
||||
rnum = tp->filedesc;
|
||||
}
|
||||
|
||||
if (tp->state == STATE_WANT_TO_SEND_FILE)
|
||||
{
|
||||
FD_SET(tp->networkdesc, &wfds);
|
||||
if (tp->networkdesc > wnum)
|
||||
wnum = tp->networkdesc;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_HTTP_DIRECTORIES)
|
||||
if (tp->state == STATE_DOING_DIR)
|
||||
{
|
||||
FD_SET(tp->networkdesc, &wfds);
|
||||
if (tp->networkdesc > wnum)
|
||||
wnum = tp->networkdesc;
|
||||
}
|
||||
#endif
|
||||
tp = tp->next;
|
||||
}
|
||||
|
||||
active = select(wnum > rnum ? wnum+1 : rnum+1,
|
||||
rnum != -1 ? &rfds : NULL, wnum != -1 ? &wfds : NULL,
|
||||
NULL, NULL);
|
||||
|
||||
// New connection?
|
||||
sp = servers;
|
||||
while (active > 0 && sp != NULL)
|
||||
{
|
||||
if (FD_ISSET(sp->sd, &rfds))
|
||||
{
|
||||
handlenewconnection(sp->sd, sp->is_ssl);
|
||||
active--;
|
||||
}
|
||||
|
||||
sp = sp->next;
|
||||
}
|
||||
|
||||
// Handle the established sockets
|
||||
tp = usedconns;
|
||||
|
||||
while (active > 0 && tp != NULL)
|
||||
{
|
||||
to = tp;
|
||||
tp = tp->next;
|
||||
|
||||
if (to->state == STATE_WANT_TO_READ_HEAD)
|
||||
if (FD_ISSET(to->networkdesc, &rfds))
|
||||
{
|
||||
active--;
|
||||
procreadhead(to);
|
||||
}
|
||||
|
||||
if (to->state == STATE_WANT_TO_SEND_HEAD)
|
||||
if (FD_ISSET(to->networkdesc, &wfds))
|
||||
{
|
||||
active--;
|
||||
procsendhead(to);
|
||||
}
|
||||
|
||||
if (to->state == STATE_WANT_TO_READ_FILE)
|
||||
if (FD_ISSET(to->filedesc, &rfds))
|
||||
{
|
||||
active--;
|
||||
procreadfile(to);
|
||||
}
|
||||
|
||||
if (to->state == STATE_WANT_TO_SEND_FILE)
|
||||
if (FD_ISSET(to->networkdesc, &wfds))
|
||||
{
|
||||
active--;
|
||||
procsendfile(to);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_HTTP_DIRECTORIES)
|
||||
if (to->state == STATE_DOING_DIR)
|
||||
if (FD_ISSET(to->networkdesc, &wfds))
|
||||
{
|
||||
active--;
|
||||
procdodir(to);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
selectloop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void addindex(char *tp)
|
||||
{
|
||||
struct indexstruct *ex = (struct indexstruct *)
|
||||
malloc(sizeof(struct indexstruct));
|
||||
ex->name = strdup(tp);
|
||||
ex->next = indexlist;
|
||||
indexlist = ex;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_HTTP_PERM_CHECK)
|
||||
static void procpermcheck(char *pathtocheck)
|
||||
static void procpermcheck(const char *pathtocheck)
|
||||
{
|
||||
char thepath[MAXREQUESTLENGTH];
|
||||
#ifndef WIN32
|
||||
@@ -232,31 +327,35 @@ static void procpermcheck(char *pathtocheck)
|
||||
{
|
||||
printf("WARNING: UID (%d) is unable to read %s\n",
|
||||
(int)getuid(), pathtocheck);
|
||||
TTY_FLUSH();
|
||||
return;
|
||||
}
|
||||
|
||||
while ((dp=readdir(tpdir)))
|
||||
while ((dp = readdir(tpdir)))
|
||||
{
|
||||
if (strcmp(dp->d_name, "..")==0)
|
||||
if (strcmp(dp->d_name, "..") == 0)
|
||||
continue;
|
||||
|
||||
if (strcmp(dp->d_name, ".")==0)
|
||||
if (strcmp(dp->d_name, ".") == 0)
|
||||
continue;
|
||||
|
||||
snprintf(thepath, sizeof(thepath), "%s/%s", pathtocheck, dp->d_name);
|
||||
|
||||
if (isdir(thepath))
|
||||
if (isdir(thepath))
|
||||
{
|
||||
procpermcheck(thepath);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (access(thepath, R_OK) != 0)
|
||||
printf("WARNING: UID (%d) is unable to read %s\n",
|
||||
printf("WARNING: UID (%d) is unable to read %s\n",
|
||||
(int)getuid(), thepath);
|
||||
|
||||
if (access(thepath, W_OK) == 0)
|
||||
printf("SECURITY: UID (%d) is ABLE TO WRITE TO %s\n",
|
||||
printf("SECURITY: UID (%d) is ABLE TO WRITE TO %s\n",
|
||||
(int)getuid(), thepath);
|
||||
|
||||
TTY_FLUSH();
|
||||
}
|
||||
|
||||
closedir(tpdir);
|
||||
@@ -335,149 +434,6 @@ static void addtoservers(int sd)
|
||||
servers = tp;
|
||||
}
|
||||
|
||||
static void selectloop(void)
|
||||
{
|
||||
fd_set rfds, wfds;
|
||||
struct connstruct *tp, *to;
|
||||
struct serverstruct *sp;
|
||||
int rnum, wnum, active;
|
||||
int currtime;
|
||||
|
||||
while (1)
|
||||
{
|
||||
// MAIN SELECT LOOP
|
||||
FD_ZERO(&rfds);
|
||||
FD_ZERO(&wfds);
|
||||
rnum = wnum = -1;
|
||||
|
||||
// Add the listening sockets
|
||||
sp = servers;
|
||||
while (sp != NULL)
|
||||
{
|
||||
FD_SET(sp->sd, &rfds);
|
||||
if (sp->sd > rnum) rnum = sp->sd;
|
||||
sp = sp->next;
|
||||
}
|
||||
|
||||
// Add the established sockets
|
||||
tp = usedconns;
|
||||
currtime = time(NULL);
|
||||
|
||||
while (tp != NULL)
|
||||
{
|
||||
if (currtime > tp->timeout)
|
||||
{
|
||||
to = tp;
|
||||
tp = tp->next;
|
||||
removeconnection(to);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tp->state == STATE_WANT_TO_READ_HEAD)
|
||||
{
|
||||
FD_SET(tp->networkdesc, &rfds);
|
||||
if (tp->networkdesc > rnum)
|
||||
rnum = tp->networkdesc;
|
||||
}
|
||||
|
||||
if (tp->state == STATE_WANT_TO_SEND_HEAD)
|
||||
{
|
||||
FD_SET(tp->networkdesc, &wfds);
|
||||
if (tp->networkdesc > wnum)
|
||||
wnum = tp->networkdesc;
|
||||
}
|
||||
|
||||
if (tp->state == STATE_WANT_TO_READ_FILE)
|
||||
{
|
||||
FD_SET(tp->filedesc, &rfds);
|
||||
if (tp->filedesc > rnum)
|
||||
rnum = tp->filedesc;
|
||||
}
|
||||
|
||||
if (tp->state == STATE_WANT_TO_SEND_FILE)
|
||||
{
|
||||
FD_SET(tp->networkdesc, &wfds);
|
||||
if (tp->networkdesc > wnum)
|
||||
wnum = tp->networkdesc;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_HTTP_DIRECTORIES)
|
||||
if (tp->state == STATE_DOING_DIR)
|
||||
{
|
||||
FD_SET(tp->networkdesc, &wfds);
|
||||
if (tp->networkdesc > wnum)
|
||||
wnum = tp->networkdesc;
|
||||
}
|
||||
#endif
|
||||
tp = tp->next;
|
||||
}
|
||||
|
||||
active = select(wnum > rnum ? wnum+1 : rnum+1,
|
||||
rnum != -1 ? &rfds : NULL,
|
||||
wnum != -1 ? &wfds : NULL,
|
||||
NULL, NULL);
|
||||
|
||||
// Handle the listening sockets
|
||||
sp = servers;
|
||||
while (active > 0 && sp != NULL)
|
||||
{
|
||||
if (FD_ISSET(sp->sd, &rfds))
|
||||
{
|
||||
handlenewconnection(sp->sd, sp->is_ssl);
|
||||
active--;
|
||||
}
|
||||
|
||||
sp = sp->next;
|
||||
}
|
||||
|
||||
// Handle the established sockets
|
||||
tp = usedconns;
|
||||
|
||||
while (active > 0 && tp != NULL)
|
||||
{
|
||||
to = tp;
|
||||
tp = tp->next;
|
||||
|
||||
if (to->state == STATE_WANT_TO_READ_HEAD)
|
||||
if (FD_ISSET(to->networkdesc, &rfds))
|
||||
{
|
||||
active--;
|
||||
procreadhead(to);
|
||||
}
|
||||
|
||||
if (to->state == STATE_WANT_TO_SEND_HEAD)
|
||||
if (FD_ISSET(to->networkdesc, &wfds))
|
||||
{
|
||||
active--;
|
||||
procsendhead(to);
|
||||
}
|
||||
|
||||
if (to->state == STATE_WANT_TO_READ_FILE)
|
||||
if (FD_ISSET(to->filedesc, &rfds))
|
||||
{
|
||||
active--;
|
||||
procreadfile(to);
|
||||
}
|
||||
|
||||
if (to->state == STATE_WANT_TO_SEND_FILE)
|
||||
if (FD_ISSET(to->networkdesc, &wfds))
|
||||
{
|
||||
active--;
|
||||
procsendfile(to);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_HTTP_DIRECTORIES)
|
||||
if (to->state == STATE_DOING_DIR)
|
||||
if (FD_ISSET(to->networkdesc, &wfds))
|
||||
{
|
||||
active--;
|
||||
procdodir(to);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} // MAIN SELECT LOOP
|
||||
}
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
static void handlenewconnection(int listenfd, int is_ssl)
|
||||
{
|
||||
@@ -486,9 +442,6 @@ static void handlenewconnection(int listenfd, int is_ssl)
|
||||
char ipbuf[100];
|
||||
int connfd = accept(listenfd, (struct sockaddr *)&their_addr, &tp);
|
||||
|
||||
if (connfd == -1)
|
||||
return;
|
||||
|
||||
if (tp == sizeof(struct sockaddr_in6))
|
||||
{
|
||||
inet_ntop(AF_INET6, &their_addr.sin6_addr, ipbuf, sizeof(ipbuf));
|
||||
@@ -512,10 +465,6 @@ static void handlenewconnection(int listenfd, int is_ssl)
|
||||
struct sockaddr_in their_addr;
|
||||
int tp = sizeof(struct sockaddr_in);
|
||||
int connfd = accept(listenfd, (struct sockaddr *)&their_addr, &tp);
|
||||
|
||||
if (connfd == -1)
|
||||
return;
|
||||
|
||||
addconnection(connfd, inet_ntoa(their_addr.sin_addr), is_ssl);
|
||||
}
|
||||
#endif
|
||||
@@ -524,62 +473,60 @@ static int openlistener(int port)
|
||||
{
|
||||
int sd;
|
||||
#ifdef WIN32
|
||||
char tp=1;
|
||||
char tp = 1;
|
||||
#else
|
||||
int tp=1;
|
||||
int tp = 1;
|
||||
#endif
|
||||
#ifndef HAVE_IPV6
|
||||
struct sockaddr_in my_addr;
|
||||
|
||||
if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
|
||||
return -1;
|
||||
|
||||
setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &tp, sizeof(tp));
|
||||
my_addr.sin_family = AF_INET; // host byte order
|
||||
my_addr.sin_port = htons((short)port); // short, network byte order
|
||||
my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
|
||||
memset(&(my_addr.sin_zero), 0, 8); // zero the rest of the struct
|
||||
|
||||
if (bind(sd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1)
|
||||
{
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen(sd, BACKLOG) == -1)
|
||||
{
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sd;
|
||||
}
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
static int openlistener6(int port)
|
||||
{
|
||||
int sd,tp;
|
||||
memset(&my_addr, 0, sizeof(my_addr));
|
||||
my_addr.sin_family = AF_INET;
|
||||
my_addr.sin_port = htons((short)port);
|
||||
my_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
#else
|
||||
struct sockaddr_in6 my_addr;
|
||||
|
||||
if ((sd = socket(AF_INET6, SOCK_STREAM, 0)) == -1)
|
||||
return -1;
|
||||
|
||||
setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &tp, sizeof(tp));
|
||||
memset(&my_addr, 0, sizeof(my_addr));
|
||||
my_addr.sin6_family = AF_INET6;
|
||||
my_addr.sin6_port = htons(port);
|
||||
my_addr.sin6_addr.s_addr = INADDR_ANY;
|
||||
#endif
|
||||
|
||||
if (bind(sd, (struct sockaddr *)&my_addr, sizeof(my_addr)) == -1)
|
||||
{
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen(sd, BACKLOG) == -1)
|
||||
{
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &tp, sizeof(tp));
|
||||
bind(sd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));
|
||||
listen(sd, BACKLOG);
|
||||
|
||||
return sd;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Wrapper function for strncpy() that guarantees
|
||||
a null-terminated string. This is to avoid any possible
|
||||
issues due to strncpy()'s behaviour.
|
||||
*/
|
||||
char *my_strncpy(char *dest, const char *src, size_t n)
|
||||
{
|
||||
strncpy(dest, src, n);
|
||||
dest[n-1] = '\0';
|
||||
return dest;
|
||||
}
|
||||
|
||||
int isdir(const char *tpbuf)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (stat(tpbuf, &st) == -1)
|
||||
return 0;
|
||||
|
||||
if ((st.st_mode & S_IFMT) == S_IFDIR)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
441
httpd/proc.c
441
httpd/proc.c
@@ -27,21 +27,31 @@
|
||||
#include "axhttp.h"
|
||||
|
||||
static int special_read(struct connstruct *cn, void *buf, size_t count);
|
||||
static int special_write(struct connstruct *cn,
|
||||
const uint8_t *buf, size_t count);
|
||||
static void send301(struct connstruct *cn);
|
||||
static void send404(struct connstruct *cn);
|
||||
static int procindex(struct connstruct *cn, struct stat *stp);
|
||||
static int hexit(char c);
|
||||
static void urldecode(char *buf);
|
||||
static void buildactualfile(struct connstruct *cn);
|
||||
static int sanitizefile(const char *buf);
|
||||
static int sanitizehost(char *buf);
|
||||
|
||||
#if defined(CONFIG_HTTP_DIRECTORIES)
|
||||
static void urlencode(unsigned char *s, unsigned char *t);
|
||||
static void urlencode(const uint8_t *s, uint8_t *t);
|
||||
static void procdirlisting(struct connstruct *cn);
|
||||
static int issockwriteable(int sd);
|
||||
#endif
|
||||
#if defined(CONFIG_HTTP_HAS_CGI)
|
||||
static void proccgi(struct connstruct *cn, int has_pathinfo);
|
||||
static int trycgi_withpathinfo(struct connstruct *cn);
|
||||
static void split(char *tp, char *sp[], int maxwords, char sc);
|
||||
static int iscgi(const char *fn);
|
||||
#endif
|
||||
|
||||
// Returns 1 if elems should continue being read, 0 otherwise
|
||||
int procheadelem(struct connstruct *cn, char *buf)
|
||||
static int procheadelem(struct connstruct *cn, char *buf)
|
||||
{
|
||||
char *delim, *value;
|
||||
#if defined(CONFIG_HTTP_HAS_CGI)
|
||||
@@ -98,7 +108,8 @@ int procheadelem(struct connstruct *cn, char *buf)
|
||||
my_strncpy(cn->virtualhostreq, value, MAXREQUESTLENGTH);
|
||||
}
|
||||
else if (strcmp(buf, "Connection:")==0 &&
|
||||
strcmp(value, "close")==0) {
|
||||
strcmp(value, "close")==0)
|
||||
{
|
||||
cn->close_when_done = 1;
|
||||
}
|
||||
else if (strcmp(buf, "If-Modified-Since:") ==0 )
|
||||
@@ -111,33 +122,26 @@ int procheadelem(struct connstruct *cn, char *buf)
|
||||
}
|
||||
|
||||
#if defined(CONFIG_HTTP_DIRECTORIES)
|
||||
void procdirlisting(struct connstruct *cn)
|
||||
static void procdirlisting(struct connstruct *cn)
|
||||
{
|
||||
char buf[MAXREQUESTLENGTH];
|
||||
char actualfile[1024];
|
||||
|
||||
#ifndef CONFIG_HTTP_DIRECTORIES
|
||||
if (allowdirectorylisting == 0)
|
||||
{
|
||||
send404(cn);
|
||||
removeconnection(cn);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cn->reqtype == TYPE_HEAD)
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\nContent-Type: text/html\n\n");
|
||||
snprintf(buf, sizeof(buf),
|
||||
"HTTP/1.1 200 OK\nContent-Type: text/html\n\n");
|
||||
write(cn->networkdesc, buf, strlen(buf));
|
||||
|
||||
removeconnection(cn);
|
||||
return;
|
||||
}
|
||||
|
||||
strcpy(actualfile, cn->actualfile);
|
||||
|
||||
#ifdef WIN32
|
||||
strcat(actualfile, "*");
|
||||
cn->dirp = FindFirstFile(actualfile, &cn->file_data);
|
||||
|
||||
if (cn->dirp == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
send404(cn);
|
||||
@@ -145,10 +149,7 @@ void procdirlisting(struct connstruct *cn)
|
||||
return;
|
||||
}
|
||||
#else
|
||||
|
||||
cn->dirp = opendir(actualfile);
|
||||
|
||||
if (cn->dirp == NULL)
|
||||
if ((cn->dirp = opendir(actualfile)) == NULL)
|
||||
{
|
||||
send404(cn);
|
||||
removeconnection(cn);
|
||||
@@ -159,7 +160,10 @@ void procdirlisting(struct connstruct *cn)
|
||||
readdir(cn->dirp);
|
||||
#endif
|
||||
|
||||
sprintf(buf, "HTTP/1.1 200 OK\nContent-Type: text/html\n\n<HTML><BODY>\n<TITLE>Directory Listing</TITLE>\n<H2>Directory listing of %s://%s%s</H2><BR>\n", cn->is_ssl ? "https" : "http", cn->virtualhostreq, cn->filereq);
|
||||
snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\nContent-Type: text/html\n\n"
|
||||
"<HTML><BODY>\n<TITLE>Directory Listing</TITLE>\n"
|
||||
"<H2>Directory listing of %s://%s%s</H2><BR>\n",
|
||||
cn->is_ssl ? "https" : "http", cn->virtualhostreq, cn->filereq);
|
||||
special_write(cn, buf, strlen(buf));
|
||||
cn->state = STATE_DOING_DIR;
|
||||
}
|
||||
@@ -179,14 +183,14 @@ void procdodir(struct connstruct *cn)
|
||||
#ifdef WIN32
|
||||
if (!FindNextFile(cn->dirp, &cn->file_data))
|
||||
#else
|
||||
if ((dp = readdir(cn->dirp)) == NULL)
|
||||
if ((dp = readdir(cn->dirp)) == NULL)
|
||||
#endif
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "</BODY></HTML>\n");
|
||||
special_write(cn, buf, strlen(buf));
|
||||
removeconnection(cn);
|
||||
return;
|
||||
}
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "</BODY></HTML>\n");
|
||||
special_write(cn, buf, strlen(buf));
|
||||
removeconnection(cn);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
file = cn->file_data.cFileName;
|
||||
@@ -199,31 +203,45 @@ void procdodir(struct connstruct *cn)
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s%s", cn->actualfile, file);
|
||||
putslash = isdir(buf);
|
||||
|
||||
urlencode(file, encbuf);
|
||||
snprintf(buf, sizeof(buf), "<A HREF=\"%s%s\">%s%s</A><BR>\n",
|
||||
encbuf, putslash ? "/" : "", file, putslash ? "/" : "");
|
||||
special_write(cn, buf, strlen(buf));
|
||||
} while (issockwriteable(cn->networkdesc));
|
||||
}
|
||||
|
||||
}
|
||||
while (issockwriteable(cn->networkdesc));
|
||||
static int issockwriteable(int sd)
|
||||
{
|
||||
fd_set wfds;
|
||||
struct timeval tv;
|
||||
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
FD_ZERO(&wfds);
|
||||
FD_SET(sd, &wfds);
|
||||
|
||||
select(FD_SETSIZE, NULL, &wfds, NULL, &tv);
|
||||
return FD_ISSET(sd, &wfds);
|
||||
}
|
||||
|
||||
/* Encode funny chars -> %xx in newly allocated storage */
|
||||
/* (preserves '/' !) */
|
||||
static void urlencode(unsigned char *s, unsigned char *t)
|
||||
static void urlencode(const uint8_t *s, uint8_t *t)
|
||||
{
|
||||
uint8_t *p, *tp;
|
||||
const uint8_t *p = s;
|
||||
uint8_t *tp;
|
||||
|
||||
tp =t ;
|
||||
tp = t;
|
||||
|
||||
for (p=s; *p; p++)
|
||||
for (; *p; p++)
|
||||
{
|
||||
if ((*p > 0x00 && *p < ',') ||
|
||||
(*p > '9' && *p < 'A') ||
|
||||
(*p > 'Z' && *p < '_') ||
|
||||
(*p > '_' && *p < 'a') ||
|
||||
(*p > 'z' && *p < 0xA1)) {
|
||||
(*p > 'z' && *p < 0xA1))
|
||||
{
|
||||
sprintf((char *)tp, "%%%02X", *p);
|
||||
tp += 3;
|
||||
}
|
||||
@@ -245,24 +263,23 @@ void procreadhead(struct connstruct *cn)
|
||||
int rv;
|
||||
|
||||
rv = special_read(cn, buf, sizeof(buf)-1);
|
||||
if (rv <= 0) {
|
||||
if (rv < 0)
|
||||
if (rv <= 0)
|
||||
{
|
||||
if (rv < 0) // really dead?
|
||||
removeconnection(cn);
|
||||
return;
|
||||
}
|
||||
|
||||
buf[rv] = '\0';
|
||||
|
||||
next = tp = buf;
|
||||
|
||||
// Split up lines and send to procheadelem()
|
||||
while(*next != '\0')
|
||||
while (*next != '\0')
|
||||
{
|
||||
// If we have a blank line, advance to next stage!
|
||||
if (*next == '\r' || *next == '\n')
|
||||
{
|
||||
buildactualfile(cn);
|
||||
|
||||
cn->state = STATE_WANT_TO_SEND_HEAD;
|
||||
return;
|
||||
}
|
||||
@@ -273,7 +290,7 @@ void procreadhead(struct connstruct *cn)
|
||||
if (*next == '\r')
|
||||
{
|
||||
*next = '\0';
|
||||
next+=2;
|
||||
next += 2;
|
||||
}
|
||||
else if (*next == '\n')
|
||||
*next++ = '\0';
|
||||
@@ -295,8 +312,8 @@ void procsendhead(struct connstruct *cn)
|
||||
struct stat stbuf;
|
||||
time_t now = cn->timeout - CONFIG_HTTP_TIMEOUT;
|
||||
char date[32];
|
||||
strcpy(date, ctime(&now));
|
||||
|
||||
strcpy(date, ctime(&now));
|
||||
strcpy(actualfile, cn->actualfile);
|
||||
|
||||
#ifdef WIN32
|
||||
@@ -309,8 +326,9 @@ void procsendhead(struct connstruct *cn)
|
||||
{
|
||||
#if defined(CONFIG_HTTP_HAS_CGI)
|
||||
if (trycgi_withpathinfo(cn) == 0)
|
||||
{ // We Try To Find A CGI
|
||||
proccgi(cn,1);
|
||||
{
|
||||
// We Try To Find A CGI
|
||||
proccgi(cn, 1);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -321,7 +339,7 @@ void procsendhead(struct connstruct *cn)
|
||||
}
|
||||
|
||||
#if defined(CONFIG_HTTP_HAS_CGI)
|
||||
if (iscgi(cn->actualfile))
|
||||
if (iscgi(cn->actualfile))
|
||||
{
|
||||
#ifndef WIN32
|
||||
// Set up CGI script
|
||||
@@ -333,7 +351,7 @@ void procsendhead(struct connstruct *cn)
|
||||
}
|
||||
#endif
|
||||
|
||||
proccgi(cn,0);
|
||||
proccgi(cn, 0);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -362,7 +380,7 @@ void procsendhead(struct connstruct *cn)
|
||||
|
||||
#if defined(CONFIG_HTTP_HAS_CGI)
|
||||
// If the index is a CGI file, handle it like any other CGI
|
||||
if (iscgi(cn->actualfile))
|
||||
if (iscgi(cn->actualfile))
|
||||
{
|
||||
// Set up CGI script
|
||||
if ((stbuf.st_mode & S_IEXEC) == 0 || isdir(cn->actualfile))
|
||||
@@ -372,45 +390,7 @@ void procsendhead(struct connstruct *cn)
|
||||
return;
|
||||
}
|
||||
|
||||
proccgi(cn,0);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
// If the index isn't a CGI, we continue on with the index file
|
||||
}
|
||||
|
||||
if ((stbuf.st_mode & S_IFMT) == S_IFDIR)
|
||||
{
|
||||
if (cn->filereq[strlen(cn->filereq)-1] != '/')
|
||||
{
|
||||
send301(cn);
|
||||
removeconnection(cn);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check to see if this dir has an index file
|
||||
if (procindex(cn, &stbuf) == 0)
|
||||
{
|
||||
#if defined(CONFIG_HTTP_DIRECTORIES)
|
||||
// If not, we do a directory listing of it
|
||||
procdirlisting(cn);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_HTTP_HAS_CGI)
|
||||
// If the index is a CGI file, handle it like any other CGI
|
||||
if (iscgi(cn->actualfile))
|
||||
{
|
||||
// Set up CGI script
|
||||
if ((stbuf.st_mode & S_IEXEC) == 0 || isdir(cn->actualfile))
|
||||
{
|
||||
send404(cn);
|
||||
removeconnection(cn);
|
||||
return;
|
||||
}
|
||||
|
||||
proccgi(cn,0);
|
||||
proccgi(cn, 0);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -419,7 +399,8 @@ void procsendhead(struct connstruct *cn)
|
||||
|
||||
if (cn->modified_since)
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "HTTP/1.1 304 Not Modified\nServer: axhttpd V%s\nDate: %s\n", VERSION, date);
|
||||
snprintf(buf, sizeof(buf), "HTTP/1.1 304 Not Modified\nServer: "
|
||||
"axhttpd V%s\nDate: %s\n", VERSION, date);
|
||||
special_write(cn, buf, strlen(buf));
|
||||
cn->modified_since = 0;
|
||||
cn->state = STATE_WANT_TO_READ_HEAD;
|
||||
@@ -433,12 +414,11 @@ void procsendhead(struct connstruct *cn)
|
||||
TTY_FLUSH();
|
||||
#endif
|
||||
|
||||
snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\nServer: axhttpd V%s\nContent-Type: %s\nContent-Length: %ld\nDate: %sLast-Modified: %s\n",
|
||||
VERSION,
|
||||
getmimetype(cn->actualfile),
|
||||
(long) stbuf.st_size,
|
||||
date,
|
||||
ctime(&(stbuf.st_mtime))); // ctime() has a \n on the end
|
||||
snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\nServer: axhttpd V%s\n"
|
||||
"Content-Type: %s\nContent-Length: %ld\n"
|
||||
"Date: %sLast-Modified: %s\n", VERSION,
|
||||
getmimetype(cn->actualfile), (long) stbuf.st_size,
|
||||
date, ctime(&(stbuf.st_mtime))); // ctime() has a \n on the end
|
||||
}
|
||||
|
||||
special_write(cn, buf, strlen(buf));
|
||||
@@ -478,7 +458,6 @@ void procsendhead(struct connstruct *cn)
|
||||
#else
|
||||
cn->state = STATE_WANT_TO_READ_FILE;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -490,10 +469,11 @@ void procreadfile(struct connstruct *cn)
|
||||
{
|
||||
close(cn->filedesc);
|
||||
cn->filedesc = -1;
|
||||
if (cn->close_when_done) /* close immediately */
|
||||
|
||||
if (cn->close_when_done) /* close immediately */
|
||||
removeconnection(cn);
|
||||
else
|
||||
{ /* keep socket open - HTTP 1.1 */
|
||||
{ /* keep socket open - HTTP 1.1 */
|
||||
cn->state = STATE_WANT_TO_READ_HEAD;
|
||||
cn->numbytes = 0;
|
||||
}
|
||||
@@ -514,7 +494,9 @@ void procsendfile(struct connstruct *cn)
|
||||
else if (rv == cn->numbytes)
|
||||
cn->state = STATE_WANT_TO_READ_FILE;
|
||||
else if (rv == 0)
|
||||
{ /* Do nothing */ }
|
||||
{
|
||||
/* Do nothing */
|
||||
}
|
||||
else
|
||||
{
|
||||
memmove(cn->databuf, cn->databuf + rv, cn->numbytes - rv);
|
||||
@@ -522,24 +504,16 @@ void procsendfile(struct connstruct *cn)
|
||||
}
|
||||
}
|
||||
|
||||
int special_write(struct connstruct *cn, const uint8_t *buf, size_t count)
|
||||
static int special_write(struct connstruct *cn,
|
||||
const uint8_t *buf, size_t count)
|
||||
{
|
||||
int res;
|
||||
|
||||
if (cn->is_ssl)
|
||||
{
|
||||
SSL *ssl = ssl_find(servers->ssl_ctx, cn->networkdesc);
|
||||
if (ssl)
|
||||
{
|
||||
res = ssl_write(ssl, (unsigned char *)buf, count);
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
return ssl ? ssl_write(ssl, (uint8_t *)buf, count) : -1;
|
||||
}
|
||||
else
|
||||
res = SOCKET_WRITE(cn->networkdesc, buf, count);
|
||||
|
||||
return res;
|
||||
return SOCKET_WRITE(cn->networkdesc, buf, count);
|
||||
}
|
||||
|
||||
static int special_read(struct connstruct *cn, void *buf, size_t count)
|
||||
@@ -549,7 +523,7 @@ static int special_read(struct connstruct *cn, void *buf, size_t count)
|
||||
if (cn->is_ssl)
|
||||
{
|
||||
SSL *ssl = ssl_find(servers->ssl_ctx, cn->networkdesc);
|
||||
unsigned char *read_buf;
|
||||
uint8_t *read_buf;
|
||||
|
||||
if ((res = ssl_read(ssl, &read_buf)) > SSL_OK)
|
||||
memcpy(buf, read_buf, res > (int)count ? count : res);
|
||||
@@ -566,26 +540,12 @@ static int special_read(struct connstruct *cn, void *buf, size_t count)
|
||||
static int procindex(struct connstruct *cn, struct stat *stp)
|
||||
{
|
||||
char tbuf[MAXREQUESTLENGTH];
|
||||
struct indexstruct *tp;
|
||||
|
||||
tp = indexlist;
|
||||
|
||||
while(tp != NULL) {
|
||||
sprintf(tbuf, "%s%s%s", cn->actualfile,
|
||||
#ifdef WIN32
|
||||
"\\",
|
||||
#else
|
||||
"/",
|
||||
#endif
|
||||
tp->name);
|
||||
|
||||
if (stat(tbuf, stp) != -1)
|
||||
{
|
||||
my_strncpy(cn->actualfile, tbuf, MAXREQUESTLENGTH);
|
||||
return 1;
|
||||
}
|
||||
|
||||
tp = tp->next;
|
||||
sprintf(tbuf, "%s%s", cn->actualfile, "index.html");
|
||||
if (stat(tbuf, stp) != -1)
|
||||
{
|
||||
my_strncpy(cn->actualfile, tbuf, MAXREQUESTLENGTH);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -599,8 +559,6 @@ static void proccgi(struct connstruct *cn, int has_pathinfo)
|
||||
char buf[MAXREQUESTLENGTH];
|
||||
#ifdef WIN32
|
||||
int tmp_stdout;
|
||||
#else
|
||||
int fv;
|
||||
#endif
|
||||
|
||||
snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\nServer: axhttpd V%s\n%s",
|
||||
@@ -614,28 +572,15 @@ static void proccgi(struct connstruct *cn, int has_pathinfo)
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
if (pipe(tpipe) == -1)
|
||||
{
|
||||
removeconnection(cn);
|
||||
return;
|
||||
}
|
||||
pipe(tpipe);
|
||||
|
||||
fv = fork();
|
||||
|
||||
if (fv == -1)
|
||||
{
|
||||
close(tpipe[0]);
|
||||
close(tpipe[1]);
|
||||
removeconnection(cn);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fv != 0)
|
||||
if (fork() > 0) // parent
|
||||
{
|
||||
// Close the write descriptor
|
||||
close(tpipe[1]);
|
||||
cn->filedesc = tpipe[0];
|
||||
cn->state = STATE_WANT_TO_READ_FILE;
|
||||
cn->close_when_done = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -653,7 +598,6 @@ static void proccgi(struct connstruct *cn, int has_pathinfo)
|
||||
|
||||
close(tpipe[0]);
|
||||
close(tpipe[1]);
|
||||
|
||||
myargs[0] = cn->actualfile;
|
||||
myargs[1] = cn->cgiargs;
|
||||
myargs[2] = NULL;
|
||||
@@ -666,11 +610,7 @@ static void proccgi(struct connstruct *cn, int has_pathinfo)
|
||||
|
||||
execv(cn->actualfile, myargs);
|
||||
#else /* WIN32 */
|
||||
if (_pipe(tpipe, 4096, O_BINARY| O_NOINHERIT) == -1)
|
||||
{
|
||||
removeconnection(cn);
|
||||
return;
|
||||
}
|
||||
_pipe(tpipe, 4096, O_BINARY| O_NOINHERIT);
|
||||
|
||||
myargs[0] = "sh";
|
||||
myargs[1] = "-c";
|
||||
@@ -703,6 +643,7 @@ static void proccgi(struct connstruct *cn, int has_pathinfo)
|
||||
close(tmp_stdout);
|
||||
cn->filedesc = tpipe[0];
|
||||
cn->state = STATE_WANT_TO_READ_FILE;
|
||||
cn->close_when_done = 1;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
@@ -716,6 +657,97 @@ static void proccgi(struct connstruct *cn, int has_pathinfo)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static int trycgi_withpathinfo(struct connstruct *cn)
|
||||
{
|
||||
char tpfile[MAXREQUESTLENGTH];
|
||||
char fr_str[MAXREQUESTLENGTH];
|
||||
char *fr_rs[MAXCGIARGS]; // filereq splitted
|
||||
int i = 0, offset;
|
||||
|
||||
my_strncpy(fr_str, cn->filereq, MAXREQUESTLENGTH);
|
||||
split(fr_str, fr_rs, MAXCGIARGS, '/');
|
||||
|
||||
while (fr_rs[i] != NULL)
|
||||
{
|
||||
snprintf(tpfile, sizeof(tpfile), "%s/%s%s",
|
||||
webroot, cn->virtualhostreq, fr_str);
|
||||
|
||||
if (iscgi(tpfile) && isdir(tpfile) == 0)
|
||||
{
|
||||
/* We've found our CGI file! */
|
||||
my_strncpy(cn->actualfile, tpfile, MAXREQUESTLENGTH);
|
||||
my_strncpy(cn->cgiscriptinfo, fr_str, MAXREQUESTLENGTH);
|
||||
|
||||
offset = (fr_rs[i] + strlen(fr_rs[i])) - fr_str;
|
||||
my_strncpy(cn->cgipathinfo, cn->filereq+offset, MAXREQUESTLENGTH);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
*(fr_rs[i]+strlen(fr_rs[i])) = '/';
|
||||
i++;
|
||||
}
|
||||
|
||||
/* Couldn't find any CGIs :( */
|
||||
*(cn->cgiscriptinfo) = '\0';
|
||||
*(cn->cgipathinfo) = '\0';
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int iscgi(const char *fn)
|
||||
{
|
||||
struct cgiextstruct *tp;
|
||||
int fnlen, extlen;
|
||||
|
||||
fnlen = strlen(fn);
|
||||
tp = cgiexts;
|
||||
|
||||
while (tp != NULL)
|
||||
{
|
||||
extlen = strlen(tp->ext);
|
||||
|
||||
if (strcasecmp(fn+(fnlen-extlen), tp->ext) == 0)
|
||||
return 1;
|
||||
|
||||
tp = tp->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void split(char *tp, char *sp[], int maxwords, char sc)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while(1)
|
||||
{
|
||||
/* Skip leading whitespace */
|
||||
while (*tp == sc) tp++;
|
||||
|
||||
if (*tp == '\0')
|
||||
{
|
||||
sp[i] = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (i==maxwords-2)
|
||||
{
|
||||
sp[maxwords-2] = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
sp[i] = tp;
|
||||
|
||||
while(*tp != sc && *tp != '\0')
|
||||
tp++;
|
||||
|
||||
if (*tp == sc)
|
||||
*tp++ = '\0';
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_HTTP_HAS_CGI */
|
||||
|
||||
/* Decode string %xx -> char (in place) */
|
||||
@@ -730,26 +762,28 @@ static void urldecode(char *buf)
|
||||
{
|
||||
v = 0;
|
||||
|
||||
if (*p=='%')
|
||||
if (*p == '%')
|
||||
{
|
||||
s = p;
|
||||
s++;
|
||||
|
||||
if (isxdigit((int) s[0]) && isxdigit((int) s[1]))
|
||||
{
|
||||
v = hexit(s[0])*16+hexit(s[1]);
|
||||
v = hexit(s[0])*16 + hexit(s[1]);
|
||||
|
||||
if (v)
|
||||
{ /* do not decode %00 to null char */
|
||||
*w=(char)v;
|
||||
p=&s[1];
|
||||
{
|
||||
/* do not decode %00 to null char */
|
||||
*w = (char)v;
|
||||
p = &s[1];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!v)
|
||||
*w=*p;
|
||||
p++; w++;
|
||||
if (!v) *w=*p;
|
||||
p++;
|
||||
w++;
|
||||
}
|
||||
|
||||
*w='\0';
|
||||
@@ -757,27 +791,98 @@ static void urldecode(char *buf)
|
||||
|
||||
static int hexit(char c)
|
||||
{
|
||||
if ( c >= '0' && c <= '9' )
|
||||
if (c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
if ( c >= 'a' && c <= 'f' )
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
return c - 'a' + 10;
|
||||
if ( c >= 'A' && c <= 'F' )
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
return c - 'A' + 10;
|
||||
|
||||
return 0;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void send301(struct connstruct *cn)
|
||||
{
|
||||
char buf[2048];
|
||||
snprintf(buf, sizeof(buf), "HTTP/1.1 301 Moved Permanently\nLocation: %s/\n\n<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<HTML><HEAD>\n<TITLE>301 Moved Permanently</TITLE>\n</HEAD><BODY>\n<H1>Moved Permanently</H1>\nThe document has moved <A HREF=\"%s/\">here</A>.<P>\n<HR>\n</BODY></HTML>\n", cn->filereq, cn->filereq);
|
||||
snprintf(buf, sizeof(buf),
|
||||
"HTTP/1.1 301 Moved Permanently\nLocation: %s/\n\n"
|
||||
"<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
|
||||
"<HTML><HEAD>\n<TITLE>301 Moved Permanently</TITLE>\n"
|
||||
"</HEAD><BODY>\n<H1>Moved Permanently</H1>\n"
|
||||
"The document has moved <A HREF=\"%s/\">here</A>.<P>\n"
|
||||
"<HR>\n</BODY></HTML>\n", cn->filereq, cn->filereq);
|
||||
special_write(cn, buf, strlen(buf));
|
||||
}
|
||||
|
||||
static void send404(struct connstruct *cn)
|
||||
{
|
||||
char buf[1024];
|
||||
sprintf(buf, "HTTP/1.0 404 Not Found\nContent-Type: text/html\n\n<HTML><BODY>\n<TITLE>404 Not Found</TITLE><H1>It ain't there my friend. (404 Not Found)</H1>\n</BODY></HTML>\n");
|
||||
strcpy(buf, "HTTP/1.0 404 Not Found\nContent-Type: text/html\n\n"
|
||||
"<HTML><BODY>\n<TITLE>404 Not Found</TITLE><H1>"
|
||||
"404 Not Found</H1>\n</BODY></HTML>\n");
|
||||
special_write(cn, buf, strlen(buf));
|
||||
}
|
||||
|
||||
static void buildactualfile(struct connstruct *cn)
|
||||
{
|
||||
snprintf(cn->actualfile, MAXREQUESTLENGTH, "%s%s", webroot, cn->filereq);
|
||||
|
||||
/* Add directory slash if not there */
|
||||
if (isdir(cn->actualfile) &&
|
||||
cn->actualfile[strlen(cn->actualfile)-1] != '/')
|
||||
strcat(cn->actualfile, "/");
|
||||
|
||||
#ifdef WIN32
|
||||
/* convert all the forward slashes to back slashes */
|
||||
{
|
||||
char *t = cn->actualfile;
|
||||
while ((t = strchr(t, '/')))
|
||||
{
|
||||
*t++ = '\\';
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static int sanitizefile(const char *buf)
|
||||
{
|
||||
int len, i;
|
||||
|
||||
// Don't accept anything not starting with a /
|
||||
if (*buf != '/')
|
||||
return 0;
|
||||
|
||||
len = strlen(buf);
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
// Check for "/." : In other words, don't send files starting with a .
|
||||
// Notice, GOBBLES, that this includes ".."
|
||||
if (buf[i] == '/' && buf[i+1] == '.')
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int sanitizehost(char *buf)
|
||||
{
|
||||
while (*buf != '\0')
|
||||
{
|
||||
// Handle the port
|
||||
if (*buf == ':')
|
||||
{
|
||||
*buf = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Enforce some basic URL rules...
|
||||
if (isalnum(*buf)==0 && *buf != '-' && *buf != '.') return 0;
|
||||
if (*buf == '.' && *(buf+1) == '.') return 0;
|
||||
if (*buf == '.' && *(buf+1) == '-') return 0;
|
||||
if (*buf == '-' && *(buf+1) == '.') return 0;
|
||||
buf++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user