@ -111,6 +111,8 @@ static int http_proactive_auth;
@@ -111,6 +111,8 @@ static int http_proactive_auth;
static const char *user_agent;
static int curl_empty_auth;
enum http_follow_config http_follow_config = HTTP_FOLLOW_INITIAL;
#if LIBCURL_VERSION_NUM >= 0x071700
/* Use CURLOPT_KEYPASSWD as is */
#elif LIBCURL_VERSION_NUM >= 0x070903
@ -366,6 +368,16 @@ static int http_options(const char *var, const char *value, void *cb)
@@ -366,6 +368,16 @@ static int http_options(const char *var, const char *value, void *cb)
return 0;
}
if (!strcmp("http.followredirects", var)) {
if (value && !strcmp(value, "initial"))
http_follow_config = HTTP_FOLLOW_INITIAL;
else if (git_config_bool(var, value))
http_follow_config = HTTP_FOLLOW_ALWAYS;
else
http_follow_config = HTTP_FOLLOW_NONE;
return 0;
}
/* Fall back on the default ones */
return git_default_config(var, value, cb);
}
@ -717,7 +729,6 @@ static CURL *get_curl_handle(void)
@@ -717,7 +729,6 @@ static CURL *get_curl_handle(void)
curl_low_speed_time);
}
curl_easy_setopt(result, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(result, CURLOPT_MAXREDIRS, 20);
#if LIBCURL_VERSION_NUM >= 0x071301
curl_easy_setopt(result, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL);
@ -734,6 +745,7 @@ static CURL *get_curl_handle(void)
@@ -734,6 +745,7 @@ static CURL *get_curl_handle(void)
if (is_transport_allowed("ftps"))
allowed_protocols |= CURLPROTO_FTPS;
curl_easy_setopt(result, CURLOPT_REDIR_PROTOCOLS, allowed_protocols);
curl_easy_setopt(result, CURLOPT_PROTOCOLS, allowed_protocols);
#else
if (transport_restrict_protocols())
warning("protocol restrictions not applied to curl redirects because\n"
@ -1044,6 +1056,16 @@ struct active_request_slot *get_active_slot(void)
@@ -1044,6 +1056,16 @@ struct active_request_slot *get_active_slot(void)
curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 1);
curl_easy_setopt(slot->curl, CURLOPT_RANGE, NULL);
/*
* Default following to off unless "ALWAYS" is configured; this gives
* callers a sane starting point, and they can tweak for individual
* HTTP_FOLLOW_* cases themselves.
*/
if (http_follow_config == HTTP_FOLLOW_ALWAYS)
curl_easy_setopt(slot->curl, CURLOPT_FOLLOWLOCATION, 1);
else
curl_easy_setopt(slot->curl, CURLOPT_FOLLOWLOCATION, 0);
#if LIBCURL_VERSION_NUM >= 0x070a08
curl_easy_setopt(slot->curl, CURLOPT_IPRESOLVE, git_curl_ipresolve);
#endif
@ -1286,9 +1308,12 @@ static int handle_curl_result(struct slot_results *results)
@@ -1286,9 +1308,12 @@ static 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.
*
* Likewise, if we see a redirect (30x code), that means we turned off
* redirect-following, and we should treat the result as an error.
*/
if (results->curl_result == CURLE_OK &&
results->http_code >= 400) {
results->http_code >= 300) {
results->curl_result = CURLE_HTTP_RETURNED_ERROR;
/*
* Normally curl will already have put the "reason phrase"
@ -1607,6 +1632,9 @@ static int http_request(const char *url,
@@ -1607,6 +1632,9 @@ static int http_request(const char *url,
strbuf_addstr(&buf, " no-cache");
if (options && options->keep_error)
curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 0);
if (options && options->initial_request &&
http_follow_config == HTTP_FOLLOW_INITIAL)
curl_easy_setopt(slot->curl, CURLOPT_FOLLOWLOCATION, 1);
headers = curl_slist_append(headers, buf.buf);
@ -1655,16 +1683,16 @@ static int http_request(const char *url,
@@ -1655,16 +1683,16 @@ static int http_request(const char *url,
*
* Note that this assumes a sane redirect scheme. It's entirely possible
* in the example above to end up at a URL that does not even end in
* "info/refs". In such a case we simply punt, as there is not much we can
* do (and such a scheme is unlikely to represent a real git repository,
* which means we are likely about to abort anyway).
* "info/refs". In such a case we die. There's not much we can do, such a
* scheme is unlikely to represent a real git repository, and failing to
* rewrite the base opens options for malicious redirects to do funny things.
*/
static int update_url_from_redirect(struct strbuf *base,
const char *asked,
const struct strbuf *got)
{
const char *tail;
size_t tail_len;
size_t new_len;
if (!strcmp(asked, got->buf))
return 0;
@ -1673,14 +1701,16 @@ static int update_url_from_redirect(struct strbuf *base,
@@ -1673,14 +1701,16 @@ static int update_url_from_redirect(struct strbuf *base,
die("BUG: update_url_from_redirect: %s is not a superset of %s",
asked, base->buf);
tail_len = strlen(tail);
if (got->len < tail_len ||
strcmp(tail, got->buf + got->len - tail_len))
return 0; /* insane redirect scheme */
new_len = got->len;
if (!strip_suffix_mem(got->buf, &new_len, tail))
die(_("unable to update url base from redirection:\n"
" asked for: %s\n"
" redirect: %s"),
asked, got->buf);
strbuf_reset(base);
strbuf_add(base, got->buf, got->len - tail_len);
strbuf_add(base, got->buf, new_len);
return 1;
}
@ -2028,7 +2058,7 @@ static size_t fwrite_sha1_file(char *ptr, size_t eltsize, size_t nmemb,
@@ -2028,7 +2058,7 @@ static size_t fwrite_sha1_file(char *ptr, size_t eltsize, size_t nmemb,
if (c != CURLE_OK)
die("BUG: curl_easy_getinfo for HTTP code failed: %s",
curl_easy_strerror(c));
if (slot->http_code >= 400)
if (slot->http_code >= 300)
return size;
}