From: Ted Nyman Date: Mon, 27 Jul 2026 00:28:40 +0000 (-0700) Subject: http: accept HTTP 416 for complete partial packs X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=85f4f04f820c9aa6cfdfb4594ceb9b41515a8245;p=thirdparty%2Fgit.git http: accept HTTP 416 for complete partial packs A resumed pack request may already have all bytes of the remote pack. A server can respond to the resulting Range request with HTTP 416 instead of returning an empty response. Accept that response in each pack-download caller and let index-pack validate the completed staging file. This can happen without concurrent downloads when a previous attempt completed the transfer but failed before indexing it. Add a regression test that seeds a complete partial pack and checks that http-fetch indexes it after the server returns HTTP 416. Signed-off-by: Ted Nyman Signed-off-by: Junio C Hamano --- diff --git a/http-fetch.c b/http-fetch.c index 601a77c3c1..05f68f306a 100644 --- a/http-fetch.c +++ b/http-fetch.c @@ -70,7 +70,8 @@ static void fetch_single_packfile(struct object_id *packfile_hash, if (start_active_slot(preq->slot)) { run_active_slot(preq->slot); - if (results.curl_result != CURLE_OK) { + if (results.curl_result != CURLE_OK && + results.http_code != 416) { struct url_info url; char *nurl = url_normalize(preq->url, &url); if (!nurl || !git_env_bool("GIT_TRACE_REDACT", 1)) { diff --git a/http-push.c b/http-push.c index 3c23cbba27..03dc8102a1 100644 --- a/http-push.c +++ b/http-push.c @@ -595,7 +595,8 @@ static void finish_request(struct transfer_request *request) } else if (request->state == RUN_FETCH_PACKED) { int fail = 1; - if (request->curl_result != CURLE_OK) { + if (request->curl_result != CURLE_OK && + request->http_code != 416) { fprintf(stderr, "Unable to get pack file %s\n%s", request->url, curl_errorstr); } else { diff --git a/http-walker.c b/http-walker.c index b58a3b2a92..abafca84d6 100644 --- a/http-walker.c +++ b/http-walker.c @@ -451,7 +451,8 @@ static int http_fetch_pack(struct walker *walker, struct alt_base *repo, if (start_active_slot(preq->slot)) { run_active_slot(preq->slot); - if (results.curl_result != CURLE_OK) { + if (results.curl_result != CURLE_OK && + results.http_code != 416) { error("Unable to get pack file %s\n%s", preq->url, curl_errorstr); goto abort; diff --git a/t/t5550-http-fetch-dumb.sh b/t/t5550-http-fetch-dumb.sh index b0080bf204..621f2fbf73 100755 --- a/t/t5550-http-fetch-dumb.sh +++ b/t/t5550-http-fetch-dumb.sh @@ -293,6 +293,25 @@ test_expect_success 'http-fetch --packfile' ' git -C packfileclient cat-file -e "$HASH" ' +test_expect_success 'http-fetch --packfile accepts an already complete partial' ' + git init packfileclient-complete && + p=$(cd "$HTTPD_DOCUMENT_ROOT_PATH"/repo_pack.git && + ls objects/pack/pack-*.pack) && + packhash=$(basename "$p" .pack) && + packhash=${packhash#pack-} && + tmpfile="packfileclient-complete/.git/objects/pack/pack-$packhash.pack.temp" && + cp "$HTTPD_DOCUMENT_ROOT_PATH/repo_pack.git/$p" "$tmpfile" && + chmod u+w "$tmpfile" && + GIT_TRACE_CURL="$TRASH_DIRECTORY/complete.trace" \ + git -C packfileclient-complete http-fetch --packfile="$packhash" \ + --index-pack-arg=index-pack \ + --index-pack-arg=--stdin --index-pack-arg=--keep \ + "$HTTPD_URL/dumb/repo_pack.git/$p" >out && + test_grep "416 Requested Range Not Satisfiable" complete.trace && + test_path_is_missing "$tmpfile" && + git -C packfileclient-complete cat-file -e "$HASH" +' + test_expect_success 'fetch notices corrupt pack' ' cp -R "$HTTPD_DOCUMENT_ROOT_PATH"/repo_pack.git "$HTTPD_DOCUMENT_ROOT_PATH"/repo_bad1.git && (cd "$HTTPD_DOCUMENT_ROOT_PATH"/repo_bad1.git &&