commit - 6e5370b0f38658d91de41782c4fec170db11606c
commit + c811fd62d1fbec7ac5e58e10b242c3d4f8b4cdb4
blob - 5e75f4801579643302462cdd46c22f21d2bf3880
blob + 772c35e98bb5ed0874ea08d5d0d4437001a7480e
--- gotd/session_read.c
+++ gotd/session_read.c
GOTD_STATE_EXPECT_LIST_REFS,
GOTD_STATE_EXPECT_CAPABILITIES,
GOTD_STATE_EXPECT_WANT,
- GOTD_STATE_EXPECT_HAVE,
- GOTD_STATE_EXPECT_DONE,
+ GOTD_STATE_EXPECT_HAVE_OR_DONE,
GOTD_STATE_DONE,
};
err = forward_want(client, &imsg);
break;
case GOTD_IMSG_HAVE:
- if (gotd_session.state != GOTD_STATE_EXPECT_HAVE) {
+ if (gotd_session.state !=
+ GOTD_STATE_EXPECT_HAVE_OR_DONE) {
err = got_error_msg(GOT_ERR_BAD_REQUEST,
"unexpected have-line received");
break;
break;
case GOTD_IMSG_FLUSH:
if (gotd_session.state != GOTD_STATE_EXPECT_WANT &&
- gotd_session.state != GOTD_STATE_EXPECT_HAVE &&
- gotd_session.state != GOTD_STATE_EXPECT_DONE) {
+ gotd_session.state !=
+ GOTD_STATE_EXPECT_HAVE_OR_DONE) {
err = got_error_msg(GOT_ERR_BAD_REQUEST,
"unexpected flush-pkt received");
break;
log_debug("received flush-pkt from uid %d",
client->euid);
if (gotd_session.state == GOTD_STATE_EXPECT_WANT) {
- gotd_session.state = GOTD_STATE_EXPECT_HAVE;
- log_debug("uid %d: expecting have-lines",
- client->euid);
- } else if (gotd_session.state == GOTD_STATE_EXPECT_HAVE) {
- gotd_session.state = GOTD_STATE_EXPECT_DONE;
+ gotd_session.state =
+ GOTD_STATE_EXPECT_HAVE_OR_DONE;
+ log_debug("uid %d: expecting have-lines "
+ "or 'done'", client->euid);
+ } else if (gotd_session.state ==
+ GOTD_STATE_EXPECT_HAVE_OR_DONE) {
client->accept_flush_pkt = 1;
- log_debug("uid %d: expecting 'done'",
- client->euid);
- } else if (gotd_session.state != GOTD_STATE_EXPECT_DONE) {
+ log_debug("uid %d: expecting more have-lines "
+ "or 'done'", client->euid);
+ } else if (gotd_session.state !=
+ GOTD_STATE_EXPECT_HAVE_OR_DONE) {
/* should not happen, see above */
err = got_error_msg(GOT_ERR_BAD_REQUEST,
"unexpected client state");
}
break;
case GOTD_IMSG_DONE:
- if (gotd_session.state != GOTD_STATE_EXPECT_HAVE &&
- gotd_session.state != GOTD_STATE_EXPECT_DONE) {
+ if (gotd_session.state !=
+ GOTD_STATE_EXPECT_HAVE_OR_DONE) {
err = got_error_msg(GOT_ERR_BAD_REQUEST,
"unexpected flush-pkt received");
break;
blob - 16d6eeece5252ed4c35915742908b5fda451090d
blob + e03137e6800e1939de4210d638076544517c3445
--- lib/serve.c
+++ lib/serve.c
enum protostate {
STATE_EXPECT_WANT,
STATE_EXPECT_MORE_WANT,
- STATE_EXPECT_HAVE,
- STATE_EXPECT_DONE,
+ STATE_EXPECT_HAVE_OR_DONE,
STATE_DONE,
};
enum protostate curstate = STATE_EXPECT_WANT;
if (n == 0) {
if (curstate != STATE_EXPECT_WANT &&
curstate != STATE_EXPECT_MORE_WANT &&
- curstate != STATE_EXPECT_HAVE &&
- curstate != STATE_EXPECT_DONE) {
+ curstate != STATE_EXPECT_HAVE_OR_DONE) {
err = got_error_msg(GOT_ERR_BAD_PACKET,
"unexpected flush packet received");
goto done;
if (curstate == STATE_EXPECT_WANT ||
curstate == STATE_EXPECT_MORE_WANT ||
- curstate == STATE_EXPECT_HAVE) {
+ curstate == STATE_EXPECT_HAVE_OR_DONE) {
err = forward_flushpkt(&ibuf);
if (err)
goto done;
}
- if (curstate == STATE_EXPECT_HAVE && !have_ack) {
+ if (curstate == STATE_EXPECT_HAVE_OR_DONE &&
+ !have_ack) {
err = send_nak(outfd, chattygot);
if (err)
goto done;
}
if (curstate == STATE_EXPECT_MORE_WANT)
- curstate = STATE_EXPECT_HAVE;
- else
- curstate = STATE_EXPECT_DONE;
+ curstate = STATE_EXPECT_HAVE_OR_DONE;
} else if (n >= 5 && strncmp(buf, "want ", 5) == 0) {
if (curstate != STATE_EXPECT_WANT &&
curstate != STATE_EXPECT_MORE_WANT) {
if (curstate == STATE_EXPECT_WANT)
curstate = STATE_EXPECT_MORE_WANT;
} else if (n >= 5 && strncmp(buf, "have ", 5) == 0) {
- if (curstate != STATE_EXPECT_HAVE &&
- curstate != STATE_EXPECT_DONE) {
+ if (curstate != STATE_EXPECT_HAVE_OR_DONE) {
err = got_error_msg(GOT_ERR_BAD_PACKET,
"unexpected 'have' packet");
goto done;
- }
- if (curstate == STATE_EXPECT_HAVE) {
- err = recv_have(&have_ack, outfd, &ibuf,
- buf, n, chattygot);
- if (err)
- goto done;
- seen_have = 1;
}
+ err = recv_have(&have_ack, outfd, &ibuf,
+ buf, n, chattygot);
+ if (err)
+ goto done;
+ seen_have = 1;
} else if (n == 5 && strncmp(buf, "done\n", 5) == 0) {
- if (curstate != STATE_EXPECT_HAVE &&
- curstate != STATE_EXPECT_DONE) {
+ if (curstate != STATE_EXPECT_HAVE_OR_DONE) {
err = got_error_msg(GOT_ERR_BAD_PACKET,
"unexpected 'done' packet");
goto done;
blob - c38bd07b843aa78426c9e628f609604a4d815417
blob + 4482c735241818f4fa534feaaf319e44c6d23018
--- regress/gotd/Makefile
+++ regress/gotd/Makefile
test_repo_read_bad_user test_repo_read_bad_group \
test_repo_write test_repo_write_empty test_request_bad \
test_repo_write_protected test_repo_write_readonly \
- test_email_notification test_http_notification
+ test_email_notification test_http_notification \
+ test_git_interop
NOOBJ=Yes
CLEANFILES=gotd.conf
'env $(GOTD_TEST_ENV) sh ./http_notification.sh'
@$(GOTD_STOP_CMD) 2>/dev/null
+test_git_interop: prepare_test_repo start_gotd_rw
+ @-$(GOTD_TRAP); su ${GOTD_TEST_USER} -c \
+ 'env $(GOTD_TEST_ENV) sh ./test_git_interop.sh'
+ @$(GOTD_STOP_CMD) 2>/dev/null
+ @su -m ${GOTD_USER} -c 'env $(GOTD_TEST_ENV) sh ./check_test_repo.sh'
+
.include <bsd.regress.mk>
blob - /dev/null
blob + 96d81eef9e29a430bae977c16bfab9eceb33997f (mode 644)
--- /dev/null
+++ regress/gotd/test_git_interop.sh
+#!/bin/sh
+#
+# Copyright (c) 2024 Stefan Sperling <stsp@openbsd.org>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+. ../cmdline/common.sh
+. ./common.sh
+
+test_fetch_with_git_history_walk() {
+ local testroot=`test_init fetch_with_git_history_walk 1`
+
+ git clone -q ${GOTD_TEST_REPO_URL} $testroot/repo-clone \
+ 2> $testroot/stderr
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "git clone failed unexpectedly" >&2
+ test_done "$testroot" "1"
+ return 1
+ fi
+
+ # Create new commits on a branch which doesn't exist in gotd repo.
+ # We want Git to send a flush-pkt followed by more have-lines. This
+ # requires at least 16 commits (fetch-pack.c:INITIAL_FLUSH 16).
+ git -C $testroot/repo-clone branch newbranch
+ for i in `seq 24`; do
+ echo $i >> $testroot/repo-clone/file$i
+ git -C $testroot/repo-clone add file$i
+ git_commit $testroot/repo-clone -m "add file$i"
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "git commit failed unexpectedly" >&2
+ test_done "$testroot" "1"
+ return 1
+ fi
+ done
+
+ git clone -q ${GOTD_TEST_REPO_URL} $testroot/repo-clone2 \
+ 2> $testroot/stderr
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "git clone failed unexpectedly" >&2
+ test_done "$testroot" "1"
+ return 1
+ fi
+
+ # create new commits on main branch, and push to gotd
+ for i in `seq 2`; do
+ echo $i >> $testroot/repo-clone2/file$i
+ git -C $testroot/repo-clone2 add file$i
+ git_commit $testroot/repo-clone2 -m "add file$i"
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "git commit failed unexpectedly" >&2
+ test_done "$testroot" "1"
+ return 1
+ fi
+ done
+
+ git -C $testroot/repo-clone2 push -q origin main
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "git push failed unexpectedly" >&2
+ test_done "$testroot" "1"
+ return 1
+ fi
+
+ # Fetching changes into the first repository clone should work.
+ # This used to fail because gotd rejected additional have-lines
+ # once Git had sent a flush-pkt.
+ git -C $testroot/repo-clone fetch -q 2> $testroot/stderr
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "git fetch failed unexpectedly" >&2
+ test_done "$testroot" "1"
+ return 1
+ fi
+
+ test_done "$testroot" "0"
+}
+
+run_test test_fetch_with_git_history_walk