diff options
Diffstat (limited to 'http-push.c')
-rw-r--r-- | http-push.c | 221 |
1 files changed, 125 insertions, 96 deletions
diff --git a/http-push.c b/http-push.c index 6805288857..30d2d34041 100644 --- a/http-push.c +++ b/http-push.c @@ -10,6 +10,7 @@ #include "exec_cmd.h" #include "remote.h" #include "list-objects.h" +#include "sigchain.h" #include <expat.h> @@ -87,6 +88,7 @@ static struct object_list *objects; struct repo { char *url; + char *path; int path_len; int has_info_refs; int can_update_info_refs; @@ -126,7 +128,7 @@ struct transfer_request char errorstr[CURL_ERROR_SIZE]; long http_code; unsigned char real_sha1[20]; - SHA_CTX c; + git_SHA_CTX c; z_stream stream; int zret; int rename; @@ -151,6 +153,7 @@ struct remote_lock char *url; char *owner; char *token; + char tmpfile_suffix[41]; time_t start_time; long timeout; int refreshing; @@ -176,6 +179,47 @@ struct remote_ls_ctx struct remote_ls_ctx *parent; }; +/* get_dav_token_headers options */ +enum dav_header_flag { + DAV_HEADER_IF = (1u << 0), + DAV_HEADER_LOCK = (1u << 1), + DAV_HEADER_TIMEOUT = (1u << 2) +}; + +static struct curl_slist *get_dav_token_headers(struct remote_lock *lock, enum dav_header_flag options) +{ + struct strbuf buf = STRBUF_INIT; + struct curl_slist *dav_headers = NULL; + + if (options & DAV_HEADER_IF) { + strbuf_addf(&buf, "If: (<%s>)", lock->token); + dav_headers = curl_slist_append(dav_headers, buf.buf); + strbuf_reset(&buf); + } + if (options & DAV_HEADER_LOCK) { + strbuf_addf(&buf, "Lock-Token: <%s>", lock->token); + dav_headers = curl_slist_append(dav_headers, buf.buf); + strbuf_reset(&buf); + } + if (options & DAV_HEADER_TIMEOUT) { + strbuf_addf(&buf, "Timeout: Second-%ld", lock->timeout); + dav_headers = curl_slist_append(dav_headers, buf.buf); + strbuf_reset(&buf); + } + strbuf_release(&buf); + + return dav_headers; +} + +static void append_remote_object_url(struct strbuf *buf, const char *url, + const char *hex, + int only_two_digit_prefix) +{ + strbuf_addf(buf, "%sobjects/%.*s/", url, 2, hex); + if (!only_two_digit_prefix) + strbuf_addf(buf, "%s", hex+2); +} + static void finish_request(struct transfer_request *request); static void release_request(struct transfer_request *request); @@ -188,6 +232,15 @@ static void process_response(void *callback_data) } #ifdef USE_CURL_MULTI + +static char *get_remote_object_url(const char *url, const char *hex, + int only_two_digit_prefix) +{ + struct strbuf buf = STRBUF_INIT; + append_remote_object_url(&buf, url, hex, only_two_digit_prefix); + return strbuf_detach(&buf, NULL); +} + static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb, void *data) { @@ -208,8 +261,8 @@ static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb, do { request->stream.next_out = expn; request->stream.avail_out = sizeof(expn); - request->zret = inflate(&request->stream, Z_SYNC_FLUSH); - SHA1_Update(&request->c, expn, + request->zret = git_inflate(&request->stream, Z_SYNC_FLUSH); + git_SHA1_Update(&request->c, expn, sizeof(expn) - request->stream.avail_out); } while (request->stream.avail_in && request->zret == Z_OK); data_received++; @@ -222,7 +275,6 @@ static void start_fetch_loose(struct transfer_request *request) char *filename; char prevfile[PATH_MAX]; char *url; - char *posn; int prevlocal; unsigned char prev_buf[PREV_BUF_SIZE]; ssize_t prev_read = 0; @@ -268,21 +320,12 @@ static void start_fetch_loose(struct transfer_request *request) memset(&request->stream, 0, sizeof(request->stream)); - inflateInit(&request->stream); + git_inflate_init(&request->stream); - SHA1_Init(&request->c); + git_SHA1_Init(&request->c); - url = xmalloc(strlen(remote->url) + 50); - request->url = xmalloc(strlen(remote->url) + 50); - strcpy(url, remote->url); - posn = url + strlen(remote->url); - strcpy(posn, "objects/"); - posn += 8; - memcpy(posn, hex, 2); - posn += 2; - *(posn++) = '/'; - strcpy(posn, hex + 2); - strcpy(request->url, url); + url = get_remote_object_url(remote->url, hex, 0); + request->url = xstrdup(url); /* If a previous temp file is present, process what was already fetched. */ @@ -309,8 +352,8 @@ static void start_fetch_loose(struct transfer_request *request) file; also rewind to the beginning of the local file. */ if (prev_read == -1) { memset(&request->stream, 0, sizeof(request->stream)); - inflateInit(&request->stream); - SHA1_Init(&request->c); + git_inflate_init(&request->stream); + git_SHA1_Init(&request->c); if (prev_posn>0) { prev_posn = 0; lseek(request->local_fileno, 0, SEEK_SET); @@ -355,16 +398,8 @@ static void start_mkcol(struct transfer_request *request) { char *hex = sha1_to_hex(request->obj->sha1); struct active_request_slot *slot; - char *posn; - request->url = xmalloc(strlen(remote->url) + 13); - strcpy(request->url, remote->url); - posn = request->url + strlen(remote->url); - strcpy(posn, "objects/"); - posn += 8; - memcpy(posn, hex, 2); - posn += 2; - strcpy(posn, "/"); + request->url = get_remote_object_url(remote->url, hex, 1); slot = get_active_slot(); slot->callback_func = process_response; @@ -479,7 +514,7 @@ static void start_put(struct transfer_request *request) { char *hex = sha1_to_hex(request->obj->sha1); struct active_request_slot *slot; - char *posn; + struct strbuf buf = STRBUF_INIT; enum object_type type; char hdr[50]; void *unpacked; @@ -518,21 +553,13 @@ static void start_put(struct transfer_request *request) request->buffer.buf.len = stream.total_out; - request->url = xmalloc(strlen(remote->url) + - strlen(request->lock->token) + 51); - strcpy(request->url, remote->url); - posn = request->url + strlen(remote->url); - strcpy(posn, "objects/"); - posn += 8; - memcpy(posn, hex, 2); - posn += 2; - *(posn++) = '/'; - strcpy(posn, hex + 2); - request->dest = xmalloc(strlen(request->url) + 14); - sprintf(request->dest, "Destination: %s", request->url); - posn += 38; - *(posn++) = '_'; - strcpy(posn, request->lock->token); + strbuf_addstr(&buf, "Destination: "); + append_remote_object_url(&buf, remote->url, hex, 0); + request->dest = strbuf_detach(&buf, NULL); + + append_remote_object_url(&buf, remote->url, hex, 0); + strbuf_add(&buf, request->lock->tmpfile_suffix, 41); + request->url = strbuf_detach(&buf, NULL); slot = get_active_slot(); slot->callback_func = process_response; @@ -587,18 +614,12 @@ static int refresh_lock(struct remote_lock *lock) { struct active_request_slot *slot; struct slot_results results; - char *if_header; - char timeout_header[25]; - struct curl_slist *dav_headers = NULL; + struct curl_slist *dav_headers; int rc = 0; lock->refreshing = 1; - if_header = xmalloc(strlen(lock->token) + 25); - sprintf(if_header, "If: (<opaquelocktoken:%s>)", lock->token); - sprintf(timeout_header, "Timeout: Second-%ld", lock->timeout); - dav_headers = curl_slist_append(dav_headers, if_header); - dav_headers = curl_slist_append(dav_headers, timeout_header); + dav_headers = get_dav_token_headers(lock, DAV_HEADER_IF | DAV_HEADER_TIMEOUT); slot = get_active_slot(); slot->results = &results; @@ -621,7 +642,6 @@ static int refresh_lock(struct remote_lock *lock) lock->refreshing = 0; curl_slist_free_all(dav_headers); - free(if_header); return rc; } @@ -741,8 +761,8 @@ static void finish_request(struct transfer_request *request) if (request->http_code == 416) fprintf(stderr, "Warning: requested range invalid; we may already have all the data.\n"); - inflateEnd(&request->stream); - SHA1_Final(request->real_sha1, &request->c); + git_inflate_end(&request->stream); + git_SHA1_Final(request->real_sha1, &request->c); if (request->zret != Z_STREAM_END) { unlink(request->tmpfile); } else if (hashcmp(request->obj->sha1, request->real_sha1)) { @@ -1110,6 +1130,8 @@ static void handle_lockprop_ctx(struct xml_ctx *ctx, int tag_closed) static void handle_new_lock_ctx(struct xml_ctx *ctx, int tag_closed) { struct remote_lock *lock = (struct remote_lock *)ctx->userData; + git_SHA_CTX sha_ctx; + unsigned char lock_token_sha1[20]; if (tag_closed && ctx->cdata) { if (!strcmp(ctx->name, DAV_ACTIVELOCK_OWNER)) { @@ -1120,10 +1142,15 @@ static void handle_new_lock_ctx(struct xml_ctx *ctx, int tag_closed) lock->timeout = strtol(ctx->cdata + 7, NULL, 10); } else if (!strcmp(ctx->name, DAV_ACTIVELOCK_TOKEN)) { - if (!prefixcmp(ctx->cdata, "opaquelocktoken:")) { - lock->token = xmalloc(strlen(ctx->cdata) - 15); - strcpy(lock->token, ctx->cdata + 16); - } + lock->token = xmalloc(strlen(ctx->cdata) + 1); + strcpy(lock->token, ctx->cdata); + + git_SHA1_Init(&sha_ctx); + git_SHA1_Update(&sha_ctx, lock->token, strlen(lock->token)); + git_SHA1_Final(lock_token_sha1, &sha_ctx); + + lock->tmpfile_suffix[0] = '_'; + memcpy(lock->tmpfile_suffix + 1, sha1_to_hex(lock_token_sha1), 40); } } } @@ -1202,7 +1229,8 @@ static struct remote_lock *lock_remote(const char *path, long timeout) /* Make sure leading directories exist for the remote ref */ ep = strchr(url + strlen(remote->url) + 1, '/'); while (ep) { - *ep = 0; + char saved_character = ep[1]; + ep[1] = '\0'; slot = get_active_slot(); slot->results = &results; curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1); @@ -1224,7 +1252,7 @@ static struct remote_lock *lock_remote(const char *path, long timeout) free(url); return NULL; } - *ep = '/'; + ep[1] = saved_character; ep = strchr(ep + 1, '/'); } @@ -1303,14 +1331,10 @@ static int unlock_remote(struct remote_lock *lock) struct active_request_slot *slot; struct slot_results results; struct remote_lock *prev = remote->locks; - char *lock_token_header; - struct curl_slist *dav_headers = NULL; + struct curl_slist *dav_headers; int rc = 0; - lock_token_header = xmalloc(strlen(lock->token) + 31); - sprintf(lock_token_header, "Lock-Token: <opaquelocktoken:%s>", - lock->token); - dav_headers = curl_slist_append(dav_headers, lock_token_header); + dav_headers = get_dav_token_headers(lock, DAV_HEADER_LOCK); slot = get_active_slot(); slot->results = &results; @@ -1331,7 +1355,6 @@ static int unlock_remote(struct remote_lock *lock) } curl_slist_free_all(dav_headers); - free(lock_token_header); if (remote->locks == lock) { remote->locks = lock->next; @@ -1364,7 +1387,7 @@ static void remove_locks(void) static void remove_locks_on_signal(int signo) { remove_locks(); - signal(signo, SIG_DFL); + sigchain_pop(signo); raise(signo); } @@ -1426,9 +1449,17 @@ static void handle_remote_ls_ctx(struct xml_ctx *ctx, int tag_closed) ls->userFunc(ls); } } else if (!strcmp(ctx->name, DAV_PROPFIND_NAME) && ctx->cdata) { - ls->dentry_name = xmalloc(strlen(ctx->cdata) - - remote->path_len + 1); - strcpy(ls->dentry_name, ctx->cdata + remote->path_len); + char *path = ctx->cdata; + if (*ctx->cdata == 'h') { + path = strstr(path, "//"); + if (path) { + path = strchr(path+2, '/'); + } + } + if (path) { + path += remote->path_len; + ls->dentry_name = xstrdup(path); + } } else if (!strcmp(ctx->name, DAV_PROPFIND_COLLECTION)) { ls->dentry_flags |= IS_DIR; } @@ -1439,6 +1470,12 @@ static void handle_remote_ls_ctx(struct xml_ctx *ctx, int tag_closed) } } +/* + * NEEDSWORK: remote_ls() ignores info/refs on the remote side. But it + * should _only_ heed the information from that file, instead of trying to + * determine the refs from the remote file system (badly: it does not even + * know about packed-refs). + */ static void remote_ls(const char *path, int flags, void (*userFunc)(struct remote_ls_ctx *ls), void *userData) @@ -1717,13 +1754,10 @@ static int update_remote(unsigned char *sha1, struct remote_lock *lock) { struct active_request_slot *slot; struct slot_results results; - char *if_header; struct buffer out_buffer = { STRBUF_INIT, 0 }; - struct curl_slist *dav_headers = NULL; + struct curl_slist *dav_headers; - if_header = xmalloc(strlen(lock->token) + 25); - sprintf(if_header, "If: (<opaquelocktoken:%s>)", lock->token); - dav_headers = curl_slist_append(dav_headers, if_header); + dav_headers = get_dav_token_headers(lock, DAV_HEADER_IF); strbuf_addf(&out_buffer.buf, "%s\n", sha1_to_hex(sha1)); @@ -1742,7 +1776,6 @@ static int update_remote(unsigned char *sha1, struct remote_lock *lock) if (start_active_slot(slot)) { run_active_slot(slot); strbuf_release(&out_buffer.buf); - free(if_header); if (results.curl_result != CURLE_OK) { fprintf(stderr, "PUT error: curl result=%d, HTTP code=%ld\n", @@ -1752,7 +1785,6 @@ static int update_remote(unsigned char *sha1, struct remote_lock *lock) } } else { strbuf_release(&out_buffer.buf); - free(if_header); fprintf(stderr, "Unable to start PUT request\n"); return 0; } @@ -1780,7 +1812,7 @@ static void one_remote_ref(char *refname) struct ref *ref; struct object *obj; - ref = alloc_ref_from_str(refname); + ref = alloc_ref(refname); if (http_fetch_ref(remote->url, ref) != 0) { fprintf(stderr, @@ -1887,7 +1919,7 @@ static void add_remote_info_ref(struct remote_ls_ctx *ls) char *ref_info; struct ref *ref; - ref = alloc_ref_from_str(ls->dentry_name); + ref = alloc_ref(ls->dentry_name); if (http_fetch_ref(remote->url, ref) != 0) { fprintf(stderr, @@ -1934,15 +1966,12 @@ static void update_remote_info_refs(struct remote_lock *lock) struct buffer buffer = { STRBUF_INIT, 0 }; struct active_request_slot *slot; struct slot_results results; - char *if_header; - struct curl_slist *dav_headers = NULL; + struct curl_slist *dav_headers; remote_ls("refs/", (PROCESS_FILES | RECURSIVE), add_remote_info_ref, &buffer.buf); if (!aborted) { - if_header = xmalloc(strlen(lock->token) + 25); - sprintf(if_header, "If: (<opaquelocktoken:%s>)", lock->token); - dav_headers = curl_slist_append(dav_headers, if_header); + dav_headers = get_dav_token_headers(lock, DAV_HEADER_IF); slot = get_active_slot(); slot->results = &results; @@ -1964,7 +1993,6 @@ static void update_remote_info_refs(struct remote_lock *lock) results.curl_result, results.http_code); } } - free(if_header); } strbuf_release(&buffer.buf); } @@ -2170,6 +2198,8 @@ int main(int argc, char **argv) struct ref *ref; char *rewritten_url = NULL; + git_extract_argv0_path(argv[0]); + setup_git_directory(); remote = xcalloc(sizeof(*remote), 1); @@ -2208,10 +2238,11 @@ int main(int argc, char **argv) if (!remote->url) { char *path = strstr(arg, "//"); remote->url = arg; + remote->path_len = strlen(arg); if (path) { - path = strchr(path+2, '/'); - if (path) - remote->path_len = strlen(path); + remote->path = strchr(path+2, '/'); + if (remote->path) + remote->path_len = strlen(remote->path); } continue; } @@ -2237,11 +2268,12 @@ int main(int argc, char **argv) no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:"); if (remote->url && remote->url[strlen(remote->url)-1] != '/') { - rewritten_url = malloc(strlen(remote->url)+2); + rewritten_url = xmalloc(strlen(remote->url)+2); strcpy(rewritten_url, remote->url); strcat(rewritten_url, "/"); + remote->path = rewritten_url + (remote->path - remote->url); + remote->path_len++; remote->url = rewritten_url; - ++remote->path_len; } /* Verify DAV compliance/lock support */ @@ -2250,10 +2282,7 @@ int main(int argc, char **argv) goto cleanup; } - signal(SIGINT, remove_locks_on_signal); - signal(SIGHUP, remove_locks_on_signal); - signal(SIGQUIT, remove_locks_on_signal); - signal(SIGTERM, remove_locks_on_signal); + sigchain_push_common(remove_locks_on_signal); /* Check whether the remote has server info files */ remote->can_update_info_refs = 0; |