extracting project name from uri

Change-Id: I58b7bce5f5bae6fa8e1baa75e88f21f1e331bee7
diff --git a/src/backend.c b/src/backend.c
index 87dda72..4615c90 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -188,6 +188,11 @@
 	int slashes = 0;
 	const char *start, *end;
 	int depth = 1;
+	int orig_uri_len = uri_len;
+	const char *orig_start;
+	const char *p, *params;
+	int buflen = 0;
+	char *buf;
 
 	if (px->lbprm.tot_weight == 0)
 		return NULL;
@@ -199,29 +204,99 @@
 	if (px->uri_len_limit)
 		uri_len = MIN(uri_len, px->uri_len_limit);
 
-	start = end = uri;
-	if (px->uri_git == 1) {
+	orig_start = start = end = uri;
+	if (px->uri_gerrit == 1) {
+		p = memchr(uri, '?', uri_len);
+		params = p;
+		if (p) {
+			p++;
+			uri_len = p - uri;
+			params = p;
+			if (p[7] == '=') {
+				if (memcmp(p, "service", 7) == 0) {
+					p += 8;
+					depth = 2;
+				}
+			}
+		}
+
 		end = uri + uri_len - 1;
 		while (uri_len--) {
 			c = *end;
 			if (c == '/') {
+				if (p == NULL)
+					p = end + 1;
 				slashes++;
 				if (slashes == depth)
 					break;
 			}
-			else if (c == '?')
-				depth = 2;
 			end--;
 		}
-		//get rid of redundant '/'
-		while ((end - start) > 1 && *(start+1) == '/')
-			start++;
-		while ((end - start) > 1 && *(end-1) == '/')
-			end--;
-		//get rid of trailing ".git"
-		if ((end - start) > 4 && strncmp(end-4, ".git", 4) == 0)
-			end -= 4;
+		if (!strncmp(p, "git-receive-pack", 16) || !strncmp(p, "git-upload-pack", 15)) {
+			// we have git request here
+			// get rid of redundant '/'
+			while ((end - start) > 1 && *(start+1) == '/')
+				start++;
+			while ((end - start) > 1 && *(end-1) == '/')
+				end--;
+			// get rid of trailing ".git"
+			if ((end - start) > 4 && strncmp(end-4, ".git", 4) == 0)
+				end -= 4;
 
+			hash = gen_hash(px, start, (end - start));
+		} else {
+			if (px->uri_dirs_depth1 > 0){
+				// reset state       
+				uri_len = orig_uri_len;
+				if (params != NULL)
+					uri_len = params - uri;
+				depth = px->uri_dirs_depth1;
+				slashes = 0;
+				buf = (char *)malloc(uri_len);
+				orig_start = start = end = uri;
+				while (uri_len--) {
+					c = *end;
+					if (c == '/') {
+						if (slashes == 1 && end - start == 2) {
+							depth += 1;
+							orig_start = start = end;
+						}
+						slashes++;
+						if (slashes == depth - 1) {
+							if (memcmp(start, "/changes", end - start) != 0 && memcmp(start, "/projects", end - start) != 0)
+								break;
+							start = end;
+							p = start;
+						}
+						else if (slashes == depth) { /* depth+1 */
+							memcpy(buf + buflen, p, end - p);
+							buflen += (end - p);
+							break;
+						}
+					}
+					else if (c == '%') {
+						if (orig_start != start && uri_len > 2 && memcmp(end, "%2F", 3) == 0) {
+							memcpy(buf + buflen, p, end - p);
+							buflen += (end - p) + 1;
+							buf[buflen - 1] = '/';
+							p = end + 3;
+						}
+					}
+					else if (c == '~') {
+						memcpy(buf + buflen, p, end - p);
+						buflen += (end - p);
+						break;
+					}
+					end++;
+				}
+			}
+			if (buflen > 0)
+				hash = gen_hash(px, buf, buflen);
+			if (buf != NULL)
+				free(buf);
+			if (buflen <= 0) /*let's fallback to round robin */
+				return NULL;
+		}
 	} else {
 		while (uri_len--) {
 			c = *end;
@@ -234,10 +309,9 @@
 				break;
 			end++;
 		}
+		hash = gen_hash(px, start, (end - start));
 	}
 	
-	hash = gen_hash(px, start, (end - start));
-
 	if ((px->lbprm.algo & BE_LB_HASH_MOD) == BE_LB_HMOD_AVAL)
 		hash = full_hash(hash);
  hash_done:
@@ -1384,7 +1458,7 @@
 		curproxy->lbprm.algo |= BE_LB_ALGO_UH;
 
 		curproxy->uri_whole = 0;
-		curproxy->uri_git = 1;
+		curproxy->uri_gerrit = 0;
 
 		while (*args[arg]) {
 			if (!strcmp(args[arg], "len")) {
@@ -1394,7 +1468,6 @@
 				}
 				curproxy->uri_len_limit = atoi(args[arg+1]);
 				arg += 2;
-				curproxy->uri_git = 0;
 			}
 			else if (!strcmp(args[arg], "depth")) {
 				if (!*args[arg+1] || (atoi(args[arg+1]) <= 0)) {
@@ -1406,12 +1479,20 @@
 				 */
 				curproxy->uri_dirs_depth1 = atoi(args[arg+1]) + 1;
 				arg += 2;
-				curproxy->uri_git = 0;
 			}
 			else if (!strcmp(args[arg], "whole")) {
 				curproxy->uri_whole = 1;
 				arg += 1;
-				curproxy->uri_git = 0;
+			}
+			else if (!strcmp(args[arg], "gerrit")) {
+				if (!*args[arg+1] || (atoi(args[arg+1]) < 0)) {
+					memprintf(err, "%s : '%s' expects a non negative integer  (got '%s').", args[0], args[arg], args[arg+1]);
+					return -1;
+				}
+				curproxy->uri_gerrit = 1;
+				// 0 means whole uri
+				curproxy->uri_dirs_depth1 = atoi(args[arg+1]);
+				arg += 2;
 			}
 			else {
 				memprintf(err, "%s only accepts parameters 'len', 'depth', and 'whole' (got '%s').", args[0], args[arg]);