summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--connect.c37
-rwxr-xr-xt/t5700-protocol-v1.sh223
2 files changed, 255 insertions, 5 deletions
diff --git a/connect.c b/connect.c
index a5e708a618..b8695a2fa2 100644
--- a/connect.c
+++ b/connect.c
@@ -871,6 +871,7 @@ struct child_process *git_connect(int fd[2], const char *url,
printf("Diag: path=%s\n", path ? path : "NULL");
conn = NULL;
} else if (protocol == PROTO_GIT) {
+ struct strbuf request = STRBUF_INIT;
/*
* Set up virtual host information based on where we will
* connect, unless the user has overridden us in
@@ -898,13 +899,25 @@ struct child_process *git_connect(int fd[2], const char *url,
* Note: Do not add any other headers here! Doing so
* will cause older git-daemon servers to crash.
*/
- packet_write_fmt(fd[1],
- "%s %s%chost=%s%c",
- prog, path, 0,
- target_host, 0);
+ strbuf_addf(&request,
+ "%s %s%chost=%s%c",
+ prog, path, 0,
+ target_host, 0);
+
+ /* If using a new version put that stuff here after a second null byte */
+ if (get_protocol_version_config() > 0) {
+ strbuf_addch(&request, '\0');
+ strbuf_addf(&request, "version=%d%c",
+ get_protocol_version_config(), '\0');
+ }
+
+ packet_write(fd[1], request.buf, request.len);
+
free(target_host);
+ strbuf_release(&request);
} else {
struct strbuf cmd = STRBUF_INIT;
+ const char *const *var;
conn = xmalloc(sizeof(*conn));
child_process_init(conn);
@@ -917,7 +930,9 @@ struct child_process *git_connect(int fd[2], const char *url,
sq_quote_buf(&cmd, path);
/* remove repo-local variables from the environment */
- conn->env = local_repo_env;
+ for (var = local_repo_env; *var; var++)
+ argv_array_push(&conn->env_array, *var);
+
conn->use_shell = 1;
conn->in = conn->out = -1;
if (protocol == PROTO_SSH) {
@@ -971,6 +986,14 @@ struct child_process *git_connect(int fd[2], const char *url,
}
argv_array_push(&conn->args, ssh);
+
+ if (get_protocol_version_config() > 0) {
+ argv_array_push(&conn->args, "-o");
+ argv_array_push(&conn->args, "SendEnv=" GIT_PROTOCOL_ENVIRONMENT);
+ argv_array_pushf(&conn->env_array, GIT_PROTOCOL_ENVIRONMENT "=version=%d",
+ get_protocol_version_config());
+ }
+
if (flags & CONNECT_IPV4)
argv_array_push(&conn->args, "-4");
else if (flags & CONNECT_IPV6)
@@ -985,6 +1008,10 @@ struct child_process *git_connect(int fd[2], const char *url,
argv_array_push(&conn->args, ssh_host);
} else {
transport_check_allowed("file");
+ if (get_protocol_version_config() > 0) {
+ argv_array_pushf(&conn->env_array, GIT_PROTOCOL_ENVIRONMENT "=version=%d",
+ get_protocol_version_config());
+ }
}
argv_array_push(&conn->args, cmd.buf);
diff --git a/t/t5700-protocol-v1.sh b/t/t5700-protocol-v1.sh
new file mode 100755
index 0000000000..6551932da9
--- /dev/null
+++ b/t/t5700-protocol-v1.sh
@@ -0,0 +1,223 @@
+#!/bin/sh
+
+test_description='test git wire-protocol transition'
+
+TEST_NO_CREATE_REPO=1
+
+. ./test-lib.sh
+
+# Test protocol v1 with 'git://' transport
+#
+. "$TEST_DIRECTORY"/lib-git-daemon.sh
+start_git_daemon --export-all --enable=receive-pack
+daemon_parent=$GIT_DAEMON_DOCUMENT_ROOT_PATH/parent
+
+test_expect_success 'create repo to be served by git-daemon' '
+ git init "$daemon_parent" &&
+ test_commit -C "$daemon_parent" one
+'
+
+test_expect_success 'clone with git:// using protocol v1' '
+ GIT_TRACE_PACKET=1 git -c protocol.version=1 \
+ clone "$GIT_DAEMON_URL/parent" daemon_child 2>log &&
+
+ git -C daemon_child log -1 --format=%s >actual &&
+ git -C "$daemon_parent" log -1 --format=%s >expect &&
+ test_cmp expect actual &&
+
+ # Client requested to use protocol v1
+ grep "clone> .*\\\0\\\0version=1\\\0$" log &&
+ # Server responded using protocol v1
+ grep "clone< version 1" log
+'
+
+test_expect_success 'fetch with git:// using protocol v1' '
+ test_commit -C "$daemon_parent" two &&
+
+ GIT_TRACE_PACKET=1 git -C daemon_child -c protocol.version=1 \
+ fetch 2>log &&
+
+ git -C daemon_child log -1 --format=%s origin/master >actual &&
+ git -C "$daemon_parent" log -1 --format=%s >expect &&
+ test_cmp expect actual &&
+
+ # Client requested to use protocol v1
+ grep "fetch> .*\\\0\\\0version=1\\\0$" log &&
+ # Server responded using protocol v1
+ grep "fetch< version 1" log
+'
+
+test_expect_success 'pull with git:// using protocol v1' '
+ GIT_TRACE_PACKET=1 git -C daemon_child -c protocol.version=1 \
+ pull 2>log &&
+
+ git -C daemon_child log -1 --format=%s >actual &&
+ git -C "$daemon_parent" log -1 --format=%s >expect &&
+ test_cmp expect actual &&
+
+ # Client requested to use protocol v1
+ grep "fetch> .*\\\0\\\0version=1\\\0$" log &&
+ # Server responded using protocol v1
+ grep "fetch< version 1" log
+'
+
+test_expect_success 'push with git:// using protocol v1' '
+ test_commit -C daemon_child three &&
+
+ # Push to another branch, as the target repository has the
+ # master branch checked out and we cannot push into it.
+ GIT_TRACE_PACKET=1 git -C daemon_child -c protocol.version=1 \
+ push origin HEAD:client_branch 2>log &&
+
+ git -C daemon_child log -1 --format=%s >actual &&
+ git -C "$daemon_parent" log -1 --format=%s client_branch >expect &&
+ test_cmp expect actual &&
+
+ # Client requested to use protocol v1
+ grep "push> .*\\\0\\\0version=1\\\0$" log &&
+ # Server responded using protocol v1
+ grep "push< version 1" log
+'
+
+stop_git_daemon
+
+# Test protocol v1 with 'file://' transport
+#
+test_expect_success 'create repo to be served by file:// transport' '
+ git init file_parent &&
+ test_commit -C file_parent one
+'
+
+test_expect_success 'clone with file:// using protocol v1' '
+ GIT_TRACE_PACKET=1 git -c protocol.version=1 \
+ clone "file://$(pwd)/file_parent" file_child 2>log &&
+
+ git -C file_child log -1 --format=%s >actual &&
+ git -C file_parent log -1 --format=%s >expect &&
+ test_cmp expect actual &&
+
+ # Server responded using protocol v1
+ grep "clone< version 1" log
+'
+
+test_expect_success 'fetch with file:// using protocol v1' '
+ test_commit -C file_parent two &&
+
+ GIT_TRACE_PACKET=1 git -C file_child -c protocol.version=1 \
+ fetch 2>log &&
+
+ git -C file_child log -1 --format=%s origin/master >actual &&
+ git -C file_parent log -1 --format=%s >expect &&
+ test_cmp expect actual &&
+
+ # Server responded using protocol v1
+ grep "fetch< version 1" log
+'
+
+test_expect_success 'pull with file:// using protocol v1' '
+ GIT_TRACE_PACKET=1 git -C file_child -c protocol.version=1 \
+ pull 2>log &&
+
+ git -C file_child log -1 --format=%s >actual &&
+ git -C file_parent log -1 --format=%s >expect &&
+ test_cmp expect actual &&
+
+ # Server responded using protocol v1
+ grep "fetch< version 1" log
+'
+
+test_expect_success 'push with file:// using protocol v1' '
+ test_commit -C file_child three &&
+
+ # Push to another branch, as the target repository has the
+ # master branch checked out and we cannot push into it.
+ GIT_TRACE_PACKET=1 git -C file_child -c protocol.version=1 \
+ push origin HEAD:client_branch 2>log &&
+
+ git -C file_child log -1 --format=%s >actual &&
+ git -C file_parent log -1 --format=%s client_branch >expect &&
+ test_cmp expect actual &&
+
+ # Server responded using protocol v1
+ grep "push< version 1" log
+'
+
+# Test protocol v1 with 'ssh://' transport
+#
+test_expect_success 'setup ssh wrapper' '
+ GIT_SSH="$GIT_BUILD_DIR/t/helper/test-fake-ssh" &&
+ export GIT_SSH &&
+ export TRASH_DIRECTORY &&
+ >"$TRASH_DIRECTORY"/ssh-output
+'
+
+expect_ssh () {
+ test_when_finished '(cd "$TRASH_DIRECTORY" && rm -f ssh-expect && >ssh-output)' &&
+ echo "ssh: -o SendEnv=GIT_PROTOCOL myhost $1 '$PWD/ssh_parent'" >"$TRASH_DIRECTORY/ssh-expect" &&
+ (cd "$TRASH_DIRECTORY" && test_cmp ssh-expect ssh-output)
+}
+
+test_expect_success 'create repo to be served by ssh:// transport' '
+ git init ssh_parent &&
+ test_commit -C ssh_parent one
+'
+
+test_expect_success 'clone with ssh:// using protocol v1' '
+ GIT_TRACE_PACKET=1 git -c protocol.version=1 \
+ clone "ssh://myhost:$(pwd)/ssh_parent" ssh_child 2>log &&
+ expect_ssh git-upload-pack &&
+
+ git -C ssh_child log -1 --format=%s >actual &&
+ git -C ssh_parent log -1 --format=%s >expect &&
+ test_cmp expect actual &&
+
+ # Server responded using protocol v1
+ grep "clone< version 1" log
+'
+
+test_expect_success 'fetch with ssh:// using protocol v1' '
+ test_commit -C ssh_parent two &&
+
+ GIT_TRACE_PACKET=1 git -C ssh_child -c protocol.version=1 \
+ fetch 2>log &&
+ expect_ssh git-upload-pack &&
+
+ git -C ssh_child log -1 --format=%s origin/master >actual &&
+ git -C ssh_parent log -1 --format=%s >expect &&
+ test_cmp expect actual &&
+
+ # Server responded using protocol v1
+ grep "fetch< version 1" log
+'
+
+test_expect_success 'pull with ssh:// using protocol v1' '
+ GIT_TRACE_PACKET=1 git -C ssh_child -c protocol.version=1 \
+ pull 2>log &&
+ expect_ssh git-upload-pack &&
+
+ git -C ssh_child log -1 --format=%s >actual &&
+ git -C ssh_parent log -1 --format=%s >expect &&
+ test_cmp expect actual &&
+
+ # Server responded using protocol v1
+ grep "fetch< version 1" log
+'
+
+test_expect_success 'push with ssh:// using protocol v1' '
+ test_commit -C ssh_child three &&
+
+ # Push to another branch, as the target repository has the
+ # master branch checked out and we cannot push into it.
+ GIT_TRACE_PACKET=1 git -C ssh_child -c protocol.version=1 \
+ push origin HEAD:client_branch 2>log &&
+ expect_ssh git-receive-pack &&
+
+ git -C ssh_child log -1 --format=%s >actual &&
+ git -C ssh_parent log -1 --format=%s client_branch >expect &&
+ test_cmp expect actual &&
+
+ # Server responded using protocol v1
+ grep "push< version 1" log
+'
+
+test_done