Add Last-Modified: HTTP header.
authorchrisz <chrisz@openbsd.org>
Thu, 21 Aug 2014 19:23:10 +0000 (19:23 +0000)
committerchrisz <chrisz@openbsd.org>
Thu, 21 Aug 2014 19:23:10 +0000 (19:23 +0000)
OK reyk@

usr.sbin/httpd/httpd.h
usr.sbin/httpd/server_fcgi.c
usr.sbin/httpd/server_file.c
usr.sbin/httpd/server_http.c

index 371dd1c..6f1b48d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: httpd.h,v 1.53 2014/08/13 16:04:28 reyk Exp $ */
+/*     $OpenBSD: httpd.h,v 1.54 2014/08/21 19:23:10 chrisz Exp $       */
 
 /*
  * Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -512,7 +512,7 @@ int  server_headers(struct client *,
            int (*)(struct client *, struct kv *, void *), void *);
 int     server_writeresponse_http(struct client *);
 int     server_response_http(struct client *, u_int, struct media_type *,
-           size_t);
+           size_t, time_t);
 void    server_reset_http(struct client *);
 void    server_close_http(struct client *);
 int     server_response(struct httpd *, struct client *);
@@ -520,7 +520,7 @@ struct server_config *
         server_getlocation(struct client *, const char *);
 const char *
         server_http_host(struct sockaddr_storage *, char *, size_t);
-void    server_http_date(char *, size_t);
+ssize_t         server_http_time(time_t, char *, size_t);
 int     server_log_http(struct client *, u_int, size_t);
 
 /* server_file.c */
index 848bae4..6eb668e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: server_fcgi.c,v 1.33 2014/08/13 18:00:54 chrisz Exp $ */
+/*     $OpenBSD: server_fcgi.c,v 1.34 2014/08/21 19:23:10 chrisz Exp $ */
 
 /*
  * Copyright (c) 2014 Florian Obser <florian@openbsd.org>
@@ -562,9 +562,9 @@ server_fcgi_header(struct client *clt, u_int code)
        } else if (kv_add(&desc->http_headers, "Connection", "close") == NULL)
                return (-1);
 
-       /* Date header is mandatory and should be added last */
-       server_http_date(tmbuf, sizeof(tmbuf));
-       if (kv_add(&desc->http_headers, "Date", tmbuf) == NULL)
+       /* Date header is mandatory and should be added as late as possible */
+       if (server_http_time(time(NULL), tmbuf, sizeof(tmbuf)) <= 0 ||
+           kv_add(&desc->http_headers, "Date", tmbuf) == NULL)
                return (-1);
 
        /* Write initial header (fcgi might append more) */
index e87bcbd..28b17c7 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: server_file.c,v 1.33 2014/08/14 07:50:35 chrisz Exp $ */
+/*     $OpenBSD: server_file.c,v 1.34 2014/08/21 19:23:10 chrisz Exp $ */
 
 /*
  * Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -49,7 +49,7 @@
 int     server_file_access(struct httpd *, struct client *, char *, size_t);
 int     server_file_request(struct httpd *, struct client *, char *,
            struct stat *);
-int     server_file_index(struct httpd *, struct client *);
+int     server_file_index(struct httpd *, struct client *, struct stat *);
 int     server_file_method(struct client *);
 
 int
@@ -123,7 +123,7 @@ server_file_access(struct httpd *env, struct client *clt,
                                goto fail;
                        }
 
-                       return (server_file_index(env, clt));
+                       return (server_file_index(env, clt, &st));
                }
                return (ret);
        } else if (!S_ISREG(st.st_mode)) {
@@ -220,7 +220,8 @@ server_file_request(struct httpd *env, struct client *clt, char *path,
                goto abort;
 
        media = media_find(env->sc_mediatypes, path);
-       ret = server_response_http(clt, 200, media, st->st_size);
+       ret = server_response_http(clt, 200, media, st->st_size,
+           MIN(time(NULL), st->st_mtim.tv_sec));
        switch (ret) {
        case -1:
                goto fail;
@@ -267,7 +268,7 @@ server_file_request(struct httpd *env, struct client *clt, char *path,
 }
 
 int
-server_file_index(struct httpd *env, struct client *clt)
+server_file_index(struct httpd *env, struct client *clt, struct stat *st)
 {
        char                      path[MAXPATHLEN];
        char                      tmstr[21];
@@ -279,9 +280,8 @@ server_file_index(struct httpd *env, struct client *clt)
        struct evbuffer          *evb = NULL;
        struct media_type        *media;
        const char               *style;
-       struct stat               st;
        struct tm                 tm;
-       time_t                    t;
+       time_t                    t, dir_mtime;
 
        if ((ret = server_file_method(clt)) != 0) {
                code = ret;
@@ -297,6 +297,9 @@ server_file_index(struct httpd *env, struct client *clt)
        if ((fd = open(path, O_RDONLY)) == -1)
                goto abort;
 
+       /* Save last modification time */
+       dir_mtime = MIN(time(NULL), st->st_mtim.tv_sec);
+
        if ((evb = evbuffer_new()) == NULL)
                goto abort;
 
@@ -328,12 +331,12 @@ server_file_index(struct httpd *env, struct client *clt)
                dp = namelist[i];
 
                if (skip ||
-                   fstatat(fd, dp->d_name, &st, 0) == -1) {
+                   fstatat(fd, dp->d_name, st, 0) == -1) {
                        free(dp);
                        continue;
                }
 
-               t = st.st_mtime;
+               t = st->st_mtime;
                localtime_r(&t, &tm);
                strftime(tmstr, sizeof(tmstr), "%d-%h-%Y %R", &tm);
                namewidth = 51 - strlen(dp->d_name);
@@ -341,18 +344,18 @@ server_file_index(struct httpd *env, struct client *clt)
                if (dp->d_name[0] == '.' &&
                    !(dp->d_name[1] == '.' && dp->d_name[2] == '\0')) {
                        /* ignore hidden files starting with a dot */
-               } else if (S_ISDIR(st.st_mode)) {
+               } else if (S_ISDIR(st->st_mode)) {
                        namewidth -= 1; /* trailing slash */
                        if (evbuffer_add_printf(evb,
                            "<a href=\"%s\">%s/</a>%*s%s%20s\n",
                            dp->d_name, dp->d_name,
                            MAX(namewidth, 0), " ", tmstr, "-") == -1)
                                skip = 1;
-               } else if (S_ISREG(st.st_mode)) {
+               } else if (S_ISREG(st->st_mode)) {
                        if (evbuffer_add_printf(evb,
                            "<a href=\"%s\">%s</a>%*s%s%20llu\n",
                            dp->d_name, dp->d_name,
-                           MAX(namewidth, 0), " ", tmstr, st.st_size) == -1)
+                           MAX(namewidth, 0), " ", tmstr, st->st_size) == -1)
                                skip = 1;
                }
                free(dp);
@@ -368,7 +371,8 @@ server_file_index(struct httpd *env, struct client *clt)
        fd = -1;
 
        media = media_find(env->sc_mediatypes, "index.html");
-       ret = server_response_http(clt, 200, media, EVBUFFER_LENGTH(evb));
+       ret = server_response_http(clt, 200, media, EVBUFFER_LENGTH(evb),
+           dir_mtime);
        switch (ret) {
        case -1:
                goto fail;
index 9e09428..af996a5 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: server_http.c,v 1.44 2014/08/08 18:29:42 reyk Exp $   */
+/*     $OpenBSD: server_http.c,v 1.45 2014/08/21 19:23:10 chrisz Exp $ */
 
 /*
  * Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -534,16 +534,16 @@ server_reset_http(struct client *clt)
        server_log(clt, NULL);
 }
 
-void
-server_http_date(char *tmbuf, size_t len)
+ssize_t
+server_http_time(time_t t, char *tmbuf, size_t len)
 {
-       time_t                   t;
        struct tm                tm;
 
        /* New HTTP/1.1 RFC 7231 prefers IMF-fixdate from RFC 5322 */
-       time(&t);
-       gmtime_r(&t, &tm);
-       strftime(tmbuf, len, "%a, %d %h %Y %T %Z", &tm);
+       if (t == -1 || gmtime_r(&t, &tm) == NULL)
+               return (-1);
+       else
+               return (strftime(tmbuf, len, "%a, %d %h %Y %T %Z", &tm));
 }
 
 const char *
@@ -602,7 +602,8 @@ server_abort_http(struct client *clt, u_int code, const char *msg)
        if (print_host(&srv_conf->ss, hbuf, sizeof(hbuf)) == NULL)
                goto done;
 
-       server_http_date(tmbuf, sizeof(tmbuf));
+       if (server_http_time(time(NULL), tmbuf, sizeof(tmbuf)) <= 0)
+               goto done;
 
        /* Do not send details of the Internal Server Error */
        switch (code) {
@@ -790,7 +791,7 @@ server_getlocation(struct client *clt, const char *path)
 
 int
 server_response_http(struct client *clt, u_int code,
-    struct media_type *media, size_t size)
+    struct media_type *media, size_t size, time_t mtime)
 {
        struct http_descriptor  *desc = clt->clt_desc;
        const char              *error;
@@ -835,9 +836,14 @@ server_response_http(struct client *clt, u_int code,
            kv_set(cl, "%ld", size) == -1)
                return (-1);
 
-       /* Date header is mandatory and should be added last */
-       server_http_date(tmbuf, sizeof(tmbuf));
-       if (kv_add(&desc->http_headers, "Date", tmbuf) == NULL)
+       /* Set last modification time */
+       if (server_http_time(mtime, tmbuf, sizeof(tmbuf)) <= 0 ||
+           kv_add(&desc->http_headers, "Last-Modified", tmbuf) == NULL)
+               return (-1);
+
+       /* Date header is mandatory and should be added as late as possible */
+       if (server_http_time(time(NULL), tmbuf, sizeof(tmbuf)) <= 0 ||
+           kv_add(&desc->http_headers, "Date", tmbuf) == NULL)
                return (-1);
 
        /* Write completed header */