]> git.kaiwu.me - haproxy.git/commitdiff
BUG/MINOR: http: do not consume the delimiter of a truncated q-factor
authorWilly Tarreau <w@1wt.eu>
Wed, 30 Sep 2026 06:50:07 +0000 (08:50 +0200)
committerWilly Tarreau <w@1wt.eu>
Wed, 30 Sep 2026 14:11:24 +0000 (16:11 +0200)
http_parse_qvalue() increments its cursor before checking that the
character it just read is the '.' which must follow the integer part:

if (*qvalue++ != '.')
goto out;

so when the q-factor has no decimal part, as in "q=0", the cursor
reported through <end> points one byte past the character which
terminated it, that is past the ',' separating it from the next value.

sample_conv_q_preferred(), which implements the "language" converter,
resumes its scan at that position and then looks for the next ',' from
there, so it silently skips everything up to the following separator.
With "accept-language: fr;q=0, en;q=0.1" the "en" value is never
examined and the converter reports no match at all, while "q=0.0"
works as expected.

The other caller, the accept-encoding parsing of the compression
filter, passes NULL as <end> and is unaffected. Note that this bug
has been there since the introduction of the function in 1.5-dev23
via commit 0e9b1b4d1f ("MEDIUM: compression: consider the "q="
attribute in Accept-Encoding").

This should be backported to all branches.

src/http.c

index c29f77572f9cb760d41def356daf82cb33f955b8..9cc202475b29a6247bbb923afbfc90caa17e2198 100644 (file)
@@ -1266,8 +1266,9 @@ int http_parse_qvalue(const char *qvalue, const char **end)
                goto out;
        q = (*qvalue++ - '0') * 1000;
 
-       if (*qvalue++ != '.')
+       if (*qvalue != '.')
                goto out;
+       qvalue++;
 
        if (!isdigit((unsigned char)*qvalue))
                goto out;