* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
#include "urldata.h"
#include "cookie.h"
-#include "strequal.h"
#include "strtok.h"
#include "sendf.h"
#include "slist.h"
#include "share.h"
#include "strtoofft.h"
-#include "rawstr.h"
+#include "strcase.h"
#include "curl_memrchr.h"
#include "inet_pton.h"
if(hostname_len < cookie_domain_len)
return FALSE;
- if(!Curl_raw_equal(cooke_domain, hostname+hostname_len-cookie_domain_len))
+ if(!strcasecompare(cooke_domain, hostname+hostname_len-cookie_domain_len))
return FALSE;
/* A lead char of cookie_domain is not '.'.
* matching cookie path and url path
* RFC6265 5.1.4 Paths and Path-Match
*/
-static bool pathmatch(const char* cookie_path, const char* request_uri)
+static bool pathmatch(const char *cookie_path, const char *request_uri)
{
size_t cookie_path_len;
size_t uri_path_len;
- char* uri_path = NULL;
- char* pos;
+ char *uri_path = NULL;
+ char *pos;
bool ret = FALSE;
/* cookie_path must not have last '/' separator. ex: /sample */
/* this was a "<name>=" with no content, and we must allow
'secure' and 'httponly' specified this weirdly */
done = TRUE;
- if(Curl_raw_equal("secure", name))
+ if(strcasecompare("secure", name))
co->secure = TRUE;
- else if(Curl_raw_equal("httponly", name))
+ else if(strcasecompare("httponly", name))
co->httponly = TRUE;
else if(sep)
/* there was a '=' so we're not done parsing this field */
}
if(done)
;
- else if(Curl_raw_equal("path", name)) {
+ else if(strcasecompare("path", name)) {
strstore(&co->path, whatptr);
if(!co->path) {
badcookie = TRUE; /* out of memory bad */
break;
}
}
- else if(Curl_raw_equal("domain", name)) {
+ else if(strcasecompare("domain", name)) {
bool is_ip;
- const char *dotp;
/* Now, we make sure that our host is within the given domain,
or the given domain is not valid and thus cannot be set. */
if('.' == whatptr[0])
whatptr++; /* ignore preceding dot */
- is_ip = isip(domain ? domain : whatptr);
+#ifndef USE_LIBPSL
+ /*
+ * Without PSL we don't know when the incoming cookie is set on a
+ * TLD or otherwise "protected" suffix. To reduce risk, we require a
+ * dot OR the exact host name being "localhost".
+ */
+ {
+ const char *dotp;
+ /* check for more dots */
+ dotp = strchr(whatptr, '.');
+ if(!dotp && !strcasecompare("localhost", whatptr))
+ domain=":";
+ }
+#endif
- /* check for more dots */
- dotp = strchr(whatptr, '.');
- if(!dotp)
- domain=":";
+ is_ip = isip(domain ? domain : whatptr);
if(!domain
|| (is_ip && !strcmp(whatptr, domain))
whatptr);
}
}
- else if(Curl_raw_equal("version", name)) {
+ else if(strcasecompare("version", name)) {
strstore(&co->version, whatptr);
if(!co->version) {
badcookie = TRUE;
break;
}
}
- else if(Curl_raw_equal("max-age", name)) {
+ else if(strcasecompare("max-age", name)) {
/* Defined in RFC2109:
Optional. The Max-Age attribute defines the lifetime of the
break;
}
}
- else if(Curl_raw_equal("expires", name)) {
+ else if(strcasecompare("expires", name)) {
strstore(&co->expirestr, whatptr);
if(!co->expirestr) {
badcookie = TRUE;
As far as I can see, it is set to true when the cookie says
.domain.com and to false when the domain is complete www.domain.com
*/
- co->tailmatch = Curl_raw_equal(ptr, "TRUE")?TRUE:FALSE;
+ co->tailmatch = strcasecompare(ptr, "TRUE")?TRUE:FALSE;
break;
case 2:
/* It turns out, that sometimes the file format allows the path
fields++; /* add a field and fall down to secure */
/* FALLTHROUGH */
case 3:
- co->secure = Curl_raw_equal(ptr, "TRUE")?TRUE:FALSE;
+ co->secure = strcasecompare(ptr, "TRUE")?TRUE:FALSE;
break;
case 4:
co->expires = curlx_strtoofft(ptr, NULL, 10);
/* Check if the domain is a Public Suffix and if yes, ignore the cookie.
This needs a libpsl compiled with builtin data. */
if(domain && co->domain && !isip(co->domain)) {
- if(((psl = psl_builtin()) != NULL)
- && !psl_is_cookie_domain_acceptable(psl, domain, co->domain)) {
+ psl = psl_builtin();
+ if(psl && !psl_is_cookie_domain_acceptable(psl, domain, co->domain)) {
infof(data,
"cookie '%s' dropped, domain '%s' must not set cookies for '%s'\n",
co->name, domain, co->domain);
clist = c->cookies;
replace_old = FALSE;
while(clist) {
- if(Curl_raw_equal(clist->name, co->name)) {
+ if(strcasecompare(clist->name, co->name)) {
/* the names are identical */
if(clist->domain && co->domain) {
- if(Curl_raw_equal(clist->domain, co->domain))
+ if(strcasecompare(clist->domain, co->domain) &&
+ (clist->tailmatch == co->tailmatch))
/* The domains are identical */
replace_old=TRUE;
}
/* the domains were identical */
if(clist->spath && co->spath) {
- if(Curl_raw_equal(clist->spath, co->spath)) {
+ if(strcasecompare(clist->spath, co->spath)) {
replace_old = TRUE;
}
else
return co;
}
+/*
+ * get_line() makes sure to only return complete whole lines that fit in 'len'
+ * bytes and end with a newline.
+ */
+static char *get_line(char *buf, int len, FILE *input)
+{
+ bool partial = FALSE;
+ while(1) {
+ char *b = fgets(buf, len, input);
+ if(b) {
+ size_t rlen = strlen(b);
+ if(rlen && (b[rlen-1] == '\n')) {
+ if(partial) {
+ partial = FALSE;
+ continue;
+ }
+ return b;
+ }
+ else
+ /* read a partial, discard the next piece that ends with newline */
+ partial = TRUE;
+ }
+ else
+ break;
+ }
+ return NULL;
+}
+
+
/*****************************************************************************
*
* Curl_cookie_init()
}
c->running = FALSE; /* this is not running, this is init */
- if(file && strequal(file, "-")) {
+ if(file && !strcmp(file, "-")) {
fp = stdin;
fromfile=FALSE;
}
line = malloc(MAX_COOKIE_LINE);
if(!line)
goto fail;
- while(fgets(line, MAX_COOKIE_LINE, fp)) {
+ while(get_line(line, MAX_COOKIE_LINE, fp)) {
if(checkprefix("Set-Cookie:", line)) {
/* This is a cookie line, get it! */
lineptr=&line[11];
return 0;
}
+#define CLONE(field) \
+ do { \
+ if(src->field) { \
+ d->field = strdup(src->field); \
+ if(!d->field) \
+ goto fail; \
+ } \
+ } while(0)
+
+static struct Cookie *dup_cookie(struct Cookie *src)
+{
+ struct Cookie *d = calloc(sizeof(struct Cookie), 1);
+ if(d) {
+ CLONE(expirestr);
+ CLONE(domain);
+ CLONE(path);
+ CLONE(spath);
+ CLONE(name);
+ CLONE(value);
+ CLONE(maxage);
+ CLONE(version);
+ d->expires = src->expires;
+ d->tailmatch = src->tailmatch;
+ d->secure = src->secure;
+ d->livecookie = src->livecookie;
+ d->httponly = src->httponly;
+ }
+ return d;
+
+ fail:
+ freecookie(d);
+ return NULL;
+}
+
/*****************************************************************************
*
* Curl_cookie_getlist()
/* now check if the domain is correct */
if(!co->domain ||
(co->tailmatch && !is_ip && tailmatch(co->domain, host)) ||
- ((!co->tailmatch || is_ip) && Curl_raw_equal(host, co->domain)) ) {
+ ((!co->tailmatch || is_ip) && strcasecompare(host, co->domain)) ) {
/* the right part of the host matches the domain stuff in the
cookie data */
/* and now, we know this is a match and we should create an
entry for the return-linked-list */
- newco = malloc(sizeof(struct Cookie));
+ newco = dup_cookie(co);
if(newco) {
- /* first, copy the whole source cookie: */
- memcpy(newco, co, sizeof(struct Cookie));
-
/* then modify our next */
newco->next = mainco;
else {
fail:
/* failure, clear up the allocated chain and return NULL */
- while(mainco) {
- co = mainco->next;
- free(mainco);
- mainco = co;
- }
-
+ Curl_cookie_freelist(mainco);
return NULL;
}
}
void Curl_cookie_clearall(struct CookieInfo *cookies)
{
if(cookies) {
- Curl_cookie_freelist(cookies->cookies, TRUE);
+ Curl_cookie_freelist(cookies->cookies);
cookies->cookies = NULL;
cookies->numcookies = 0;
}
*
* Free a list of cookies previously returned by Curl_cookie_getlist();
*
- * The 'cookiestoo' argument tells this function whether to just free the
- * list or actually also free all cookies within the list as well.
- *
****************************************************************************/
-void Curl_cookie_freelist(struct Cookie *co, bool cookiestoo)
+void Curl_cookie_freelist(struct Cookie *co)
{
struct Cookie *next;
while(co) {
next = co->next;
- if(cookiestoo)
- freecookie(co);
- else
- free(co); /* we only free the struct since the "members" are all just
- pointed out in the main cookie list! */
+ freecookie(co);
co = next;
}
}
{
if(c) {
free(c->filename);
- Curl_cookie_freelist(c->cookies, TRUE);
+ Curl_cookie_freelist(c->cookies);
free(c); /* free the base struct as well */
}
}
/* at first, remove expired cookies */
remove_expired(c);
- if(strequal("-", dumphere)) {
+ if(!strcmp("-", dumphere)) {
/* use stdout */
out = stdout;
use_stdout=TRUE;