serve: provide "receive" function for object-format capability

We get any "object-format" specified by the client by searching for it in the collected list of capabilities the client sent. We can instead just handle it as soon as they send it. This is slightly more efficient, and gets us one step closer to dropping that collected list. Note that we do still have to do our final hash check after receiving all capabilities (because they might not have sent an object-format line at all, and we still have to check that the default matches our repository algorithm). Since the check_algorithm() function would now be down to a single if() statement, I've just inlined it in its only caller. There should be no change of behavior here, except for two broken-protocol cases: - if the client sends multiple conflicting object-format capabilities (which they should not), we'll now choose the last one rather than the first. We could also detect and complain about the duplicates quite easily now, which we could not before, but I didn't do so here. - if the client sends a bogus "object-format" with no equals sign, we'll now say so, rather than "unknown object format: ''" Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Sep 14, 2021 at 19:51 UTC c7d3aabd2793ab5772627ff6da95f8f7c28258ab
1 file changed +17 -17
serve.c
+17 -17
@@ -10,6 +10,7 @@
10 #include "upload-pack.h"
11
12 static int advertise_sid = -1;
13 +static int client_hash_algo = GIT_HASH_SHA1;
14
15 static int always_advertise(struct repository *r,
16 struct strbuf *value)
@@ -33,6 +34,17 @@ static int object_format_advertise(struct repository *r,
34 return 1;
35 }
36
37 +static void object_format_receive(struct repository *r,
38 + const char *algo_name)
39 +{
40 + if (!algo_name)
41 + die("object-format capability requires an argument");
42 +
43 + client_hash_algo = hash_algo_by_name(algo_name);
44 + if (client_hash_algo == GIT_HASH_UNKNOWN)
45 + die("unknown object format '%s'", algo_name);
46 +}
47 +
48 static int session_id_advertise(struct repository *r, struct strbuf *value)
49 {
50 if (advertise_sid == -1 &&
@@ -104,6 +116,7 @@ static struct protocol_capability capabilities[] = {
116 {
117 .name = "object-format",
118 .advertise = object_format_advertise,
119 + .receive = object_format_receive,
120 },
121 {
122 .name = "session-id",
@@ -228,22 +241,6 @@ static int has_capability(const struct strvec *keys, const char *capability,
241 return 0;
242 }
243
231 -static void check_algorithm(struct repository *r, struct strvec *keys)
232 -{
233 - int client = GIT_HASH_SHA1, server = hash_algo_by_ptr(r->hash_algo);
234 - const char *algo_name;
235 -
236 - if (has_capability(keys, "object-format", &algo_name)) {
237 - client = hash_algo_by_name(algo_name);
238 - if (client == GIT_HASH_UNKNOWN)
239 - die("unknown object format '%s'", algo_name);
240 - }
241 -
242 - if (client != server)
243 - die("mismatched object format: server %s; client %s\n",
244 - r->hash_algo->name, hash_algos[client].name);
245 -}
246 -
244 enum request_state {
245 PROCESS_REQUEST_KEYS,
246 PROCESS_REQUEST_DONE,
@@ -317,7 +314,10 @@ static int process_request(void)
314 if (!command)
315 die("no command requested");
316
320 - check_algorithm(the_repository, &keys);
317 + if (client_hash_algo != hash_algo_by_ptr(the_repository->hash_algo))
318 + die("mismatched object format: server %s; client %s\n",
319 + the_repository->hash_algo->name,
320 + hash_algos[client_hash_algo].name);
321
322 if (has_capability(&keys, "session-id", &client_sid))
323 trace2_data_string("transfer", NULL, "client-sid", client_sid);