diff --git a/docs/libcurl/opts/CURLOPT_COOKIELIST.md b/docs/libcurl/opts/CURLOPT_COOKIELIST.md index d7a6c0b129..138a927a56 100644 --- a/docs/libcurl/opts/CURLOPT_COOKIELIST.md +++ b/docs/libcurl/opts/CURLOPT_COOKIELIST.md @@ -81,7 +81,7 @@ NULL int main(void) { - char *my_cookie = + const char *my_cookie = "example.com" /* Hostname */ SEP "FALSE" /* Include subdomains */ SEP "/" /* Path */ diff --git a/lib/cookie.c b/lib/cookie.c index aaa65368cf..e1f1c306a0 100644 --- a/lib/cookie.c +++ b/lib/cookie.c @@ -815,10 +815,9 @@ parse_netscape(struct Cookie *co, * This line is NOT an HTTP header style line, we do offer support for * reading the odd netscape cookies-file format here */ - char *ptr; - char *firstptr; - char *tok_buf = NULL; + const char *ptr, *next; int fields; + size_t len; /* * In 2008, Internet Explorer introduced HTTP-only cookies to prevent XSS @@ -835,29 +834,22 @@ parse_netscape(struct Cookie *co, /* do not even try the comments */ return CERR_COMMENT; - /* strip off the possible end-of-line characters */ - ptr = strchr(lineptr, '\r'); - if(ptr) - *ptr = 0; /* clear it */ - ptr = strchr(lineptr, '\n'); - if(ptr) - *ptr = 0; /* clear it */ - - /* tokenize on TAB */ - firstptr = Curl_strtok_r((char *)lineptr, "\t", &tok_buf); - /* * Now loop through the fields and init the struct we already have * allocated */ fields = 0; - for(ptr = firstptr; ptr; - ptr = Curl_strtok_r(NULL, "\t", &tok_buf), fields++) { + for(next = lineptr; next; fields++) { + ptr = next; + len = strcspn(ptr, "\t\r\n"); + next = (ptr[len] == '\t' ? &ptr[len + 1] : NULL); switch(fields) { case 0: - if(ptr[0]=='.') /* skip preceding dots */ + if(ptr[0]=='.') { /* skip preceding dots */ ptr++; - co->domain = strdup(ptr); + len--; + } + co->domain = Curl_memdup0(ptr, len); if(!co->domain) return CERR_OUT_OF_MEMORY; break; @@ -867,13 +859,13 @@ parse_netscape(struct Cookie *co, * domain can access the variable. Set TRUE when the cookie says * .domain.com and to false when the domain is complete www.domain.com */ - co->tailmatch = !!strcasecompare(ptr, "TRUE"); + co->tailmatch = !!strncasecompare(ptr, "TRUE", len); break; case 2: /* The file format allows the path field to remain not filled in */ - if(strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) { + if(strncmp("TRUE", ptr, len) && strncmp("FALSE", ptr, len)) { /* only if the path does not look like a boolean option! */ - co->path = strdup(ptr); + co->path = Curl_memdup0(ptr, len); if(!co->path) return CERR_OUT_OF_MEMORY; else { @@ -894,7 +886,7 @@ parse_netscape(struct Cookie *co, FALLTHROUGH(); case 3: co->secure = FALSE; - if(strcasecompare(ptr, "TRUE")) { + if(strncasecompare(ptr, "TRUE", len)) { if(secure || ci->running) co->secure = TRUE; else @@ -902,11 +894,19 @@ parse_netscape(struct Cookie *co, } break; case 4: - if(curlx_strtoofft(ptr, NULL, 10, &co->expires)) - return CERR_RANGE; + { + char *endp; + const char *p; + /* make sure curlx_strtoofft won't read past the current field */ + for(p = ptr; p < &ptr[len] && ISDIGIT(*p); ++p) + ; + if(p == ptr || p != &ptr[len] || + curlx_strtoofft(ptr, &endp, 10, &co->expires) || endp != &ptr[len]) + return CERR_RANGE; + } break; case 5: - co->name = strdup(ptr); + co->name = Curl_memdup0(ptr, len); if(!co->name) return CERR_OUT_OF_MEMORY; else { @@ -918,7 +918,7 @@ parse_netscape(struct Cookie *co, } break; case 6: - co->value = strdup(ptr); + co->value = Curl_memdup0(ptr, len); if(!co->value) return CERR_OUT_OF_MEMORY; break; diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index ec30fdf31c..73ef90920a 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -269,7 +269,7 @@ test3008 test3009 test3010 test3011 test3012 test3013 test3014 test3015 \ test3016 test3017 test3018 test3019 test3020 test3021 test3022 test3023 \ test3024 test3025 test3026 test3027 test3028 test3029 test3030 test3031 \ \ -test3100 test3101 test3102 test3103 \ +test3100 test3101 test3102 test3103 test3104 \ test3200 \ test3201 test3202 test3203 test3204 test3205 test3207 diff --git a/tests/data/test3104 b/tests/data/test3104 new file mode 100644 index 0000000000..5853898514 --- /dev/null +++ b/tests/data/test3104 @@ -0,0 +1,60 @@ + + + +cookies + + + +# +# Server-side + + +HTTP/1.1 200 OK +Date: Tue, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT +ETag: "21025-dc7-39462498" +Accept-Ranges: bytes +Content-Length: 6 +Connection: close +Content-Type: text/html +Funny-head: yesyes + +-foo- + + + +# +# Client-side + + +cookies +proxy + + +http + + +lib%TESTNUMBER + + +CURLOPT_COOKIELIST with netscape format + + +http://%HOSTIP:%HTTPPORT/%TESTNUMBER + + + +# +# Verify data after the test has been "shot" + + +GET http://example.com/ HTTP/1.1 +Host: example.com +Accept: */* +Proxy-Connection: Keep-Alive +Cookie: name=value + + + + diff --git a/tests/libtest/Makefile.inc b/tests/libtest/Makefile.inc index a84886f591..174c7a8da6 100644 --- a/tests/libtest/Makefile.inc +++ b/tests/libtest/Makefile.inc @@ -75,7 +75,7 @@ LIBTESTPROGS = libauthretry libntlmconnect libprereq \ lib2402 lib2404 lib2405 \ lib2502 \ lib3010 lib3025 lib3026 lib3027 \ - lib3100 lib3101 lib3102 lib3103 lib3207 + lib3100 lib3101 lib3102 lib3103 lib3104 lib3207 libntlmconnect_SOURCES = libntlmconnect.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) libntlmconnect_LDADD = $(TESTUTIL_LIBS) @@ -718,5 +718,7 @@ lib3102_LDADD = $(TESTUTIL_LIBS) lib3103_SOURCES = lib3103.c $(SUPPORTFILES) lib3103_LDADD = $(TESTUTIL_LIBS) +lib3104_SOURCES = lib3104.c $(SUPPORTFILES) + lib3207_SOURCES = lib3207.c $(SUPPORTFILES) $(TESTUTIL) $(THREADS) $(WARNLESS) $(MULTIBYTE) lib3207_LDADD = $(TESTUTIL_LIBS) diff --git a/tests/libtest/lib3104.c b/tests/libtest/lib3104.c new file mode 100644 index 0000000000..7e0e1d80dc --- /dev/null +++ b/tests/libtest/lib3104.c @@ -0,0 +1,66 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 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 + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "test.h" + +#include "memdebug.h" + +CURLcode test(char *URL) +{ + CURLcode res = CURLE_OK; + CURLSH *share; + CURL *curl; + + curl_global_init(CURL_GLOBAL_ALL); + + share = curl_share_init(); + curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE); + + curl = curl_easy_init(); + test_setopt(curl, CURLOPT_SHARE, share); + + test_setopt(curl, CURLOPT_VERBOSE, 1L); + test_setopt(curl, CURLOPT_HEADER, 1L); + test_setopt(curl, CURLOPT_PROXY, URL); + test_setopt(curl, CURLOPT_URL, "http://example.com/"); + + test_setopt(curl, CURLOPT_COOKIEFILE, ""); + + test_setopt(curl, CURLOPT_COOKIELIST, + "example.com\tFALSE\t/\tFALSE\t0\tname\tvalue"); + + res = curl_easy_perform(curl); + if(res) { + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + } + +test_cleanup: + + /* always cleanup */ + curl_easy_cleanup(curl); + curl_share_cleanup(share); + curl_global_cleanup(); + + return res; +}