From: Willy Tarreau Date: Wed, 30 Sep 2026 08:49:48 +0000 (+0200) Subject: BUG/MINOR: sample: zero-pad the fractional part emitted by http_date() X-Git-Tag: v3.5-dev8~85 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=5b515a38cef696a28a568fdbc41b16ac2ad863b4;p=haproxy.git BUG/MINOR: sample: zero-pad the fractional part emitted by http_date() When http_date() is given the "ms" or "us" unit, it appends the sub-second part of the date with a plain "%d", so it is printed without any padding: 123 ms gives ".123" but 23 ms gives ".23", which stands for a completely different instant, and 23 us gives ".23" as well although the two units must not produce the same string. The fraction is now printed over the number of digits its unit requires, three for milliseconds and six for microseconds. The test which selects the format is also made to depend on that width rather than on the unit argument, which is equivalent but clearer. The bug was introduced in 2.1-dev4 with commit ae6f125c7b ("MINOR: sample: add us/ms support to date/http_date"), so this fix should be backported to all stable branches. --- diff --git a/src/http_conv.c b/src/http_conv.c index 02c3a79b1..b97ce6d6e 100644 --- a/src/http_conv.c +++ b/src/http_conv.c @@ -63,6 +63,7 @@ static int sample_conv_http_date(const struct arg *args, struct sample *smp, voi struct buffer *temp; struct tm tm; int sec_frac = 0; + int frac_digits = 0; time_t curr_date; /* add offset */ @@ -72,11 +73,13 @@ static int sample_conv_http_date(const struct arg *args, struct sample *smp, voi /* report in milliseconds */ if (args[1].type == ARGT_SINT && args[1].data.sint == TIME_UNIT_MS) { sec_frac = smp->data.u.sint % 1000; + frac_digits = 3; smp->data.u.sint /= 1000; } /* report in microseconds */ else if (args[1].type == ARGT_SINT && args[1].data.sint == TIME_UNIT_US) { sec_frac = smp->data.u.sint % 1000000; + frac_digits = 6; smp->data.u.sint /= 1000000; } @@ -86,19 +89,14 @@ static int sample_conv_http_date(const struct arg *args, struct sample *smp, voi get_gmtime(curr_date, &tm); temp = get_trash_chunk(); - if (args[1].type == ARGT_SINT && args[1].data.sint != TIME_UNIT_S) { - temp->data = snprintf(temp->area, temp->size - temp->data, - "%s, %02d %s %04d %02d:%02d:%02d.%d GMT", - day[tm.tm_wday], tm.tm_mday, mon[tm.tm_mon], - 1900+tm.tm_year, - tm.tm_hour, tm.tm_min, tm.tm_sec, sec_frac); - } else { - temp->data = snprintf(temp->area, temp->size - temp->data, - "%s, %02d %s %04d %02d:%02d:%02d GMT", - day[tm.tm_wday], tm.tm_mday, mon[tm.tm_mon], - 1900+tm.tm_year, - tm.tm_hour, tm.tm_min, tm.tm_sec); - } + temp->data = snprintf(temp->area, temp->size - temp->data, + (frac_digits == 6) ? "%s, %02d %s %04d %02d:%02d:%02d.%06d GMT" : + (frac_digits == 3) ? "%s, %02d %s %04d %02d:%02d:%02d.%03d GMT" : + "%s, %02d %s %04d %02d:%02d:%02d GMT", + day[tm.tm_wday], tm.tm_mday, mon[tm.tm_mon], + 1900+tm.tm_year, + tm.tm_hour, tm.tm_min, tm.tm_sec, + sec_frac); smp->data.u.str = *temp; smp->data.type = SMP_T_STR;