From: Willy Tarreau Date: Sun, 3 Jan 2010 18:45:54 +0000 (+0100) Subject: [BUG] http: fix cookie parser to support spaces and commas in values X-Git-Tag: v1.4-dev5~8 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=305ae859572b81339cc210d9d84b01449fd1d44e;p=thirdparty%2Fhaproxy.git [BUG] http: fix cookie parser to support spaces and commas in values The cookie parser could be fooled by spaces or commas in cookie names and values, causing the persistence cookie not to be matched if located just after such a cookie. Now spaces found in values are considered as part of the value, and spaces, commas and semi-colons found in values or names, are skipped till next cookie name. This fix must be backported to 1.3. --- diff --git a/src/proto_http.c b/src/proto_http.c index c94efffaff..f0e8785267 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -4953,7 +4953,7 @@ void manage_client_side_appsession(struct session *t, const char *buf, int len) void manage_client_side_cookies(struct session *t, struct buffer *req) { struct http_txn *txn = &t->txn; - char *p1, *p2, *p3, *p4; + char *p1, *p2, *p3, *p4, *p5; char *del_colon, *del_cookie, *colon; int app_cookies; @@ -5008,6 +5008,7 @@ void manage_client_side_cookies(struct session *t, struct buffer *req) while (p1 < cur_end) { /* skip spaces and colons, but keep an eye on these ones */ + resync_name: while (p1 < cur_end) { if (*p1 == ';' || *p1 == ',') colon = p1; @@ -5021,8 +5022,14 @@ void manage_client_side_cookies(struct session *t, struct buffer *req) /* p1 is at the beginning of the cookie name */ p2 = p1; - while (p2 < cur_end && *p2 != '=') + while (p2 < cur_end && *p2 != '=') { + if (*p2 == ',' || *p2 == ';' || isspace((unsigned char)*p2)) { + /* oops, the cookie name was truncated, resync */ + p1 = p2; + goto resync_name; + } p2++; + } if (p2 == cur_end) break; @@ -5031,16 +5038,20 @@ void manage_client_side_cookies(struct session *t, struct buffer *req) if (p3 == cur_end) break; - p4 = p3; - while (p4 < cur_end && !isspace((unsigned char)*p4) && *p4 != ';' && *p4 != ',') - p4++; + /* parse the value, stripping leading and trailing spaces but keeping insiders. */ + p5 = p4 = p3; + while (p5 < cur_end && *p5 != ';' && *p5 != ',') { + if (!isspace((unsigned char)*p5)) + p4 = p5 + 1; + p5++; + } /* here, we have the cookie name between p1 and p2, * and its value between p3 and p4. * we can process it : * - * Cookie: NAME=VALUE; - * | || || | + * Cookie: NAME=VALUE ; + * | || || |+-> p5 * | || || +--> p4 * | || |+-------> p3 * | || +--------> p2 @@ -5080,8 +5091,8 @@ void manage_client_side_cookies(struct session *t, struct buffer *req) * have the server ID betweek p3 and delim, and the original cookie between * delim+1 and p4. Otherwise, delim==p4 : * - * Cookie: NAME=SRV~VALUE; - * | || || | | + * Cookie: NAME=SRV~VALUE ; + * | || || | |+-> p5 * | || || | +--> p4 * | || || +--------> delim * | || |+-----------> p3 @@ -5147,6 +5158,7 @@ void manage_client_side_cookies(struct session *t, struct buffer *req) delta = buffer_replace2(req, p3, delim + 1, NULL, 0); p4 += delta; + p5 += delta; cur_end += delta; cur_next += delta; cur_hdr->len += delta; @@ -5173,6 +5185,7 @@ void manage_client_side_cookies(struct session *t, struct buffer *req) delta = buffer_replace2(req, del_cookie, p1, NULL, 0); p4 += delta; + p5 += delta; cur_end += delta; cur_next += delta; cur_hdr->len += delta; @@ -5208,7 +5221,7 @@ void manage_client_side_cookies(struct session *t, struct buffer *req) } /* we'll have to look for another cookie ... */ - p1 = p4; + p1 = p5; } /* while (p1 < cur_end) */ /* There's no more cookie on this line.