Merge branch 'jx/remote-archive-over-smart-http'

"git archive --remote=<remote>" learned to talk over the smart
http (aka stateless) transport.

* jx/remote-archive-over-smart-http:
  transport-helper: call do_take_over() in process_connect
  transport-helper: call do_take_over() in connect_helper
  http-backend: new rpc-service for git-upload-archive
  transport-helper: protocol v2 supports upload-archive
  remote-curl: supports git-upload-archive service
  transport-helper: no connection restriction in connect_helper
This commit is contained in:
Junio C Hamano
2024-01-30 13:34:12 -08:00
4 changed files with 68 additions and 22 deletions

View File

@ -38,6 +38,7 @@ struct rpc_service {
static struct rpc_service rpc_service[] = { static struct rpc_service rpc_service[] = {
{ "upload-pack", "uploadpack", 1, 1 }, { "upload-pack", "uploadpack", 1, 1 },
{ "receive-pack", "receivepack", 0, -1 }, { "receive-pack", "receivepack", 0, -1 },
{ "upload-archive", "uploadarchive", 0, -1 },
}; };
static struct string_list *get_parameters(void) static struct string_list *get_parameters(void)
@ -639,10 +640,15 @@ static void check_content_type(struct strbuf *hdr, const char *accepted_type)
static void service_rpc(struct strbuf *hdr, char *service_name) static void service_rpc(struct strbuf *hdr, char *service_name)
{ {
const char *argv[] = {NULL, "--stateless-rpc", ".", NULL}; struct strvec argv = STRVEC_INIT;
struct rpc_service *svc = select_service(hdr, service_name); struct rpc_service *svc = select_service(hdr, service_name);
struct strbuf buf = STRBUF_INIT; struct strbuf buf = STRBUF_INIT;
strvec_push(&argv, svc->name);
if (strcmp(service_name, "git-upload-archive"))
strvec_push(&argv, "--stateless-rpc");
strvec_push(&argv, ".");
strbuf_reset(&buf); strbuf_reset(&buf);
strbuf_addf(&buf, "application/x-git-%s-request", svc->name); strbuf_addf(&buf, "application/x-git-%s-request", svc->name);
check_content_type(hdr, buf.buf); check_content_type(hdr, buf.buf);
@ -655,9 +661,9 @@ static void service_rpc(struct strbuf *hdr, char *service_name)
end_headers(hdr); end_headers(hdr);
argv[0] = svc->name; run_service(argv.v, svc->buffer_input);
run_service(argv, svc->buffer_input);
strbuf_release(&buf); strbuf_release(&buf);
strvec_clear(&argv);
} }
static int dead; static int dead;
@ -723,6 +729,7 @@ static struct service_cmd {
{"GET", "/objects/pack/pack-[0-9a-f]{64}\\.idx$", get_idx_file}, {"GET", "/objects/pack/pack-[0-9a-f]{64}\\.idx$", get_idx_file},
{"POST", "/git-upload-pack$", service_rpc}, {"POST", "/git-upload-pack$", service_rpc},
{"POST", "/git-upload-archive$", service_rpc},
{"POST", "/git-receive-pack$", service_rpc} {"POST", "/git-receive-pack$", service_rpc}
}; };

View File

@ -1446,8 +1446,14 @@ static int stateless_connect(const char *service_name)
* establish a stateless connection, otherwise we need to tell the * establish a stateless connection, otherwise we need to tell the
* client to fallback to using other transport helper functions to * client to fallback to using other transport helper functions to
* complete their request. * complete their request.
*
* The "git-upload-archive" service is a read-only operation. Fallback
* to use "git-upload-pack" service to discover protocol version.
*/ */
discover = discover_refs(service_name, 0); if (!strcmp(service_name, "git-upload-archive"))
discover = discover_refs("git-upload-pack", 0);
else
discover = discover_refs(service_name, 0);
if (discover->version != protocol_v2) { if (discover->version != protocol_v2) {
printf("fallback\n"); printf("fallback\n");
fflush(stdout); fflush(stdout);
@ -1485,9 +1491,11 @@ static int stateless_connect(const char *service_name)
/* /*
* Dump the capability listing that we got from the server earlier * Dump the capability listing that we got from the server earlier
* during the info/refs request. * during the info/refs request. This does not work with the
* "git-upload-archive" service.
*/ */
write_or_die(rpc.in, discover->buf, discover->len); if (strcmp(service_name, "git-upload-archive"))
write_or_die(rpc.in, discover->buf, discover->len);
/* Until we see EOF keep sending POSTs */ /* Until we see EOF keep sending POSTs */
while (1) { while (1) {

View File

@ -239,4 +239,38 @@ check_zip with_untracked2
check_added with_untracked2 untracked one/untracked check_added with_untracked2 untracked one/untracked
check_added with_untracked2 untracked two/untracked check_added with_untracked2 untracked two/untracked
# Test remote archive over HTTP protocol.
#
# Note: this should be the last part of this test suite, because
# by including lib-httpd.sh, the test may end early if httpd tests
# should not be run.
#
. "$TEST_DIRECTORY"/lib-httpd.sh
start_httpd
test_expect_success "setup for HTTP protocol" '
cp -R bare.git "$HTTPD_DOCUMENT_ROOT_PATH/bare.git" &&
git -C "$HTTPD_DOCUMENT_ROOT_PATH/bare.git" \
config http.uploadpack true &&
set_askpass user@host pass@host
'
setup_askpass_helper
test_expect_success 'remote archive does not work with protocol v1' '
test_must_fail git -c protocol.version=1 archive \
--remote="$HTTPD_URL/auth/smart/bare.git" \
--output=remote-http.zip HEAD >actual 2>&1 &&
cat >expect <<-EOF &&
fatal: can${SQ}t connect to subservice git-upload-archive
EOF
test_cmp expect actual
'
test_expect_success 'archive remote http repository' '
git archive --remote="$HTTPD_URL/auth/smart/bare.git" \
--output=remote-http.zip HEAD &&
test_cmp_bin d.zip remote-http.zip
'
test_done test_done

View File

@ -626,7 +626,8 @@ static int process_connect_service(struct transport *transport,
ret = run_connect(transport, &cmdbuf); ret = run_connect(transport, &cmdbuf);
} else if (data->stateless_connect && } else if (data->stateless_connect &&
(get_protocol_version_config() == protocol_v2) && (get_protocol_version_config() == protocol_v2) &&
!strcmp("git-upload-pack", name)) { (!strcmp("git-upload-pack", name) ||
!strcmp("git-upload-archive", name))) {
strbuf_addf(&cmdbuf, "stateless-connect %s\n", name); strbuf_addf(&cmdbuf, "stateless-connect %s\n", name);
ret = run_connect(transport, &cmdbuf); ret = run_connect(transport, &cmdbuf);
if (ret) if (ret)
@ -643,6 +644,7 @@ static int process_connect(struct transport *transport,
struct helper_data *data = transport->data; struct helper_data *data = transport->data;
const char *name; const char *name;
const char *exec; const char *exec;
int ret;
name = for_push ? "git-receive-pack" : "git-upload-pack"; name = for_push ? "git-receive-pack" : "git-upload-pack";
if (for_push) if (for_push)
@ -650,7 +652,10 @@ static int process_connect(struct transport *transport,
else else
exec = data->transport_options.uploadpack; exec = data->transport_options.uploadpack;
return process_connect_service(transport, name, exec); ret = process_connect_service(transport, name, exec);
if (ret)
do_take_over(transport);
return ret;
} }
static int connect_helper(struct transport *transport, const char *name, static int connect_helper(struct transport *transport, const char *name,
@ -660,14 +665,14 @@ static int connect_helper(struct transport *transport, const char *name,
/* Get_helper so connect is inited. */ /* Get_helper so connect is inited. */
get_helper(transport); get_helper(transport);
if (!data->connect)
die(_("operation not supported by protocol"));
if (!process_connect_service(transport, name, exec)) if (!process_connect_service(transport, name, exec))
die(_("can't connect to subservice %s"), name); die(_("can't connect to subservice %s"), name);
fd[0] = data->helper->out; fd[0] = data->helper->out;
fd[1] = data->helper->in; fd[1] = data->helper->in;
do_take_over(transport);
return 0; return 0;
} }
@ -682,10 +687,8 @@ static int fetch_refs(struct transport *transport,
get_helper(transport); get_helper(transport);
if (process_connect(transport, 0)) { if (process_connect(transport, 0))
do_take_over(transport);
return transport->vtable->fetch_refs(transport, nr_heads, to_fetch); return transport->vtable->fetch_refs(transport, nr_heads, to_fetch);
}
/* /*
* If we reach here, then the server, the client, and/or the transport * If we reach here, then the server, the client, and/or the transport
@ -1142,10 +1145,8 @@ static int push_refs(struct transport *transport,
{ {
struct helper_data *data = transport->data; struct helper_data *data = transport->data;
if (process_connect(transport, 1)) { if (process_connect(transport, 1))
do_take_over(transport);
return transport->vtable->push_refs(transport, remote_refs, flags); return transport->vtable->push_refs(transport, remote_refs, flags);
}
if (!remote_refs) { if (!remote_refs) {
fprintf(stderr, fprintf(stderr,
@ -1186,11 +1187,9 @@ static struct ref *get_refs_list(struct transport *transport, int for_push,
{ {
get_helper(transport); get_helper(transport);
if (process_connect(transport, for_push)) { if (process_connect(transport, for_push))
do_take_over(transport);
return transport->vtable->get_refs_list(transport, for_push, return transport->vtable->get_refs_list(transport, for_push,
transport_options); transport_options);
}
return get_refs_list_using_list(transport, for_push); return get_refs_list_using_list(transport, for_push);
} }
@ -1274,10 +1273,8 @@ static int get_bundle_uri(struct transport *transport)
{ {
get_helper(transport); get_helper(transport);
if (process_connect(transport, 0)) { if (process_connect(transport, 0))
do_take_over(transport);
return transport->vtable->get_bundle_uri(transport); return transport->vtable->get_bundle_uri(transport);
}
return -1; return -1;
} }