remote-curl: fix parsing of detached SHA256 heads

The dumb HTTP transport tries to read the remote HEAD reference by
downloading the "HEAD" file and then parsing it via `http_fetch_ref()`.
This function will either parse the file as an object ID in case it is
exactly `the_hash_algo->hexsz` long, or otherwise it will check whether
the reference starts with "ref :" and parse it as a symbolic ref.

This is broken when parsing detached HEADs of a remote SHA256 repository
because we never update `the_hash_algo` to the discovered remote object
hash. Consequently, `the_hash_algo` will always be the fallback SHA1
hash algorithm, which will cause us to fail parsing HEAD altogteher when
it contains a SHA256 object ID.

Fix this issue by setting up `the_hash_algo` via `repo_set_hash_algo()`.
While at it, let's make the expected SHA1 fallback explicit in our code,
which also addresses an upcoming issue where we are going to remove the
SHA1 fallback for `the_hash_algo`.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Patrick Steinhardt
2024-05-07 06:53:10 +02:00
committed by Junio C Hamano
parent 813f17fd6b
commit bd455cec37
2 changed files with 33 additions and 1 deletions

View File

@@ -266,12 +266,23 @@ static struct ref *parse_git_refs(struct discovery *heads, int for_push)
return list;
}
/*
* Try to detect the hash algorithm used by the remote repository when using
* the dumb HTTP transport. As dumb transports cannot tell us the object hash
* directly have to derive it from the advertised ref lengths.
*/
static const struct git_hash_algo *detect_hash_algo(struct discovery *heads)
{
const char *p = memchr(heads->buf, '\t', heads->len);
int algo;
/*
* In case the remote has no refs we have no way to reliably determine
* the object hash used by that repository. In that case we simply fall
* back to SHA1, which may or may not be correct.
*/
if (!p)
return the_hash_algo;
return &hash_algos[GIT_HASH_SHA1];
algo = hash_algo_by_length((p - heads->buf) / 2);
if (algo == GIT_HASH_UNKNOWN)
@@ -295,6 +306,12 @@ static struct ref *parse_info_refs(struct discovery *heads)
"is this a git repository?",
transport_anonymize_url(url.buf));
/*
* Set the repository's hash algo to whatever we have just detected.
* This ensures that we can correctly parse the remote references.
*/
repo_set_hash_algo(the_repository, hash_algo_by_ptr(options.hash_algo));
data = heads->buf;
start = NULL;
mid = data;