From: Junio C Hamano Date: Tue, 20 Dec 2011 00:05:59 +0000 (-0800) Subject: Merge branch 'jk/maint-push-over-dav' X-Git-Tag: v1.7.9-rc0~45 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/1d3a035d6d48bfa870b6ebe7c59f12b66e3a1b1c?ds=inline;hp=-c Merge branch 'jk/maint-push-over-dav' * jk/maint-push-over-dav: http-push: enable "proactive auth" t5540: test DAV push with authentication Conflicts: http.c --- 1d3a035d6d48bfa870b6ebe7c59f12b66e3a1b1c diff --combined http.c index 8e72664061,7e454f7787..0ffd79cd81 --- a/http.c +++ b/http.c @@@ -3,8 -3,8 +3,8 @@@ #include "sideband.h" #include "run-command.h" #include "url.h" +#include "credential.h" -int data_received; int active_requests; int http_is_verbose; size_t http_post_buffer = 16 * LARGE_PACKET_MAX; @@@ -42,7 -42,8 +42,8 @@@ static long curl_low_speed_time = -1 static int curl_ftp_no_epsv; static const char *curl_http_proxy; static const char *curl_cookie_file; -static char *user_name, *user_pass, *description; +static struct credential http_auth = CREDENTIAL_INIT; + static int http_proactive_auth; static const char *user_agent; #if LIBCURL_VERSION_NUM >= 0x071700 @@@ -53,7 -54,7 +54,7 @@@ #define CURLOPT_KEYPASSWD CURLOPT_SSLCERTPASSWD #endif -static char *ssl_cert_password; +static struct credential cert_auth = CREDENTIAL_INIT; static int ssl_cert_password_required; static struct curl_slist *pragma_header; @@@ -99,11 -100,13 +100,11 @@@ size_t fwrite_buffer(char *ptr, size_t struct strbuf *buffer = buffer_; strbuf_add(buffer, ptr, size); - data_received++; return size; } size_t fwrite_null(char *ptr, size_t eltsize, size_t nmemb, void *strbuf) { - data_received++; return eltsize * nmemb; } @@@ -137,6 -140,27 +138,6 @@@ static void process_curl_messages(void } #endif -static char *git_getpass_with_description(const char *what, const char *desc) -{ - struct strbuf prompt = STRBUF_INIT; - char *r; - - if (desc) - strbuf_addf(&prompt, "%s for '%s': ", what, desc); - else - strbuf_addf(&prompt, "%s: ", what); - /* - * NEEDSWORK: for usernames, we should do something less magical that - * actually echoes the characters. However, we need to read from - * /dev/tty and not stdio, which is not portable (but getpass will do - * it for us). http.c uses the same workaround. - */ - r = git_getpass(prompt.buf); - - strbuf_release(&prompt); - return xstrdup(r); -} - static int http_options(const char *var, const char *value, void *cb) { if (!strcmp("http.sslverify", var)) { @@@ -209,11 -233,11 +210,11 @@@ static void init_curl_http_auth(CURL *result) { - if (user_name) { + if (http_auth.username) { struct strbuf up = STRBUF_INIT; - if (!user_pass) - user_pass = xstrdup(git_getpass_with_description("Password", description)); - strbuf_addf(&up, "%s:%s", user_name, user_pass); + credential_fill(&http_auth); + strbuf_addf(&up, "%s:%s", + http_auth.username, http_auth.password); curl_easy_setopt(result, CURLOPT_USERPWD, strbuf_detach(&up, NULL)); } @@@ -221,14 -245,18 +222,14 @@@ static int has_cert_password(void) { - if (ssl_cert_password != NULL) - return 1; if (ssl_cert == NULL || ssl_cert_password_required != 1) return 0; - /* Only prompt the user once. */ - ssl_cert_password_required = -1; - ssl_cert_password = git_getpass_with_description("Certificate Password", description); - if (ssl_cert_password != NULL) { - ssl_cert_password = xstrdup(ssl_cert_password); - return 1; - } else - return 0; + if (!cert_auth.password) { + cert_auth.protocol = xstrdup("cert"); + cert_auth.path = xstrdup(ssl_cert); + credential_fill(&cert_auth); + } + return 1; } static CURL *get_curl_handle(void) @@@ -252,10 -280,13 +253,13 @@@ curl_easy_setopt(result, CURLOPT_HTTPAUTH, CURLAUTH_ANY); #endif + if (http_proactive_auth) + init_curl_http_auth(result); + if (ssl_cert != NULL) curl_easy_setopt(result, CURLOPT_SSLCERT, ssl_cert); if (has_cert_password()) - curl_easy_setopt(result, CURLOPT_KEYPASSWD, ssl_cert_password); + curl_easy_setopt(result, CURLOPT_KEYPASSWD, cert_auth.password); #if LIBCURL_VERSION_NUM >= 0x070903 if (ssl_key != NULL) curl_easy_setopt(result, CURLOPT_SSLKEY, ssl_key); @@@ -297,6 -328,42 +301,6 @@@ return result; } -static void http_auth_init(const char *url) -{ - const char *at, *colon, *cp, *slash, *host; - - cp = strstr(url, "://"); - if (!cp) - return; - - /* - * Ok, the URL looks like "proto://something". Which one? - * "proto://:@/...", - * "proto://@/...", or just - * "proto:///..."? - */ - cp += 3; - at = strchr(cp, '@'); - colon = strchr(cp, ':'); - slash = strchrnul(cp, '/'); - if (!at || slash <= at) { - /* No credentials, but we may have to ask for some later */ - host = cp; - } - else if (!colon || at <= colon) { - /* Only username */ - user_name = url_decode_mem(cp, at - cp); - user_pass = NULL; - host = at + 1; - } else { - user_name = url_decode_mem(cp, colon - cp); - user_pass = url_decode_mem(colon + 1, at - (colon + 1)); - host = at + 1; - } - - description = url_decode_mem(host, slash - host); -} - static void set_from_env(const char **var, const char *envname) { const char *val = getenv(envname); @@@ -304,7 -371,7 +308,7 @@@ *var = val; } - void http_init(struct remote *remote, const char *url) + void http_init(struct remote *remote, const char *url, int proactive_auth) { char *low_speed_limit; char *low_speed_time; @@@ -315,6 -382,8 +319,8 @@@ curl_global_init(CURL_GLOBAL_ALL); + http_proactive_auth = proactive_auth; + if (remote && remote->http_proxy) curl_http_proxy = xstrdup(remote->http_proxy); @@@ -369,7 -438,7 +375,7 @@@ curl_ftp_no_epsv = 1; if (url) { - http_auth_init(url); + credential_from_url(&http_auth, url); if (!ssl_cert_password_required && getenv("GIT_SSL_CERT_PASSWORD_PROTECTED") && !prefixcmp(url, "https://")) @@@ -418,10 -487,10 +424,10 @@@ void http_cleanup(void curl_http_proxy = NULL; } - if (ssl_cert_password != NULL) { - memset(ssl_cert_password, 0, strlen(ssl_cert_password)); - free(ssl_cert_password); - ssl_cert_password = NULL; + if (cert_auth.password != NULL) { + memset(cert_auth.password, 0, strlen(cert_auth.password)); + free(cert_auth.password); + cert_auth.password = NULL; } ssl_cert_password_required = 0; } @@@ -473,6 -542,7 +479,6 @@@ struct active_request_slot *get_active_ active_requests++; slot->in_use = 1; - slot->local = NULL; slot->results = NULL; slot->finished = NULL; slot->callback_data = NULL; @@@ -576,6 -646,8 +582,6 @@@ void step_active_slots(void void run_active_slot(struct active_request_slot *slot) { #ifdef USE_CURL_MULTI - long last_pos = 0; - long current_pos; fd_set readfds; fd_set writefds; fd_set excfds; @@@ -585,33 -657,25 +591,33 @@@ slot->finished = &finished; while (!finished) { - data_received = 0; step_active_slots(); - if (!data_received && slot->local != NULL) { - current_pos = ftell(slot->local); - if (current_pos > last_pos) - data_received++; - last_pos = current_pos; - } + if (slot->in_use) { +#if LIBCURL_VERSION_NUM >= 0x070f04 + long curl_timeout; + curl_multi_timeout(curlm, &curl_timeout); + if (curl_timeout == 0) { + continue; + } else if (curl_timeout == -1) { + select_timeout.tv_sec = 0; + select_timeout.tv_usec = 50000; + } else { + select_timeout.tv_sec = curl_timeout / 1000; + select_timeout.tv_usec = (curl_timeout % 1000) * 1000; + } +#else + select_timeout.tv_sec = 0; + select_timeout.tv_usec = 50000; +#endif - if (slot->in_use && !data_received) { - max_fd = 0; + max_fd = -1; FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&excfds); - select_timeout.tv_sec = 0; - select_timeout.tv_usec = 50000; - select(max_fd, &readfds, &writefds, - &excfds, &select_timeout); + curl_multi_fdset(curlm, &readfds, &writefds, &excfds, &max_fd); + + select(max_fd+1, &readfds, &writefds, &excfds, &select_timeout); } } #else @@@ -756,6 -820,7 +762,6 @@@ static int http_request(const char *url headers = curl_slist_append(headers, buf.buf); strbuf_reset(&buf); } - slot->local = result; } else curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer); @@@ -777,11 -842,17 +783,11 @@@ else if (missing_target(&results)) ret = HTTP_MISSING_TARGET; else if (results.http_code == 401) { - if (user_name && user_pass) { + if (http_auth.username && http_auth.password) { + credential_reject(&http_auth); 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. - */ - if (!user_name) - user_name = xstrdup(git_getpass_with_description("Username", description)); + credential_fill(&http_auth); init_curl_http_auth(slot->curl); ret = HTTP_REAUTH; } @@@ -797,12 -868,10 +803,12 @@@ ret = HTTP_START_FAILED; } - slot->local = NULL; curl_slist_free_all(headers); strbuf_release(&buf); + if (ret == HTTP_OK) + credential_approve(&http_auth); + return ret; } @@@ -994,6 -1063,7 +1000,6 @@@ void release_http_pack_request(struct h if (preq->packfile != NULL) { fclose(preq->packfile); preq->packfile = NULL; - preq->slot->local = NULL; } if (preq->range_header != NULL) { curl_slist_free_all(preq->range_header); @@@ -1015,6 -1085,7 +1021,6 @@@ int finish_http_pack_request(struct htt fclose(preq->packfile); preq->packfile = NULL; - preq->slot->local = NULL; lst = preq->lst; while (*lst != p) @@@ -1083,6 -1154,7 +1089,6 @@@ struct http_pack_request *new_http_pack } preq->slot = get_active_slot(); - preq->slot->local = preq->packfile; curl_easy_setopt(preq->slot->curl, CURLOPT_FILE, preq->packfile); curl_easy_setopt(preq->slot->curl, CURLOPT_WRITEFUNCTION, fwrite); curl_easy_setopt(preq->slot->curl, CURLOPT_URL, preq->url); @@@ -1139,6 -1211,7 +1145,6 @@@ static size_t fwrite_sha1_file(char *pt git_SHA1_Update(&freq->c, expn, sizeof(expn) - freq->stream.avail_out); } while (freq->stream.avail_in && freq->zret == Z_OK); - data_received++; return size; } diff --combined http.h index ee1606942a,51f6ba73ba..0b61653894 --- a/http.h +++ b/http.h @@@ -49,6 -49,7 +49,6 @@@ struct slot_results struct active_request_slot { CURL *curl; - FILE *local; int in_use; CURLcode curl_result; long http_code; @@@ -85,9 -86,11 +85,10 @@@ extern void add_fill_function(void *dat extern void step_active_slots(void); #endif - extern void http_init(struct remote *remote, const char *url); + extern void http_init(struct remote *remote, const char *url, + int proactive_auth); extern void http_cleanup(void); -extern int data_received; extern int active_requests; extern int http_is_verbose; extern size_t http_post_buffer; diff --combined remote-curl.c index 94dc4886d0,0757b19a80..6a352de7be --- a/remote-curl.c +++ b/remote-curl.c @@@ -200,7 -200,7 +200,7 @@@ static struct ref *parse_git_refs(struc if (start_async(&async)) die("cannot start thread to parse advertised refs"); - get_remote_heads(async.out, &list, 0, NULL, 0, NULL); + get_remote_heads(async.out, &list, 0, NULL); close(async.out); if (finish_async(&async)) die("ref parsing thread failed"); @@@ -859,7 -859,7 +859,7 @@@ int main(int argc, const char **argv url = strbuf_detach(&buf, NULL); - http_init(remote, url); + http_init(remote, url, 0); do { if (strbuf_getline(&buf, stdin, '\n') == EOF) {