#!/bin/sh test_description='apply-one-time-script CGI helper is safe under concurrent requests' . ./test-lib.sh HELPER="$TEST_DIRECTORY/lib-httpd/apply-one-time-script.sh" test_expect_success PIPE 'helper only serves one rewritten response for concurrent requests' ' mkdir workdir fakebin && ENTERED="$PWD/entered" && GATE="$PWD/gate" && export ENTERED GATE && mkfifo "$ENTERED" "$GATE" && # A stub git-http-backend that returns a response based on # $ROLE. For $ROLE = modify, return the response string # "packfile", which ends up being modified by the example # one-time-script below. # # Otherwise, run the branch returning a response that # should be passed through, and block until released # by "read -r $GATE". write_script fakebin/git-http-backend <<-\EOF && printf "Status: 200 OK\r\n" printf "Content-Type: application/x-git-result\r\n" printf "\r\n" if test "$ROLE" = modify then printf "packfile\n" else echo entered >"$ENTERED" read -r released <"$GATE" printf "refs\n" fi EOF # An example one-time-script for apply-one-time-script # to execute. Checks for "packfile" in the response # that will be returned, and replaces it with a # modified response. Passes through responses without # "packfile" in them. write_script workdir/one-time-script <<-\EOF && if grep packfile "$1" >/dev/null then sed "/packfile/q" "$1" && printf "REPLACED\n" else cat "$1" fi EOF GIT_EXEC_PATH="$PWD/fakebin" && export GIT_EXEC_PATH && # Ensure $GATE has a reader so the test does not block indefinitely if # the helper is buggy and "echo released >&9" below does not unblock # the unmodified response gate. exec 9<>"$GATE" && # Launch the passthrough request in the background. Record its pid # so it can be killed when the test finishes if, for some reason, the # request stays blocked and would stall a test runner. { ( cd workdir && ROLE=passthrough sh "$HELPER" >../passthrough.out 2>../passthrough.err ) & } && passthrough_pid=$! && test_when_finished "kill $passthrough_pid 2>/dev/null || :" && # Wait until the passthrough request is "in-flight" and paused # mid-response. read -r entered <"$ENTERED" && # Launch the request for a modified response while the passthrough # request is concurrently "in-flight" and paused. ( cd workdir && ROLE=modify sh "$HELPER" >../modify.out 2>../modify.err ) && # Unblock the passthrough request, allowing git-http-backend to # complete its response. echo released >&9 && { wait "$passthrough_pid" || :; } && test_must_be_empty passthrough.err && test_must_be_empty modify.err && test_grep "Status: 200 OK" passthrough.out && test_grep "Status: 200 OK" modify.out && test_grep REPLACED modify.out && test_grep ! REPLACED passthrough.out && test_grep refs passthrough.out ' test_done