Le mercredi 14 octobre 2009 22:39:39, Willy Tarreau a écrit :
> > > Do it for either 1.3 or 1.4, I'll do the back/forward port. If you
> > > prefer to proceed on both, of course feel free to do so :-)
> > 
> > I can do both, this will let you work on something else ;)
> 
> Nice, I appreciate it.

OK, here comes the 2 patch files for haproxy-1.3.21 and haproxy-1.4-dev4.
Please note 3 minor changes in those versions (proto_http.c / proto_http.h) :

1. void manage_client_side_appsession(struct session *t, char *buf);
becomes
void manage_client_side_appsession(struct session *t, const char *buf);

2. An unused variable in get_srv_from_appsession(...) has been removed.

3. After some more tests, I've applied a fix on request_count (used for debug) 
to have nearly the same behaviour in normal mode and "request-learn" mode.

-- 
Cyril Bonté
diff -Naur haproxy-1.4-dev4/include/proto/proto_http.h haproxy-1.4-dev4-appsession-final/include/proto/proto_http.h
--- haproxy-1.4-dev4/include/proto/proto_http.h	2009-10-12 06:40:53.000000000 +0200
+++ haproxy-1.4-dev4-appsession-final/include/proto/proto_http.h	2009-10-14 22:55:55.000000000 +0200
@@ -74,6 +74,7 @@
 int apply_filter_to_req_line(struct session *t, struct buffer *req, struct hdr_exp *exp);
 int apply_filters_to_request(struct session *t, struct buffer *req, struct hdr_exp *exp);
 int apply_filters_to_response(struct session *t, struct buffer *rtr, struct hdr_exp *exp);
+void manage_client_side_appsession(struct session *t, const char *buf);
 void manage_client_side_cookies(struct session *t, struct buffer *req);
 void manage_server_side_cookies(struct session *t, struct buffer *rtr);
 void check_response_for_cacheability(struct session *t, struct buffer *rtr);
diff -Naur haproxy-1.4-dev4/include/types/proxy.h haproxy-1.4-dev4-appsession-final/include/types/proxy.h
--- haproxy-1.4-dev4/include/types/proxy.h	2009-10-12 06:40:53.000000000 +0200
+++ haproxy-1.4-dev4-appsession-final/include/types/proxy.h	2009-10-12 21:24:42.000000000 +0200
@@ -124,6 +124,9 @@
 #define PR_O2_INDEPSTR	0x00001000	/* independant streams, don't update rex on write */
 #define PR_O2_SOCKSTAT	0x00002000	/* collect & provide separate statistics for sockets */
 
+/* bits for proxy->appsession_options */
+#define PR_O_AS_REQL	0x00000001      /* learn the session id from the request */
+
 struct error_snapshot {
 	struct timeval when;		/* date of this event, (tv_sec == 0) means "never" */
 	unsigned int len;		/* original length of the last invalid request/response */
@@ -177,6 +180,7 @@
 	char *appsession_name;			/* name of the cookie to look for */
 	int  appsession_name_len;		/* strlen(appsession_name), computed only once */
 	int  appsession_len;			/* length of the appsession cookie value to be used */
+	int  appsession_options;		/* options for appsession */
 	struct appsession_hash htbl_proxy;	/* Per Proxy hashtable */
 	char *capture_name;			/* beginning of the name of the cookie to capture */
 	int  capture_namelen;			/* length of the cookie name to match */
diff -Naur haproxy-1.4-dev4/include/types/session.h haproxy-1.4-dev4-appsession-final/include/types/session.h
--- haproxy-1.4-dev4/include/types/session.h	2009-10-12 06:40:53.000000000 +0200
+++ haproxy-1.4-dev4-appsession-final/include/types/session.h	2009-10-12 21:25:15.000000000 +0200
@@ -162,6 +162,7 @@
 	int conn_retries;			/* number of connect retries left */
 	int flags;				/* some flags describing the session */
 	unsigned term_trace;			/* term trace: 4*8 bits indicating which part of the code closed */
+	char *sessid;			/* the session id, if found in the request or in the response */
 	struct buffer *req;			/* request buffer */
 	struct buffer *rep;			/* response buffer */
 	struct stream_interface si[2];          /* client and server stream interfaces */
diff -Naur haproxy-1.4-dev4/src/cfgparse.c haproxy-1.4-dev4-appsession-final/src/cfgparse.c
--- haproxy-1.4-dev4/src/cfgparse.c	2009-10-12 06:40:53.000000000 +0200
+++ haproxy-1.4-dev4-appsession-final/src/cfgparse.c	2009-10-12 21:26:10.000000000 +0200
@@ -1517,6 +1517,7 @@
 		}
 	}
 	else if (!strcmp(args[0], "appsession")) {  /* cookie name */
+		int cur_arg;
 
 		if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
 			err_code |= ERR_WARN;
@@ -1546,6 +1547,14 @@
 			err_code |= ERR_ALERT | ERR_ABORT;
 			goto out;
 		}
+
+		cur_arg = 6;
+		while (*(args[cur_arg])) {
+			if (!strcmp(args[cur_arg], "request-learn")) {
+				curproxy->appsession_options |= PR_O_AS_REQL;
+			}
+			cur_arg++;
+		}
 	} /* Url App Session */
 	else if (!strcmp(args[0], "capture")) {
 		if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
diff -Naur haproxy-1.4-dev4/src/client.c haproxy-1.4-dev4-appsession-final/src/client.c
--- haproxy-1.4-dev4/src/client.c	2009-10-12 06:40:53.000000000 +0200
+++ haproxy-1.4-dev4-appsession-final/src/client.c	2009-10-12 21:26:38.000000000 +0200
@@ -184,7 +184,7 @@
 		 */
 		s->be = s->fe = p;
 
-		s->req = s->rep = NULL; /* will be allocated later */
+		s->sessid = s->req = s->rep = NULL; /* will be allocated later */
 
 		s->si[0].state = s->si[0].prev_state = SI_ST_EST;
 		s->si[0].err_type = SI_ET_NONE;
diff -Naur haproxy-1.4-dev4/src/proto_http.c haproxy-1.4-dev4-appsession-final/src/proto_http.c
--- haproxy-1.4-dev4/src/proto_http.c	2009-10-12 06:40:53.000000000 +0200
+++ haproxy-1.4-dev4-appsession-final/src/proto_http.c	2009-10-14 23:38:28.000000000 +0200
@@ -3557,6 +3557,73 @@
 
 
 /*
+ * Try to retrieve the server associated to the appsession.
+ * If the server is found, it's assigned to the session.
+ */
+void manage_client_side_appsession(struct session *t, const char *buf) {
+	struct http_txn *txn = &t->txn;
+	appsess *asession = NULL;
+	char *sessid_temp = NULL;
+
+	if (t->be->appsession_options & PR_O_AS_REQL) {
+		/* request-learn option is enabled : store the sessid in the session for future use */
+		if (t->sessid != NULL) {
+			/* free previously allocated memory as we don't need the session id found in the URL anymore */
+			pool_free2(apools.sessid, t->sessid);
+		}
+
+		if ((t->sessid = pool_alloc2(apools.sessid)) == NULL) {
+			Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
+			send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
+			return;
+		}
+
+		memcpy(t->sessid, buf, t->be->appsession_len);
+		t->sessid[t->be->appsession_len] = 0;
+	}
+
+	if ((sessid_temp = pool_alloc2(apools.sessid)) == NULL) {
+		Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
+		send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
+		return;
+	}
+
+	memcpy(sessid_temp, buf, t->be->appsession_len);
+	sessid_temp[t->be->appsession_len] = 0;
+
+	asession = appsession_hash_lookup(&(t->be->htbl_proxy), sessid_temp);
+	/* free previously allocated memory */
+	pool_free2(apools.sessid, sessid_temp);
+	
+	if (asession != NULL) {
+		asession->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
+		if (!(t->be->appsession_options & PR_O_AS_REQL)) {
+			asession->request_count++;
+		}
+
+		if (asession->serverid != NULL) {
+			struct server *srv = t->be->srv;
+			while (srv) {
+				if (strcmp(srv->id, asession->serverid) == 0) {
+					if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
+						/* we found the server and it's usable */
+						txn->flags &= ~TX_CK_MASK;
+						txn->flags |= TX_CK_VALID;
+						t->flags |= SN_DIRECT | SN_ASSIGNED;
+						t->srv = srv;
+						break;
+					} else {
+						txn->flags &= ~TX_CK_MASK;
+						txn->flags |= TX_CK_DOWN;
+					}
+				}
+				srv = srv->next;
+			}
+		}
+	}
+}
+
+/*
  * Manage client-side cookie. It can impact performance by about 2% so it is
  * desirable to call it only when needed.
  */
@@ -3567,9 +3634,6 @@
 	char *del_colon, *del_cookie, *colon;
 	int app_cookies;
 
-	appsess *asession_temp = NULL;
-	appsess local_asession;
-
 	char *cur_ptr, *cur_end, *cur_next;
 	int cur_idx, old_idx;
 
@@ -3799,63 +3863,7 @@
 					/* first, let's see if the cookie is our appcookie*/
 
 					/* Cool... it's the right one */
-
-					asession_temp = &local_asession;
-			  
-					if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
-						Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
-						send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
-						return;
-					}
-
-					memcpy(asession_temp->sessid, p3, t->be->appsession_len);
-					asession_temp->sessid[t->be->appsession_len] = 0;
-					asession_temp->serverid = NULL;
-
-					/* only do insert, if lookup fails */
-					asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
-					if (asession_temp == NULL) {
-						if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
-							/* free previously allocated memory */
-							pool_free2(apools.sessid, local_asession.sessid);
-							Alert("Not enough memory process_cli():asession:calloc().\n");
-							send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
-							return;
-						}
-
-						asession_temp->sessid = local_asession.sessid;
-						asession_temp->serverid = local_asession.serverid;
-						asession_temp->request_count = 0;
-						appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
-					} else {
-						/* free previously allocated memory */
-						pool_free2(apools.sessid, local_asession.sessid);
-					}
-					if (asession_temp->serverid == NULL) {
-						/* TODO redispatch request */
-						Alert("Found Application Session without matching server.\n");
-					} else {
-						struct server *srv = t->be->srv;
-						while (srv) {
-							if (strcmp(srv->id, asession_temp->serverid) == 0) {
-								if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
-									/* we found the server and it's usable */
-									txn->flags &= ~TX_CK_MASK;
-									txn->flags |= TX_CK_VALID;
-									t->flags |= SN_DIRECT | SN_ASSIGNED;
-									t->srv = srv;
-									break;
-								} else {
-									txn->flags &= ~TX_CK_MASK;
-									txn->flags |= TX_CK_DOWN;
-								}
-							}
-							srv = srv->next;
-						}/* end while(srv) */
-					}/* end else if server == NULL */
-
-					asession_temp->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
-					asession_temp->request_count++;
+					manage_client_side_appsession(t, p3);
 #if defined(DEBUG_HASH)
 					Alert("manage_client_side_cookies\n");
 					appsession_hash_dump(&(t->be->htbl_proxy));
@@ -4133,9 +4141,6 @@
 	struct http_txn *txn = &t->txn;
 	char *p1, *p2, *p3, *p4;
 
-	appsess *asession_temp = NULL;
-	appsess local_asession;
-
 	char *cur_ptr, *cur_end, *cur_next;
 	int cur_idx, old_idx, delta;
 
@@ -4276,60 +4281,64 @@
 
 				/* Cool... it's the right one */
 
-				size_t server_id_len = strlen(t->srv->id) + 1;
-				asession_temp = &local_asession;
-		      
-				if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
+				if (t->sessid != NULL) {
+					/* free previously allocated memory as we don't need it anymore */
+					pool_free2(apools.sessid, t->sessid);
+				}
+				/* Store the sessid in the session for future use */
+				if ((t->sessid = pool_alloc2(apools.sessid)) == NULL) {
 					Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
 					send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
 					return;
 				}
-				memcpy(asession_temp->sessid, p3, t->be->appsession_len);
-				asession_temp->sessid[t->be->appsession_len] = 0;
-				asession_temp->serverid = NULL;
-
-				/* only do insert, if lookup fails */
-				asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
-				if (asession_temp == NULL) {
-					if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
-						Alert("Not enough Memory process_srv():asession:calloc().\n");
-						send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession:calloc().\n");
-						return;
-					}
-					asession_temp->sessid = local_asession.sessid;
-					asession_temp->serverid = local_asession.serverid;
-					asession_temp->request_count = 0;
-					appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
-				} else {
-					/* free wasted memory */
-					pool_free2(apools.sessid, local_asession.sessid);
-				}
-
-				if (asession_temp->serverid == NULL) {
-					if ((asession_temp->serverid = pool_alloc2(apools.serverid)) == NULL) {
-						Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
-						send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
-						return;
-					}
-					asession_temp->serverid[0] = '\0';
-				}
-		      
-				if (asession_temp->serverid[0] == '\0')
-					memcpy(asession_temp->serverid, t->srv->id, server_id_len);
-		      
-				asession_temp->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
-				asession_temp->request_count++;
-#if defined(DEBUG_HASH)
-				Alert("manage_server_side_cookies\n");
-				appsession_hash_dump(&(t->be->htbl_proxy));
-#endif
+				memcpy(t->sessid, p3, t->be->appsession_len);
+				t->sessid[t->be->appsession_len] = 0;
 			}/* end if ((t->proxy->appsession_name != NULL) ... */
 			break; /* we don't want to loop again since there cannot be another cookie on the same line */
 		} /* we're now at the end of the cookie value */
-
 		/* keep the link from this header to next one */
 		old_idx = cur_idx;
 	} /* end of cookie processing on this header */
+	
+	if (t->sessid != NULL) {
+		appsess *asession = NULL;
+		/* only do insert, if lookup fails */
+		asession = appsession_hash_lookup(&(t->be->htbl_proxy), t->sessid);
+		if (asession == NULL) {
+			if ((asession = pool_alloc2(pool2_appsess)) == NULL) {
+				Alert("Not enough Memory process_srv():asession:calloc().\n");
+				send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession:calloc().\n");
+				return;
+			}
+			if ((asession->sessid = pool_alloc2(apools.sessid)) == NULL) {
+				Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
+				send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
+				return;
+			}
+			memcpy(asession->sessid, t->sessid, t->be->appsession_len);
+			asession->sessid[t->be->appsession_len] = 0;
+
+			size_t server_id_len = strlen(t->srv->id) + 1;
+			if ((asession->serverid = pool_alloc2(apools.serverid)) == NULL) {
+				Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
+				send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
+				return;
+			}
+			asession->serverid[0] = '\0';
+			memcpy(asession->serverid, t->srv->id, server_id_len);
+			
+			asession->request_count = 0;
+			appsession_hash_insert(&(t->be->htbl_proxy), asession);
+		}
+      
+		asession->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
+		asession->request_count++;
+	}
+		      
+#if defined(DEBUG_HASH)
+	Alert("manage_server_side_cookies\n");
+	appsession_hash_dump(&(t->be->htbl_proxy));
+#endif
 }
 
 
@@ -4427,9 +4436,6 @@
  */
 void get_srv_from_appsession(struct session *t, const char *begin, int len)
 {
-	struct http_txn *txn = &t->txn;
-	appsess *asession_temp = NULL;
-	appsess local_asession;
 	char *request_line;
 
 	if (t->be->appsession_name == NULL ||
@@ -4448,69 +4454,11 @@
 	/* skip jsessionid= */
 	request_line += t->be->appsession_name_len + 1;
 	
-	/* First try if we already have an appsession */
-	asession_temp = &local_asession;
-	
-	if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
-		Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
-		send_log(t->be, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
-		return;
-	}
-	
-	/* Copy the sessionid */
-	memcpy(asession_temp->sessid, request_line, t->be->appsession_len);
-	asession_temp->sessid[t->be->appsession_len] = 0;
-	asession_temp->serverid = NULL;
-	
-	/* only do insert, if lookup fails */
-	asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
-	if (asession_temp == NULL) {
-		if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
-			/* free previously allocated memory */
-			pool_free2(apools.sessid, local_asession.sessid);
-			Alert("Not enough memory process_cli():asession:calloc().\n");
-			send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
-			return;
-		}
-		asession_temp->sessid = local_asession.sessid;
-		asession_temp->serverid = local_asession.serverid;
-		asession_temp->request_count=0;
-		appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
-	}
-	else {
-		/* free previously allocated memory */
-		pool_free2(apools.sessid, local_asession.sessid);
-	}
-
-	asession_temp->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
-	asession_temp->request_count++;
-
+	manage_client_side_appsession(t, request_line);
 #if defined(DEBUG_HASH)
 	Alert("get_srv_from_appsession\n");
 	appsession_hash_dump(&(t->be->htbl_proxy));
 #endif
-	if (asession_temp->serverid == NULL) {
-		/* TODO redispatch request */
-		Alert("Found Application Session without matching server.\n");
-	} else {
-		struct server *srv = t->be->srv;
-		while (srv) {
-			if (strcmp(srv->id, asession_temp->serverid) == 0) {
-				if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
-					/* we found the server and it's usable */
-					txn->flags &= ~TX_CK_MASK;
-					txn->flags |= TX_CK_VALID;
-					t->flags |= SN_DIRECT | SN_ASSIGNED;
-					t->srv = srv;
-					break;
-				} else {
-					txn->flags &= ~TX_CK_MASK;
-					txn->flags |= TX_CK_DOWN;
-				}
-			}
-			srv = srv->next;
-		}
-	}
 }
 
 
diff -Naur haproxy-1.4-dev4/src/session.c haproxy-1.4-dev4-appsession-final/src/session.c
--- haproxy-1.4-dev4/src/session.c	2009-10-12 06:40:53.000000000 +0200
+++ haproxy-1.4-dev4-appsession-final/src/session.c	2009-10-12 21:41:23.000000000 +0200
@@ -77,6 +77,9 @@
 	pool_free2(pool2_buffer, s->req);
 	pool_free2(pool2_buffer, s->rep);
 
+	if (s->sessid)
+		pool_free2(apools.sessid, s->sessid);
+
 	if (fe) {
 		pool_free2(fe->hdr_idx_pool, txn->hdr_idx.v);
 
diff -Naur haproxy-1.3.21/include/proto/proto_http.h haproxy-1.3.21-appsession-final/include/proto/proto_http.h
--- haproxy-1.3.21/include/proto/proto_http.h	2009-10-12 06:20:09.000000000 +0200
+++ haproxy-1.3.21-appsession-final/include/proto/proto_http.h	2009-10-14 23:12:55.000000000 +0200
@@ -75,6 +75,7 @@
 int apply_filter_to_req_line(struct session *t, struct buffer *req, struct hdr_exp *exp);
 int apply_filters_to_request(struct session *t, struct buffer *req, struct hdr_exp *exp);
 int apply_filters_to_response(struct session *t, struct buffer *rtr, struct hdr_exp *exp);
+void manage_client_side_appsession(struct session *t, const char *buf);
 void manage_client_side_cookies(struct session *t, struct buffer *req);
 void manage_server_side_cookies(struct session *t, struct buffer *rtr);
 void check_response_for_cacheability(struct session *t, struct buffer *rtr);
diff -Naur haproxy-1.3.21/include/types/proxy.h haproxy-1.3.21-appsession-final/include/types/proxy.h
--- haproxy-1.3.21/include/types/proxy.h	2009-10-12 06:20:09.000000000 +0200
+++ haproxy-1.3.21-appsession-final/include/types/proxy.h	2009-10-14 22:58:41.000000000 +0200
@@ -120,6 +120,9 @@
 /* 0x80..0x800 already used in 1.4 */
 #define PR_O2_INDEPSTR	0x00001000	/* independant streams, don't update rex on write */
 
+/* bits for proxy->appsession_options */
+#define PR_O_AS_REQL	0x00000001      /* learn the session id from the request */
+
 /* This structure is used to apply fast weighted round robin on a server group */
 struct fwrr_group {
 	struct eb_root curr;    /* tree for servers in "current" time range */
@@ -207,6 +210,7 @@
 	char *appsession_name;			/* name of the cookie to look for */
 	int  appsession_name_len;		/* strlen(appsession_name), computed only once */
 	int  appsession_len;			/* length of the appsession cookie value to be used */
+	int  appsession_options;		/* options for appsession */
 	struct appsession_hash htbl_proxy;	/* Per Proxy hashtable */
 	char *capture_name;			/* beginning of the name of the cookie to capture */
 	int  capture_namelen;			/* length of the cookie name to match */
diff -Naur haproxy-1.3.21/include/types/session.h haproxy-1.3.21-appsession-final/include/types/session.h
--- haproxy-1.3.21/include/types/session.h	2009-10-12 06:20:09.000000000 +0200
+++ haproxy-1.3.21-appsession-final/include/types/session.h	2009-10-14 22:59:06.000000000 +0200
@@ -162,6 +162,7 @@
 	int conn_retries;			/* number of connect retries left */
 	int flags;				/* some flags describing the session */
 	unsigned term_trace;			/* term trace: 4*8 bits indicating which part of the code closed */
+	char *sessid;			/* the session id, if found in the request or in the response */
 	struct buffer *req;			/* request buffer */
 	struct buffer *rep;			/* response buffer */
 	struct stream_interface si[2];          /* client and server stream interfaces */
diff -Naur haproxy-1.3.21/src/cfgparse.c haproxy-1.3.21-appsession-final/src/cfgparse.c
--- haproxy-1.3.21/src/cfgparse.c	2009-10-12 06:20:09.000000000 +0200
+++ haproxy-1.3.21-appsession-final/src/cfgparse.c	2009-10-14 23:00:08.000000000 +0200
@@ -1326,6 +1326,7 @@
 		}
 	}/* end else if (!strcmp(args[0], "cookie"))  */
 	else if (!strcmp(args[0], "appsession")) {  /* cookie name */
+		int cur_arg;
 
 		if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
 			err_code |= ERR_WARN;
@@ -1355,6 +1356,14 @@
 			err_code |= ERR_ALERT | ERR_ABORT;
 			goto out;
 		}
+
+		cur_arg = 6;
+		while (*(args[cur_arg])) {
+			if (!strcmp(args[cur_arg], "request-learn")) {
+				curproxy->appsession_options |= PR_O_AS_REQL;
+			}
+			cur_arg++;
+		}
 	} /* Url App Session */
 	else if (!strcmp(args[0], "capture")) {
 		if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
diff -Naur haproxy-1.3.21/src/client.c haproxy-1.3.21-appsession-final/src/client.c
--- haproxy-1.3.21/src/client.c	2009-10-12 06:20:09.000000000 +0200
+++ haproxy-1.3.21-appsession-final/src/client.c	2009-10-14 23:00:49.000000000 +0200
@@ -179,7 +179,7 @@
 		}
 
 		s->ana_state = 0;  /* analysers may change it but must reset it upon exit */
-		s->req = s->rep = NULL; /* will be allocated later */
+		s->sessid = s->req = s->rep = NULL; /* will be allocated later */
 
 		s->si[0].state = s->si[0].prev_state = SI_ST_EST;
 		s->si[0].err_type = SI_ET_NONE;
diff -Naur haproxy-1.3.21/src/proto_http.c haproxy-1.3.21-appsession-final/src/proto_http.c
--- haproxy-1.3.21/src/proto_http.c	2009-10-12 06:20:09.000000000 +0200
+++ haproxy-1.3.21-appsession-final/src/proto_http.c	2009-10-14 23:46:44.000000000 +0200
@@ -3368,6 +3368,73 @@
 
 
 /*
+ * Try to retrieve the server associated to the appsession.
+ * If the server is found, it's assigned to the session.
+ */
+void manage_client_side_appsession(struct session *t, const char *buf) {
+	struct http_txn *txn = &t->txn;
+	appsess *asession = NULL;
+	char *sessid_temp = NULL;
+
+	if (t->be->appsession_options & PR_O_AS_REQL) {
+		/* request-learn option is enabled : store the sessid in the session for future use */
+		if (t->sessid != NULL) {
+			/* free previously allocated memory as we don't need the session id found in the URL anymore */
+			pool_free2(apools.sessid, t->sessid);
+		}
+
+		if ((t->sessid = pool_alloc2(apools.sessid)) == NULL) {
+			Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
+			send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
+			return;
+		}
+
+		memcpy(t->sessid, buf, t->be->appsession_len);
+		t->sessid[t->be->appsession_len] = 0;
+	}
+
+	if ((sessid_temp = pool_alloc2(apools.sessid)) == NULL) {
+		Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
+		send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
+		return;
+	}
+
+	memcpy(sessid_temp, buf, t->be->appsession_len);
+	sessid_temp[t->be->appsession_len] = 0;
+
+	asession = appsession_hash_lookup(&(t->be->htbl_proxy), sessid_temp);
+	/* free previously allocated memory */
+	pool_free2(apools.sessid, sessid_temp);
+	
+	if (asession != NULL) {
+		asession->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
+		if (!(t->be->appsession_options & PR_O_AS_REQL)) {
+			asession->request_count++;
+		}
+
+		if (asession->serverid != NULL) {
+			struct server *srv = t->be->srv;
+			while (srv) {
+				if (strcmp(srv->id, asession->serverid) == 0) {
+					if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
+						/* we found the server and it's usable */
+						txn->flags &= ~TX_CK_MASK;
+						txn->flags |= TX_CK_VALID;
+						t->flags |= SN_DIRECT | SN_ASSIGNED;
+						t->srv = srv;
+						break;
+					} else {
+						txn->flags &= ~TX_CK_MASK;
+						txn->flags |= TX_CK_DOWN;
+					}
+				}
+				srv = srv->next;
+			}
+		}
+	}
+}
+
+/*
  * Manage client-side cookie. It can impact performance by about 2% so it is
  * desirable to call it only when needed.
  */
@@ -3378,9 +3445,6 @@
 	char *del_colon, *del_cookie, *colon;
 	int app_cookies;
 
-	appsess *asession_temp = NULL;
-	appsess local_asession;
-
 	char *cur_ptr, *cur_end, *cur_next;
 	int cur_idx, old_idx;
 
@@ -3610,63 +3674,7 @@
 					/* first, let's see if the cookie is our appcookie*/
 
 					/* Cool... it's the right one */
-
-					asession_temp = &local_asession;
-			  
-					if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
-						Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
-						send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
-						return;
-					}
-
-					memcpy(asession_temp->sessid, p3, t->be->appsession_len);
-					asession_temp->sessid[t->be->appsession_len] = 0;
-					asession_temp->serverid = NULL;
-
-					/* only do insert, if lookup fails */
-					asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
-					if (asession_temp == NULL) {
-						if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
-							/* free previously allocated memory */
-							pool_free2(apools.sessid, local_asession.sessid);
-							Alert("Not enough memory process_cli():asession:calloc().\n");
-							send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
-							return;
-						}
-
-						asession_temp->sessid = local_asession.sessid;
-						asession_temp->serverid = local_asession.serverid;
-						asession_temp->request_count = 0;
-						appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
-					} else {
-						/* free previously allocated memory */
-						pool_free2(apools.sessid, local_asession.sessid);
-					}
-					if (asession_temp->serverid == NULL) {
-						/* TODO redispatch request */
-						Alert("Found Application Session without matching server.\n");
-					} else {
-						struct server *srv = t->be->srv;
-						while (srv) {
-							if (strcmp(srv->id, asession_temp->serverid) == 0) {
-								if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
-									/* we found the server and it's usable */
-									txn->flags &= ~TX_CK_MASK;
-									txn->flags |= TX_CK_VALID;
-									t->flags |= SN_DIRECT | SN_ASSIGNED;
-									t->srv = srv;
-									break;
-								} else {
-									txn->flags &= ~TX_CK_MASK;
-									txn->flags |= TX_CK_DOWN;
-								}
-							}
-							srv = srv->next;
-						}/* end while(srv) */
-					}/* end else if server == NULL */
-
-					asession_temp->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
-					asession_temp->request_count++;
+					manage_client_side_appsession(t, p3);
 #if defined(DEBUG_HASH)
 					Alert("manage_client_side_cookies\n");
 					appsession_hash_dump(&(t->be->htbl_proxy));
@@ -3944,9 +3952,6 @@
 	struct http_txn *txn = &t->txn;
 	char *p1, *p2, *p3, *p4;
 
-	appsess *asession_temp = NULL;
-	appsess local_asession;
-
 	char *cur_ptr, *cur_end, *cur_next;
 	int cur_idx, old_idx, delta;
 
@@ -4087,60 +4092,64 @@
 
 				/* Cool... it's the right one */
 
-				size_t server_id_len = strlen(t->srv->id) + 1;
-				asession_temp = &local_asession;
-		      
-				if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
+				if (t->sessid != NULL) {
+					/* free previously allocated memory as we don't need it anymore */
+					pool_free2(apools.sessid, t->sessid);
+				}
+				/* Store the sessid in the session for future use */
+				if ((t->sessid = pool_alloc2(apools.sessid)) == NULL) {
 					Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
 					send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
 					return;
 				}
-				memcpy(asession_temp->sessid, p3, t->be->appsession_len);
-				asession_temp->sessid[t->be->appsession_len] = 0;
-				asession_temp->serverid = NULL;
-
-				/* only do insert, if lookup fails */
-				asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
-				if (asession_temp == NULL) {
-					if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
-						Alert("Not enough Memory process_srv():asession:calloc().\n");
-						send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession:calloc().\n");
-						return;
-					}
-					asession_temp->sessid = local_asession.sessid;
-					asession_temp->serverid = local_asession.serverid;
-					asession_temp->request_count = 0;
-					appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
-				} else {
-					/* free wasted memory */
-					pool_free2(apools.sessid, local_asession.sessid);
-				}
-
-				if (asession_temp->serverid == NULL) {
-					if ((asession_temp->serverid = pool_alloc2(apools.serverid)) == NULL) {
-						Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
-						send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
-						return;
-					}
-					asession_temp->serverid[0] = '\0';
-				}
-		      
-				if (asession_temp->serverid[0] == '\0')
-					memcpy(asession_temp->serverid, t->srv->id, server_id_len);
-		      
-				asession_temp->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
-				asession_temp->request_count++;
-#if defined(DEBUG_HASH)
-				Alert("manage_server_side_cookies\n");
-				appsession_hash_dump(&(t->be->htbl_proxy));
-#endif
+				memcpy(t->sessid, p3, t->be->appsession_len);
+				t->sessid[t->be->appsession_len] = 0;
 			}/* end if ((t->proxy->appsession_name != NULL) ... */
 			break; /* we don't want to loop again since there cannot be another cookie on the same line */
 		} /* we're now at the end of the cookie value */
-
 		/* keep the link from this header to next one */
 		old_idx = cur_idx;
 	} /* end of cookie processing on this header */
+	
+	if (t->sessid != NULL) {
+		appsess *asession = NULL;
+		/* only do insert, if lookup fails */
+		asession = appsession_hash_lookup(&(t->be->htbl_proxy), t->sessid);
+		if (asession == NULL) {
+			if ((asession = pool_alloc2(pool2_appsess)) == NULL) {
+				Alert("Not enough Memory process_srv():asession:calloc().\n");
+				send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession:calloc().\n");
+				return;
+			}
+			if ((asession->sessid = pool_alloc2(apools.sessid)) == NULL) {
+				Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
+				send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
+				return;
+			}
+			memcpy(asession->sessid, t->sessid, t->be->appsession_len);
+			asession->sessid[t->be->appsession_len] = 0;
+
+			size_t server_id_len = strlen(t->srv->id) + 1;
+			if ((asession->serverid = pool_alloc2(apools.serverid)) == NULL) {
+				Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
+				send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
+				return;
+			}
+			asession->serverid[0] = '\0';
+			memcpy(asession->serverid, t->srv->id, server_id_len);
+			
+			asession->request_count = 0;
+			appsession_hash_insert(&(t->be->htbl_proxy), asession);
+		}
+      
+		asession->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
+		asession->request_count++;
+	}
+		      
+#if defined(DEBUG_HASH)
+	Alert("manage_server_side_cookies\n");
+	appsession_hash_dump(&(t->be->htbl_proxy));
+#endif
 }
 
 
@@ -4238,9 +4247,6 @@
  */
 void get_srv_from_appsession(struct session *t, const char *begin, int len)
 {
-	struct http_txn *txn = &t->txn;
-	appsess *asession_temp = NULL;
-	appsess local_asession;
 	char *request_line;
 
 	if (t->be->appsession_name == NULL ||
@@ -4259,69 +4265,11 @@
 	/* skip jsessionid= */
 	request_line += t->be->appsession_name_len + 1;
 	
-	/* First try if we already have an appsession */
-	asession_temp = &local_asession;
-	
-	if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
-		Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
-		send_log(t->be, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
-		return;
-	}
-	
-	/* Copy the sessionid */
-	memcpy(asession_temp->sessid, request_line, t->be->appsession_len);
-	asession_temp->sessid[t->be->appsession_len] = 0;
-	asession_temp->serverid = NULL;
-	
-	/* only do insert, if lookup fails */
-	asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
-	if (asession_temp == NULL) {
-		if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
-			/* free previously allocated memory */
-			pool_free2(apools.sessid, local_asession.sessid);
-			Alert("Not enough memory process_cli():asession:calloc().\n");
-			send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
-			return;
-		}
-		asession_temp->sessid = local_asession.sessid;
-		asession_temp->serverid = local_asession.serverid;
-		asession_temp->request_count=0;
-		appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
-	}
-	else {
-		/* free previously allocated memory */
-		pool_free2(apools.sessid, local_asession.sessid);
-	}
-
-	asession_temp->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
-	asession_temp->request_count++;
-
+	manage_client_side_appsession(t, request_line);
 #if defined(DEBUG_HASH)
 	Alert("get_srv_from_appsession\n");
 	appsession_hash_dump(&(t->be->htbl_proxy));
 #endif
-	if (asession_temp->serverid == NULL) {
-		/* TODO redispatch request */
-		Alert("Found Application Session without matching server.\n");
-	} else {
-		struct server *srv = t->be->srv;
-		while (srv) {
-			if (strcmp(srv->id, asession_temp->serverid) == 0) {
-				if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
-					/* we found the server and it's usable */
-					txn->flags &= ~TX_CK_MASK;
-					txn->flags |= TX_CK_VALID;
-					t->flags |= SN_DIRECT | SN_ASSIGNED;
-					t->srv = srv;
-					break;
-				} else {
-					txn->flags &= ~TX_CK_MASK;
-					txn->flags |= TX_CK_DOWN;
-				}
-			}
-			srv = srv->next;
-		}
-	}
 }
 
 
diff -Naur haproxy-1.3.21/src/session.c haproxy-1.3.21-appsession-final/src/session.c
--- haproxy-1.3.21/src/session.c	2009-10-12 06:20:09.000000000 +0200
+++ haproxy-1.3.21-appsession-final/src/session.c	2009-10-14 23:09:30.000000000 +0200
@@ -78,6 +78,9 @@
 	pool_free2(pool2_buffer, s->req);
 	pool_free2(pool2_buffer, s->rep);
 
+	if (s->sessid)
+		pool_free2(apools.sessid, s->sessid);
+
 	if (fe) {
 		pool_free2(fe->hdr_idx_pool, txn->hdr_idx.v);
 

Reply via email to