Merge branch 'mg/http-auth'

* mg/http-auth:
  http-push.c: use a faux remote to pass to http_init
  Do not name "repo" struct "remote" in push_http.c
  http.c: CURLOPT_NETRC_OPTIONAL is not available in ancient versions of cURL
  http authentication via prompts
  http_init(): Fix config file parsing
  http.c: style cleanups

Conflicts:
	http-push.c
This commit is contained in:
Junio C Hamano 2009-03-26 00:27:59 -07:00
commit 6422c6af38
2 changed files with 190 additions and 141 deletions

View file

@ -97,7 +97,7 @@ struct repo
struct remote_lock *locks; struct remote_lock *locks;
}; };
static struct repo *remote; static struct repo *repo;
enum transfer_state { enum transfer_state {
NEED_FETCH, NEED_FETCH,
@ -324,7 +324,7 @@ static void start_fetch_loose(struct transfer_request *request)
git_SHA1_Init(&request->c); git_SHA1_Init(&request->c);
url = get_remote_object_url(remote->url, hex, 0); url = get_remote_object_url(repo->url, hex, 0);
request->url = xstrdup(url); request->url = xstrdup(url);
/* If a previous temp file is present, process what was already /* If a previous temp file is present, process what was already
@ -389,7 +389,7 @@ static void start_fetch_loose(struct transfer_request *request)
request->state = RUN_FETCH_LOOSE; request->state = RUN_FETCH_LOOSE;
if (!start_active_slot(slot)) { if (!start_active_slot(slot)) {
fprintf(stderr, "Unable to start GET request\n"); fprintf(stderr, "Unable to start GET request\n");
remote->can_update_info_refs = 0; repo->can_update_info_refs = 0;
release_request(request); release_request(request);
} }
} }
@ -399,7 +399,7 @@ static void start_mkcol(struct transfer_request *request)
char *hex = sha1_to_hex(request->obj->sha1); char *hex = sha1_to_hex(request->obj->sha1);
struct active_request_slot *slot; struct active_request_slot *slot;
request->url = get_remote_object_url(remote->url, hex, 1); request->url = get_remote_object_url(repo->url, hex, 1);
slot = get_active_slot(); slot = get_active_slot();
slot->callback_func = process_response; slot->callback_func = process_response;
@ -434,10 +434,10 @@ static void start_fetch_packed(struct transfer_request *request)
struct transfer_request *check_request = request_queue_head; struct transfer_request *check_request = request_queue_head;
struct active_request_slot *slot; struct active_request_slot *slot;
target = find_sha1_pack(request->obj->sha1, remote->packs); target = find_sha1_pack(request->obj->sha1, repo->packs);
if (!target) { if (!target) {
fprintf(stderr, "Unable to fetch %s, will not be able to update server info refs\n", sha1_to_hex(request->obj->sha1)); fprintf(stderr, "Unable to fetch %s, will not be able to update server info refs\n", sha1_to_hex(request->obj->sha1));
remote->can_update_info_refs = 0; repo->can_update_info_refs = 0;
release_request(request); release_request(request);
return; return;
} }
@ -450,9 +450,9 @@ static void start_fetch_packed(struct transfer_request *request)
snprintf(request->tmpfile, sizeof(request->tmpfile), snprintf(request->tmpfile, sizeof(request->tmpfile),
"%s.temp", filename); "%s.temp", filename);
url = xmalloc(strlen(remote->url) + 64); url = xmalloc(strlen(repo->url) + 64);
sprintf(url, "%sobjects/pack/pack-%s.pack", sprintf(url, "%sobjects/pack/pack-%s.pack",
remote->url, sha1_to_hex(target->sha1)); repo->url, sha1_to_hex(target->sha1));
/* Make sure there isn't another open request for this pack */ /* Make sure there isn't another open request for this pack */
while (check_request) { while (check_request) {
@ -469,7 +469,7 @@ static void start_fetch_packed(struct transfer_request *request)
if (!packfile) { if (!packfile) {
fprintf(stderr, "Unable to open local file %s for pack", fprintf(stderr, "Unable to open local file %s for pack",
request->tmpfile); request->tmpfile);
remote->can_update_info_refs = 0; repo->can_update_info_refs = 0;
free(url); free(url);
return; return;
} }
@ -505,7 +505,7 @@ static void start_fetch_packed(struct transfer_request *request)
request->state = RUN_FETCH_PACKED; request->state = RUN_FETCH_PACKED;
if (!start_active_slot(slot)) { if (!start_active_slot(slot)) {
fprintf(stderr, "Unable to start GET request\n"); fprintf(stderr, "Unable to start GET request\n");
remote->can_update_info_refs = 0; repo->can_update_info_refs = 0;
release_request(request); release_request(request);
} }
} }
@ -554,10 +554,10 @@ static void start_put(struct transfer_request *request)
request->buffer.buf.len = stream.total_out; request->buffer.buf.len = stream.total_out;
strbuf_addstr(&buf, "Destination: "); strbuf_addstr(&buf, "Destination: ");
append_remote_object_url(&buf, remote->url, hex, 0); append_remote_object_url(&buf, repo->url, hex, 0);
request->dest = strbuf_detach(&buf, NULL); request->dest = strbuf_detach(&buf, NULL);
append_remote_object_url(&buf, remote->url, hex, 0); append_remote_object_url(&buf, repo->url, hex, 0);
strbuf_add(&buf, request->lock->tmpfile_suffix, 41); strbuf_add(&buf, request->lock->tmpfile_suffix, 41);
request->url = strbuf_detach(&buf, NULL); request->url = strbuf_detach(&buf, NULL);
@ -648,7 +648,7 @@ static int refresh_lock(struct remote_lock *lock)
static void check_locks(void) static void check_locks(void)
{ {
struct remote_lock *lock = remote->locks; struct remote_lock *lock = repo->locks;
time_t current_time = time(NULL); time_t current_time = time(NULL);
int time_remaining; int time_remaining;
@ -788,7 +788,7 @@ static void finish_request(struct transfer_request *request)
if (request->curl_result != CURLE_OK) { if (request->curl_result != CURLE_OK) {
fprintf(stderr, "Unable to get pack file %s\n%s", fprintf(stderr, "Unable to get pack file %s\n%s",
request->url, curl_errorstr); request->url, curl_errorstr);
remote->can_update_info_refs = 0; repo->can_update_info_refs = 0;
} else { } else {
off_t pack_size = ftell(request->local_stream); off_t pack_size = ftell(request->local_stream);
@ -798,7 +798,7 @@ static void finish_request(struct transfer_request *request)
request->filename)) { request->filename)) {
target = (struct packed_git *)request->userData; target = (struct packed_git *)request->userData;
target->pack_size = pack_size; target->pack_size = pack_size;
lst = &remote->packs; lst = &repo->packs;
while (*lst != target) while (*lst != target)
lst = &((*lst)->next); lst = &((*lst)->next);
*lst = (*lst)->next; *lst = (*lst)->next;
@ -806,7 +806,7 @@ static void finish_request(struct transfer_request *request)
if (!verify_pack(target)) if (!verify_pack(target))
install_packed_git(target); install_packed_git(target);
else else
remote->can_update_info_refs = 0; repo->can_update_info_refs = 0;
} }
} }
release_request(request); release_request(request);
@ -889,7 +889,7 @@ static int add_send_request(struct object *obj, struct remote_lock *lock)
get_remote_object_list(obj->sha1[0]); get_remote_object_list(obj->sha1[0]);
if (obj->flags & (REMOTE | PUSHING)) if (obj->flags & (REMOTE | PUSHING))
return 0; return 0;
target = find_sha1_pack(obj->sha1, remote->packs); target = find_sha1_pack(obj->sha1, repo->packs);
if (target) { if (target) {
obj->flags |= REMOTE; obj->flags |= REMOTE;
return 0; return 0;
@ -930,8 +930,8 @@ static int fetch_index(unsigned char *sha1)
struct slot_results results; struct slot_results results;
/* Don't use the index if the pack isn't there */ /* Don't use the index if the pack isn't there */
url = xmalloc(strlen(remote->url) + 64); url = xmalloc(strlen(repo->url) + 64);
sprintf(url, "%sobjects/pack/pack-%s.pack", remote->url, hex); sprintf(url, "%sobjects/pack/pack-%s.pack", repo->url, hex);
slot = get_active_slot(); slot = get_active_slot();
slot->results = &results; slot->results = &results;
curl_easy_setopt(slot->curl, CURLOPT_URL, url); curl_easy_setopt(slot->curl, CURLOPT_URL, url);
@ -956,7 +956,7 @@ static int fetch_index(unsigned char *sha1)
if (push_verbosely) if (push_verbosely)
fprintf(stderr, "Getting index for pack %s\n", hex); fprintf(stderr, "Getting index for pack %s\n", hex);
sprintf(url, "%sobjects/pack/pack-%s.idx", remote->url, hex); sprintf(url, "%sobjects/pack/pack-%s.idx", repo->url, hex);
filename = sha1_pack_index_name(sha1); filename = sha1_pack_index_name(sha1);
snprintf(tmpfile, sizeof(tmpfile), "%s.temp", filename); snprintf(tmpfile, sizeof(tmpfile), "%s.temp", filename);
@ -1018,8 +1018,8 @@ static int setup_index(unsigned char *sha1)
return -1; return -1;
new_pack = parse_pack_index(sha1); new_pack = parse_pack_index(sha1);
new_pack->next = remote->packs; new_pack->next = repo->packs;
remote->packs = new_pack; repo->packs = new_pack;
return 0; return 0;
} }
@ -1037,8 +1037,8 @@ static int fetch_indices(void)
if (push_verbosely) if (push_verbosely)
fprintf(stderr, "Getting pack list\n"); fprintf(stderr, "Getting pack list\n");
url = xmalloc(strlen(remote->url) + 20); url = xmalloc(strlen(repo->url) + 20);
sprintf(url, "%sobjects/info/packs", remote->url); sprintf(url, "%sobjects/info/packs", repo->url);
slot = get_active_slot(); slot = get_active_slot();
slot->results = &results; slot->results = &results;
@ -1223,11 +1223,11 @@ static struct remote_lock *lock_remote(const char *path, long timeout)
struct curl_slist *dav_headers = NULL; struct curl_slist *dav_headers = NULL;
struct xml_ctx ctx; struct xml_ctx ctx;
url = xmalloc(strlen(remote->url) + strlen(path) + 1); url = xmalloc(strlen(repo->url) + strlen(path) + 1);
sprintf(url, "%s%s", remote->url, path); sprintf(url, "%s%s", repo->url, path);
/* Make sure leading directories exist for the remote ref */ /* Make sure leading directories exist for the remote ref */
ep = strchr(url + strlen(remote->url) + 1, '/'); ep = strchr(url + strlen(repo->url) + 1, '/');
while (ep) { while (ep) {
char saved_character = ep[1]; char saved_character = ep[1];
ep[1] = '\0'; ep[1] = '\0';
@ -1319,8 +1319,8 @@ static struct remote_lock *lock_remote(const char *path, long timeout)
} else { } else {
lock->url = url; lock->url = url;
lock->start_time = time(NULL); lock->start_time = time(NULL);
lock->next = remote->locks; lock->next = repo->locks;
remote->locks = lock; repo->locks = lock;
} }
return lock; return lock;
@ -1330,7 +1330,7 @@ static int unlock_remote(struct remote_lock *lock)
{ {
struct active_request_slot *slot; struct active_request_slot *slot;
struct slot_results results; struct slot_results results;
struct remote_lock *prev = remote->locks; struct remote_lock *prev = repo->locks;
struct curl_slist *dav_headers; struct curl_slist *dav_headers;
int rc = 0; int rc = 0;
@ -1356,8 +1356,8 @@ static int unlock_remote(struct remote_lock *lock)
curl_slist_free_all(dav_headers); curl_slist_free_all(dav_headers);
if (remote->locks == lock) { if (repo->locks == lock) {
remote->locks = lock->next; repo->locks = lock->next;
} else { } else {
while (prev && prev->next != lock) while (prev && prev->next != lock)
prev = prev->next; prev = prev->next;
@ -1375,7 +1375,7 @@ static int unlock_remote(struct remote_lock *lock)
static void remove_locks(void) static void remove_locks(void)
{ {
struct remote_lock *lock = remote->locks; struct remote_lock *lock = repo->locks;
fprintf(stderr, "Removing remote locks...\n"); fprintf(stderr, "Removing remote locks...\n");
while (lock) { while (lock) {
@ -1457,7 +1457,7 @@ static void handle_remote_ls_ctx(struct xml_ctx *ctx, int tag_closed)
} }
} }
if (path) { if (path) {
path += remote->path_len; path += repo->path_len;
ls->dentry_name = xstrdup(path); ls->dentry_name = xstrdup(path);
} }
} else if (!strcmp(ctx->name, DAV_PROPFIND_COLLECTION)) { } else if (!strcmp(ctx->name, DAV_PROPFIND_COLLECTION)) {
@ -1480,7 +1480,7 @@ static void remote_ls(const char *path, int flags,
void (*userFunc)(struct remote_ls_ctx *ls), void (*userFunc)(struct remote_ls_ctx *ls),
void *userData) void *userData)
{ {
char *url = xmalloc(strlen(remote->url) + strlen(path) + 1); char *url = xmalloc(strlen(repo->url) + strlen(path) + 1);
struct active_request_slot *slot; struct active_request_slot *slot;
struct slot_results results; struct slot_results results;
struct strbuf in_buffer = STRBUF_INIT; struct strbuf in_buffer = STRBUF_INIT;
@ -1496,7 +1496,7 @@ static void remote_ls(const char *path, int flags,
ls.userData = userData; ls.userData = userData;
ls.userFunc = userFunc; ls.userFunc = userFunc;
sprintf(url, "%s%s", remote->url, path); sprintf(url, "%s%s", repo->url, path);
strbuf_addf(&out_buffer.buf, PROPFIND_ALL_REQUEST); strbuf_addf(&out_buffer.buf, PROPFIND_ALL_REQUEST);
@ -1574,7 +1574,7 @@ static int locking_available(void)
struct xml_ctx ctx; struct xml_ctx ctx;
int lock_flags = 0; int lock_flags = 0;
strbuf_addf(&out_buffer.buf, PROPFIND_SUPPORTEDLOCK_REQUEST, remote->url); strbuf_addf(&out_buffer.buf, PROPFIND_SUPPORTEDLOCK_REQUEST, repo->url);
dav_headers = curl_slist_append(dav_headers, "Depth: 0"); dav_headers = curl_slist_append(dav_headers, "Depth: 0");
dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml"); dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml");
@ -1586,7 +1586,7 @@ static int locking_available(void)
curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer); curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer); curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer); curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
curl_easy_setopt(slot->curl, CURLOPT_URL, remote->url); curl_easy_setopt(slot->curl, CURLOPT_URL, repo->url);
curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1); curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);
curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PROPFIND); curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PROPFIND);
curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers); curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
@ -1617,15 +1617,15 @@ static int locking_available(void)
XML_ParserFree(parser); XML_ParserFree(parser);
if (!lock_flags) if (!lock_flags)
error("no DAV locking support on %s", error("no DAV locking support on %s",
remote->url); repo->url);
} else { } else {
error("Cannot access URL %s, return code %d", error("Cannot access URL %s, return code %d",
remote->url, results.curl_result); repo->url, results.curl_result);
lock_flags = 0; lock_flags = 0;
} }
} else { } else {
error("Unable to start PROPFIND request on %s", remote->url); error("Unable to start PROPFIND request on %s", repo->url);
} }
strbuf_release(&out_buffer.buf); strbuf_release(&out_buffer.buf);
@ -1801,10 +1801,10 @@ static void one_remote_ref(char *refname)
ref = alloc_ref(refname); ref = alloc_ref(refname);
if (http_fetch_ref(remote->url, ref) != 0) { if (http_fetch_ref(repo->url, ref) != 0) {
fprintf(stderr, fprintf(stderr,
"Unable to fetch ref %s from %s\n", "Unable to fetch ref %s from %s\n",
refname, remote->url); refname, repo->url);
free(ref); free(ref);
return; return;
} }
@ -1813,7 +1813,7 @@ static void one_remote_ref(char *refname)
* Fetch a copy of the object if it doesn't exist locally - it * Fetch a copy of the object if it doesn't exist locally - it
* may be required for updating server info later. * may be required for updating server info later.
*/ */
if (remote->can_update_info_refs && !has_sha1_file(ref->old_sha1)) { if (repo->can_update_info_refs && !has_sha1_file(ref->old_sha1)) {
obj = lookup_unknown_object(ref->old_sha1); obj = lookup_unknown_object(ref->old_sha1);
if (obj) { if (obj) {
fprintf(stderr, " fetch %s for %s\n", fprintf(stderr, " fetch %s for %s\n",
@ -1853,10 +1853,10 @@ static void add_remote_info_ref(struct remote_ls_ctx *ls)
ref = alloc_ref(ls->dentry_name); ref = alloc_ref(ls->dentry_name);
if (http_fetch_ref(remote->url, ref) != 0) { if (http_fetch_ref(repo->url, ref) != 0) {
fprintf(stderr, fprintf(stderr,
"Unable to fetch ref %s from %s\n", "Unable to fetch ref %s from %s\n",
ls->dentry_name, remote->url); ls->dentry_name, repo->url);
aborted = 1; aborted = 1;
free(ref); free(ref);
return; return;
@ -1931,12 +1931,12 @@ static void update_remote_info_refs(struct remote_lock *lock)
static int remote_exists(const char *path) static int remote_exists(const char *path)
{ {
char *url = xmalloc(strlen(remote->url) + strlen(path) + 1); char *url = xmalloc(strlen(repo->url) + strlen(path) + 1);
struct active_request_slot *slot; struct active_request_slot *slot;
struct slot_results results; struct slot_results results;
int ret = -1; int ret = -1;
sprintf(url, "%s%s", remote->url, path); sprintf(url, "%s%s", repo->url, path);
slot = get_active_slot(); slot = get_active_slot();
slot->results = &results; slot->results = &results;
@ -1966,8 +1966,8 @@ static void fetch_symref(const char *path, char **symref, unsigned char *sha1)
struct active_request_slot *slot; struct active_request_slot *slot;
struct slot_results results; struct slot_results results;
url = xmalloc(strlen(remote->url) + strlen(path) + 1); url = xmalloc(strlen(repo->url) + strlen(path) + 1);
sprintf(url, "%s%s", remote->url, path); sprintf(url, "%s%s", repo->url, path);
slot = get_active_slot(); slot = get_active_slot();
slot->results = &results; slot->results = &results;
@ -2082,7 +2082,7 @@ static int delete_remote_branch(char *pattern, int force)
"of your current HEAD.\n" "of your current HEAD.\n"
"If you are sure you want to delete it," "If you are sure you want to delete it,"
" run:\n\t'git http-push -D %s %s'", " run:\n\t'git http-push -D %s %s'",
remote_ref->name, remote->url, pattern); remote_ref->name, repo->url, pattern);
} }
} }
@ -2090,8 +2090,8 @@ static int delete_remote_branch(char *pattern, int force)
fprintf(stderr, "Removing remote branch '%s'\n", remote_ref->name); fprintf(stderr, "Removing remote branch '%s'\n", remote_ref->name);
if (dry_run) if (dry_run)
return 0; return 0;
url = xmalloc(strlen(remote->url) + strlen(remote_ref->name) + 1); url = xmalloc(strlen(repo->url) + strlen(remote_ref->name) + 1);
sprintf(url, "%s%s", remote->url, remote_ref->name); sprintf(url, "%s%s", repo->url, remote_ref->name);
slot = get_active_slot(); slot = get_active_slot();
slot->results = &results; slot->results = &results;
curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1); curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
@ -2128,13 +2128,14 @@ int main(int argc, char **argv)
int i; int i;
int new_refs; int new_refs;
struct ref *ref, *local_refs; struct ref *ref, *local_refs;
struct remote *remote;
char *rewritten_url = NULL; char *rewritten_url = NULL;
git_extract_argv0_path(argv[0]); git_extract_argv0_path(argv[0]);
setup_git_directory(); setup_git_directory();
remote = xcalloc(sizeof(*remote), 1); repo = xcalloc(sizeof(*repo), 1);
argv++; argv++;
for (i = 1; i < argc; i++, argv++) { for (i = 1; i < argc; i++, argv++) {
@ -2167,14 +2168,14 @@ int main(int argc, char **argv)
continue; continue;
} }
} }
if (!remote->url) { if (!repo->url) {
char *path = strstr(arg, "//"); char *path = strstr(arg, "//");
remote->url = arg; repo->url = arg;
remote->path_len = strlen(arg); repo->path_len = strlen(arg);
if (path) { if (path) {
remote->path = strchr(path+2, '/'); repo->path = strchr(path+2, '/');
if (remote->path) if (repo->path)
remote->path_len = strlen(remote->path); repo->path_len = strlen(repo->path);
} }
continue; continue;
} }
@ -2187,7 +2188,7 @@ int main(int argc, char **argv)
die("git-push is not available for http/https repository when not compiled with USE_CURL_MULTI"); die("git-push is not available for http/https repository when not compiled with USE_CURL_MULTI");
#endif #endif
if (!remote->url) if (!repo->url)
usage(http_push_usage); usage(http_push_usage);
if (delete_branch && nr_refspec != 1) if (delete_branch && nr_refspec != 1)
@ -2195,17 +2196,24 @@ int main(int argc, char **argv)
memset(remote_dir_exists, -1, 256); memset(remote_dir_exists, -1, 256);
http_init(NULL); /*
* Create a minimum remote by hand to give to http_init(),
* primarily to allow it to look at the URL.
*/
remote = xcalloc(sizeof(*remote), 1);
ALLOC_GROW(remote->url, remote->url_nr + 1, remote->url_alloc);
remote->url[remote->url_nr++] = repo->url;
http_init(remote);
no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:"); no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:");
if (remote->url && remote->url[strlen(remote->url)-1] != '/') { if (repo->url && repo->url[strlen(repo->url)-1] != '/') {
rewritten_url = xmalloc(strlen(remote->url)+2); rewritten_url = xmalloc(strlen(repo->url)+2);
strcpy(rewritten_url, remote->url); strcpy(rewritten_url, repo->url);
strcat(rewritten_url, "/"); strcat(rewritten_url, "/");
remote->path = rewritten_url + (remote->path - remote->url); repo->path = rewritten_url + (repo->path - repo->url);
remote->path_len++; repo->path_len++;
remote->url = rewritten_url; repo->url = rewritten_url;
} }
/* Verify DAV compliance/lock support */ /* Verify DAV compliance/lock support */
@ -2217,20 +2225,20 @@ int main(int argc, char **argv)
sigchain_push_common(remove_locks_on_signal); sigchain_push_common(remove_locks_on_signal);
/* Check whether the remote has server info files */ /* Check whether the remote has server info files */
remote->can_update_info_refs = 0; repo->can_update_info_refs = 0;
remote->has_info_refs = remote_exists("info/refs"); repo->has_info_refs = remote_exists("info/refs");
remote->has_info_packs = remote_exists("objects/info/packs"); repo->has_info_packs = remote_exists("objects/info/packs");
if (remote->has_info_refs) { if (repo->has_info_refs) {
info_ref_lock = lock_remote("info/refs", LOCK_TIME); info_ref_lock = lock_remote("info/refs", LOCK_TIME);
if (info_ref_lock) if (info_ref_lock)
remote->can_update_info_refs = 1; repo->can_update_info_refs = 1;
else { else {
error("cannot lock existing info/refs"); error("cannot lock existing info/refs");
rc = 1; rc = 1;
goto cleanup; goto cleanup;
} }
} }
if (remote->has_info_packs) if (repo->has_info_packs)
fetch_indices(); fetch_indices();
/* Get a list of all local and remote heads to validate refspecs */ /* Get a list of all local and remote heads to validate refspecs */
@ -2388,8 +2396,8 @@ int main(int argc, char **argv)
} }
/* Update remote server info if appropriate */ /* Update remote server info if appropriate */
if (remote->has_info_refs && new_refs) { if (repo->has_info_refs && new_refs) {
if (info_ref_lock && remote->can_update_info_refs) { if (info_ref_lock && repo->can_update_info_refs) {
fprintf(stderr, "Updating remote server info\n"); fprintf(stderr, "Updating remote server info\n");
if (!dry_run) if (!dry_run)
update_remote_info_refs(info_ref_lock); update_remote_info_refs(info_ref_lock);
@ -2402,7 +2410,7 @@ int main(int argc, char **argv)
free(rewritten_url); free(rewritten_url);
if (info_ref_lock) if (info_ref_lock)
unlock_remote(info_ref_lock); unlock_remote(info_ref_lock);
free(remote); free(repo);
curl_slist_free_all(no_pragma_header); curl_slist_free_all(no_pragma_header);

169
http.c
View file

@ -1,7 +1,7 @@
#include "http.h" #include "http.h"
int data_received; int data_received;
int active_requests = 0; int active_requests;
#ifdef USE_CURL_MULTI #ifdef USE_CURL_MULTI
static int max_requests = -1; static int max_requests = -1;
@ -13,22 +13,23 @@ static CURL *curl_default;
char curl_errorstr[CURL_ERROR_SIZE]; char curl_errorstr[CURL_ERROR_SIZE];
static int curl_ssl_verify = -1; static int curl_ssl_verify = -1;
static const char *ssl_cert = NULL; static const char *ssl_cert;
#if LIBCURL_VERSION_NUM >= 0x070902 #if LIBCURL_VERSION_NUM >= 0x070902
static const char *ssl_key = NULL; static const char *ssl_key;
#endif #endif
#if LIBCURL_VERSION_NUM >= 0x070908 #if LIBCURL_VERSION_NUM >= 0x070908
static const char *ssl_capath = NULL; static const char *ssl_capath;
#endif #endif
static const char *ssl_cainfo = NULL; static const char *ssl_cainfo;
static long curl_low_speed_limit = -1; static long curl_low_speed_limit = -1;
static long curl_low_speed_time = -1; static long curl_low_speed_time = -1;
static int curl_ftp_no_epsv = 0; static int curl_ftp_no_epsv;
static const char *curl_http_proxy = NULL; static const char *curl_http_proxy;
static char *user_name, *user_pass;
static struct curl_slist *pragma_header; static struct curl_slist *pragma_header;
static struct active_request_slot *active_queue_head = NULL; static struct active_request_slot *active_queue_head;
size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb, void *buffer_) size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb, void *buffer_)
{ {
@ -94,53 +95,33 @@ static void process_curl_messages(void)
static int http_options(const char *var, const char *value, void *cb) static int http_options(const char *var, const char *value, void *cb)
{ {
if (!strcmp("http.sslverify", var)) { if (!strcmp("http.sslverify", var)) {
if (curl_ssl_verify == -1) { curl_ssl_verify = git_config_bool(var, value);
curl_ssl_verify = git_config_bool(var, value);
}
return 0;
}
if (!strcmp("http.sslcert", var)) {
if (ssl_cert == NULL)
return git_config_string(&ssl_cert, var, value);
return 0; return 0;
} }
if (!strcmp("http.sslcert", var))
return git_config_string(&ssl_cert, var, value);
#if LIBCURL_VERSION_NUM >= 0x070902 #if LIBCURL_VERSION_NUM >= 0x070902
if (!strcmp("http.sslkey", var)) { if (!strcmp("http.sslkey", var))
if (ssl_key == NULL) return git_config_string(&ssl_key, var, value);
return git_config_string(&ssl_key, var, value);
return 0;
}
#endif #endif
#if LIBCURL_VERSION_NUM >= 0x070908 #if LIBCURL_VERSION_NUM >= 0x070908
if (!strcmp("http.sslcapath", var)) { if (!strcmp("http.sslcapath", var))
if (ssl_capath == NULL) return git_config_string(&ssl_capath, var, value);
return git_config_string(&ssl_capath, var, value);
return 0;
}
#endif #endif
if (!strcmp("http.sslcainfo", var)) { if (!strcmp("http.sslcainfo", var))
if (ssl_cainfo == NULL) return git_config_string(&ssl_cainfo, var, value);
return git_config_string(&ssl_cainfo, var, value);
return 0;
}
#ifdef USE_CURL_MULTI #ifdef USE_CURL_MULTI
if (!strcmp("http.maxrequests", var)) { if (!strcmp("http.maxrequests", var)) {
if (max_requests == -1) max_requests = git_config_int(var, value);
max_requests = git_config_int(var, value);
return 0; return 0;
} }
#endif #endif
if (!strcmp("http.lowspeedlimit", var)) { if (!strcmp("http.lowspeedlimit", var)) {
if (curl_low_speed_limit == -1) curl_low_speed_limit = (long)git_config_int(var, value);
curl_low_speed_limit = (long)git_config_int(var, value);
return 0; return 0;
} }
if (!strcmp("http.lowspeedtime", var)) { if (!strcmp("http.lowspeedtime", var)) {
if (curl_low_speed_time == -1) curl_low_speed_time = (long)git_config_int(var, value);
curl_low_speed_time = (long)git_config_int(var, value);
return 0; return 0;
} }
@ -148,19 +129,28 @@ static int http_options(const char *var, const char *value, void *cb)
curl_ftp_no_epsv = git_config_bool(var, value); curl_ftp_no_epsv = git_config_bool(var, value);
return 0; return 0;
} }
if (!strcmp("http.proxy", var)) { if (!strcmp("http.proxy", var))
if (curl_http_proxy == NULL) return git_config_string(&curl_http_proxy, var, value);
return git_config_string(&curl_http_proxy, var, value);
return 0;
}
/* Fall back on the default ones */ /* Fall back on the default ones */
return git_default_config(var, value, cb); return git_default_config(var, value, cb);
} }
static CURL* get_curl_handle(void) static void init_curl_http_auth(CURL *result)
{ {
CURL* result = curl_easy_init(); if (user_name) {
struct strbuf up = STRBUF_INIT;
if (!user_pass)
user_pass = xstrdup(getpass("Password: "));
strbuf_addf(&up, "%s:%s", user_name, user_pass);
curl_easy_setopt(result, CURLOPT_USERPWD,
strbuf_detach(&up, NULL));
}
}
static CURL *get_curl_handle(void)
{
CURL *result = curl_easy_init();
if (!curl_ssl_verify) { if (!curl_ssl_verify) {
curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, 0); curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, 0);
@ -176,6 +166,8 @@ static CURL* get_curl_handle(void)
curl_easy_setopt(result, CURLOPT_NETRC, CURL_NETRC_OPTIONAL); curl_easy_setopt(result, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
#endif #endif
init_curl_http_auth(result);
if (ssl_cert != NULL) if (ssl_cert != NULL)
curl_easy_setopt(result, CURLOPT_SSLCERT, ssl_cert); curl_easy_setopt(result, CURLOPT_SSLCERT, ssl_cert);
#if LIBCURL_VERSION_NUM >= 0x070902 #if LIBCURL_VERSION_NUM >= 0x070902
@ -213,11 +205,60 @@ static CURL* get_curl_handle(void)
return result; return result;
} }
static void http_auth_init(const char *url)
{
char *at, *colon, *cp, *slash;
int len;
cp = strstr(url, "://");
if (!cp)
return;
/*
* Ok, the URL looks like "proto://something". Which one?
* "proto://<user>:<pass>@<host>/...",
* "proto://<user>@<host>/...", or just
* "proto://<host>/..."?
*/
cp += 3;
at = strchr(cp, '@');
colon = strchr(cp, ':');
slash = strchrnul(cp, '/');
if (!at || slash <= at)
return; /* No credentials */
if (!colon || at <= colon) {
/* Only username */
len = at - cp;
user_name = xmalloc(len + 1);
memcpy(user_name, cp, len);
user_name[len] = '\0';
user_pass = NULL;
} else {
len = colon - cp;
user_name = xmalloc(len + 1);
memcpy(user_name, cp, len);
user_name[len] = '\0';
len = at - (colon + 1);
user_pass = xmalloc(len + 1);
memcpy(user_pass, colon + 1, len);
user_pass[len] = '\0';
}
}
static void set_from_env(const char **var, const char *envname)
{
const char *val = getenv(envname);
if (val)
*var = val;
}
void http_init(struct remote *remote) void http_init(struct remote *remote)
{ {
char *low_speed_limit; char *low_speed_limit;
char *low_speed_time; char *low_speed_time;
git_config(http_options, NULL);
curl_global_init(CURL_GLOBAL_ALL); curl_global_init(CURL_GLOBAL_ALL);
if (remote && remote->http_proxy) if (remote && remote->http_proxy)
@ -242,14 +283,14 @@ void http_init(struct remote *remote)
if (getenv("GIT_SSL_NO_VERIFY")) if (getenv("GIT_SSL_NO_VERIFY"))
curl_ssl_verify = 0; curl_ssl_verify = 0;
ssl_cert = getenv("GIT_SSL_CERT"); set_from_env(&ssl_cert, "GIT_SSL_CERT");
#if LIBCURL_VERSION_NUM >= 0x070902 #if LIBCURL_VERSION_NUM >= 0x070902
ssl_key = getenv("GIT_SSL_KEY"); set_from_env(&ssl_key, "GIT_SSL_KEY");
#endif #endif
#if LIBCURL_VERSION_NUM >= 0x070908 #if LIBCURL_VERSION_NUM >= 0x070908
ssl_capath = getenv("GIT_SSL_CAPATH"); set_from_env(&ssl_capath, "GIT_SSL_CAPATH");
#endif #endif
ssl_cainfo = getenv("GIT_SSL_CAINFO"); set_from_env(&ssl_cainfo, "GIT_SSL_CAINFO");
low_speed_limit = getenv("GIT_HTTP_LOW_SPEED_LIMIT"); low_speed_limit = getenv("GIT_HTTP_LOW_SPEED_LIMIT");
if (low_speed_limit != NULL) if (low_speed_limit != NULL)
@ -258,8 +299,6 @@ void http_init(struct remote *remote)
if (low_speed_time != NULL) if (low_speed_time != NULL)
curl_low_speed_time = strtol(low_speed_time, NULL, 10); curl_low_speed_time = strtol(low_speed_time, NULL, 10);
git_config(http_options, NULL);
if (curl_ssl_verify == -1) if (curl_ssl_verify == -1)
curl_ssl_verify = 1; curl_ssl_verify = 1;
@ -271,6 +310,9 @@ void http_init(struct remote *remote)
if (getenv("GIT_CURL_FTP_NO_EPSV")) if (getenv("GIT_CURL_FTP_NO_EPSV"))
curl_ftp_no_epsv = 1; curl_ftp_no_epsv = 1;
if (remote && remote->url && remote->url[0])
http_auth_init(remote->url[0]);
#ifndef NO_CURL_EASY_DUPHANDLE #ifndef NO_CURL_EASY_DUPHANDLE
curl_default = get_curl_handle(); curl_default = get_curl_handle();
#endif #endif
@ -322,15 +364,14 @@ struct active_request_slot *get_active_slot(void)
/* Wait for a slot to open up if the queue is full */ /* Wait for a slot to open up if the queue is full */
while (active_requests >= max_requests) { while (active_requests >= max_requests) {
curl_multi_perform(curlm, &num_transfers); curl_multi_perform(curlm, &num_transfers);
if (num_transfers < active_requests) { if (num_transfers < active_requests)
process_curl_messages(); process_curl_messages();
}
} }
#endif #endif
while (slot != NULL && slot->in_use) { while (slot != NULL && slot->in_use)
slot = slot->next; slot = slot->next;
}
if (slot == NULL) { if (slot == NULL) {
newslot = xmalloc(sizeof(*newslot)); newslot = xmalloc(sizeof(*newslot));
newslot->curl = NULL; newslot->curl = NULL;
@ -341,9 +382,8 @@ struct active_request_slot *get_active_slot(void)
if (slot == NULL) { if (slot == NULL) {
active_queue_head = newslot; active_queue_head = newslot;
} else { } else {
while (slot->next != NULL) { while (slot->next != NULL)
slot = slot->next; slot = slot->next;
}
slot->next = newslot; slot->next = newslot;
} }
slot = newslot; slot = newslot;
@ -404,7 +444,7 @@ struct fill_chain {
struct fill_chain *next; struct fill_chain *next;
}; };
static struct fill_chain *fill_cfg = NULL; static struct fill_chain *fill_cfg;
void add_fill_function(void *data, int (*fill)(void *)) void add_fill_function(void *data, int (*fill)(void *))
{ {
@ -535,9 +575,8 @@ static void finish_active_slot(struct active_request_slot *slot)
} }
/* Run callback if appropriate */ /* Run callback if appropriate */
if (slot->callback_func != NULL) { if (slot->callback_func != NULL)
slot->callback_func(slot->callback_data); slot->callback_func(slot->callback_data);
}
} }
void finish_all_active_slots(void) void finish_all_active_slots(void)
@ -567,8 +606,10 @@ static inline int needs_quote(int ch)
static inline int hex(int v) static inline int hex(int v)
{ {
if (v < 10) return '0' + v; if (v < 10)
else return 'A' + v - 10; return '0' + v;
else
return 'A' + v - 10;
} }
static char *quote_ref_url(const char *base, const char *ref) static char *quote_ref_url(const char *base, const char *ref)