Skip to content

Commit e172755

Browse files
peffgitster
authored andcommitted
upload-pack: fix transfer.hiderefs over smart-http
When upload-pack advertises the refs (either for a normal, non-stateless request, or for the initial contact in a stateless one), we call for_each_ref with the send_ref function as its callback. send_ref, in turn, calls mark_our_ref, which checks whether the ref is hidden, and sets OUR_REF or HIDDEN_REF on the object as appropriate. If it is hidden, mark_our_ref also returns "1" to signal send_ref that the ref should not be advertised. If we are not advertising refs, (i.e., the follow-up invocation by an http client to send its "want" lines), we use mark_our_ref directly as a callback to for_each_ref. Its marking does the right thing, but when it then returns "1" to for_each_ref, the latter interprets this as an error and stops iterating. As a result, we skip marking all of the refs that come lexicographically after it. Any "want" lines from the client asking for those objects will fail, as they were not properly marked with OUR_REF. To solve this, we introduce a wrapper callback around mark_our_ref which always returns 0 (even if the ref is hidden, we want to keep iterating). We also tweak the signature of mark_our_ref to exclude unnecessary parameters that were present only to conform to the callback interface. This should make it less likely for somebody to accidentally use it as a callback in the future. Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 3c84ac8 commit e172755

File tree

2 files changed

+21
-4
lines changed

2 files changed

+21
-4
lines changed

t/t5551-http-fetch-smart.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,17 @@ test_expect_success 'cookies stored in http.cookiefile when http.savecookies set
213213
test_cmp expect_cookies.txt cookies_tail.txt
214214
'
215215

216+
test_expect_success 'transfer.hiderefs works over smart-http' '
217+
test_commit hidden &&
218+
test_commit visible &&
219+
git push public HEAD^:refs/heads/a HEAD:refs/heads/b &&
220+
git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \
221+
config transfer.hiderefs refs/heads/a &&
222+
git clone --bare "$HTTPD_URL/smart/repo.git" hidden.git &&
223+
test_must_fail git -C hidden.git rev-parse --verify a &&
224+
git -C hidden.git rev-parse --verify b
225+
'
226+
216227
test_expect_success EXPENSIVE 'create 50,000 tags in the repo' '
217228
(
218229
cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&

upload-pack.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -680,7 +680,7 @@ static void receive_needs(void)
680680
}
681681

682682
/* return non-zero if the ref is hidden, otherwise 0 */
683-
static int mark_our_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
683+
static int mark_our_ref(const char *refname, const unsigned char *sha1)
684684
{
685685
struct object *o = lookup_unknown_object(sha1);
686686

@@ -694,6 +694,12 @@ static int mark_our_ref(const char *refname, const unsigned char *sha1, int flag
694694
return 0;
695695
}
696696

697+
static int check_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
698+
{
699+
mark_our_ref(refname, sha1);
700+
return 0;
701+
}
702+
697703
static void format_symref_info(struct strbuf *buf, struct string_list *symref)
698704
{
699705
struct string_list_item *item;
@@ -712,7 +718,7 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo
712718
const char *refname_nons = strip_namespace(refname);
713719
unsigned char peeled[20];
714720

715-
if (mark_our_ref(refname, sha1, flag, NULL))
721+
if (mark_our_ref(refname, sha1))
716722
return 0;
717723

718724
if (capabilities) {
@@ -766,8 +772,8 @@ static void upload_pack(void)
766772
advertise_shallow_grafts(1);
767773
packet_flush(1);
768774
} else {
769-
head_ref_namespaced(mark_our_ref, NULL);
770-
for_each_namespaced_ref(mark_our_ref, NULL);
775+
head_ref_namespaced(check_ref, NULL);
776+
for_each_namespaced_ref(check_ref, NULL);
771777
}
772778
string_list_clear(&symref, 1);
773779
if (advertise_refs)

0 commit comments

Comments
 (0)