mirror of
https://github.com/git-for-windows/git.git
synced 2026-06-27 13:21:17 -05:00
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>
111 lines
3.6 KiB
C
111 lines
3.6 KiB
C
#include "git-compat-util.h"
|
|
#include "gettext.h"
|
|
#include "hex.h"
|
|
#include "pkt-line.h"
|
|
#include "connect.h"
|
|
#include "oid-array.h"
|
|
#include "odb.h"
|
|
#include "fetch-object-info.h"
|
|
#include "string-list.h"
|
|
|
|
/* Sends git-cat-file object-info command and its arguments into the request buffer. */
|
|
static void send_object_info_request(const int fd_out, struct object_info_args *args)
|
|
{
|
|
struct strbuf req_buf = STRBUF_INIT;
|
|
|
|
write_command_and_capabilities(&req_buf, "object-info", args->server_options);
|
|
|
|
if (unsorted_string_list_has_string(args->object_info_options, "size"))
|
|
packet_buf_write(&req_buf, "size");
|
|
|
|
if (args->oids)
|
|
for (size_t i = 0; i < args->oids->nr; i++)
|
|
packet_buf_write(&req_buf, "oid %s", oid_to_hex(&args->oids->oid[i]));
|
|
|
|
packet_buf_flush(&req_buf);
|
|
if (write_in_full(fd_out, req_buf.buf, req_buf.len) < 0)
|
|
die_errno(_("unable to write request to remote"));
|
|
|
|
strbuf_release(&req_buf);
|
|
}
|
|
|
|
int fetch_object_info(const enum protocol_version version, struct object_info_args *args,
|
|
struct packet_reader *reader, struct object_info *object_info_data,
|
|
const int stateless_rpc, const int fd_out)
|
|
{
|
|
int size_index = -1;
|
|
|
|
switch (version) {
|
|
case protocol_v2:
|
|
if (!server_supports_v2("object-info"))
|
|
die(_("object-info capability is not enabled on the server"));
|
|
/*
|
|
* When removing an element from the list it gets swapped by the
|
|
* last element, iterate backwards to prevent elements skipping
|
|
* evaluation.
|
|
*
|
|
* object_info_options->nr can be safely casted without overflow
|
|
* beacuse the number of options is a small known number (the
|
|
* supported placeholders which currently are size and type).
|
|
*/
|
|
for (int i = (int)args->object_info_options->nr - 1; i >= 0; i--)
|
|
if (!server_supports_feature("object-info",
|
|
args->object_info_options->items[i].string, 0))
|
|
unsorted_string_list_delete_item(args->object_info_options, i, 0);
|
|
/*
|
|
* If no options are left after the filtering, avoid unnecessary
|
|
* request to the server.
|
|
*/
|
|
if (!args->object_info_options->nr)
|
|
return 0;
|
|
|
|
send_object_info_request(fd_out, args);
|
|
break;
|
|
case protocol_v1:
|
|
case protocol_v0:
|
|
die(_("unsupported protocol version. expected v2"));
|
|
case protocol_unknown_version:
|
|
BUG("unknown protocol version");
|
|
}
|
|
|
|
for (size_t i = 0; i < args->object_info_options->nr; i++) {
|
|
if (packet_reader_read(reader) != PACKET_READ_NORMAL) {
|
|
check_stateless_delimiter(stateless_rpc, reader,
|
|
"stateless delimiter expected");
|
|
return -1;
|
|
}
|
|
|
|
if (!string_list_has_string(args->object_info_options, reader->line))
|
|
return -1;
|
|
|
|
if (!strcmp(reader->line, "size")) {
|
|
size_index = i;
|
|
for (size_t j = 0; j < args->oids->nr; j++)
|
|
object_info_data[j].sizep = xcalloc(1, sizeof(*object_info_data[j].sizep));
|
|
}
|
|
}
|
|
|
|
for (size_t i = 0; packet_reader_read(reader) == PACKET_READ_NORMAL && i < args->oids->nr; i++) {
|
|
struct string_list object_info_values = STRING_LIST_INIT_DUP;
|
|
|
|
string_list_split(&object_info_values, reader->line, " ", -1);
|
|
if (0 <= size_index) {
|
|
if (!strcmp(object_info_values.items[1 + size_index].string, "")) {
|
|
FREE_AND_NULL(object_info_data[i].sizep);
|
|
string_list_clear(&object_info_values, 0);
|
|
continue;
|
|
}
|
|
if (strtoul_szt(object_info_values.items[1 + size_index].string,
|
|
10, object_info_data[i].sizep))
|
|
die("object-info: ref %s has invalid size %s",
|
|
object_info_values.items[0].string,
|
|
object_info_values.items[1 + size_index].string);
|
|
}
|
|
|
|
string_list_clear(&object_info_values, 0);
|
|
}
|
|
check_stateless_delimiter(stateless_rpc, reader, "stateless delimiter expected");
|
|
|
|
return 0;
|
|
}
|