If-Modified-Since is sent by http clients to be notified if a file has
been changed. This patch adds a function server_file_modified_since
that checks the time of the file from stat with the time sent from the
client. The separate function will help implement proper Range support.

I found 'timeoff' to be useful for converting to a time_t that is in
GMT; however, did not find documentation on this in the man pages. It
seems to be a function dating back to at least the NetBSD fork. If 
there is a better time function I should be using please let me know.

The logic is separated out so we can reuse this in the future. I was
thinking this should be in http.c instead of server_file.c, but for
right now it is only useful for file operations. If-Modified-Since on
autoindex will not work due to how the index would be checked by this
code.

There is room for the 'If-Unmodified-Since' header, but it is not
really useful for file operations without Range support.


Index: usr.sbin/httpd/server_file.c
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/server_file.c,v
retrieving revision 1.51
diff -u -p -r1.51 server_file.c
--- usr.sbin/httpd/server_file.c        12 Feb 2015 10:05:29 -0000      1.51
+++ usr.sbin/httpd/server_file.c        18 Apr 2015 16:41:55 -0000
@@ -42,6 +42,7 @@ int    server_file_request(struct httpd *,
            struct stat *);
 int     server_file_index(struct httpd *, struct client *, struct stat *);
 int     server_file_method(struct client *);
+int     server_file_modified_since(struct http_descriptor *, struct stat *);
 
 int
 server_file_access(struct httpd *env, struct client *clt,
@@ -123,6 +124,10 @@ server_file_access(struct httpd *env, st
                goto fail;
        }
 
+       if ((ret = server_file_modified_since(desc, &st)) != -1) {
+               return ret;
+       }
+
        return (server_file_request(env, clt, path, &st));
 
  fail:
@@ -466,4 +471,24 @@ server_file_error(struct bufferevent *be
        }
        server_close(clt, "unknown event error");
        return;
+}
+
+int
+server_file_modified_since(struct http_descriptor * desc, struct stat * st)
+{
+       struct kv                key, *since;
+       struct tm                tm;
+
+       memset(&tm, 0, sizeof(struct tm));
+
+       key.kv_key = "If-Modified-Since";
+       if ((since = kv_find(&desc->http_headers, &key)) != NULL &&
+           since->kv_value != NULL) {
+               if (strptime(since->kv_value, "%a, %d %h %Y %T %Z", &tm) != 
NULL &&
+                   timeoff(&tm, 0L) >= st->st_mtim.tv_sec) {
+                       return 304;
+               }
+       }
+
+       return (-1);
 }

Reply via email to