git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 4/5] Improve XML parsing in http-push
@ 2005-11-18 19:03 Nick Hengeveld
  0 siblings, 0 replies; only message in thread
From: Nick Hengeveld @ 2005-11-18 19:03 UTC (permalink / raw)
  To: git

Improved XML parsing - replace specialized doc parser callbacks with generic
functions that track the parser context and use document-specific callbacks
to process that data.

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


---

 http-push.c |  319 ++++++++++++++++++++++++++++++-----------------------------
 1 files changed, 163 insertions(+), 156 deletions(-)

applies-to: 819a270f2d0479478cd34d90e5d764ffad88b9d5
61e23ac52c5276cdddc9dd4d0de444dfe1dde39d
diff --git a/http-push.c b/http-push.c
index afdcd8b..2932693 100644
--- a/http-push.c
+++ b/http-push.c
@@ -24,13 +24,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 "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<D:propfind xmlns:D=\"DAV:\">\n<D:prop xmlns:R=\"%s\">\n<D:supportedlock/>\n</D:prop>\n</D:propfind>"
 #define LOCK_REQUEST "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<D:lockinfo xmlns:D=\"DAV:\">\n<D:lockscope><D:exclusive/></D:lockscope>\n<D:locktype><D:write/></D:locktype>\n<D:owner>\n<D:href>mailto:%s</D:href>\n</D:owner>\n</D:lockinfo>"
 
@@ -92,14 +107,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 +126,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)
@@ -734,107 +742,101 @@ int fetch_ref(char *ref, unsigned char *
         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;
+	int *lock_flags = (int *)ctx->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;
+	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)
-{
-	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 handle_new_lock_ctx(struct xml_ctx *ctx, int tag_closed)
+{
+	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);
+
+	if (ctx->cdata) {
+		free(ctx->cdata);
+		ctx->cdata = NULL;
 	}
 
-	free(this);
+	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 +849,11 @@ static struct active_lock *lock_remote(c
 	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 +897,6 @@ static struct active_lock *lock_remote(c
 	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 +912,41 @@ static struct active_lock *lock_remote(c
 	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 +955,12 @@ static struct active_lock *lock_remote(c
 			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;
 }
 
@@ -1000,13 +999,15 @@ static int unlock_remote(struct active_l
 	if (lock->owner != NULL)
 		free(lock->owner);
 	free(lock->url);
+/* Freeing the token causes a segfault...
 	free(lock->token);
+*/
 	free(lock);
 
 	return rc;
 }
 
-static int check_locking(void)
+static int locking_available(void)
 {
 	struct active_request_slot *slot;
 	struct buffer in_buffer;
@@ -1015,8 +1016,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 +1047,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)
@@ -1269,7 +1276,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;
---
0.99.9.GIT

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2005-11-18 19:03 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-11-18 19:03 [PATCH 4/5] Improve XML parsing in http-push Nick Hengeveld

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).