http: avoid disconnecting on 404s for loose objects
[gitweb.git] / http-walker.c
index 88da5468e77f5a543edb7583e2846f19eb509653..48f2df4d31e7248bdfde0a48db007cad30175c16 100644 (file)
@@ -29,7 +29,7 @@ struct object_request {
 struct alternates_request {
        struct walker *walker;
        const char *base;
-       char *url;
+       struct strbuf *url;
        struct strbuf *buffer;
        struct active_request_slot *slot;
        int http_specific;
@@ -195,10 +195,11 @@ static void process_alternates_response(void *callback_data)
 
                        /* Try reusing the slot to get non-http alternates */
                        alt_req->http_specific = 0;
-                       sprintf(alt_req->url, "%s/objects/info/alternates",
-                               base);
+                       strbuf_reset(alt_req->url);
+                       strbuf_addf(alt_req->url, "%s/objects/info/alternates",
+                                   base);
                        curl_easy_setopt(slot->curl, CURLOPT_URL,
-                                        alt_req->url);
+                                        alt_req->url->buf);
                        active_requests++;
                        slot->in_use = 1;
                        if (slot->finished != NULL)
@@ -312,7 +313,7 @@ static void process_alternates_response(void *callback_data)
 static void fetch_alternates(struct walker *walker, const char *base)
 {
        struct strbuf buffer = STRBUF_INIT;
-       char *url;
+       struct strbuf url = STRBUF_INIT;
        struct active_request_slot *slot;
        struct alternates_request alt_req;
        struct walker_data *cdata = walker->data;
@@ -338,7 +339,7 @@ static void fetch_alternates(struct walker *walker, const char *base)
        if (walker->get_verbosely)
                fprintf(stderr, "Getting alternates list for %s\n", base);
 
-       url = xstrfmt("%s/objects/info/http-alternates", base);
+       strbuf_addf(&url, "%s/objects/info/http-alternates", base);
 
        /*
         * Use a callback to process the result, since another request
@@ -351,10 +352,10 @@ static void fetch_alternates(struct walker *walker, const char *base)
 
        curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
-       curl_easy_setopt(slot->curl, CURLOPT_URL, url);
+       curl_easy_setopt(slot->curl, CURLOPT_URL, url.buf);
 
        alt_req.base = base;
-       alt_req.url = url;
+       alt_req.url = &url;
        alt_req.buffer = &buffer;
        alt_req.http_specific = 1;
        alt_req.slot = slot;
@@ -365,7 +366,7 @@ static void fetch_alternates(struct walker *walker, const char *base)
                cdata->got_alternates = -1;
 
        strbuf_release(&buffer);
-       free(url);
+       strbuf_release(&url);
 }
 
 static int fetch_indices(struct walker *walker, struct alt_base *repo)
@@ -446,7 +447,7 @@ static void abort_object_request(struct object_request *obj_req)
        release_object_request(obj_req);
 }
 
-static int fetch_object(struct walker *walker, struct alt_base *repo, unsigned char *sha1)
+static int fetch_object(struct walker *walker, unsigned char *sha1)
 {
        char *hex = sha1_to_hex(sha1);
        int ret = 0;
@@ -487,6 +488,15 @@ static int fetch_object(struct walker *walker, struct alt_base *repo, unsigned c
                req->localfile = -1;
        }
 
+       /*
+        * we turned off CURLOPT_FAILONERROR to avoid losing a
+        * persistent connection and got CURLE_OK.
+        */
+       if (req->http_code == 404 && req->curl_result == CURLE_OK &&
+                       (starts_with(req->url, "http://") ||
+                        starts_with(req->url, "https://")))
+               req->curl_result = CURLE_HTTP_RETURNED_ERROR;
+
        if (obj_req->state == ABORTED) {
                ret = error("Request for %s aborted", hex);
        } else if (req->curl_result != CURLE_OK &&
@@ -517,7 +527,7 @@ static int fetch(struct walker *walker, unsigned char *sha1)
        struct walker_data *data = walker->data;
        struct alt_base *altbase = data->alt;
 
-       if (!fetch_object(walker, altbase, sha1))
+       if (!fetch_object(walker, sha1))
                return 0;
        while (altbase) {
                if (!http_fetch_pack(walker, altbase, sha1))