X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=http-push.c;h=fe925609b4024119c6171dd32350a6570bea8516;hb=d5a6aafc90a14382120727e4e81ee1a380e8b194;hp=afdcd8b8d381753620c83f157666b4e7617ea19a;hpb=29508e1efb8d5a18f78ca0f9be45fdde49ef6b76;p=git.git diff --git a/http-push.c b/http-push.c index afdcd8b8..fe925609 100644 --- a/http-push.c +++ b/http-push.c @@ -6,8 +6,6 @@ #include "blob.h" #include "http.h" -#ifdef USE_CURL_MULTI - #include static const char http_push_usage[] = @@ -24,13 +22,28 @@ enum XML_Status { #define RANGE_HEADER_SIZE 30 -/* DAV method names and request body templates */ +/* DAV methods */ #define DAV_LOCK "LOCK" #define DAV_MKCOL "MKCOL" #define DAV_MOVE "MOVE" #define DAV_PROPFIND "PROPFIND" #define DAV_PUT "PUT" #define DAV_UNLOCK "UNLOCK" + +/* DAV lock flags */ +#define DAV_PROP_LOCKWR (1u << 0) +#define DAV_PROP_LOCKEX (1u << 1) +#define DAV_LOCK_OK (1u << 2) + +/* DAV XML properties */ +#define DAV_CTX_LOCKENTRY ".multistatus.response.propstat.prop.supportedlock.lockentry" +#define DAV_CTX_LOCKTYPE_WRITE ".multistatus.response.propstat.prop.supportedlock.lockentry.locktype.write" +#define DAV_CTX_LOCKTYPE_EXCLUSIVE ".multistatus.response.propstat.prop.supportedlock.lockentry.lockscope.exclusive" +#define DAV_ACTIVELOCK_OWNER ".prop.lockdiscovery.activelock.owner.href" +#define DAV_ACTIVELOCK_TIMEOUT ".prop.lockdiscovery.activelock.timeout" +#define DAV_ACTIVELOCK_TOKEN ".prop.lockdiscovery.activelock.locktoken.href" + +/* DAV request body templates */ #define PROPFIND_REQUEST "\n\n\n\n\n" #define LOCK_REQUEST "\n\n\n\n\nmailto:%s\n\n" @@ -92,14 +105,17 @@ struct transfer_request static struct transfer_request *request_queue_head = NULL; +struct xml_ctx +{ + char *name; + int len; + char *cdata; + void (*userFunc)(struct xml_ctx *ctx, int tag_closed); + void *userData; +}; + struct active_lock { - int ctx_activelock; - int ctx_owner; - int ctx_owner_href; - int ctx_timeout; - int ctx_locktoken; - int ctx_locktoken_href; char *url; char *owner; char *token; @@ -108,16 +124,6 @@ struct active_lock int refreshing; }; -struct lockprop -{ - int supported_lock; - int lock_entry; - int lock_scope; - int lock_type; - int lock_exclusive; - int lock_exclusive_write; -}; - static void finish_request(struct transfer_request *request); static void process_response(void *callback_data) @@ -157,6 +163,7 @@ static void start_check(struct transfer_request *request) } else { request->state = ABORTED; free(request->url); + request->url = NULL; } } @@ -190,6 +197,7 @@ static void start_mkcol(struct transfer_request *request) } else { request->state = ABORTED; free(request->url); + request->url = NULL; } } @@ -236,8 +244,6 @@ static void start_put(struct transfer_request *request) request->buffer.size = stream.total_out; request->buffer.posn = 0; - if (request->url != NULL) - free(request->url); request->url = xmalloc(strlen(remote->url) + strlen(request->lock->token) + 51); strcpy(request->url, remote->url); @@ -273,6 +279,7 @@ static void start_put(struct transfer_request *request) } else { request->state = ABORTED; free(request->url); + request->url = NULL; } } @@ -298,6 +305,7 @@ static void start_move(struct transfer_request *request) } else { request->state = ABORTED; free(request->url); + request->url = NULL; } } @@ -362,6 +370,13 @@ static void finish_request(struct transfer_request *request) if (request->headers != NULL) curl_slist_free_all(request->headers); + + /* URL is reused for MOVE after PUT */ + if (request->state != RUN_PUT) { + free(request->url); + request->url = NULL; + } + if (request->state == RUN_HEAD) { if (request->http_code == 404) { request->state = NEED_PUSH; @@ -427,7 +442,8 @@ static void release_request(struct transfer_request *request) entry->next = entry->next->next; } - free(request->url); + if (request->url != NULL) + free(request->url); free(request); } @@ -567,6 +583,7 @@ static int fetch_index(unsigned char *sha1) } } else { free(url); + fclose(indexfile); return error("Unable to start request"); } @@ -734,107 +751,101 @@ int fetch_ref(char *ref, unsigned char *sha1) return 0; } -static void -start_activelock_element(void *userData, const char *name, const char **atts) +static void handle_lockprop_ctx(struct xml_ctx *ctx, int tag_closed) { - struct active_lock *lock = (struct active_lock *)userData; - - if (lock->ctx_activelock && !strcmp(name, "D:timeout")) - lock->ctx_timeout = 1; - else if (lock->ctx_owner && strstr(name, "href")) - lock->ctx_owner_href = 1; - else if (lock->ctx_activelock && strstr(name, "owner")) - lock->ctx_owner = 1; - else if (lock->ctx_locktoken && !strcmp(name, "D:href")) - lock->ctx_locktoken_href = 1; - else if (lock->ctx_activelock && !strcmp(name, "D:locktoken")) - lock->ctx_locktoken = 1; - else if (!strcmp(name, "D:activelock")) - lock->ctx_activelock = 1; + int *lock_flags = (int *)ctx->userData; + + if (tag_closed) { + if (!strcmp(ctx->name, DAV_CTX_LOCKENTRY)) { + if ((*lock_flags & DAV_PROP_LOCKEX) && + (*lock_flags & DAV_PROP_LOCKWR)) { + *lock_flags |= DAV_LOCK_OK; + } + *lock_flags &= DAV_LOCK_OK; + } else if (!strcmp(ctx->name, DAV_CTX_LOCKTYPE_WRITE)) { + *lock_flags |= DAV_PROP_LOCKWR; + } else if (!strcmp(ctx->name, DAV_CTX_LOCKTYPE_EXCLUSIVE)) { + *lock_flags |= DAV_PROP_LOCKEX; + } + } } -static void -end_activelock_element(void *userData, const char *name) +static void handle_new_lock_ctx(struct xml_ctx *ctx, int tag_closed) { - struct active_lock *lock = (struct active_lock *)userData; - - if (lock->ctx_timeout && !strcmp(name, "D:timeout")) { - lock->ctx_timeout = 0; - } else if (lock->ctx_owner_href && strstr(name, "href")) { - lock->ctx_owner_href = 0; - } else if (lock->ctx_owner && strstr(name, "owner")) { - lock->ctx_owner = 0; - } else if (lock->ctx_locktoken_href && !strcmp(name, "D:href")) { - lock->ctx_locktoken_href = 0; - } else if (lock->ctx_locktoken && !strcmp(name, "D:locktoken")) { - lock->ctx_locktoken = 0; - } else if (lock->ctx_activelock && !strcmp(name, "D:activelock")) { - lock->ctx_activelock = 0; + struct active_lock *lock = (struct active_lock *)ctx->userData; + + if (tag_closed && ctx->cdata) { + if (!strcmp(ctx->name, DAV_ACTIVELOCK_OWNER)) { + lock->owner = xmalloc(strlen(ctx->cdata) + 1); + strcpy(lock->owner, ctx->cdata); + } else if (!strcmp(ctx->name, DAV_ACTIVELOCK_TIMEOUT)) { + if (!strncmp(ctx->cdata, "Second-", 7)) + lock->timeout = + strtol(ctx->cdata + 7, NULL, 10); + } else if (!strcmp(ctx->name, DAV_ACTIVELOCK_TOKEN)) { + if (!strncmp(ctx->cdata, "opaquelocktoken:", 16)) { + lock->token = xmalloc(strlen(ctx->cdata) - 15); + strcpy(lock->token, ctx->cdata + 16); + } + } } } static void -activelock_cdata(void *userData, const XML_Char *s, int len) +xml_start_tag(void *userData, const char *name, const char **atts) { - struct active_lock *lock = (struct active_lock *)userData; - char *this = malloc(len+1); - strncpy(this, s, len); - - if (lock->ctx_owner_href) { - lock->owner = malloc(len+1); - strcpy(lock->owner, this); - } else if (lock->ctx_locktoken_href) { - if (!strncmp(this, "opaquelocktoken:", 16)) { - lock->token = malloc(len-15); - strcpy(lock->token, this+16); - } - } else if (lock->ctx_timeout) { - if (!strncmp(this, "Second-", 7)) - lock->timeout = strtol(this+7, NULL, 10); + struct xml_ctx *ctx = (struct xml_ctx *)userData; + const char *c = index(name, ':'); + int new_len; + + if (c == NULL) + c = name; + else + c++; + + new_len = strlen(ctx->name) + strlen(c) + 2; + + if (new_len > ctx->len) { + ctx->name = xrealloc(ctx->name, new_len); + ctx->len = new_len; } + strcat(ctx->name, "."); + strcat(ctx->name, c); - free(this); + if (ctx->cdata) { + free(ctx->cdata); + ctx->cdata = NULL; + } + + ctx->userFunc(ctx, 0); } static void -start_lockprop_element(void *userData, const char *name, const char **atts) +xml_end_tag(void *userData, const char *name) { - struct lockprop *prop = (struct lockprop *)userData; + struct xml_ctx *ctx = (struct xml_ctx *)userData; + const char *c = index(name, ':'); + char *ep; - if (prop->lock_type && !strcmp(name, "D:write")) { - if (prop->lock_exclusive) { - prop->lock_exclusive_write = 1; - } - } else if (prop->lock_scope && !strcmp(name, "D:exclusive")) { - prop->lock_exclusive = 1; - } else if (prop->lock_entry) { - if (!strcmp(name, "D:lockscope")) { - prop->lock_scope = 1; - } else if (!strcmp(name, "D:locktype")) { - prop->lock_type = 1; - } - } else if (prop->supported_lock) { - if (!strcmp(name, "D:lockentry")) { - prop->lock_entry = 1; - } - } else if (!strcmp(name, "D:supportedlock")) { - prop->supported_lock = 1; - } + ctx->userFunc(ctx, 1); + + if (c == NULL) + c = name; + else + c++; + + ep = ctx->name + strlen(ctx->name) - strlen(c) - 1; + *ep = 0; } static void -end_lockprop_element(void *userData, const char *name) +xml_cdata(void *userData, const XML_Char *s, int len) { - struct lockprop *prop = (struct lockprop *)userData; - - if (!strcmp(name, "D:lockentry")) { - prop->lock_entry = 0; - prop->lock_scope = 0; - prop->lock_type = 0; - prop->lock_exclusive = 0; - } else if (!strcmp(name, "D:supportedlock")) { - prop->supported_lock = 0; - } + struct xml_ctx *ctx = (struct xml_ctx *)userData; + if (ctx->cdata) + free(ctx->cdata); + ctx->cdata = xcalloc(len+1, 1); + strncpy(ctx->cdata, s, len); } static struct active_lock *lock_remote(char *file, long timeout) @@ -847,10 +858,11 @@ static struct active_lock *lock_remote(char *file, long timeout) char *url; char *ep; char timeout_header[25]; - struct active_lock *new_lock; + struct active_lock *new_lock = NULL; XML_Parser parser = XML_ParserCreate(NULL); enum XML_Status result; struct curl_slist *dav_headers = NULL; + struct xml_ctx ctx; url = xmalloc(strlen(remote->url) + strlen(file) + 1); sprintf(url, "%s%s", remote->url, file); @@ -894,12 +906,6 @@ static struct active_lock *lock_remote(char *file, long timeout) in_buffer.posn = 0; in_buffer.buffer = in_data; - new_lock = xcalloc(1, sizeof(*new_lock)); - new_lock->owner = NULL; - new_lock->token = NULL; - new_lock->timeout = -1; - new_lock->refreshing = 0; - sprintf(timeout_header, "Timeout: Second-%ld", timeout); dav_headers = curl_slist_append(dav_headers, timeout_header); dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml"); @@ -915,40 +921,41 @@ static struct active_lock *lock_remote(char *file, long timeout) curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_LOCK); curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers); + new_lock = xcalloc(1, sizeof(*new_lock)); + new_lock->owner = NULL; + new_lock->token = NULL; + new_lock->timeout = -1; + new_lock->refreshing = 0; + if (start_active_slot(slot)) { run_active_slot(slot); - if (slot->curl_result != CURLE_OK) { - fprintf(stderr, "Got HTTP error %ld\n", slot->http_code); - free(new_lock); - free(url); - free(out_data); - free(in_data); - return NULL; + if (slot->curl_result == CURLE_OK) { + ctx.name = xcalloc(10, 1); + ctx.len = 0; + ctx.cdata = NULL; + ctx.userFunc = handle_new_lock_ctx; + ctx.userData = new_lock; + XML_SetUserData(parser, &ctx); + XML_SetElementHandler(parser, xml_start_tag, + xml_end_tag); + XML_SetCharacterDataHandler(parser, xml_cdata); + result = XML_Parse(parser, in_buffer.buffer, + in_buffer.posn, 1); + free(ctx.name); + if (result != XML_STATUS_OK) { + fprintf(stderr, "XML error: %s\n", + XML_ErrorString( + XML_GetErrorCode(parser))); + new_lock->timeout = -1; + } } } else { - free(new_lock); - free(url); - free(out_data); - free(in_data); fprintf(stderr, "Unable to start request\n"); - return NULL; } + curl_slist_free_all(dav_headers); free(out_data); - - XML_SetUserData(parser, new_lock); - XML_SetElementHandler(parser, start_activelock_element, - end_activelock_element); - XML_SetCharacterDataHandler(parser, activelock_cdata); - result = XML_Parse(parser, in_buffer.buffer, in_buffer.posn, 1); free(in_data); - if (result != XML_STATUS_OK) { - fprintf(stderr, "%s", XML_ErrorString( - XML_GetErrorCode(parser))); - free(url); - free(new_lock); - return NULL; - } if (new_lock->token == NULL || new_lock->timeout <= 0) { if (new_lock->token != NULL) @@ -957,11 +964,12 @@ static struct active_lock *lock_remote(char *file, long timeout) free(new_lock->owner); free(url); free(new_lock); - return NULL; + new_lock = NULL; + } else { + new_lock->url = url; + new_lock->start_time = time(NULL); } - new_lock->url = url; - new_lock->start_time = time(NULL); return new_lock; } @@ -1006,7 +1014,7 @@ static int unlock_remote(struct active_lock *lock) return rc; } -static int check_locking(void) +static int locking_available(void) { struct active_request_slot *slot; struct buffer in_buffer; @@ -1015,8 +1023,9 @@ static int check_locking(void) char *out_data; XML_Parser parser = XML_ParserCreate(NULL); enum XML_Status result; - struct lockprop supported_lock; struct curl_slist *dav_headers = NULL; + struct xml_ctx ctx; + int lock_flags = 0; out_buffer.size = strlen(PROPFIND_REQUEST) + strlen(remote->url) - 2; out_data = xmalloc(out_buffer.size + 1); @@ -1045,30 +1054,35 @@ static int check_locking(void) if (start_active_slot(slot)) { run_active_slot(slot); - free(out_data); - if (slot->curl_result != CURLE_OK) { - free(in_buffer.buffer); - return -1; + if (slot->curl_result == CURLE_OK) { + ctx.name = xcalloc(10, 1); + ctx.len = 0; + ctx.cdata = NULL; + ctx.userFunc = handle_lockprop_ctx; + ctx.userData = &lock_flags; + XML_SetUserData(parser, &ctx); + XML_SetElementHandler(parser, xml_start_tag, + xml_end_tag); + result = XML_Parse(parser, in_buffer.buffer, + in_buffer.posn, 1); + free(ctx.name); + + if (result != XML_STATUS_OK) { + fprintf(stderr, "XML error: %s\n", + XML_ErrorString( + XML_GetErrorCode(parser))); + lock_flags = 0; + } } - - XML_SetUserData(parser, &supported_lock); - XML_SetElementHandler(parser, start_lockprop_element, - end_lockprop_element); - result = XML_Parse(parser, in_buffer.buffer, in_buffer.posn, 1); - free(in_buffer.buffer); - if (result != XML_STATUS_OK) - return error("%s", XML_ErrorString( - XML_GetErrorCode(parser))); } else { - free(out_data); - free(in_buffer.buffer); - return error("Unable to start request"); + fprintf(stderr, "Unable to start request\n"); } - if (supported_lock.lock_exclusive_write) - return 0; - else - return 1; + free(out_data); + free(in_buffer.buffer); + curl_slist_free_all(dav_headers); + + return lock_flags; } static int is_ancestor(unsigned char *sha1, struct commit *commit) @@ -1223,6 +1237,7 @@ int main(int argc, char **argv) int rc = 0; int i; + setup_git_directory(); setup_ident(); remote = xmalloc(sizeof(*remote)); @@ -1257,6 +1272,9 @@ int main(int argc, char **argv) break; } + if (!remote->url) + usage(http_push_usage); + memset(remote_dir_exists, 0, 256); http_init(); @@ -1269,7 +1287,7 @@ int main(int argc, char **argv) "Pragma: no-cache"); /* Verify DAV compliance/lock support */ - if (check_locking() != 0) { + if (!locking_available()) { fprintf(stderr, "Error: no DAV locking support on remote repo %s\n", remote->url); rc = 1; goto cleanup; @@ -1408,10 +1426,3 @@ int main(int argc, char **argv) return rc; } -#else /* ifdef USE_CURL_MULTI */ -int main(int argc, char **argv) -{ - fprintf(stderr, "http-push requires curl 7.9.8 or higher.\n"); - return 1; -} -#endif