#include "pack.h"
#include "sideband.h"
#include "run-command.h"
+#include "url.h"
int data_received;
int active_requests;
static int curl_ftp_no_epsv;
static const char *curl_http_proxy;
static char *user_name, *user_pass;
+static const char *user_agent;
#if LIBCURL_VERSION_NUM >= 0x071700
/* Use CURLOPT_KEYPASSWD as is */
return 0;
}
+ if (!strcmp("http.useragent", var))
+ return git_config_string(&user_agent, var, value);
+
/* Fall back on the default ones */
return git_default_config(var, value, cb);
}
}
curl_easy_setopt(result, CURLOPT_FOLLOWLOCATION, 1);
+#if LIBCURL_VERSION_NUM >= 0x071301
+ curl_easy_setopt(result, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL);
+#elif LIBCURL_VERSION_NUM >= 0x071101
+ curl_easy_setopt(result, CURLOPT_POST301, 1);
+#endif
if (getenv("GIT_CURL_VERBOSE"))
curl_easy_setopt(result, CURLOPT_VERBOSE, 1);
- curl_easy_setopt(result, CURLOPT_USERAGENT, GIT_USER_AGENT);
+ curl_easy_setopt(result, CURLOPT_USERAGENT,
+ user_agent ? user_agent : GIT_HTTP_USER_AGENT);
if (curl_ftp_no_epsv)
curl_easy_setopt(result, CURLOPT_FTP_USE_EPSV, 0);
static void http_auth_init(const char *url)
{
- char *at, *colon, *cp, *slash;
+ char *at, *colon, *cp, *slash, *decoded;
int len;
cp = strstr(url, "://");
user_name = xmalloc(len + 1);
memcpy(user_name, cp, len);
user_name[len] = '\0';
+ decoded = url_decode(user_name);
+ free(user_name);
+ user_name = decoded;
user_pass = NULL;
} else {
len = colon - cp;
user_name = xmalloc(len + 1);
memcpy(user_name, cp, len);
user_name[len] = '\0';
+ decoded = url_decode(user_name);
+ free(user_name);
+ user_name = decoded;
len = at - (colon + 1);
user_pass = xmalloc(len + 1);
memcpy(user_pass, colon + 1, len);
user_pass[len] = '\0';
+ decoded = url_decode(user_pass);
+ free(user_pass);
+ user_pass = decoded;
}
}
#endif
set_from_env(&ssl_cainfo, "GIT_SSL_CAINFO");
+ set_from_env(&user_agent, "GIT_HTTP_USER_AGENT");
+
low_speed_limit = getenv("GIT_HTTP_LOW_SPEED_LIMIT");
if (low_speed_limit != NULL)
curl_low_speed_limit = strtol(low_speed_limit, NULL, 10);
curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, NULL);
curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, NULL);
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, NULL);
+ curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, NULL);
curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 0);
curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
return 'A' + v - 10;
}
-void end_url_with_slash(struct strbuf *buf, const char *url)
-{
- strbuf_addstr(buf, url);
- if (buf->len && buf->buf[buf->len - 1] != '/')
- strbuf_addstr(buf, "/");
-}
-
static char *quote_ref_url(const char *base, const char *ref)
{
struct strbuf buf = STRBUF_INIT;
ret = HTTP_OK;
else if (missing_target(&results))
ret = HTTP_MISSING_TARGET;
- else
+ else if (results.http_code == 401) {
+ if (user_name) {
+ ret = HTTP_NOAUTH;
+ } else {
+ /*
+ * git_getpass is needed here because its very likely stdin/stdout are
+ * pipes to our parent process. So we instead need to use /dev/tty,
+ * but that is non-portable. Using git_getpass() can at least be stubbed
+ * on other platforms with a different implementation if/when necessary.
+ */
+ user_name = xstrdup(git_getpass("Username: "));
+ init_curl_http_auth(slot->curl);
+ ret = HTTP_REAUTH;
+ }
+ } else
ret = HTTP_ERROR;
} else {
error("Unable to start HTTP request for %s", url);
int http_get_strbuf(const char *url, struct strbuf *result, int options)
{
- return http_request(url, result, HTTP_REQUEST_STRBUF, options);
+ int http_ret = http_request(url, result, HTTP_REQUEST_STRBUF, options);
+ if (http_ret == HTTP_REAUTH) {
+ http_ret = http_request(url, result, HTTP_REQUEST_STRBUF, options);
+ }
+ return http_ret;
}
/*