]> git.kaiwu.me - haproxy.git/commitdiff
BUG/MINOR: sample: zero-pad the fractional part emitted by http_date()
authorWilly Tarreau <w@1wt.eu>
Wed, 30 Sep 2026 08:49:48 +0000 (10:49 +0200)
committerWilly Tarreau <w@1wt.eu>
Wed, 30 Sep 2026 14:11:24 +0000 (16:11 +0200)
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.

src/http_conv.c

index 02c3a79b14b098d2e6d2c3a4d2e2d778f10f0e17..b97ce6d6eeb6ccd576234326dcefe6eeb08ce7db 100644 (file)
@@ -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;