If-Modified-Since is already sent by most web browsers to httpd. This patch adds a check to server_file_access before we send the file back.
This does not do any checks for autoindex directories as the size and last modification dates of files would not get updated properly. I separated the logic for checking the header values as it can be reused for different side effects of other headers like Range. 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); }