Skip to content

Commit f936c9b

Browse files
committed
Merge branch 'jk/daemon-fixes' into maint
Assorted fixes to "git daemon". * jk/daemon-fixes: daemon: fix length computation in newline stripping t/lib-git-daemon: add network-protocol helpers daemon: handle NULs in extended attribute string daemon: fix off-by-one in logging extended attributes t/lib-git-daemon: record daemon log t5570: use ls-remote instead of clone for interp tests
2 parents b0e0fc2 + ed15e58 commit f936c9b

File tree

4 files changed

+107
-20
lines changed

4 files changed

+107
-20
lines changed

daemon.c

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,7 @@ static char *parse_host_arg(struct hostinfo *hi, char *extra_args, int buflen)
597597
if (strncasecmp("host=", extra_args, 5) == 0) {
598598
val = extra_args + 5;
599599
vallen = strlen(val) + 1;
600+
loginfo("Extended attribute \"host\": %s", val);
600601
if (*val) {
601602
/* Split <host>:<port> at colon. */
602603
char *host;
@@ -647,9 +648,11 @@ static void parse_extra_args(struct hostinfo *hi, struct argv_array *env,
647648
}
648649
}
649650

650-
if (git_protocol.len > 0)
651+
if (git_protocol.len > 0) {
652+
loginfo("Extended attribute \"protocol\": %s", git_protocol.buf);
651653
argv_array_pushf(env, GIT_PROTOCOL_ENVIRONMENT "=%s",
652654
git_protocol.buf);
655+
}
653656
strbuf_release(&git_protocol);
654657
}
655658

@@ -757,14 +760,8 @@ static int execute(void)
757760
alarm(0);
758761

759762
len = strlen(line);
760-
if (pktlen != len)
761-
loginfo("Extended attributes (%d bytes) exist <%.*s>",
762-
(int) pktlen - len,
763-
(int) pktlen - len, line + len + 1);
764-
if (len && line[len-1] == '\n') {
765-
line[--len] = 0;
766-
pktlen--;
767-
}
763+
if (len && line[len-1] == '\n')
764+
line[len-1] = 0;
768765

769766
/* parse additional args hidden behind a NUL byte */
770767
if (len != pktlen)

t/lib-git-daemon.sh

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ LIB_GIT_DAEMON_PORT=${LIB_GIT_DAEMON_PORT-${this_test#t}}
3232

3333
GIT_DAEMON_PID=
3434
GIT_DAEMON_DOCUMENT_ROOT_PATH="$PWD"/repo
35-
GIT_DAEMON_URL=git://127.0.0.1:$LIB_GIT_DAEMON_PORT
35+
GIT_DAEMON_HOST_PORT=127.0.0.1:$LIB_GIT_DAEMON_PORT
36+
GIT_DAEMON_URL=git://$GIT_DAEMON_HOST_PORT
3637

3738
start_git_daemon() {
3839
if test -n "$GIT_DAEMON_PID"
@@ -53,11 +54,19 @@ start_git_daemon() {
5354
"$@" "$GIT_DAEMON_DOCUMENT_ROOT_PATH" \
5455
>&3 2>git_daemon_output &
5556
GIT_DAEMON_PID=$!
57+
>daemon.log
5658
{
57-
read line <&7
58-
echo >&4 "$line"
59-
cat <&7 >&4 &
60-
} 7<git_daemon_output &&
59+
read -r line <&7
60+
printf "%s\n" "$line"
61+
printf >&4 "%s\n" "$line"
62+
(
63+
while read -r line <&7
64+
do
65+
printf "%s\n" "$line"
66+
printf >&4 "%s\n" "$line"
67+
done
68+
) &
69+
} 7<git_daemon_output >>"$TRASH_DIRECTORY/daemon.log" &&
6170

6271
# Check expected output
6372
if test x"$(expr "$line" : "\[[0-9]*\] \(.*\)")" != x"Ready to rumble"
@@ -90,3 +99,25 @@ stop_git_daemon() {
9099
GIT_DAEMON_PID=
91100
rm -f git_daemon_output
92101
}
102+
103+
# A stripped-down version of a netcat client, that connects to a "host:port"
104+
# given in $1, sends its stdin followed by EOF, then dumps the response (until
105+
# EOF) to stdout.
106+
fake_nc() {
107+
if ! test_declared_prereq FAKENC
108+
then
109+
echo >&4 "fake_nc: need to declare FAKENC prerequisite"
110+
return 127
111+
fi
112+
perl -Mstrict -MIO::Socket::INET -e '
113+
my $s = IO::Socket::INET->new(shift)
114+
or die "unable to open socket: $!";
115+
print $s <STDIN>;
116+
$s->shutdown(1);
117+
print <$s>;
118+
' "$@"
119+
}
120+
121+
test_lazy_prereq FAKENC '
122+
perl -MIO::Socket::INET -e "exit 0"
123+
'

t/t5570-git-daemon.sh

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -167,23 +167,48 @@ test_expect_success 'access repo via interpolated hostname' '
167167
git init --bare "$repo" &&
168168
git push "$repo" HEAD &&
169169
>"$repo"/git-daemon-export-ok &&
170-
rm -rf tmp.git &&
171170
GIT_OVERRIDE_VIRTUAL_HOST=localhost \
172-
git clone --bare "$GIT_DAEMON_URL/interp.git" tmp.git &&
173-
rm -rf tmp.git &&
171+
git ls-remote "$GIT_DAEMON_URL/interp.git" &&
174172
GIT_OVERRIDE_VIRTUAL_HOST=LOCALHOST \
175-
git clone --bare "$GIT_DAEMON_URL/interp.git" tmp.git
173+
git ls-remote "$GIT_DAEMON_URL/interp.git"
176174
'
177175

178176
test_expect_success 'hostname cannot break out of directory' '
179-
rm -rf tmp.git &&
180177
repo="$GIT_DAEMON_DOCUMENT_ROOT_PATH/../escape.git" &&
181178
git init --bare "$repo" &&
182179
git push "$repo" HEAD &&
183180
>"$repo"/git-daemon-export-ok &&
184181
test_must_fail \
185182
env GIT_OVERRIDE_VIRTUAL_HOST=.. \
186-
git clone --bare "$GIT_DAEMON_URL/escape.git" tmp.git
183+
git ls-remote "$GIT_DAEMON_URL/escape.git"
184+
'
185+
186+
test_expect_success 'daemon log records all attributes' '
187+
cat >expect <<-\EOF &&
188+
Extended attribute "host": localhost
189+
Extended attribute "protocol": version=1
190+
EOF
191+
>daemon.log &&
192+
GIT_OVERRIDE_VIRTUAL_HOST=localhost \
193+
git -c protocol.version=1 \
194+
ls-remote "$GIT_DAEMON_URL/interp.git" &&
195+
grep -i extended.attribute daemon.log | cut -d" " -f2- >actual &&
196+
test_cmp expect actual
197+
'
198+
199+
test_expect_success FAKENC 'hostname interpolation works after LF-stripping' '
200+
{
201+
printf "git-upload-pack /interp.git\n\0host=localhost" | packetize
202+
printf "0000"
203+
} >input &&
204+
fake_nc "$GIT_DAEMON_HOST_PORT" <input >output &&
205+
depacketize <output >output.raw &&
206+
207+
# just pick out the value of master, which avoids any protocol
208+
# particulars
209+
perl -lne "print \$1 if m{^(\\S+) refs/heads/master}" <output.raw >actual &&
210+
git -C "$repo" rev-parse master >expect &&
211+
test_cmp expect actual
187212
'
188213

189214
stop_git_daemon

t/test-lib-functions.sh

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,3 +1020,37 @@ nongit () {
10201020
"$@"
10211021
)
10221022
}
1023+
1024+
# convert stdin to pktline representation; note that empty input becomes an
1025+
# empty packet, not a flush packet (for that you can just print 0000 yourself).
1026+
packetize() {
1027+
cat >packetize.tmp &&
1028+
len=$(wc -c <packetize.tmp) &&
1029+
printf '%04x%s' "$(($len + 4))" &&
1030+
cat packetize.tmp &&
1031+
rm -f packetize.tmp
1032+
}
1033+
1034+
# Parse the input as a series of pktlines, writing the result to stdout.
1035+
# Sideband markers are removed automatically, and the output is routed to
1036+
# stderr if appropriate.
1037+
#
1038+
# NUL bytes are converted to "\\0" for ease of parsing with text tools.
1039+
depacketize () {
1040+
perl -e '
1041+
while (read(STDIN, $len, 4) == 4) {
1042+
if ($len eq "0000") {
1043+
print "FLUSH\n";
1044+
} else {
1045+
read(STDIN, $buf, hex($len) - 4);
1046+
$buf =~ s/\0/\\0/g;
1047+
if ($buf =~ s/^[\x2\x3]//) {
1048+
print STDERR $buf;
1049+
} else {
1050+
$buf =~ s/^\x1//;
1051+
print $buf;
1052+
}
1053+
}
1054+
}
1055+
'
1056+
}

0 commit comments

Comments
 (0)