Merge branch 'jk/upload-pack-bounded-resources'
Various parts of upload-pack has been updated to bound the resource consumption relative to the size of the repository to protect from abusive clients. * jk/upload-pack-bounded-resources: upload-pack: free tree buffers after parsing upload-pack: use PARSE_OBJECT_SKIP_HASH_CHECK in more places upload-pack: always turn off save_commit_buffer upload-pack: disallow object-info capability by default upload-pack: accept only a single packfile-uri line upload-pack: use a strmap for want-ref lines upload-pack: use oidset for deepen_not list upload-pack: switch deepen-not list to an oid_array upload-pack: drop separate v2 "haves" array
This commit is contained in:
@ -121,3 +121,7 @@ transfer.bundleURI::
|
|||||||
information from the remote server (if advertised) and download
|
information from the remote server (if advertised) and download
|
||||||
bundles before continuing the clone through the Git protocol.
|
bundles before continuing the clone through the Git protocol.
|
||||||
Defaults to `false`.
|
Defaults to `false`.
|
||||||
|
|
||||||
|
transfer.advertiseObjectInfo::
|
||||||
|
When `true`, the `object-info` capability is advertised by
|
||||||
|
servers. Defaults to false.
|
||||||
|
@ -346,7 +346,8 @@ the 'wanted-refs' section in the server's response as explained below.
|
|||||||
want-ref <ref>
|
want-ref <ref>
|
||||||
Indicates to the server that the client wants to retrieve a
|
Indicates to the server that the client wants to retrieve a
|
||||||
particular ref, where <ref> is the full name of a ref on the
|
particular ref, where <ref> is the full name of a ref on the
|
||||||
server.
|
server. It is a protocol error to send want-ref for the
|
||||||
|
same ref more than once.
|
||||||
|
|
||||||
If the 'sideband-all' feature is advertised, the following argument can be
|
If the 'sideband-all' feature is advertised, the following argument can be
|
||||||
included in the client's request:
|
included in the client's request:
|
||||||
@ -361,7 +362,8 @@ included in the client's request:
|
|||||||
If the 'packfile-uris' feature is advertised, the following argument
|
If the 'packfile-uris' feature is advertised, the following argument
|
||||||
can be included in the client's request as well as the potential
|
can be included in the client's request as well as the potential
|
||||||
addition of the 'packfile-uris' section in the server's response as
|
addition of the 'packfile-uris' section in the server's response as
|
||||||
explained below.
|
explained below. Note that at most one `packfile-uris` line can be sent
|
||||||
|
to the server.
|
||||||
|
|
||||||
packfile-uris <comma-separated-list-of-protocols>
|
packfile-uris <comma-separated-list-of-protocols>
|
||||||
Indicates to the server that the client is willing to receive
|
Indicates to the server that the client is willing to receive
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "replace-object.h"
|
#include "replace-object.h"
|
||||||
#include "upload-pack.h"
|
#include "upload-pack.h"
|
||||||
#include "serve.h"
|
#include "serve.h"
|
||||||
|
#include "commit.h"
|
||||||
|
|
||||||
static const char * const upload_pack_usage[] = {
|
static const char * const upload_pack_usage[] = {
|
||||||
N_("git-upload-pack [--[no-]strict] [--timeout=<n>] [--stateless-rpc]\n"
|
N_("git-upload-pack [--[no-]strict] [--timeout=<n>] [--stateless-rpc]\n"
|
||||||
@ -37,6 +38,7 @@ int cmd_upload_pack(int argc, const char **argv, const char *prefix)
|
|||||||
|
|
||||||
packet_trace_identity("upload-pack");
|
packet_trace_identity("upload-pack");
|
||||||
disable_replace_refs();
|
disable_replace_refs();
|
||||||
|
save_commit_buffer = 0;
|
||||||
|
|
||||||
argc = parse_options(argc, argv, prefix, options, upload_pack_usage, 0);
|
argc = parse_options(argc, argv, prefix, options, upload_pack_usage, 0);
|
||||||
|
|
||||||
|
14
object.c
14
object.c
@ -271,6 +271,7 @@ struct object *parse_object_with_flags(struct repository *r,
|
|||||||
enum parse_object_flags flags)
|
enum parse_object_flags flags)
|
||||||
{
|
{
|
||||||
int skip_hash = !!(flags & PARSE_OBJECT_SKIP_HASH_CHECK);
|
int skip_hash = !!(flags & PARSE_OBJECT_SKIP_HASH_CHECK);
|
||||||
|
int discard_tree = !!(flags & PARSE_OBJECT_DISCARD_TREE);
|
||||||
unsigned long size;
|
unsigned long size;
|
||||||
enum object_type type;
|
enum object_type type;
|
||||||
int eaten;
|
int eaten;
|
||||||
@ -298,6 +299,17 @@ struct object *parse_object_with_flags(struct repository *r,
|
|||||||
return lookup_object(r, oid);
|
return lookup_object(r, oid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the caller does not care about the tree buffer and does not
|
||||||
|
* care about checking the hash, we can simply verify that we
|
||||||
|
* have the on-disk object with the correct type.
|
||||||
|
*/
|
||||||
|
if (skip_hash && discard_tree &&
|
||||||
|
(!obj || obj->type == OBJ_TREE) &&
|
||||||
|
oid_object_info(r, oid, NULL) == OBJ_TREE) {
|
||||||
|
return &lookup_tree(r, oid)->object;
|
||||||
|
}
|
||||||
|
|
||||||
buffer = repo_read_object_file(r, oid, &type, &size);
|
buffer = repo_read_object_file(r, oid, &type, &size);
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
if (!skip_hash &&
|
if (!skip_hash &&
|
||||||
@ -311,6 +323,8 @@ struct object *parse_object_with_flags(struct repository *r,
|
|||||||
buffer, &eaten);
|
buffer, &eaten);
|
||||||
if (!eaten)
|
if (!eaten)
|
||||||
free(buffer);
|
free(buffer);
|
||||||
|
if (discard_tree && type == OBJ_TREE)
|
||||||
|
free_tree_buffer((struct tree *)obj);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
1
object.h
1
object.h
@ -197,6 +197,7 @@ void *object_as_type(struct object *obj, enum object_type type, int quiet);
|
|||||||
*/
|
*/
|
||||||
enum parse_object_flags {
|
enum parse_object_flags {
|
||||||
PARSE_OBJECT_SKIP_HASH_CHECK = 1 << 0,
|
PARSE_OBJECT_SKIP_HASH_CHECK = 1 << 0,
|
||||||
|
PARSE_OBJECT_DISCARD_TREE = 1 << 1,
|
||||||
};
|
};
|
||||||
struct object *parse_object(struct repository *r, const struct object_id *oid);
|
struct object *parse_object(struct repository *r, const struct object_id *oid);
|
||||||
struct object *parse_object_with_flags(struct repository *r,
|
struct object *parse_object_with_flags(struct repository *r,
|
||||||
|
@ -381,7 +381,8 @@ static struct object *get_reference(struct rev_info *revs, const char *name,
|
|||||||
|
|
||||||
object = parse_object_with_flags(revs->repo, oid,
|
object = parse_object_with_flags(revs->repo, oid,
|
||||||
revs->verify_objects ? 0 :
|
revs->verify_objects ? 0 :
|
||||||
PARSE_OBJECT_SKIP_HASH_CHECK);
|
PARSE_OBJECT_SKIP_HASH_CHECK |
|
||||||
|
PARSE_OBJECT_DISCARD_TREE);
|
||||||
|
|
||||||
if (!object) {
|
if (!object) {
|
||||||
if (revs->ignore_missing)
|
if (revs->ignore_missing)
|
||||||
|
14
serve.c
14
serve.c
@ -12,6 +12,7 @@
|
|||||||
#include "trace2.h"
|
#include "trace2.h"
|
||||||
|
|
||||||
static int advertise_sid = -1;
|
static int advertise_sid = -1;
|
||||||
|
static int advertise_object_info = -1;
|
||||||
static int client_hash_algo = GIT_HASH_SHA1;
|
static int client_hash_algo = GIT_HASH_SHA1;
|
||||||
|
|
||||||
static int always_advertise(struct repository *r UNUSED,
|
static int always_advertise(struct repository *r UNUSED,
|
||||||
@ -67,6 +68,17 @@ static void session_id_receive(struct repository *r UNUSED,
|
|||||||
trace2_data_string("transfer", NULL, "client-sid", client_sid);
|
trace2_data_string("transfer", NULL, "client-sid", client_sid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int object_info_advertise(struct repository *r, struct strbuf *value UNUSED)
|
||||||
|
{
|
||||||
|
if (advertise_object_info == -1 &&
|
||||||
|
repo_config_get_bool(r, "transfer.advertiseobjectinfo",
|
||||||
|
&advertise_object_info)) {
|
||||||
|
/* disabled by default */
|
||||||
|
advertise_object_info = 0;
|
||||||
|
}
|
||||||
|
return advertise_object_info;
|
||||||
|
}
|
||||||
|
|
||||||
struct protocol_capability {
|
struct protocol_capability {
|
||||||
/*
|
/*
|
||||||
* The name of the capability. The server uses this name when
|
* The name of the capability. The server uses this name when
|
||||||
@ -135,7 +147,7 @@ static struct protocol_capability capabilities[] = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "object-info",
|
.name = "object-info",
|
||||||
.advertise = always_advertise,
|
.advertise = object_info_advertise,
|
||||||
.command = cap_object_info,
|
.command = cap_object_info,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -131,7 +131,6 @@ test_expect_success 'git upload-pack --advertise-refs: v2' '
|
|||||||
fetch=shallow wait-for-done
|
fetch=shallow wait-for-done
|
||||||
server-option
|
server-option
|
||||||
object-format=$(test_oid algo)
|
object-format=$(test_oid algo)
|
||||||
object-info
|
|
||||||
0000
|
0000
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
@ -20,7 +20,6 @@ test_expect_success 'test capability advertisement' '
|
|||||||
fetch=shallow wait-for-done
|
fetch=shallow wait-for-done
|
||||||
server-option
|
server-option
|
||||||
object-format=$(test_oid algo)
|
object-format=$(test_oid algo)
|
||||||
object-info
|
|
||||||
EOF
|
EOF
|
||||||
cat >expect.trailer <<-EOF &&
|
cat >expect.trailer <<-EOF &&
|
||||||
0000
|
0000
|
||||||
@ -323,6 +322,8 @@ test_expect_success 'unexpected lines are not allowed in fetch request' '
|
|||||||
# Test the basics of object-info
|
# Test the basics of object-info
|
||||||
#
|
#
|
||||||
test_expect_success 'basics of object-info' '
|
test_expect_success 'basics of object-info' '
|
||||||
|
test_config transfer.advertiseObjectInfo true &&
|
||||||
|
|
||||||
test-tool pkt-line pack >in <<-EOF &&
|
test-tool pkt-line pack >in <<-EOF &&
|
||||||
command=object-info
|
command=object-info
|
||||||
object-format=$(test_oid algo)
|
object-format=$(test_oid algo)
|
||||||
@ -380,4 +381,25 @@ test_expect_success 'basics of bundle-uri: dies if not enabled' '
|
|||||||
test_must_be_empty out
|
test_must_be_empty out
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'object-info missing from capabilities when disabled' '
|
||||||
|
test_config transfer.advertiseObjectInfo false &&
|
||||||
|
|
||||||
|
GIT_TEST_SIDEBAND_ALL=0 test-tool serve-v2 \
|
||||||
|
--advertise-capabilities >out &&
|
||||||
|
test-tool pkt-line unpack <out >actual &&
|
||||||
|
|
||||||
|
! grep object.info actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'object-info commands rejected when disabled' '
|
||||||
|
test_config transfer.advertiseObjectInfo false &&
|
||||||
|
|
||||||
|
test-tool pkt-line pack >in <<-EOF &&
|
||||||
|
command=object-info
|
||||||
|
EOF
|
||||||
|
|
||||||
|
test_must_fail test-tool serve-v2 --stateless-rpc <in 2>err &&
|
||||||
|
grep invalid.command err
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
117
upload-pack.c
117
upload-pack.c
@ -28,6 +28,7 @@
|
|||||||
#include "shallow.h"
|
#include "shallow.h"
|
||||||
#include "write-or-die.h"
|
#include "write-or-die.h"
|
||||||
#include "json-writer.h"
|
#include "json-writer.h"
|
||||||
|
#include "strmap.h"
|
||||||
|
|
||||||
/* Remember to update object flag allocation in object.h */
|
/* Remember to update object flag allocation in object.h */
|
||||||
#define THEY_HAVE (1u << 11)
|
#define THEY_HAVE (1u << 11)
|
||||||
@ -61,12 +62,11 @@ struct upload_pack_data {
|
|||||||
struct string_list symref; /* v0 only */
|
struct string_list symref; /* v0 only */
|
||||||
struct object_array want_obj;
|
struct object_array want_obj;
|
||||||
struct object_array have_obj;
|
struct object_array have_obj;
|
||||||
struct oid_array haves; /* v2 only */
|
struct strmap wanted_refs; /* v2 only */
|
||||||
struct string_list wanted_refs; /* v2 only */
|
|
||||||
struct strvec hidden_refs;
|
struct strvec hidden_refs;
|
||||||
|
|
||||||
struct object_array shallows;
|
struct object_array shallows;
|
||||||
struct string_list deepen_not;
|
struct oidset deepen_not;
|
||||||
struct object_array extra_edge_obj;
|
struct object_array extra_edge_obj;
|
||||||
int depth;
|
int depth;
|
||||||
timestamp_t deepen_since;
|
timestamp_t deepen_since;
|
||||||
@ -113,6 +113,7 @@ struct upload_pack_data {
|
|||||||
unsigned done : 1; /* v2 only */
|
unsigned done : 1; /* v2 only */
|
||||||
unsigned allow_ref_in_want : 1; /* v2 only */
|
unsigned allow_ref_in_want : 1; /* v2 only */
|
||||||
unsigned allow_sideband_all : 1; /* v2 only */
|
unsigned allow_sideband_all : 1; /* v2 only */
|
||||||
|
unsigned seen_haves : 1; /* v2 only */
|
||||||
unsigned advertise_sid : 1;
|
unsigned advertise_sid : 1;
|
||||||
unsigned sent_capabilities : 1;
|
unsigned sent_capabilities : 1;
|
||||||
};
|
};
|
||||||
@ -120,13 +121,12 @@ struct upload_pack_data {
|
|||||||
static void upload_pack_data_init(struct upload_pack_data *data)
|
static void upload_pack_data_init(struct upload_pack_data *data)
|
||||||
{
|
{
|
||||||
struct string_list symref = STRING_LIST_INIT_DUP;
|
struct string_list symref = STRING_LIST_INIT_DUP;
|
||||||
struct string_list wanted_refs = STRING_LIST_INIT_DUP;
|
struct strmap wanted_refs = STRMAP_INIT;
|
||||||
struct strvec hidden_refs = STRVEC_INIT;
|
struct strvec hidden_refs = STRVEC_INIT;
|
||||||
struct object_array want_obj = OBJECT_ARRAY_INIT;
|
struct object_array want_obj = OBJECT_ARRAY_INIT;
|
||||||
struct object_array have_obj = OBJECT_ARRAY_INIT;
|
struct object_array have_obj = OBJECT_ARRAY_INIT;
|
||||||
struct oid_array haves = OID_ARRAY_INIT;
|
|
||||||
struct object_array shallows = OBJECT_ARRAY_INIT;
|
struct object_array shallows = OBJECT_ARRAY_INIT;
|
||||||
struct string_list deepen_not = STRING_LIST_INIT_DUP;
|
struct oidset deepen_not = OID_ARRAY_INIT;
|
||||||
struct string_list uri_protocols = STRING_LIST_INIT_DUP;
|
struct string_list uri_protocols = STRING_LIST_INIT_DUP;
|
||||||
struct object_array extra_edge_obj = OBJECT_ARRAY_INIT;
|
struct object_array extra_edge_obj = OBJECT_ARRAY_INIT;
|
||||||
struct string_list allowed_filters = STRING_LIST_INIT_DUP;
|
struct string_list allowed_filters = STRING_LIST_INIT_DUP;
|
||||||
@ -137,7 +137,6 @@ static void upload_pack_data_init(struct upload_pack_data *data)
|
|||||||
data->hidden_refs = hidden_refs;
|
data->hidden_refs = hidden_refs;
|
||||||
data->want_obj = want_obj;
|
data->want_obj = want_obj;
|
||||||
data->have_obj = have_obj;
|
data->have_obj = have_obj;
|
||||||
data->haves = haves;
|
|
||||||
data->shallows = shallows;
|
data->shallows = shallows;
|
||||||
data->deepen_not = deepen_not;
|
data->deepen_not = deepen_not;
|
||||||
data->uri_protocols = uri_protocols;
|
data->uri_protocols = uri_protocols;
|
||||||
@ -155,13 +154,12 @@ static void upload_pack_data_init(struct upload_pack_data *data)
|
|||||||
static void upload_pack_data_clear(struct upload_pack_data *data)
|
static void upload_pack_data_clear(struct upload_pack_data *data)
|
||||||
{
|
{
|
||||||
string_list_clear(&data->symref, 1);
|
string_list_clear(&data->symref, 1);
|
||||||
string_list_clear(&data->wanted_refs, 1);
|
strmap_clear(&data->wanted_refs, 1);
|
||||||
strvec_clear(&data->hidden_refs);
|
strvec_clear(&data->hidden_refs);
|
||||||
object_array_clear(&data->want_obj);
|
object_array_clear(&data->want_obj);
|
||||||
object_array_clear(&data->have_obj);
|
object_array_clear(&data->have_obj);
|
||||||
oid_array_clear(&data->haves);
|
|
||||||
object_array_clear(&data->shallows);
|
object_array_clear(&data->shallows);
|
||||||
string_list_clear(&data->deepen_not, 0);
|
oidset_clear(&data->deepen_not);
|
||||||
object_array_clear(&data->extra_edge_obj);
|
object_array_clear(&data->extra_edge_obj);
|
||||||
list_objects_filter_release(&data->filter_options);
|
list_objects_filter_release(&data->filter_options);
|
||||||
string_list_clear(&data->allowed_filters, 0);
|
string_list_clear(&data->allowed_filters, 0);
|
||||||
@ -471,7 +469,9 @@ static void create_pack_file(struct upload_pack_data *pack_data,
|
|||||||
static int do_got_oid(struct upload_pack_data *data, const struct object_id *oid)
|
static int do_got_oid(struct upload_pack_data *data, const struct object_id *oid)
|
||||||
{
|
{
|
||||||
int we_knew_they_have = 0;
|
int we_knew_they_have = 0;
|
||||||
struct object *o = parse_object(the_repository, oid);
|
struct object *o = parse_object_with_flags(the_repository, oid,
|
||||||
|
PARSE_OBJECT_SKIP_HASH_CHECK |
|
||||||
|
PARSE_OBJECT_DISCARD_TREE);
|
||||||
|
|
||||||
if (!o)
|
if (!o)
|
||||||
die("oops (%s)", oid_to_hex(oid));
|
die("oops (%s)", oid_to_hex(oid));
|
||||||
@ -528,8 +528,6 @@ static int get_common_commits(struct upload_pack_data *data,
|
|||||||
int got_other = 0;
|
int got_other = 0;
|
||||||
int sent_ready = 0;
|
int sent_ready = 0;
|
||||||
|
|
||||||
save_commit_buffer = 0;
|
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const char *arg;
|
const char *arg;
|
||||||
|
|
||||||
@ -926,12 +924,13 @@ static int send_shallow_list(struct upload_pack_data *data)
|
|||||||
strvec_push(&av, "rev-list");
|
strvec_push(&av, "rev-list");
|
||||||
if (data->deepen_since)
|
if (data->deepen_since)
|
||||||
strvec_pushf(&av, "--max-age=%"PRItime, data->deepen_since);
|
strvec_pushf(&av, "--max-age=%"PRItime, data->deepen_since);
|
||||||
if (data->deepen_not.nr) {
|
if (oidset_size(&data->deepen_not)) {
|
||||||
|
const struct object_id *oid;
|
||||||
|
struct oidset_iter iter;
|
||||||
strvec_push(&av, "--not");
|
strvec_push(&av, "--not");
|
||||||
for (i = 0; i < data->deepen_not.nr; i++) {
|
oidset_iter_init(&data->deepen_not, &iter);
|
||||||
struct string_list_item *s = data->deepen_not.items + i;
|
while ((oid = oidset_iter_next(&iter)))
|
||||||
strvec_push(&av, s->string);
|
strvec_push(&av, oid_to_hex(oid));
|
||||||
}
|
|
||||||
strvec_push(&av, "--not");
|
strvec_push(&av, "--not");
|
||||||
}
|
}
|
||||||
for (i = 0; i < data->want_obj.nr; i++) {
|
for (i = 0; i < data->want_obj.nr; i++) {
|
||||||
@ -1007,7 +1006,7 @@ static int process_deepen_since(const char *line, timestamp_t *deepen_since, int
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_deepen_not(const char *line, struct string_list *deepen_not, int *deepen_rev_list)
|
static int process_deepen_not(const char *line, struct oidset *deepen_not, int *deepen_rev_list)
|
||||||
{
|
{
|
||||||
const char *arg;
|
const char *arg;
|
||||||
if (skip_prefix(line, "deepen-not ", &arg)) {
|
if (skip_prefix(line, "deepen-not ", &arg)) {
|
||||||
@ -1015,7 +1014,7 @@ static int process_deepen_not(const char *line, struct string_list *deepen_not,
|
|||||||
struct object_id oid;
|
struct object_id oid;
|
||||||
if (expand_ref(the_repository, arg, strlen(arg), &oid, &ref) != 1)
|
if (expand_ref(the_repository, arg, strlen(arg), &oid, &ref) != 1)
|
||||||
die("git upload-pack: ambiguous deepen-not: %s", line);
|
die("git upload-pack: ambiguous deepen-not: %s", line);
|
||||||
string_list_append(deepen_not, ref);
|
oidset_insert(deepen_not, &oid);
|
||||||
free(ref);
|
free(ref);
|
||||||
*deepen_rev_list = 1;
|
*deepen_rev_list = 1;
|
||||||
return 1;
|
return 1;
|
||||||
@ -1151,7 +1150,9 @@ static void receive_needs(struct upload_pack_data *data,
|
|||||||
free(client_sid);
|
free(client_sid);
|
||||||
}
|
}
|
||||||
|
|
||||||
o = parse_object(the_repository, &oid_buf);
|
o = parse_object_with_flags(the_repository, &oid_buf,
|
||||||
|
PARSE_OBJECT_SKIP_HASH_CHECK |
|
||||||
|
PARSE_OBJECT_DISCARD_TREE);
|
||||||
if (!o) {
|
if (!o) {
|
||||||
packet_writer_error(&data->writer,
|
packet_writer_error(&data->writer,
|
||||||
"upload-pack: not our ref %s",
|
"upload-pack: not our ref %s",
|
||||||
@ -1468,7 +1469,8 @@ static int parse_want(struct packet_writer *writer, const char *line,
|
|||||||
"expected to get oid, not '%s'", line);
|
"expected to get oid, not '%s'", line);
|
||||||
|
|
||||||
o = parse_object_with_flags(the_repository, &oid,
|
o = parse_object_with_flags(the_repository, &oid,
|
||||||
PARSE_OBJECT_SKIP_HASH_CHECK);
|
PARSE_OBJECT_SKIP_HASH_CHECK |
|
||||||
|
PARSE_OBJECT_DISCARD_TREE);
|
||||||
|
|
||||||
if (!o) {
|
if (!o) {
|
||||||
packet_writer_error(writer,
|
packet_writer_error(writer,
|
||||||
@ -1490,14 +1492,13 @@ static int parse_want(struct packet_writer *writer, const char *line,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int parse_want_ref(struct packet_writer *writer, const char *line,
|
static int parse_want_ref(struct packet_writer *writer, const char *line,
|
||||||
struct string_list *wanted_refs,
|
struct strmap *wanted_refs,
|
||||||
struct strvec *hidden_refs,
|
struct strvec *hidden_refs,
|
||||||
struct object_array *want_obj)
|
struct object_array *want_obj)
|
||||||
{
|
{
|
||||||
const char *refname_nons;
|
const char *refname_nons;
|
||||||
if (skip_prefix(line, "want-ref ", &refname_nons)) {
|
if (skip_prefix(line, "want-ref ", &refname_nons)) {
|
||||||
struct object_id oid;
|
struct object_id oid;
|
||||||
struct string_list_item *item;
|
|
||||||
struct object *o = NULL;
|
struct object *o = NULL;
|
||||||
struct strbuf refname = STRBUF_INIT;
|
struct strbuf refname = STRBUF_INIT;
|
||||||
|
|
||||||
@ -1509,8 +1510,11 @@ static int parse_want_ref(struct packet_writer *writer, const char *line,
|
|||||||
}
|
}
|
||||||
strbuf_release(&refname);
|
strbuf_release(&refname);
|
||||||
|
|
||||||
item = string_list_append(wanted_refs, refname_nons);
|
if (strmap_put(wanted_refs, refname_nons, oiddup(&oid))) {
|
||||||
item->util = oiddup(&oid);
|
packet_writer_error(writer, "duplicate want-ref %s",
|
||||||
|
refname_nons);
|
||||||
|
die("duplicate want-ref %s", refname_nons);
|
||||||
|
}
|
||||||
|
|
||||||
if (!starts_with(refname_nons, "refs/tags/")) {
|
if (!starts_with(refname_nons, "refs/tags/")) {
|
||||||
struct commit *commit = lookup_commit_in_graph(the_repository, &oid);
|
struct commit *commit = lookup_commit_in_graph(the_repository, &oid);
|
||||||
@ -1532,15 +1536,14 @@ static int parse_want_ref(struct packet_writer *writer, const char *line,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_have(const char *line, struct oid_array *haves)
|
static int parse_have(const char *line, struct upload_pack_data *data)
|
||||||
{
|
{
|
||||||
const char *arg;
|
const char *arg;
|
||||||
if (skip_prefix(line, "have ", &arg)) {
|
if (skip_prefix(line, "have ", &arg)) {
|
||||||
struct object_id oid;
|
struct object_id oid;
|
||||||
|
|
||||||
if (get_oid_hex(arg, &oid))
|
got_oid(data, arg, &oid);
|
||||||
die("git upload-pack: expected SHA1 object, got '%s'", arg);
|
data->seen_haves = 1;
|
||||||
oid_array_append(haves, &oid);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1552,13 +1555,13 @@ static void trace2_fetch_info(struct upload_pack_data *data)
|
|||||||
struct json_writer jw = JSON_WRITER_INIT;
|
struct json_writer jw = JSON_WRITER_INIT;
|
||||||
|
|
||||||
jw_object_begin(&jw, 0);
|
jw_object_begin(&jw, 0);
|
||||||
jw_object_intmax(&jw, "haves", data->haves.nr);
|
jw_object_intmax(&jw, "haves", data->have_obj.nr);
|
||||||
jw_object_intmax(&jw, "wants", data->want_obj.nr);
|
jw_object_intmax(&jw, "wants", data->want_obj.nr);
|
||||||
jw_object_intmax(&jw, "want-refs", data->wanted_refs.nr);
|
jw_object_intmax(&jw, "want-refs", strmap_get_size(&data->wanted_refs));
|
||||||
jw_object_intmax(&jw, "depth", data->depth);
|
jw_object_intmax(&jw, "depth", data->depth);
|
||||||
jw_object_intmax(&jw, "shallows", data->shallows.nr);
|
jw_object_intmax(&jw, "shallows", data->shallows.nr);
|
||||||
jw_object_bool(&jw, "deepen-since", data->deepen_since);
|
jw_object_bool(&jw, "deepen-since", data->deepen_since);
|
||||||
jw_object_intmax(&jw, "deepen-not", data->deepen_not.nr);
|
jw_object_intmax(&jw, "deepen-not", oidset_size(&data->deepen_not));
|
||||||
jw_object_bool(&jw, "deepen-relative", data->deepen_relative);
|
jw_object_bool(&jw, "deepen-relative", data->deepen_relative);
|
||||||
if (data->filter_options.choice)
|
if (data->filter_options.choice)
|
||||||
jw_object_string(&jw, "filter", list_object_filter_config_name(data->filter_options.choice));
|
jw_object_string(&jw, "filter", list_object_filter_config_name(data->filter_options.choice));
|
||||||
@ -1586,7 +1589,7 @@ static void process_args(struct packet_reader *request,
|
|||||||
&data->hidden_refs, &data->want_obj))
|
&data->hidden_refs, &data->want_obj))
|
||||||
continue;
|
continue;
|
||||||
/* process have line */
|
/* process have line */
|
||||||
if (parse_have(arg, &data->haves))
|
if (parse_have(arg, data))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* process args like thin-pack */
|
/* process args like thin-pack */
|
||||||
@ -1646,6 +1649,9 @@ static void process_args(struct packet_reader *request,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (skip_prefix(arg, "packfile-uris ", &p)) {
|
if (skip_prefix(arg, "packfile-uris ", &p)) {
|
||||||
|
if (data->uri_protocols.nr)
|
||||||
|
send_err_and_die(data,
|
||||||
|
"multiple packfile-uris lines forbidden");
|
||||||
string_list_split(&data->uri_protocols, p, ',', -1);
|
string_list_split(&data->uri_protocols, p, ',', -1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -1664,27 +1670,7 @@ static void process_args(struct packet_reader *request,
|
|||||||
trace2_fetch_info(data);
|
trace2_fetch_info(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_haves(struct upload_pack_data *data, struct oid_array *common)
|
static int send_acks(struct upload_pack_data *data, struct object_array *acks)
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* Process haves */
|
|
||||||
for (i = 0; i < data->haves.nr; i++) {
|
|
||||||
const struct object_id *oid = &data->haves.oid[i];
|
|
||||||
|
|
||||||
if (!repo_has_object_file_with_flags(the_repository, oid,
|
|
||||||
OBJECT_INFO_QUICK | OBJECT_INFO_SKIP_FETCH_OBJECT))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
oid_array_append(common, oid);
|
|
||||||
|
|
||||||
do_got_oid(data, oid);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int send_acks(struct upload_pack_data *data, struct oid_array *acks)
|
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -1696,7 +1682,7 @@ static int send_acks(struct upload_pack_data *data, struct oid_array *acks)
|
|||||||
|
|
||||||
for (i = 0; i < acks->nr; i++) {
|
for (i = 0; i < acks->nr; i++) {
|
||||||
packet_writer_write(&data->writer, "ACK %s\n",
|
packet_writer_write(&data->writer, "ACK %s\n",
|
||||||
oid_to_hex(&acks->oid[i]));
|
oid_to_hex(&acks->objects[i].item->oid));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data->wait_for_done && ok_to_give_up(data)) {
|
if (!data->wait_for_done && ok_to_give_up(data)) {
|
||||||
@ -1710,13 +1696,11 @@ static int send_acks(struct upload_pack_data *data, struct oid_array *acks)
|
|||||||
|
|
||||||
static int process_haves_and_send_acks(struct upload_pack_data *data)
|
static int process_haves_and_send_acks(struct upload_pack_data *data)
|
||||||
{
|
{
|
||||||
struct oid_array common = OID_ARRAY_INIT;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
process_haves(data, &common);
|
|
||||||
if (data->done) {
|
if (data->done) {
|
||||||
ret = 1;
|
ret = 1;
|
||||||
} else if (send_acks(data, &common)) {
|
} else if (send_acks(data, &data->have_obj)) {
|
||||||
packet_writer_delim(&data->writer);
|
packet_writer_delim(&data->writer);
|
||||||
ret = 1;
|
ret = 1;
|
||||||
} else {
|
} else {
|
||||||
@ -1725,24 +1709,23 @@ static int process_haves_and_send_acks(struct upload_pack_data *data)
|
|||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
oid_array_clear(&data->haves);
|
|
||||||
oid_array_clear(&common);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void send_wanted_ref_info(struct upload_pack_data *data)
|
static void send_wanted_ref_info(struct upload_pack_data *data)
|
||||||
{
|
{
|
||||||
const struct string_list_item *item;
|
struct hashmap_iter iter;
|
||||||
|
const struct strmap_entry *e;
|
||||||
|
|
||||||
if (!data->wanted_refs.nr)
|
if (strmap_empty(&data->wanted_refs))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
packet_writer_write(&data->writer, "wanted-refs\n");
|
packet_writer_write(&data->writer, "wanted-refs\n");
|
||||||
|
|
||||||
for_each_string_list_item(item, &data->wanted_refs) {
|
strmap_for_each_entry(&data->wanted_refs, &iter, e) {
|
||||||
packet_writer_write(&data->writer, "%s %s\n",
|
packet_writer_write(&data->writer, "%s %s\n",
|
||||||
oid_to_hex(item->util),
|
oid_to_hex(e->value),
|
||||||
item->string);
|
e->key);
|
||||||
}
|
}
|
||||||
|
|
||||||
packet_writer_delim(&data->writer);
|
packet_writer_delim(&data->writer);
|
||||||
@ -1796,7 +1779,7 @@ int upload_pack_v2(struct repository *r UNUSED, struct packet_reader *request)
|
|||||||
* they didn't want anything.
|
* they didn't want anything.
|
||||||
*/
|
*/
|
||||||
state = FETCH_DONE;
|
state = FETCH_DONE;
|
||||||
} else if (data.haves.nr) {
|
} else if (data.seen_haves) {
|
||||||
/*
|
/*
|
||||||
* Request had 'have' lines, so lets ACK them.
|
* Request had 'have' lines, so lets ACK them.
|
||||||
*/
|
*/
|
||||||
|
Reference in New Issue
Block a user