diff options
authorBryce Kwon <bryce@brycekwon.com>
committerBryce Kwon <bryce@brycekwon.com>
commit
parent
tree
download
Show an odd pushed date rather than die on it
A date past what the system holds, a zone that is no hhmm offset, or a date earlier than its own westward offset all made git die inside show_date, which took the summary, refs, log, commit and feed pages of the repository down. They are now clamped as git's own log clamps them.
-rw-r--r--source/parsing.c18
-rw-r--r--source/ui-atom.c4
-rw-r--r--source/ui-shared.c6
-rwxr-xr-xtests/t0303-robustness.sh39
4 files changed, 62 insertions, 5 deletions
diff --git a/source/parsing.c b/source/parsing.c
index dab81fa..71ecdb7 100644
--- a/source/parsing.c
+++ b/source/parsing.c
@@ -71,10 +71,24 @@ static void parse_user(const char *line, char **name, char **email, timestamp_t
strbuf_addch(&address, '>');
*email = strbuf_detach(&address, NULL);
+ // Clamped as git's own show_ident_date clamps them: a date past
+ // what the system can hold becomes the epoch, and a zone that is
+ // no hhmm offset becomes UTC, where git's date code would die on
+ // either and take the whole page with it.
if (ident.date_begin)
*date = parse_timestamp(ident.date_begin, NULL, 10);
- if (ident.tz_begin)
- *tz = atoi(ident.tz_begin);
+ if (date_overflows(*date))
+ *date = 0;
+ if (ident.tz_begin) {
+ long zone = strtol(ident.tz_begin, NULL, 10);
+ long west = zone < 0 ? -zone : 0;
+
+ *tz = zone > -10000 && zone < 10000 ? zone : 0;
+ // A date earlier than its own westward offset has no
+ // local time before the epoch to show.
+ if (*date < (timestamp_t)((west / 100) * 60 + west % 100) * 60)
+ *tz = 0;
+ }
}
}
diff --git a/source/ui-atom.c b/source/ui-atom.c
index 0f82c0d..55b59a1 100644
--- a/source/ui-atom.c
+++ b/source/ui-atom.c
@@ -24,6 +24,10 @@
*/
static const char *feed_date(timestamp_t when)
{
+ // The newest commit's date comes straight from git, unclamped, and
+ // git's date code dies on one the system cannot hold.
+ if (date_overflows(when))
+ when = 0;
return show_date(when, 0, date_mode_from_type(DATE_ISO8601_STRICT));
}
diff --git a/source/ui-shared.c b/source/ui-shared.c
index a0a0664..d1b9994 100644
--- a/source/ui-shared.c
+++ b/source/ui-shared.c
@@ -1418,9 +1418,9 @@ void cgit_print_age(time_t t, int tz, time_t max_relative)
if (!t)
return;
time(&now);
- secs = now - t;
- if (secs < 0)
- secs = 0;
+ // A date past now, or one so far off that the difference cannot be
+ // held, reads as no age at all.
+ secs = t > now ? 0 : now - t;
if (!ctx.cfg.enable_relative_dates || (secs > max_relative && max_relative >= 0)) {
print_abs_date(t, tz);
diff --git a/tests/t0303-robustness.sh b/tests/t0303-robustness.sh
index 05237c6..3cd49ed 100755
--- a/tests/t0303-robustness.sh
+++ b/tests/t0303-robustness.sh
@@ -796,4 +796,43 @@ test_expect_success 'the error page does not resolve the id it refused' '
! grep "<title>.* @ " tmp
'
+# A pushed date or zone outside what git's date code accepts used to end the
+# summary, refs and log pages inside git. Each is now shown as the epoch or
+# as UTC, the way git's own log shows them.
+test_expect_success 'odd dates and zones in pushed objects render' '
+ test_create_repo repos/dates &&
+ (
+ cd repos/dates &&
+ test_commit base &&
+ c=$(git rev-parse HEAD) &&
+ t=$(printf "object %s\\ntype commit\\ntag early\\ntagger E <e@x> 1 -0100\\n\\nearly\\n" $c |
+ git hash-object -t tag -w --stdin) &&
+ git update-ref refs/tags/early $t &&
+ tree=$(git rev-parse HEAD^{tree}) &&
+ far=$(printf "tree %s\\nauthor A <a@x> 9223372036854775808 +0000\\ncommitter A <a@x> 9223372036854775808 +0000\\n\\nfar\\n" $tree |
+ git hash-object -t commit -w --literally --stdin) &&
+ git update-ref refs/heads/far $far &&
+ zone=$(printf "tree %s\\nauthor A <a@x> 1700000000 -2147483648\\ncommitter A <a@x> 1700000000 +99999999999\\n\\nzone\\n" $tree |
+ git hash-object -t commit -w --literally --stdin) &&
+ git update-ref refs/heads/zone $zone
+ ) &&
+ {
+ echo "virtual-root=/" &&
+ echo "cache-size=0" &&
+ echo "repo.url=dates" &&
+ echo "repo.path=$PWD/repos/dates/.git"
+ } >datesrc &&
+ for q in "url=dates/" "url=dates/refs/" "url=dates/tag/&h=early" \
+ "url=dates/log/&h=far" "url=dates/commit/&h=far" "url=dates/commit/&h=zone" \
+ "url=dates/atom/&h=far"
+ do
+ CGIT_CONFIG="$PWD/datesrc" QUERY_STRING="$q" cgit >tmp 2>err &&
+ grep "^Status: 200" tmp &&
+ ! grep "Unable to complete" tmp &&
+ ! grep "Timestamp" err || return 1
+ done &&
+ CGIT_CONFIG="$PWD/datesrc" QUERY_STRING="url=dates/commit/&h=far" cgit >tmp &&
+ grep "1970-01-01" tmp
+'
+
test_done