log_ref_setup(): improve robustness against races
[gitweb.git] / http-walker.c
index 0b2425531a8120fb29f37ee473a1e6e974959605..b34b6ace7cd80a482eae16e2063aa9d8960e8729 100644 (file)
@@ -3,6 +3,7 @@
 #include "walker.h"
 #include "http.h"
 #include "list.h"
+#include "transport.h"
 
 struct alt_base {
        char *base;
@@ -160,6 +161,32 @@ static void prefetch(struct walker *walker, unsigned char *sha1)
 #endif
 }
 
+static int is_alternate_allowed(const char *url)
+{
+       const char *protocols[] = {
+               "http", "https", "ftp", "ftps"
+       };
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(protocols); i++) {
+               const char *end;
+               if (skip_prefix(url, protocols[i], &end) &&
+                   starts_with(end, "://"))
+                       break;
+       }
+
+       if (i >= ARRAY_SIZE(protocols)) {
+               warning("ignoring alternate with unknown protocol: %s", url);
+               return 0;
+       }
+       if (!is_transport_allowed(protocols[i], 0)) {
+               warning("ignoring alternate with restricted protocol: %s", url);
+               return 0;
+       }
+
+       return 1;
+}
+
 static void process_alternates_response(void *callback_data)
 {
        struct alternates_request *alt_req =
@@ -274,18 +301,20 @@ static void process_alternates_response(void *callback_data)
                                struct strbuf target = STRBUF_INIT;
                                strbuf_add(&target, base, serverlen);
                                strbuf_add(&target, data + i, posn - i - 7);
-                               if (walker->get_verbosely)
-                                       fprintf(stderr, "Also look at %s\n",
+
+                               if (is_alternate_allowed(target.buf)) {
+                                       warning("adding alternate object store: %s",
                                                target.buf);
-                               newalt = xmalloc(sizeof(*newalt));
-                               newalt->next = NULL;
-                               newalt->base = strbuf_detach(&target, NULL);
-                               newalt->got_indices = 0;
-                               newalt->packs = NULL;
-
-                               while (tail->next != NULL)
-                                       tail = tail->next;
-                               tail->next = newalt;
+                                       newalt = xmalloc(sizeof(*newalt));
+                                       newalt->next = NULL;
+                                       newalt->base = strbuf_detach(&target, NULL);
+                                       newalt->got_indices = 0;
+                                       newalt->packs = NULL;
+
+                                       while (tail->next != NULL)
+                                               tail = tail->next;
+                                       tail->next = newalt;
+                               }
                        }
                }
                i = posn + 1;
@@ -302,6 +331,9 @@ static void fetch_alternates(struct walker *walker, const char *base)
        struct alternates_request alt_req;
        struct walker_data *cdata = walker->data;
 
+       if (http_follow_config != HTTP_FOLLOW_ALWAYS)
+               return;
+
        /*
         * If another request has already started fetching alternates,
         * wait for them to arrive and return to processing this request's
@@ -480,10 +512,13 @@ static int fetch_object(struct walker *walker, unsigned char *sha1)
         * 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 &&
+       if (req->http_code >= 300 && req->curl_result == CURLE_OK &&
                        (starts_with(req->url, "http://") ||
-                        starts_with(req->url, "https://")))
+                        starts_with(req->url, "https://"))) {
                req->curl_result = CURLE_HTTP_RETURNED_ERROR;
+               xsnprintf(req->errorstr, sizeof(req->errorstr),
+                         "HTTP request failed");
+       }
 
        if (obj_req->state == ABORTED) {
                ret = error("Request for %s aborted", hex);