Skip to content

Commit 8eb8635

Browse files
chriscoolgitster
authored andcommitted
t5710: use proper file:// URIs for absolute paths
In t5710, we frequently construct local file URIs using `file://$(pwd)`. On Unix-like systems, $(pwd) returns an absolute path starting with a slash (e.g., `/tmp/repo`), resulting in a valid 3-slash URI with an empty host (`file:///tmp/repo`). However, on Windows, $(pwd) returns a path starting with a drive letter (e.g., `D:/a/repo`). This results in a 2-slash URI (`file://D:/a/repo`). Standard URI parsers misinterpret this format, treating `D:` as the host rather than part of the absolute path. This is to be expected because RFC 8089 says that the `//` prefix with an empty local host must be followed by an absolute path starting with a slash. While this hasn't broken the existing tests (because the old `promisor.acceptFromServer` logic relies entirely on strict `strcmp()` without normalizing the URLs), it will break future commits that pass these URLs through `url_normalize()` or similar functions. To future-proof the tests and ensure cross-platform URI compliance, let's introduce a $TRASH_DIRECTORY_URL helper variable that explicitly guarantees a leading slash for the path component, ensuring valid 3-slash `file:///` URIs on all operating systems. While at it, let's also introduce $ENCODED_TRASH_DIRECTORY_URL to handle some common special characters in directory paths. To be extra safe, let's skip all the tests if there are uncommon special characters in the directory path. Then let's replace all instances of `file://$(pwd)` with $TRASH_DIRECTORY_URL across the test script, and let's simplify the `sendFields` and `checkFields` tests to use $ENCODED_TRASH_DIRECTORY_URL directly. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent d56e483 commit 8eb8635

1 file changed

Lines changed: 51 additions & 28 deletions

File tree

t/t5710-promisor-remote-capability.sh

Lines changed: 51 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,31 @@ copy_to_lop () {
7676
cp "$path" "$path2"
7777
}
7878

79+
# On Windows, `pwd` returns a path like 'D:/foo/bar'. Prepend '/' to turn
80+
# it into '/D:/foo/bar', which is what git expects in file:// URLs on Windows.
81+
# On Unix, the path already starts with '/', so this is a no-op.
82+
pwd_path=$(pwd)
83+
case "$pwd_path" in
84+
[a-zA-Z]:*) pwd_path="/$pwd_path" ;;
85+
esac
86+
87+
# Allowed characters: alphanumeric, standard path/URI (_ . ~ / : -),
88+
# and those percent-encoded below (% space = , ;)
89+
rest=$(printf "%s" "$pwd_path" | tr -d 'a-zA-Z0-9_.~/:% =,;-')
90+
if test -n "$rest"
91+
then
92+
skip_all="PWD contains unsupported special characters"
93+
test_done
94+
fi
95+
96+
TRASH_DIRECTORY_URL="file://$pwd_path"
97+
98+
encoded_path=$(printf "%s" "$pwd_path" |
99+
sed -e 's/%/%25/g' -e 's/ /%20/g' -e 's/=/%3D/g' \
100+
-e 's/;/%3B/g' -e 's/,/%2C/g')
101+
102+
ENCODED_TRASH_DIRECTORY_URL="file://$encoded_path"
103+
79104
test_expect_success "setup for testing promisor remote advertisement" '
80105
# Create another bare repo called "lop" (for Large Object Promisor)
81106
git init --bare lop &&
@@ -88,7 +113,7 @@ test_expect_success "setup for testing promisor remote advertisement" '
88113
initialize_server 1 "$oid" &&
89114
90115
# Configure lop as promisor remote for server
91-
git -C server remote add lop "file://$(pwd)/lop" &&
116+
git -C server remote add lop "$TRASH_DIRECTORY_URL/lop" &&
92117
git -C server config remote.lop.promisor true &&
93118
94119
git -C lop config uploadpack.allowFilter true &&
@@ -104,7 +129,7 @@ test_expect_success "clone with promisor.advertise set to 'true'" '
104129
# Clone from server to create a client
105130
GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \
106131
-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
107-
-c remote.lop.url="file://$(pwd)/lop" \
132+
-c remote.lop.url="$TRASH_DIRECTORY_URL/lop" \
108133
-c promisor.acceptfromserver=All \
109134
--no-local --filter="blob:limit=5k" server client &&
110135
@@ -119,7 +144,7 @@ test_expect_success "clone with promisor.advertise set to 'false'" '
119144
# Clone from server to create a client
120145
GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \
121146
-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
122-
-c remote.lop.url="file://$(pwd)/lop" \
147+
-c remote.lop.url="$TRASH_DIRECTORY_URL/lop" \
123148
-c promisor.acceptfromserver=All \
124149
--no-local --filter="blob:limit=5k" server client &&
125150
@@ -137,7 +162,7 @@ test_expect_success "clone with promisor.acceptfromserver set to 'None'" '
137162
# Clone from server to create a client
138163
GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \
139164
-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
140-
-c remote.lop.url="file://$(pwd)/lop" \
165+
-c remote.lop.url="$TRASH_DIRECTORY_URL/lop" \
141166
-c promisor.acceptfromserver=None \
142167
--no-local --filter="blob:limit=5k" server client &&
143168
@@ -156,8 +181,8 @@ test_expect_success "init + fetch with promisor.advertise set to 'true'" '
156181
git -C client init &&
157182
git -C client config remote.lop.promisor true &&
158183
git -C client config remote.lop.fetch "+refs/heads/*:refs/remotes/lop/*" &&
159-
git -C client config remote.lop.url "file://$(pwd)/lop" &&
160-
git -C client config remote.server.url "file://$(pwd)/server" &&
184+
git -C client config remote.lop.url "$TRASH_DIRECTORY_URL/lop" &&
185+
git -C client config remote.server.url "$TRASH_DIRECTORY_URL/server" &&
161186
git -C client config remote.server.fetch "+refs/heads/*:refs/remotes/server/*" &&
162187
git -C client config promisor.acceptfromserver All &&
163188
GIT_NO_LAZY_FETCH=0 git -C client fetch --filter="blob:limit=5k" server &&
@@ -177,10 +202,10 @@ test_expect_success "clone with two promisors but only one advertised" '
177202
GIT_TRACE="$(pwd)/trace" GIT_NO_LAZY_FETCH=0 git clone \
178203
-c remote.unused_lop.promisor=true \
179204
-c remote.unused_lop.fetch="+refs/heads/*:refs/remotes/unused_lop/*" \
180-
-c remote.unused_lop.url="file://$(pwd)/unused_lop" \
205+
-c remote.unused_lop.url="$TRASH_DIRECTORY_URL/unused_lop" \
181206
-c remote.lop.promisor=true \
182207
-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
183-
-c remote.lop.url="file://$(pwd)/lop" \
208+
-c remote.lop.url="$TRASH_DIRECTORY_URL/lop" \
184209
-c promisor.acceptfromserver=All \
185210
--no-local --filter="blob:limit=5k" server client &&
186211
@@ -210,11 +235,11 @@ test_expect_success "init + fetch two promisors but only one advertised" '
210235
git -C client init &&
211236
git -C client config remote.unused_lop.promisor true &&
212237
git -C client config remote.unused_lop.fetch "+refs/heads/*:refs/remotes/unused_lop/*" &&
213-
git -C client config remote.unused_lop.url "file://$(pwd)/unused_lop" &&
238+
git -C client config remote.unused_lop.url "$TRASH_DIRECTORY_URL/unused_lop" &&
214239
git -C client config remote.lop.promisor true &&
215240
git -C client config remote.lop.fetch "+refs/heads/*:refs/remotes/lop/*" &&
216-
git -C client config remote.lop.url "file://$(pwd)/lop" &&
217-
git -C client config remote.server.url "file://$(pwd)/server" &&
241+
git -C client config remote.lop.url "$TRASH_DIRECTORY_URL/lop" &&
242+
git -C client config remote.server.url "$TRASH_DIRECTORY_URL/server" &&
218243
git -C client config remote.server.fetch "+refs/heads/*:refs/remotes/server/*" &&
219244
git -C client config promisor.acceptfromserver All &&
220245
@@ -242,7 +267,7 @@ test_expect_success "clone with promisor.acceptfromserver set to 'KnownName'" '
242267
# Clone from server to create a client
243268
GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \
244269
-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
245-
-c remote.lop.url="file://$(pwd)/lop" \
270+
-c remote.lop.url="$TRASH_DIRECTORY_URL/lop" \
246271
-c promisor.acceptfromserver=KnownName \
247272
--no-local --filter="blob:limit=5k" server client &&
248273
@@ -257,7 +282,7 @@ test_expect_success "clone with 'KnownName' and different remote names" '
257282
# Clone from server to create a client
258283
GIT_NO_LAZY_FETCH=0 git clone -c remote.serverTwo.promisor=true \
259284
-c remote.serverTwo.fetch="+refs/heads/*:refs/remotes/lop/*" \
260-
-c remote.serverTwo.url="file://$(pwd)/lop" \
285+
-c remote.serverTwo.url="$TRASH_DIRECTORY_URL/lop" \
261286
-c promisor.acceptfromserver=KnownName \
262287
--no-local --filter="blob:limit=5k" server client &&
263288
@@ -294,7 +319,7 @@ test_expect_success "clone with promisor.acceptfromserver set to 'KnownUrl'" '
294319
# Clone from server to create a client
295320
GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \
296321
-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
297-
-c remote.lop.url="file://$(pwd)/lop" \
322+
-c remote.lop.url="$TRASH_DIRECTORY_URL/lop" \
298323
-c promisor.acceptfromserver=KnownUrl \
299324
--no-local --filter="blob:limit=5k" server client &&
300325
@@ -311,7 +336,7 @@ test_expect_success "clone with 'KnownUrl' and different remote urls" '
311336
# Clone from server to create a client
312337
GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \
313338
-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
314-
-c remote.lop.url="file://$(pwd)/serverTwo" \
339+
-c remote.lop.url="$TRASH_DIRECTORY_URL/serverTwo" \
315340
-c promisor.acceptfromserver=KnownUrl \
316341
--no-local --filter="blob:limit=5k" server client &&
317342
@@ -326,7 +351,7 @@ test_expect_success "clone with 'KnownUrl' and url not configured on the server"
326351
git -C server config promisor.advertise true &&
327352
test_when_finished "rm -rf client" &&
328353
329-
test_when_finished "git -C server config set remote.lop.url \"file://$(pwd)/lop\"" &&
354+
test_when_finished "git -C server config set remote.lop.url \"$TRASH_DIRECTORY_URL/lop\"" &&
330355
git -C server config unset remote.lop.url &&
331356
332357
# Clone from server to create a client
@@ -335,7 +360,7 @@ test_expect_success "clone with 'KnownUrl' and url not configured on the server"
335360
# missing, so the remote name will be used instead which will fail.
336361
test_must_fail env GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \
337362
-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
338-
-c remote.lop.url="file://$(pwd)/lop" \
363+
-c remote.lop.url="$TRASH_DIRECTORY_URL/lop" \
339364
-c promisor.acceptfromserver=KnownUrl \
340365
--no-local --filter="blob:limit=5k" server client &&
341366
@@ -347,7 +372,7 @@ test_expect_success "clone with 'KnownUrl' and empty url, so not advertised" '
347372
git -C server config promisor.advertise true &&
348373
test_when_finished "rm -rf client" &&
349374
350-
test_when_finished "git -C server config set remote.lop.url \"file://$(pwd)/lop\"" &&
375+
test_when_finished "git -C server config set remote.lop.url \"$TRASH_DIRECTORY_URL/lop\"" &&
351376
git -C server config set remote.lop.url "" &&
352377
353378
# Clone from server to create a client
@@ -356,7 +381,7 @@ test_expect_success "clone with 'KnownUrl' and empty url, so not advertised" '
356381
# so the remote name will be used instead which will fail.
357382
test_must_fail env GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \
358383
-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
359-
-c remote.lop.url="file://$(pwd)/lop" \
384+
-c remote.lop.url="$TRASH_DIRECTORY_URL/lop" \
360385
-c promisor.acceptfromserver=KnownUrl \
361386
--no-local --filter="blob:limit=5k" server client &&
362387
@@ -380,13 +405,12 @@ test_expect_success "clone with promisor.sendFields" '
380405
GIT_TRACE_PACKET="$(pwd)/trace" GIT_NO_LAZY_FETCH=0 git clone \
381406
-c remote.lop.promisor=true \
382407
-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
383-
-c remote.lop.url="file://$(pwd)/lop" \
408+
-c remote.lop.url="$TRASH_DIRECTORY_URL/lop" \
384409
-c promisor.acceptfromserver=All \
385410
--no-local --filter="blob:limit=5k" server client &&
386411
387412
# Check that fields are properly transmitted
388-
ENCODED_URL=$(echo "file://$(pwd)/lop" | sed -e "s/ /%20/g") &&
389-
PR1="name=lop,url=$ENCODED_URL,partialCloneFilter=blob:none" &&
413+
PR1="name=lop,url=$ENCODED_TRASH_DIRECTORY_URL/lop,partialCloneFilter=blob:none" &&
390414
PR2="name=otherLop,url=https://invalid.invalid,partialCloneFilter=blob:limit=10k,token=fooBar" &&
391415
test_grep "clone< promisor-remote=$PR1;$PR2" trace &&
392416
test_grep "clone> promisor-remote=lop;otherLop" trace &&
@@ -411,15 +435,14 @@ test_expect_success "clone with promisor.checkFields" '
411435
GIT_TRACE_PACKET="$(pwd)/trace" GIT_NO_LAZY_FETCH=0 git clone \
412436
-c remote.lop.promisor=true \
413437
-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
414-
-c remote.lop.url="file://$(pwd)/lop" \
438+
-c remote.lop.url="$TRASH_DIRECTORY_URL/lop" \
415439
-c remote.lop.partialCloneFilter="blob:none" \
416440
-c promisor.acceptfromserver=All \
417441
-c promisor.checkFields=partialcloneFilter \
418442
--no-local --filter="blob:limit=5k" server client &&
419443
420444
# Check that fields are properly transmitted
421-
ENCODED_URL=$(echo "file://$(pwd)/lop" | sed -e "s/ /%20/g") &&
422-
PR1="name=lop,url=$ENCODED_URL,partialCloneFilter=blob:none" &&
445+
PR1="name=lop,url=$ENCODED_TRASH_DIRECTORY_URL/lop,partialCloneFilter=blob:none" &&
423446
PR2="name=otherLop,url=https://invalid.invalid,partialCloneFilter=blob:limit=10k,token=fooBar" &&
424447
test_grep "clone< promisor-remote=$PR1;$PR2" trace &&
425448
test_grep "clone> promisor-remote=lop" trace &&
@@ -449,7 +472,7 @@ test_expect_success "clone with promisor.storeFields=partialCloneFilter" '
449472
GIT_TRACE_PACKET="$(pwd)/trace" GIT_NO_LAZY_FETCH=0 git clone \
450473
-c remote.lop.promisor=true \
451474
-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
452-
-c remote.lop.url="file://$(pwd)/lop" \
475+
-c remote.lop.url="$TRASH_DIRECTORY_URL/lop" \
453476
-c remote.lop.token="fooYYY" \
454477
-c remote.lop.partialCloneFilter="blob:none" \
455478
-c promisor.acceptfromserver=All \
@@ -501,7 +524,7 @@ test_expect_success "clone and fetch with --filter=auto" '
501524
502525
GIT_TRACE_PACKET="$(pwd)/trace" GIT_NO_LAZY_FETCH=0 git clone \
503526
-c remote.lop.promisor=true \
504-
-c remote.lop.url="file://$(pwd)/lop" \
527+
-c remote.lop.url="$TRASH_DIRECTORY_URL/lop" \
505528
-c promisor.acceptfromserver=All \
506529
--no-local --filter=auto server client 2>err &&
507530
@@ -558,7 +581,7 @@ test_expect_success "clone with promisor.advertise set to 'true' but don't delet
558581
# Clone from server to create a client
559582
GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \
560583
-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
561-
-c remote.lop.url="file://$(pwd)/lop" \
584+
-c remote.lop.url="$TRASH_DIRECTORY_URL/lop" \
562585
-c promisor.acceptfromserver=All \
563586
--no-local --filter="blob:limit=5k" server client &&
564587

0 commit comments

Comments
 (0)