char curl_errorstr[CURL_ERROR_SIZE];
static int curl_ssl_verify = -1;
+static int curl_ssl_try;
static const char *ssl_cert;
#if LIBCURL_VERSION_NUM >= 0x070903
static const char *ssl_key;
ssl_cert_password_required = 1;
return 0;
}
+ if (!strcmp("http.ssltry", var)) {
+ curl_ssl_try = git_config_bool(var, value);
+ return 0;
+ }
if (!strcmp("http.minsessions", var)) {
min_curl_sessions = git_config_int(var, value);
#ifndef USE_CURL_MULTI
#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,
if (curl_ftp_no_epsv)
curl_easy_setopt(result, CURLOPT_FTP_USE_EPSV, 0);
+#ifdef CURLOPT_USE_SSL
+ if (curl_ssl_try)
+ curl_easy_setopt(result, CURLOPT_USE_SSL, CURLUSESSL_TRY);
+#endif
+
if (curl_http_proxy) {
curl_easy_setopt(result, CURLOPT_PROXY, curl_http_proxy);
curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
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);
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;
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);
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;
}
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);
}
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;