implement http not modified

On each request send "last-modified" header with the modification time of
each file. the client will store this field and send it on the next
request(s). On the server check the "if-modified-since" field with the
modified date sent by the client, depending on this send all the data or
the "304 not modified" http status.

CAVEAT: it is assumed the exact field will be send by the client, no date/time
conversion is done for simplicity sake, as far as that's possible with http ;)
This commit is contained in:
Hiltjo Posthuma 2014-02-15 15:36:52 +01:00 committed by sin
parent dfda73adf1
commit 7cd3150df7

45
quark.c
View file

@ -38,6 +38,7 @@ typedef struct {
static const char HttpOk[] = "200 OK"; static const char HttpOk[] = "200 OK";
static const char HttpMoved[] = "301 Moved Permanently"; static const char HttpMoved[] = "301 Moved Permanently";
static const char HttpNotModified[] = "304 Not Modified";
static const char HttpUnauthorized[] = "401 Unauthorized"; 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";
@ -67,6 +68,7 @@ static char host[NI_MAXHOST];
static char reqbuf[MAXBUFLEN+1]; static char reqbuf[MAXBUFLEN+1];
static char resbuf[MAXBUFLEN+1]; static char resbuf[MAXBUFLEN+1];
static char reqhost[256]; static char reqhost[256];
static char reqmod[256];
static int fd; static int fd;
static Request req; static Request req;
@ -184,6 +186,18 @@ responsecontenttype(const char *mimetype) {
return writetext(resbuf); 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];
@ -200,10 +214,13 @@ void
responsefile(void) { responsefile(void) {
const char *mimetype = "unknown"; const char *mimetype = "unknown";
char *p; char *p;
int i, ffd; char mod[25];
int i, ffd, r;
struct stat st; struct stat st;
time_t t;
if(stat(reqbuf, &st) == -1 || (ffd = open(reqbuf, O_RDONLY)) == -1) { r = stat(reqbuf, &st);
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(responsehdr(HttpNotFound) != -1
&& responsecontenttype(texthtml) != -1) && responsecontenttype(texthtml) != -1)
@ -214,6 +231,15 @@ responsefile(void) {
writetext("\r\n<html><body>404 Not Found</body></html>\r\n"); writetext("\r\n<html><body>404 Not Found</body></html>\r\n");
} }
else { else {
t = st.st_mtim.tv_sec;
memcpy(mod, asctime(gmtime(&t)), 24);
mod[24] = 0;
if(!strcmp(reqmod, mod)) {
if(responsehdr(HttpNotModified) != -1)
;
else
return;
} else {
if((p = strrchr(reqbuf, '.'))) { if((p = strrchr(reqbuf, '.'))) {
p++; p++;
for(i = 0; i < LENGTH(servermimes); i++) for(i = 0; i < LENGTH(servermimes); i++)
@ -223,6 +249,7 @@ responsefile(void) {
} }
} }
if(responsehdr(HttpOk) != -1 if(responsehdr(HttpOk) != -1
&& responsemodified(mod) != -1
&& responsecontentlen(st.st_size) != -1 && responsecontentlen(st.st_size) != -1
&& responsecontenttype(mimetype) != -1) && responsecontenttype(mimetype) != -1)
; ;
@ -230,6 +257,7 @@ responsefile(void) {
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);
}
close(ffd); close(ffd);
} }
} }
@ -388,12 +416,23 @@ request(void) {
for(p = res; *p && *p != ' ' && *p != '\t' && *p != '\r' && *p != '\n'; p++); for(p = res; *p && *p != ' ' && *p != '\t' && *p != '\r' && *p != '\n'; p++);
if(!*p) if(!*p)
goto invalid_request; goto invalid_request;
*p = 0;
if(p - res > sizeof reqhost) if(p - res > sizeof reqhost)
goto invalid_request; goto invalid_request;
memcpy(reqhost, res, p - res); memcpy(reqhost, res, p - res);
reqhost[p - res] = 0; reqhost[p - res] = 0;
} }
if((res = strstr(reqbuf, "If-Modified-Since:"))) {
for(res = res + 19; *res && (*res == ' ' || *res == '\t'); res++);
if(!*res)
goto invalid_request;
for(p = res; *p && *p != '\r' && *p != '\n'; p++);
if(!*p)
goto invalid_request;
if(p - res > sizeof reqmod)
goto invalid_request;
memcpy(reqmod, res, p - res);
reqmod[p - res] = 0;
}
for(p = reqbuf; *p && *p != '\r' && *p != '\n'; p++); for(p = reqbuf; *p && *p != '\r' && *p != '\n'; p++);
if(*p == '\r' || *p == '\n') { if(*p == '\r' || *p == '\n') {
*p = 0; *p = 0;