diff --git a/CHANGES b/CHANGES index 79ab4f630..c8dfd1180 100644 --- a/CHANGES +++ b/CHANGES @@ -6,6 +6,19 @@ Changelog +Daniel Stenberg (20 Jan 2010) +- As was pointed out on the http-state mailing list, the order of cookies in a + HTTP Cookie: header _needs_ to be sorted on the path length in the cases + where two cookies using the same name are set more than once using + (overlapping) paths. Realizing this, identically named cookies must be + sorted correctly. But detecting only identically named cookies and take care + of them individually is harder than just to blindly and unconditionally sort + all cookies based on their path lengths. All major browsers also already do + this, so this makes our behavior one step closer to them in the cookie area. + + Test case 8 was the only one that broke due to this change and I updated it + accordingly. + Daniel Stenberg (19 Jan 2010) - David McCreedy brought a fix and a new test case (129) to make libcurl work again when downloading files over FTP using ASCII and it turns out that the diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 37b314c1e..e4abf5fa4 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -46,6 +46,7 @@ This release includes the following bugfixes: o progress callback called repeatedly during slow connects o curl_multi_fdset() would return -1 too often during SCP/SFTP transfers o FTP file size checks with ASCII transfers + o HTTP Cookie: headers sort cookies based on specified path lengths This release includes the following known bugs: diff --git a/lib/cookie.c b/lib/cookie.c index 7be8fc3c5..3a3edd516 100644 --- a/lib/cookie.c +++ b/lib/cookie.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -774,6 +774,18 @@ struct CookieInfo *Curl_cookie_init(struct SessionHandle *data, return c; } +/* sort this so that the longest path gets before the shorter path */ +static int cookie_sort(const void *p1, const void *p2) +{ + struct Cookie *c1 = *(struct Cookie **)p1; + struct Cookie *c2 = *(struct Cookie **)p2; + + size_t l1 = c1->path?strlen(c1->path):0; + size_t l2 = c2->path?strlen(c2->path):0; + + return l2 - l1; +} + /***************************************************************************** * * Curl_cookie_getlist() @@ -794,6 +806,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, struct Cookie *co; time_t now = time(NULL); struct Cookie *mainco=NULL; + int matches=0; if(!c || !c->cookies) return NULL; /* no cookie struct or no cookies in the struct */ @@ -834,8 +847,11 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, /* point the main to us */ mainco = newco; + + matches++; } else { + fail: /* failure, clear up the allocated chain and return NULL */ while(mainco) { co = mainco->next; @@ -851,6 +867,36 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, co = co->next; } + if(matches) { + /* Now we need to make sure that if there is a name appearing more than + once, the longest specified path version comes first. To make this + the swiftest way, we just sort them all based on path length. */ + struct Cookie **array; + int i; + + /* alloc an array and store all cookie pointers */ + array = (struct Cookie **)malloc(sizeof(struct Cookie *) * matches); + if(!array) + goto fail; + + co = mainco; + + for(i=0; co; co = co->next) + array[i++] = co; + + /* now sort the cookie pointers in path lenth order */ + qsort(array, matches, sizeof(struct Cookie *), cookie_sort); + + /* remake the linked list order according to the new order */ + + mainco = array[0]; /* start here */ + for(i=0; inext = array[i+1]; + array[matches-1]->next = NULL; /* terminate the list */ + + free(array); /* remove the temporary data again */ + } + return mainco; /* return the new list */ } diff --git a/tests/data/test8 b/tests/data/test8 index 6131894fd..15e643b66 100644 --- a/tests/data/test8 +++ b/tests/data/test8 @@ -55,7 +55,7 @@ Set-Cookie: blexp=yesyes; domain=.0.0.1; domain=.0.0.1; expiry=totally bad; GET /we/want/8 HTTP/1.1 Host: %HOSTIP:%HTTPPORT Accept: */* -Cookie: blexp=yesyes; cookie=yes; partmatch=present; foobar=name +Cookie: cookie=yes; partmatch=present; foobar=name; blexp=yesyes