upload-pack: send part of packfile response as uri
Teach upload-pack to send part of its packfile response as URIs. An administrator may configure a repository with one or more "uploadpack.blobpackfileuri" lines, each line containing an OID, a pack hash, and a URI. A client may configure fetch.uriprotocols to be a comma-separated list of protocols that it is willing to use to fetch additional packfiles - this list will be sent to the server. Whenever an object with one of those OIDs would appear in the packfile transmitted by upload-pack, the server may exclude that object, and instead send the URI. The client will then download the packs referred to by those URIs before performing the connectivity check. Signed-off-by: Jonathan Tan <jonathantanmy@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
9da69a6539
commit
dd4b732df7
@ -117,6 +117,8 @@ static unsigned long window_memory_limit = 0;
|
|||||||
|
|
||||||
static struct list_objects_filter_options filter_options;
|
static struct list_objects_filter_options filter_options;
|
||||||
|
|
||||||
|
static struct string_list uri_protocols = STRING_LIST_INIT_NODUP;
|
||||||
|
|
||||||
enum missing_action {
|
enum missing_action {
|
||||||
MA_ERROR = 0, /* fail if any missing objects are encountered */
|
MA_ERROR = 0, /* fail if any missing objects are encountered */
|
||||||
MA_ALLOW_ANY, /* silently allow ALL missing objects */
|
MA_ALLOW_ANY, /* silently allow ALL missing objects */
|
||||||
@ -125,6 +127,15 @@ enum missing_action {
|
|||||||
static enum missing_action arg_missing_action;
|
static enum missing_action arg_missing_action;
|
||||||
static show_object_fn fn_show_object;
|
static show_object_fn fn_show_object;
|
||||||
|
|
||||||
|
struct configured_exclusion {
|
||||||
|
struct oidmap_entry e;
|
||||||
|
char *pack_hash_hex;
|
||||||
|
char *uri;
|
||||||
|
};
|
||||||
|
static struct oidmap configured_exclusions;
|
||||||
|
|
||||||
|
static struct oidset excluded_by_config;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* stats
|
* stats
|
||||||
*/
|
*/
|
||||||
@ -969,6 +980,25 @@ static void write_reused_pack(struct hashfile *f)
|
|||||||
unuse_pack(&w_curs);
|
unuse_pack(&w_curs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void write_excluded_by_configs(void)
|
||||||
|
{
|
||||||
|
struct oidset_iter iter;
|
||||||
|
const struct object_id *oid;
|
||||||
|
|
||||||
|
oidset_iter_init(&excluded_by_config, &iter);
|
||||||
|
while ((oid = oidset_iter_next(&iter))) {
|
||||||
|
struct configured_exclusion *ex =
|
||||||
|
oidmap_get(&configured_exclusions, oid);
|
||||||
|
|
||||||
|
if (!ex)
|
||||||
|
BUG("configured exclusion wasn't configured");
|
||||||
|
write_in_full(1, ex->pack_hash_hex, strlen(ex->pack_hash_hex));
|
||||||
|
write_in_full(1, " ", 1);
|
||||||
|
write_in_full(1, ex->uri, strlen(ex->uri));
|
||||||
|
write_in_full(1, "\n", 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static const char no_split_warning[] = N_(
|
static const char no_split_warning[] = N_(
|
||||||
"disabling bitmap writing, packs are split due to pack.packSizeLimit"
|
"disabling bitmap writing, packs are split due to pack.packSizeLimit"
|
||||||
);
|
);
|
||||||
@ -1266,6 +1296,25 @@ static int want_object_in_pack(const struct object_id *oid,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (uri_protocols.nr) {
|
||||||
|
struct configured_exclusion *ex =
|
||||||
|
oidmap_get(&configured_exclusions, oid);
|
||||||
|
int i;
|
||||||
|
const char *p;
|
||||||
|
|
||||||
|
if (ex) {
|
||||||
|
for (i = 0; i < uri_protocols.nr; i++) {
|
||||||
|
if (skip_prefix(ex->uri,
|
||||||
|
uri_protocols.items[i].string,
|
||||||
|
&p) &&
|
||||||
|
*p == ':') {
|
||||||
|
oidset_insert(&excluded_by_config, oid);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2864,6 +2913,29 @@ static int git_pack_config(const char *k, const char *v, void *cb)
|
|||||||
pack_idx_opts.version);
|
pack_idx_opts.version);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (!strcmp(k, "uploadpack.blobpackfileuri")) {
|
||||||
|
struct configured_exclusion *ex = xmalloc(sizeof(*ex));
|
||||||
|
const char *oid_end, *pack_end;
|
||||||
|
/*
|
||||||
|
* Stores the pack hash. This is not a true object ID, but is
|
||||||
|
* of the same form.
|
||||||
|
*/
|
||||||
|
struct object_id pack_hash;
|
||||||
|
|
||||||
|
if (parse_oid_hex(v, &ex->e.oid, &oid_end) ||
|
||||||
|
*oid_end != ' ' ||
|
||||||
|
parse_oid_hex(oid_end + 1, &pack_hash, &pack_end) ||
|
||||||
|
*pack_end != ' ')
|
||||||
|
die(_("value of uploadpack.blobpackfileuri must be "
|
||||||
|
"of the form '<object-hash> <pack-hash> <uri>' (got '%s')"), v);
|
||||||
|
if (oidmap_get(&configured_exclusions, &ex->e.oid))
|
||||||
|
die(_("object already configured in another "
|
||||||
|
"uploadpack.blobpackfileuri (got '%s')"), v);
|
||||||
|
ex->pack_hash_hex = xcalloc(1, pack_end - oid_end);
|
||||||
|
memcpy(ex->pack_hash_hex, oid_end + 1, pack_end - oid_end - 1);
|
||||||
|
ex->uri = xstrdup(pack_end + 1);
|
||||||
|
oidmap_put(&configured_exclusions, ex);
|
||||||
|
}
|
||||||
return git_default_config(k, v, cb);
|
return git_default_config(k, v, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3462,6 +3534,9 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
|
|||||||
N_("do not pack objects in promisor packfiles")),
|
N_("do not pack objects in promisor packfiles")),
|
||||||
OPT_BOOL(0, "delta-islands", &use_delta_islands,
|
OPT_BOOL(0, "delta-islands", &use_delta_islands,
|
||||||
N_("respect islands during delta compression")),
|
N_("respect islands during delta compression")),
|
||||||
|
OPT_STRING_LIST(0, "uri-protocol", &uri_protocols,
|
||||||
|
N_("protocol"),
|
||||||
|
N_("exclude any configured uploadpack.blobpackfileuri with this protocol")),
|
||||||
OPT_END(),
|
OPT_END(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -3650,6 +3725,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
|
|||||||
}
|
}
|
||||||
|
|
||||||
trace2_region_enter("pack-objects", "write-pack-file", the_repository);
|
trace2_region_enter("pack-objects", "write-pack-file", the_repository);
|
||||||
|
write_excluded_by_configs();
|
||||||
write_pack_file();
|
write_pack_file();
|
||||||
trace2_region_leave("pack-objects", "write-pack-file", the_repository);
|
trace2_region_leave("pack-objects", "write-pack-file", the_repository);
|
||||||
|
|
||||||
|
112
fetch-pack.c
112
fetch-pack.c
@ -38,6 +38,7 @@ static int server_supports_filtering;
|
|||||||
static struct shallow_lock shallow_lock;
|
static struct shallow_lock shallow_lock;
|
||||||
static const char *alternate_shallow_file;
|
static const char *alternate_shallow_file;
|
||||||
static struct strbuf fsck_msg_types = STRBUF_INIT;
|
static struct strbuf fsck_msg_types = STRBUF_INIT;
|
||||||
|
static struct string_list uri_protocols = STRING_LIST_INIT_DUP;
|
||||||
|
|
||||||
/* Remember to update object flag allocation in object.h */
|
/* Remember to update object flag allocation in object.h */
|
||||||
#define COMPLETE (1U << 0)
|
#define COMPLETE (1U << 0)
|
||||||
@ -795,6 +796,7 @@ static void write_promisor_file(const char *keep_name,
|
|||||||
|
|
||||||
static int get_pack(struct fetch_pack_args *args,
|
static int get_pack(struct fetch_pack_args *args,
|
||||||
int xd[2], struct string_list *pack_lockfiles,
|
int xd[2], struct string_list *pack_lockfiles,
|
||||||
|
int only_packfile,
|
||||||
struct ref **sought, int nr_sought)
|
struct ref **sought, int nr_sought)
|
||||||
{
|
{
|
||||||
struct async demux;
|
struct async demux;
|
||||||
@ -855,8 +857,15 @@ static int get_pack(struct fetch_pack_args *args,
|
|||||||
"--keep=fetch-pack %"PRIuMAX " on %s",
|
"--keep=fetch-pack %"PRIuMAX " on %s",
|
||||||
(uintmax_t)getpid(), hostname);
|
(uintmax_t)getpid(), hostname);
|
||||||
}
|
}
|
||||||
if (args->check_self_contained_and_connected)
|
if (only_packfile && args->check_self_contained_and_connected)
|
||||||
argv_array_push(&cmd.args, "--check-self-contained-and-connected");
|
argv_array_push(&cmd.args, "--check-self-contained-and-connected");
|
||||||
|
else
|
||||||
|
/*
|
||||||
|
* We cannot perform any connectivity checks because
|
||||||
|
* not all packs have been downloaded; let the caller
|
||||||
|
* have this responsibility.
|
||||||
|
*/
|
||||||
|
args->check_self_contained_and_connected = 0;
|
||||||
/*
|
/*
|
||||||
* If we're obtaining the filename of a lockfile, we'll use
|
* If we're obtaining the filename of a lockfile, we'll use
|
||||||
* that filename to write a .promisor file with more
|
* that filename to write a .promisor file with more
|
||||||
@ -1068,7 +1077,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
|
|||||||
alternate_shallow_file = setup_temporary_shallow(si->shallow);
|
alternate_shallow_file = setup_temporary_shallow(si->shallow);
|
||||||
else
|
else
|
||||||
alternate_shallow_file = NULL;
|
alternate_shallow_file = NULL;
|
||||||
if (get_pack(args, fd, pack_lockfiles, sought, nr_sought))
|
if (get_pack(args, fd, pack_lockfiles, 1, sought, nr_sought))
|
||||||
die(_("git fetch-pack: fetch failed."));
|
die(_("git fetch-pack: fetch failed."));
|
||||||
|
|
||||||
all_done:
|
all_done:
|
||||||
@ -1222,6 +1231,26 @@ static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out,
|
|||||||
warning("filtering not recognized by server, ignoring");
|
warning("filtering not recognized by server, ignoring");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (server_supports_feature("fetch", "packfile-uris", 0)) {
|
||||||
|
int i;
|
||||||
|
struct strbuf to_send = STRBUF_INIT;
|
||||||
|
|
||||||
|
for (i = 0; i < uri_protocols.nr; i++) {
|
||||||
|
const char *s = uri_protocols.items[i].string;
|
||||||
|
|
||||||
|
if (!strcmp(s, "https") || !strcmp(s, "http")) {
|
||||||
|
if (to_send.len)
|
||||||
|
strbuf_addch(&to_send, ',');
|
||||||
|
strbuf_addstr(&to_send, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (to_send.len) {
|
||||||
|
packet_buf_write(&req_buf, "packfile-uris %s",
|
||||||
|
to_send.buf);
|
||||||
|
strbuf_release(&to_send);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* add wants */
|
/* add wants */
|
||||||
add_wants(args->no_dependents, wants, &req_buf);
|
add_wants(args->no_dependents, wants, &req_buf);
|
||||||
|
|
||||||
@ -1444,6 +1473,21 @@ static void receive_wanted_refs(struct packet_reader *reader,
|
|||||||
die(_("error processing wanted refs: %d"), reader->status);
|
die(_("error processing wanted refs: %d"), reader->status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void receive_packfile_uris(struct packet_reader *reader,
|
||||||
|
struct string_list *uris)
|
||||||
|
{
|
||||||
|
process_section_header(reader, "packfile-uris", 0);
|
||||||
|
while (packet_reader_read(reader) == PACKET_READ_NORMAL) {
|
||||||
|
if (reader->pktlen < the_hash_algo->hexsz ||
|
||||||
|
reader->line[the_hash_algo->hexsz] != ' ')
|
||||||
|
die("expected '<hash> <uri>', got: %s\n", reader->line);
|
||||||
|
|
||||||
|
string_list_append(uris, reader->line);
|
||||||
|
}
|
||||||
|
if (reader->status != PACKET_READ_DELIM)
|
||||||
|
die("expected DELIM");
|
||||||
|
}
|
||||||
|
|
||||||
enum fetch_state {
|
enum fetch_state {
|
||||||
FETCH_CHECK_LOCAL = 0,
|
FETCH_CHECK_LOCAL = 0,
|
||||||
FETCH_SEND_REQUEST,
|
FETCH_SEND_REQUEST,
|
||||||
@ -1470,6 +1514,8 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
|
|||||||
struct fetch_negotiator negotiator_alloc;
|
struct fetch_negotiator negotiator_alloc;
|
||||||
struct fetch_negotiator *negotiator;
|
struct fetch_negotiator *negotiator;
|
||||||
int seen_ack = 0;
|
int seen_ack = 0;
|
||||||
|
struct string_list packfile_uris = STRING_LIST_INIT_DUP;
|
||||||
|
int i;
|
||||||
|
|
||||||
if (args->no_dependents) {
|
if (args->no_dependents) {
|
||||||
negotiator = NULL;
|
negotiator = NULL;
|
||||||
@ -1558,9 +1604,12 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
|
|||||||
if (process_section_header(&reader, "wanted-refs", 1))
|
if (process_section_header(&reader, "wanted-refs", 1))
|
||||||
receive_wanted_refs(&reader, sought, nr_sought);
|
receive_wanted_refs(&reader, sought, nr_sought);
|
||||||
|
|
||||||
/* get the pack */
|
/* get the pack(s) */
|
||||||
|
if (process_section_header(&reader, "packfile-uris", 1))
|
||||||
|
receive_packfile_uris(&reader, &packfile_uris);
|
||||||
process_section_header(&reader, "packfile", 0);
|
process_section_header(&reader, "packfile", 0);
|
||||||
if (get_pack(args, fd, pack_lockfiles, sought, nr_sought))
|
if (get_pack(args, fd, pack_lockfiles,
|
||||||
|
!packfile_uris.nr, sought, nr_sought))
|
||||||
die(_("git fetch-pack: fetch failed."));
|
die(_("git fetch-pack: fetch failed."));
|
||||||
|
|
||||||
state = FETCH_DONE;
|
state = FETCH_DONE;
|
||||||
@ -1570,8 +1619,55 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < packfile_uris.nr; i++) {
|
||||||
|
struct child_process cmd = CHILD_PROCESS_INIT;
|
||||||
|
char packname[GIT_MAX_HEXSZ + 1];
|
||||||
|
const char *uri = packfile_uris.items[i].string +
|
||||||
|
the_hash_algo->hexsz + 1;
|
||||||
|
|
||||||
|
argv_array_push(&cmd.args, "http-fetch");
|
||||||
|
argv_array_pushf(&cmd.args, "--packfile=%.*s",
|
||||||
|
(int) the_hash_algo->hexsz,
|
||||||
|
packfile_uris.items[i].string);
|
||||||
|
argv_array_push(&cmd.args, uri);
|
||||||
|
cmd.git_cmd = 1;
|
||||||
|
cmd.no_stdin = 1;
|
||||||
|
cmd.out = -1;
|
||||||
|
if (start_command(&cmd))
|
||||||
|
die("fetch-pack: unable to spawn http-fetch");
|
||||||
|
|
||||||
|
if (read_in_full(cmd.out, packname, 5) < 0 ||
|
||||||
|
memcmp(packname, "keep\t", 5))
|
||||||
|
die("fetch-pack: expected keep then TAB at start of http-fetch output");
|
||||||
|
|
||||||
|
if (read_in_full(cmd.out, packname,
|
||||||
|
the_hash_algo->hexsz + 1) < 0 ||
|
||||||
|
packname[the_hash_algo->hexsz] != '\n')
|
||||||
|
die("fetch-pack: expected hash then LF at end of http-fetch output");
|
||||||
|
|
||||||
|
packname[the_hash_algo->hexsz] = '\0';
|
||||||
|
|
||||||
|
close(cmd.out);
|
||||||
|
|
||||||
|
if (finish_command(&cmd))
|
||||||
|
die("fetch-pack: unable to finish http-fetch");
|
||||||
|
|
||||||
|
if (memcmp(packfile_uris.items[i].string, packname,
|
||||||
|
the_hash_algo->hexsz))
|
||||||
|
die("fetch-pack: pack downloaded from %s does not match expected hash %.*s",
|
||||||
|
uri, (int) the_hash_algo->hexsz,
|
||||||
|
packfile_uris.items[i].string);
|
||||||
|
|
||||||
|
string_list_append_nodup(pack_lockfiles,
|
||||||
|
xstrfmt("%s/pack/pack-%s.keep",
|
||||||
|
get_object_directory(),
|
||||||
|
packname));
|
||||||
|
}
|
||||||
|
string_list_clear(&packfile_uris, 0);
|
||||||
|
|
||||||
if (negotiator)
|
if (negotiator)
|
||||||
negotiator->release(negotiator);
|
negotiator->release(negotiator);
|
||||||
|
|
||||||
oidset_clear(&common);
|
oidset_clear(&common);
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
@ -1608,6 +1704,14 @@ static void fetch_pack_config(void)
|
|||||||
git_config_get_bool("repack.usedeltabaseoffset", &prefer_ofs_delta);
|
git_config_get_bool("repack.usedeltabaseoffset", &prefer_ofs_delta);
|
||||||
git_config_get_bool("fetch.fsckobjects", &fetch_fsck_objects);
|
git_config_get_bool("fetch.fsckobjects", &fetch_fsck_objects);
|
||||||
git_config_get_bool("transfer.fsckobjects", &transfer_fsck_objects);
|
git_config_get_bool("transfer.fsckobjects", &transfer_fsck_objects);
|
||||||
|
if (!uri_protocols.nr) {
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
if (!git_config_get_string("fetch.uriprotocols", &str) && str) {
|
||||||
|
string_list_split(&uri_protocols, str, ',', -1);
|
||||||
|
free(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
git_config(fetch_pack_config_cb, NULL);
|
git_config(fetch_pack_config_cb, NULL);
|
||||||
}
|
}
|
||||||
|
@ -748,6 +748,94 @@ test_expect_success 'when server does not send "ready", expect FLUSH' '
|
|||||||
test_i18ngrep "expected no other sections to be sent after no .ready." err
|
test_i18ngrep "expected no other sections to be sent after no .ready." err
|
||||||
'
|
'
|
||||||
|
|
||||||
|
configure_exclusion () {
|
||||||
|
git -C "$1" hash-object "$2" >objh &&
|
||||||
|
git -C "$1" pack-objects "$HTTPD_DOCUMENT_ROOT_PATH/mypack" <objh >packh &&
|
||||||
|
git -C "$1" config --add \
|
||||||
|
"uploadpack.blobpackfileuri" \
|
||||||
|
"$(cat objh) $(cat packh) $HTTPD_URL/dumb/mypack-$(cat packh).pack" &&
|
||||||
|
cat objh
|
||||||
|
}
|
||||||
|
|
||||||
|
test_expect_success 'part of packfile response provided as URI' '
|
||||||
|
P="$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
|
||||||
|
rm -rf "$P" http_child log &&
|
||||||
|
|
||||||
|
git init "$P" &&
|
||||||
|
git -C "$P" config "uploadpack.allowsidebandall" "true" &&
|
||||||
|
|
||||||
|
echo my-blob >"$P/my-blob" &&
|
||||||
|
git -C "$P" add my-blob &&
|
||||||
|
echo other-blob >"$P/other-blob" &&
|
||||||
|
git -C "$P" add other-blob &&
|
||||||
|
git -C "$P" commit -m x &&
|
||||||
|
|
||||||
|
configure_exclusion "$P" my-blob >h &&
|
||||||
|
configure_exclusion "$P" other-blob >h2 &&
|
||||||
|
|
||||||
|
GIT_TRACE=1 GIT_TRACE_PACKET="$(pwd)/log" GIT_TEST_SIDEBAND_ALL=1 \
|
||||||
|
git -c protocol.version=2 \
|
||||||
|
-c fetch.uriprotocols=http,https \
|
||||||
|
clone "$HTTPD_URL/smart/http_parent" http_child &&
|
||||||
|
|
||||||
|
# Ensure that my-blob and other-blob are in separate packfiles.
|
||||||
|
for idx in http_child/.git/objects/pack/*.idx
|
||||||
|
do
|
||||||
|
git verify-pack --verbose $idx >out &&
|
||||||
|
{
|
||||||
|
grep "^[0-9a-f]\{16,\} " out || :
|
||||||
|
} >out.objectlist &&
|
||||||
|
if test_line_count = 1 out.objectlist
|
||||||
|
then
|
||||||
|
if grep $(cat h) out
|
||||||
|
then
|
||||||
|
>hfound
|
||||||
|
fi &&
|
||||||
|
if grep $(cat h2) out
|
||||||
|
then
|
||||||
|
>h2found
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done &&
|
||||||
|
test -f hfound &&
|
||||||
|
test -f h2found &&
|
||||||
|
|
||||||
|
# Ensure that there are exactly 6 files (3 .pack and 3 .idx).
|
||||||
|
ls http_child/.git/objects/pack/* >filelist &&
|
||||||
|
test_line_count = 6 filelist
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'fetching with valid packfile URI but invalid hash fails' '
|
||||||
|
P="$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
|
||||||
|
rm -rf "$P" http_child log &&
|
||||||
|
|
||||||
|
git init "$P" &&
|
||||||
|
git -C "$P" config "uploadpack.allowsidebandall" "true" &&
|
||||||
|
|
||||||
|
echo my-blob >"$P/my-blob" &&
|
||||||
|
git -C "$P" add my-blob &&
|
||||||
|
echo other-blob >"$P/other-blob" &&
|
||||||
|
git -C "$P" add other-blob &&
|
||||||
|
git -C "$P" commit -m x &&
|
||||||
|
|
||||||
|
configure_exclusion "$P" my-blob >h &&
|
||||||
|
# Configure a URL for other-blob. Just reuse the hash of the object as
|
||||||
|
# the hash of the packfile, since the hash does not matter for this
|
||||||
|
# test as long as it is not the hash of the pack, and it is of the
|
||||||
|
# expected length.
|
||||||
|
git -C "$P" hash-object other-blob >objh &&
|
||||||
|
git -C "$P" pack-objects "$HTTPD_DOCUMENT_ROOT_PATH/mypack" <objh >packh &&
|
||||||
|
git -C "$P" config --add \
|
||||||
|
"uploadpack.blobpackfileuri" \
|
||||||
|
"$(cat objh) $(cat objh) $HTTPD_URL/dumb/mypack-$(cat packh).pack" &&
|
||||||
|
|
||||||
|
test_must_fail env GIT_TEST_SIDEBAND_ALL=1 \
|
||||||
|
git -c protocol.version=2 \
|
||||||
|
-c fetch.uriprotocols=http,https \
|
||||||
|
clone "$HTTPD_URL/smart/http_parent" http_child 2>err &&
|
||||||
|
test_i18ngrep "pack downloaded from.*does not match expected hash" err
|
||||||
|
'
|
||||||
|
|
||||||
# DO NOT add non-httpd-specific tests here, because the last part of this
|
# DO NOT add non-httpd-specific tests here, because the last part of this
|
||||||
# test script is only executed when httpd is available and enabled.
|
# test script is only executed when httpd is available and enabled.
|
||||||
|
|
||||||
|
@ -83,6 +83,8 @@ struct upload_pack_data {
|
|||||||
/* 0 for no sideband, otherwise DEFAULT_PACKET_MAX or LARGE_PACKET_MAX */
|
/* 0 for no sideband, otherwise DEFAULT_PACKET_MAX or LARGE_PACKET_MAX */
|
||||||
int use_sideband;
|
int use_sideband;
|
||||||
|
|
||||||
|
struct string_list uri_protocols;
|
||||||
|
|
||||||
struct list_objects_filter_options filter_options;
|
struct list_objects_filter_options filter_options;
|
||||||
|
|
||||||
struct packet_writer writer;
|
struct packet_writer writer;
|
||||||
@ -114,6 +116,7 @@ static void upload_pack_data_init(struct upload_pack_data *data)
|
|||||||
struct oid_array haves = OID_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 string_list deepen_not = STRING_LIST_INIT_DUP;
|
||||||
|
struct string_list uri_protocols = STRING_LIST_INIT_DUP;
|
||||||
|
|
||||||
memset(data, 0, sizeof(*data));
|
memset(data, 0, sizeof(*data));
|
||||||
data->symref = symref;
|
data->symref = symref;
|
||||||
@ -123,6 +126,7 @@ static void upload_pack_data_init(struct upload_pack_data *data)
|
|||||||
data->haves = haves;
|
data->haves = haves;
|
||||||
data->shallows = shallows;
|
data->shallows = shallows;
|
||||||
data->deepen_not = deepen_not;
|
data->deepen_not = deepen_not;
|
||||||
|
data->uri_protocols = uri_protocols;
|
||||||
packet_writer_init(&data->writer, 1);
|
packet_writer_init(&data->writer, 1);
|
||||||
|
|
||||||
data->keepalive = 5;
|
data->keepalive = 5;
|
||||||
@ -176,10 +180,12 @@ static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
|
|||||||
struct output_state {
|
struct output_state {
|
||||||
char buffer[8193];
|
char buffer[8193];
|
||||||
int used;
|
int used;
|
||||||
|
unsigned packfile_uris_started : 1;
|
||||||
|
unsigned packfile_started : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int relay_pack_data(int pack_objects_out, struct output_state *os,
|
static int relay_pack_data(int pack_objects_out, struct output_state *os,
|
||||||
int use_sideband)
|
int use_sideband, int write_packfile_line)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* We keep the last byte to ourselves
|
* We keep the last byte to ourselves
|
||||||
@ -200,6 +206,37 @@ static int relay_pack_data(int pack_objects_out, struct output_state *os,
|
|||||||
}
|
}
|
||||||
os->used += readsz;
|
os->used += readsz;
|
||||||
|
|
||||||
|
while (!os->packfile_started) {
|
||||||
|
char *p;
|
||||||
|
if (os->used >= 4 && !memcmp(os->buffer, "PACK", 4)) {
|
||||||
|
os->packfile_started = 1;
|
||||||
|
if (write_packfile_line) {
|
||||||
|
if (os->packfile_uris_started)
|
||||||
|
packet_delim(1);
|
||||||
|
packet_write_fmt(1, "\1packfile\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((p = memchr(os->buffer, '\n', os->used))) {
|
||||||
|
if (!os->packfile_uris_started) {
|
||||||
|
os->packfile_uris_started = 1;
|
||||||
|
if (!write_packfile_line)
|
||||||
|
BUG("packfile_uris requires sideband-all");
|
||||||
|
packet_write_fmt(1, "\1packfile-uris\n");
|
||||||
|
}
|
||||||
|
*p = '\0';
|
||||||
|
packet_write_fmt(1, "\1%s\n", os->buffer);
|
||||||
|
|
||||||
|
os->used -= p - os->buffer + 1;
|
||||||
|
memmove(os->buffer, p + 1, os->used);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Incomplete line.
|
||||||
|
*/
|
||||||
|
return readsz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (os->used > 1) {
|
if (os->used > 1) {
|
||||||
send_client_data(1, os->buffer, os->used - 1, use_sideband);
|
send_client_data(1, os->buffer, os->used - 1, use_sideband);
|
||||||
os->buffer[0] = os->buffer[os->used - 1];
|
os->buffer[0] = os->buffer[os->used - 1];
|
||||||
@ -212,7 +249,8 @@ static int relay_pack_data(int pack_objects_out, struct output_state *os,
|
|||||||
return readsz;
|
return readsz;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void create_pack_file(struct upload_pack_data *pack_data)
|
static void create_pack_file(struct upload_pack_data *pack_data,
|
||||||
|
const struct string_list *uri_protocols)
|
||||||
{
|
{
|
||||||
struct child_process pack_objects = CHILD_PROCESS_INIT;
|
struct child_process pack_objects = CHILD_PROCESS_INIT;
|
||||||
struct output_state output_state = { { 0 } };
|
struct output_state output_state = { { 0 } };
|
||||||
@ -262,6 +300,11 @@ static void create_pack_file(struct upload_pack_data *pack_data)
|
|||||||
spec);
|
spec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (uri_protocols) {
|
||||||
|
for (i = 0; i < uri_protocols->nr; i++)
|
||||||
|
argv_array_pushf(&pack_objects.args, "--uri-protocol=%s",
|
||||||
|
uri_protocols->items[i].string);
|
||||||
|
}
|
||||||
|
|
||||||
pack_objects.in = -1;
|
pack_objects.in = -1;
|
||||||
pack_objects.out = -1;
|
pack_objects.out = -1;
|
||||||
@ -353,7 +396,8 @@ static void create_pack_file(struct upload_pack_data *pack_data)
|
|||||||
if (0 <= pu && (pfd[pu].revents & (POLLIN|POLLHUP))) {
|
if (0 <= pu && (pfd[pu].revents & (POLLIN|POLLHUP))) {
|
||||||
int result = relay_pack_data(pack_objects.out,
|
int result = relay_pack_data(pack_objects.out,
|
||||||
&output_state,
|
&output_state,
|
||||||
pack_data->use_sideband);
|
pack_data->use_sideband,
|
||||||
|
!!uri_protocols);
|
||||||
|
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
close(pack_objects.out);
|
close(pack_objects.out);
|
||||||
@ -1210,7 +1254,7 @@ void upload_pack(struct upload_pack_options *options)
|
|||||||
receive_needs(&data, &reader);
|
receive_needs(&data, &reader);
|
||||||
if (data.want_obj.nr) {
|
if (data.want_obj.nr) {
|
||||||
get_common_commits(&data, &reader);
|
get_common_commits(&data, &reader);
|
||||||
create_pack_file(&data);
|
create_pack_file(&data, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1363,10 +1407,18 @@ static void process_args(struct packet_reader *request,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (skip_prefix(arg, "packfile-uris ", &p)) {
|
||||||
|
string_list_split(&data->uri_protocols, p, ',', -1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* ignore unknown lines maybe? */
|
/* ignore unknown lines maybe? */
|
||||||
die("unexpected line: '%s'", arg);
|
die("unexpected line: '%s'", arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data->uri_protocols.nr && !data->writer.use_sideband)
|
||||||
|
string_list_clear(&data->uri_protocols, 0);
|
||||||
|
|
||||||
if (request->status != PACKET_READ_FLUSH)
|
if (request->status != PACKET_READ_FLUSH)
|
||||||
die(_("expected flush after fetch arguments"));
|
die(_("expected flush after fetch arguments"));
|
||||||
}
|
}
|
||||||
@ -1553,8 +1605,12 @@ int upload_pack_v2(struct repository *r, struct argv_array *keys,
|
|||||||
send_wanted_ref_info(&data);
|
send_wanted_ref_info(&data);
|
||||||
send_shallow_info(&data);
|
send_shallow_info(&data);
|
||||||
|
|
||||||
|
if (data.uri_protocols.nr) {
|
||||||
|
create_pack_file(&data, &data.uri_protocols);
|
||||||
|
} else {
|
||||||
packet_writer_write(&data.writer, "packfile\n");
|
packet_writer_write(&data.writer, "packfile\n");
|
||||||
create_pack_file(&data);
|
create_pack_file(&data, NULL);
|
||||||
|
}
|
||||||
state = FETCH_DONE;
|
state = FETCH_DONE;
|
||||||
break;
|
break;
|
||||||
case FETCH_DONE:
|
case FETCH_DONE:
|
||||||
@ -1573,6 +1629,7 @@ int upload_pack_advertise(struct repository *r,
|
|||||||
int allow_filter_value;
|
int allow_filter_value;
|
||||||
int allow_ref_in_want;
|
int allow_ref_in_want;
|
||||||
int allow_sideband_all_value;
|
int allow_sideband_all_value;
|
||||||
|
char *str = NULL;
|
||||||
|
|
||||||
strbuf_addstr(value, "shallow");
|
strbuf_addstr(value, "shallow");
|
||||||
|
|
||||||
@ -1594,6 +1651,14 @@ int upload_pack_advertise(struct repository *r,
|
|||||||
&allow_sideband_all_value) &&
|
&allow_sideband_all_value) &&
|
||||||
allow_sideband_all_value))
|
allow_sideband_all_value))
|
||||||
strbuf_addstr(value, " sideband-all");
|
strbuf_addstr(value, " sideband-all");
|
||||||
|
|
||||||
|
if (!repo_config_get_string(the_repository,
|
||||||
|
"uploadpack.blobpackfileuri",
|
||||||
|
&str) &&
|
||||||
|
str) {
|
||||||
|
strbuf_addstr(value, " packfile-uris");
|
||||||
|
free(str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user