Merge branch 'kb/co-orphan-suggestion-short-sha1'
[gitweb.git] / http.c
diff --git a/http.c b/http.c
index 8803c70825ac8aefb619b6c56d6015573eb5d227..48d4ff61c757f93d8385ca014ab14bb233acbb40 100644 (file)
--- a/http.c
+++ b/http.c
@@ -282,7 +282,6 @@ static CURL *get_curl_handle(void)
 #endif
        if (ssl_cainfo != NULL)
                curl_easy_setopt(result, CURLOPT_CAINFO, ssl_cainfo);
-       curl_easy_setopt(result, CURLOPT_FAILONERROR, 1);
 
        if (curl_low_speed_limit > 0 && curl_low_speed_time > 0) {
                curl_easy_setopt(result, CURLOPT_LOW_SPEED_LIMIT,
@@ -506,6 +505,7 @@ struct active_request_slot *get_active_slot(void)
        curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, NULL);
        curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 0);
        curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
+       curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 1);
        if (http_auth.password)
                init_curl_http_auth(slot->curl);
 
@@ -761,6 +761,25 @@ char *get_remote_object_url(const char *url, const char *hex,
 
 int handle_curl_result(struct slot_results *results)
 {
+       /*
+        * If we see a failing http code with CURLE_OK, we have turned off
+        * FAILONERROR (to keep the server's custom error response), and should
+        * translate the code into failure here.
+        */
+       if (results->curl_result == CURLE_OK &&
+           results->http_code >= 400) {
+               results->curl_result = CURLE_HTTP_RETURNED_ERROR;
+               /*
+                * Normally curl will already have put the "reason phrase"
+                * from the server into curl_errorstr; unfortunately without
+                * FAILONERROR it is lost, so we can give only the numeric
+                * status code.
+                */
+               snprintf(curl_errorstr, sizeof(curl_errorstr),
+                        "The requested URL returned error: %ld",
+                        results->http_code);
+       }
+
        if (results->curl_result == CURLE_OK) {
                credential_approve(&http_auth);
                return HTTP_OK;
@@ -825,6 +844,8 @@ static int http_request(const char *url, struct strbuf *type,
        strbuf_addstr(&buf, "Pragma:");
        if (options & HTTP_NO_CACHE)
                strbuf_addstr(&buf, " no-cache");
+       if (options & HTTP_KEEP_ERROR)
+               curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 0);
 
        headers = curl_slist_append(headers, buf.buf);
 
@@ -836,7 +857,8 @@ static int http_request(const char *url, struct strbuf *type,
                run_active_slot(slot);
                ret = handle_curl_result(&results);
        } else {
-               error("Unable to start HTTP request for %s", url);
+               snprintf(curl_errorstr, sizeof(curl_errorstr),
+                        "failed to start HTTP request");
                ret = HTTP_START_FAILED;
        }
 
@@ -862,6 +884,22 @@ static int http_request_reauth(const char *url,
        int ret = http_request(url, type, result, target, options);
        if (ret != HTTP_REAUTH)
                return ret;
+
+       /*
+        * If we are using KEEP_ERROR, the previous request may have
+        * put cruft into our output stream; we should clear it out before
+        * making our next request. We only know how to do this for
+        * the strbuf case, but that is enough to satisfy current callers.
+        */
+       if (options & HTTP_KEEP_ERROR) {
+               switch (target) {
+               case HTTP_REQUEST_STRBUF:
+                       strbuf_reset(result);
+                       break;
+               default:
+                       die("BUG: HTTP_KEEP_ERROR is only supported with strbufs");
+               }
+       }
        return http_request(url, type, result, target, options);
 }
 
@@ -903,15 +941,6 @@ static int http_get_file(const char *url, const char *filename, int options)
        return ret;
 }
 
-int http_error(const char *url, int ret)
-{
-       /* http_request has already handled HTTP_START_FAILED. */
-       if (ret != HTTP_START_FAILED)
-               error("%s while accessing %s", curl_errorstr, url);
-
-       return ret;
-}
-
 int http_fetch_ref(const char *base, struct ref *ref)
 {
        char *url;