summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHauke Mehrtens2026-05-03 22:18:48 +0000
committerHauke Mehrtens2026-05-15 00:29:10 +0000
commit8e5b26f93798af44e77d91146d26ae0f95e63006 (patch)
tree409373a8f91527314d7b5676d127ef204906601b
parent4221eb8b33ea90d6a09a6048e3280907263604a6 (diff)
downloaduhttpd-8e5b26f93798af44e77d91146d26ae0f95e63006.tar.gz
file: distinguish parse failure from epoch in date precondition checks
uh_file_date2unix returned 0 on strptime() failure, which the callers could not distinguish from a successfully parsed 1970-01-01 00:00:00 UTC. Two of those callers misbehave: * uh_file_if_modified_since compared the parsed value against st_mtime with '>='. For files whose mtime sits at the Unix epoch (some tmpfs / squashfs entries on OpenWrt initramfs), any malformed If-Modified-Since header satisfied 0 >= 0 and a 304 with no body was returned, breaking content delivery. * uh_file_if_unmodified_since compared with '<='. A malformed If-Unmodified-Since header always satisfies 0 <= st_mtime (for any real file with mtime > 0), so the precondition fired and every request received a 412 Precondition Failed. Return (time_t)-1 from uh_file_date2unix on parse failure, and ignore the precondition (treat the header as if absent) in the two callers when that sentinel is returned. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
-rw-r--r--file.c19
1 files changed, 16 insertions, 3 deletions
diff --git a/file.c b/file.c
index c29ec42..230d3d6 100644
--- a/file.c
+++ b/file.c
@@ -316,7 +316,7 @@ static time_t uh_file_date2unix(const char *date)
if (strptime(date, "%a, %d %b %Y %H:%M:%S %Z", &t) != NULL)
return timegm(&t);
- return 0;
+ return (time_t)-1;
}
static char * uh_file_unix2date(time_t ts, char *buf, int len)
@@ -402,11 +402,16 @@ static bool uh_file_if_match(struct client *cl, struct stat *s)
static int uh_file_if_modified_since(struct client *cl, struct stat *s)
{
char *hdr = uh_file_header(cl, HDR_IF_MODIFIED_SINCE);
+ time_t t;
if (!hdr)
return true;
- if (uh_file_date2unix(hdr) >= s->st_mtime) {
+ t = uh_file_date2unix(hdr);
+ if (t == (time_t)-1)
+ return true;
+
+ if (t >= s->st_mtime) {
uh_file_response_304(cl, s);
return false;
}
@@ -461,8 +466,16 @@ static int uh_file_if_range(struct client *cl, struct stat *s)
static int uh_file_if_unmodified_since(struct client *cl, struct stat *s)
{
char *hdr = uh_file_header(cl, HDR_IF_UNMODIFIED_SINCE);
+ time_t t;
+
+ if (!hdr)
+ return true;
+
+ t = uh_file_date2unix(hdr);
+ if (t == (time_t)-1)
+ return true;
- if (hdr && uh_file_date2unix(hdr) <= s->st_mtime) {
+ if (t <= s->st_mtime) {
uh_file_response_412(cl);
return false;
}