All of lore.kernel.org
 help / color / mirror / Atom feed
From: Nick Hengeveld <nickh@reactrix.com>
To: git@vger.kernel.org
Subject: [PATCH 3/4] Improve lock handling
Date: Fri, 4 Nov 2005 14:22:31 -0800	[thread overview]
Message-ID: <20051104222231.GF3001@reactrix.com> (raw)

Improve lock handling: parse the server response for the timeout, owner,
and lock token

Signed-off-by: Nick Hengeveld <nickh@reactrix.com>


---

 http-push.c |  201 +++++++++++++++++++++++++++++++++++++++++++----------------
 1 files changed, 147 insertions(+), 54 deletions(-)

applies-to: 99366e40c96e3fd0436287c601697f3166e8cf36
1b26b4528dc9e14f2be5d57154022249206fcc6f
diff --git a/http-push.c b/http-push.c
index 6a241aa..85cd595 100644
--- a/http-push.c
+++ b/http-push.c
@@ -55,7 +55,6 @@ static CURL *curl_default;
 static struct curl_slist *no_pragma_header;
 static struct curl_slist *default_headers;
 static char curl_errorstr[CURL_ERROR_SIZE];
-static char *lock_token = NULL;
 
 static int push_verbosely = 0;
 static int push_all = 0;
@@ -92,7 +91,7 @@ struct transfer_request
 	unsigned char sha1[20];
 	char *url;
 	char *dest;
-	char *lock_token;
+	struct active_lock *lock;
 	struct curl_slist *headers;
 	struct buffer buffer;
 	char filename[PATH_MAX];
@@ -136,6 +135,20 @@ static char *ssl_cainfo = NULL;
 static long curl_low_speed_limit = -1;
 static long curl_low_speed_time = -1;
 
+struct active_lock
+{
+	int ctx_activelock;
+	int ctx_owner;
+	int ctx_owner_href;
+	int ctx_timeout;
+	int ctx_locktoken;
+	int ctx_locktoken_href;
+	char *owner;
+	time_t start_time;
+	long timeout;
+	char *token;
+};
+
 struct lockprop
 {
 	int supported_lock;
@@ -509,7 +522,7 @@ static void start_put(struct transfer_re
 	if (request->url != NULL)
 		free(request->url);
 	request->url = xmalloc(strlen(remote->url) + 
-			       strlen(request->lock_token) + 51);
+			       strlen(request->lock->token) + 51);
 	strcpy(request->url, remote->url);
 	posn = request->url + strlen(remote->url);
 	strcpy(posn, "objects/");
@@ -522,7 +535,7 @@ static void start_put(struct transfer_re
 	sprintf(request->dest, "Destination: %s", request->url);
 	posn += 38;
 	*(posn++) = '.';
-	strcpy(posn, request->lock_token);
+	strcpy(posn, request->lock->token);
 
 	slot = get_active_slot();
 	curl_easy_setopt(slot->curl, CURLOPT_INFILE, &request->buffer);
@@ -724,7 +737,7 @@ void process_waiting_requests(void)
 		}
 }
 
-void add_request(unsigned char *sha1, char *lock_token)
+void add_request(unsigned char *sha1, struct active_lock *lock)
 {
 	struct transfer_request *request = request_queue_head;
 	struct packed_git *target;
@@ -741,7 +754,7 @@ void add_request(unsigned char *sha1, ch
 	request = xmalloc(sizeof(*request));
 	memcpy(request->sha1, sha1, 20);
 	request->url = NULL;
-	request->lock_token = lock_token;
+	request->lock = lock;
 	request->headers = NULL;
 	request->state = NEED_CHECK;
 	request->next = request_queue_head;
@@ -999,6 +1012,68 @@ int fetch_ref(char *ref, unsigned char *
 }
 
 static void
+start_activelock_element(void *userData, const char *name, const char **atts)
+{
+	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;
+}
+
+static void
+end_activelock_element(void *userData, const char *name)
+{
+	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;
+	}
+}
+
+static void
+activelock_cdata(void *userData, const XML_Char *s, int len)
+{
+	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);
+	}
+
+	free(this);
+}
+
+static void
 start_lockprop_element(void *userData, const char *name, const char **atts)
 {
 	struct lockprop *prop = (struct lockprop *)userData;
@@ -1039,40 +1114,21 @@ end_lockprop_element(void *userData, con
 	}
 }
 
-size_t process_lock_header( void *ptr, size_t size, size_t nmemb, void *stream)
-{
-	size_t header_size = size*nmemb;
-	char *start;
-	char *end;
-
-	if (!strncmp(ptr, "Lock-Token: <opaquelocktoken:", 29)) {
-		start = ptr + 29;
-		for (end = ptr + header_size;
-		     *(end - 1) == '\r' || *(end - 1) == '\n' || *(end - 1) == '>';
-		     end--) {}
-		if (end > start) {
-			lock_token = xmalloc(end - start + 1);
-			memcpy(lock_token, start, end - start);
-			lock_token[end - start] = 0;
-		}
-	}
-
-	return header_size;
-}
-
-char *lock_remote(char *file, int timeout)
+struct active_lock *lock_remote(char *file, int timeout)
 {
 	struct active_request_slot *slot;
 	struct buffer out_buffer;
+	struct buffer in_buffer;
 	char *out_data;
+	char *in_data;
 	char *url;
 	char *ep;
 	char timeout_header[25];
+	struct active_lock *new_lock;
+	XML_Parser parser = XML_ParserCreate(NULL);
+	enum XML_Status result;
 	struct curl_slist *dav_headers = NULL;
 
-	if (lock_token != NULL)
-		free(lock_token);
-
 	url = xmalloc(strlen(remote->url) + strlen(file) + 1);
 	sprintf(url, "%s%s", remote->url, file);
 
@@ -1110,6 +1166,16 @@ char *lock_remote(char *file, int timeou
 	out_buffer.posn = 0;
 	out_buffer.buffer = out_data;
 
+	in_buffer.size = 4096;
+	in_data = xmalloc(in_buffer.size);
+	in_buffer.posn = 0;
+	in_buffer.buffer = in_data;
+
+	new_lock = xmalloc(sizeof(*new_lock));
+	new_lock->owner = NULL;
+	new_lock->token = NULL;
+	new_lock->timeout = -1;
+
 	sprintf(timeout_header, "Timeout: Second-%d", timeout);
 	dav_headers = curl_slist_append(dav_headers, timeout_header);
 	dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml");
@@ -1118,9 +1184,9 @@ char *lock_remote(char *file, int timeou
 	curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
 	curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.size);
 	curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
-	curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
-	curl_easy_setopt(slot->curl, CURLOPT_HEADERFUNCTION,
-		process_lock_header);
+	curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);
+	curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,
+			 fwrite_buffer_dynamic);
 	curl_easy_setopt(slot->curl, CURLOPT_URL, url);
 	curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);
 	curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_LOCK);
@@ -1130,13 +1196,17 @@ char *lock_remote(char *file, int timeou
 		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;
 		}
 	} else {
+		free(new_lock);
 		free(url);
 		free(out_data);
+		free(in_data);
 		fprintf(stderr, "Unable to start request\n");
 		return NULL;
 	}
@@ -1144,10 +1214,33 @@ char *lock_remote(char *file, int timeou
 	free(url);
 	free(out_data);
 
-	return strdup(lock_token);
+	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(new_lock);
+		return NULL;
+	}
+
+	if (new_lock->token == NULL || new_lock->timeout <= 0) {
+		if (new_lock->token != NULL)
+			free(new_lock->token);
+		if (new_lock->owner != NULL)
+			free(new_lock->owner);
+		free(new_lock);
+		return NULL;
+	}
+
+	new_lock->start_time = time(NULL);
+	return new_lock;
 }
 
-int unlock_remote(char *file, char *lock_token)
+int unlock_remote(char *file, struct active_lock *lock)
 {
 	struct active_request_slot *slot;
 	char *url;
@@ -1155,14 +1248,9 @@ int unlock_remote(char *file, char *lock
 	struct curl_slist *dav_headers = NULL;
 	int rc = 0;
 
-	if (lock_token == NULL) {
-		fprintf(stderr, "Unable to unlock, no lock token");
-		return 0;
-	}
-
-	lock_token_header = xmalloc(strlen(lock_token) + 31);
+	lock_token_header = xmalloc(strlen(lock->token) + 31);
 	sprintf(lock_token_header, "Lock-Token: <opaquelocktoken:%s>",
-		lock_token);
+		lock->token);
 	url = xmalloc(strlen(remote->url) + strlen(file) + 1);
 	sprintf(url, "%s%s", remote->url, file);
 	dav_headers = curl_slist_append(dav_headers, lock_token_header);
@@ -1278,7 +1366,8 @@ int is_ancestor(unsigned char *sha1, str
 	return 0;
 }
 
-void get_delta(unsigned char *sha1, struct object *obj, char *lock_token)
+void get_delta(unsigned char *sha1, struct object *obj,
+	       struct active_lock *lock)
 {
 	struct commit *commit;
 	struct commit_list *parents;
@@ -1294,7 +1383,7 @@ void get_delta(unsigned char *sha1, stru
 	if (obj->type == commit_type) {
 		if (push_verbosely)
 			fprintf(stderr, "walk %s\n", sha1_to_hex(obj->sha1));
-		add_request(obj->sha1, lock_token);
+		add_request(obj->sha1, lock);
 		commit = (struct commit *)obj;
 		if (parse_commit(commit)) {
 			fprintf(stderr, "Error parsing commit %s\n",
@@ -1307,12 +1396,12 @@ void get_delta(unsigned char *sha1, stru
 			if (sha1 == NULL ||
 			    memcmp(sha1, parents->item->object.sha1, 20))
 				get_delta(sha1, &parents->item->object,
-					  lock_token);
-		get_delta(sha1, &commit->tree->object, lock_token);
+					  lock);
+		get_delta(sha1, &commit->tree->object, lock);
 	} else if (obj->type == tree_type) {
 		if (push_verbosely)
 			fprintf(stderr, "walk %s\n", sha1_to_hex(obj->sha1));
-		add_request(obj->sha1, lock_token);
+		add_request(obj->sha1, lock);
 		tree = (struct tree *)obj;
 		if (parse_tree(tree)) {
 			fprintf(stderr, "Error parsing tree %s\n",
@@ -1324,17 +1413,18 @@ void get_delta(unsigned char *sha1, stru
 		tree->entries = NULL;
 		while (entry) {
 			struct tree_entry_list *next = entry->next;
-			get_delta(sha1, entry->item.any, lock_token);
+			get_delta(sha1, entry->item.any, lock);
 			free(entry->name);
 			free(entry);
 			entry = next;
 		}
 	} else if (obj->type == blob_type || obj->type == tag_type) {
-		add_request(obj->sha1, lock_token);
+		add_request(obj->sha1, lock);
 	}
 }
 
-int update_remote(char *remote_path, unsigned char *sha1, char *lock_token)
+int update_remote(char *remote_path, unsigned char *sha1,
+		  struct active_lock *lock)
 {
 	struct active_request_slot *slot;
 	char *url;
@@ -1347,8 +1437,8 @@ int update_remote(char *remote_path, uns
 	url = xmalloc(strlen(remote->url) + strlen(remote_path) + 1);
 	sprintf(url, "%s%s", remote->url, remote_path);
 
-	if_header = xmalloc(strlen(lock_token) + 25);
-	sprintf(if_header, "If: (<opaquelocktoken:%s>)", lock_token);
+	if_header = xmalloc(strlen(lock->token) + 25);
+	sprintf(if_header, "If: (<opaquelocktoken:%s>)", lock->token);
 	dav_headers = curl_slist_append(dav_headers, if_header);
 
 	out_buffer.size = 41;
@@ -1411,7 +1501,7 @@ int main(int argc, char **argv)
 	struct object *local_object = NULL;
 	char *remote_ref = NULL;
 	unsigned char remote_sha1[20];
-	char *remote_lock = NULL;
+	struct active_lock *remote_lock;
 	char *remote_path = NULL;
 	char *low_speed_limit;
 	char *low_speed_time;
@@ -1630,6 +1720,9 @@ int main(int argc, char **argv)
 	unlock:
 		unlock_remote(remote_path, remote_lock);
 		free(remote_path);
+		if (remote_lock->owner != NULL)
+			free(remote_lock->owner);
+		free(remote_lock->token);
 		free(remote_lock);
 	}
 
---
0.99.9.GIT

                 reply	other threads:[~2005-11-04 22:22 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20051104222231.GF3001@reactrix.com \
    --to=nickh@reactrix.com \
    --cc=git@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.