Refactor response-constructors

Instead of providing a function for each entry-type, use a small
static lookup-table and one function to rule them all.
In the future, in case the list grows, we might think about
implementing it with a small hash-lookup, but currently,
it's easy enough synchronizing the enum and the array.

While at it, improve the logic in the code itself
by using logical OR's instead of AND's.
This commit is contained in:
FRIGN 2014-08-06 17:47:56 +02:00
parent 6d5bedd72a
commit e9408312e1

128
quark.c
View file

@ -46,12 +46,28 @@ static const char HttpUnauthorized[] = "401 Unauthorized";
static const char HttpNotFound[] = "404 Not Found"; static const char HttpNotFound[] = "404 Not Found";
static const char texthtml[] = "text/html"; static const char texthtml[] = "text/html";
enum {
HEADER,
CONTENTLEN,
LOCATION,
CONTENTTYPE,
MODIFIED
};
static const char *resentry[] = {
"HTTP/1.1 %s\r\nConnection: close\r\nDate: %s\r\nServer: quark-"VERSION"\r\n",
"Content-Length: %lu\r\n",
"Location: %s%s\r\n",
"Content-Type: %s\r\n",
"Last-Modified: %s\r\n" };
static ssize_t writetext(const char *buf); static ssize_t writetext(const char *buf);
static ssize_t writedata(const char *buf, size_t buflen); static ssize_t writedata(const char *buf, size_t buflen);
static void atomiclog(int fd, const char *errstr, va_list ap); static void atomiclog(int fd, const char *errstr, va_list ap);
static void die(const char *errstr, ...);
static void logmsg(const char *errstr, ...); static void logmsg(const char *errstr, ...);
static void logerrmsg(const char *errstr, ...); static void logerrmsg(const char *errstr, ...);
static void die(const char *errstr, ...);
static int putresentry(int type, ...);
static void response(void); static void response(void);
static void responsecgi(void); static void responsecgi(void);
static void responsedir(void); static void responsedir(void);
@ -140,68 +156,18 @@ die(const char *errstr, ...) {
} }
int int
responsehdr(const char *status) { putresentry(int type, ...) {
if(snprintf(resbuf, MAXBUFLEN, va_list ap;
"HTTP/1.1 %s\r\n"
"Connection: close\r\n" va_start(ap, type);
"Date: %s\r\n" if(vsnprintf(resbuf, MAXBUFLEN, resentry[type], ap) >= MAXBUFLEN) {
"Server: quark-"VERSION"\r\n", logerrmsg("vsnprintf failed, buffer size exceeded");
status, tstamp()) >= MAXBUFLEN)
{
logerrmsg("snprintf failed, buffer size exceeded");
return -1; return -1;
} }
va_end(ap);
return writetext(resbuf); return writetext(resbuf);
} }
int
responsecontentlen(off_t size) {
if(snprintf(resbuf, MAXBUFLEN,
"Content-Length: %lu\r\n",
size) >= MAXBUFLEN)
{
logerrmsg("snprintf failed, buffer sizeof exceeded");
return -1;
}
return writetext(resbuf);
}
int
responselocation(const char *location, const char *pathinfo) {
if(snprintf(resbuf, MAXBUFLEN,
"Location: %s%s\r\n",
location, pathinfo) >= MAXBUFLEN)
{
logerrmsg("snprintf failed, buffer sizeof exceeded");
return -1;
}
return writetext(resbuf);
}
int
responsecontenttype(const char *mimetype) {
if(snprintf(resbuf, MAXBUFLEN,
"Content-Type: %s\r\n",
mimetype) >= MAXBUFLEN)
{
logerrmsg("snprintf failed, buffer sizeof exceeded");
return -1;
}
return writetext(resbuf);
}
int
responsemodified(char *mod) {
if(snprintf(resbuf, MAXBUFLEN,
"Last-Modified: %s\r\n",
mod) >= MAXBUFLEN)
{
logerrmsg("snprintf failed, buffer sizeof exceeded");
return -1;
}
return writetext(resbuf);
}
void void
responsefiledata(int fd, off_t size) { responsefiledata(int fd, off_t size) {
char buf[BUFSIZ]; char buf[BUFSIZ];
@ -226,10 +192,8 @@ responsefile(void) {
r = stat(reqbuf, &st); r = stat(reqbuf, &st);
if(r == -1 || (ffd = open(reqbuf, O_RDONLY)) == -1) { if(r == -1 || (ffd = open(reqbuf, O_RDONLY)) == -1) {
logerrmsg("%s requests unknown path %s\n", host, reqbuf); logerrmsg("%s requests unknown path %s\n", host, reqbuf);
if(responsehdr(HttpNotFound) != -1 if(putresentry(HEADER, HttpNotFound, tstamp()) == -1
&& responsecontenttype(texthtml) != -1) || putresentry(CONTENTTYPE, texthtml) == -1)
;
else
return; return;
if(req.type == GET) if(req.type == GET)
writetext("\r\n<html><body>404 Not Found</body></html>\r\n"); writetext("\r\n<html><body>404 Not Found</body></html>\r\n");
@ -239,9 +203,7 @@ responsefile(void) {
memcpy(mod, asctime(gmtime(&t)), 24); memcpy(mod, asctime(gmtime(&t)), 24);
mod[24] = 0; mod[24] = 0;
if(!strcmp(reqmod, mod)) { if(!strcmp(reqmod, mod)) {
if(responsehdr(HttpNotModified) != -1) if(putresentry(HEADER, HttpNotModified, tstamp()) == -1)
;
else
return; return;
} else { } else {
if((p = strrchr(reqbuf, '.'))) { if((p = strrchr(reqbuf, '.'))) {
@ -252,12 +214,10 @@ responsefile(void) {
break; break;
} }
} }
if(responsehdr(HttpOk) != -1 if(putresentry(HEADER, HttpOk, tstamp()) == -1
&& responsemodified(mod) != -1 || putresentry(MODIFIED, mod) == -1
&& responsecontentlen(st.st_size) != -1 || putresentry(CONTENTLEN, st.st_size) == -1
&& responsecontenttype(mimetype) != -1) || putresentry(CONTENTTYPE, mimetype) == -1)
;
else
return; return;
if(req.type == GET && writetext("\r\n") != -1) if(req.type == GET && writetext("\r\n") != -1)
responsefiledata(ffd, st.st_size); responsefiledata(ffd, st.st_size);
@ -270,10 +230,8 @@ void
responsedirdata(DIR *d) { responsedirdata(DIR *d) {
struct dirent *e; struct dirent *e;
if(responsehdr(HttpOk) != -1 if(putresentry(HEADER, HttpOk, tstamp()) == -1
&& responsecontenttype(texthtml) != -1) || putresentry(CONTENTTYPE, texthtml) == -1)
;
else
return; return;
if(req.type == GET) { if(req.type == GET) {
if(writetext("\r\n<html><body><a href='..'>..</a><br>\r\n") == -1) if(writetext("\r\n<html><body><a href='..'>..</a><br>\r\n") == -1)
@ -304,11 +262,9 @@ responsedir(void) {
reqbuf[len++] = '/'; reqbuf[len++] = '/';
reqbuf[len] = 0; reqbuf[len] = 0;
logmsg("redirecting %s to %s%s\n", host, location, reqbuf); logmsg("redirecting %s to %s%s\n", host, location, reqbuf);
if(responsehdr(HttpMoved) != -1 if(putresentry(HEADER, HttpMoved, tstamp()) == -1
&& responselocation(location, reqbuf) != -1 || putresentry(LOCATION, location, reqbuf) == -1
&& responsecontenttype(texthtml) != -1) || putresentry(CONTENTTYPE, texthtml) == -1)
;
else
return; return;
if(req.type == GET) if(req.type == GET)
writetext("\r\n<html><body>301 Moved Permanently</a></body></html>\r\n"); writetext("\r\n<html><body>301 Moved Permanently</a></body></html>\r\n");
@ -348,7 +304,7 @@ responsecgi(void) {
if(chdir(cgi_dir) == -1) if(chdir(cgi_dir) == -1)
logerrmsg("chdir to cgi directory %s failed: %s\n", cgi_dir, strerror(errno)); logerrmsg("chdir to cgi directory %s failed: %s\n", cgi_dir, strerror(errno));
if((cgi = popen(cgi_script, "r"))) { if((cgi = popen(cgi_script, "r"))) {
if(responsehdr(HttpOk) == -1) if(putresentry(HEADER, HttpOk, tstamp()) == -1)
return; return;
while((r = fread(resbuf, 1, MAXBUFLEN, cgi)) > 0) { while((r = fread(resbuf, 1, MAXBUFLEN, cgi)) > 0) {
if(writedata(resbuf, r) == -1) { if(writedata(resbuf, r) == -1) {
@ -360,10 +316,8 @@ responsecgi(void) {
} }
else { else {
logerrmsg("%s requests %s, but cannot run cgi script %s\n", host, cgi_script, reqbuf); logerrmsg("%s requests %s, but cannot run cgi script %s\n", host, cgi_script, reqbuf);
if(responsehdr(HttpNotFound) != -1 if(putresentry(HEADER, HttpNotFound, tstamp()) == -1
&& responsecontenttype(texthtml) != -1) || putresentry(CONTENTTYPE, texthtml) == -1)
;
else
return; return;
if(req.type == GET) if(req.type == GET)
writetext("\r\n<html><body>404 Not Found</body></html>\r\n"); writetext("\r\n<html><body>404 Not Found</body></html>\r\n");
@ -378,8 +332,8 @@ response(void) {
for(p = reqbuf; *p; p++) for(p = reqbuf; *p; p++)
if(*p == '\\' || (*p == '/' && *(p + 1) == '.')) { /* don't serve bogus or hidden files */ if(*p == '\\' || (*p == '/' && *(p + 1) == '.')) { /* don't serve bogus or hidden files */
logerrmsg("%s requests bogus or hidden file %s\n", host, reqbuf); logerrmsg("%s requests bogus or hidden file %s\n", host, reqbuf);
if(responsehdr(HttpUnauthorized) != -1 if(putresentry(HEADER, HttpUnauthorized, tstamp()) == -1
&& responsecontenttype(texthtml) != -1) || putresentry(CONTENTTYPE, texthtml) == -1)
; ;
else else
return; return;