bundle-uri: drain remaining response on invalid bundle-uri lines

On clone, when the client sends the `bundle-uri` command, the server might respond with invalid data. For example if it sends information about a bundle where the 'uri' is empty, it produces the following error: Cloning into 'foo'... error: bundle-uri: line has empty key or value error: error on bundle-uri response line 4: bundle.bundle-1.uri= error: could not retrieve server-advertised bundle-uri list This error is bubbled up to `transport_get_remote_bundle_uri()`, which is called by `cmd_clone()` in builtin/clone.c. Over here, the return value is ignored, so clone continues. Despite this, it still dies with this error: fatal: expected 'packfile' This happens because `get_remote_bundle_uri()` exited early, leaving some unprocessed packet data behind in the read buffer. This is misleading to the user, because it suggests a problem with the packfile exchange, when in reality it's caused by a misconfigured bundle-URI on the server-side. Fix this by continuing to read packets when an error was encountered, but without processing the remaining lines. This drains the protocol stream so no stale data is left behind and the caller can use it if they like. With this, clone now continues successfully if invalid bundle-URI data was sent by the server. This is intentional, because since the inception of `transport_get_remote_bundle_uri()` in 0cfde740f0 (clone: request the 'bundle-uri' command when available, 2022-12-22) the return value of that function is ignored in `cmd_clone()` so the clone can continue without bundles. Signed-off-by: Toon Claes <toon@iotcl.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Toon Claes committed Jul 8, 2026 at 17:03 UTC 8585c50b05c46f0b5d604a404273705a724b19f5
2 files changed +41 -3
connect.c
+12 -3
@@ -517,7 +517,7 @@ static void send_capabilities(int fd_out, struct packet_reader *reader)
517 int get_remote_bundle_uri(int fd_out, struct packet_reader *reader,
518 struct bundle_list *bundles, int stateless_rpc)
519 {
520 - int line_nr = 1;
520 + int line_nr = 1, err = 0;
521
522 /* Assert bundle-uri support */
523 ensure_server_supports_v2("bundle-uri");
@@ -536,10 +536,19 @@ int get_remote_bundle_uri(int fd_out, struct packet_reader *reader,
536 const char *line = reader->line;
537 line_nr++;
538
539 + /*
540 + * Do not parse if an error was encountered, but
541 + * continue draining the response so no stale data
542 + * is left in the reader for subsequent protocol
543 + * exchanges.
544 + */
545 + if (err)
546 + continue;
547 +
548 if (!bundle_uri_parse_line(bundles, line))
549 continue;
550
542 - return error(_("error on bundle-uri response line %d: %s"),
551 + err = error(_("error on bundle-uri response line %d: %s"),
552 line_nr, line);
553 }
554
@@ -554,7 +563,7 @@ int get_remote_bundle_uri(int fd_out, struct packet_reader *reader,
563 check_stateless_delimiter(stateless_rpc, reader,
564 _("expected response end packet after ref listing"));
565
557 - return 0;
566 + return err;
567 }
568
569 struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
t/t5558-clone-bundle-uri.sh
+29
@@ -1302,6 +1302,35 @@ test_expect_success 'bundles with newline in target path are rejected' '
1302 test_path_is_missing escape
1303 '
1304
1305 +test_expect_success 'bundles advertised with missing URI' '
1306 + git clone --no-local --mirror clone-from \
1307 + "$HTTPD_DOCUMENT_ROOT_PATH/no-uri.git" &&
1308 + git -C "$HTTPD_DOCUMENT_ROOT_PATH/no-uri.git" config uploadpack.advertiseBundleURIs true &&
1309 + git -C "$HTTPD_DOCUMENT_ROOT_PATH/no-uri.git" config bundle.version 1 &&
1310 + git -C "$HTTPD_DOCUMENT_ROOT_PATH/no-uri.git" config bundle.mode all &&
1311 + git -C "$HTTPD_DOCUMENT_ROOT_PATH/no-uri.git" config bundle.bundle-1.creationToken 1 &&
1312 +
1313 + git -c transfer.bundleURI=true clone \
1314 + "$HTTPD_URL/smart/no-uri.git" target-no-uri 2>err &&
1315 + test_grep "bundle ${SQ}bundle-1${SQ} has no uri" err &&
1316 + test_grep ! "expected packfile" err
1317 +'
1318 +
1319 +test_expect_success 'bundles advertised with empty URI' '
1320 + git clone --no-local --mirror clone-from \
1321 + "$HTTPD_DOCUMENT_ROOT_PATH/empty-uri.git" &&
1322 + git -C "$HTTPD_DOCUMENT_ROOT_PATH/empty-uri.git" config uploadpack.advertiseBundleURIs true &&
1323 + git -C "$HTTPD_DOCUMENT_ROOT_PATH/empty-uri.git" config bundle.version 1 &&
1324 + git -C "$HTTPD_DOCUMENT_ROOT_PATH/empty-uri.git" config bundle.mode all &&
1325 + git -C "$HTTPD_DOCUMENT_ROOT_PATH/empty-uri.git" config bundle.bundle-1.uri "" &&
1326 + git -C "$HTTPD_DOCUMENT_ROOT_PATH/empty-uri.git" config bundle.bundle-1.creationToken 1 &&
1327 +
1328 + git -c transfer.bundleURI=true clone \
1329 + "$HTTPD_URL/smart/empty-uri.git" target-empty-uri 2>err &&
1330 + test_grep "bundle ${SQ}bundle-1${SQ} has no uri" err &&
1331 + test_grep ! "expected packfile" err
1332 +'
1333 +
1334 # Do not add tests here unless they use the HTTP server, as they will
1335 # not run unless the HTTP dependencies exist.
1336