diff options
author | Junio C Hamano <gitster@pobox.com> | 2011-05-20 07:37:20 +0400 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2011-05-20 07:37:20 +0400 |
commit | a66fae3827d4bf39ddfdc19bbb818d67e2a3c20a (patch) | |
tree | 9466bc040243464bfc29c60b6f92ce4d33acd4c5 | |
parent | 5c359a66586cfa802f9a4b205da9750582bdb9ec (diff) | |
parent | c7730e6f5f5757ac278319f33b94c32458e21f12 (diff) |
Merge branch 'jk/git-connection-deadlock-fix'
* jk/git-connection-deadlock-fix:
test core.gitproxy configuration
send-pack: avoid deadlock on git:// push with failed pack-objects
connect: let callers know if connection is a socket
connect: treat generic proxy processes like ssh processes
Conflicts:
connect.c
-rw-r--r-- | builtin/send-pack.c | 2 | ||||
-rw-r--r-- | cache.h | 1 | ||||
-rw-r--r-- | connect.c | 35 | ||||
-rwxr-xr-x | t/t5532-fetch-proxy.sh | 43 |
4 files changed, 67 insertions, 14 deletions
diff --git a/builtin/send-pack.c b/builtin/send-pack.c index e6a3495e1c..c1f6ddd927 100644 --- a/builtin/send-pack.c +++ b/builtin/send-pack.c @@ -344,6 +344,8 @@ int send_pack(struct send_pack_args *args, ref->status = REF_STATUS_NONE; if (args->stateless_rpc) close(out); + if (git_connection_is_socket(conn)) + shutdown(fd[0], SHUT_WR); if (use_sideband) finish_async(&demux); return -1; @@ -975,6 +975,7 @@ extern struct ref *find_ref_by_name(const struct ref *list, const char *name); extern char *git_getpass(const char *prompt); extern struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags); extern int finish_connect(struct child_process *conn); +extern int git_connection_is_socket(struct child_process *conn); extern int path_match(const char *path, int nr, char **match); struct extra_have_objects { int nr, alloc; @@ -395,26 +395,28 @@ static int git_use_proxy(const char *host) return (git_proxy_command && *git_proxy_command); } -static void git_proxy_connect(int fd[2], char *host) +static struct child_process *git_proxy_connect(int fd[2], char *host) { const char *port = STR(DEFAULT_GIT_PORT); - const char *argv[4]; - struct child_process proxy; + const char **argv; + struct child_process *proxy; get_host_and_port(&host, &port); + argv = xmalloc(sizeof(*argv) * 4); argv[0] = git_proxy_command; argv[1] = host; argv[2] = port; argv[3] = NULL; - memset(&proxy, 0, sizeof(proxy)); - proxy.argv = argv; - proxy.in = -1; - proxy.out = -1; - if (start_command(&proxy)) + proxy = xcalloc(1, sizeof(*proxy)); + proxy->argv = argv; + proxy->in = -1; + proxy->out = -1; + if (start_command(proxy)) die("cannot start proxy %s", argv[0]); - fd[0] = proxy.out; /* read from proxy stdout */ - fd[1] = proxy.in; /* write to proxy stdin */ + fd[0] = proxy->out; /* read from proxy stdout */ + fd[1] = proxy->in; /* write to proxy stdin */ + return proxy; } #define MAX_CMD_LEN 1024 @@ -455,7 +457,7 @@ struct child_process *git_connect(int fd[2], const char *url_orig, char *host, *path; char *end; int c; - struct child_process *conn; + struct child_process *conn = &no_fork; enum protocol protocol = PROTO_LOCAL; int free_path = 0; char *port = NULL; @@ -540,7 +542,7 @@ struct child_process *git_connect(int fd[2], const char *url_orig, */ char *target_host = xstrdup(host); if (git_use_proxy(host)) - git_proxy_connect(fd, host); + conn = git_proxy_connect(fd, host); else git_tcp_connect(fd, host, flags); /* @@ -558,7 +560,7 @@ struct child_process *git_connect(int fd[2], const char *url_orig, free(url); if (free_path) free(path); - return &no_fork; + return conn; } conn = xcalloc(1, sizeof(*conn)); @@ -607,10 +609,15 @@ struct child_process *git_connect(int fd[2], const char *url_orig, return conn; } +int git_connection_is_socket(struct child_process *conn) +{ + return conn == &no_fork; +} + int finish_connect(struct child_process *conn) { int code; - if (!conn || conn == &no_fork) + if (!conn || git_connection_is_socket(conn)) return 0; code = finish_command(conn); diff --git a/t/t5532-fetch-proxy.sh b/t/t5532-fetch-proxy.sh new file mode 100755 index 0000000000..62f2460047 --- /dev/null +++ b/t/t5532-fetch-proxy.sh @@ -0,0 +1,43 @@ +#!/bin/sh + +test_description='fetching via git:// using core.gitproxy' +. ./test-lib.sh + +test_expect_success 'setup remote repo' ' + git init remote && + (cd remote && + echo content >file && + git add file && + git commit -m one + ) +' + +cat >proxy <<'EOF' +#!/bin/sh +echo >&2 "proxying for $*" +cmd=`perl -e ' + read(STDIN, $buf, 4); + my $n = hex($buf) - 4; + read(STDIN, $buf, $n); + my ($cmd, $other) = split /\0/, $buf; + # drop absolute-path on repo name + $cmd =~ s{ /}{ }; + print $cmd; +'` +echo >&2 "Running '$cmd'" +exec $cmd +EOF +chmod +x proxy +test_expect_success 'setup local repo' ' + git remote add fake git://example.com/remote && + git config core.gitproxy ./proxy +' + +test_expect_success 'fetch through proxy works' ' + git fetch fake && + echo one >expect && + git log -1 --format=%s FETCH_HEAD >actual && + test_cmp expect actual +' + +test_done |