diff options
authorAndrzej Hunt <>2021-09-18 13:14:32 (GMT)
committerJunio C Hamano <>2021-09-23 21:55:50 (GMT)
commite0e1dbe961b45997718e9bc0a384a5a3df527a2f (patch)
parent225bc32a989d7a22fa6addafd4ce7dcd04675dbf (diff)
connect: also update offset for features without values
parse_feature_value() does not update offset if the feature being searched for does not specify a value. A loop that uses parse_feature_value() to find a feature which was specified without a value therefore might never exit (such loops will typically use next_server_feature_value() as opposed to parse_feature_value() itself). This usually isn't an issue: there's no point in using next_server_feature_value() to search for repeated instances of the same capability unless that capability typically specifies a value - but a broken server could send a response that omits the value for a feature even when we are expecting a value. Therefore we add an offset update calculation for the no-value case, which helps ensure that loops using next_server_feature_value() will always terminate. next_server_feature_value(), and the offset calculation, were first added in 2.28 in: 2c6a403d96 (connect: add function to parse multiple v1 capability values, 2020-05-25) Thanks to Peff for authoring the test. Co-authored-by: Jeff King <> Signed-off-by: Jeff King <> Signed-off-by: Andrzej Hunt <> Signed-off-by: Junio C Hamano <>
2 files changed, 15 insertions, 0 deletions
diff --git a/connect.c b/connect.c
index 70b1338..71e8757 100644
--- a/connect.c
+++ b/connect.c
@@ -555,6 +555,8 @@ const char *parse_feature_value(const char *feature_list, const char *feature, i
if (!*value || isspace(*value)) {
if (lenp)
*lenp = 0;
+ if (offset)
+ *offset = found + len - feature_list;
return value;
/* feature with a value (e.g., "agent=git/1.2.3") */
diff --git a/t/ b/t/
index 5c94194..0983c2b 100755
--- a/t/
+++ b/t/
@@ -32,4 +32,17 @@ test_expect_success 'extra delim packet in v2 fetch args' '
test_i18ngrep "expected flush after fetch arguments" err
+test_expect_success 'bogus symref in v0 capabilities' '
+ test_commit foo &&
+ oid=$(git rev-parse HEAD) &&
+ {
+ printf "%s HEAD\0symref object-format=%s\n" "$oid" "$GIT_DEFAULT_HASH" |
+ test-tool pkt-line pack-raw-stdin &&
+ printf "0000"
+ } >input &&
+ git ls-remote --upload-pack="cat input; read junk;:" . >actual &&
+ printf "%s\tHEAD\n" "$oid" >expect &&
+ test_cmp expect actual