Raw
1 #!/bin/sh
2
3 : ${HTTP_PROTO:=HTTP/1.1}
4 test_description="test smart fetching over http via http-backend ($HTTP_PROTO)"
5 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
6 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
7
8 . ./test-lib.sh
9 . "$TEST_DIRECTORY"/lib-httpd.sh
10
11 if ! test_have_prereq PERL_TEST_HELPERS
12 then
13 skip_all='skipping http fetch smart tests; Perl not available'
14 test_done
15 fi
16
17 test "$HTTP_PROTO" = "HTTP/2" && enable_http2
18 start_httpd
19
20 test_expect_success HTTP2 'enable client-side http/2' '
21 git config --global http.version HTTP/2
22 '
23
24 test_expect_success 'setup repository' '
25 git config push.default matching &&
26 echo content >file &&
27 git add file &&
28 git commit -m one
29 '
30
31 test_expect_success 'create http-accessible bare repository' '
32 mkdir "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
33 (cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
34 git --bare init
35 ) &&
36 git remote add public "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
37 git push public main:main
38 '
39
40 setup_askpass_helper
41
42 test_expect_success 'clone http repository' '
43 if test_have_prereq HTTP2 && test "$HTTPD_PROTO" = "https"
44 then
45 # ALPN lets us immediately use HTTP/2; likewise, POSTs with
46 # bodies can use it because they do not need to upgrade
47 INITIAL_PROTO=HTTP/2
48 else
49 # either we are not using HTTP/2, or the initial
50 # request is sent via HTTP/1.1 and asks for upgrade
51 INITIAL_PROTO=HTTP/1.1
52 fi &&
53
54 cat >exp.raw <<-EOF &&
55 > GET /smart/repo.git/info/refs?service=git-upload-pack $INITIAL_PROTO
56 > accept: */*
57 > accept-encoding: ENCODINGS
58 > accept-language: ko-KR, *;q=0.9
59 > pragma: no-cache
60 {V2} > git-protocol: version=2
61 < $HTTP_PROTO 200 OK
62 < pragma: no-cache
63 < cache-control: no-cache, max-age=0, must-revalidate
64 < content-type: application/x-git-upload-pack-advertisement
65 > POST /smart/repo.git/git-upload-pack $INITIAL_PROTO
66 > accept-encoding: ENCODINGS
67 > content-type: application/x-git-upload-pack-request
68 > accept: application/x-git-upload-pack-result
69 > accept-language: ko-KR, *;q=0.9
70 {V2} > git-protocol: version=2
71 > content-length: xxx
72 < $INITIAL_PROTO 200 OK
73 < pragma: no-cache
74 < cache-control: no-cache, max-age=0, must-revalidate
75 < content-type: application/x-git-upload-pack-result
76 {V2} > POST /smart/repo.git/git-upload-pack $INITIAL_PROTO
77 {V2} > accept-encoding: ENCODINGS
78 {V2} > content-type: application/x-git-upload-pack-request
79 {V2} > accept: application/x-git-upload-pack-result
80 {V2} > accept-language: ko-KR, *;q=0.9
81 {V2} > git-protocol: version=2
82 {V2} > content-length: xxx
83 {V2} < $INITIAL_PROTO 200 OK
84 {V2} < pragma: no-cache
85 {V2} < cache-control: no-cache, max-age=0, must-revalidate
86 {V2} < content-type: application/x-git-upload-pack-result
87 EOF
88
89 if test "$GIT_TEST_PROTOCOL_VERSION" = 0
90 then
91 sed "/^{V2}/d" <exp.raw >exp
92 else
93 sed "s/^{V2} //" <exp.raw >exp
94 fi &&
95
96 GIT_TRACE_CURL=true LANGUAGE="ko_KR.UTF-8" \
97 git clone --quiet $HTTPD_URL/smart/repo.git clone 2>err &&
98 test_cmp file clone/file &&
99 tr '\''\015'\'' Q <err |
100 perl -pe '\''
101 s/(Send|Recv) header: ([A-Za-z0-9-]+):/
102 "$1 header: " . lc($2) . ":"
103 /e;
104 '\'' |
105 sed -e "
106 s/Q\$//
107 /^[^<=]/d
108 /^== Info:/d
109 /^=> Send header, /d
110 /^=> Send header:$/d
111 /^<= Recv header, /d
112 /^<= Recv header:$/d
113 s/=> Send header: //
114 s/= Recv header://
115 /^<= Recv data/d
116 /^=> Send data/d
117 /^<= Recv SSL data/d
118 /^=> Send SSL data/d
119 /^$/d
120 /^< $/d
121
122 /^[^><]/{
123 s/^/> /
124 }
125
126 /^< HTTP/ {
127 s/200$/200 OK/
128 }
129 /^< HTTP\\/1.1 101/d
130 /^[><] connection: /d
131 /^[><] upgrade: /d
132 /^> http2-settings: /d
133
134 /^> user-agent: /d
135 /^> host: /d
136 /^> POST /,$ {
137 /^> Accept: [*]\\/[*]/d
138 }
139 s/^> content-length: .*/> content-length: xxx/
140 /^> 00..want /d
141 /^> 00.*done/d
142
143 /^< server: /d
144 /^< expires: /d
145 /^< date: /d
146 /^< content-length: /d
147 /^< transfer-encoding: /d
148 " >actual &&
149
150 sed -e "s/^> accept-encoding: .*/> accept-encoding: ENCODINGS/" \
151 actual >actual.smudged &&
152 test_cmp exp actual.smudged &&
153
154 grep "accept-encoding:.*gzip" actual >actual.gzip
155 '
156
157 test_expect_success 'fetch changes via http' '
158 echo content >>file &&
159 git commit -a -m two &&
160 git push public &&
161 (cd clone && git pull) &&
162 test_cmp file clone/file
163 '
164
165 test_expect_success 'used upload-pack service' '
166 strip_access_log >log &&
167 grep "GET /smart/repo.git/info/refs?service=git-upload-pack HTTP/[0-9.]* 200" log &&
168 grep "POST /smart/repo.git/git-upload-pack HTTP/[0-9.]* 200" log
169 '
170
171 test_expect_success 'follow redirects (301)' '
172 git clone $HTTPD_URL/smart-redir-perm/repo.git --quiet repo-p
173 '
174
175 test_expect_success 'follow redirects (302)' '
176 git clone $HTTPD_URL/smart-redir-temp/repo.git --quiet repo-t
177 '
178
179 test_expect_success 'redirects re-root further requests' '
180 git clone $HTTPD_URL/smart-redir-limited/repo.git repo-redir-limited
181 '
182
183 test_expect_success 're-rooting dies on insane schemes' '
184 test_must_fail git clone $HTTPD_URL/insane-redir/repo.git insane
185 '
186
187 test_expect_success 'clone from password-protected repository' '
188 echo two >expect &&
189 set_askpass user@host pass@host &&
190 git clone --bare "$HTTPD_URL/auth/smart/repo.git" smart-auth &&
191 expect_askpass both user%40host &&
192 git --git-dir=smart-auth log -1 --format=%s >actual &&
193 test_cmp expect actual
194 '
195
196 test_expect_success 'credential.interactive=false skips askpass' '
197 set_askpass bogus nonsense &&
198 (
199 GIT_TRACE2_EVENT="$(pwd)/interactive-true" &&
200 export GIT_TRACE2_EVENT &&
201 test_must_fail git clone --bare "$HTTPD_URL/auth/smart/repo.git" interactive-true-dir &&
202 test_region credential interactive interactive-true &&
203
204 GIT_TRACE2_EVENT="$(pwd)/interactive-false" &&
205 export GIT_TRACE2_EVENT &&
206 test_must_fail git -c credential.interactive=false \
207 clone --bare "$HTTPD_URL/auth/smart/repo.git" interactive-false-dir &&
208 test_region ! credential interactive interactive-false &&
209
210 GIT_TRACE2_EVENT="$(pwd)/interactive-never" &&
211 export GIT_TRACE2_EVENT &&
212 test_must_fail git -c credential.interactive=never \
213 clone --bare "$HTTPD_URL/auth/smart/repo.git" interactive-never-dir &&
214 test_region ! credential interactive interactive-never
215 )
216 '
217
218 test_expect_success 'clone from auth-only-for-push repository' '
219 echo two >expect &&
220 set_askpass wrong &&
221 git clone --bare "$HTTPD_URL/auth-push/smart/repo.git" smart-noauth &&
222 expect_askpass none &&
223 git --git-dir=smart-noauth log -1 --format=%s >actual &&
224 test_cmp expect actual
225 '
226
227 test_expect_success 'clone from auth-only-for-objects repository' '
228 echo two >expect &&
229 set_askpass user@host pass@host &&
230 git clone --bare "$HTTPD_URL/auth-fetch/smart/repo.git" half-auth &&
231 expect_askpass both user%40host &&
232 git --git-dir=half-auth log -1 --format=%s >actual &&
233 test_cmp expect actual
234 '
235
236 test_expect_success 'no-op half-auth fetch does not require a password' '
237 set_askpass wrong &&
238
239 # NEEDSWORK: When using HTTP(S), protocol v0 supports a "half-auth"
240 # configuration with authentication required only when downloading
241 # objects and not refs, by having the HTTP server only require
242 # authentication for the "git-upload-pack" path and not "info/refs".
243 # This is not possible with protocol v2, since both objects and refs
244 # are obtained from the "git-upload-pack" path. A solution to this is
245 # to teach the server and client to be able to inline ls-refs requests
246 # as an Extra Parameter (see "git help gitformat-pack-protocol"), so that
247 # "info/refs" can serve refs, just like it does in protocol v0.
248 GIT_TEST_PROTOCOL_VERSION=0 git --git-dir=half-auth fetch &&
249 expect_askpass none
250 '
251
252 test_expect_success 'redirects send auth to new location' '
253 set_askpass user@host pass@host &&
254 git -c credential.useHttpPath=true \
255 clone $HTTPD_URL/smart-redir-auth/repo.git repo-redir-auth &&
256 expect_askpass both user%40host auth/smart/repo.git
257 '
258
259 test_expect_success 'GIT_TRACE_CURL redacts auth details' '
260 rm -rf redact-auth trace &&
261 set_askpass user@host pass@host &&
262 GIT_TRACE_CURL="$(pwd)/trace" git clone --bare "$HTTPD_URL/auth/smart/repo.git" redact-auth &&
263 expect_askpass both user%40host &&
264
265 # Ensure that there is no "Basic" followed by a base64 string, but that
266 # the auth details are redacted
267 ! grep -i "Authorization: Basic [0-9a-zA-Z+/]" trace &&
268 grep -i "Authorization: Basic <redacted>" trace
269 '
270
271 test_expect_success 'GIT_CURL_VERBOSE redacts auth details' '
272 rm -rf redact-auth trace &&
273 set_askpass user@host pass@host &&
274 GIT_CURL_VERBOSE=1 git clone --bare "$HTTPD_URL/auth/smart/repo.git" redact-auth 2>trace &&
275 expect_askpass both user%40host &&
276
277 # Ensure that there is no "Basic" followed by a base64 string, but that
278 # the auth details are redacted
279 ! grep -i "Authorization: Basic [0-9a-zA-Z+/]" trace &&
280 grep -i "Authorization: Basic <redacted>" trace
281 '
282
283 test_expect_success 'GIT_TRACE_CURL does not redact auth details if GIT_TRACE_REDACT=0' '
284 rm -rf redact-auth trace &&
285 set_askpass user@host pass@host &&
286 GIT_TRACE_REDACT=0 GIT_TRACE_CURL="$(pwd)/trace" \
287 git clone --bare "$HTTPD_URL/auth/smart/repo.git" redact-auth &&
288 expect_askpass both user%40host &&
289
290 grep -i "Authorization: Basic [0-9a-zA-Z+/]" trace
291 '
292
293 test_expect_success 'disable dumb http on server' '
294 git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \
295 config http.getanyfile false
296 '
297
298 test_expect_success 'GIT_SMART_HTTP can disable smart http' '
299 (GIT_SMART_HTTP=0 &&
300 export GIT_SMART_HTTP &&
301 cd clone &&
302 test_must_fail git fetch)
303 '
304
305 test_expect_success 'invalid Content-Type rejected' '
306 test_must_fail git clone $HTTPD_URL/broken_smart/repo.git 2>actual &&
307 test_grep "not valid:" actual
308 '
309
310 test_expect_success 'create namespaced refs' '
311 test_commit namespaced &&
312 git push public HEAD:refs/namespaces/ns/refs/heads/main &&
313 git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \
314 symbolic-ref refs/namespaces/ns/HEAD refs/namespaces/ns/refs/heads/main
315 '
316
317 test_expect_success 'smart clone respects namespace' '
318 git clone "$HTTPD_URL/smart_namespace/repo.git" ns-smart &&
319 echo namespaced >expect &&
320 git --git-dir=ns-smart/.git log -1 --format=%s >actual &&
321 test_cmp expect actual
322 '
323
324 test_expect_success 'dumb clone via http-backend respects namespace' '
325 git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \
326 config http.getanyfile true &&
327 GIT_SMART_HTTP=0 git clone \
328 "$HTTPD_URL/smart_namespace/repo.git" ns-dumb &&
329 echo namespaced >expect &&
330 git --git-dir=ns-dumb/.git log -1 --format=%s >actual &&
331 test_cmp expect actual
332 '
333
334 test_expect_success 'cookies stored in http.cookiefile when http.savecookies set' '
335 cat >cookies.txt <<-\EOF &&
336 127.0.0.1 FALSE /smart_cookies FALSE 0 othername othervalue
337 EOF
338 sort >expect_cookies.txt <<-\EOF &&
339 127.0.0.1 FALSE /smart_cookies FALSE 0 othername othervalue
340 127.0.0.1 FALSE /smart_cookies/repo.git FALSE 0 name value
341 127.0.0.1 FALSE /smart_cookies/repo.git/info FALSE 0 name value
342 EOF
343 git config http.cookiefile cookies.txt &&
344 git config http.savecookies true &&
345
346 test_when_finished "
347 git --git-dir=\"\$HTTPD_DOCUMENT_ROOT_PATH/repo.git\" \
348 tag -d cookie-tag
349 " &&
350 git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \
351 tag -m "foo" cookie-tag &&
352 git fetch $HTTPD_URL/smart_cookies/repo.git cookie-tag &&
353
354 # Strip trailing slashes from cookie paths to handle output from both
355 # old curl ("/smart_cookies/") and new ("/smart_cookies").
356 HT=" " &&
357 grep "^[^#]" cookies.txt | sed "s,/$HT,$HT," | sort >cookies_clean.txt &&
358 test_cmp expect_cookies.txt cookies_clean.txt
359 '
360
361 test_expect_success 'transfer.hiderefs works over smart-http' '
362 test_commit hidden &&
363 test_commit visible &&
364 git push public HEAD^:refs/heads/a HEAD:refs/heads/b &&
365 git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \
366 config transfer.hiderefs refs/heads/a &&
367 git clone --bare "$HTTPD_URL/smart/repo.git" hidden.git &&
368 test_must_fail git -C hidden.git rev-parse --verify a &&
369 git -C hidden.git rev-parse --verify b
370 '
371
372 # create an arbitrary number of tags, numbered from tag-$1 to tag-$2
373 create_tags () {
374 rm -f marks &&
375 for i in $(test_seq "$1" "$2")
376 do
377 # don't use here-doc, because it requires a process
378 # per loop iteration
379 echo "commit refs/heads/too-many-refs-$1" &&
380 echo "mark :$i" &&
381 echo "committer git <git@example.com> $i +0000" &&
382 echo "data 0" &&
383 echo "M 644 inline bla.txt" &&
384 echo "data 4" &&
385 echo "bla" &&
386 # make every commit dangling by always
387 # rewinding the branch after each commit
388 echo "reset refs/heads/too-many-refs-$1" &&
389 echo "from :$1"
390 done | git fast-import --export-marks=marks &&
391
392 # now assign tags to all the dangling commits we created above
393 tag=$(perl -e "print \"bla\" x 30") &&
394 sed -e "s|^:\([^ ]*\) \(.*\)$|create refs/tags/$tag-\1 \2|" <marks >input &&
395 git update-ref --stdin <input &&
396 rm input
397 }
398
399 test_expect_success 'create 2,000 tags in the repo' '
400 (
401 cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
402 create_tags 1 2000
403 )
404 '
405
406 test_expect_success CMDLINE_LIMIT \
407 'clone the 2,000 tag repo to check OS command line overflow' '
408 run_with_limited_cmdline git clone $HTTPD_URL/smart/repo.git too-many-refs &&
409 (
410 cd too-many-refs &&
411 git for-each-ref refs/tags >actual &&
412 test_line_count = 2000 actual
413 )
414 '
415
416 test_expect_success 'large fetch-pack requests can be sent using chunked encoding' '
417 GIT_TRACE_CURL=true git -c http.postbuffer=65536 \
418 clone --bare "$HTTPD_URL/smart/repo.git" split.git 2>err &&
419 {
420 test_have_prereq HTTP2 ||
421 grep "^=> Send header: Transfer-Encoding: chunked" err
422 }
423 '
424
425 test_expect_success 'test allowreachablesha1inwant' '
426 test_when_finished "rm -rf test_reachable.git" &&
427 server="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
428 main_sha=$(git -C "$server" rev-parse refs/heads/main) &&
429 git -C "$server" config uploadpack.allowreachablesha1inwant 1 &&
430
431 git init --bare test_reachable.git &&
432 git -C test_reachable.git remote add origin "$HTTPD_URL/smart/repo.git" &&
433 git -C test_reachable.git fetch origin "$main_sha"
434 '
435
436 test_expect_success 'test allowreachablesha1inwant with unreachable' '
437 test_when_finished "rm -rf test_reachable.git; git reset --hard $(git rev-parse HEAD)" &&
438
439 #create unreachable sha
440 echo content >file2 &&
441 git add file2 &&
442 git commit -m two &&
443 git push public HEAD:refs/heads/doomed &&
444 git push public :refs/heads/doomed &&
445
446 server="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
447 main_sha=$(git -C "$server" rev-parse refs/heads/main) &&
448 git -C "$server" config uploadpack.allowreachablesha1inwant 1 &&
449
450 git init --bare test_reachable.git &&
451 git -C test_reachable.git remote add origin "$HTTPD_URL/smart/repo.git" &&
452 # Some protocol versions (e.g. 2) support fetching
453 # unadvertised objects, so restrict this test to v0.
454 test_must_fail env GIT_TEST_PROTOCOL_VERSION=0 \
455 git -C test_reachable.git fetch origin "$(git rev-parse HEAD)"
456 '
457
458 test_expect_success 'test allowanysha1inwant with unreachable' '
459 test_when_finished "rm -rf test_reachable.git; git reset --hard $(git rev-parse HEAD)" &&
460
461 #create unreachable sha
462 echo content >file2 &&
463 git add file2 &&
464 git commit -m two &&
465 git push public HEAD:refs/heads/doomed &&
466 git push public :refs/heads/doomed &&
467
468 server="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
469 main_sha=$(git -C "$server" rev-parse refs/heads/main) &&
470 git -C "$server" config uploadpack.allowreachablesha1inwant 1 &&
471
472 git init --bare test_reachable.git &&
473 git -C test_reachable.git remote add origin "$HTTPD_URL/smart/repo.git" &&
474 # Some protocol versions (e.g. 2) support fetching
475 # unadvertised objects, so restrict this test to v0.
476 test_must_fail env GIT_TEST_PROTOCOL_VERSION=0 \
477 git -C test_reachable.git fetch origin "$(git rev-parse HEAD)" &&
478
479 git -C "$server" config uploadpack.allowanysha1inwant 1 &&
480 git -C test_reachable.git fetch origin "$(git rev-parse HEAD)"
481 '
482
483 test_expect_success EXPENSIVE 'http can handle enormous ref negotiation' '
484 test_when_finished "rm -f tags" &&
485 (
486 cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
487 create_tags 2001 50000
488 ) &&
489 git -C too-many-refs fetch -q --tags &&
490 (
491 cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
492 create_tags 50001 100000
493 ) &&
494 git -C too-many-refs fetch -q --tags &&
495 git -C too-many-refs for-each-ref refs/tags >tags &&
496 test_line_count = 100000 tags
497 '
498
499 test_expect_success 'custom http headers' '
500 test_must_fail git -c http.extraheader="x-magic-two: cadabra" \
501 fetch "$HTTPD_URL/smart_headers/repo.git" &&
502 git -c http.extraheader="x-magic-one: abra" \
503 -c http.extraheader="x-magic-two: cadabra" \
504 fetch "$HTTPD_URL/smart_headers/repo.git" &&
505 git update-index --add --cacheinfo 160000,$(git rev-parse HEAD),sub &&
506 git config -f .gitmodules submodule.sub.path sub &&
507 git config -f .gitmodules submodule.sub.url \
508 "$HTTPD_URL/smart_headers/repo.git" &&
509 git submodule init sub &&
510 test_must_fail git submodule update sub &&
511 git -c http.extraheader="x-magic-one: abra" \
512 -c http.extraheader="x-magic-two: cadabra" \
513 submodule update sub
514 '
515
516 test_expect_success 'using fetch command in remote-curl updates refs' '
517 SERVER="$HTTPD_DOCUMENT_ROOT_PATH/twobranch" &&
518 rm -rf "$SERVER" client &&
519
520 git init "$SERVER" &&
521 test_commit -C "$SERVER" foo &&
522 git -C "$SERVER" update-ref refs/heads/anotherbranch foo &&
523
524 git clone $HTTPD_URL/smart/twobranch client &&
525
526 test_commit -C "$SERVER" bar &&
527 git -C client -c protocol.version=0 fetch &&
528
529 git -C "$SERVER" rev-parse main >expect &&
530 git -C client rev-parse origin/main >actual &&
531 test_cmp expect actual
532 '
533
534 test_expect_success 'fetch by SHA-1 without tag following' '
535 SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" &&
536 rm -rf "$SERVER" client &&
537
538 git init "$SERVER" &&
539 test_commit -C "$SERVER" foo &&
540
541 git clone $HTTPD_URL/smart/server client &&
542
543 test_commit -C "$SERVER" bar &&
544 git -C "$SERVER" rev-parse bar >bar_hash &&
545 git -C client -c protocol.version=0 fetch \
546 --no-tags origin $(cat bar_hash)
547 '
548
549 test_expect_success 'cookies are redacted by default' '
550 rm -rf clone &&
551 echo "Set-Cookie: Foo=1" >cookies &&
552 echo "Set-Cookie: Bar=2" >>cookies &&
553 GIT_TRACE_CURL=true \
554 git -c "http.cookieFile=$(pwd)/cookies" clone \
555 $HTTPD_URL/smart/repo.git clone 2>err &&
556 grep -i "Cookie:.*Foo=<redacted>" err &&
557 grep -i "Cookie:.*Bar=<redacted>" err &&
558 ! grep -i "Cookie:.*Foo=1" err &&
559 ! grep -i "Cookie:.*Bar=2" err
560 '
561
562 test_expect_success 'empty values of cookies are also redacted' '
563 rm -rf clone &&
564 echo "Set-Cookie: Foo=" >cookies &&
565 GIT_TRACE_CURL=true \
566 git -c "http.cookieFile=$(pwd)/cookies" clone \
567 $HTTPD_URL/smart/repo.git clone 2>err &&
568 grep -i "Cookie:.*Foo=<redacted>" err
569 '
570
571 test_expect_success 'GIT_TRACE_REDACT=0 disables cookie redaction' '
572 rm -rf clone &&
573 echo "Set-Cookie: Foo=1" >cookies &&
574 echo "Set-Cookie: Bar=2" >>cookies &&
575 GIT_TRACE_REDACT=0 GIT_TRACE_CURL=true \
576 git -c "http.cookieFile=$(pwd)/cookies" clone \
577 $HTTPD_URL/smart/repo.git clone 2>err &&
578 grep -i "Cookie:.*Foo=1" err &&
579 grep -i "Cookie:.*Bar=2" err
580 '
581
582 test_expect_success 'GIT_TRACE_CURL_NO_DATA prevents data from being traced' '
583 rm -rf clone &&
584 GIT_TRACE_CURL=true \
585 git clone $HTTPD_URL/smart/repo.git clone 2>err &&
586 grep "=> Send data" err &&
587
588 rm -rf clone &&
589 GIT_TRACE_CURL=true GIT_TRACE_CURL_NO_DATA=1 \
590 git clone $HTTPD_URL/smart/repo.git clone 2>err &&
591 ! grep "=> Send data" err
592 '
593
594 test_expect_success 'server-side error detected' '
595 test_must_fail git clone $HTTPD_URL/error_smart/repo.git 2>actual &&
596 test_grep "server-side error" actual
597 '
598
599 test_expect_success 'http auth remembers successful credentials' '
600 rm -f .git-credentials &&
601 test_config credential.helper store &&
602
603 # the first request prompts the user...
604 set_askpass user@host pass@host &&
605 git ls-remote "$HTTPD_URL/auth/smart/repo.git" >/dev/null &&
606 expect_askpass both user%40host &&
607
608 # ...and the second one uses the stored value rather than
609 # prompting the user.
610 set_askpass bogus-user bogus-pass &&
611 git ls-remote "$HTTPD_URL/auth/smart/repo.git" >/dev/null &&
612 expect_askpass none
613 '
614
615 test_expect_success 'http auth forgets bogus credentials' '
616 # seed credential store with bogus values. In real life,
617 # this would probably come from a password which worked
618 # for a previous request.
619 rm -f .git-credentials &&
620 test_config credential.helper store &&
621 {
622 echo "url=$HTTPD_URL" &&
623 echo "username=bogus" &&
624 echo "password=bogus"
625 } | git credential approve &&
626
627 # we expect this to use the bogus values and fail, never even
628 # prompting the user...
629 set_askpass user@host pass@host &&
630 test_must_fail git ls-remote "$HTTPD_URL/auth/smart/repo.git" >/dev/null &&
631 expect_askpass none &&
632
633 # ...but now we should have forgotten the bad value, causing
634 # us to prompt the user again.
635 set_askpass user@host pass@host &&
636 git ls-remote "$HTTPD_URL/auth/smart/repo.git" >/dev/null &&
637 expect_askpass both user%40host
638 '
639
640 test_expect_success 'client falls back from v2 to v0 to match server' '
641 GIT_TRACE_PACKET=$PWD/trace \
642 GIT_TEST_PROTOCOL_VERSION=2 \
643 git clone $HTTPD_URL/smart_v0/repo.git repo-v0 &&
644 # check for v0; there the HEAD symref is communicated in the capability
645 # line; v2 uses a different syntax on each ref advertisement line
646 grep symref=HEAD:refs/heads/ trace
647 '
648
649 test_expect_success 'create empty http-accessible SHA-256 repository' '
650 mkdir "$HTTPD_DOCUMENT_ROOT_PATH/sha256.git" &&
651 (cd "$HTTPD_DOCUMENT_ROOT_PATH/sha256.git" &&
652 git --bare init --object-format=sha256
653 )
654 '
655
656 test_expect_success 'clone empty SHA-256 repository with protocol v2' '
657 rm -fr sha256 &&
658 echo sha256 >expected &&
659 git -c protocol.version=2 clone "$HTTPD_URL/smart/sha256.git" &&
660 git -C sha256 rev-parse --show-object-format >actual &&
661 test_cmp actual expected &&
662 git ls-remote "$HTTPD_URL/smart/sha256.git" >actual &&
663 test_must_be_empty actual
664 '
665
666 test_expect_success 'clone empty SHA-256 repository with protocol v0' '
667 rm -fr sha256 &&
668 echo sha256 >expected &&
669 GIT_TRACE=1 GIT_TRACE_PACKET=1 git -c protocol.version=0 clone "$HTTPD_URL/smart/sha256.git" &&
670 git -C sha256 rev-parse --show-object-format >actual &&
671 test_cmp actual expected &&
672 git ls-remote "$HTTPD_URL/smart/sha256.git" >actual &&
673 test_must_be_empty actual
674 '
675
676 test_expect_success 'passing hostname resolution information works' '
677 BOGUS_HOST=gitbogusexamplehost.invalid &&
678 BOGUS_HTTPD_URL=$HTTPD_PROTO://$BOGUS_HOST:$LIB_HTTPD_PORT &&
679 git -c "http.curloptResolve=$BOGUS_HOST:$LIB_HTTPD_PORT:127.0.0.1" ls-remote "$BOGUS_HTTPD_URL/smart/repo.git" >/dev/null
680 '
681
682 # here user%40host is the URL-encoded version of user@host,
683 # which is our intentionally-odd username to catch parsing errors
684 url_user=$HTTPD_URL_USER/auth/smart/repo.git
685 url_userpass=$HTTPD_URL_USER_PASS/auth/smart/repo.git
686 url_userblank=$HTTPD_PROTO://user%40host:@$HTTPD_DEST/auth/smart/repo.git
687 message="URL .*:<redacted>@.* uses plaintext credentials"
688
689 test_expect_success 'clone warns or fails when using username:password' '
690 test_when_finished "rm -rf attempt*" &&
691
692 git -c transfer.credentialsInUrl=allow \
693 clone $url_userpass attempt1 2>err &&
694 ! grep "$message" err &&
695
696 git -c transfer.credentialsInUrl=warn \
697 clone $url_userpass attempt2 2>err &&
698 grep "warning: $message" err >warnings &&
699 test_line_count -ge 1 warnings &&
700
701 test_must_fail git -c transfer.credentialsInUrl=die \
702 clone $url_userpass attempt3 2>err &&
703 grep "fatal: $message" err >warnings &&
704 test_line_count -ge 1 warnings &&
705
706 test_must_fail git -c transfer.credentialsInUrl=die \
707 clone $url_userblank attempt4 2>err &&
708 grep "fatal: $message" err >warnings &&
709 test_line_count -ge 1 warnings
710 '
711
712 test_expect_success 'clone does not detect username:password when it is https://username@domain:port/' '
713 test_when_finished "rm -rf attempt1" &&
714
715 # we are relying on lib-httpd for url construction, so document our
716 # assumptions
717 case "$HTTPD_URL_USER" in
718 *:[0-9]*) : ok ;;
719 *) BUG "httpd url does not have port: $HTTPD_URL_USER"
720 esac &&
721
722 git -c transfer.credentialsInUrl=warn clone $url_user attempt1 2>err &&
723 ! grep "uses plaintext credentials" err
724 '
725
726 test_expect_success 'fetch warns or fails when using username:password' '
727 git -c transfer.credentialsInUrl=allow fetch $url_userpass 2>err &&
728 ! grep "$message" err &&
729
730 git -c transfer.credentialsInUrl=warn fetch $url_userpass 2>err &&
731 grep "warning: $message" err >warnings &&
732 test_line_count -ge 1 warnings &&
733
734 test_must_fail git -c transfer.credentialsInUrl=die \
735 fetch $url_userpass 2>err &&
736 grep "fatal: $message" err >warnings &&
737 test_line_count -ge 1 warnings &&
738
739 test_must_fail git -c transfer.credentialsInUrl=die \
740 fetch $url_userblank 2>err &&
741 grep "fatal: $message" err >warnings &&
742 test_line_count -ge 1 warnings
743 '
744
745
746 test_expect_success 'push warns or fails when using username:password' '
747 git -c transfer.credentialsInUrl=allow push $url_userpass 2>err &&
748 ! grep "$message" err &&
749
750 git -c transfer.credentialsInUrl=warn push $url_userpass 2>err &&
751 grep "warning: $message" err >warnings &&
752
753 test_must_fail git -c transfer.credentialsInUrl=die \
754 push $url_userpass 2>err &&
755 grep "fatal: $message" err >warnings &&
756 test_line_count -ge 1 warnings
757 '
758
759 test_expect_success 'no empty path components' '
760 # In the URL, add a trailing slash, and see if git appends yet another
761 # slash.
762 git clone $HTTPD_URL/smart/repo.git/ clone-with-slash &&
763
764 strip_access_log >log &&
765 ! grep "//" log
766 '
767
768 test_expect_success 'tag following always works over v0 http' '
769 upstream=$HTTPD_DOCUMENT_ROOT_PATH/tags &&
770 git init "$upstream" &&
771 (
772 cd "$upstream" &&
773 git commit --allow-empty -m base &&
774 git tag not-annotated &&
775 git tag -m foo annotated
776 ) &&
777 git init tags &&
778 git -C tags -c protocol.version=0 \
779 fetch --depth 1 $HTTPD_URL/smart/tags \
780 refs/tags/annotated:refs/tags/annotated &&
781 git -C "$upstream" for-each-ref refs/tags >expect &&
782 git -C tags for-each-ref >actual &&
783 test_cmp expect actual
784 '
785
786 test_expect_success 'ls-remote outside repo does not segfault with fetch refspec' '
787 nongit git \
788 -c remote.origin.url="$HTTPD_URL/smart/repo.git" \
789 -c remote.origin.fetch=anything \
790 ls-remote origin
791 '
792
793 test_done