On Sat, Apr 18, 2015 at 12:19:46PM -0500, jmp wrote:
> 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.
I think timegm(3) is acceptable.
> 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;
> + }
> +
RFC 7232
A recipient MUST ignore the If-Modified-Since header field if the
received field-value is not a valid HTTP-date, or if the request
method is neither GET nor HEAD.
^^^^^^^^^^^^^^^^^^^^
> 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;
> + }
> + }
RFC 7231 defines 3 formats for HTTP-date and then goes on:
A recipient that parses a timestamp value in an HTTP header field
MUST accept all three HTTP-date formats.
I think it's ok here to only parse one variation and ignore
If-Modified-Since otherwise, we will just respond with a 200.
> +
> + return (-1);
> }
>
Here is a tweaked version of the diff (check for GET/HEAD; timegm(3)).
This is OK florian@ or if someone wants to OK it I can commit it.
diff --git server_file.c server_file.c
index 3580bbb..9abf83b 100644
--- server_file.c
+++ server_file.c
@@ -42,6 +42,7 @@ int server_file_request(struct httpd *, struct client *,
char *,
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,12 @@ server_file_access(struct httpd *env, struct client *clt,
goto fail;
}
+ if (desc->http_method == HTTP_METHOD_GET || desc->http_method ==
+ HTTP_METHOD_HEAD) {
+ if ((ret = server_file_modified_since(desc, &st)) != -1)
+ return ret;
+ }
+
return (server_file_request(env, clt, path, &st));
fail:
@@ -469,3 +476,23 @@ server_file_error(struct bufferevent *bev, short error,
void *arg)
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 && timegm(&tm) >= st->st_mtim.tv_sec) {
+ return (304);
+ }
+ }
+
+ return (-1);
+}
--
I'm not entirely sure you are real.