Skip to content

Commit cc5851c

Browse files
pabloosabaterrgitster
authored andcommitted
cat-file: make remote-object-info allow-list dynamic
The static allow-list in expand_atom() is hardcoded to only allow "objectname" and "objectsize" for remote queries. This works because up to this point all servers will either support object-info with name and size or they do not support them at all, but we cannot expect that in a future different servers with different git versions to have the same object-info capabilities. Therefore, the allow_list needs to be dynamic depending on what the server advertises. The client will now: 1. Request the protocol option that the placeholder refers to (i.e. "size" when "%(objectsize)"). 2. Filters the request in fetch_object_info() dropping any option that the server does not advertise. 3. After the fetching, the options that haven't been dropped are the ones fetched and supported by the server, these supported options are mapped and remote_allowed_atoms is populated with the placeholders. 4. expand_atom() checks remote_allowed_atoms with the same behaviour as the static allow_list had. Move object_info_options out of get_remote_info so the caller which has data can select what options will be requested instead of requesting always size. Move batch_object_write() out so there will always be an output even if all the placeholders are not supported by the server (returns an empty line). Include "type" in the object_info_options so once the server supports it, the clients know already how to request it. Mentored-by: Karthik Nayak <karthik.188@gmail.com> Mentored-by: Chandra Pratap <chandrapratap3519@gmail.com> Signed-off-by: Pablo Sabater <pabloosabaterr@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent b2f69fa commit cc5851c

2 files changed

Lines changed: 84 additions & 33 deletions

File tree

builtin/cat-file.c

Lines changed: 64 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -341,13 +341,11 @@ struct expand_data {
341341
* Flags about when an object info is being fetched from remote.
342342
*/
343343
unsigned is_remote:1;
344-
};
345-
#define EXPAND_DATA_INIT { .mode = S_IFINVALID, .type = OBJ_BAD }
346344

347-
static const char *remote_object_info_atoms[] = {
348-
"objectname",
349-
"objectsize",
345+
struct string_list remote_allowed_atoms;
350346
};
347+
#define EXPAND_DATA_INIT { .mode = S_IFINVALID, .type = OBJ_BAD, \
348+
.remote_allowed_atoms = STRING_LIST_INIT_NODUP }
351349

352350
static int is_atom(const char *atom, const char *s, int slen)
353351
{
@@ -359,17 +357,11 @@ static int expand_atom(struct strbuf *sb, const char *atom, int len,
359357
struct expand_data *data)
360358
{
361359
if (data->is_remote) {
362-
size_t i, allowed_nr = ARRAY_SIZE(remote_object_info_atoms);
363-
for (i = 0; i < allowed_nr; i++)
364-
if (is_atom(remote_object_info_atoms[i], atom, len))
360+
size_t i;
361+
for (i = 0; i < data->remote_allowed_atoms.nr; i++)
362+
if (is_atom(data->remote_allowed_atoms.items[i].string, atom, len))
365363
break;
366-
367-
/*
368-
* On remote, skip unsupported atoms returning an empty sb,
369-
* honoring how for-each-ref handles known but inapplicable
370-
* atoms (e.g. %(tagger)).
371-
*/
372-
if (i == allowed_nr)
364+
if (i == data->remote_allowed_atoms.nr)
373365
return 1;
374366
}
375367

@@ -685,12 +677,12 @@ static int get_remote_info(struct batch_options *opt,
685677
int argc,
686678
const char **argv,
687679
struct object_info **remote_object_info,
688-
struct oid_array *object_info_oids)
680+
struct oid_array *object_info_oids,
681+
struct string_list *object_info_options)
689682
{
690683
int retval = 0;
691684
struct remote *remote = NULL;
692685
struct object_id oid;
693-
struct string_list object_info_options = STRING_LIST_INIT_NODUP;
694686
struct transport *gtransport;
695687

696688
/*
@@ -738,15 +730,12 @@ static int get_remote_info(struct batch_options *opt,
738730
CALLOC_ARRAY(*remote_object_info, object_info_oids->nr);
739731
gtransport->smart_options->object_info_oids = object_info_oids;
740732

741-
string_list_append(&object_info_options, "size");
742-
743-
if (object_info_options.nr > 0) {
744-
gtransport->smart_options->object_info_options = &object_info_options;
733+
if (object_info_options->nr > 0) {
734+
gtransport->smart_options->object_info_options = object_info_options;
745735
gtransport->smart_options->object_info_data = *remote_object_info;
746736
retval = transport_fetch_object_info(gtransport);
747737
}
748738
cleanup:
749-
string_list_clear(&object_info_options, 0);
750739
transport_disconnect(gtransport);
751740
return retval;
752741
}
@@ -832,6 +821,21 @@ static void parse_cmd_mailmap(struct batch_options *opt UNUSED,
832821
load_mailmap();
833822
}
834823

824+
struct protocol_placeholder_entry {
825+
const char *option;
826+
const char *atom;
827+
};
828+
829+
static const struct protocol_placeholder_entry remote_atom_map[] = {
830+
{"size", "objectsize"},
831+
{"type", "objecttype"},
832+
/*
833+
* Add new protocol options here. Even if the server doesn't support
834+
* them the allow_list will drop them if the server doesn't advertise
835+
* them.
836+
*/
837+
};
838+
835839
static void parse_cmd_remote_object_info(struct batch_options *opt,
836840
const char *line, struct strbuf *output,
837841
struct expand_data *data)
@@ -841,6 +845,7 @@ static void parse_cmd_remote_object_info(struct batch_options *opt,
841845
char *line_to_split;
842846
struct object_info *remote_object_info = NULL;
843847
struct oid_array object_info_oids = OID_ARRAY_INIT;
848+
struct string_list object_info_options = STRING_LIST_INIT_NODUP;
844849

845850
if (strlen(line) >= MAX_REMOTE_OBJ_INFO_LINE)
846851
die(_("remote-object-info command too long"));
@@ -853,32 +858,57 @@ static void parse_cmd_remote_object_info(struct batch_options *opt,
853858
die(_("remote-object-info supports at most %d objects"),
854859
MAX_ALLOWED_OBJ_LIMIT);
855860

861+
if (data->info.sizep)
862+
string_list_append(&object_info_options, "size");
863+
if (data->info.typep)
864+
string_list_append(&object_info_options, "type");
865+
856866
if (get_remote_info(opt, count, argv, &remote_object_info,
857-
&object_info_oids))
867+
&object_info_oids, &object_info_options))
858868
goto cleanup;
859869

870+
string_list_clear(&data->remote_allowed_atoms, 0);
871+
string_list_append(&data->remote_allowed_atoms, "objectname");
872+
for (size_t i = 0; i < ARRAY_SIZE(remote_atom_map); i++)
873+
if (unsorted_string_list_has_string(&object_info_options, remote_atom_map[i].option))
874+
string_list_append(&data->remote_allowed_atoms,
875+
remote_atom_map[i].atom);
876+
860877
data->skip_object_info = 1;
861878
for (size_t i = 0; i < object_info_oids.nr; i++) {
879+
int found = 0;
862880
data->oid = object_info_oids.oid[i];
881+
/*
882+
* When reaching here, it means remote-object-info can retrieve
883+
* information from server without downloading them.
884+
*/
863885
if (remote_object_info[i].sizep) {
864-
/*
865-
* When reaching here, it means remote-object-info can retrieve
866-
* information from server without downloading them.
867-
*/
868886
data->size = *remote_object_info[i].sizep;
869-
opt->batch_mode = BATCH_MODE_INFO;
870-
data->is_remote = 1;
871-
batch_object_write(argv[i + 1], output, opt, data, NULL, 0);
872-
data->is_remote = 0;
873-
} else {
874-
report_object_status(opt, oid_to_hex(&data->oid), &data->oid, "missing");
887+
found = 1;
875888
}
889+
890+
if (remote_object_info[i].typep) {
891+
data->type = *remote_object_info[i].typep;
892+
found = 1;
893+
}
894+
895+
if (!found && object_info_options.nr > 0) {
896+
report_object_status(opt, oid_to_hex(&data->oid),
897+
&data->oid, "missing");
898+
continue;
899+
}
900+
901+
opt->batch_mode = BATCH_MODE_INFO;
902+
data->is_remote = 1;
903+
batch_object_write(argv[i + 1], output, opt, data, NULL, 0);
904+
data->is_remote = 0;
876905
}
877906
data->skip_object_info = 0;
878907

879908
cleanup:
880909
for (size_t i = 0; i < object_info_oids.nr; i++)
881910
free_object_info_contents(&remote_object_info[i]);
911+
string_list_clear(&object_info_options, 0);
882912
free(line_to_split);
883913
free(argv);
884914
free(remote_object_info);
@@ -1194,6 +1224,7 @@ static int batch_objects(struct batch_options *opt)
11941224
cleanup:
11951225
strbuf_release(&input);
11961226
strbuf_release(&output);
1227+
string_list_clear(&data.remote_allowed_atoms, 0);
11971228
cfg->warn_on_object_refname_ambiguity = save_warning;
11981229
return retval;
11991230
}

fetch-object-info.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,26 @@ int fetch_object_info(const enum protocol_version version, struct object_info_ar
5555
case protocol_v2:
5656
if (!server_supports_v2("object-info"))
5757
die(_("object-info capability is not enabled on the server"));
58+
/*
59+
* When removing an element from the list it gets swapped by the
60+
* last element, iterate backwards to prevent elements skipping
61+
* evaluation.
62+
*
63+
* object_info_options->nr can be safely casted without overflow
64+
* beacuse the number of options is a small known number (the
65+
* supported placeholders which currently are size and type).
66+
*/
67+
for (int i = (int)args->object_info_options->nr - 1; i >= 0; i--)
68+
if (!server_supports_feature("object-info",
69+
args->object_info_options->items[i].string, 0))
70+
unsorted_string_list_delete_item(args->object_info_options, i, 0);
71+
/*
72+
* If no options are left after the filtering, avoid unnecessary
73+
* request to the server.
74+
*/
75+
if (!args->object_info_options->nr)
76+
return 0;
77+
5878
send_object_info_request(fd_out, args);
5979
break;
6080
case protocol_v1:

0 commit comments

Comments
 (0)