{"thread":{"id":"19709","subject":"[PATCH 01/23] t5540-http-push: test fetching of loose objects","startedAt":"2009-06-06T08:43:23Z","lastAt":"2009-06-06T08:44:02Z","messageCount":23,"participants":["Tay Ray Chuan"],"isPatch":true,"patchVersion":1,"patchTotal":23},"messages":[{"id":"115613","messageId":"20090606164323.471f5224.rctay89@gmail.com","threadId":"19709","inReplyTo":"cover.1244277116.git.rctay89@gmail.com","subject":"[PATCH 01/23] t5540-http-push: test fetching of loose objects","fromName":"Tay Ray Chuan","fromEmail":"rctay89@gmail.com","sentAt":"2009-06-06T08:43:23Z","receivedAt":"2009-06-06T08:43:23Z","isPatch":true,"sender":{"key":"rctay89@gmail.com","avatar":"https://avatars.githubusercontent.com/u/61553?v=4"},"body":"\nSigned-off-by: Tay Ray Chuan <rctay89@gmail.com>\n---\n t/t5540-http-push.sh |   16 ++++++++++++++++\n 1 files changed, 16 insertions(+), 0 deletions(-)\n\ndiff --git a/t/t5540-http-push.sh b/t/t5540-http-push.sh\nindex 5fe479e..65a41db 100755\n--- a/t/t5540-http-push.sh\n+++ b/t/t5540-http-push.sh\n@@ -67,6 +67,22 @@ test_expect_success ' push to remote repository with unpacked refs' '\n \t test $HEAD = $(git rev-parse --verify HEAD))\n '\n\n+test_expect_failure 'http-push fetches unpacked objects' '\n+\tcp -R \"$HTTPD_DOCUMENT_ROOT_PATH\"/test_repo.git \\\n+\t\t\"$HTTPD_DOCUMENT_ROOT_PATH\"/test_repo_unpacked.git &&\n+\n+\tgit clone $HTTPD_URL/test_repo_unpacked.git \\\n+\t\t\"$ROOT_PATH\"/fetch_unpacked &&\n+\n+\t# By reset, we force git to retrieve the object\n+\t(cd \"$ROOT_PATH\"/fetch_unpacked &&\n+\t git reset --hard HEAD^ &&\n+\t git remote rm origin &&\n+\t git reflog expire --expire=0 --all &&\n+\t git prune &&\n+\t git push -f -v $HTTPD_URL/test_repo_unpacked.git master)\n+'\n+\n test_expect_success 'create and delete remote branch' '\n \tcd \"$ROOT_PATH\"/test_repo_clone &&\n \tgit checkout -b dev &&\n--\n1.6.3.1\n"},{"id":"115615","messageId":"20090606164324.c0a5e319.rctay89@gmail.com","threadId":"19709","inReplyTo":"cover.1244277116.git.rctay89@gmail.com","subject":"[PATCH 02/23] t5540-http-push: test fetching of packed objects","fromName":"Tay Ray Chuan","fromEmail":"rctay89@gmail.com","sentAt":"2009-06-06T08:43:24Z","receivedAt":"2009-06-06T08:43:24Z","isPatch":true,"sender":{"key":"rctay89@gmail.com","avatar":"https://avatars.githubusercontent.com/u/61553?v=4"},"body":"\nSigned-off-by: Tay Ray Chuan <rctay89@gmail.com>\n---\n t/t5540-http-push.sh |   20 ++++++++++++++++++++\n 1 files changed, 20 insertions(+), 0 deletions(-)\n\ndiff --git a/t/t5540-http-push.sh b/t/t5540-http-push.sh\nindex 65a41db..ad0f14b 100755\n--- a/t/t5540-http-push.sh\n+++ b/t/t5540-http-push.sh\n@@ -83,6 +83,26 @@ test_expect_failure 'http-push fetches unpacked objects' '\n \t git push -f -v $HTTPD_URL/test_repo_unpacked.git master)\n '\n\n+test_expect_failure 'http-push fetches packed objects' '\n+\tcp -R \"$HTTPD_DOCUMENT_ROOT_PATH\"/test_repo.git \\\n+\t\t\"$HTTPD_DOCUMENT_ROOT_PATH\"/test_repo_packed.git &&\n+\n+\tgit clone $HTTPD_URL/test_repo_packed.git \\\n+\t\t\"$ROOT_PATH\"/test_repo_clone_packed &&\n+\n+\t(cd \"$HTTPD_DOCUMENT_ROOT_PATH\"/test_repo_packed.git &&\n+\t git --bare repack &&\n+\t git --bare prune-packed) &&\n+\n+\t# By reset, we force git to retrieve the packed object\n+\t(cd \"$ROOT_PATH\"/test_repo_clone_packed &&\n+\t git reset --hard HEAD^ &&\n+\t git remote rm origin &&\n+\t git reflog expire --expire=0 --all &&\n+\t git prune &&\n+\t git push -f -v $HTTPD_URL/test_repo_packed.git master)\n+'\n+\n test_expect_success 'create and delete remote branch' '\n \tcd \"$ROOT_PATH\"/test_repo_clone &&\n \tgit checkout -b dev &&\n--\n1.6.3.1\n"},{"id":"115617","messageId":"20090606164326.164ce1e7.rctay89@gmail.com","threadId":"19709","inReplyTo":"cover.1244277116.git.rctay89@gmail.com","subject":"[PATCH 03/23] http*: cleanup slot->local after fclose","fromName":"Tay Ray Chuan","fromEmail":"rctay89@gmail.com","sentAt":"2009-06-06T08:43:26Z","receivedAt":"2009-06-06T08:43:26Z","isPatch":true,"sender":{"key":"rctay89@gmail.com","avatar":"https://avatars.githubusercontent.com/u/61553?v=4"},"body":"Set slot->local to NULL after doing a fclose() on the file it points\nto. This prevents the passing of a FILE* pointer to a fclose()'d file\nto ftell() in http.c::run_active_slot().\n\nThis issue was raised by Clemens Buchacher on 30th May 2009:\n\n  http://www.spinics.net/lists/git/msg104623.html\n\nSigned-off-by: Tay Ray Chuan <rctay89@gmail.com>\n---\n http-push.c   |    6 ++++++\n http-walker.c |    6 ++++++\n 2 files changed, 12 insertions(+), 0 deletions(-)\n\ndiff --git a/http-push.c b/http-push.c\nindex e16a0ad..0b12ffe 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -724,9 +724,11 @@ static void finish_request(struct transfer_request *request)\n \tstruct stat st;\n \tstruct packed_git *target;\n \tstruct packed_git **lst;\n+\tstruct active_request_slot *slot;\n\n \trequest->curl_result = request->slot->curl_result;\n \trequest->http_code = request->slot->http_code;\n+\tslot = request->slot;\n \trequest->slot = NULL;\n\n \t/* Keep locks active */\n@@ -823,6 +825,7 @@ static void finish_request(struct transfer_request *request)\n\n \t\t\tfclose(request->local_stream);\n \t\t\trequest->local_stream = NULL;\n+\t\t\tslot->local = NULL;\n \t\t\tif (!move_temp_to_file(request->tmpfile,\n \t\t\t\t\t       request->filename)) {\n \t\t\t\ttarget = (struct packed_git *)request->userData;\n@@ -1024,17 +1027,20 @@ static int fetch_index(unsigned char *sha1)\n \t\tif (results.curl_result != CURLE_OK) {\n \t\t\tfree(url);\n \t\t\tfclose(indexfile);\n+\t\t\tslot->local = NULL;\n \t\t\treturn error(\"Unable to get pack index %s\\n%s\", url,\n \t\t\t\t     curl_errorstr);\n \t\t}\n \t} else {\n \t\tfree(url);\n \t\tfclose(indexfile);\n+\t\tslot->local = NULL;\n \t\treturn error(\"Unable to start request\");\n \t}\n\n \tfree(url);\n \tfclose(indexfile);\n+\tslot->local = NULL;\n\n \treturn move_temp_to_file(tmpfile, filename);\n }\ndiff --git a/http-walker.c b/http-walker.c\nindex 7321ccc..9377851 100644\n--- a/http-walker.c\n+++ b/http-walker.c\n@@ -418,15 +418,18 @@ static int fetch_index(struct walker *walker, struct alt_base *repo, unsigned ch\n \t\trun_active_slot(slot);\n \t\tif (results.curl_result != CURLE_OK) {\n \t\t\tfclose(indexfile);\n+\t\t\tslot->local = NULL;\n \t\t\treturn error(\"Unable to get pack index %s\\n%s\", url,\n \t\t\t\t     curl_errorstr);\n \t\t}\n \t} else {\n \t\tfclose(indexfile);\n+\t\tslot->local = NULL;\n \t\treturn error(\"Unable to start request\");\n \t}\n\n \tfclose(indexfile);\n+\tslot->local = NULL;\n\n \treturn move_temp_to_file(tmpfile, filename);\n }\n@@ -776,16 +779,19 @@ static int fetch_pack(struct walker *walker, struct alt_base *repo, unsigned cha\n \t\trun_active_slot(slot);\n \t\tif (results.curl_result != CURLE_OK) {\n \t\t\tfclose(packfile);\n+\t\t\tslot->local = NULL;\n \t\t\treturn error(\"Unable to get pack file %s\\n%s\", url,\n \t\t\t\t     curl_errorstr);\n \t\t}\n \t} else {\n \t\tfclose(packfile);\n+\t\tslot->local = NULL;\n \t\treturn error(\"Unable to start request\");\n \t}\n\n \ttarget->pack_size = ftell(packfile);\n \tfclose(packfile);\n+\tslot->local = NULL;\n\n \tret = move_temp_to_file(tmpfile, filename);\n \tif (ret)\n--\n1.6.3.1\n"},{"id":"115616","messageId":"20090606164327.da5ca480.rctay89@gmail.com","threadId":"19709","inReplyTo":"cover.1244277116.git.rctay89@gmail.com","subject":"[PATCH 04/23] http-push: send out fetch requests on queue","fromName":"Tay Ray Chuan","fromEmail":"rctay89@gmail.com","sentAt":"2009-06-06T08:43:27Z","receivedAt":"2009-06-06T08:43:27Z","isPatch":true,"sender":{"key":"rctay89@gmail.com","avatar":"https://avatars.githubusercontent.com/u/61553?v=4"},"body":"Previously, requests for remote files were simply added to the queue\n(pointed to by request_queue_head) and no transfer actually takes\nplace (the fill function add_fill_function() is not added until line\n2441), even though code that followed may rely on these remote files to\nbe present (eg. the setup_revisions invocation).\n\nThe code that sends out the requests on the request queue is refactored\ninto the method run_request_queue.\n\nAfter the get_dav_remote_heads invocation (ie. after fetch requests are\nadded to the queue), the requests on the queue are sent out through an\ninvocation to run_request_queue.\n\nThis invocation to run_request_queue entails adding a fill function\nbefore pushing checks take place, which may lead to accidental,\nunwanted pushes previously.\n\nThe flag is_running_queue is introduced to prevent this from occurring.\nfill_active_slot is made to check the flag is_running_queue before\nthe sending of the requests proceeds.\n\nSigned-off-by: Tay Ray Chuan <rctay89@gmail.com>\n---\n http-push.c          |   37 ++++++++++++++++++++++++++-----------\n t/t5540-http-push.sh |    4 ++--\n 2 files changed, 28 insertions(+), 13 deletions(-)\n\ndiff --git a/http-push.c b/http-push.c\nindex 0b12ffe..218e263 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -846,11 +846,12 @@ static void finish_request(struct transfer_request *request)\n }\n\n #ifdef USE_CURL_MULTI\n+static int is_running_queue;\n static int fill_active_slot(void *unused)\n {\n \tstruct transfer_request *request;\n\n-\tif (aborted)\n+\tif (aborted || !is_running_queue)\n \t\treturn 0;\n\n \tfor (request = request_queue_head; request; request = request->next) {\n@@ -2174,6 +2175,25 @@ static int delete_remote_branch(char *pattern, int force)\n \treturn 0;\n }\n\n+void run_request_queue()\n+{\n+#ifdef USE_CURL_MULTI\n+\tis_running_queue = 1;\n+\tfill_active_slots();\n+\tadd_fill_function(NULL, fill_active_slot);\n+#endif\n+\tdo {\n+\t\tfinish_all_active_slots();\n+#ifdef USE_CURL_MULTI\n+\t\tfill_active_slots();\n+#endif\n+\t} while (request_queue_head && !aborted);\n+\n+#ifdef USE_CURL_MULTI\n+\tis_running_queue = 0;\n+#endif\n+}\n+\n int main(int argc, char **argv)\n {\n \tstruct transfer_request *request;\n@@ -2278,6 +2298,8 @@ int main(int argc, char **argv)\n \t\trepo->url = rewritten_url;\n \t}\n\n+\tis_running_queue = 0;\n+\n \t/* Verify DAV compliance/lock support */\n \tif (!locking_available()) {\n \t\trc = 1;\n@@ -2307,6 +2329,7 @@ int main(int argc, char **argv)\n \tlocal_refs = get_local_heads();\n \tfprintf(stderr, \"Fetching remote heads...\\n\");\n \tget_dav_remote_heads();\n+\trun_request_queue();\n\n \t/* Remove a remote branch if -d or -D was specified */\n \tif (delete_branch) {\n@@ -2436,16 +2459,8 @@ int main(int argc, char **argv)\n \t\tif (objects_to_send)\n \t\t\tfprintf(stderr, \"    sending %d objects\\n\",\n \t\t\t\tobjects_to_send);\n-#ifdef USE_CURL_MULTI\n-\t\tfill_active_slots();\n-\t\tadd_fill_function(NULL, fill_active_slot);\n-#endif\n-\t\tdo {\n-\t\t\tfinish_all_active_slots();\n-#ifdef USE_CURL_MULTI\n-\t\t\tfill_active_slots();\n-#endif\n-\t\t} while (request_queue_head && !aborted);\n+\n+\t\trun_request_queue();\n\n \t\t/* Update the remote branch if all went well */\n \t\tif (aborted || !update_remote(ref->new_sha1, ref_lock))\ndiff --git a/t/t5540-http-push.sh b/t/t5540-http-push.sh\nindex ad0f14b..f4a2cf6 100755\n--- a/t/t5540-http-push.sh\n+++ b/t/t5540-http-push.sh\n@@ -67,7 +67,7 @@ test_expect_success ' push to remote repository with unpacked refs' '\n \t test $HEAD = $(git rev-parse --verify HEAD))\n '\n\n-test_expect_failure 'http-push fetches unpacked objects' '\n+test_expect_success 'http-push fetches unpacked objects' '\n \tcp -R \"$HTTPD_DOCUMENT_ROOT_PATH\"/test_repo.git \\\n \t\t\"$HTTPD_DOCUMENT_ROOT_PATH\"/test_repo_unpacked.git &&\n\n@@ -83,7 +83,7 @@ test_expect_failure 'http-push fetches unpacked objects' '\n \t git push -f -v $HTTPD_URL/test_repo_unpacked.git master)\n '\n\n-test_expect_failure 'http-push fetches packed objects' '\n+test_expect_success 'http-push fetches packed objects' '\n \tcp -R \"$HTTPD_DOCUMENT_ROOT_PATH\"/test_repo.git \\\n \t\t\"$HTTPD_DOCUMENT_ROOT_PATH\"/test_repo_packed.git &&\n\n--\n1.6.3.1\n"},{"id":"115618","messageId":"20090606164331.1aa6bdf6.rctay89@gmail.com","threadId":"19709","inReplyTo":"cover.1244277116.git.rctay89@gmail.com","subject":"[PATCH 05/23] http-push: fix missing \"#ifdef USE_CURL_MULTI\" around \"is_running_queue\"","fromName":"Tay Ray Chuan","fromEmail":"rctay89@gmail.com","sentAt":"2009-06-06T08:43:31Z","receivedAt":"2009-06-06T08:43:31Z","isPatch":true,"sender":{"key":"rctay89@gmail.com","avatar":"https://avatars.githubusercontent.com/u/61553?v=4"},"body":"As it is breaking the build when USE_CURL_MULTI is not defined.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Tay Ray Chuan <rctay89@gmail.com>\n---\n http-push.c |    2 ++\n 1 files changed, 2 insertions(+), 0 deletions(-)\n\ndiff --git a/http-push.c b/http-push.c\nindex 218e263..1d84f3b 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -2298,7 +2298,9 @@ int main(int argc, char **argv)\n \t\trepo->url = rewritten_url;\n \t}\n\n+#ifdef USE_CURL_MULTI\n \tis_running_queue = 0;\n+#endif\n\n \t/* Verify DAV compliance/lock support */\n \tif (!locking_available()) {\n--\n1.6.3.1\n"},{"id":"115619","messageId":"20090606164332.6c11b93b.rctay89@gmail.com","threadId":"19709","inReplyTo":"cover.1244277116.git.rctay89@gmail.com","subject":"[PATCH 06/23] t5550-http-fetch: test fetching of packed objects","fromName":"Tay Ray Chuan","fromEmail":"rctay89@gmail.com","sentAt":"2009-06-06T08:43:32Z","receivedAt":"2009-06-06T08:43:32Z","isPatch":true,"sender":{"key":"rctay89@gmail.com","avatar":"https://avatars.githubusercontent.com/u/61553?v=4"},"body":"\nSigned-off-by: Tay Ray Chuan <rctay89@gmail.com>\n---\n t/t5550-http-fetch.sh |    8 ++++++++\n 1 files changed, 8 insertions(+), 0 deletions(-)\n\ndiff --git a/t/t5550-http-fetch.sh b/t/t5550-http-fetch.sh\nindex 05b1b62..0e69324 100755\n--- a/t/t5550-http-fetch.sh\n+++ b/t/t5550-http-fetch.sh\n@@ -53,5 +53,13 @@ test_expect_success 'http remote detects correct HEAD' '\n \t)\n '\n\n+test_expect_success 'fetch packed objects' '\n+\tcp -R \"$HTTPD_DOCUMENT_ROOT_PATH\"/repo.git \"$HTTPD_DOCUMENT_ROOT_PATH\"/repo_pack.git &&\n+\tcd \"$HTTPD_DOCUMENT_ROOT_PATH\"/repo_pack.git &&\n+\tgit --bare repack &&\n+\tgit --bare prune-packed &&\n+\tgit clone $HTTPD_URL/repo_pack.git\n+'\n+\n stop_httpd\n test_done\n--\n1.6.3.1\n"},{"id":"115620","messageId":"20090606164333.85a57ade.rctay89@gmail.com","threadId":"19709","inReplyTo":"cover.1244277116.git.rctay89@gmail.com","subject":"[PATCH 07/23] http-push, http-walker: style fixes","fromName":"Tay Ray Chuan","fromEmail":"rctay89@gmail.com","sentAt":"2009-06-06T08:43:33Z","receivedAt":"2009-06-06T08:43:33Z","isPatch":true,"sender":{"key":"rctay89@gmail.com","avatar":"https://avatars.githubusercontent.com/u/61553?v=4"},"body":"- Use tabs to indent, instead of spaces.\n\n- Do not use curly-braces around a single statement body in\n  if/while statement;\n\n- Do not start multi-line comment with description on the first\n  line after \"/*\", i.e.\n\n  /*\n   * We prefer this over...\n   */\n\n  /* comments like\n   * this (notice the first line)\n   */\n\nSigned-off-by: Tay Ray Chuan <rctay89@gmail.com>\n---\n http-push.c   |   48 ++++++++++++++++++++-------------\n http-walker.c |   83 ++++++++++++++++++++++++++++++++++----------------------\n 2 files changed, 79 insertions(+), 52 deletions(-)\n\ndiff --git a/http-push.c b/http-push.c\nindex 1d84f3b..6ac0d63 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -276,7 +276,7 @@ static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,\n \tstruct transfer_request *request = (struct transfer_request *)data;\n \tdo {\n \t\tssize_t retval = xwrite(request->local_fileno,\n-\t\t\t\t       (char *) ptr + posn, size - posn);\n+\t\t\t\t\t(char *) ptr + posn, size - posn);\n \t\tif (retval < 0)\n \t\t\treturn posn;\n \t\tposn += retval;\n@@ -289,7 +289,7 @@ static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,\n \t\trequest->stream.avail_out = sizeof(expn);\n \t\trequest->zret = git_inflate(&request->stream, Z_SYNC_FLUSH);\n \t\tgit_SHA1_Update(&request->c, expn,\n-\t\t\t    sizeof(expn) - request->stream.avail_out);\n+\t\t\t\tsizeof(expn) - request->stream.avail_out);\n \t} while (request->stream.avail_in && request->zret == Z_OK);\n \tdata_received++;\n \treturn size;\n@@ -323,7 +323,8 @@ static void start_fetch_loose(struct transfer_request *request)\n \t\terror(\"fd leakage in start: %d\", request->local_fileno);\n \trequest->local_fileno = open(request->tmpfile,\n \t\t\t\t     O_WRONLY | O_CREAT | O_EXCL, 0666);\n-\t/* This could have failed due to the \"lazy directory creation\";\n+\t/*\n+\t * This could have failed due to the \"lazy directory creation\";\n \t * try to mkdir the last path component.\n \t */\n \tif (request->local_fileno < 0 && errno == ENOENT) {\n@@ -353,8 +354,10 @@ static void start_fetch_loose(struct transfer_request *request)\n \turl = get_remote_object_url(repo->url, hex, 0);\n \trequest->url = xstrdup(url);\n\n-\t/* If a previous temp file is present, process what was already\n-\t   fetched. */\n+\t/*\n+\t * If a previous temp file is present, process what was already\n+\t * fetched.\n+\t */\n \tprevlocal = open(prevfile, O_RDONLY);\n \tif (prevlocal != -1) {\n \t\tdo {\n@@ -363,19 +366,20 @@ static void start_fetch_loose(struct transfer_request *request)\n \t\t\t\tif (fwrite_sha1_file(prev_buf,\n \t\t\t\t\t\t     1,\n \t\t\t\t\t\t     prev_read,\n-\t\t\t\t\t\t     request) == prev_read) {\n+\t\t\t\t\t\t     request) == prev_read)\n \t\t\t\t\tprev_posn += prev_read;\n-\t\t\t\t} else {\n+\t\t\t\telse\n \t\t\t\t\tprev_read = -1;\n-\t\t\t\t}\n \t\t\t}\n \t\t} while (prev_read > 0);\n \t\tclose(prevlocal);\n \t}\n \tunlink_or_warn(prevfile);\n\n-\t/* Reset inflate/SHA1 if there was an error reading the previous temp\n-\t   file; also rewind to the beginning of the local file. */\n+\t/*\n+\t * Reset inflate/SHA1 if there was an error reading the previous temp\n+\t * file; also rewind to the beginning of the local file.\n+\t */\n \tif (prev_read == -1) {\n \t\tmemset(&request->stream, 0, sizeof(request->stream));\n \t\tgit_inflate_init(&request->stream);\n@@ -398,8 +402,10 @@ static void start_fetch_loose(struct transfer_request *request)\n \tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n \tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);\n\n-\t/* If we have successfully processed data from a previous fetch\n-\t   attempt, only fetch the data we don't already have. */\n+\t/*\n+\t * If we have successfully processed data from a previous fetch\n+\t * attempt, only fetch the data we don't already have.\n+\t */\n \tif (prev_posn>0) {\n \t\tif (push_verbosely)\n \t\t\tfprintf(stderr,\n@@ -514,8 +520,10 @@ static void start_fetch_packed(struct transfer_request *request)\n \tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);\n \tslot->local = packfile;\n\n-\t/* If there is data present from a previous transfer attempt,\n-\t   resume where it left off */\n+\t/*\n+\t * If there is data present from a previous transfer attempt,\n+\t * resume where it left off\n+\t */\n \tprev_posn = ftell(packfile);\n \tif (prev_posn>0) {\n \t\tif (push_verbosely)\n@@ -780,7 +788,8 @@ static void finish_request(struct transfer_request *request)\n \t\t\taborted = 1;\n \t\t}\n \t} else if (request->state == RUN_FETCH_LOOSE) {\n-\t\tclose(request->local_fileno); request->local_fileno = -1;\n+\t\tclose(request->local_fileno);\n+\t\trequest->local_fileno = -1;\n\n \t\tif (request->curl_result != CURLE_OK &&\n \t\t    request->http_code != 416) {\n@@ -803,9 +812,8 @@ static void finish_request(struct transfer_request *request)\n \t\t\t\t\tmove_temp_to_file(\n \t\t\t\t\t\trequest->tmpfile,\n \t\t\t\t\t\trequest->filename);\n-\t\t\t\tif (request->rename == 0) {\n+\t\t\t\tif (request->rename == 0)\n \t\t\t\t\trequest->obj->flags |= (LOCAL | REMOTE);\n-\t\t\t\t}\n \t\t\t}\n \t\t}\n\n@@ -1010,8 +1018,10 @@ static int fetch_index(unsigned char *sha1)\n \tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);\n \tslot->local = indexfile;\n\n-\t/* If there is data present from a previous transfer attempt,\n-\t   resume where it left off */\n+\t/*\n+\t * If there is data present from a previous transfer attempt,\n+\t * resume where it left off\n+\t */\n \tprev_posn = ftell(indexfile);\n \tif (prev_posn>0) {\n \t\tif (push_verbosely)\ndiff --git a/http-walker.c b/http-walker.c\nindex 9377851..6ac1783 100644\n--- a/http-walker.c\n+++ b/http-walker.c\n@@ -71,7 +71,7 @@ static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,\n \tstruct object_request *obj_req = (struct object_request *)data;\n \tdo {\n \t\tssize_t retval = xwrite(obj_req->local,\n-\t\t\t\t       (char *) ptr + posn, size - posn);\n+\t\t\t\t\t(char *) ptr + posn, size - posn);\n \t\tif (retval < 0)\n \t\t\treturn posn;\n \t\tposn += retval;\n@@ -84,7 +84,7 @@ static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,\n \t\tobj_req->stream.avail_out = sizeof(expn);\n \t\tobj_req->zret = git_inflate(&obj_req->stream, Z_SYNC_FLUSH);\n \t\tgit_SHA1_Update(&obj_req->c, expn,\n-\t\t\t    sizeof(expn) - obj_req->stream.avail_out);\n+\t\t\t\tsizeof(expn) - obj_req->stream.avail_out);\n \t} while (obj_req->stream.avail_in && obj_req->zret == Z_OK);\n \tdata_received++;\n \treturn size;\n@@ -119,7 +119,8 @@ static void start_object_request(struct walker *walker,\n \t\terror(\"fd leakage in start: %d\", obj_req->local);\n \tobj_req->local = open(obj_req->tmpfile,\n \t\t\t      O_WRONLY | O_CREAT | O_EXCL, 0666);\n-\t/* This could have failed due to the \"lazy directory creation\";\n+\t/*\n+\t * This could have failed due to the \"lazy directory creation\";\n \t * try to mkdir the last path component.\n \t */\n \tif (obj_req->local < 0 && errno == ENOENT) {\n@@ -158,8 +159,10 @@ static void start_object_request(struct walker *walker,\n \tstrcpy(posn, hex + 2);\n \tstrcpy(obj_req->url, url);\n\n-\t/* If a previous temp file is present, process what was already\n-\t   fetched. */\n+\t/*\n+\t * If a previous temp file is present, process what was already\n+\t * fetched.\n+\t */\n \tprevlocal = open(prevfile, O_RDONLY);\n \tif (prevlocal != -1) {\n \t\tdo {\n@@ -168,19 +171,20 @@ static void start_object_request(struct walker *walker,\n \t\t\t\tif (fwrite_sha1_file(prev_buf,\n \t\t\t\t\t\t     1,\n \t\t\t\t\t\t     prev_read,\n-\t\t\t\t\t\t     obj_req) == prev_read) {\n+\t\t\t\t\t\t     obj_req) == prev_read)\n \t\t\t\t\tprev_posn += prev_read;\n-\t\t\t\t} else {\n+\t\t\t\telse\n \t\t\t\t\tprev_read = -1;\n-\t\t\t\t}\n \t\t\t}\n \t\t} while (prev_read > 0);\n \t\tclose(prevlocal);\n \t}\n \tunlink_or_warn(prevfile);\n\n-\t/* Reset inflate/SHA1 if there was an error reading the previous temp\n-\t   file; also rewind to the beginning of the local file. */\n+\t/*\n+\t * Reset inflate/SHA1 if there was an error reading the previous temp\n+\t * file; also rewind to the beginning of the local file.\n+\t */\n \tif (prev_read == -1) {\n \t\tmemset(&obj_req->stream, 0, sizeof(obj_req->stream));\n \t\tgit_inflate_init(&obj_req->stream);\n@@ -203,8 +207,10 @@ static void start_object_request(struct walker *walker,\n \tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n \tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, data->no_pragma_header);\n\n-\t/* If we have successfully processed data from a previous fetch\n-\t   attempt, only fetch the data we don't already have. */\n+\t/*\n+\t * If we have successfully processed data from a previous fetch\n+\t * attempt, only fetch the data we don't already have.\n+\t */\n \tif (prev_posn>0) {\n \t\tif (walker->get_verbosely)\n \t\t\tfprintf(stderr,\n@@ -221,7 +227,8 @@ static void start_object_request(struct walker *walker,\n \tif (!start_active_slot(slot)) {\n \t\tobj_req->state = ABORTED;\n \t\tobj_req->slot = NULL;\n-\t\tclose(obj_req->local); obj_req->local = -1;\n+\t\tclose(obj_req->local);\n+\t\tobj_req->local = -1;\n \t\tfree(obj_req->url);\n \t\treturn;\n \t}\n@@ -231,7 +238,8 @@ static void finish_object_request(struct object_request *obj_req)\n {\n \tstruct stat st;\n\n-\tclose(obj_req->local); obj_req->local = -1;\n+\tclose(obj_req->local);\n+\tobj_req->local = -1;\n\n \tif (obj_req->http_code == 416) {\n \t\tfprintf(stderr, \"Warning: requested range invalid; we may already have all the data.\\n\");\n@@ -350,9 +358,8 @@ static void prefetch(struct walker *walker, unsigned char *sha1)\n \t\tobject_queue_head = newreq;\n \t} else {\n \t\ttail = object_queue_head;\n-\t\twhile (tail->next != NULL) {\n+\t\twhile (tail->next != NULL)\n \t\t\ttail = tail->next;\n-\t\t}\n \t\ttail->next = newreq;\n \t}\n\n@@ -401,8 +408,10 @@ static int fetch_index(struct walker *walker, struct alt_base *repo, unsigned ch\n \tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, data->no_pragma_header);\n \tslot->local = indexfile;\n\n-\t/* If there is data present from a previous transfer attempt,\n-\t   resume where it left off */\n+\t/*\n+\t * If there is data present from a previous transfer attempt,\n+\t * resume where it left off\n+\t */\n \tprev_posn = ftell(indexfile);\n \tif (prev_posn>0) {\n \t\tif (walker->get_verbosely)\n@@ -507,7 +516,8 @@ static void process_alternates_response(void *callback_data)\n \t\t\tstruct alt_base *newalt;\n \t\t\tchar *target = NULL;\n \t\t\tif (data[i] == '/') {\n-\t\t\t\t/* This counts\n+\t\t\t\t/*\n+\t\t\t\t * This counts\n \t\t\t\t * http://git.host/pub/scm/linux.git/\n \t\t\t\t * -----------here^\n \t\t\t\t * so memcpy(dst, base, serverlen) will\n@@ -520,7 +530,8 @@ static void process_alternates_response(void *callback_data)\n \t\t\t\t\tokay = 1;\n \t\t\t\t}\n \t\t\t} else if (!memcmp(data + i, \"../\", 3)) {\n-\t\t\t\t/* Relative URL; chop the corresponding\n+\t\t\t\t/*\n+\t\t\t\t * Relative URL; chop the corresponding\n \t\t\t\t * number of subpath from base (and ../\n \t\t\t\t * from data), and concatenate the result.\n \t\t\t\t *\n@@ -549,7 +560,7 @@ static void process_alternates_response(void *callback_data)\n \t\t\t\t}\n \t\t\t\t/* If the server got removed, give up. */\n \t\t\t\tokay = strchr(base, ':') - base + 3 <\n-\t\t\t\t\tserverlen;\n+\t\t\t\t       serverlen;\n \t\t\t} else if (alt_req->http_specific) {\n \t\t\t\tchar *colon = strchr(data + i, ':');\n \t\t\t\tchar *slash = strchr(data + i, '/');\n@@ -593,9 +604,11 @@ static void fetch_alternates(struct walker *walker, const char *base)\n \tstruct alternates_request alt_req;\n \tstruct walker_data *cdata = walker->data;\n\n-\t/* If another request has already started fetching alternates,\n-\t   wait for them to arrive and return to processing this request's\n-\t   curl message */\n+\t/*\n+\t * If another request has already started fetching alternates,\n+\t * wait for them to arrive and return to processing this request's\n+\t * curl message\n+\t */\n #ifdef USE_CURL_MULTI\n \twhile (cdata->got_alternates == 0) {\n \t\tstep_active_slots();\n@@ -615,8 +628,10 @@ static void fetch_alternates(struct walker *walker, const char *base)\n \turl = xmalloc(strlen(base) + 31);\n \tsprintf(url, \"%s/objects/info/http-alternates\", base);\n\n-\t/* Use a callback to process the result, since another request\n-\t   may fail and need to have alternates loaded before continuing */\n+\t/*\n+\t * Use a callback to process the result, since another request\n+\t * may fail and need to have alternates loaded before continuing\n+\t */\n \tslot = get_active_slot();\n \tslot->callback_func = process_alternates_response;\n \talt_req.walker = walker;\n@@ -762,8 +777,10 @@ static int fetch_pack(struct walker *walker, struct alt_base *repo, unsigned cha\n \tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, data->no_pragma_header);\n \tslot->local = packfile;\n\n-\t/* If there is data present from a previous transfer attempt,\n-\t   resume where it left off */\n+\t/*\n+\t * If there is data present from a previous transfer attempt,\n+\t * resume where it left off\n+\t */\n \tprev_posn = ftell(packfile);\n \tif (prev_posn>0) {\n \t\tif (walker->get_verbosely)\n@@ -840,18 +857,18 @@ static int fetch_object(struct walker *walker, struct alt_base *repo, unsigned c\n \t}\n\n #ifdef USE_CURL_MULTI\n-\twhile (obj_req->state == WAITING) {\n+\twhile (obj_req->state == WAITING)\n \t\tstep_active_slots();\n-\t}\n #else\n \tstart_object_request(walker, obj_req);\n #endif\n\n-\twhile (obj_req->state == ACTIVE) {\n+\twhile (obj_req->state == ACTIVE)\n \t\trun_active_slot(obj_req->slot);\n-\t}\n+\n \tif (obj_req->local != -1) {\n-\t\tclose(obj_req->local); obj_req->local = -1;\n+\t\tclose(obj_req->local);\n+\t\tobj_req->local = -1;\n \t}\n\n \tif (obj_req->state == ABORTED) {\n--\n1.6.3.1\n"},{"id":"115621","messageId":"20090606164334.b25e538e.rctay89@gmail.com","threadId":"19709","inReplyTo":"cover.1244277116.git.rctay89@gmail.com","subject":"[PATCH 08/23] http-walker: verify remote packs","fromName":"Tay Ray Chuan","fromEmail":"rctay89@gmail.com","sentAt":"2009-06-06T08:43:34Z","receivedAt":"2009-06-06T08:43:34Z","isPatch":true,"sender":{"key":"rctay89@gmail.com","avatar":"https://avatars.githubusercontent.com/u/61553?v=4"},"body":"In c17fb6e (\"Verify remote packs, speed up pending request queue\"),\nchanges were made to index fetching in http-push.c, particularly the\nmethods fetch_index and setup_index. Since http-walker.c has similar\ncode for index fetching, these improvements should apply to\nhttp-walker.c's fetch_index and setup_index.\n\nInvocations of free() of string memory are reproduced as well.\n\nSigned-off-by: Tay Ray Chuan <rctay89@gmail.com>\n---\n http-walker.c |   33 ++++++++++++++++++++++++++++++---\n 1 files changed, 30 insertions(+), 3 deletions(-)\n\ndiff --git a/http-walker.c b/http-walker.c\nindex 6ac1783..bbc3023 100644\n--- a/http-walker.c\n+++ b/http-walker.c\n@@ -384,24 +384,48 @@ static int fetch_index(struct walker *walker, struct alt_base *repo, unsigned ch\n \tstruct active_request_slot *slot;\n \tstruct slot_results results;\n\n-\tif (has_pack_index(sha1))\n+\t/* Don't use the index if the pack isn't there */\n+\turl = xmalloc(strlen(repo->base) + 64);\n+\tsprintf(url, \"%s/objects/pack/pack-%s.pack\", repo->base, hex);\n+\tslot = get_active_slot();\n+\tslot->results = &results;\n+\tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n+\tcurl_easy_setopt(slot->curl, CURLOPT_NOBODY, 1);\n+\tif (start_active_slot(slot)) {\n+\t\trun_active_slot(slot);\n+\t\tif (results.curl_result != CURLE_OK) {\n+\t\t\tfree(url);\n+\t\t\treturn error(\"Unable to verify pack %s is available\",\n+\t\t\t\t     hex);\n+\t\t}\n+\t} else {\n+\t\tfree(url);\n+\t\treturn error(\"Unable to start request\");\n+\t}\n+\n+\tif (has_pack_index(sha1)) {\n+\t\tfree(url);\n \t\treturn 0;\n+\t}\n\n \tif (walker->get_verbosely)\n \t\tfprintf(stderr, \"Getting index for pack %s\\n\", hex);\n\n-\turl = xmalloc(strlen(repo->base) + 64);\n \tsprintf(url, \"%s/objects/pack/pack-%s.idx\", repo->base, hex);\n\n \tfilename = sha1_pack_index_name(sha1);\n \tsnprintf(tmpfile, sizeof(tmpfile), \"%s.temp\", filename);\n \tindexfile = fopen(tmpfile, \"a\");\n-\tif (!indexfile)\n+\tif (!indexfile) {\n+\t\tfree(url);\n \t\treturn error(\"Unable to open local file %s for pack index\",\n \t\t\t     tmpfile);\n+\t}\n\n \tslot = get_active_slot();\n \tslot->results = &results;\n+\tcurl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);\n+\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);\n \tcurl_easy_setopt(slot->curl, CURLOPT_FILE, indexfile);\n \tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite);\n \tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n@@ -426,17 +450,20 @@ static int fetch_index(struct walker *walker, struct alt_base *repo, unsigned ch\n \tif (start_active_slot(slot)) {\n \t\trun_active_slot(slot);\n \t\tif (results.curl_result != CURLE_OK) {\n+\t\t\tfree(url);\n \t\t\tfclose(indexfile);\n \t\t\tslot->local = NULL;\n \t\t\treturn error(\"Unable to get pack index %s\\n%s\", url,\n \t\t\t\t     curl_errorstr);\n \t\t}\n \t} else {\n+\t\tfree(url);\n \t\tfclose(indexfile);\n \t\tslot->local = NULL;\n \t\treturn error(\"Unable to start request\");\n \t}\n\n+\tfree(url);\n \tfclose(indexfile);\n \tslot->local = NULL;\n\n--\n1.6.3.1\n"},{"id":"115622","messageId":"20090606164336.09a76a43.rctay89@gmail.com","threadId":"19709","inReplyTo":"cover.1244277116.git.rctay89@gmail.com","subject":"[PATCH 09/23] http*: copy string returned by sha1_to_hex","fromName":"Tay Ray Chuan","fromEmail":"rctay89@gmail.com","sentAt":"2009-06-06T08:43:36Z","receivedAt":"2009-06-06T08:43:36Z","isPatch":true,"sender":{"key":"rctay89@gmail.com","avatar":"https://avatars.githubusercontent.com/u/61553?v=4"},"body":"In the fetch_index implementations in http-push.c and http-walker.c,\nthe string returned by sha1_to_hex is assumed to stay immutable.\n\nThis patch ensures that hex stays immutable by copying the string\nreturned by sha1_to_hex (via xstrdup) and frees it subsequently. It\nalso refactors free()'s and fclose()'s with labels.\n\nSigned-off-by: Tay Ray Chuan <rctay89@gmail.com>\n---\n http-push.c   |   47 ++++++++++++++++++++++++-----------------------\n http-walker.c |   45 +++++++++++++++++++++++----------------------\n 2 files changed, 47 insertions(+), 45 deletions(-)\n\ndiff --git a/http-push.c b/http-push.c\nindex 6ac0d63..c8cb6e4 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -958,7 +958,8 @@ static int add_send_request(struct object *obj, struct remote_lock *lock)\n\n static int fetch_index(unsigned char *sha1)\n {\n-\tchar *hex = sha1_to_hex(sha1);\n+\tint ret = 0;\n+\tchar *hex = xstrdup(sha1_to_hex(sha1));\n \tchar *filename;\n \tchar *url;\n \tchar tmpfile[PATH_MAX];\n@@ -980,18 +981,18 @@ static int fetch_index(unsigned char *sha1)\n \tif (start_active_slot(slot)) {\n \t\trun_active_slot(slot);\n \t\tif (results.curl_result != CURLE_OK) {\n-\t\t\tfree(url);\n-\t\t\treturn error(\"Unable to verify pack %s is available\",\n-\t\t\t\t     hex);\n+\t\t\tret = error(\"Unable to verify pack %s is available\",\n+\t\t\t\t    hex);\n+\t\t\tgoto cleanup_pack;\n \t\t}\n \t} else {\n-\t\tfree(url);\n-\t\treturn error(\"Unable to start request\");\n+\t\tret = error(\"Unable to start request\");\n+\t\tgoto cleanup_pack;\n \t}\n\n \tif (has_pack_index(sha1)) {\n-\t\tfree(url);\n-\t\treturn 0;\n+\t\tret = 0;\n+\t\tgoto cleanup_pack;\n \t}\n\n \tif (push_verbosely)\n@@ -1003,9 +1004,9 @@ static int fetch_index(unsigned char *sha1)\n \tsnprintf(tmpfile, sizeof(tmpfile), \"%s.temp\", filename);\n \tindexfile = fopen(tmpfile, \"a\");\n \tif (!indexfile) {\n-\t\tfree(url);\n-\t\treturn error(\"Unable to open local file %s for pack index\",\n-\t\t\t     tmpfile);\n+\t\tret = error(\"Unable to open local file %s for pack index\",\n+\t\t\t    tmpfile);\n+\t\tgoto cleanup_pack;\n \t}\n\n \tslot = get_active_slot();\n@@ -1036,24 +1037,24 @@ static int fetch_index(unsigned char *sha1)\n \tif (start_active_slot(slot)) {\n \t\trun_active_slot(slot);\n \t\tif (results.curl_result != CURLE_OK) {\n-\t\t\tfree(url);\n-\t\t\tfclose(indexfile);\n-\t\t\tslot->local = NULL;\n-\t\t\treturn error(\"Unable to get pack index %s\\n%s\", url,\n-\t\t\t\t     curl_errorstr);\n+\t\t\tret = error(\"Unable to get pack index %s\\n%s\", url,\n+\t\t\t\t    curl_errorstr);\n+\t\t\tgoto cleanup_index;\n \t\t}\n \t} else {\n-\t\tfree(url);\n-\t\tfclose(indexfile);\n-\t\tslot->local = NULL;\n-\t\treturn error(\"Unable to start request\");\n+\t\tret = error(\"Unable to start request\");\n+\t\tgoto cleanup_index;\n \t}\n\n-\tfree(url);\n+\tret = move_temp_to_file(tmpfile, filename);\n+\n+cleanup_index:\n \tfclose(indexfile);\n \tslot->local = NULL;\n-\n-\treturn move_temp_to_file(tmpfile, filename);\n+cleanup_pack:\n+\tfree(url);\n+\tfree(hex);\n+\treturn ret;\n }\n\n static int setup_index(unsigned char *sha1)\ndiff --git a/http-walker.c b/http-walker.c\nindex bbc3023..d6cc622 100644\n--- a/http-walker.c\n+++ b/http-walker.c\n@@ -371,7 +371,8 @@ static void prefetch(struct walker *walker, unsigned char *sha1)\n\n static int fetch_index(struct walker *walker, struct alt_base *repo, unsigned char *sha1)\n {\n-\tchar *hex = sha1_to_hex(sha1);\n+\tint ret = 0;\n+\tchar *hex = xstrdup(sha1_to_hex(sha1));\n \tchar *filename;\n \tchar *url;\n \tchar tmpfile[PATH_MAX];\n@@ -394,18 +395,18 @@ static int fetch_index(struct walker *walker, struct alt_base *repo, unsigned ch\n \tif (start_active_slot(slot)) {\n \t\trun_active_slot(slot);\n \t\tif (results.curl_result != CURLE_OK) {\n-\t\t\tfree(url);\n-\t\t\treturn error(\"Unable to verify pack %s is available\",\n+\t\t\tret = error(\"Unable to verify pack %s is available\",\n \t\t\t\t     hex);\n+\t\t\tgoto cleanup_pack;\n \t\t}\n \t} else {\n-\t\tfree(url);\n-\t\treturn error(\"Unable to start request\");\n+\t\tret = error(\"Unable to start request\");\n+\t\tgoto cleanup_pack;\n \t}\n\n \tif (has_pack_index(sha1)) {\n-\t\tfree(url);\n-\t\treturn 0;\n+\t\tret = 0;\n+\t\tgoto cleanup_pack;\n \t}\n\n \tif (walker->get_verbosely)\n@@ -417,9 +418,9 @@ static int fetch_index(struct walker *walker, struct alt_base *repo, unsigned ch\n \tsnprintf(tmpfile, sizeof(tmpfile), \"%s.temp\", filename);\n \tindexfile = fopen(tmpfile, \"a\");\n \tif (!indexfile) {\n-\t\tfree(url);\n-\t\treturn error(\"Unable to open local file %s for pack index\",\n-\t\t\t     tmpfile);\n+\t\tret = error(\"Unable to open local file %s for pack index\",\n+\t\t\t    tmpfile);\n+\t\tgoto cleanup_pack;\n \t}\n\n \tslot = get_active_slot();\n@@ -450,24 +451,24 @@ static int fetch_index(struct walker *walker, struct alt_base *repo, unsigned ch\n \tif (start_active_slot(slot)) {\n \t\trun_active_slot(slot);\n \t\tif (results.curl_result != CURLE_OK) {\n-\t\t\tfree(url);\n-\t\t\tfclose(indexfile);\n-\t\t\tslot->local = NULL;\n-\t\t\treturn error(\"Unable to get pack index %s\\n%s\", url,\n-\t\t\t\t     curl_errorstr);\n+\t\t\tret = error(\"Unable to get pack index %s\\n%s\", url,\n+\t\t\t\t    curl_errorstr);\n+\t\t\tgoto cleanup_index;\n \t\t}\n \t} else {\n-\t\tfree(url);\n-\t\tfclose(indexfile);\n-\t\tslot->local = NULL;\n-\t\treturn error(\"Unable to start request\");\n+\t\tret = error(\"Unable to start request\");\n+\t\tgoto cleanup_index;\n \t}\n\n-\tfree(url);\n+\tret = move_temp_to_file(tmpfile, filename);\n+\n+cleanup_index:\n \tfclose(indexfile);\n \tslot->local = NULL;\n-\n-\treturn move_temp_to_file(tmpfile, filename);\n+cleanup_pack:\n+\tfree(url);\n+\tfree(hex);\n+\treturn ret;\n }\n\n static int setup_index(struct walker *walker, struct alt_base *repo, unsigned char *sha1)\n--\n1.6.3.1\n"},{"id":"115623","messageId":"20090606164337.42b74cfa.rctay89@gmail.com","threadId":"19709","inReplyTo":"cover.1244277116.git.rctay89@gmail.com","subject":"[PATCH 10/23] http-push: do not SEGV after fetching a bad pack idx file","fromName":"Tay Ray Chuan","fromEmail":"rctay89@gmail.com","sentAt":"2009-06-06T08:43:37Z","receivedAt":"2009-06-06T08:43:37Z","isPatch":true,"sender":{"key":"rctay89@gmail.com","avatar":"https://avatars.githubusercontent.com/u/61553?v=4"},"body":"In a70c232 (\"http-fetch: do not SEGV after fetching a bad pack idx\nfile\"), changes were made to the setup_index method in http-fetch.c\n(known in its present form as http-walker.c after 30ae764 (\"Modularize\ncommit-walker\")). Since http-push.c has similar similar code for\nprocessing index files, these changes should apply to http-push.c's\nimplementation of setup_index as well.\n\nSigned-off-by: Tay Ray Chuan <rctay89@gmail.com>\n---\n http-push.c |    2 ++\n 1 files changed, 2 insertions(+), 0 deletions(-)\n\ndiff --git a/http-push.c b/http-push.c\nindex c8cb6e4..a6ca2ac 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -1065,6 +1065,8 @@ static int setup_index(unsigned char *sha1)\n \t\treturn -1;\n\n \tnew_pack = parse_pack_index(sha1);\n+\tif (!new_pack)\n+\t\treturn -1; /* parse_pack_index() already issued error message */\n \tnew_pack->next = repo->packs;\n \trepo->packs = new_pack;\n \treturn 0;\n--\n1.6.3.1\n"},{"id":"115624","messageId":"20090606164338.44e20f8c.rctay89@gmail.com","threadId":"19709","inReplyTo":"cover.1244277116.git.rctay89@gmail.com","subject":"[PATCH 11/23] Don't expect verify_pack() callers to set pack_size","fromName":"Tay Ray Chuan","fromEmail":"rctay89@gmail.com","sentAt":"2009-06-06T08:43:38Z","receivedAt":"2009-06-06T08:43:38Z","isPatch":true,"sender":{"key":"rctay89@gmail.com","avatar":"https://avatars.githubusercontent.com/u/61553?v=4"},"body":"From:\tMike Hommey <mh@glandium.org>\nDate:\tSun, 18 Jan 2009 09:04:26 +0100\n\nSince use_pack() will end up populating pack_size if it is not already set,\nwe can just adapt the code in verify_packfile() such that it doesn't require\npack_size to be set beforehand.\n\nThis allows callers not to have to set pack_size themselves, and we can thus\nrevert changes from 1c23d794 (Don't die in git-http-fetch when fetching packs).\n\nSigned-off-by: Mike Hommey <mh@glandium.org>\nSigned-off-by: Tay Ray Chuan <rctay89@gmail.com>\n---\n pack-check.c |    8 +++++---\n 1 files changed, 5 insertions(+), 3 deletions(-)\n\ndiff --git a/pack-check.c b/pack-check.c\nindex 90c33b1..166ca70 100644\n--- a/pack-check.c\n+++ b/pack-check.c\n@@ -49,7 +49,7 @@ static int verify_packfile(struct packed_git *p,\n \tconst unsigned char *index_base = p->index_data;\n \tgit_SHA_CTX ctx;\n \tunsigned char sha1[20], *pack_sig;\n-\toff_t offset = 0, pack_sig_ofs = p->pack_size - 20;\n+\toff_t offset = 0, pack_sig_ofs = 0;\n \tuint32_t nr_objects, i;\n \tint err = 0;\n \tstruct idx_entry *entries;\n@@ -61,14 +61,16 @@ static int verify_packfile(struct packed_git *p,\n \t */\n\n \tgit_SHA1_Init(&ctx);\n-\twhile (offset < pack_sig_ofs) {\n+\tdo {\n \t\tunsigned int remaining;\n \t\tunsigned char *in = use_pack(p, w_curs, offset, &remaining);\n \t\toffset += remaining;\n+\t\tif (!pack_sig_ofs)\n+\t\t\tpack_sig_ofs = p->pack_size - 20;\n \t\tif (offset > pack_sig_ofs)\n \t\t\tremaining -= (unsigned int)(offset - pack_sig_ofs);\n \t\tgit_SHA1_Update(&ctx, in, remaining);\n-\t}\n+\t} while (offset < pack_sig_ofs);\n \tgit_SHA1_Final(sha1, &ctx);\n \tpack_sig = use_pack(p, w_curs, pack_sig_ofs, NULL);\n \tif (hashcmp(sha1, pack_sig))\n--\n1.6.3.1\n"},{"id":"115625","messageId":"20090606164340.a49e63ad.rctay89@gmail.com","threadId":"19709","inReplyTo":"cover.1244277116.git.rctay89@gmail.com","subject":"[PATCH 12/23] transport.c::get_refs_via_curl(): do not leak refs_url","fromName":"Tay Ray Chuan","fromEmail":"rctay89@gmail.com","sentAt":"2009-06-06T08:43:40Z","receivedAt":"2009-06-06T08:43:40Z","isPatch":true,"sender":{"key":"rctay89@gmail.com","avatar":"https://avatars.githubusercontent.com/u/61553?v=4"},"body":"From:\tMike Hommey <mh@glandium.org>\n\nSigned-off-by: Mike Hommey <mh@glandium.org>\nSigned-off-by: Tay Ray Chuan <rctay89@gmail.com>\n---\n\nThis is based on Mike's earlier patch:\n\nSubject: [WIP Patch 02/12] Some cleanup in get_refs_via_curl()\nDate:   Sun, 18 Jan 2009 09:04:27 +0100\n\nI've removed the http_cleanup() invocation, after Johannes reported\nthat it breaks http clone. I've also renamed it, for clarity's sake.\n\n transport.c |    1 +\n 1 files changed, 1 insertions(+), 0 deletions(-)\n\ndiff --git a/transport.c b/transport.c\nindex efecb65..9edd5aa 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -519,6 +519,7 @@ static struct ref *get_refs_via_curl(struct transport *transport, int for_push)\n \t\tfree(ref);\n \t}\n\n+\tfree(refs_url);\n \treturn refs;\n }\n\n--\n1.6.3.1\n"},{"id":"115626","messageId":"20090606164341.f8876a3c.rctay89@gmail.com","threadId":"19709","inReplyTo":"cover.1244277116.git.rctay89@gmail.com","subject":"[PATCH 13/23] http*: move common variables and macros to http.[ch]","fromName":"Tay Ray Chuan","fromEmail":"rctay89@gmail.com","sentAt":"2009-06-06T08:43:41Z","receivedAt":"2009-06-06T08:43:41Z","isPatch":true,"sender":{"key":"rctay89@gmail.com","avatar":"https://avatars.githubusercontent.com/u/61553?v=4"},"body":"Move RANGE_HEADER_SIZE to http.h.\n\nCreate no_pragma_header, the curl header list containing the header\n\"Pragma:\" in http.[ch]. It is allocated in http_init, and freed in\nhttp_cleanup. This replaces the no_pragma_header in http-push.c, and\nthe no_pragma_header member in walker_data in http-walker.c.\n\nCreate http_is_verbose. It is to be used by methods in http.c, and is\nmodified at the entry points of http.c's users, namely http-push.c\n(when parsing options) and http-walker.c (in get_http_walker).\n\nSigned-off-by: Tay Ray Chuan <rctay89@gmail.com>\n---\n http-push.c   |    8 +-------\n http-walker.c |   18 +++++-------------\n http.c        |    9 +++++++++\n http.h        |    5 +++++\n 4 files changed, 20 insertions(+), 20 deletions(-)\n\ndiff --git a/http-push.c b/http-push.c\nindex a6ca2ac..b01db75 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -27,7 +27,6 @@ enum XML_Status {\n #endif\n\n #define PREV_BUF_SIZE 4096\n-#define RANGE_HEADER_SIZE 30\n\n /* DAV methods */\n #define DAV_LOCK \"LOCK\"\n@@ -76,8 +75,6 @@ static int pushing;\n static int aborted;\n static signed char remote_dir_exists[256];\n\n-static struct curl_slist *no_pragma_header;\n-\n static int push_verbosely;\n static int push_all = MATCH_REFS_NONE;\n static int force_all;\n@@ -2251,6 +2248,7 @@ int main(int argc, char **argv)\n \t\t\t}\n \t\t\tif (!strcmp(arg, \"--verbose\")) {\n \t\t\t\tpush_verbosely = 1;\n+\t\t\t\thttp_is_verbose = 1;\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(arg, \"-d\")) {\n@@ -2300,8 +2298,6 @@ int main(int argc, char **argv)\n \tremote->url[remote->url_nr++] = repo->url;\n \thttp_init(remote);\n\n-\tno_pragma_header = curl_slist_append(no_pragma_header, \"Pragma:\");\n-\n \tif (repo->url && repo->url[strlen(repo->url)-1] != '/') {\n \t\trewritten_url = xmalloc(strlen(repo->url)+2);\n \t\tstrcpy(rewritten_url, repo->url);\n@@ -2504,8 +2500,6 @@ int main(int argc, char **argv)\n \t\tunlock_remote(info_ref_lock);\n \tfree(repo);\n\n-\tcurl_slist_free_all(no_pragma_header);\n-\n \thttp_cleanup();\n\n \trequest = request_queue_head;\ndiff --git a/http-walker.c b/http-walker.c\nindex d6cc622..032a7be 100644\n--- a/http-walker.c\n+++ b/http-walker.c\n@@ -5,7 +5,6 @@\n #include \"http.h\"\n\n #define PREV_BUF_SIZE 4096\n-#define RANGE_HEADER_SIZE 30\n\n struct alt_base\n {\n@@ -57,7 +56,6 @@ struct walker_data {\n \tconst char *url;\n \tint got_alternates;\n \tstruct alt_base *alt;\n-\tstruct curl_slist *no_pragma_header;\n };\n\n static struct object_request *object_queue_head;\n@@ -108,7 +106,6 @@ static void start_object_request(struct walker *walker,\n \tchar range[RANGE_HEADER_SIZE];\n \tstruct curl_slist *range_header = NULL;\n \tstruct active_request_slot *slot;\n-\tstruct walker_data *data = walker->data;\n\n \tsnprintf(prevfile, sizeof(prevfile), \"%s.prev\", obj_req->filename);\n \tunlink_or_warn(prevfile);\n@@ -205,7 +202,7 @@ static void start_object_request(struct walker *walker,\n \tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_sha1_file);\n \tcurl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, obj_req->errorstr);\n \tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, data->no_pragma_header);\n+\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);\n\n \t/*\n \t * If we have successfully processed data from a previous fetch\n@@ -354,6 +351,8 @@ static void prefetch(struct walker *walker, unsigned char *sha1)\n \tnewreq->slot = NULL;\n \tnewreq->next = NULL;\n\n+\thttp_is_verbose = walker->get_verbosely;\n+\n \tif (object_queue_head == NULL) {\n \t\tobject_queue_head = newreq;\n \t} else {\n@@ -379,7 +378,6 @@ static int fetch_index(struct walker *walker, struct alt_base *repo, unsigned ch\n \tlong prev_posn = 0;\n \tchar range[RANGE_HEADER_SIZE];\n \tstruct curl_slist *range_header = NULL;\n-\tstruct walker_data *data = walker->data;\n\n \tFILE *indexfile;\n \tstruct active_request_slot *slot;\n@@ -430,7 +428,7 @@ static int fetch_index(struct walker *walker, struct alt_base *repo, unsigned ch\n \tcurl_easy_setopt(slot->curl, CURLOPT_FILE, indexfile);\n \tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite);\n \tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, data->no_pragma_header);\n+\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);\n \tslot->local = indexfile;\n\n \t/*\n@@ -768,7 +766,6 @@ static int fetch_pack(struct walker *walker, struct alt_base *repo, unsigned cha\n \tlong prev_posn = 0;\n \tchar range[RANGE_HEADER_SIZE];\n \tstruct curl_slist *range_header = NULL;\n-\tstruct walker_data *data = walker->data;\n\n \tstruct active_request_slot *slot;\n \tstruct slot_results results;\n@@ -802,7 +799,7 @@ static int fetch_pack(struct walker *walker, struct alt_base *repo, unsigned cha\n \tcurl_easy_setopt(slot->curl, CURLOPT_FILE, packfile);\n \tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite);\n \tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, data->no_pragma_header);\n+\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);\n \tslot->local = packfile;\n\n \t/*\n@@ -948,10 +945,7 @@ static int fetch_ref(struct walker *walker, struct ref *ref)\n\n static void cleanup(struct walker *walker)\n {\n-\tstruct walker_data *data = walker->data;\n \thttp_cleanup();\n-\n-\tcurl_slist_free_all(data->no_pragma_header);\n }\n\n struct walker *get_http_walker(const char *url, struct remote *remote)\n@@ -962,8 +956,6 @@ struct walker *get_http_walker(const char *url, struct remote *remote)\n\n \thttp_init(remote);\n\n-\tdata->no_pragma_header = curl_slist_append(NULL, \"Pragma:\");\n-\n \tdata->alt = xmalloc(sizeof(*data->alt));\n \tdata->alt->base = xmalloc(strlen(url) + 1);\n \tstrcpy(data->alt->base, url);\ndiff --git a/http.c b/http.c\nindex 2e3d649..3ca60bb 100644\n--- a/http.c\n+++ b/http.c\n@@ -2,6 +2,7 @@\n\n int data_received;\n int active_requests;\n+int http_is_verbose;\n\n #ifdef USE_CURL_MULTI\n static int max_requests = -1;\n@@ -29,6 +30,8 @@ static char *user_name, *user_pass;\n\n static struct curl_slist *pragma_header;\n\n+struct curl_slist *no_pragma_header;\n+\n static struct active_request_slot *active_queue_head;\n\n size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb, void *buffer_)\n@@ -276,6 +279,8 @@ void http_init(struct remote *remote)\n \tchar *low_speed_limit;\n \tchar *low_speed_time;\n\n+\thttp_is_verbose = 0;\n+\n \tgit_config(http_options, NULL);\n\n \tcurl_global_init(CURL_GLOBAL_ALL);\n@@ -284,6 +289,7 @@ void http_init(struct remote *remote)\n \t\tcurl_http_proxy = xstrdup(remote->http_proxy);\n\n \tpragma_header = curl_slist_append(pragma_header, \"Pragma: no-cache\");\n+\tno_pragma_header = curl_slist_append(no_pragma_header, \"Pragma:\");\n\n #ifdef USE_CURL_MULTI\n \t{\n@@ -366,6 +372,9 @@ void http_cleanup(void)\n \tcurl_slist_free_all(pragma_header);\n \tpragma_header = NULL;\n\n+\tcurl_slist_free_all(no_pragma_header);\n+\tno_pragma_header = NULL;\n+\n \tif (curl_http_proxy) {\n \t\tfree((void *)curl_http_proxy);\n \t\tcurl_http_proxy = NULL;\ndiff --git a/http.h b/http.h\nindex 26abebe..1ef7dc1 100644\n--- a/http.h\n+++ b/http.h\n@@ -88,11 +88,16 @@ extern void add_fill_function(void *data, int (*fill)(void *));\n extern void step_active_slots(void);\n #endif\n\n+extern struct curl_slist *no_pragma_header;\n+\n+#define RANGE_HEADER_SIZE 30\n+\n extern void http_init(struct remote *remote);\n extern void http_cleanup(void);\n\n extern int data_received;\n extern int active_requests;\n+extern int http_is_verbose;\n\n extern char curl_errorstr[CURL_ERROR_SIZE];\n\n--\n1.6.3.1\n"},{"id":"115627","messageId":"20090606164343.57ed98e4.rctay89@gmail.com","threadId":"19709","inReplyTo":"cover.1244277116.git.rctay89@gmail.com","subject":"[PATCH 14/23] http: create function end_url_with_slash","fromName":"Tay Ray Chuan","fromEmail":"rctay89@gmail.com","sentAt":"2009-06-06T08:43:43Z","receivedAt":"2009-06-06T08:43:43Z","isPatch":true,"sender":{"key":"rctay89@gmail.com","avatar":"https://avatars.githubusercontent.com/u/61553?v=4"},"body":"The logic to append a slash to the url if necessary in quote_ref_url\n(added in 113106e \"http.c: use strbuf API in quote_ref_url\") has been\nmoved to a new function, end_url_with_slash.\n\nThe method takes a strbuf, the URL, and the path to be appended to the\nURL. It first adds the URL to the strbuf. It then appends a slash\nif the URL does not end with a slash.\n\nThe check on ref in quote_ref_url for a slash at the beginning has been\nremoved as a result of using end_url_with_slash. This check is not\nneeded, because slashes will be quoted anyway.\n\nSigned-off-by: Tay Ray Chuan <rctay89@gmail.com>\n---\n http.c |   12 +++++++++---\n 1 files changed, 9 insertions(+), 3 deletions(-)\n\ndiff --git a/http.c b/http.c\nindex 3ca60bb..75fce9e 100644\n--- a/http.c\n+++ b/http.c\n@@ -620,6 +620,7 @@ void finish_all_active_slots(void)\n \t\t}\n }\n\n+/* Helpers for modifying and creating URLs */\n static inline int needs_quote(int ch)\n {\n \tif (((ch >= 'A') && (ch <= 'Z'))\n@@ -640,15 +641,20 @@ static inline int hex(int v)\n \t\treturn 'A' + v - 10;\n }\n\n+static void end_url_with_slash(struct strbuf *buf, const char *url)\n+{\n+\tstrbuf_addstr(buf, url);\n+\tif (buf->len && buf->buf[buf->len - 1] != '/')\n+\t\tstrbuf_addstr(buf, \"/\");\n+}\n+\n static char *quote_ref_url(const char *base, const char *ref)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n \tconst char *cp;\n \tint ch;\n\n-\tstrbuf_addstr(&buf, base);\n-\tif (buf.len && buf.buf[buf.len - 1] != '/' && *ref != '/')\n-\t\tstrbuf_addstr(&buf, \"/\");\n+\tend_url_with_slash(&buf, base);\n\n \tfor (cp = ref; (ch = *cp) != 0; cp++)\n \t\tif (needs_quote(ch))\n--\n1.6.3.1\n"},{"id":"115628","messageId":"20090606164353.967cce80.rctay89@gmail.com","threadId":"19709","inReplyTo":"cover.1244277116.git.rctay89@gmail.com","subject":"[PATCH 15/23] http.c: new functions for the http API","fromName":"Tay Ray Chuan","fromEmail":"rctay89@gmail.com","sentAt":"2009-06-06T08:43:53Z","receivedAt":"2009-06-06T08:43:53Z","isPatch":true,"sender":{"key":"rctay89@gmail.com","avatar":"https://avatars.githubusercontent.com/u/61553?v=4"},"body":"From:\tMike Hommey <mh@glandium.org>\n\nThe new functions added are:\n - http_request() (internal function)\n - http_get_strbuf()\n - http_get_file()\n - http_error()\n\nhttp_get_strbuf and http_get_file allow respectively to retrieve contents of\nan URL to a strbuf or an opened file handle.\n\nhttp_error prints out an error message containing the URL and the curl error\n(in curl_errorstr).\n\nSigned-off-by: Mike Hommey <mh@glandium.org>\nSigned-off-by: Tay Ray Chuan <rctay89@gmail.com>\n---\n\nThis patch is based on Mike's earlier patch:\n\nSubject: [WIP Patch 03/12] Two new functions for the http API\nDate:\tSun, 18 Jan 2009 09:04:28 +0100\n\nI've added a new return status code for http_request,\nHTTP_START_FAILED, since some callers need to know when\nstart_active_slot() fails.\n\nhttp_request() will emit an error message when start_active_slot()\nfails; for other cases, no error message is emitted.\n\nI've added http_error(). (see description above)\n\nI've added the list of new functions to the commit message body, as\nsuggested by Jakub.\n\n http.c |  104 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n http.h |   30 ++++++++++++++++++\n 2 files changed, 134 insertions(+), 0 deletions(-)\n\ndiff --git a/http.c b/http.c\nindex 75fce9e..df22180 100644\n--- a/http.c\n+++ b/http.c\n@@ -665,6 +665,110 @@ static char *quote_ref_url(const char *base, const char *ref)\n \treturn strbuf_detach(&buf, NULL);\n }\n\n+/* http_request() targets */\n+#define HTTP_REQUEST_STRBUF\t0\n+#define HTTP_REQUEST_FILE\t1\n+\n+static int http_request(const char *url, void *result, int target, int options)\n+{\n+\tstruct active_request_slot *slot;\n+\tstruct slot_results results;\n+\tstruct curl_slist *headers = NULL;\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tint ret;\n+\n+\tslot = get_active_slot();\n+\tslot->results = &results;\n+\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);\n+\n+\tif (result == NULL) {\n+\t\tcurl_easy_setopt(slot->curl, CURLOPT_NOBODY, 1);\n+\t} else {\n+\t\tcurl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);\n+\t\tcurl_easy_setopt(slot->curl, CURLOPT_FILE, result);\n+\n+\t\tif (target == HTTP_REQUEST_FILE) {\n+\t\t\tlong posn = ftell(result);\n+\t\t\tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,\n+\t\t\t\t\t fwrite);\n+\t\t\tif (posn > 0) {\n+\t\t\t\tstrbuf_addf(&buf, \"Range: bytes=%ld-\", posn);\n+\t\t\t\theaders = curl_slist_append(headers, buf.buf);\n+\t\t\t\tstrbuf_reset(&buf);\n+\t\t\t}\n+\t\t\tslot->local = result;\n+\t\t} else\n+\t\t\tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,\n+\t\t\t\t\t fwrite_buffer);\n+\t}\n+\n+\tstrbuf_addstr(&buf, \"Pragma:\");\n+\tif (options & HTTP_NO_CACHE)\n+\t\tstrbuf_addstr(&buf, \" no-cache\");\n+\n+\theaders = curl_slist_append(headers, buf.buf);\n+\n+\tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n+\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, headers);\n+\n+\tif (start_active_slot(slot)) {\n+\t\trun_active_slot(slot);\n+\t\tif (results.curl_result == CURLE_OK)\n+\t\t\tret = HTTP_OK;\n+\t\telse if (missing_target(&results))\n+\t\t\tret = HTTP_MISSING_TARGET;\n+\t\telse\n+\t\t\tret = HTTP_ERROR;\n+\t} else {\n+\t\terror(\"Unable to start HTTP request for %s\", url);\n+\t\tret = HTTP_START_FAILED;\n+\t}\n+\n+\tslot->local = NULL;\n+\tcurl_slist_free_all(headers);\n+\tstrbuf_release(&buf);\n+\n+\treturn ret;\n+}\n+\n+int http_get_strbuf(const char *url, struct strbuf *result, int options)\n+{\n+\treturn http_request(url, result, HTTP_REQUEST_STRBUF, options);\n+}\n+\n+int http_get_file(const char *url, const char *filename, int options)\n+{\n+\tint ret;\n+\tstruct strbuf tmpfile = STRBUF_INIT;\n+\tFILE *result;\n+\n+\tstrbuf_addf(&tmpfile, \"%s.temp\", filename);\n+\tresult = fopen(tmpfile.buf, \"a\");\n+\tif (! result) {\n+\t\terror(\"Unable to open local file %s\", tmpfile.buf);\n+\t\tret = HTTP_ERROR;\n+\t\tgoto cleanup;\n+\t}\n+\n+\tret = http_request(url, result, HTTP_REQUEST_FILE, options);\n+\tfclose(result);\n+\n+\tif ((ret == HTTP_OK) && move_temp_to_file(tmpfile.buf, filename))\n+\t\tret = HTTP_ERROR;\n+cleanup:\n+\tstrbuf_release(&tmpfile);\n+\treturn ret;\n+}\n+\n+int http_error(const char *url, int ret)\n+{\n+\t/* http_request has already handled HTTP_START_FAILED. */\n+\tif (ret != HTTP_START_FAILED)\n+\t\terror(\"%s while accessing %s\\n\", curl_errorstr, url);\n+\n+\treturn ret;\n+}\n+\n int http_fetch_ref(const char *base, struct ref *ref)\n {\n \tchar *url;\ndiff --git a/http.h b/http.h\nindex 1ef7dc1..3d878d5 100644\n--- a/http.h\n+++ b/http.h\n@@ -114,6 +114,36 @@ static inline int missing__target(int code, int result)\n\n #define missing_target(a) missing__target((a)->http_code, (a)->curl_result)\n\n+/* Options for http_request_*() */\n+#define HTTP_NO_CACHE\t\t1\n+\n+/* Return values for http_request_*() */\n+#define HTTP_OK\t\t\t0\n+#define HTTP_MISSING_TARGET\t1\n+#define HTTP_ERROR\t\t2\n+#define HTTP_START_FAILED\t3\n+\n+/*\n+ * Requests an url and stores the result in a strbuf.\n+ *\n+ * If the result pointer is NULL, a HTTP HEAD request is made instead of GET.\n+ */\n+int http_get_strbuf(const char *url, struct strbuf *result, int options);\n+\n+/*\n+ * Downloads an url and stores the result in the given file.\n+ *\n+ * If a previous interrupted download is detected (i.e. a previous temporary\n+ * file is still around) the download is resumed.\n+ */\n+int http_get_file(const char *url, const char *filename, int options);\n+\n+/*\n+ * Prints an error message using error() containing url and curl_errorstr,\n+ * and returns ret.\n+ */\n+int http_error(const char *url, int ret);\n+\n extern int http_fetch_ref(const char *base, struct ref *ref);\n\n #endif /* HTTP_H */\n--\n1.6.3.1\n"},{"id":"115630","messageId":"20090606164354.82d6073b.rctay89@gmail.com","threadId":"19709","inReplyTo":"cover.1244277116.git.rctay89@gmail.com","subject":"[PATCH 16/23] transport.c::get_refs_via_curl(): use the new http API","fromName":"Tay Ray Chuan","fromEmail":"rctay89@gmail.com","sentAt":"2009-06-06T08:43:54Z","receivedAt":"2009-06-06T08:43:54Z","isPatch":true,"sender":{"key":"rctay89@gmail.com","avatar":"https://avatars.githubusercontent.com/u/61553?v=4"},"body":"From:\tMike Hommey <mh@glandium.org>\n\nSigned-off-by: Mike Hommey <mh@glandium.org>\nSigned-off-by: Tay Ray Chuan <rctay89@gmail.com>\n---\n\nThis is based on Mike's earlier patch:\n\nSubject: [WIP Patch 05/12] Use the new http API in get_refs_via_curl()\nDate:\tSun, 18 Jan 2009 09:04:30 +0100\n\nI added back the die()'s like in the original, which Mike had removed.\n\n transport.c |   35 +++++++++++++----------------------\n 1 files changed, 13 insertions(+), 22 deletions(-)\n\ndiff --git a/transport.c b/transport.c\nindex 9edd5aa..af75f7b 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -439,9 +439,7 @@ static struct ref *get_refs_via_curl(struct transport *transport, int for_push)\n \tchar *ref_name;\n \tchar *refs_url;\n \tint i = 0;\n-\n-\tstruct active_request_slot *slot;\n-\tstruct slot_results results;\n+\tint http_ret;\n\n \tstruct ref *refs = NULL;\n \tstruct ref *ref = NULL;\n@@ -461,25 +459,16 @@ static struct ref *get_refs_via_curl(struct transport *transport, int for_push)\n \trefs_url = xmalloc(strlen(transport->url) + 11);\n \tsprintf(refs_url, \"%s/info/refs\", transport->url);\n\n-\tslot = get_active_slot();\n-\tslot->results = &results;\n-\tcurl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_URL, refs_url);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);\n-\n-\tif (start_active_slot(slot)) {\n-\t\trun_active_slot(slot);\n-\t\tif (results.curl_result != CURLE_OK) {\n-\t\t\tstrbuf_release(&buffer);\n-\t\t\tif (missing_target(&results))\n-\t\t\t\tdie(\"%s not found: did you run git update-server-info on the server?\", refs_url);\n-\t\t\telse\n-\t\t\t\tdie(\"%s download error - %s\", refs_url, curl_errorstr);\n-\t\t}\n-\t} else {\n-\t\tstrbuf_release(&buffer);\n-\t\tdie(\"Unable to start HTTP request\");\n+\thttp_ret = http_get_strbuf(refs_url, &buffer, HTTP_NO_CACHE);\n+\tswitch (http_ret) {\n+\tcase HTTP_OK:\n+\t\tbreak;\n+\tcase HTTP_MISSING_TARGET:\n+\t\tdie(\"%s not found: did you run git update-server-info on the\"\n+\t\t    \" server?\", refs_url);\n+\tdefault:\n+\t\thttp_error(refs_url, http_ret);\n+\t\tdie(\"HTTP request failed\");\n \t}\n\n \tdata = buffer.buf;\n@@ -519,6 +508,8 @@ static struct ref *get_refs_via_curl(struct transport *transport, int for_push)\n \t\tfree(ref);\n \t}\n\n+cleanup:\n+\tstrbuf_release(&buffer);\n \tfree(refs_url);\n \treturn refs;\n }\n--\n1.6.3.1\n"},{"id":"115629","messageId":"20090606164355.b2f491f1.rctay89@gmail.com","threadId":"19709","inReplyTo":"cover.1244277116.git.rctay89@gmail.com","subject":"[PATCH 17/23] http.c::http_fetch_ref(): use the new http API","fromName":"Tay Ray Chuan","fromEmail":"rctay89@gmail.com","sentAt":"2009-06-06T08:43:55Z","receivedAt":"2009-06-06T08:43:55Z","isPatch":true,"sender":{"key":"rctay89@gmail.com","avatar":"https://avatars.githubusercontent.com/u/61553?v=4"},"body":"From:\tMike Hommey <mh@glandium.org>\n\nThe error message (\"Unable to start request\") has been removed, since\nthe http API already prints it.\n\nSigned-off-by: Mike Hommey <mh@glandium.org>\nSigned-off-by: Tay Ray Chuan <rctay89@gmail.com>\n---\n\nThis is based on Mike's earlier patch:\n\nSubject: [WIP Patch 04/12] Use the new http API in http_fetch_ref()\nDate:\tSun, 18 Jan 2009 09:04:29 +0100\n\n http.c |   33 ++++++++-------------------------\n 1 files changed, 8 insertions(+), 25 deletions(-)\n\ndiff --git a/http.c b/http.c\nindex df22180..2a49372 100644\n--- a/http.c\n+++ b/http.c\n@@ -773,34 +773,17 @@ int http_fetch_ref(const char *base, struct ref *ref)\n {\n \tchar *url;\n \tstruct strbuf buffer = STRBUF_INIT;\n-\tstruct active_request_slot *slot;\n-\tstruct slot_results results;\n-\tint ret;\n+\tint ret = -1;\n\n \turl = quote_ref_url(base, ref->name);\n-\tslot = get_active_slot();\n-\tslot->results = &results;\n-\tcurl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n-\tif (start_active_slot(slot)) {\n-\t\trun_active_slot(slot);\n-\t\tif (results.curl_result == CURLE_OK) {\n-\t\t\tstrbuf_rtrim(&buffer);\n-\t\t\tif (buffer.len == 40)\n-\t\t\t\tret = get_sha1_hex(buffer.buf, ref->old_sha1);\n-\t\t\telse if (!prefixcmp(buffer.buf, \"ref: \")) {\n-\t\t\t\tref->symref = xstrdup(buffer.buf + 5);\n-\t\t\t\tret = 0;\n-\t\t\t} else\n-\t\t\t\tret = 1;\n-\t\t} else {\n-\t\t\tret = error(\"Couldn't get %s for %s\\n%s\",\n-\t\t\t\t    url, ref->name, curl_errorstr);\n+\tif (http_get_strbuf(url, &buffer, HTTP_NO_CACHE) == HTTP_OK) {\n+\t\tstrbuf_rtrim(&buffer);\n+\t\tif (buffer.len == 40)\n+\t\t\tret = get_sha1_hex(buffer.buf, ref->old_sha1);\n+\t\telse if (!prefixcmp(buffer.buf, \"ref: \")) {\n+\t\t\tref->symref = xstrdup(buffer.buf + 5);\n+\t\t\tret = 0;\n \t\t}\n-\t} else {\n-\t\tret = error(\"Unable to start request\");\n \t}\n\n \tstrbuf_release(&buffer);\n--\n1.6.3.1\n"},{"id":"115632","messageId":"20090606164357.1212eb1d.rctay89@gmail.com","threadId":"19709","inReplyTo":"cover.1244277116.git.rctay89@gmail.com","subject":"[PATCH 18/23] http-push.c::remote_exists(): use the new http API","fromName":"Tay Ray Chuan","fromEmail":"rctay89@gmail.com","sentAt":"2009-06-06T08:43:57Z","receivedAt":"2009-06-06T08:43:57Z","isPatch":true,"sender":{"key":"rctay89@gmail.com","avatar":"https://avatars.githubusercontent.com/u/61553?v=4"},"body":"From:\tMike Hommey <mh@glandium.org>\n\nSigned-off-by: Mike Hommey <mh@glandium.org>\nSigned-off-by: Tay Ray Chuan <rctay89@gmail.com>\n---\n\nThis is based on Mike's earlier patch:\n\nSubject: [WIP Patch 08/12] Use the new http API in update_remote_info_refs()\nDate:\tSun, 18 Jan 2009 09:04:33 +0100\n\n http-push.c |   31 ++++++++++++-------------------\n 1 files changed, 12 insertions(+), 19 deletions(-)\n\ndiff --git a/http-push.c b/http-push.c\nindex b01db75..455e0aa 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -2005,29 +2005,22 @@ static void update_remote_info_refs(struct remote_lock *lock)\n static int remote_exists(const char *path)\n {\n \tchar *url = xmalloc(strlen(repo->url) + strlen(path) + 1);\n-\tstruct active_request_slot *slot;\n-\tstruct slot_results results;\n-\tint ret = -1;\n+\tint ret;\n\n \tsprintf(url, \"%s%s\", repo->url, path);\n\n-\tslot = get_active_slot();\n-\tslot->results = &results;\n-\tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_NOBODY, 1);\n-\n-\tif (start_active_slot(slot)) {\n-\t\trun_active_slot(slot);\n-\t\tif (results.http_code == 404)\n-\t\t\tret = 0;\n-\t\telse if (results.curl_result == CURLE_OK)\n-\t\t\tret = 1;\n-\t\telse\n-\t\t\tfprintf(stderr, \"HEAD HTTP error %ld\\n\", results.http_code);\n-\t} else {\n-\t\tfprintf(stderr, \"Unable to start HEAD request\\n\");\n+\tswitch (http_get_strbuf(url, NULL, 0)) {\n+\tcase HTTP_OK:\n+\t\tret = 1;\n+\t\tbreak;\n+\tcase HTTP_MISSING_TARGET:\n+\t\tret = 0;\n+\t\tbreak;\n+\tcase HTTP_ERROR:\n+\t\thttp_error(url, HTTP_ERROR);\n+\tdefault:\n+\t\tret = -1;\n \t}\n-\n \tfree(url);\n \treturn ret;\n }\n--\n1.6.3.1\n"},{"id":"115633","messageId":"20090606164358.29164835.rctay89@gmail.com","threadId":"19709","inReplyTo":"cover.1244277116.git.rctay89@gmail.com","subject":"[PATCH 19/23] http-push.c::fetch_symref(): use the new http API","fromName":"Tay Ray Chuan","fromEmail":"rctay89@gmail.com","sentAt":"2009-06-06T08:43:58Z","receivedAt":"2009-06-06T08:43:58Z","isPatch":true,"sender":{"key":"rctay89@gmail.com","avatar":"https://avatars.githubusercontent.com/u/61553?v=4"},"body":"From:\tMike Hommey <mh@glandium.org>\n\nSigned-off-by: Mike Hommey <mh@glandium.org>\nSigned-off-by: Tay Ray Chuan <rctay89@gmail.com>\n---\n\nThis is based on Mike's earlier patch:\n\nSubject: [WIP Patch 09/12] Use the new http API in fetch_symref()\nDate:\tSun, 18 Jan 2009 09:04:34 +0100\n\n http-push.c |   20 +++-----------------\n 1 files changed, 3 insertions(+), 17 deletions(-)\n\ndiff --git a/http-push.c b/http-push.c\nindex 455e0aa..1714e4e 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -2029,27 +2029,13 @@ static void fetch_symref(const char *path, char **symref, unsigned char *sha1)\n {\n \tchar *url;\n \tstruct strbuf buffer = STRBUF_INIT;\n-\tstruct active_request_slot *slot;\n-\tstruct slot_results results;\n\n \turl = xmalloc(strlen(repo->url) + strlen(path) + 1);\n \tsprintf(url, \"%s%s\", repo->url, path);\n\n-\tslot = get_active_slot();\n-\tslot->results = &results;\n-\tcurl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n-\tif (start_active_slot(slot)) {\n-\t\trun_active_slot(slot);\n-\t\tif (results.curl_result != CURLE_OK) {\n-\t\t\tdie(\"Couldn't get %s for remote symref\\n%s\",\n-\t\t\t    url, curl_errorstr);\n-\t\t}\n-\t} else {\n-\t\tdie(\"Unable to start remote symref request\");\n-\t}\n+\tif (http_get_strbuf(url, &buffer, 0) != HTTP_OK)\n+\t\tdie(\"Couldn't get %s for remote symref\\n%s\", url,\n+\t\t    curl_errorstr);\n \tfree(url);\n\n \tfree(*symref);\n--\n1.6.3.1\n"},{"id":"115634","messageId":"20090606164359.818a2d9f.rctay89@gmail.com","threadId":"19709","inReplyTo":"cover.1244277116.git.rctay89@gmail.com","subject":"[PATCH 20/23] http*: add http_get_info_packs","fromName":"Tay Ray Chuan","fromEmail":"rctay89@gmail.com","sentAt":"2009-06-06T08:43:59Z","receivedAt":"2009-06-06T08:43:59Z","isPatch":true,"sender":{"key":"rctay89@gmail.com","avatar":"https://avatars.githubusercontent.com/u/61553?v=4"},"body":"http-push.c and http-walker.c no longer have to use fetch_index or\nsetup_index; they simply need to use http_get_info_packs, a new http\nmethod, in their fetch_indices implementations.\n\nMove fetch_index() and rename to fetch_pack_index() in http.c; this\nmethod is not meant to be used outside of http.c. It invokes\nend_url_with_slash with base_url; apart from that change, the code is\nidentical.\n\nMove setup_index() and rename to fetch_and_setup_pack_index() in\nhttp.c; this method is not meant to be used outside of http.c.\n\nDo not immediately set ret to 0 in http-walker.c::fetch_indices();\ninstead do it in the HTTP_MISSING_TARGET case, to make it clear that\nthe HTTP_OK and HTTP_MISSING_TARGET cases both return 0.\n\nSigned-off-by: Tay Ray Chuan <rctay89@gmail.com>\n---\n\nClemens, I've corrected the return values for\nhttp-push.c::fetch_indices(). I won't touch repo->has_info_packs yet,\nthough, as I've already mentioned.\n\n http-push.c   |  179 +++----------------------------------------------------\n http-walker.c |  184 +++------------------------------------------------------\n http.c        |  164 ++++++++++++++++++++++++++++++++++++++++++++++++++\n http.h        |    4 +\n 4 files changed, 186 insertions(+), 345 deletions(-)\n\ndiff --git a/http-push.c b/http-push.c\nindex 1714e4e..d6f3b8e 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -953,184 +953,23 @@ static int add_send_request(struct object *obj, struct remote_lock *lock)\n \treturn 1;\n }\n\n-static int fetch_index(unsigned char *sha1)\n-{\n-\tint ret = 0;\n-\tchar *hex = xstrdup(sha1_to_hex(sha1));\n-\tchar *filename;\n-\tchar *url;\n-\tchar tmpfile[PATH_MAX];\n-\tlong prev_posn = 0;\n-\tchar range[RANGE_HEADER_SIZE];\n-\tstruct curl_slist *range_header = NULL;\n-\n-\tFILE *indexfile;\n-\tstruct active_request_slot *slot;\n-\tstruct slot_results results;\n-\n-\t/* Don't use the index if the pack isn't there */\n-\turl = xmalloc(strlen(repo->url) + 64);\n-\tsprintf(url, \"%sobjects/pack/pack-%s.pack\", repo->url, hex);\n-\tslot = get_active_slot();\n-\tslot->results = &results;\n-\tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_NOBODY, 1);\n-\tif (start_active_slot(slot)) {\n-\t\trun_active_slot(slot);\n-\t\tif (results.curl_result != CURLE_OK) {\n-\t\t\tret = error(\"Unable to verify pack %s is available\",\n-\t\t\t\t    hex);\n-\t\t\tgoto cleanup_pack;\n-\t\t}\n-\t} else {\n-\t\tret = error(\"Unable to start request\");\n-\t\tgoto cleanup_pack;\n-\t}\n-\n-\tif (has_pack_index(sha1)) {\n-\t\tret = 0;\n-\t\tgoto cleanup_pack;\n-\t}\n-\n-\tif (push_verbosely)\n-\t\tfprintf(stderr, \"Getting index for pack %s\\n\", hex);\n-\n-\tsprintf(url, \"%sobjects/pack/pack-%s.idx\", repo->url, hex);\n-\n-\tfilename = sha1_pack_index_name(sha1);\n-\tsnprintf(tmpfile, sizeof(tmpfile), \"%s.temp\", filename);\n-\tindexfile = fopen(tmpfile, \"a\");\n-\tif (!indexfile) {\n-\t\tret = error(\"Unable to open local file %s for pack index\",\n-\t\t\t    tmpfile);\n-\t\tgoto cleanup_pack;\n-\t}\n-\n-\tslot = get_active_slot();\n-\tslot->results = &results;\n-\tcurl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_FILE, indexfile);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);\n-\tslot->local = indexfile;\n-\n-\t/*\n-\t * If there is data present from a previous transfer attempt,\n-\t * resume where it left off\n-\t */\n-\tprev_posn = ftell(indexfile);\n-\tif (prev_posn>0) {\n-\t\tif (push_verbosely)\n-\t\t\tfprintf(stderr,\n-\t\t\t\t\"Resuming fetch of index for pack %s at byte %ld\\n\",\n-\t\t\t\thex, prev_posn);\n-\t\tsprintf(range, \"Range: bytes=%ld-\", prev_posn);\n-\t\trange_header = curl_slist_append(range_header, range);\n-\t\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, range_header);\n-\t}\n-\n-\tif (start_active_slot(slot)) {\n-\t\trun_active_slot(slot);\n-\t\tif (results.curl_result != CURLE_OK) {\n-\t\t\tret = error(\"Unable to get pack index %s\\n%s\", url,\n-\t\t\t\t    curl_errorstr);\n-\t\t\tgoto cleanup_index;\n-\t\t}\n-\t} else {\n-\t\tret = error(\"Unable to start request\");\n-\t\tgoto cleanup_index;\n-\t}\n-\n-\tret = move_temp_to_file(tmpfile, filename);\n-\n-cleanup_index:\n-\tfclose(indexfile);\n-\tslot->local = NULL;\n-cleanup_pack:\n-\tfree(url);\n-\tfree(hex);\n-\treturn ret;\n-}\n-\n-static int setup_index(unsigned char *sha1)\n-{\n-\tstruct packed_git *new_pack;\n-\n-\tif (fetch_index(sha1))\n-\t\treturn -1;\n-\n-\tnew_pack = parse_pack_index(sha1);\n-\tif (!new_pack)\n-\t\treturn -1; /* parse_pack_index() already issued error message */\n-\tnew_pack->next = repo->packs;\n-\trepo->packs = new_pack;\n-\treturn 0;\n-}\n-\n static int fetch_indices(void)\n {\n-\tunsigned char sha1[20];\n-\tchar *url;\n-\tstruct strbuf buffer = STRBUF_INIT;\n-\tchar *data;\n-\tint i = 0;\n-\n-\tstruct active_request_slot *slot;\n-\tstruct slot_results results;\n+\tint ret;\n\n \tif (push_verbosely)\n \t\tfprintf(stderr, \"Getting pack list\\n\");\n\n-\turl = xmalloc(strlen(repo->url) + 20);\n-\tsprintf(url, \"%sobjects/info/packs\", repo->url);\n-\n-\tslot = get_active_slot();\n-\tslot->results = &results;\n-\tcurl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);\n-\tif (start_active_slot(slot)) {\n-\t\trun_active_slot(slot);\n-\t\tif (results.curl_result != CURLE_OK) {\n-\t\t\tstrbuf_release(&buffer);\n-\t\t\tfree(url);\n-\t\t\tif (results.http_code == 404)\n-\t\t\t\treturn 0;\n-\t\t\telse\n-\t\t\t\treturn error(\"%s\", curl_errorstr);\n-\t\t}\n-\t} else {\n-\t\tstrbuf_release(&buffer);\n-\t\tfree(url);\n-\t\treturn error(\"Unable to start request\");\n-\t}\n-\tfree(url);\n-\n-\tdata = buffer.buf;\n-\twhile (i < buffer.len) {\n-\t\tswitch (data[i]) {\n-\t\tcase 'P':\n-\t\t\ti++;\n-\t\t\tif (i + 52 < buffer.len &&\n-\t\t\t    !prefixcmp(data + i, \" pack-\") &&\n-\t\t\t    !prefixcmp(data + i + 46, \".pack\\n\")) {\n-\t\t\t\tget_sha1_hex(data + i + 6, sha1);\n-\t\t\t\tsetup_index(sha1);\n-\t\t\t\ti += 51;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\tdefault:\n-\t\t\twhile (data[i] != '\\n')\n-\t\t\t\ti++;\n-\t\t}\n-\t\ti++;\n+\tswitch (http_get_info_packs(repo->url, &repo->packs)) {\n+\tcase HTTP_OK:\n+\tcase HTTP_MISSING_TARGET:\n+\t\tret = 0;\n+\t\tbreak;\n+\tdefault:\n+\t\tret = -1;\n \t}\n\n-\tstrbuf_release(&buffer);\n-\treturn 0;\n+\treturn ret;\n }\n\n static void one_remote_object(const char *hex)\ndiff --git a/http-walker.c b/http-walker.c\nindex 032a7be..ac343fd 100644\n--- a/http-walker.c\n+++ b/http-walker.c\n@@ -368,124 +368,6 @@ static void prefetch(struct walker *walker, unsigned char *sha1)\n #endif\n }\n\n-static int fetch_index(struct walker *walker, struct alt_base *repo, unsigned char *sha1)\n-{\n-\tint ret = 0;\n-\tchar *hex = xstrdup(sha1_to_hex(sha1));\n-\tchar *filename;\n-\tchar *url;\n-\tchar tmpfile[PATH_MAX];\n-\tlong prev_posn = 0;\n-\tchar range[RANGE_HEADER_SIZE];\n-\tstruct curl_slist *range_header = NULL;\n-\n-\tFILE *indexfile;\n-\tstruct active_request_slot *slot;\n-\tstruct slot_results results;\n-\n-\t/* Don't use the index if the pack isn't there */\n-\turl = xmalloc(strlen(repo->base) + 64);\n-\tsprintf(url, \"%s/objects/pack/pack-%s.pack\", repo->base, hex);\n-\tslot = get_active_slot();\n-\tslot->results = &results;\n-\tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_NOBODY, 1);\n-\tif (start_active_slot(slot)) {\n-\t\trun_active_slot(slot);\n-\t\tif (results.curl_result != CURLE_OK) {\n-\t\t\tret = error(\"Unable to verify pack %s is available\",\n-\t\t\t\t     hex);\n-\t\t\tgoto cleanup_pack;\n-\t\t}\n-\t} else {\n-\t\tret = error(\"Unable to start request\");\n-\t\tgoto cleanup_pack;\n-\t}\n-\n-\tif (has_pack_index(sha1)) {\n-\t\tret = 0;\n-\t\tgoto cleanup_pack;\n-\t}\n-\n-\tif (walker->get_verbosely)\n-\t\tfprintf(stderr, \"Getting index for pack %s\\n\", hex);\n-\n-\tsprintf(url, \"%s/objects/pack/pack-%s.idx\", repo->base, hex);\n-\n-\tfilename = sha1_pack_index_name(sha1);\n-\tsnprintf(tmpfile, sizeof(tmpfile), \"%s.temp\", filename);\n-\tindexfile = fopen(tmpfile, \"a\");\n-\tif (!indexfile) {\n-\t\tret = error(\"Unable to open local file %s for pack index\",\n-\t\t\t    tmpfile);\n-\t\tgoto cleanup_pack;\n-\t}\n-\n-\tslot = get_active_slot();\n-\tslot->results = &results;\n-\tcurl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_FILE, indexfile);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);\n-\tslot->local = indexfile;\n-\n-\t/*\n-\t * If there is data present from a previous transfer attempt,\n-\t * resume where it left off\n-\t */\n-\tprev_posn = ftell(indexfile);\n-\tif (prev_posn>0) {\n-\t\tif (walker->get_verbosely)\n-\t\t\tfprintf(stderr,\n-\t\t\t\t\"Resuming fetch of index for pack %s at byte %ld\\n\",\n-\t\t\t\thex, prev_posn);\n-\t\tsprintf(range, \"Range: bytes=%ld-\", prev_posn);\n-\t\trange_header = curl_slist_append(range_header, range);\n-\t\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, range_header);\n-\t}\n-\n-\tif (start_active_slot(slot)) {\n-\t\trun_active_slot(slot);\n-\t\tif (results.curl_result != CURLE_OK) {\n-\t\t\tret = error(\"Unable to get pack index %s\\n%s\", url,\n-\t\t\t\t    curl_errorstr);\n-\t\t\tgoto cleanup_index;\n-\t\t}\n-\t} else {\n-\t\tret = error(\"Unable to start request\");\n-\t\tgoto cleanup_index;\n-\t}\n-\n-\tret = move_temp_to_file(tmpfile, filename);\n-\n-cleanup_index:\n-\tfclose(indexfile);\n-\tslot->local = NULL;\n-cleanup_pack:\n-\tfree(url);\n-\tfree(hex);\n-\treturn ret;\n-}\n-\n-static int setup_index(struct walker *walker, struct alt_base *repo, unsigned char *sha1)\n-{\n-\tstruct packed_git *new_pack;\n-\tif (has_pack_file(sha1))\n-\t\treturn 0; /* don't list this as something we can get */\n-\n-\tif (fetch_index(walker, repo, sha1))\n-\t\treturn -1;\n-\n-\tnew_pack = parse_pack_index(sha1);\n-\tif (!new_pack)\n-\t\treturn -1; /* parse_pack_index() already issued error message */\n-\tnew_pack->next = repo->packs;\n-\trepo->packs = new_pack;\n-\treturn 0;\n-}\n-\n static void process_alternates_response(void *callback_data)\n {\n \tstruct alternates_request *alt_req =\n@@ -684,15 +566,7 @@ static void fetch_alternates(struct walker *walker, const char *base)\n\n static int fetch_indices(struct walker *walker, struct alt_base *repo)\n {\n-\tunsigned char sha1[20];\n-\tchar *url;\n-\tstruct strbuf buffer = STRBUF_INIT;\n-\tchar *data;\n-\tint i = 0;\n-\tint ret = 0;\n-\n-\tstruct active_request_slot *slot;\n-\tstruct slot_results results;\n+\tint ret;\n\n \tif (repo->got_indices)\n \t\treturn 0;\n@@ -700,57 +574,17 @@ static int fetch_indices(struct walker *walker, struct alt_base *repo)\n \tif (walker->get_verbosely)\n \t\tfprintf(stderr, \"Getting pack list for %s\\n\", repo->base);\n\n-\turl = xmalloc(strlen(repo->base) + 21);\n-\tsprintf(url, \"%s/objects/info/packs\", repo->base);\n-\n-\tslot = get_active_slot();\n-\tslot->results = &results;\n-\tcurl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);\n-\tif (start_active_slot(slot)) {\n-\t\trun_active_slot(slot);\n-\t\tif (results.curl_result != CURLE_OK) {\n-\t\t\tif (missing_target(&results)) {\n-\t\t\t\trepo->got_indices = 1;\n-\t\t\t\tgoto cleanup;\n-\t\t\t} else {\n-\t\t\t\trepo->got_indices = 0;\n-\t\t\t\tret = error(\"%s\", curl_errorstr);\n-\t\t\t\tgoto cleanup;\n-\t\t\t}\n-\t\t}\n-\t} else {\n+\tswitch (http_get_info_packs(repo->base, &repo->packs)) {\n+\tcase HTTP_OK:\n+\tcase HTTP_MISSING_TARGET:\n+\t\trepo->got_indices = 1;\n+\t\tret = 0;\n+\t\tbreak;\n+\tdefault:\n \t\trepo->got_indices = 0;\n-\t\tret = error(\"Unable to start request\");\n-\t\tgoto cleanup;\n+\t\tret = -1;\n \t}\n\n-\tdata = buffer.buf;\n-\twhile (i < buffer.len) {\n-\t\tswitch (data[i]) {\n-\t\tcase 'P':\n-\t\t\ti++;\n-\t\t\tif (i + 52 <= buffer.len &&\n-\t\t\t    !prefixcmp(data + i, \" pack-\") &&\n-\t\t\t    !prefixcmp(data + i + 46, \".pack\\n\")) {\n-\t\t\t\tget_sha1_hex(data + i + 6, sha1);\n-\t\t\t\tsetup_index(walker, repo, sha1);\n-\t\t\t\ti += 51;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\tdefault:\n-\t\t\twhile (i < buffer.len && data[i] != '\\n')\n-\t\t\t\ti++;\n-\t\t}\n-\t\ti++;\n-\t}\n-\n-\trepo->got_indices = 1;\n-cleanup:\n-\tstrbuf_release(&buffer);\n-\tfree(url);\n \treturn ret;\n }\n\ndiff --git a/http.c b/http.c\nindex 2a49372..96d83d5 100644\n--- a/http.c\n+++ b/http.c\n@@ -790,3 +790,167 @@ int http_fetch_ref(const char *base, struct ref *ref)\n \tfree(url);\n \treturn ret;\n }\n+\n+/* Helpers for fetching packs */\n+static int fetch_pack_index(unsigned char *sha1, const char *base_url)\n+{\n+\tint ret = 0;\n+\tchar *hex = xstrdup(sha1_to_hex(sha1));\n+\tchar *filename;\n+\tchar *url;\n+\tchar tmpfile[PATH_MAX];\n+\tlong prev_posn = 0;\n+\tchar range[RANGE_HEADER_SIZE];\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tstruct curl_slist *range_header = NULL;\n+\n+\tFILE *indexfile;\n+\tstruct active_request_slot *slot;\n+\tstruct slot_results results;\n+\n+\t/* Don't use the index if the pack isn't there */\n+\tend_url_with_slash(&buf, base_url);\n+\tstrbuf_addf(&buf, \"objects/pack/pack-%s.pack\", hex);\n+\turl = strbuf_detach(&buf, 0);\n+\n+\tslot = get_active_slot();\n+\tslot->results = &results;\n+\tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n+\tcurl_easy_setopt(slot->curl, CURLOPT_NOBODY, 1);\n+\tif (start_active_slot(slot)) {\n+\t\trun_active_slot(slot);\n+\t\tif (results.curl_result != CURLE_OK) {\n+\t\t\tret = error(\"Unable to verify pack %s is available\",\n+\t\t\t\t    hex);\n+\t\t\tgoto cleanup_pack;\n+\t\t}\n+\t} else {\n+\t\tret = error(\"Unable to start request\");\n+\t\tgoto cleanup_pack;\n+\t}\n+\n+\tif (has_pack_index(sha1)) {\n+\t\tret = 0;\n+\t\tgoto cleanup_pack;\n+\t}\n+\n+\tif (http_is_verbose)\n+\t\tfprintf(stderr, \"Getting index for pack %s\\n\", hex);\n+\n+\tend_url_with_slash(&buf, base_url);\n+\tstrbuf_addf(&buf, \"objects/pack/pack-%s.idx\", hex);\n+\turl = strbuf_detach(&buf, NULL);\n+\n+\tfilename = sha1_pack_index_name(sha1);\n+\tsnprintf(tmpfile, sizeof(tmpfile), \"%s.temp\", filename);\n+\tindexfile = fopen(tmpfile, \"a\");\n+\tif (!indexfile) {\n+\t\tret = error(\"Unable to open local file %s for pack index\",\n+\t\t\t    tmpfile);\n+\t\tgoto cleanup_pack;\n+\t}\n+\n+\tslot = get_active_slot();\n+\tslot->results = &results;\n+\tcurl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);\n+\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);\n+\tcurl_easy_setopt(slot->curl, CURLOPT_FILE, indexfile);\n+\tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite);\n+\tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n+\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);\n+\tslot->local = indexfile;\n+\n+\t/*\n+\t * If there is data present from a previous transfer attempt,\n+\t * resume where it left off\n+\t */\n+\tprev_posn = ftell(indexfile);\n+\tif (prev_posn>0) {\n+\t\tif (http_is_verbose)\n+\t\t\tfprintf(stderr,\n+\t\t\t\t\"Resuming fetch of index for pack %s at byte %ld\\n\",\n+\t\t\t\thex, prev_posn);\n+\t\tsprintf(range, \"Range: bytes=%ld-\", prev_posn);\n+\t\trange_header = curl_slist_append(range_header, range);\n+\t\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, range_header);\n+\t}\n+\n+\tif (start_active_slot(slot)) {\n+\t\trun_active_slot(slot);\n+\t\tif (results.curl_result != CURLE_OK) {\n+\t\t\tret = error(\"Unable to get pack index %s\\n%s\",\n+\t\t\t\t    url, curl_errorstr);\n+\t\t\tgoto cleanup_index;\n+\t\t}\n+\t} else {\n+\t\tret = error(\"Unable to start request\");\n+\t\tgoto cleanup_index;\n+\t}\n+\n+\tret = move_temp_to_file(tmpfile, filename);\n+\n+cleanup_index:\n+\tfclose(indexfile);\n+\tslot->local = NULL;\n+cleanup_pack:\n+\tfree(hex);\n+\tfree(url);\n+\treturn ret;\n+}\n+\n+static int fetch_and_setup_pack_index(struct packed_git **packs_head,\n+\tunsigned char *sha1, const char *base_url)\n+{\n+\tstruct packed_git *new_pack;\n+\n+\tif (fetch_pack_index(sha1, base_url))\n+\t\treturn -1;\n+\n+\tnew_pack = parse_pack_index(sha1);\n+\tif (!new_pack)\n+\t\treturn -1; /* parse_pack_index() already issued error message */\n+\tnew_pack->next = *packs_head;\n+\t*packs_head = new_pack;\n+\treturn 0;\n+}\n+\n+int http_get_info_packs(const char *base_url, struct packed_git **packs_head)\n+{\n+\tint ret = 0, i = 0;\n+\tchar *url, *data;\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tunsigned char sha1[20];\n+\n+\tend_url_with_slash(&buf, base_url);\n+\tstrbuf_addstr(&buf, \"objects/info/packs\");\n+\turl = strbuf_detach(&buf, NULL);\n+\n+\tret = http_get_strbuf(url, &buf, HTTP_NO_CACHE);\n+\tif (ret != HTTP_OK)\n+\t\tgoto cleanup;\n+\n+\tdata = buf.buf;\n+\twhile (i < buf.len) {\n+\t\tswitch (data[i]) {\n+\t\tcase 'P':\n+\t\t\ti++;\n+\t\t\tif (i + 52 <= buf.len &&\n+\t\t\t    !prefixcmp(data + i, \" pack-\") &&\n+\t\t\t    !prefixcmp(data + i + 46, \".pack\\n\")) {\n+\t\t\t\tget_sha1_hex(data + i + 6, sha1);\n+\t\t\t\tfetch_and_setup_pack_index(packs_head, sha1,\n+\t\t\t\t\t\t      base_url);\n+\t\t\t\ti += 51;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\tdefault:\n+\t\t\twhile (i < buf.len && data[i] != '\\n')\n+\t\t\t\ti++;\n+\t\t}\n+\t\ti++;\n+\t}\n+\n+cleanup:\n+\tfree(url);\n+\treturn ret;\n+}\ndiff --git a/http.h b/http.h\nindex 3d878d5..180b1c2 100644\n--- a/http.h\n+++ b/http.h\n@@ -146,4 +146,8 @@ int http_error(const char *url, int ret);\n\n extern int http_fetch_ref(const char *base, struct ref *ref);\n\n+/* Helpers for fetching packs */\n+extern int http_get_info_packs(const char *base_url,\n+\tstruct packed_git **packs_head);\n+\n #endif /* HTTP_H */\n--\n1.6.3.1\n"},{"id":"115631","messageId":"20090606164400.c923729b.rctay89@gmail.com","threadId":"19709","inReplyTo":"cover.1244277116.git.rctay89@gmail.com","subject":"[PATCH 21/23] http: use new http API in fetch_index()","fromName":"Tay Ray Chuan","fromEmail":"rctay89@gmail.com","sentAt":"2009-06-06T08:44:00Z","receivedAt":"2009-06-06T08:44:00Z","isPatch":true,"sender":{"key":"rctay89@gmail.com","avatar":"https://avatars.githubusercontent.com/u/61553?v=4"},"body":"\nSigned-off-by: Tay Ray Chuan <rctay89@gmail.com>\n---\n http.c |   81 ++++++---------------------------------------------------------\n 1 files changed, 8 insertions(+), 73 deletions(-)\n\ndiff --git a/http.c b/http.c\nindex 96d83d5..0701a6f 100644\n--- a/http.c\n+++ b/http.c\n@@ -798,40 +798,22 @@ static int fetch_pack_index(unsigned char *sha1, const char *base_url)\n \tchar *hex = xstrdup(sha1_to_hex(sha1));\n \tchar *filename;\n \tchar *url;\n-\tchar tmpfile[PATH_MAX];\n-\tlong prev_posn = 0;\n-\tchar range[RANGE_HEADER_SIZE];\n \tstruct strbuf buf = STRBUF_INIT;\n-\tstruct curl_slist *range_header = NULL;\n-\n-\tFILE *indexfile;\n-\tstruct active_request_slot *slot;\n-\tstruct slot_results results;\n\n \t/* Don't use the index if the pack isn't there */\n \tend_url_with_slash(&buf, base_url);\n \tstrbuf_addf(&buf, \"objects/pack/pack-%s.pack\", hex);\n \turl = strbuf_detach(&buf, 0);\n\n-\tslot = get_active_slot();\n-\tslot->results = &results;\n-\tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_NOBODY, 1);\n-\tif (start_active_slot(slot)) {\n-\t\trun_active_slot(slot);\n-\t\tif (results.curl_result != CURLE_OK) {\n-\t\t\tret = error(\"Unable to verify pack %s is available\",\n-\t\t\t\t    hex);\n-\t\t\tgoto cleanup_pack;\n-\t\t}\n-\t} else {\n-\t\tret = error(\"Unable to start request\");\n-\t\tgoto cleanup_pack;\n+\tif (http_get_strbuf(url, NULL, 0)) {\n+\t\tret = error(\"Unable to verify pack %s is available\",\n+\t\t\t    hex);\n+\t\tgoto cleanup;\n \t}\n\n \tif (has_pack_index(sha1)) {\n \t\tret = 0;\n-\t\tgoto cleanup_pack;\n+\t\tgoto cleanup;\n \t}\n\n \tif (http_is_verbose)\n@@ -842,57 +824,10 @@ static int fetch_pack_index(unsigned char *sha1, const char *base_url)\n \turl = strbuf_detach(&buf, NULL);\n\n \tfilename = sha1_pack_index_name(sha1);\n-\tsnprintf(tmpfile, sizeof(tmpfile), \"%s.temp\", filename);\n-\tindexfile = fopen(tmpfile, \"a\");\n-\tif (!indexfile) {\n-\t\tret = error(\"Unable to open local file %s for pack index\",\n-\t\t\t    tmpfile);\n-\t\tgoto cleanup_pack;\n-\t}\n+\tif (http_get_file(url, filename, 0) != HTTP_OK)\n+\t\tret = error(\"Unable to get pack index %s\\n\", url);\n\n-\tslot = get_active_slot();\n-\tslot->results = &results;\n-\tcurl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_FILE, indexfile);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);\n-\tslot->local = indexfile;\n-\n-\t/*\n-\t * If there is data present from a previous transfer attempt,\n-\t * resume where it left off\n-\t */\n-\tprev_posn = ftell(indexfile);\n-\tif (prev_posn>0) {\n-\t\tif (http_is_verbose)\n-\t\t\tfprintf(stderr,\n-\t\t\t\t\"Resuming fetch of index for pack %s at byte %ld\\n\",\n-\t\t\t\thex, prev_posn);\n-\t\tsprintf(range, \"Range: bytes=%ld-\", prev_posn);\n-\t\trange_header = curl_slist_append(range_header, range);\n-\t\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, range_header);\n-\t}\n-\n-\tif (start_active_slot(slot)) {\n-\t\trun_active_slot(slot);\n-\t\tif (results.curl_result != CURLE_OK) {\n-\t\t\tret = error(\"Unable to get pack index %s\\n%s\",\n-\t\t\t\t    url, curl_errorstr);\n-\t\t\tgoto cleanup_index;\n-\t\t}\n-\t} else {\n-\t\tret = error(\"Unable to start request\");\n-\t\tgoto cleanup_index;\n-\t}\n-\n-\tret = move_temp_to_file(tmpfile, filename);\n-\n-cleanup_index:\n-\tfclose(indexfile);\n-\tslot->local = NULL;\n-cleanup_pack:\n+cleanup:\n \tfree(hex);\n \tfree(url);\n \treturn ret;\n--\n1.6.3.1\n"},{"id":"115635","messageId":"20090606164401.c0d1d202.rctay89@gmail.com","threadId":"19709","inReplyTo":"cover.1244277116.git.rctay89@gmail.com","subject":"[PATCH 22/23] http*: add helper methods for fetching packs","fromName":"Tay Ray Chuan","fromEmail":"rctay89@gmail.com","sentAt":"2009-06-06T08:44:01Z","receivedAt":"2009-06-06T08:44:01Z","isPatch":true,"sender":{"key":"rctay89@gmail.com","avatar":"https://avatars.githubusercontent.com/u/61553?v=4"},"body":"The code handling the fetching of packs in http-push.c and\nhttp-walker.c have been refactored into new methods and a new struct\n(http_pack_request) in http.c. They are not meant to be invoked\nelsewhere.\n\nThe new methods in http.c are\n - new_http_pack_request\n - finish_http_pack_request\n - release_http_pack_request\n\nand the new struct is http_pack_request.\n\nAdd a function, new_http_pack_request(), that deals with the details of\ncoming up with the filename to store the retrieved packfile, resuming a\npreviously aborted request, and making a new curl request. Update\nhttp-push.c::start_fetch_packed() and http-walker.c::fetch_pack() to\nuse this.\n\nAdd a function, finish_http_pack_request(), that deals with renaming\nthe pack, advancing the pack list, and installing the pack. Update\nhttp-push.c::finish_request() and http-walker.c::fetch_pack to use\nthis.\n\nUpdate release_request() in http-push.c and http-walker.c to invoke\nrelease_http_pack_request() to clean up pack request helper data.\n\nThe local_stream member of the transfer_request struct in http-push.c\nhas been removed, as the packfile pointer will be managed in the struct\nhttp_pack_request.\n\nSigned-off-by: Tay Ray Chuan <rctay89@gmail.com>\n---\n http-push.c   |  110 +++++++++++++-------------------------------------------\n http-walker.c |   85 +++++++++----------------------------------\n http.c        |  106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++\n http.h        |   17 +++++++++\n 4 files changed, 167 insertions(+), 151 deletions(-)\n\ndiff --git a/http-push.c b/http-push.c\nindex d6f3b8e..71d9967 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -1,6 +1,5 @@\n #include \"cache.h\"\n #include \"commit.h\"\n-#include \"pack.h\"\n #include \"tag.h\"\n #include \"blob.h\"\n #include \"http.h\"\n@@ -119,7 +118,6 @@ struct transfer_request\n \tchar filename[PATH_MAX];\n \tchar tmpfile[PATH_MAX];\n \tint local_fileno;\n-\tFILE *local_stream;\n \tenum transfer_state state;\n \tCURLcode curl_result;\n \tchar errorstr[CURL_ERROR_SIZE];\n@@ -452,16 +450,10 @@ static void start_mkcol(struct transfer_request *request)\n\n static void start_fetch_packed(struct transfer_request *request)\n {\n-\tchar *url;\n \tstruct packed_git *target;\n-\tFILE *packfile;\n-\tchar *filename;\n-\tlong prev_posn = 0;\n-\tchar range[RANGE_HEADER_SIZE];\n-\tstruct curl_slist *range_header = NULL;\n\n \tstruct transfer_request *check_request = request_queue_head;\n-\tstruct active_request_slot *slot;\n+\tstruct http_pack_request *preq;\n\n \ttarget = find_sha1_pack(request->obj->sha1, repo->packs);\n \tif (!target) {\n@@ -474,68 +466,35 @@ static void start_fetch_packed(struct transfer_request *request)\n \tfprintf(stderr,\t\"Fetching pack %s\\n\", sha1_to_hex(target->sha1));\n \tfprintf(stderr, \" which contains %s\\n\", sha1_to_hex(request->obj->sha1));\n\n-\tfilename = sha1_pack_name(target->sha1);\n-\tsnprintf(request->filename, sizeof(request->filename), \"%s\", filename);\n-\tsnprintf(request->tmpfile, sizeof(request->tmpfile),\n-\t\t \"%s.temp\", filename);\n-\n-\turl = xmalloc(strlen(repo->url) + 64);\n-\tsprintf(url, \"%sobjects/pack/pack-%s.pack\",\n-\t\trepo->url, sha1_to_hex(target->sha1));\n+\tpreq = new_http_pack_request(target, repo->url);\n+\tif (preq == NULL) {\n+\t\trelease_http_pack_request(preq);\n+\t\trepo->can_update_info_refs = 0;\n+\t\treturn;\n+\t}\n+\tpreq->lst = &repo->packs;\n\n \t/* Make sure there isn't another open request for this pack */\n \twhile (check_request) {\n \t\tif (check_request->state == RUN_FETCH_PACKED &&\n-\t\t    !strcmp(check_request->url, url)) {\n-\t\t\tfree(url);\n+\t\t    !strcmp(check_request->url, preq->url)) {\n+\t\t\trelease_http_pack_request(preq);\n \t\t\trelease_request(request);\n \t\t\treturn;\n \t\t}\n \t\tcheck_request = check_request->next;\n \t}\n\n-\tpackfile = fopen(request->tmpfile, \"a\");\n-\tif (!packfile) {\n-\t\tfprintf(stderr, \"Unable to open local file %s for pack\",\n-\t\t\trequest->tmpfile);\n-\t\trepo->can_update_info_refs = 0;\n-\t\tfree(url);\n-\t\treturn;\n-\t}\n-\n-\tslot = get_active_slot();\n-\tslot->callback_func = process_response;\n-\tslot->callback_data = request;\n-\trequest->slot = slot;\n-\trequest->local_stream = packfile;\n-\trequest->userData = target;\n-\n-\trequest->url = url;\n-\tcurl_easy_setopt(slot->curl, CURLOPT_FILE, packfile);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);\n-\tslot->local = packfile;\n-\n-\t/*\n-\t * If there is data present from a previous transfer attempt,\n-\t * resume where it left off\n-\t */\n-\tprev_posn = ftell(packfile);\n-\tif (prev_posn>0) {\n-\t\tif (push_verbosely)\n-\t\t\tfprintf(stderr,\n-\t\t\t\t\"Resuming fetch of pack %s at byte %ld\\n\",\n-\t\t\t\tsha1_to_hex(target->sha1), prev_posn);\n-\t\tsprintf(range, \"Range: bytes=%ld-\", prev_posn);\n-\t\trange_header = curl_slist_append(range_header, range);\n-\t\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, range_header);\n-\t}\n+\tpreq->slot->callback_func = process_response;\n+\tpreq->slot->callback_data = request;\n+\trequest->slot = preq->slot;\n+\trequest->userData = preq;\n\n \t/* Try to get the request started, abort the request on error */\n \trequest->state = RUN_FETCH_PACKED;\n-\tif (!start_active_slot(slot)) {\n+\tif (!start_active_slot(preq->slot)) {\n \t\tfprintf(stderr, \"Unable to start GET request\\n\");\n+\t\trelease_http_pack_request(preq);\n \t\trepo->can_update_info_refs = 0;\n \t\trelease_request(request);\n \t}\n@@ -718,8 +677,6 @@ static void release_request(struct transfer_request *request)\n\n \tif (request->local_fileno != -1)\n \t\tclose(request->local_fileno);\n-\tif (request->local_stream)\n-\t\tfclose(request->local_stream);\n \tfree(request->url);\n \tfree(request);\n }\n@@ -727,13 +684,10 @@ static void release_request(struct transfer_request *request)\n static void finish_request(struct transfer_request *request)\n {\n \tstruct stat st;\n-\tstruct packed_git *target;\n-\tstruct packed_git **lst;\n-\tstruct active_request_slot *slot;\n+\tstruct http_pack_request *preq;\n\n \trequest->curl_result = request->slot->curl_result;\n \trequest->http_code = request->slot->http_code;\n-\tslot = request->slot;\n \trequest->slot = NULL;\n\n \t/* Keep locks active */\n@@ -821,31 +775,21 @@ static void finish_request(struct transfer_request *request)\n \t\t\tstart_fetch_packed(request);\n\n \t} else if (request->state == RUN_FETCH_PACKED) {\n+\t\tint fail = 1;\n \t\tif (request->curl_result != CURLE_OK) {\n \t\t\tfprintf(stderr, \"Unable to get pack file %s\\n%s\",\n \t\t\t\trequest->url, curl_errorstr);\n-\t\t\trepo->can_update_info_refs = 0;\n \t\t} else {\n-\t\t\toff_t pack_size = ftell(request->local_stream);\n-\n-\t\t\tfclose(request->local_stream);\n-\t\t\trequest->local_stream = NULL;\n-\t\t\tslot->local = NULL;\n-\t\t\tif (!move_temp_to_file(request->tmpfile,\n-\t\t\t\t\t       request->filename)) {\n-\t\t\t\ttarget = (struct packed_git *)request->userData;\n-\t\t\t\ttarget->pack_size = pack_size;\n-\t\t\t\tlst = &repo->packs;\n-\t\t\t\twhile (*lst != target)\n-\t\t\t\t\tlst = &((*lst)->next);\n-\t\t\t\t*lst = (*lst)->next;\n-\n-\t\t\t\tif (!verify_pack(target))\n-\t\t\t\t\tinstall_packed_git(target);\n-\t\t\t\telse\n-\t\t\t\t\trepo->can_update_info_refs = 0;\n+\t\t\tpreq = (struct http_pack_request *)request->userData;\n+\n+\t\t\tif (preq) {\n+\t\t\t\tif (finish_http_pack_request(preq) > 0)\n+\t\t\t\t\tfail = 0;\n+\t\t\t\trelease_http_pack_request(preq);\n \t\t\t}\n \t\t}\n+\t\tif (fail)\n+\t\t\trepo->can_update_info_refs = 0;\n \t\trelease_request(request);\n \t}\n }\n@@ -900,7 +844,6 @@ static void add_fetch_request(struct object *obj)\n \trequest->lock = NULL;\n \trequest->headers = NULL;\n \trequest->local_fileno = -1;\n-\trequest->local_stream = NULL;\n \trequest->state = NEED_FETCH;\n \trequest->next = request_queue_head;\n \trequest_queue_head = request;\n@@ -940,7 +883,6 @@ static int add_send_request(struct object *obj, struct remote_lock *lock)\n \trequest->lock = lock;\n \trequest->headers = NULL;\n \trequest->local_fileno = -1;\n-\trequest->local_stream = NULL;\n \trequest->state = NEED_PUSH;\n \trequest->next = request_queue_head;\n \trequest_queue_head = request;\ndiff --git a/http-walker.c b/http-walker.c\nindex ac343fd..8f7a975 100644\n--- a/http-walker.c\n+++ b/http-walker.c\n@@ -1,6 +1,5 @@\n #include \"cache.h\"\n #include \"commit.h\"\n-#include \"pack.h\"\n #include \"walker.h\"\n #include \"http.h\"\n\n@@ -590,19 +589,10 @@ static int fetch_indices(struct walker *walker, struct alt_base *repo)\n\n static int fetch_pack(struct walker *walker, struct alt_base *repo, unsigned char *sha1)\n {\n-\tchar *url;\n \tstruct packed_git *target;\n-\tstruct packed_git **lst;\n-\tFILE *packfile;\n-\tchar *filename;\n-\tchar tmpfile[PATH_MAX];\n \tint ret;\n-\tlong prev_posn = 0;\n-\tchar range[RANGE_HEADER_SIZE];\n-\tstruct curl_slist *range_header = NULL;\n-\n-\tstruct active_request_slot *slot;\n \tstruct slot_results results;\n+\tstruct http_pack_request *preq;\n\n \tif (fetch_indices(walker, repo))\n \t\treturn -1;\n@@ -617,72 +607,33 @@ static int fetch_pack(struct walker *walker, struct alt_base *repo, unsigned cha\n \t\t\tsha1_to_hex(sha1));\n \t}\n\n-\turl = xmalloc(strlen(repo->base) + 65);\n-\tsprintf(url, \"%s/objects/pack/pack-%s.pack\",\n-\t\trepo->base, sha1_to_hex(target->sha1));\n+\tpreq = new_http_pack_request(target, repo->base);\n+\tif (preq == NULL)\n+\t\tgoto abort;\n+\tpreq->lst = &repo->packs;\n+\tpreq->slot->results = &results;\n\n-\tfilename = sha1_pack_name(target->sha1);\n-\tsnprintf(tmpfile, sizeof(tmpfile), \"%s.temp\", filename);\n-\tpackfile = fopen(tmpfile, \"a\");\n-\tif (!packfile)\n-\t\treturn error(\"Unable to open local file %s for pack\",\n-\t\t\t     tmpfile);\n-\n-\tslot = get_active_slot();\n-\tslot->results = &results;\n-\tcurl_easy_setopt(slot->curl, CURLOPT_FILE, packfile);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);\n-\tslot->local = packfile;\n-\n-\t/*\n-\t * If there is data present from a previous transfer attempt,\n-\t * resume where it left off\n-\t */\n-\tprev_posn = ftell(packfile);\n-\tif (prev_posn>0) {\n-\t\tif (walker->get_verbosely)\n-\t\t\tfprintf(stderr,\n-\t\t\t\t\"Resuming fetch of pack %s at byte %ld\\n\",\n-\t\t\t\tsha1_to_hex(target->sha1), prev_posn);\n-\t\tsprintf(range, \"Range: bytes=%ld-\", prev_posn);\n-\t\trange_header = curl_slist_append(range_header, range);\n-\t\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, range_header);\n-\t}\n-\n-\tif (start_active_slot(slot)) {\n-\t\trun_active_slot(slot);\n+\tif (start_active_slot(preq->slot)) {\n+\t\trun_active_slot(preq->slot);\n \t\tif (results.curl_result != CURLE_OK) {\n-\t\t\tfclose(packfile);\n-\t\t\tslot->local = NULL;\n-\t\t\treturn error(\"Unable to get pack file %s\\n%s\", url,\n-\t\t\t\t     curl_errorstr);\n+\t\t\terror(\"Unable to get pack file %s\\n%s\", preq->url,\n+\t\t\t      curl_errorstr);\n+\t\t\tgoto abort;\n \t\t}\n \t} else {\n-\t\tfclose(packfile);\n-\t\tslot->local = NULL;\n-\t\treturn error(\"Unable to start request\");\n+\t\terror(\"Unable to start request\");\n+\t\tgoto abort;\n \t}\n\n-\ttarget->pack_size = ftell(packfile);\n-\tfclose(packfile);\n-\tslot->local = NULL;\n-\n-\tret = move_temp_to_file(tmpfile, filename);\n+\tret = finish_http_pack_request(preq);\n+\trelease_http_pack_request(preq);\n \tif (ret)\n \t\treturn ret;\n\n-\tlst = &repo->packs;\n-\twhile (*lst != target)\n-\t\tlst = &((*lst)->next);\n-\t*lst = (*lst)->next;\n-\n-\tif (verify_pack(target))\n-\t\treturn -1;\n-\tinstall_packed_git(target);\n-\n \treturn 0;\n+\n+abort:\n+\treturn -1;\n }\n\n static void abort_object_request(struct object_request *obj_req)\ndiff --git a/http.c b/http.c\nindex 0701a6f..3815934 100644\n--- a/http.c\n+++ b/http.c\n@@ -1,4 +1,5 @@\n #include \"http.h\"\n+#include \"pack.h\"\n\n int data_received;\n int active_requests;\n@@ -889,3 +890,108 @@ cleanup:\n \tfree(url);\n \treturn ret;\n }\n+\n+void release_http_pack_request(struct http_pack_request *preq)\n+{\n+\tif (preq->packfile != NULL) {\n+\t\tfclose(preq->packfile);\n+\t\tpreq->packfile = NULL;\n+\t\tpreq->slot->local = NULL;\n+\t}\n+\tif (preq->range_header != NULL) {\n+\t\tcurl_slist_free_all(preq->range_header);\n+\t\tpreq->range_header = NULL;\n+\t}\n+\tpreq->slot = NULL;\n+\tfree(preq->url);\n+}\n+\n+int finish_http_pack_request(struct http_pack_request *preq)\n+{\n+\tint ret;\n+\tstruct packed_git **lst;\n+\n+\tpreq->target->pack_size = ftell(preq->packfile);\n+\n+\tif (preq->packfile != NULL) {\n+\t\tfclose(preq->packfile);\n+\t\tpreq->packfile = NULL;\n+\t\tpreq->slot->local = NULL;\n+\t}\n+\n+\tret = move_temp_to_file(preq->tmpfile, preq->filename);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tlst = preq->lst;\n+\twhile (*lst != preq->target)\n+\t\tlst = &((*lst)->next);\n+\t*lst = (*lst)->next;\n+\n+\tif (verify_pack(preq->target))\n+\t\treturn -1;\n+\tinstall_packed_git(preq->target);\n+\n+\treturn 0;\n+}\n+\n+struct http_pack_request *new_http_pack_request(\n+\tstruct packed_git *target, const char *base_url)\n+{\n+\tchar *url;\n+\tchar *filename;\n+\tlong prev_posn = 0;\n+\tchar range[RANGE_HEADER_SIZE];\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tstruct http_pack_request *preq;\n+\n+\tpreq = xmalloc(sizeof(*preq));\n+\tpreq->target = target;\n+\tpreq->range_header = NULL;\n+\n+\tend_url_with_slash(&buf, base_url);\n+\tstrbuf_addf(&buf, \"objects/pack/pack-%s.pack\",\n+\t\tsha1_to_hex(target->sha1));\n+\turl = strbuf_detach(&buf, NULL);\n+\tpreq->url = xstrdup(url);\n+\n+\tfilename = sha1_pack_name(target->sha1);\n+\tsnprintf(preq->filename, sizeof(preq->filename), \"%s\", filename);\n+\tsnprintf(preq->tmpfile, sizeof(preq->tmpfile), \"%s.temp\", filename);\n+\tpreq->packfile = fopen(preq->tmpfile, \"a\");\n+\tif (!preq->packfile) {\n+\t\terror(\"Unable to open local file %s for pack\",\n+\t\t      preq->tmpfile);\n+\t\tgoto abort;\n+\t}\n+\n+\tpreq->slot = get_active_slot();\n+\tpreq->slot->local = preq->packfile;\n+\tcurl_easy_setopt(preq->slot->curl, CURLOPT_FILE, preq->packfile);\n+\tcurl_easy_setopt(preq->slot->curl, CURLOPT_WRITEFUNCTION, fwrite);\n+\tcurl_easy_setopt(preq->slot->curl, CURLOPT_URL, url);\n+\tcurl_easy_setopt(preq->slot->curl, CURLOPT_HTTPHEADER,\n+\t\tno_pragma_header);\n+\n+\t/*\n+\t * If there is data present from a previous transfer attempt,\n+\t * resume where it left off\n+\t */\n+\tprev_posn = ftell(preq->packfile);\n+\tif (prev_posn>0) {\n+\t\tif (http_is_verbose)\n+\t\t\tfprintf(stderr,\n+\t\t\t\t\"Resuming fetch of pack %s at byte %ld\\n\",\n+\t\t\t\tsha1_to_hex(target->sha1), prev_posn);\n+\t\tsprintf(range, \"Range: bytes=%ld-\", prev_posn);\n+\t\tpreq->range_header = curl_slist_append(NULL, range);\n+\t\tcurl_easy_setopt(preq->slot->curl, CURLOPT_HTTPHEADER,\n+\t\t\tpreq->range_header);\n+\t}\n+\n+\treturn preq;\n+\n+abort:\n+\tfree(filename);\n+\treturn NULL;\n+}\ndiff --git a/http.h b/http.h\nindex 180b1c2..511c0c4 100644\n--- a/http.h\n+++ b/http.h\n@@ -150,4 +150,21 @@ extern int http_fetch_ref(const char *base, struct ref *ref);\n extern int http_get_info_packs(const char *base_url,\n \tstruct packed_git **packs_head);\n\n+struct http_pack_request\n+{\n+\tchar *url;\n+\tstruct packed_git *target;\n+\tstruct packed_git **lst;\n+\tFILE *packfile;\n+\tchar filename[PATH_MAX];\n+\tchar tmpfile[PATH_MAX];\n+\tstruct curl_slist *range_header;\n+\tstruct active_request_slot *slot;\n+};\n+\n+extern struct http_pack_request *new_http_pack_request(\n+\tstruct packed_git *target, const char *base_url);\n+extern int finish_http_pack_request(struct http_pack_request *preq);\n+extern void release_http_pack_request(struct http_pack_request *preq);\n+\n #endif /* HTTP_H */\n--\n1.6.3.1\n"},{"id":"115636","messageId":"20090606164402.2529fe71.rctay89@gmail.com","threadId":"19709","inReplyTo":"cover.1244277116.git.rctay89@gmail.com","subject":"[PATCH 23/23] http*: add helper methods for fetching objects (loose)","fromName":"Tay Ray Chuan","fromEmail":"rctay89@gmail.com","sentAt":"2009-06-06T08:44:02Z","receivedAt":"2009-06-06T08:44:02Z","isPatch":true,"sender":{"key":"rctay89@gmail.com","avatar":"https://avatars.githubusercontent.com/u/61553?v=4"},"body":"The code handling the fetching of loose objects in http-push.c and\nhttp-walker.c have been refactored into new methods and a new struct\n(object_http_request) in http.c. They are not meant to be invoked\nelsewhere.\n\nThe new methods in http.c are\n - new_http_object_request\n - process_http_object_request\n - finish_http_object_request\n - abort_http_object_request\n - release_http_object_request\n\nand the new struct is http_object_request.\n\nRANGER_HEADER_SIZE and no_pragma_header is no longer made available\noutside of http.c, since after the above changes, there are no other\ninstances of usage outside of http.c.\n\nRemove members of the transfer_request struct in http-push.c and\nhttp-walker.c, including filename, real_sha1 and zret, as they are used\nno longer used.\n\nMove the methods append_remote_object_url() and get_remote_object_url()\nfrom http-push.c to http.c. Additionally, get_remote_object_url() is no\nlonger defined only when USE_CURL_MULTI is defined, since\nnon-USE_CURL_MULTI code in http.c uses it (namely, in\nnew_http_object_request()).\n\nRefactor code from http-push.c::start_fetch_loose() and\nhttp-walker.c::start_object_fetch_request() that deals with the details\nof coming up with the filename to store the retrieved object, resuming\na previously aborted request, and making a new curl request, into a new\nfunction, new_http_object_request().\n\nRefactor code from http-walker.c::process_object_request() into the\nfunction, process_http_object_request().\n\nRefactor code from http-push.c::finish_request() and\nhttp-walker.c::finish_object_request() into a new function,\nfinish_http_object_request(). It returns the result of the\nmove_temp_to_file() invocation.\n\nAdd a function, release_http_object_request(), which cleans up object\nrequest data. http-push.c and http-walker.c invoke this function\nseparately; http-push.c::release_request() and\nhttp-walker.c::release_object_request() do not invoke this function.\n\nAdd a function, abort_http_object_request(), which unlink()s the object\nfile and invokes release_http_object_request(). Update\nhttp-walker.c::abort_object_request() to use this.\n\nSigned-off-by: Tay Ray Chuan <rctay89@gmail.com>\n---\n http-push.c   |  213 +++------------------------------------------\n http-walker.c |  267 +++++++++------------------------------------------------\n http.c        |  250 +++++++++++++++++++++++++++++++++++++++++++++++++++++-\n http.h        |   37 +++++++-\n 4 files changed, 336 insertions(+), 431 deletions(-)\n\ndiff --git a/http-push.c b/http-push.c\nindex 71d9967..0d83465 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -115,18 +115,10 @@ struct transfer_request\n \tstruct remote_lock *lock;\n \tstruct curl_slist *headers;\n \tstruct buffer buffer;\n-\tchar filename[PATH_MAX];\n-\tchar tmpfile[PATH_MAX];\n-\tint local_fileno;\n \tenum transfer_state state;\n \tCURLcode curl_result;\n \tchar errorstr[CURL_ERROR_SIZE];\n \tlong http_code;\n-\tunsigned char real_sha1[20];\n-\tgit_SHA_CTX c;\n-\tz_stream stream;\n-\tint zret;\n-\tint rename;\n \tvoid *userData;\n \tstruct active_request_slot *slot;\n \tstruct transfer_request *next;\n@@ -232,15 +224,6 @@ static struct curl_slist *get_dav_token_headers(struct remote_lock *lock, enum d\n \treturn dav_headers;\n }\n\n-static void append_remote_object_url(struct strbuf *buf, const char *url,\n-\t\t\t\t     const char *hex,\n-\t\t\t\t     int only_two_digit_prefix)\n-{\n-\tstrbuf_addf(buf, \"%sobjects/%.*s/\", url, 2, hex);\n-\tif (!only_two_digit_prefix)\n-\t\tstrbuf_addf(buf, \"%s\", hex+2);\n-}\n-\n static void finish_request(struct transfer_request *request);\n static void release_request(struct transfer_request *request);\n\n@@ -254,169 +237,29 @@ static void process_response(void *callback_data)\n\n #ifdef USE_CURL_MULTI\n\n-static char *get_remote_object_url(const char *url, const char *hex,\n-\t\t\t\t   int only_two_digit_prefix)\n-{\n-\tstruct strbuf buf = STRBUF_INIT;\n-\tappend_remote_object_url(&buf, url, hex, only_two_digit_prefix);\n-\treturn strbuf_detach(&buf, NULL);\n-}\n-\n-static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,\n-\t\t\t       void *data)\n-{\n-\tunsigned char expn[4096];\n-\tsize_t size = eltsize * nmemb;\n-\tint posn = 0;\n-\tstruct transfer_request *request = (struct transfer_request *)data;\n-\tdo {\n-\t\tssize_t retval = xwrite(request->local_fileno,\n-\t\t\t\t\t(char *) ptr + posn, size - posn);\n-\t\tif (retval < 0)\n-\t\t\treturn posn;\n-\t\tposn += retval;\n-\t} while (posn < size);\n-\n-\trequest->stream.avail_in = size;\n-\trequest->stream.next_in = ptr;\n-\tdo {\n-\t\trequest->stream.next_out = expn;\n-\t\trequest->stream.avail_out = sizeof(expn);\n-\t\trequest->zret = git_inflate(&request->stream, Z_SYNC_FLUSH);\n-\t\tgit_SHA1_Update(&request->c, expn,\n-\t\t\t\tsizeof(expn) - request->stream.avail_out);\n-\t} while (request->stream.avail_in && request->zret == Z_OK);\n-\tdata_received++;\n-\treturn size;\n-}\n-\n static void start_fetch_loose(struct transfer_request *request)\n {\n-\tchar *hex = sha1_to_hex(request->obj->sha1);\n-\tchar *filename;\n-\tchar prevfile[PATH_MAX];\n-\tchar *url;\n-\tint prevlocal;\n-\tunsigned char prev_buf[PREV_BUF_SIZE];\n-\tssize_t prev_read = 0;\n-\tlong prev_posn = 0;\n-\tchar range[RANGE_HEADER_SIZE];\n-\tstruct curl_slist *range_header = NULL;\n \tstruct active_request_slot *slot;\n+\tstruct http_object_request *obj_req;\n\n-\tfilename = sha1_file_name(request->obj->sha1);\n-\tsnprintf(request->filename, sizeof(request->filename), \"%s\", filename);\n-\tsnprintf(request->tmpfile, sizeof(request->tmpfile),\n-\t\t \"%s.temp\", filename);\n-\n-\tsnprintf(prevfile, sizeof(prevfile), \"%s.prev\", request->filename);\n-\tunlink_or_warn(prevfile);\n-\trename(request->tmpfile, prevfile);\n-\tunlink_or_warn(request->tmpfile);\n-\n-\tif (request->local_fileno != -1)\n-\t\terror(\"fd leakage in start: %d\", request->local_fileno);\n-\trequest->local_fileno = open(request->tmpfile,\n-\t\t\t\t     O_WRONLY | O_CREAT | O_EXCL, 0666);\n-\t/*\n-\t * This could have failed due to the \"lazy directory creation\";\n-\t * try to mkdir the last path component.\n-\t */\n-\tif (request->local_fileno < 0 && errno == ENOENT) {\n-\t\tchar *dir = strrchr(request->tmpfile, '/');\n-\t\tif (dir) {\n-\t\t\t*dir = 0;\n-\t\t\tmkdir(request->tmpfile, 0777);\n-\t\t\t*dir = '/';\n-\t\t}\n-\t\trequest->local_fileno = open(request->tmpfile,\n-\t\t\t\t\t     O_WRONLY | O_CREAT | O_EXCL, 0666);\n-\t}\n-\n-\tif (request->local_fileno < 0) {\n+\tobj_req = new_http_object_request(repo->url, request->obj->sha1);\n+\tif (obj_req == NULL) {\n \t\trequest->state = ABORTED;\n-\t\terror(\"Couldn't create temporary file %s for %s: %s\",\n-\t\t      request->tmpfile, request->filename, strerror(errno));\n \t\treturn;\n \t}\n\n-\tmemset(&request->stream, 0, sizeof(request->stream));\n-\n-\tgit_inflate_init(&request->stream);\n-\n-\tgit_SHA1_Init(&request->c);\n-\n-\turl = get_remote_object_url(repo->url, hex, 0);\n-\trequest->url = xstrdup(url);\n-\n-\t/*\n-\t * If a previous temp file is present, process what was already\n-\t * fetched.\n-\t */\n-\tprevlocal = open(prevfile, O_RDONLY);\n-\tif (prevlocal != -1) {\n-\t\tdo {\n-\t\t\tprev_read = xread(prevlocal, prev_buf, PREV_BUF_SIZE);\n-\t\t\tif (prev_read>0) {\n-\t\t\t\tif (fwrite_sha1_file(prev_buf,\n-\t\t\t\t\t\t     1,\n-\t\t\t\t\t\t     prev_read,\n-\t\t\t\t\t\t     request) == prev_read)\n-\t\t\t\t\tprev_posn += prev_read;\n-\t\t\t\telse\n-\t\t\t\t\tprev_read = -1;\n-\t\t\t}\n-\t\t} while (prev_read > 0);\n-\t\tclose(prevlocal);\n-\t}\n-\tunlink_or_warn(prevfile);\n-\n-\t/*\n-\t * Reset inflate/SHA1 if there was an error reading the previous temp\n-\t * file; also rewind to the beginning of the local file.\n-\t */\n-\tif (prev_read == -1) {\n-\t\tmemset(&request->stream, 0, sizeof(request->stream));\n-\t\tgit_inflate_init(&request->stream);\n-\t\tgit_SHA1_Init(&request->c);\n-\t\tif (prev_posn>0) {\n-\t\t\tprev_posn = 0;\n-\t\t\tlseek(request->local_fileno, 0, SEEK_SET);\n-\t\t\tftruncate(request->local_fileno, 0);\n-\t\t}\n-\t}\n-\n-\tslot = get_active_slot();\n+\tslot = obj_req->slot;\n \tslot->callback_func = process_response;\n \tslot->callback_data = request;\n \trequest->slot = slot;\n-\n-\tcurl_easy_setopt(slot->curl, CURLOPT_FILE, request);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_sha1_file);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, request->errorstr);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);\n-\n-\t/*\n-\t * If we have successfully processed data from a previous fetch\n-\t * attempt, only fetch the data we don't already have.\n-\t */\n-\tif (prev_posn>0) {\n-\t\tif (push_verbosely)\n-\t\t\tfprintf(stderr,\n-\t\t\t\t\"Resuming fetch of object %s at byte %ld\\n\",\n-\t\t\t\thex, prev_posn);\n-\t\tsprintf(range, \"Range: bytes=%ld-\", prev_posn);\n-\t\trange_header = curl_slist_append(range_header, range);\n-\t\tcurl_easy_setopt(slot->curl,\n-\t\t\t\t CURLOPT_HTTPHEADER, range_header);\n-\t}\n+\trequest->userData = obj_req;\n\n \t/* Try to get the request started, abort the request on error */\n \trequest->state = RUN_FETCH_LOOSE;\n \tif (!start_active_slot(slot)) {\n \t\tfprintf(stderr, \"Unable to start GET request\\n\");\n \t\trepo->can_update_info_refs = 0;\n+\t\trelease_http_object_request(obj_req);\n \t\trelease_request(request);\n \t}\n }\n@@ -675,16 +518,14 @@ static void release_request(struct transfer_request *request)\n \t\t\tentry->next = entry->next->next;\n \t}\n\n-\tif (request->local_fileno != -1)\n-\t\tclose(request->local_fileno);\n \tfree(request->url);\n \tfree(request);\n }\n\n static void finish_request(struct transfer_request *request)\n {\n-\tstruct stat st;\n \tstruct http_pack_request *preq;\n+\tstruct http_object_request *obj_req;\n\n \trequest->curl_result = request->slot->curl_result;\n \trequest->http_code = request->slot->http_code;\n@@ -739,39 +580,17 @@ static void finish_request(struct transfer_request *request)\n \t\t\taborted = 1;\n \t\t}\n \t} else if (request->state == RUN_FETCH_LOOSE) {\n-\t\tclose(request->local_fileno);\n-\t\trequest->local_fileno = -1;\n-\n-\t\tif (request->curl_result != CURLE_OK &&\n-\t\t    request->http_code != 416) {\n-\t\t\tif (stat(request->tmpfile, &st) == 0) {\n-\t\t\t\tif (st.st_size == 0)\n-\t\t\t\t\tunlink_or_warn(request->tmpfile);\n-\t\t\t}\n-\t\t} else {\n-\t\t\tif (request->http_code == 416)\n-\t\t\t\twarning(\"requested range invalid; we may already have all the data.\");\n-\n-\t\t\tgit_inflate_end(&request->stream);\n-\t\t\tgit_SHA1_Final(request->real_sha1, &request->c);\n-\t\t\tif (request->zret != Z_STREAM_END) {\n-\t\t\t\tunlink_or_warn(request->tmpfile);\n-\t\t\t} else if (hashcmp(request->obj->sha1, request->real_sha1)) {\n-\t\t\t\tunlink_or_warn(request->tmpfile);\n-\t\t\t} else {\n-\t\t\t\trequest->rename =\n-\t\t\t\t\tmove_temp_to_file(\n-\t\t\t\t\t\trequest->tmpfile,\n-\t\t\t\t\t\trequest->filename);\n-\t\t\t\tif (request->rename == 0)\n-\t\t\t\t\trequest->obj->flags |= (LOCAL | REMOTE);\n-\t\t\t}\n-\t\t}\n+\t\tobj_req = (struct http_object_request *)request->userData;\n+\n+\t\tif (finish_http_object_request(obj_req) == 0)\n+\t\t\tif (obj_req->rename == 0)\n+\t\t\t\trequest->obj->flags |= (LOCAL | REMOTE);\n\n \t\t/* Try fetching packed if necessary */\n-\t\tif (request->obj->flags & LOCAL)\n+\t\tif (request->obj->flags & LOCAL) {\n+\t\t\trelease_http_object_request(obj_req);\n \t\t\trelease_request(request);\n-\t\telse\n+\t\t} else\n \t\t\tstart_fetch_packed(request);\n\n \t} else if (request->state == RUN_FETCH_PACKED) {\n@@ -843,7 +662,6 @@ static void add_fetch_request(struct object *obj)\n \trequest->url = NULL;\n \trequest->lock = NULL;\n \trequest->headers = NULL;\n-\trequest->local_fileno = -1;\n \trequest->state = NEED_FETCH;\n \trequest->next = request_queue_head;\n \trequest_queue_head = request;\n@@ -882,7 +700,6 @@ static int add_send_request(struct object *obj, struct remote_lock *lock)\n \trequest->url = NULL;\n \trequest->lock = lock;\n \trequest->headers = NULL;\n-\trequest->local_fileno = -1;\n \trequest->state = NEED_PUSH;\n \trequest->next = request_queue_head;\n \trequest_queue_head = request;\ndiff --git a/http-walker.c b/http-walker.c\nindex 8f7a975..700bc13 100644\n--- a/http-walker.c\n+++ b/http-walker.c\n@@ -3,8 +3,6 @@\n #include \"walker.h\"\n #include \"http.h\"\n\n-#define PREV_BUF_SIZE 4096\n-\n struct alt_base\n {\n \tchar *base;\n@@ -25,20 +23,8 @@ struct object_request\n \tstruct walker *walker;\n \tunsigned char sha1[20];\n \tstruct alt_base *repo;\n-\tchar *url;\n-\tchar filename[PATH_MAX];\n-\tchar tmpfile[PATH_MAX];\n-\tint local;\n \tenum object_request_state state;\n-\tCURLcode curl_result;\n-\tchar errorstr[CURL_ERROR_SIZE];\n-\tlong http_code;\n-\tunsigned char real_sha1[20];\n-\tgit_SHA_CTX c;\n-\tz_stream stream;\n-\tint zret;\n-\tint rename;\n-\tstruct active_request_slot *slot;\n+\tstruct http_object_request *req;\n \tstruct object_request *next;\n };\n\n@@ -59,34 +45,6 @@ struct walker_data {\n\n static struct object_request *object_queue_head;\n\n-static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,\n-\t\t\t       void *data)\n-{\n-\tunsigned char expn[4096];\n-\tsize_t size = eltsize * nmemb;\n-\tint posn = 0;\n-\tstruct object_request *obj_req = (struct object_request *)data;\n-\tdo {\n-\t\tssize_t retval = xwrite(obj_req->local,\n-\t\t\t\t\t(char *) ptr + posn, size - posn);\n-\t\tif (retval < 0)\n-\t\t\treturn posn;\n-\t\tposn += retval;\n-\t} while (posn < size);\n-\n-\tobj_req->stream.avail_in = size;\n-\tobj_req->stream.next_in = ptr;\n-\tdo {\n-\t\tobj_req->stream.next_out = expn;\n-\t\tobj_req->stream.avail_out = sizeof(expn);\n-\t\tobj_req->zret = git_inflate(&obj_req->stream, Z_SYNC_FLUSH);\n-\t\tgit_SHA1_Update(&obj_req->c, expn,\n-\t\t\t\tsizeof(expn) - obj_req->stream.avail_out);\n-\t} while (obj_req->stream.avail_in && obj_req->zret == Z_OK);\n-\tdata_received++;\n-\treturn size;\n-}\n-\n static void fetch_alternates(struct walker *walker, const char *base);\n\n static void process_object_response(void *callback_data);\n@@ -94,172 +52,35 @@ static void process_object_response(void *callback_data);\n static void start_object_request(struct walker *walker,\n \t\t\t\t struct object_request *obj_req)\n {\n-\tchar *hex = sha1_to_hex(obj_req->sha1);\n-\tchar prevfile[PATH_MAX];\n-\tchar *url;\n-\tchar *posn;\n-\tint prevlocal;\n-\tunsigned char prev_buf[PREV_BUF_SIZE];\n-\tssize_t prev_read = 0;\n-\tlong prev_posn = 0;\n-\tchar range[RANGE_HEADER_SIZE];\n-\tstruct curl_slist *range_header = NULL;\n \tstruct active_request_slot *slot;\n+\tstruct http_object_request *req;\n\n-\tsnprintf(prevfile, sizeof(prevfile), \"%s.prev\", obj_req->filename);\n-\tunlink_or_warn(prevfile);\n-\trename(obj_req->tmpfile, prevfile);\n-\tunlink_or_warn(obj_req->tmpfile);\n-\n-\tif (obj_req->local != -1)\n-\t\terror(\"fd leakage in start: %d\", obj_req->local);\n-\tobj_req->local = open(obj_req->tmpfile,\n-\t\t\t      O_WRONLY | O_CREAT | O_EXCL, 0666);\n-\t/*\n-\t * This could have failed due to the \"lazy directory creation\";\n-\t * try to mkdir the last path component.\n-\t */\n-\tif (obj_req->local < 0 && errno == ENOENT) {\n-\t\tchar *dir = strrchr(obj_req->tmpfile, '/');\n-\t\tif (dir) {\n-\t\t\t*dir = 0;\n-\t\t\tmkdir(obj_req->tmpfile, 0777);\n-\t\t\t*dir = '/';\n-\t\t}\n-\t\tobj_req->local = open(obj_req->tmpfile,\n-\t\t\t\t      O_WRONLY | O_CREAT | O_EXCL, 0666);\n-\t}\n-\n-\tif (obj_req->local < 0) {\n+\treq = new_http_object_request(obj_req->repo->base, obj_req->sha1);\n+\tif (req == NULL) {\n \t\tobj_req->state = ABORTED;\n-\t\terror(\"Couldn't create temporary file %s for %s: %s\",\n-\t\t      obj_req->tmpfile, obj_req->filename, strerror(errno));\n \t\treturn;\n \t}\n+\tobj_req->req = req;\n\n-\tmemset(&obj_req->stream, 0, sizeof(obj_req->stream));\n-\n-\tgit_inflate_init(&obj_req->stream);\n-\n-\tgit_SHA1_Init(&obj_req->c);\n-\n-\turl = xmalloc(strlen(obj_req->repo->base) + 51);\n-\tobj_req->url = xmalloc(strlen(obj_req->repo->base) + 51);\n-\tstrcpy(url, obj_req->repo->base);\n-\tposn = url + strlen(obj_req->repo->base);\n-\tstrcpy(posn, \"/objects/\");\n-\tposn += 9;\n-\tmemcpy(posn, hex, 2);\n-\tposn += 2;\n-\t*(posn++) = '/';\n-\tstrcpy(posn, hex + 2);\n-\tstrcpy(obj_req->url, url);\n-\n-\t/*\n-\t * If a previous temp file is present, process what was already\n-\t * fetched.\n-\t */\n-\tprevlocal = open(prevfile, O_RDONLY);\n-\tif (prevlocal != -1) {\n-\t\tdo {\n-\t\t\tprev_read = xread(prevlocal, prev_buf, PREV_BUF_SIZE);\n-\t\t\tif (prev_read>0) {\n-\t\t\t\tif (fwrite_sha1_file(prev_buf,\n-\t\t\t\t\t\t     1,\n-\t\t\t\t\t\t     prev_read,\n-\t\t\t\t\t\t     obj_req) == prev_read)\n-\t\t\t\t\tprev_posn += prev_read;\n-\t\t\t\telse\n-\t\t\t\t\tprev_read = -1;\n-\t\t\t}\n-\t\t} while (prev_read > 0);\n-\t\tclose(prevlocal);\n-\t}\n-\tunlink_or_warn(prevfile);\n-\n-\t/*\n-\t * Reset inflate/SHA1 if there was an error reading the previous temp\n-\t * file; also rewind to the beginning of the local file.\n-\t */\n-\tif (prev_read == -1) {\n-\t\tmemset(&obj_req->stream, 0, sizeof(obj_req->stream));\n-\t\tgit_inflate_init(&obj_req->stream);\n-\t\tgit_SHA1_Init(&obj_req->c);\n-\t\tif (prev_posn>0) {\n-\t\t\tprev_posn = 0;\n-\t\t\tlseek(obj_req->local, 0, SEEK_SET);\n-\t\t\tftruncate(obj_req->local, 0);\n-\t\t}\n-\t}\n-\n-\tslot = get_active_slot();\n+\tslot = req->slot;\n \tslot->callback_func = process_object_response;\n \tslot->callback_data = obj_req;\n-\tobj_req->slot = slot;\n-\n-\tcurl_easy_setopt(slot->curl, CURLOPT_FILE, obj_req);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_sha1_file);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, obj_req->errorstr);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);\n-\n-\t/*\n-\t * If we have successfully processed data from a previous fetch\n-\t * attempt, only fetch the data we don't already have.\n-\t */\n-\tif (prev_posn>0) {\n-\t\tif (walker->get_verbosely)\n-\t\t\tfprintf(stderr,\n-\t\t\t\t\"Resuming fetch of object %s at byte %ld\\n\",\n-\t\t\t\thex, prev_posn);\n-\t\tsprintf(range, \"Range: bytes=%ld-\", prev_posn);\n-\t\trange_header = curl_slist_append(range_header, range);\n-\t\tcurl_easy_setopt(slot->curl,\n-\t\t\t\t CURLOPT_HTTPHEADER, range_header);\n-\t}\n\n \t/* Try to get the request started, abort the request on error */\n \tobj_req->state = ACTIVE;\n \tif (!start_active_slot(slot)) {\n \t\tobj_req->state = ABORTED;\n-\t\tobj_req->slot = NULL;\n-\t\tclose(obj_req->local);\n-\t\tobj_req->local = -1;\n-\t\tfree(obj_req->url);\n+\t\trelease_http_object_request(req);\n \t\treturn;\n \t}\n }\n\n static void finish_object_request(struct object_request *obj_req)\n {\n-\tstruct stat st;\n-\n-\tclose(obj_req->local);\n-\tobj_req->local = -1;\n-\n-\tif (obj_req->http_code == 416) {\n-\t\tfprintf(stderr, \"Warning: requested range invalid; we may already have all the data.\\n\");\n-\t} else if (obj_req->curl_result != CURLE_OK) {\n-\t\tif (stat(obj_req->tmpfile, &st) == 0)\n-\t\t\tif (st.st_size == 0)\n-\t\t\t\tunlink_or_warn(obj_req->tmpfile);\n+\tif (finish_http_object_request(obj_req->req))\n \t\treturn;\n-\t}\n-\n-\tgit_inflate_end(&obj_req->stream);\n-\tgit_SHA1_Final(obj_req->real_sha1, &obj_req->c);\n-\tif (obj_req->zret != Z_STREAM_END) {\n-\t\tunlink_or_warn(obj_req->tmpfile);\n-\t\treturn;\n-\t}\n-\tif (hashcmp(obj_req->sha1, obj_req->real_sha1)) {\n-\t\tunlink_or_warn(obj_req->tmpfile);\n-\t\treturn;\n-\t}\n-\tobj_req->rename =\n-\t\tmove_temp_to_file(obj_req->tmpfile, obj_req->filename);\n\n-\tif (obj_req->rename == 0)\n+\tif (obj_req->req->rename == 0)\n \t\twalker_say(obj_req->walker, \"got %s\\n\", sha1_to_hex(obj_req->sha1));\n }\n\n@@ -271,19 +92,16 @@ static void process_object_response(void *callback_data)\n \tstruct walker_data *data = walker->data;\n \tstruct alt_base *alt = data->alt;\n\n-\tobj_req->curl_result = obj_req->slot->curl_result;\n-\tobj_req->http_code = obj_req->slot->http_code;\n-\tobj_req->slot = NULL;\n+\tprocess_http_object_request(obj_req->req);\n \tobj_req->state = COMPLETE;\n\n \t/* Use alternates if necessary */\n-\tif (missing_target(obj_req)) {\n+\tif (missing_target(obj_req->req)) {\n \t\tfetch_alternates(walker, alt->base);\n \t\tif (obj_req->repo->next != NULL) {\n \t\t\tobj_req->repo =\n \t\t\t\tobj_req->repo->next;\n-\t\t\tclose(obj_req->local);\n-\t\t\tobj_req->local = -1;\n+\t\t\trelease_http_object_request(obj_req->req);\n \t\t\tstart_object_request(walker, obj_req);\n \t\t\treturn;\n \t\t}\n@@ -296,8 +114,8 @@ static void release_object_request(struct object_request *obj_req)\n {\n \tstruct object_request *entry = object_queue_head;\n\n-\tif (obj_req->local != -1)\n-\t\terror(\"fd leakage in release: %d\", obj_req->local);\n+\tif (obj_req->req !=NULL && obj_req->req->localfile != -1)\n+\t\terror(\"fd leakage in release: %d\", obj_req->req->localfile);\n \tif (obj_req == object_queue_head) {\n \t\tobject_queue_head = obj_req->next;\n \t} else {\n@@ -307,7 +125,6 @@ static void release_object_request(struct object_request *obj_req)\n \t\t\tentry->next = entry->next->next;\n \t}\n\n-\tfree(obj_req->url);\n \tfree(obj_req);\n }\n\n@@ -335,19 +152,13 @@ static void prefetch(struct walker *walker, unsigned char *sha1)\n \tstruct object_request *newreq;\n \tstruct object_request *tail;\n \tstruct walker_data *data = walker->data;\n-\tchar *filename = sha1_file_name(sha1);\n\n \tnewreq = xmalloc(sizeof(*newreq));\n \tnewreq->walker = walker;\n \thashcpy(newreq->sha1, sha1);\n \tnewreq->repo = data->alt;\n-\tnewreq->url = NULL;\n-\tnewreq->local = -1;\n \tnewreq->state = WAITING;\n-\tsnprintf(newreq->filename, sizeof(newreq->filename), \"%s\", filename);\n-\tsnprintf(newreq->tmpfile, sizeof(newreq->tmpfile),\n-\t\t \"%s.temp\", filename);\n-\tnewreq->slot = NULL;\n+\tnewreq->req = NULL;\n \tnewreq->next = NULL;\n\n \thttp_is_verbose = walker->get_verbosely;\n@@ -638,15 +449,6 @@ abort:\n\n static void abort_object_request(struct object_request *obj_req)\n {\n-\tif (obj_req->local >= 0) {\n-\t\tclose(obj_req->local);\n-\t\tobj_req->local = -1;\n-\t}\n-\tunlink_or_warn(obj_req->tmpfile);\n-\tif (obj_req->slot) {\n-\t\trelease_active_slot(obj_req->slot);\n-\t\tobj_req->slot = NULL;\n-\t}\n \trelease_object_request(obj_req);\n }\n\n@@ -655,6 +457,7 @@ static int fetch_object(struct walker *walker, struct alt_base *repo, unsigned c\n \tchar *hex = sha1_to_hex(sha1);\n \tint ret = 0;\n \tstruct object_request *obj_req = object_queue_head;\n+\tstruct http_object_request *req;\n\n \twhile (obj_req != NULL && hashcmp(obj_req->sha1, sha1))\n \t\tobj_req = obj_req->next;\n@@ -662,6 +465,8 @@ static int fetch_object(struct walker *walker, struct alt_base *repo, unsigned c\n \t\treturn error(\"Couldn't find request for %s in the queue\", hex);\n\n \tif (has_sha1_file(obj_req->sha1)) {\n+\t\tif (obj_req->req != NULL)\n+\t\t\tabort_http_object_request(obj_req->req);\n \t\tabort_object_request(obj_req);\n \t\treturn 0;\n \t}\n@@ -673,34 +478,42 @@ static int fetch_object(struct walker *walker, struct alt_base *repo, unsigned c\n \tstart_object_request(walker, obj_req);\n #endif\n\n+\t/*\n+\t * obj_req->req might change when fetching alternates in the callback\n+\t * process_object_response; therefore, the \"shortcut\" variable, req,\n+\t * is used only after we're done with slots.\n+\t */\n \twhile (obj_req->state == ACTIVE)\n-\t\trun_active_slot(obj_req->slot);\n+\t\trun_active_slot(obj_req->req->slot);\n+\n+\treq = obj_req->req;\n\n-\tif (obj_req->local != -1) {\n-\t\tclose(obj_req->local);\n-\t\tobj_req->local = -1;\n+\tif (req->localfile != -1) {\n+\t\tclose(req->localfile);\n+\t\treq->localfile = -1;\n \t}\n\n \tif (obj_req->state == ABORTED) {\n \t\tret = error(\"Request for %s aborted\", hex);\n-\t} else if (obj_req->curl_result != CURLE_OK &&\n-\t\t   obj_req->http_code != 416) {\n-\t\tif (missing_target(obj_req))\n+\t} else if (req->curl_result != CURLE_OK &&\n+\t\t   req->http_code != 416) {\n+\t\tif (missing_target(req))\n \t\t\tret = -1; /* Be silent, it is probably in a pack. */\n \t\telse\n \t\t\tret = error(\"%s (curl_result = %d, http_code = %ld, sha1 = %s)\",\n-\t\t\t\t    obj_req->errorstr, obj_req->curl_result,\n-\t\t\t\t    obj_req->http_code, hex);\n-\t} else if (obj_req->zret != Z_STREAM_END) {\n+\t\t\t\t    req->errorstr, req->curl_result,\n+\t\t\t\t    req->http_code, hex);\n+\t} else if (req->zret != Z_STREAM_END) {\n \t\twalker->corrupt_object_found++;\n-\t\tret = error(\"File %s (%s) corrupt\", hex, obj_req->url);\n-\t} else if (hashcmp(obj_req->sha1, obj_req->real_sha1)) {\n+\t\tret = error(\"File %s (%s) corrupt\", hex, req->url);\n+\t} else if (hashcmp(obj_req->sha1, req->real_sha1)) {\n \t\tret = error(\"File %s has bad hash\", hex);\n-\t} else if (obj_req->rename < 0) {\n+\t} else if (req->rename < 0) {\n \t\tret = error(\"unable to write sha1 filename %s\",\n-\t\t\t    obj_req->filename);\n+\t\t\t    req->filename);\n \t}\n\n+\trelease_http_object_request(req);\n \trelease_object_request(obj_req);\n \treturn ret;\n }\ndiff --git a/http.c b/http.c\nindex 3815934..95b2137 100644\n--- a/http.c\n+++ b/http.c\n@@ -12,6 +12,10 @@ static CURLM *curlm;\n #ifndef NO_CURL_EASY_DUPHANDLE\n static CURL *curl_default;\n #endif\n+\n+#define PREV_BUF_SIZE 4096\n+#define RANGE_HEADER_SIZE 30\n+\n char curl_errorstr[CURL_ERROR_SIZE];\n\n static int curl_ssl_verify = -1;\n@@ -30,8 +34,7 @@ static const char *curl_http_proxy;\n static char *user_name, *user_pass;\n\n static struct curl_slist *pragma_header;\n-\n-struct curl_slist *no_pragma_header;\n+static struct curl_slist *no_pragma_header;\n\n static struct active_request_slot *active_queue_head;\n\n@@ -666,6 +669,23 @@ static char *quote_ref_url(const char *base, const char *ref)\n \treturn strbuf_detach(&buf, NULL);\n }\n\n+void append_remote_object_url(struct strbuf *buf, const char *url,\n+\t\t\t      const char *hex,\n+\t\t\t      int only_two_digit_prefix)\n+{\n+\tstrbuf_addf(buf, \"%s/objects/%.*s/\", url, 2, hex);\n+\tif (!only_two_digit_prefix)\n+\t\tstrbuf_addf(buf, \"%s\", hex+2);\n+}\n+\n+char *get_remote_object_url(const char *url, const char *hex,\n+\t\t\t    int only_two_digit_prefix)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tappend_remote_object_url(&buf, url, hex, only_two_digit_prefix);\n+\treturn strbuf_detach(&buf, NULL);\n+}\n+\n /* http_request() targets */\n #define HTTP_REQUEST_STRBUF\t0\n #define HTTP_REQUEST_FILE\t1\n@@ -995,3 +1015,229 @@ abort:\n \tfree(filename);\n \treturn NULL;\n }\n+\n+/* Helpers for fetching objects (loose) */\n+static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,\n+\t\t\t       void *data)\n+{\n+\tunsigned char expn[4096];\n+\tsize_t size = eltsize * nmemb;\n+\tint posn = 0;\n+\tstruct http_object_request *freq =\n+\t\t(struct http_object_request *)data;\n+\tdo {\n+\t\tssize_t retval = xwrite(freq->localfile,\n+\t\t\t\t\t(char *) ptr + posn, size - posn);\n+\t\tif (retval < 0)\n+\t\t\treturn posn;\n+\t\tposn += retval;\n+\t} while (posn < size);\n+\n+\tfreq->stream.avail_in = size;\n+\tfreq->stream.next_in = ptr;\n+\tdo {\n+\t\tfreq->stream.next_out = expn;\n+\t\tfreq->stream.avail_out = sizeof(expn);\n+\t\tfreq->zret = git_inflate(&freq->stream, Z_SYNC_FLUSH);\n+\t\tgit_SHA1_Update(&freq->c, expn,\n+\t\t\t\tsizeof(expn) - freq->stream.avail_out);\n+\t} while (freq->stream.avail_in && freq->zret == Z_OK);\n+\tdata_received++;\n+\treturn size;\n+}\n+\n+struct http_object_request *new_http_object_request(const char *base_url,\n+\tunsigned char *sha1)\n+{\n+\tchar *hex = sha1_to_hex(sha1);\n+\tchar *filename;\n+\tchar prevfile[PATH_MAX];\n+\tchar *url;\n+\tint prevlocal;\n+\tunsigned char prev_buf[PREV_BUF_SIZE];\n+\tssize_t prev_read = 0;\n+\tlong prev_posn = 0;\n+\tchar range[RANGE_HEADER_SIZE];\n+\tstruct curl_slist *range_header = NULL;\n+\tstruct http_object_request *freq;\n+\n+\tfreq = xmalloc(sizeof(*freq));\n+\thashcpy(freq->sha1, sha1);\n+\tfreq->localfile = -1;\n+\n+\tfilename = sha1_file_name(sha1);\n+\tsnprintf(freq->filename, sizeof(freq->filename), \"%s\", filename);\n+\tsnprintf(freq->tmpfile, sizeof(freq->tmpfile),\n+\t\t \"%s.temp\", filename);\n+\n+\tsnprintf(prevfile, sizeof(prevfile), \"%s.prev\", filename);\n+\tunlink_or_warn(prevfile);\n+\trename(freq->tmpfile, prevfile);\n+\tunlink_or_warn(freq->tmpfile);\n+\n+\tif (freq->localfile != -1)\n+\t\terror(\"fd leakage in start: %d\", freq->localfile);\n+\tfreq->localfile = open(freq->tmpfile,\n+\t\t\t       O_WRONLY | O_CREAT | O_EXCL, 0666);\n+\t/*\n+\t * This could have failed due to the \"lazy directory creation\";\n+\t * try to mkdir the last path component.\n+\t */\n+\tif (freq->localfile < 0 && errno == ENOENT) {\n+\t\tchar *dir = strrchr(freq->tmpfile, '/');\n+\t\tif (dir) {\n+\t\t\t*dir = 0;\n+\t\t\tmkdir(freq->tmpfile, 0777);\n+\t\t\t*dir = '/';\n+\t\t}\n+\t\tfreq->localfile = open(freq->tmpfile,\n+\t\t\t\t       O_WRONLY | O_CREAT | O_EXCL, 0666);\n+\t}\n+\n+\tif (freq->localfile < 0) {\n+\t\terror(\"Couldn't create temporary file %s for %s: %s\",\n+\t\t      freq->tmpfile, freq->filename, strerror(errno));\n+\t\tgoto abort;\n+\t}\n+\n+\tmemset(&freq->stream, 0, sizeof(freq->stream));\n+\n+\tgit_inflate_init(&freq->stream);\n+\n+\tgit_SHA1_Init(&freq->c);\n+\n+\turl = get_remote_object_url(base_url, hex, 0);\n+\tfreq->url = xstrdup(url);\n+\n+\t/*\n+\t * If a previous temp file is present, process what was already\n+\t * fetched.\n+\t */\n+\tprevlocal = open(prevfile, O_RDONLY);\n+\tif (prevlocal != -1) {\n+\t\tdo {\n+\t\t\tprev_read = xread(prevlocal, prev_buf, PREV_BUF_SIZE);\n+\t\t\tif (prev_read>0) {\n+\t\t\t\tif (fwrite_sha1_file(prev_buf,\n+\t\t\t\t\t\t     1,\n+\t\t\t\t\t\t     prev_read,\n+\t\t\t\t\t\t     freq) == prev_read) {\n+\t\t\t\t\tprev_posn += prev_read;\n+\t\t\t\t} else {\n+\t\t\t\t\tprev_read = -1;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t} while (prev_read > 0);\n+\t\tclose(prevlocal);\n+\t}\n+\tunlink_or_warn(prevfile);\n+\n+\t/*\n+\t * Reset inflate/SHA1 if there was an error reading the previous temp\n+\t * file; also rewind to the beginning of the local file.\n+\t */\n+\tif (prev_read == -1) {\n+\t\tmemset(&freq->stream, 0, sizeof(freq->stream));\n+\t\tgit_inflate_init(&freq->stream);\n+\t\tgit_SHA1_Init(&freq->c);\n+\t\tif (prev_posn>0) {\n+\t\t\tprev_posn = 0;\n+\t\t\tlseek(freq->localfile, 0, SEEK_SET);\n+\t\t\tftruncate(freq->localfile, 0);\n+\t\t}\n+\t}\n+\n+\tfreq->slot = get_active_slot();\n+\n+\tcurl_easy_setopt(freq->slot->curl, CURLOPT_FILE, freq);\n+\tcurl_easy_setopt(freq->slot->curl, CURLOPT_WRITEFUNCTION, fwrite_sha1_file);\n+\tcurl_easy_setopt(freq->slot->curl, CURLOPT_ERRORBUFFER, freq->errorstr);\n+\tcurl_easy_setopt(freq->slot->curl, CURLOPT_URL, url);\n+\tcurl_easy_setopt(freq->slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);\n+\n+\t/*\n+\t * If we have successfully processed data from a previous fetch\n+\t * attempt, only fetch the data we don't already have.\n+\t */\n+\tif (prev_posn>0) {\n+\t\tif (http_is_verbose)\n+\t\t\tfprintf(stderr,\n+\t\t\t\t\"Resuming fetch of object %s at byte %ld\\n\",\n+\t\t\t\thex, prev_posn);\n+\t\tsprintf(range, \"Range: bytes=%ld-\", prev_posn);\n+\t\trange_header = curl_slist_append(range_header, range);\n+\t\tcurl_easy_setopt(freq->slot->curl,\n+\t\t\t\t CURLOPT_HTTPHEADER, range_header);\n+\t}\n+\n+\treturn freq;\n+\n+\tfree(url);\n+abort:\n+\tfree(filename);\n+\tfree(freq);\n+\treturn NULL;\n+}\n+\n+void process_http_object_request(struct http_object_request *freq)\n+{\n+\tif (freq->slot == NULL)\n+\t\treturn;\n+\tfreq->curl_result = freq->slot->curl_result;\n+\tfreq->http_code = freq->slot->http_code;\n+\tfreq->slot = NULL;\n+}\n+\n+int finish_http_object_request(struct http_object_request *freq)\n+{\n+\tstruct stat st;\n+\n+\tclose(freq->localfile);\n+\tfreq->localfile = -1;\n+\n+\tprocess_http_object_request(freq);\n+\n+\tif (freq->http_code == 416) {\n+\t\tfprintf(stderr, \"Warning: requested range invalid; we may already have all the data.\\n\");\n+\t} else if (freq->curl_result != CURLE_OK) {\n+\t\tif (stat(freq->tmpfile, &st) == 0)\n+\t\t\tif (st.st_size == 0)\n+\t\t\t\tunlink_or_warn(freq->tmpfile);\n+\t\treturn -1;\n+\t}\n+\n+\tgit_inflate_end(&freq->stream);\n+\tgit_SHA1_Final(freq->real_sha1, &freq->c);\n+\tif (freq->zret != Z_STREAM_END) {\n+\t\tunlink_or_warn(freq->tmpfile);\n+\t\treturn -1;\n+\t}\n+\tif (hashcmp(freq->sha1, freq->real_sha1)) {\n+\t\tunlink_or_warn(freq->tmpfile);\n+\t\treturn -1;\n+\t}\n+\tfreq->rename =\n+\t\tmove_temp_to_file(freq->tmpfile, freq->filename);\n+\n+\treturn freq->rename;\n+}\n+\n+void abort_http_object_request(struct http_object_request *freq)\n+{\n+\tunlink_or_warn(freq->tmpfile);\n+\n+\trelease_http_object_request(freq);\n+}\n+\n+void release_http_object_request(struct http_object_request *freq)\n+{\n+\tif (freq->localfile != -1) {\n+\t\tclose(freq->localfile);\n+\t\tfreq->localfile = -1;\n+\t}\n+\tif (freq->url != NULL) {\n+\t\tfree(freq->url);\n+\t\tfreq->url = NULL;\n+\t}\n+\tfreq->slot = NULL;\n+}\ndiff --git a/http.h b/http.h\nindex 511c0c4..4c4e99c 100644\n--- a/http.h\n+++ b/http.h\n@@ -88,10 +88,6 @@ extern void add_fill_function(void *data, int (*fill)(void *));\n extern void step_active_slots(void);\n #endif\n\n-extern struct curl_slist *no_pragma_header;\n-\n-#define RANGE_HEADER_SIZE 30\n-\n extern void http_init(struct remote *remote);\n extern void http_cleanup(void);\n\n@@ -114,6 +110,13 @@ static inline int missing__target(int code, int result)\n\n #define missing_target(a) missing__target((a)->http_code, (a)->curl_result)\n\n+/* Helpers for modifying and creating URLs */\n+extern void append_remote_object_url(struct strbuf *buf, const char *url,\n+\t\t\t\t     const char *hex,\n+\t\t\t\t     int only_two_digit_prefix);\n+extern char *get_remote_object_url(const char *url, const char *hex,\n+\t\t\t\t   int only_two_digit_prefix);\n+\n /* Options for http_request_*() */\n #define HTTP_NO_CACHE\t\t1\n\n@@ -167,4 +170,30 @@ extern struct http_pack_request *new_http_pack_request(\n extern int finish_http_pack_request(struct http_pack_request *preq);\n extern void release_http_pack_request(struct http_pack_request *preq);\n\n+/* Helpers for fetching object */\n+struct http_object_request\n+{\n+\tchar *url;\n+\tchar filename[PATH_MAX];\n+\tchar tmpfile[PATH_MAX];\n+\tint localfile;\n+\tCURLcode curl_result;\n+\tchar errorstr[CURL_ERROR_SIZE];\n+\tlong http_code;\n+\tunsigned char sha1[20];\n+\tunsigned char real_sha1[20];\n+\tgit_SHA_CTX c;\n+\tz_stream stream;\n+\tint zret;\n+\tint rename;\n+\tstruct active_request_slot *slot;\n+};\n+\n+extern struct http_object_request *new_http_object_request(\n+\tconst char *base_url, unsigned char *sha1);\n+extern void process_http_object_request(struct http_object_request *freq);\n+extern int finish_http_object_request(struct http_object_request *freq);\n+extern void abort_http_object_request(struct http_object_request *freq);\n+extern void release_http_object_request(struct http_object_request *freq);\n+\n #endif /* HTTP_H */\n--\n1.6.3.1\n"}]}