{"thread":{"id":"2354","subject":"[PATCH 3/4] Improve lock handling","startedAt":"2005-11-04T22:22:31Z","lastAt":"2005-11-04T22:22:31Z","messageCount":1,"participants":["Nick Hengeveld"],"isPatch":true,"patchVersion":1,"patchTotal":4},"messages":[{"id":"11161","messageId":"20051104222231.GF3001@reactrix.com","threadId":"2354","inReplyTo":null,"subject":"[PATCH 3/4] Improve lock handling","fromName":"Nick Hengeveld","fromEmail":"nickh@reactrix.com","sentAt":"2005-11-04T22:22:31Z","receivedAt":"2005-11-04T22:22:31Z","isPatch":true,"sender":{"key":"nickh@reactrix.com","avatar":null},"body":"Improve lock handling: parse the server response for the timeout, owner,\nand lock token\n\nSigned-off-by: Nick Hengeveld <nickh@reactrix.com>\n\n\n---\n\n http-push.c |  201 +++++++++++++++++++++++++++++++++++++++++++----------------\n 1 files changed, 147 insertions(+), 54 deletions(-)\n\napplies-to: 99366e40c96e3fd0436287c601697f3166e8cf36\n1b26b4528dc9e14f2be5d57154022249206fcc6f\ndiff --git a/http-push.c b/http-push.c\nindex 6a241aa..85cd595 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -55,7 +55,6 @@ static CURL *curl_default;\n static struct curl_slist *no_pragma_header;\n static struct curl_slist *default_headers;\n static char curl_errorstr[CURL_ERROR_SIZE];\n-static char *lock_token = NULL;\n \n static int push_verbosely = 0;\n static int push_all = 0;\n@@ -92,7 +91,7 @@ struct transfer_request\n \tunsigned char sha1[20];\n \tchar *url;\n \tchar *dest;\n-\tchar *lock_token;\n+\tstruct active_lock *lock;\n \tstruct curl_slist *headers;\n \tstruct buffer buffer;\n \tchar filename[PATH_MAX];\n@@ -136,6 +135,20 @@ static char *ssl_cainfo = NULL;\n static long curl_low_speed_limit = -1;\n static long curl_low_speed_time = -1;\n \n+struct active_lock\n+{\n+\tint ctx_activelock;\n+\tint ctx_owner;\n+\tint ctx_owner_href;\n+\tint ctx_timeout;\n+\tint ctx_locktoken;\n+\tint ctx_locktoken_href;\n+\tchar *owner;\n+\ttime_t start_time;\n+\tlong timeout;\n+\tchar *token;\n+};\n+\n struct lockprop\n {\n \tint supported_lock;\n@@ -509,7 +522,7 @@ static void start_put(struct transfer_re\n \tif (request->url != NULL)\n \t\tfree(request->url);\n \trequest->url = xmalloc(strlen(remote->url) + \n-\t\t\t       strlen(request->lock_token) + 51);\n+\t\t\t       strlen(request->lock->token) + 51);\n \tstrcpy(request->url, remote->url);\n \tposn = request->url + strlen(remote->url);\n \tstrcpy(posn, \"objects/\");\n@@ -522,7 +535,7 @@ static void start_put(struct transfer_re\n \tsprintf(request->dest, \"Destination: %s\", request->url);\n \tposn += 38;\n \t*(posn++) = '.';\n-\tstrcpy(posn, request->lock_token);\n+\tstrcpy(posn, request->lock->token);\n \n \tslot = get_active_slot();\n \tcurl_easy_setopt(slot->curl, CURLOPT_INFILE, &request->buffer);\n@@ -724,7 +737,7 @@ void process_waiting_requests(void)\n \t\t}\n }\n \n-void add_request(unsigned char *sha1, char *lock_token)\n+void add_request(unsigned char *sha1, struct active_lock *lock)\n {\n \tstruct transfer_request *request = request_queue_head;\n \tstruct packed_git *target;\n@@ -741,7 +754,7 @@ void add_request(unsigned char *sha1, ch\n \trequest = xmalloc(sizeof(*request));\n \tmemcpy(request->sha1, sha1, 20);\n \trequest->url = NULL;\n-\trequest->lock_token = lock_token;\n+\trequest->lock = lock;\n \trequest->headers = NULL;\n \trequest->state = NEED_CHECK;\n \trequest->next = request_queue_head;\n@@ -999,6 +1012,68 @@ int fetch_ref(char *ref, unsigned char *\n }\n \n static void\n+start_activelock_element(void *userData, const char *name, const char **atts)\n+{\n+\tstruct active_lock *lock = (struct active_lock *)userData;\n+\n+\tif (lock->ctx_activelock && !strcmp(name, \"D:timeout\"))\n+\t\tlock->ctx_timeout = 1;\n+\telse if (lock->ctx_owner && strstr(name, \"href\"))\n+\t\tlock->ctx_owner_href = 1;\n+\telse if (lock->ctx_activelock && strstr(name, \"owner\"))\n+\t\tlock->ctx_owner = 1;\n+\telse if (lock->ctx_locktoken && !strcmp(name, \"D:href\"))\n+\t\tlock->ctx_locktoken_href = 1;\n+\telse if (lock->ctx_activelock && !strcmp(name, \"D:locktoken\"))\n+\t\tlock->ctx_locktoken = 1;\n+\telse if (!strcmp(name, \"D:activelock\"))\n+\t\tlock->ctx_activelock = 1;\n+}\n+\n+static void\n+end_activelock_element(void *userData, const char *name)\n+{\n+\tstruct active_lock *lock = (struct active_lock *)userData;\n+\n+\tif (lock->ctx_timeout && !strcmp(name, \"D:timeout\")) {\n+\t\tlock->ctx_timeout = 0;\n+\t} else if (lock->ctx_owner_href && strstr(name, \"href\")) {\n+\t\tlock->ctx_owner_href = 0;\n+\t} else if (lock->ctx_owner && strstr(name, \"owner\")) {\n+\t\tlock->ctx_owner = 0;\n+\t} else if (lock->ctx_locktoken_href && !strcmp(name, \"D:href\")) {\n+\t\tlock->ctx_locktoken_href = 0;\n+\t} else if (lock->ctx_locktoken && !strcmp(name, \"D:locktoken\")) {\n+\t\tlock->ctx_locktoken = 0;\n+\t} else if (lock->ctx_activelock && !strcmp(name, \"D:activelock\")) {\n+\t\tlock->ctx_activelock = 0;\n+\t}\n+}\n+\n+static void\n+activelock_cdata(void *userData, const XML_Char *s, int len)\n+{\n+\tstruct active_lock *lock = (struct active_lock *)userData;\n+\tchar *this = malloc(len+1);\n+\tstrncpy(this, s, len);\n+\n+\tif (lock->ctx_owner_href) {\n+\t\tlock->owner = malloc(len+1);\n+\t\tstrcpy(lock->owner, this);\n+\t} else if (lock->ctx_locktoken_href) {\n+\t\tif (!strncmp(this, \"opaquelocktoken:\", 16)) {\n+\t\t\tlock->token = malloc(len-15);\n+\t\t\tstrcpy(lock->token, this+16);\n+\t\t}\n+\t} else if (lock->ctx_timeout) {\n+\t\tif (!strncmp(this, \"Second-\", 7))\n+\t\t\tlock->timeout = strtol(this+7, NULL, 10);\n+\t}\n+\n+\tfree(this);\n+}\n+\n+static void\n start_lockprop_element(void *userData, const char *name, const char **atts)\n {\n \tstruct lockprop *prop = (struct lockprop *)userData;\n@@ -1039,40 +1114,21 @@ end_lockprop_element(void *userData, con\n \t}\n }\n \n-size_t process_lock_header( void *ptr, size_t size, size_t nmemb, void *stream)\n-{\n-\tsize_t header_size = size*nmemb;\n-\tchar *start;\n-\tchar *end;\n-\n-\tif (!strncmp(ptr, \"Lock-Token: <opaquelocktoken:\", 29)) {\n-\t\tstart = ptr + 29;\n-\t\tfor (end = ptr + header_size;\n-\t\t     *(end - 1) == '\\r' || *(end - 1) == '\\n' || *(end - 1) == '>';\n-\t\t     end--) {}\n-\t\tif (end > start) {\n-\t\t\tlock_token = xmalloc(end - start + 1);\n-\t\t\tmemcpy(lock_token, start, end - start);\n-\t\t\tlock_token[end - start] = 0;\n-\t\t}\n-\t}\n-\n-\treturn header_size;\n-}\n-\n-char *lock_remote(char *file, int timeout)\n+struct active_lock *lock_remote(char *file, int timeout)\n {\n \tstruct active_request_slot *slot;\n \tstruct buffer out_buffer;\n+\tstruct buffer in_buffer;\n \tchar *out_data;\n+\tchar *in_data;\n \tchar *url;\n \tchar *ep;\n \tchar timeout_header[25];\n+\tstruct active_lock *new_lock;\n+\tXML_Parser parser = XML_ParserCreate(NULL);\n+\tenum XML_Status result;\n \tstruct curl_slist *dav_headers = NULL;\n \n-\tif (lock_token != NULL)\n-\t\tfree(lock_token);\n-\n \turl = xmalloc(strlen(remote->url) + strlen(file) + 1);\n \tsprintf(url, \"%s%s\", remote->url, file);\n \n@@ -1110,6 +1166,16 @@ char *lock_remote(char *file, int timeou\n \tout_buffer.posn = 0;\n \tout_buffer.buffer = out_data;\n \n+\tin_buffer.size = 4096;\n+\tin_data = xmalloc(in_buffer.size);\n+\tin_buffer.posn = 0;\n+\tin_buffer.buffer = in_data;\n+\n+\tnew_lock = xmalloc(sizeof(*new_lock));\n+\tnew_lock->owner = NULL;\n+\tnew_lock->token = NULL;\n+\tnew_lock->timeout = -1;\n+\n \tsprintf(timeout_header, \"Timeout: Second-%d\", timeout);\n \tdav_headers = curl_slist_append(dav_headers, timeout_header);\n \tdav_headers = curl_slist_append(dav_headers, \"Content-Type: text/xml\");\n@@ -1118,9 +1184,9 @@ char *lock_remote(char *file, int timeou\n \tcurl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);\n \tcurl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.size);\n \tcurl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_HEADERFUNCTION,\n-\t\tprocess_lock_header);\n+\tcurl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);\n+\tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,\n+\t\t\t fwrite_buffer_dynamic);\n \tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n \tcurl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);\n \tcurl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_LOCK);\n@@ -1130,13 +1196,17 @@ char *lock_remote(char *file, int timeou\n \t\trun_active_slot(slot);\n \t\tif (slot->curl_result != CURLE_OK) {\n \t\t\tfprintf(stderr, \"Got HTTP error %ld\\n\", slot->http_code);\n+\t\t\tfree(new_lock);\n \t\t\tfree(url);\n \t\t\tfree(out_data);\n+\t\t\tfree(in_data);\n \t\t\treturn NULL;\n \t\t}\n \t} else {\n+\t\tfree(new_lock);\n \t\tfree(url);\n \t\tfree(out_data);\n+\t\tfree(in_data);\n \t\tfprintf(stderr, \"Unable to start request\\n\");\n \t\treturn NULL;\n \t}\n@@ -1144,10 +1214,33 @@ char *lock_remote(char *file, int timeou\n \tfree(url);\n \tfree(out_data);\n \n-\treturn strdup(lock_token);\n+\tXML_SetUserData(parser, new_lock);\n+\tXML_SetElementHandler(parser, start_activelock_element,\n+\t\t\t\t      end_activelock_element);\n+\tXML_SetCharacterDataHandler(parser, activelock_cdata);\n+\tresult = XML_Parse(parser, in_buffer.buffer, in_buffer.posn, 1);\n+\tfree(in_data);\n+\tif (result != XML_STATUS_OK) {\n+\t\tfprintf(stderr, \"%s\", XML_ErrorString(\n+\t\t\t\tXML_GetErrorCode(parser)));\n+\t\tfree(new_lock);\n+\t\treturn NULL;\n+\t}\n+\n+\tif (new_lock->token == NULL || new_lock->timeout <= 0) {\n+\t\tif (new_lock->token != NULL)\n+\t\t\tfree(new_lock->token);\n+\t\tif (new_lock->owner != NULL)\n+\t\t\tfree(new_lock->owner);\n+\t\tfree(new_lock);\n+\t\treturn NULL;\n+\t}\n+\n+\tnew_lock->start_time = time(NULL);\n+\treturn new_lock;\n }\n \n-int unlock_remote(char *file, char *lock_token)\n+int unlock_remote(char *file, struct active_lock *lock)\n {\n \tstruct active_request_slot *slot;\n \tchar *url;\n@@ -1155,14 +1248,9 @@ int unlock_remote(char *file, char *lock\n \tstruct curl_slist *dav_headers = NULL;\n \tint rc = 0;\n \n-\tif (lock_token == NULL) {\n-\t\tfprintf(stderr, \"Unable to unlock, no lock token\");\n-\t\treturn 0;\n-\t}\n-\n-\tlock_token_header = xmalloc(strlen(lock_token) + 31);\n+\tlock_token_header = xmalloc(strlen(lock->token) + 31);\n \tsprintf(lock_token_header, \"Lock-Token: <opaquelocktoken:%s>\",\n-\t\tlock_token);\n+\t\tlock->token);\n \turl = xmalloc(strlen(remote->url) + strlen(file) + 1);\n \tsprintf(url, \"%s%s\", remote->url, file);\n \tdav_headers = curl_slist_append(dav_headers, lock_token_header);\n@@ -1278,7 +1366,8 @@ int is_ancestor(unsigned char *sha1, str\n \treturn 0;\n }\n \n-void get_delta(unsigned char *sha1, struct object *obj, char *lock_token)\n+void get_delta(unsigned char *sha1, struct object *obj,\n+\t       struct active_lock *lock)\n {\n \tstruct commit *commit;\n \tstruct commit_list *parents;\n@@ -1294,7 +1383,7 @@ void get_delta(unsigned char *sha1, stru\n \tif (obj->type == commit_type) {\n \t\tif (push_verbosely)\n \t\t\tfprintf(stderr, \"walk %s\\n\", sha1_to_hex(obj->sha1));\n-\t\tadd_request(obj->sha1, lock_token);\n+\t\tadd_request(obj->sha1, lock);\n \t\tcommit = (struct commit *)obj;\n \t\tif (parse_commit(commit)) {\n \t\t\tfprintf(stderr, \"Error parsing commit %s\\n\",\n@@ -1307,12 +1396,12 @@ void get_delta(unsigned char *sha1, stru\n \t\t\tif (sha1 == NULL ||\n \t\t\t    memcmp(sha1, parents->item->object.sha1, 20))\n \t\t\t\tget_delta(sha1, &parents->item->object,\n-\t\t\t\t\t  lock_token);\n-\t\tget_delta(sha1, &commit->tree->object, lock_token);\n+\t\t\t\t\t  lock);\n+\t\tget_delta(sha1, &commit->tree->object, lock);\n \t} else if (obj->type == tree_type) {\n \t\tif (push_verbosely)\n \t\t\tfprintf(stderr, \"walk %s\\n\", sha1_to_hex(obj->sha1));\n-\t\tadd_request(obj->sha1, lock_token);\n+\t\tadd_request(obj->sha1, lock);\n \t\ttree = (struct tree *)obj;\n \t\tif (parse_tree(tree)) {\n \t\t\tfprintf(stderr, \"Error parsing tree %s\\n\",\n@@ -1324,17 +1413,18 @@ void get_delta(unsigned char *sha1, stru\n \t\ttree->entries = NULL;\n \t\twhile (entry) {\n \t\t\tstruct tree_entry_list *next = entry->next;\n-\t\t\tget_delta(sha1, entry->item.any, lock_token);\n+\t\t\tget_delta(sha1, entry->item.any, lock);\n \t\t\tfree(entry->name);\n \t\t\tfree(entry);\n \t\t\tentry = next;\n \t\t}\n \t} else if (obj->type == blob_type || obj->type == tag_type) {\n-\t\tadd_request(obj->sha1, lock_token);\n+\t\tadd_request(obj->sha1, lock);\n \t}\n }\n \n-int update_remote(char *remote_path, unsigned char *sha1, char *lock_token)\n+int update_remote(char *remote_path, unsigned char *sha1,\n+\t\t  struct active_lock *lock)\n {\n \tstruct active_request_slot *slot;\n \tchar *url;\n@@ -1347,8 +1437,8 @@ int update_remote(char *remote_path, uns\n \turl = xmalloc(strlen(remote->url) + strlen(remote_path) + 1);\n \tsprintf(url, \"%s%s\", remote->url, remote_path);\n \n-\tif_header = xmalloc(strlen(lock_token) + 25);\n-\tsprintf(if_header, \"If: (<opaquelocktoken:%s>)\", lock_token);\n+\tif_header = xmalloc(strlen(lock->token) + 25);\n+\tsprintf(if_header, \"If: (<opaquelocktoken:%s>)\", lock->token);\n \tdav_headers = curl_slist_append(dav_headers, if_header);\n \n \tout_buffer.size = 41;\n@@ -1411,7 +1501,7 @@ int main(int argc, char **argv)\n \tstruct object *local_object = NULL;\n \tchar *remote_ref = NULL;\n \tunsigned char remote_sha1[20];\n-\tchar *remote_lock = NULL;\n+\tstruct active_lock *remote_lock;\n \tchar *remote_path = NULL;\n \tchar *low_speed_limit;\n \tchar *low_speed_time;\n@@ -1630,6 +1720,9 @@ int main(int argc, char **argv)\n \tunlock:\n \t\tunlock_remote(remote_path, remote_lock);\n \t\tfree(remote_path);\n+\t\tif (remote_lock->owner != NULL)\n+\t\t\tfree(remote_lock->owner);\n+\t\tfree(remote_lock->token);\n \t\tfree(remote_lock);\n \t}\n \n---\n0.99.9.GIT\n"}]}