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:
parent
6d5bedd72a
commit
e9408312e1
1 changed files with 41 additions and 87 deletions
128
quark.c
128
quark.c
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue