Merge branch 'tc/bundle-uri-empty-fix'

The client-side parser of the server-advertised bundle-URI list has
been updated to drain the remaining response in order to avoid
protocol desynchronization when the server sends a misconfigured list.
Also, the server-side has been taught to omit empty configuration
values instead of sending invalid key-value lines.

* tc/bundle-uri-empty-fix:
  bundle-uri: stop sending invalid bundle configuration
  bundle-uri: drain remaining response on invalid bundle-uri lines
main
Junio C Hamano 2026-07-19 10:42:19 -07:00
commit f590fcd0dc
4 changed files with 70 additions and 5 deletions

View File

@ -946,8 +946,12 @@ static int config_to_packet_line(const char *key, const char *value,
{
struct packet_reader *writer = data;

if (starts_with(key, "bundle."))
packet_write_fmt(writer->fd, "%s=%s", key, value);
if (starts_with(key, "bundle.")) {
if (value && *value)
packet_write_fmt(writer->fd, "%s=%s", key, value);
else
warning(_("config '%s' has no value"), key);
}

return 0;
}

View File

@ -517,7 +517,7 @@ static void send_capabilities(int fd_out, struct packet_reader *reader)
int get_remote_bundle_uri(int fd_out, struct packet_reader *reader,
struct bundle_list *bundles, int stateless_rpc)
{
int line_nr = 1;
int line_nr = 1, err = 0;

/* Assert bundle-uri support */
ensure_server_supports_v2("bundle-uri");
@ -536,10 +536,19 @@ int get_remote_bundle_uri(int fd_out, struct packet_reader *reader,
const char *line = reader->line;
line_nr++;

/*
* Do not parse if an error was encountered, but
* continue draining the response so no stale data
* is left in the reader for subsequent protocol
* exchanges.
*/
if (err)
continue;

if (!bundle_uri_parse_line(bundles, line))
continue;

return error(_("error on bundle-uri response line %d: %s"),
err = error(_("error on bundle-uri response line %d: %s"),
line_nr, line);
}

@ -554,7 +563,7 @@ int get_remote_bundle_uri(int fd_out, struct packet_reader *reader,
check_stateless_delimiter(stateless_rpc, reader,
_("expected response end packet after ref listing"));

return 0;
return err;
}

struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,

View File

@ -214,3 +214,26 @@ test_expect_success "test bundle-uri with $BUNDLE_URI_PROTOCOL:// using protocol
>actual &&
test_cmp_config_output expect actual
'

test_expect_success "test bundle-uri with $BUNDLE_URI_PROTOCOL:// using protocol v2 with empty value" '
test_config -C "$BUNDLE_URI_PARENT" \
bundle.bundle1.uri "$BUNDLE_URI_BUNDLE_URI_ESCAPED-1.bdl" &&
test_config -C "$BUNDLE_URI_PARENT" \
bundle.bundle2.uri "" &&

# The empty bundle.bundle2.uri value is invalid configuration and the
# server must not advertise it to the client.
cat >expect <<-EOF &&
[bundle]
version = 1
mode = all
[bundle "bundle1"]
uri = $BUNDLE_URI_BUNDLE_URI_ESCAPED-1.bdl
EOF

test-tool bundle-uri \
ls-remote \
"$BUNDLE_URI_REPO_URI" \
>actual &&
test_cmp_config_output expect actual
'

View File

@ -1302,6 +1302,35 @@ test_expect_success 'bundles with newline in target path are rejected' '
test_path_is_missing escape
'

test_expect_success 'bundles advertised with missing URI' '
git clone --no-local --mirror clone-from \
"$HTTPD_DOCUMENT_ROOT_PATH/no-uri.git" &&
git -C "$HTTPD_DOCUMENT_ROOT_PATH/no-uri.git" config uploadpack.advertiseBundleURIs true &&
git -C "$HTTPD_DOCUMENT_ROOT_PATH/no-uri.git" config bundle.version 1 &&
git -C "$HTTPD_DOCUMENT_ROOT_PATH/no-uri.git" config bundle.mode all &&
git -C "$HTTPD_DOCUMENT_ROOT_PATH/no-uri.git" config bundle.bundle-1.creationToken 1 &&

git -c transfer.bundleURI=true clone \
"$HTTPD_URL/smart/no-uri.git" target-no-uri 2>err &&
test_grep "bundle ${SQ}bundle-1${SQ} has no uri" err &&
test_grep ! "expected packfile" err
'

test_expect_success 'bundles advertised with empty URI' '
git clone --no-local --mirror clone-from \
"$HTTPD_DOCUMENT_ROOT_PATH/empty-uri.git" &&
git -C "$HTTPD_DOCUMENT_ROOT_PATH/empty-uri.git" config uploadpack.advertiseBundleURIs true &&
git -C "$HTTPD_DOCUMENT_ROOT_PATH/empty-uri.git" config bundle.version 1 &&
git -C "$HTTPD_DOCUMENT_ROOT_PATH/empty-uri.git" config bundle.mode all &&
git -C "$HTTPD_DOCUMENT_ROOT_PATH/empty-uri.git" config bundle.bundle-1.uri "" &&
git -C "$HTTPD_DOCUMENT_ROOT_PATH/empty-uri.git" config bundle.bundle-1.creationToken 1 &&

git -c transfer.bundleURI=true clone \
"$HTTPD_URL/smart/empty-uri.git" target-empty-uri 2>err &&
test_grep "bundle ${SQ}bundle-1${SQ} has no uri" err &&
test_grep ! "expected packfile" err
'

# Do not add tests here unless they use the HTTP server, as they will
# not run unless the HTTP dependencies exist.