Browse Source

Added HTTP caching to static data.

default 1 year ago
parent
commit
d343b40ee5
4 changed files with 45 additions and 14 deletions
  1. 32 7
      data.c
  2. 6 4
      html.c
  3. 5 1
      httpd.c
  4. 2 2
      snac.h

+ 32 - 7
data.c

@@ -1533,19 +1533,44 @@ xs_str *_static_fn(snac *snac, const char *id)
 }
 
 
-int static_get(snac *snac, const char *id, xs_val **data, int *size)
+int static_get(snac *snac, const char *id, xs_val **data, int *size,
+                const char *inm, xs_str **etag)
 /* returns static content */
 {
     xs *fn = _static_fn(snac, id);
-    FILE *f;
     int status = 404;
 
-    if (fn && (f = fopen(fn, "rb")) != NULL) {
-        *size = XS_ALL;
-        *data = xs_read(f, size);
-        fclose(f);
+    if (fn) {
+        double tm = mtime(fn);
 
-        status = 200;
+        if (tm > 0.0) {
+            /* file exists; build the etag */
+            xs *e = xs_fmt("W/\"snac-%.0lf\"", tm);
+
+            /* if if-none-match is set, check if it's the same */
+            if (!xs_is_null(inm) && strcmp(e, inm) == 0) {
+                /* client has the newest version */
+                status = 304;
+            }
+            else {
+                /* newer or never downloaded; read the full file */
+                FILE *f;
+
+                if ((f = fopen(fn, "rb")) != NULL) {
+                    *size = XS_ALL;
+                    *data = xs_read(f, size);
+                    fclose(f);
+
+                    status = 200;
+                }
+            }
+
+            /* if caller wants the etag, return it */
+            if (etag != NULL)
+                *etag = xs_dup(e);
+
+            srv_debug(1, xs_fmt("static_get(): %d %s %s", status, id, e));
+        }
     }
 
     return status;

+ 6 - 4
html.c

@@ -226,7 +226,7 @@ d_char *html_user_header(snac *snac, d_char *s, int local)
         int size;
 
         /* try to open the user css */
-        if (!valid_status(static_get(snac, "style.css", &css, &size))) {
+        if (!valid_status(static_get(snac, "style.css", &css, &size, NULL, NULL))) {
             /* it's not there; try to open the server-wide css */
             FILE *f;
             xs *g_css_fn = xs_fmt("%s/style.css", srv_basedir);
@@ -1542,7 +1542,7 @@ xs_str *html_notifications(snac *snac)
 
 
 int html_get_handler(const xs_dict *req, const char *q_path,
-                     char **body, int *b_size, char **ctype)
+                     char **body, int *b_size, char **ctype, xs_str **etag)
 {
     char *accept = xs_dict_get(req, "accept");
     int status = 404;
@@ -1695,10 +1695,12 @@ int html_get_handler(const xs_dict *req, const char *q_path,
         char *id = xs_list_get(l, 1);
         int sz;
 
-        if (valid_status(static_get(&snac, id, body, &sz))) {
+        status = static_get(&snac, id, body, &sz,
+                        xs_dict_get(req, "if-none-match"), etag);
+
+        if (valid_status(status)) {
             *b_size = sz;
             *ctype  = xs_mime_by_ext(id);
-            status  = 200;
         }
     }
     else

+ 5 - 1
httpd.c

@@ -156,6 +156,7 @@ void httpd_connection(FILE *f)
     xs *headers  = NULL;
     xs *q_path   = NULL;
     xs *payload  = NULL;
+    xs *etag     = NULL;
     int p_size   = 0;
     char *p;
 
@@ -198,7 +199,7 @@ void httpd_connection(FILE *f)
 #endif /* NO_MASTODON_API */
 
         if (status == 0)
-            status = html_get_handler(req, q_path, &body, &b_size, &ctype);
+            status = html_get_handler(req, q_path, &body, &b_size, &ctype, &etag);
     }
     else
     if (strcmp(method, "POST") == 0) {
@@ -263,6 +264,9 @@ void httpd_connection(FILE *f)
     headers = xs_dict_append(headers, "content-type", ctype);
     headers = xs_dict_append(headers, "x-creator",    USER_AGENT);
 
+    if (!xs_is_null(etag))
+        headers = xs_dict_append(headers, "etag", etag);
+
     if (b_size == 0 && body != NULL)
         b_size = strlen(body);
 

+ 2 - 2
snac.h

@@ -137,7 +137,7 @@ int is_hidden(snac *snac, const char *id);
 int actor_add(const char *actor, xs_dict *msg);
 int actor_get(snac *snac, const char *actor, xs_dict **data);
 
-int static_get(snac *snac, const char *id, xs_val **data, int *size);
+int static_get(snac *snac, const char *id, xs_val **data, int *size, const char *inm, xs_str **etag);
 void static_put(snac *snac, const char *id, const char *data, int size);
 void static_put_meta(snac *snac, const char *id, const char *str);
 xs_str *static_get_meta(snac *snac, const char *id);
@@ -250,7 +250,7 @@ xs_str *not_really_markdown(const char *content, xs_list **attach);
 xs_str *sanitize(const char *content);
 
 int html_get_handler(const xs_dict *req, const char *q_path,
-                     char **body, int *b_size, char **ctype);
+                     char **body, int *b_size, char **ctype, xs_str **etag);
 int html_post_handler(const xs_dict *req, const char *q_path,
                       char *payload, int p_size,
                       char **body, int *b_size, char **ctype);