remote-curl: add 'get' capability

A future change will want a way to download a file over HTTP(S) using the simplest of download mechanisms. We do not want to assume that the server on the other side understands anything about the Git protocol but could be a simple static web server. Create the new 'get' capability for the remote helpers which advertises that the 'get' command is avalable. A caller can send a line containing 'get <url> <path>' to download the file at <url> into the file at <path>. Reviewed-by: Josh Steadmon <steadmon@google.com> Signed-off-by: Derrick Stolee <derrickstolee@github.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Derrick Stolee committed Aug 9, 2022 at 13:11 UTC b5624a44744d6e5f9c749e4df02932c724e2097e
3 files changed +74
Documentation/gitremote-helpers.txt
+9
@@ -168,6 +168,9 @@ Supported commands: 'list', 'import'.
168 Can guarantee that when a clone is requested, the received
169 pack is self contained and is connected.
170
171 +'get'::
172 + Can use the 'get' command to download a file from a given URI.
173 +
174 If a helper advertises 'connect', Git will use it if possible and
175 fall back to another capability if the helper requests so when
176 connecting (see the 'connect' command under COMMANDS).
@@ -418,6 +421,12 @@ Supported if the helper has the "connect" capability.
421 +
422 Supported if the helper has the "stateless-connect" capability.
423
424 +'get' <uri> <path>::
425 + Downloads the file from the given `<uri>` to the given `<path>`. If
426 + `<path>.temp` exists, then Git assumes that the `.temp` file is a
427 + partial download from a previous attempt and will resume the
428 + download from that position.
429 +
430 If a fatal error occurs, the program writes the error message to
431 stderr and exits. The caller should expect that a suitable error
432 message has been printed if the child closes the connection without
remote-curl.c
+28
@@ -1286,6 +1286,29 @@ static void parse_fetch(struct strbuf *buf)
1286 strbuf_reset(buf);
1287 }
1288
1289 +static void parse_get(const char *arg)
1290 +{
1291 + struct strbuf url = STRBUF_INIT;
1292 + struct strbuf path = STRBUF_INIT;
1293 + const char *space;
1294 +
1295 + space = strchr(arg, ' ');
1296 +
1297 + if (!space)
1298 + die(_("protocol error: expected '<url> <path>', missing space"));
1299 +
1300 + strbuf_add(&url, arg, space - arg);
1301 + strbuf_addstr(&path, space + 1);
1302 +
1303 + if (http_get_file(url.buf, path.buf, NULL))
1304 + die(_("failed to download file at URL '%s'"), url.buf);
1305 +
1306 + strbuf_release(&url);
1307 + strbuf_release(&path);
1308 + printf("\n");
1309 + fflush(stdout);
1310 +}
1311 +
1312 static int push_dav(int nr_spec, const char **specs)
1313 {
1314 struct child_process child = CHILD_PROCESS_INIT;
@@ -1564,9 +1587,14 @@ int cmd_main(int argc, const char **argv)
1587 printf("unsupported\n");
1588 fflush(stdout);
1589
1590 + } else if (skip_prefix(buf.buf, "get ", &arg)) {
1591 + parse_get(arg);
1592 + fflush(stdout);
1593 +
1594 } else if (!strcmp(buf.buf, "capabilities")) {
1595 printf("stateless-connect\n");
1596 printf("fetch\n");
1597 + printf("get\n");
1598 printf("option\n");
1599 printf("push\n");
1600 printf("check-connectivity\n");
t/t5557-http-get.sh new
+37
@@ -0,0 +1,37 @@
1 +#!/bin/sh
2 +
3 +test_description='test downloading a file by URL'
4 +
5 +. ./test-lib.sh
6 +
7 +. "$TEST_DIRECTORY"/lib-httpd.sh
8 +start_httpd
9 +
10 +test_expect_success 'get by URL: 404' '
11 + test_when_finished "rm -f file.temp" &&
12 + url="$HTTPD_URL/none.txt" &&
13 + cat >input <<-EOF &&
14 + capabilities
15 + get $url file1
16 + EOF
17 +
18 + test_must_fail git remote-http $url <input 2>err &&
19 + test_path_is_missing file1 &&
20 + grep "failed to download file at URL" err
21 +'
22 +
23 +test_expect_success 'get by URL: 200' '
24 + echo data >"$HTTPD_DOCUMENT_ROOT_PATH/exists.txt" &&
25 +
26 + url="$HTTPD_URL/exists.txt" &&
27 + cat >input <<-EOF &&
28 + capabilities
29 + get $url file2
30 +
31 + EOF
32 +
33 + git remote-http $url <input &&
34 + test_cmp "$HTTPD_DOCUMENT_ROOT_PATH/exists.txt" file2
35 +'
36 +
37 +test_done