-/* $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>
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 *);
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 */
-/* $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>
} 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) */
-/* $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>
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
goto fail;
}
- return (server_file_index(env, clt));
+ return (server_file_index(env, clt, &st));
}
return (ret);
} else if (!S_ISREG(st.st_mode)) {
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;
}
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];
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;
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;
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);
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);
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;
-/* $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>
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 *
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) {
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;
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 */