00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083 #include "curl_setup.h"
00084
00085 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
00086
00087 #ifdef USE_LIBPSL
00088 # include <libpsl.h>
00089 #endif
00090
00091 #include "urldata.h"
00092 #include "cookie.h"
00093 #include "strtok.h"
00094 #include "sendf.h"
00095 #include "slist.h"
00096 #include "share.h"
00097 #include "strtoofft.h"
00098 #include "strcase.h"
00099 #include "curl_memrchr.h"
00100 #include "inet_pton.h"
00101
00102
00103 #include "curl_printf.h"
00104 #include "curl_memory.h"
00105 #include "memdebug.h"
00106
00107 static void freecookie(struct Cookie *co)
00108 {
00109 free(co->expirestr);
00110 free(co->domain);
00111 free(co->path);
00112 free(co->spath);
00113 free(co->name);
00114 free(co->value);
00115 free(co->maxage);
00116 free(co->version);
00117 free(co);
00118 }
00119
00120 static bool tailmatch(const char *cooke_domain, const char *hostname)
00121 {
00122 size_t cookie_domain_len = strlen(cooke_domain);
00123 size_t hostname_len = strlen(hostname);
00124
00125 if(hostname_len < cookie_domain_len)
00126 return FALSE;
00127
00128 if(!strcasecompare(cooke_domain, hostname+hostname_len-cookie_domain_len))
00129 return FALSE;
00130
00131
00132
00133
00134
00135
00136
00137
00138 if(hostname_len == cookie_domain_len)
00139 return TRUE;
00140 if('.' == *(hostname + hostname_len - cookie_domain_len - 1))
00141 return TRUE;
00142 return FALSE;
00143 }
00144
00145
00146
00147
00148
00149 static bool pathmatch(const char *cookie_path, const char *request_uri)
00150 {
00151 size_t cookie_path_len;
00152 size_t uri_path_len;
00153 char *uri_path = NULL;
00154 char *pos;
00155 bool ret = FALSE;
00156
00157
00158 cookie_path_len = strlen(cookie_path);
00159 if(1 == cookie_path_len) {
00160
00161 return TRUE;
00162 }
00163
00164 uri_path = strdup(request_uri);
00165 if(!uri_path)
00166 return FALSE;
00167 pos = strchr(uri_path, '?');
00168 if(pos)
00169 *pos = 0x0;
00170
00171
00172 if(0 == strlen(uri_path) || uri_path[0] != '/') {
00173 free(uri_path);
00174 uri_path = strdup("/");
00175 if(!uri_path)
00176 return FALSE;
00177 }
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188 uri_path_len = strlen(uri_path);
00189
00190 if(uri_path_len < cookie_path_len) {
00191 ret = FALSE;
00192 goto pathmatched;
00193 }
00194
00195
00196 if(strncmp(cookie_path, uri_path, cookie_path_len)) {
00197 ret = FALSE;
00198 goto pathmatched;
00199 }
00200
00201
00202 if(cookie_path_len == uri_path_len) {
00203 ret = TRUE;
00204 goto pathmatched;
00205 }
00206
00207
00208 if(uri_path[cookie_path_len] == '/') {
00209 ret = TRUE;
00210 goto pathmatched;
00211 }
00212
00213 ret = FALSE;
00214
00215 pathmatched:
00216 free(uri_path);
00217 return ret;
00218 }
00219
00220
00221
00222
00223 static char *sanitize_cookie_path(const char *cookie_path)
00224 {
00225 size_t len;
00226 char *new_path = strdup(cookie_path);
00227 if(!new_path)
00228 return NULL;
00229
00230
00231 len = strlen(new_path);
00232 if(new_path[0] == '\"') {
00233 memmove((void *)new_path, (const void *)(new_path + 1), len);
00234 len--;
00235 }
00236 if(len && (new_path[len - 1] == '\"')) {
00237 new_path[len - 1] = 0x0;
00238 len--;
00239 }
00240
00241
00242 if(new_path[0] != '/') {
00243
00244 free(new_path);
00245 new_path = strdup("/");
00246 return new_path;
00247 }
00248
00249
00250 if(len && new_path[len - 1] == '/') {
00251 new_path[len - 1] = 0x0;
00252 }
00253
00254 return new_path;
00255 }
00256
00257
00258
00259
00260
00261
00262 void Curl_cookie_loadfiles(struct Curl_easy *data)
00263 {
00264 struct curl_slist *list = data->change.cookielist;
00265 if(list) {
00266 Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
00267 while(list) {
00268 struct CookieInfo *newcookies = Curl_cookie_init(data,
00269 list->data,
00270 data->cookies,
00271 data->set.cookiesession);
00272 if(!newcookies)
00273
00274
00275
00276 infof(data, "ignoring failed cookie_init for %s\n", list->data);
00277 else
00278 data->cookies = newcookies;
00279 list = list->next;
00280 }
00281 curl_slist_free_all(data->change.cookielist);
00282 data->change.cookielist = NULL;
00283 Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
00284 }
00285 }
00286
00287
00288
00289
00290
00291
00292
00293 static void strstore(char **str, const char *newstr)
00294 {
00295 free(*str);
00296 *str = strdup(newstr);
00297 }
00298
00299
00300
00301
00302 static void remove_expired(struct CookieInfo *cookies)
00303 {
00304 struct Cookie *co, *nx, *pv;
00305 curl_off_t now = (curl_off_t)time(NULL);
00306
00307 co = cookies->cookies;
00308 pv = NULL;
00309 while(co) {
00310 nx = co->next;
00311 if(co->expires && co->expires < now) {
00312 if(co == cookies->cookies) {
00313 cookies->cookies = co->next;
00314 }
00315 else {
00316 pv->next = co->next;
00317 }
00318 cookies->numcookies--;
00319 freecookie(co);
00320 }
00321 else {
00322 pv = co;
00323 }
00324 co = nx;
00325 }
00326 }
00327
00328
00329
00330
00331 static bool isip(const char *domain)
00332 {
00333 struct in_addr addr;
00334 #ifdef ENABLE_IPV6
00335 struct in6_addr addr6;
00336 #endif
00337
00338 if(Curl_inet_pton(AF_INET, domain, &addr)
00339 #ifdef ENABLE_IPV6
00340 || Curl_inet_pton(AF_INET6, domain, &addr6)
00341 #endif
00342 ) {
00343
00344 return TRUE;
00345 }
00346
00347 return FALSE;
00348 }
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363 struct Cookie *
00364 Curl_cookie_add(struct Curl_easy *data,
00365
00366
00367
00368
00369 struct CookieInfo *c,
00370 bool httpheader,
00371 char *lineptr,
00372 const char *domain,
00373 const char *path)
00374
00375
00376 {
00377 struct Cookie *clist;
00378 char name[MAX_NAME];
00379 struct Cookie *co;
00380 struct Cookie *lastc=NULL;
00381 time_t now = time(NULL);
00382 bool replace_old = FALSE;
00383 bool badcookie = FALSE;
00384
00385 #ifdef USE_LIBPSL
00386 const psl_ctx_t *psl;
00387 #endif
00388
00389 #ifdef CURL_DISABLE_VERBOSE_STRINGS
00390 (void)data;
00391 #endif
00392
00393
00394 co = calloc(1, sizeof(struct Cookie));
00395 if(!co)
00396 return NULL;
00397
00398 if(httpheader) {
00399
00400 const char *ptr;
00401 const char *semiptr;
00402 char *what;
00403
00404 what = malloc(MAX_COOKIE_LINE);
00405 if(!what) {
00406 free(co);
00407 return NULL;
00408 }
00409
00410 semiptr=strchr(lineptr, ';');
00411
00412 while(*lineptr && ISBLANK(*lineptr))
00413 lineptr++;
00414
00415 ptr = lineptr;
00416 do {
00417
00418 name[0]=what[0]=0;
00419 if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\r\n=] =%"
00420 MAX_COOKIE_LINE_TXT "[^;\r\n]",
00421 name, what)) {
00422
00423
00424
00425 const char *whatptr;
00426 bool done = FALSE;
00427 bool sep;
00428 size_t len=strlen(what);
00429 size_t nlen = strlen(name);
00430 const char *endofn = &ptr[ nlen ];
00431
00432
00433 sep = (*endofn == '=')?TRUE:FALSE;
00434
00435 if(nlen) {
00436 endofn--;
00437 if(ISBLANK(*endofn)) {
00438
00439 while(*endofn && ISBLANK(*endofn) && nlen) {
00440 endofn--;
00441 nlen--;
00442 }
00443 name[nlen]=0;
00444 }
00445 }
00446
00447
00448 while(len && ISBLANK(what[len-1])) {
00449 what[len-1]=0;
00450 len--;
00451 }
00452
00453
00454 whatptr=what;
00455 while(*whatptr && ISBLANK(*whatptr))
00456 whatptr++;
00457
00458 if(!co->name && sep) {
00459
00460 co->name = strdup(name);
00461 co->value = strdup(whatptr);
00462 if(!co->name || !co->value) {
00463 badcookie = TRUE;
00464 break;
00465 }
00466 }
00467 else if(!len) {
00468
00469
00470 done = TRUE;
00471 if(strcasecompare("secure", name))
00472 co->secure = TRUE;
00473 else if(strcasecompare("httponly", name))
00474 co->httponly = TRUE;
00475 else if(sep)
00476
00477 done = FALSE;
00478 }
00479 if(done)
00480 ;
00481 else if(strcasecompare("path", name)) {
00482 strstore(&co->path, whatptr);
00483 if(!co->path) {
00484 badcookie = TRUE;
00485 break;
00486 }
00487 co->spath = sanitize_cookie_path(co->path);
00488 if(!co->spath) {
00489 badcookie = TRUE;
00490 break;
00491 }
00492 }
00493 else if(strcasecompare("domain", name)) {
00494 bool is_ip;
00495 const char *dotp;
00496
00497
00498
00499
00500 if('.' == whatptr[0])
00501 whatptr++;
00502
00503 is_ip = isip(domain ? domain : whatptr);
00504
00505
00506 dotp = strchr(whatptr, '.');
00507 if(!dotp)
00508 domain=":";
00509
00510 if(!domain
00511 || (is_ip && !strcmp(whatptr, domain))
00512 || (!is_ip && tailmatch(whatptr, domain))) {
00513 strstore(&co->domain, whatptr);
00514 if(!co->domain) {
00515 badcookie = TRUE;
00516 break;
00517 }
00518 if(!is_ip)
00519 co->tailmatch=TRUE;
00520
00521 }
00522 else {
00523
00524
00525
00526 badcookie=TRUE;
00527 infof(data, "skipped cookie with bad tailmatch domain: %s\n",
00528 whatptr);
00529 }
00530 }
00531 else if(strcasecompare("version", name)) {
00532 strstore(&co->version, whatptr);
00533 if(!co->version) {
00534 badcookie = TRUE;
00535 break;
00536 }
00537 }
00538 else if(strcasecompare("max-age", name)) {
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548 strstore(&co->maxage, whatptr);
00549 if(!co->maxage) {
00550 badcookie = TRUE;
00551 break;
00552 }
00553 }
00554 else if(strcasecompare("expires", name)) {
00555 strstore(&co->expirestr, whatptr);
00556 if(!co->expirestr) {
00557 badcookie = TRUE;
00558 break;
00559 }
00560 }
00561
00562
00563
00564 }
00565 else {
00566
00567 }
00568
00569 if(!semiptr || !*semiptr) {
00570
00571 semiptr = NULL;
00572 continue;
00573 }
00574
00575 ptr=semiptr+1;
00576 while(*ptr && ISBLANK(*ptr))
00577 ptr++;
00578 semiptr=strchr(ptr, ';');
00579
00580 if(!semiptr && *ptr)
00581
00582
00583 semiptr=strchr(ptr, '\0');
00584 } while(semiptr);
00585
00586 if(co->maxage) {
00587 co->expires =
00588 curlx_strtoofft((*co->maxage=='\"')?
00589 &co->maxage[1]:&co->maxage[0], NULL, 10);
00590 if(CURL_OFF_T_MAX - now < co->expires)
00591
00592 co->expires = CURL_OFF_T_MAX;
00593 else
00594 co->expires += now;
00595 }
00596 else if(co->expirestr) {
00597
00598
00599 co->expires = curl_getdate(co->expirestr, NULL);
00600
00601
00602
00603
00604 if(co->expires == 0)
00605 co->expires = 1;
00606 else if(co->expires < 0)
00607 co->expires = 0;
00608 }
00609
00610 if(!badcookie && !co->domain) {
00611 if(domain) {
00612
00613 co->domain=strdup(domain);
00614 if(!co->domain)
00615 badcookie = TRUE;
00616 }
00617 }
00618
00619 if(!badcookie && !co->path && path) {
00620
00621
00622
00623 char *queryp = strchr(path, '?');
00624
00625
00626
00627 char *endslash;
00628 if(!queryp)
00629 endslash = strrchr(path, '/');
00630 else
00631 endslash = memrchr(path, '/', (size_t)(queryp - path));
00632 if(endslash) {
00633 size_t pathlen = (size_t)(endslash-path+1);
00634 co->path=malloc(pathlen+1);
00635 if(co->path) {
00636 memcpy(co->path, path, pathlen);
00637 co->path[pathlen]=0;
00638 co->spath = sanitize_cookie_path(co->path);
00639 if(!co->spath)
00640 badcookie = TRUE;
00641 }
00642 else
00643 badcookie = TRUE;
00644 }
00645 }
00646
00647 free(what);
00648
00649 if(badcookie || !co->name) {
00650
00651
00652 freecookie(co);
00653 return NULL;
00654 }
00655
00656 }
00657 else {
00658
00659
00660 char *ptr;
00661 char *firstptr;
00662 char *tok_buf=NULL;
00663 int fields;
00664
00665
00666
00667
00668
00669
00670
00671
00672 if(strncmp(lineptr, "#HttpOnly_", 10) == 0) {
00673 lineptr += 10;
00674 co->httponly = TRUE;
00675 }
00676
00677 if(lineptr[0]=='#') {
00678
00679 free(co);
00680 return NULL;
00681 }
00682
00683 ptr=strchr(lineptr, '\r');
00684 if(ptr)
00685 *ptr=0;
00686 ptr=strchr(lineptr, '\n');
00687 if(ptr)
00688 *ptr=0;
00689
00690 firstptr=strtok_r(lineptr, "\t", &tok_buf);
00691
00692
00693
00694 for(ptr=firstptr, fields=0; ptr && !badcookie;
00695 ptr=strtok_r(NULL, "\t", &tok_buf), fields++) {
00696 switch(fields) {
00697 case 0:
00698 if(ptr[0]=='.')
00699 ptr++;
00700 co->domain = strdup(ptr);
00701 if(!co->domain)
00702 badcookie = TRUE;
00703 break;
00704 case 1:
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715 co->tailmatch = strcasecompare(ptr, "TRUE")?TRUE:FALSE;
00716 break;
00717 case 2:
00718
00719
00720
00721 if(strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
00722
00723 co->path = strdup(ptr);
00724 if(!co->path)
00725 badcookie = TRUE;
00726 else {
00727 co->spath = sanitize_cookie_path(co->path);
00728 if(!co->spath) {
00729 badcookie = TRUE;
00730 }
00731 }
00732 break;
00733 }
00734
00735 co->path = strdup("/");
00736 if(!co->path)
00737 badcookie = TRUE;
00738 co->spath = strdup("/");
00739 if(!co->spath)
00740 badcookie = TRUE;
00741 fields++;
00742
00743 case 3:
00744 co->secure = strcasecompare(ptr, "TRUE")?TRUE:FALSE;
00745 break;
00746 case 4:
00747 co->expires = curlx_strtoofft(ptr, NULL, 10);
00748 break;
00749 case 5:
00750 co->name = strdup(ptr);
00751 if(!co->name)
00752 badcookie = TRUE;
00753 break;
00754 case 6:
00755 co->value = strdup(ptr);
00756 if(!co->value)
00757 badcookie = TRUE;
00758 break;
00759 }
00760 }
00761 if(6 == fields) {
00762
00763 co->value = strdup("");
00764 if(!co->value)
00765 badcookie = TRUE;
00766 else
00767 fields++;
00768 }
00769
00770 if(!badcookie && (7 != fields))
00771
00772 badcookie = TRUE;
00773
00774 if(badcookie) {
00775 freecookie(co);
00776 return NULL;
00777 }
00778
00779 }
00780
00781 if(!c->running &&
00782 c->newsession &&
00783 !co->expires) {
00784 freecookie(co);
00785 return NULL;
00786 }
00787
00788 co->livecookie = c->running;
00789
00790
00791
00792
00793
00794
00795 remove_expired(c);
00796
00797 #ifdef USE_LIBPSL
00798
00799
00800 if(domain && co->domain && !isip(co->domain)) {
00801 psl = psl_builtin();
00802 if(psl && !psl_is_cookie_domain_acceptable(psl, domain, co->domain)) {
00803 infof(data,
00804 "cookie '%s' dropped, domain '%s' must not set cookies for '%s'\n",
00805 co->name, domain, co->domain);
00806 freecookie(co);
00807 return NULL;
00808 }
00809 }
00810 #endif
00811
00812 clist = c->cookies;
00813 replace_old = FALSE;
00814 while(clist) {
00815 if(strcasecompare(clist->name, co->name)) {
00816
00817
00818 if(clist->domain && co->domain) {
00819 if(strcasecompare(clist->domain, co->domain) &&
00820 (clist->tailmatch == co->tailmatch))
00821
00822 replace_old=TRUE;
00823 }
00824 else if(!clist->domain && !co->domain)
00825 replace_old = TRUE;
00826
00827 if(replace_old) {
00828
00829
00830 if(clist->spath && co->spath) {
00831 if(strcasecompare(clist->spath, co->spath)) {
00832 replace_old = TRUE;
00833 }
00834 else
00835 replace_old = FALSE;
00836 }
00837 else if(!clist->spath && !co->spath)
00838 replace_old = TRUE;
00839 else
00840 replace_old = FALSE;
00841
00842 }
00843
00844 if(replace_old && !co->livecookie && clist->livecookie) {
00845
00846
00847
00848
00849
00850
00851 freecookie(co);
00852 return NULL;
00853 }
00854
00855 if(replace_old) {
00856 co->next = clist->next;
00857
00858
00859 free(clist->name);
00860 free(clist->value);
00861 free(clist->domain);
00862 free(clist->path);
00863 free(clist->spath);
00864 free(clist->expirestr);
00865 free(clist->version);
00866 free(clist->maxage);
00867
00868 *clist = *co;
00869
00870 free(co);
00871 co = clist;
00872
00873
00874
00875 do {
00876 lastc = clist;
00877 clist = clist->next;
00878 } while(clist);
00879 break;
00880 }
00881 }
00882 lastc = clist;
00883 clist = clist->next;
00884 }
00885
00886 if(c->running)
00887
00888 infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, "
00889 "expire %" CURL_FORMAT_CURL_OFF_T "\n",
00890 replace_old?"Replaced":"Added", co->name, co->value,
00891 co->domain, co->path, co->expires);
00892
00893 if(!replace_old) {
00894
00895 if(lastc)
00896 lastc->next = co;
00897 else
00898 c->cookies = co;
00899 c->numcookies++;
00900 }
00901
00902 return co;
00903 }
00904
00905
00906
00907
00908
00909 static char *get_line(char *buf, int len, FILE *input)
00910 {
00911 bool partial = FALSE;
00912 while(1) {
00913 char *b = fgets(buf, len, input);
00914 if(b) {
00915 size_t rlen = strlen(b);
00916 if(rlen && (b[rlen-1] == '\n')) {
00917 if(partial) {
00918 partial = FALSE;
00919 continue;
00920 }
00921 return b;
00922 }
00923 else
00924
00925 partial = TRUE;
00926 }
00927 else
00928 break;
00929 }
00930 return NULL;
00931 }
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945 struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
00946 const char *file,
00947 struct CookieInfo *inc,
00948 bool newsession)
00949 {
00950 struct CookieInfo *c;
00951 FILE *fp = NULL;
00952 bool fromfile=TRUE;
00953 char *line = NULL;
00954
00955 if(NULL == inc) {
00956
00957 c = calloc(1, sizeof(struct CookieInfo));
00958 if(!c)
00959 return NULL;
00960 c->filename = strdup(file?file:"none");
00961 if(!c->filename)
00962 goto fail;
00963 }
00964 else {
00965
00966 c = inc;
00967 }
00968 c->running = FALSE;
00969
00970 if(file && !strcmp(file, "-")) {
00971 fp = stdin;
00972 fromfile=FALSE;
00973 }
00974 else if(file && !*file) {
00975
00976 fp = NULL;
00977 }
00978 else
00979 fp = file?fopen(file, FOPEN_READTEXT):NULL;
00980
00981 c->newsession = newsession;
00982
00983 if(fp) {
00984 char *lineptr;
00985 bool headerline;
00986
00987 line = malloc(MAX_COOKIE_LINE);
00988 if(!line)
00989 goto fail;
00990 while(get_line(line, MAX_COOKIE_LINE, fp)) {
00991 if(checkprefix("Set-Cookie:", line)) {
00992
00993 lineptr=&line[11];
00994 headerline=TRUE;
00995 }
00996 else {
00997 lineptr=line;
00998 headerline=FALSE;
00999 }
01000 while(*lineptr && ISBLANK(*lineptr))
01001 lineptr++;
01002
01003 Curl_cookie_add(data, c, headerline, lineptr, NULL, NULL);
01004 }
01005 free(line);
01006
01007 if(fromfile)
01008 fclose(fp);
01009 }
01010
01011 c->running = TRUE;
01012
01013 return c;
01014
01015 fail:
01016 free(line);
01017 if(!inc)
01018
01019
01020 Curl_cookie_cleanup(c);
01021 if(fromfile && fp)
01022 fclose(fp);
01023 return NULL;
01024 }
01025
01026
01027 static int cookie_sort(const void *p1, const void *p2)
01028 {
01029 struct Cookie *c1 = *(struct Cookie **)p1;
01030 struct Cookie *c2 = *(struct Cookie **)p2;
01031 size_t l1, l2;
01032
01033
01034 l1 = c1->path ? strlen(c1->path) : 0;
01035 l2 = c2->path ? strlen(c2->path) : 0;
01036
01037 if(l1 != l2)
01038 return (l2 > l1) ? 1 : -1 ;
01039
01040
01041 l1 = c1->domain ? strlen(c1->domain) : 0;
01042 l2 = c2->domain ? strlen(c2->domain) : 0;
01043
01044 if(l1 != l2)
01045 return (l2 > l1) ? 1 : -1 ;
01046
01047
01048 if(c1->name && c2->name)
01049 return strcmp(c1->name, c2->name);
01050
01051
01052 return 0;
01053 }
01054
01055 #define CLONE(field) \
01056 do { \
01057 if(src->field) { \
01058 dup->field = strdup(src->field); \
01059 if(!dup->field) \
01060 goto fail; \
01061 } \
01062 } while(0)
01063
01064 static struct Cookie *dup_cookie(struct Cookie *src)
01065 {
01066 struct Cookie *dup = calloc(sizeof(struct Cookie), 1);
01067 if(dup) {
01068 CLONE(expirestr);
01069 CLONE(domain);
01070 CLONE(path);
01071 CLONE(spath);
01072 CLONE(name);
01073 CLONE(value);
01074 CLONE(maxage);
01075 CLONE(version);
01076 dup->expires = src->expires;
01077 dup->tailmatch = src->tailmatch;
01078 dup->secure = src->secure;
01079 dup->livecookie = src->livecookie;
01080 dup->httponly = src->httponly;
01081 }
01082 return dup;
01083
01084 fail:
01085 freecookie(dup);
01086 return NULL;
01087 }
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101 struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
01102 const char *host, const char *path,
01103 bool secure)
01104 {
01105 struct Cookie *newco;
01106 struct Cookie *co;
01107 time_t now = time(NULL);
01108 struct Cookie *mainco=NULL;
01109 size_t matches = 0;
01110 bool is_ip;
01111
01112 if(!c || !c->cookies)
01113 return NULL;
01114
01115
01116 remove_expired(c);
01117
01118
01119 is_ip = isip(host);
01120
01121 co = c->cookies;
01122
01123 while(co) {
01124
01125
01126
01127 if((!co->expires || (co->expires > now)) &&
01128 (co->secure?secure:TRUE)) {
01129
01130
01131 if(!co->domain ||
01132 (co->tailmatch && !is_ip && tailmatch(co->domain, host)) ||
01133 ((!co->tailmatch || is_ip) && strcasecompare(host, co->domain)) ) {
01134
01135
01136
01137
01138
01139 if(!co->spath || pathmatch(co->spath, path) ) {
01140
01141
01142
01143
01144 newco = dup_cookie(co);
01145 if(newco) {
01146
01147 newco->next = mainco;
01148
01149
01150 mainco = newco;
01151
01152 matches++;
01153 }
01154 else {
01155 fail:
01156
01157 Curl_cookie_freelist(mainco);
01158 return NULL;
01159 }
01160 }
01161 }
01162 }
01163 co = co->next;
01164 }
01165
01166 if(matches) {
01167
01168
01169
01170 struct Cookie **array;
01171 size_t i;
01172
01173
01174 array = malloc(sizeof(struct Cookie *) * matches);
01175 if(!array)
01176 goto fail;
01177
01178 co = mainco;
01179
01180 for(i=0; co; co = co->next)
01181 array[i++] = co;
01182
01183
01184 qsort(array, matches, sizeof(struct Cookie *), cookie_sort);
01185
01186
01187
01188 mainco = array[0];
01189 for(i=0; i<matches-1; i++)
01190 array[i]->next = array[i+1];
01191 array[matches-1]->next = NULL;
01192
01193 free(array);
01194 }
01195
01196 return mainco;
01197 }
01198
01199
01200
01201
01202
01203
01204
01205
01206 void Curl_cookie_clearall(struct CookieInfo *cookies)
01207 {
01208 if(cookies) {
01209 Curl_cookie_freelist(cookies->cookies);
01210 cookies->cookies = NULL;
01211 cookies->numcookies = 0;
01212 }
01213 }
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223 void Curl_cookie_freelist(struct Cookie *co)
01224 {
01225 struct Cookie *next;
01226 while(co) {
01227 next = co->next;
01228 freecookie(co);
01229 co = next;
01230 }
01231 }
01232
01233
01234
01235
01236
01237
01238
01239
01240
01241 void Curl_cookie_clearsess(struct CookieInfo *cookies)
01242 {
01243 struct Cookie *first, *curr, *next, *prev = NULL;
01244
01245 if(!cookies || !cookies->cookies)
01246 return;
01247
01248 first = curr = prev = cookies->cookies;
01249
01250 for(; curr; curr = next) {
01251 next = curr->next;
01252 if(!curr->expires) {
01253 if(first == curr)
01254 first = next;
01255
01256 if(prev == curr)
01257 prev = next;
01258 else
01259 prev->next = next;
01260
01261 freecookie(curr);
01262 cookies->numcookies--;
01263 }
01264 else
01265 prev = curr;
01266 }
01267
01268 cookies->cookies = first;
01269 }
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279 void Curl_cookie_cleanup(struct CookieInfo *c)
01280 {
01281 if(c) {
01282 free(c->filename);
01283 Curl_cookie_freelist(c->cookies);
01284 free(c);
01285 }
01286 }
01287
01288
01289
01290
01291
01292
01293
01294 static char *get_netscape_format(const struct Cookie *co)
01295 {
01296 return aprintf(
01297 "%s"
01298 "%s%s\t"
01299 "%s\t"
01300 "%s\t"
01301 "%s\t"
01302 "%" CURL_FORMAT_CURL_OFF_T "\t"
01303 "%s\t"
01304 "%s",
01305 co->httponly?"#HttpOnly_":"",
01306
01307
01308 (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"",
01309 co->domain?co->domain:"unknown",
01310 co->tailmatch?"TRUE":"FALSE",
01311 co->path?co->path:"/",
01312 co->secure?"TRUE":"FALSE",
01313 co->expires,
01314 co->name,
01315 co->value?co->value:"");
01316 }
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326 static int cookie_output(struct CookieInfo *c, const char *dumphere)
01327 {
01328 struct Cookie *co;
01329 FILE *out;
01330 bool use_stdout=FALSE;
01331 char *format_ptr;
01332
01333 if((NULL == c) || (0 == c->numcookies))
01334
01335
01336 return 0;
01337
01338
01339 remove_expired(c);
01340
01341 if(!strcmp("-", dumphere)) {
01342
01343 out = stdout;
01344 use_stdout=TRUE;
01345 }
01346 else {
01347 out = fopen(dumphere, FOPEN_WRITETEXT);
01348 if(!out)
01349 return 1;
01350 }
01351
01352 fputs("# Netscape HTTP Cookie File\n"
01353 "# https://curl.haxx.se/docs/http-cookies.html\n"
01354 "# This file was generated by libcurl! Edit at your own risk.\n\n",
01355 out);
01356
01357 for(co = c->cookies; co; co = co->next) {
01358 if(!co->domain)
01359 continue;
01360 format_ptr = get_netscape_format(co);
01361 if(format_ptr == NULL) {
01362 fprintf(out, "#\n# Fatal libcurl error\n");
01363 if(!use_stdout)
01364 fclose(out);
01365 return 1;
01366 }
01367 fprintf(out, "%s\n", format_ptr);
01368 free(format_ptr);
01369 }
01370
01371 if(!use_stdout)
01372 fclose(out);
01373
01374 return 0;
01375 }
01376
01377 struct curl_slist *Curl_cookie_list(struct Curl_easy *data)
01378 {
01379 struct curl_slist *list = NULL;
01380 struct curl_slist *beg;
01381 struct Cookie *c;
01382 char *line;
01383
01384 if((data->cookies == NULL) ||
01385 (data->cookies->numcookies == 0))
01386 return NULL;
01387
01388 for(c = data->cookies->cookies; c; c = c->next) {
01389 if(!c->domain)
01390 continue;
01391 line = get_netscape_format(c);
01392 if(!line) {
01393 curl_slist_free_all(list);
01394 return NULL;
01395 }
01396 beg = Curl_slist_append_nodup(list, line);
01397 if(!beg) {
01398 free(line);
01399 curl_slist_free_all(list);
01400 return NULL;
01401 }
01402 list = beg;
01403 }
01404
01405 return list;
01406 }
01407
01408 void Curl_flush_cookies(struct Curl_easy *data, int cleanup)
01409 {
01410 if(data->set.str[STRING_COOKIEJAR]) {
01411 if(data->change.cookielist) {
01412
01413
01414
01415 Curl_cookie_loadfiles(data);
01416 }
01417
01418 Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
01419
01420
01421 if(cookie_output(data->cookies, data->set.str[STRING_COOKIEJAR]))
01422 infof(data, "WARNING: failed to save cookies in %s\n",
01423 data->set.str[STRING_COOKIEJAR]);
01424 }
01425 else {
01426 if(cleanup && data->change.cookielist) {
01427
01428
01429 curl_slist_free_all(data->change.cookielist);
01430 data->change.cookielist = NULL;
01431 }
01432 Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
01433 }
01434
01435 if(cleanup && (!data->share || (data->cookies != data->share->cookies))) {
01436 Curl_cookie_cleanup(data->cookies);
01437 }
01438 Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
01439 }
01440
01441 #endif