From bb6e777da9d7460a03051101309e6185a4e696c0 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 3 Jan 2010 19:45:54 +0100 Subject: [PATCH] [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. (cherry picked from commit 305ae859572b81339cc210d9d84b01449fd1d44e) --- src/proto_http.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/src/proto_http.c b/src/proto_http.c index 46528b5f39..32ac33e432 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -3440,7 +3440,7 @@ void manage_client_side_appsession(struct session *t, const char *buf) { 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; @@ -3495,6 +3495,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; @@ -3508,8 +3509,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; @@ -3518,16 +3525,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 @@ -3567,8 +3578,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 @@ -3634,6 +3645,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; @@ -3660,6 +3672,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; @@ -3682,7 +3695,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. -- 2.47.3