* 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 *uri_path)
{
size_t cookie_path_len;
size_t uri_path_len;
- char *uri_path = NULL;
- char *pos;
bool ret = FALSE;
/* cookie_path must not have last '/' separator. ex: /sample */
return TRUE;
}
- uri_path = strdup(request_uri);
- if(!uri_path)
- return FALSE;
- pos = strchr(uri_path, '?');
- if(pos)
- *pos = 0x0;
-
/* #-fragments are already cut off! */
- if(0 == strlen(uri_path) || uri_path[0] != '/') {
- strstore(&uri_path, "/", 1);
- if(!uri_path)
- return FALSE;
- }
+ if(0 == strlen(uri_path) || uri_path[0] != '/')
+ uri_path = "/";
/*
* here, RFC6265 5.1.4 says
uri_path_len = strlen(uri_path);
- if(uri_path_len < cookie_path_len) {
- ret = FALSE;
+ if(uri_path_len < cookie_path_len)
goto pathmatched;
- }
/* not using checkprefix() because matching should be case-sensitive */
- if(strncmp(cookie_path, uri_path, cookie_path_len)) {
- ret = FALSE;
+ if(strncmp(cookie_path, uri_path, cookie_path_len))
goto pathmatched;
- }
/* The cookie-path and the uri-path are identical. */
if(cookie_path_len == uri_path_len) {
goto pathmatched;
}
- ret = FALSE;
-
pathmatched:
- free(uri_path);
return ret;
}
*/
static char *sanitize_cookie_path(const char *cookie_path)
{
- size_t len;
- char *new_path = strdup(cookie_path);
- if(!new_path)
- return NULL;
+ size_t len = strlen(cookie_path);
- /* some stupid site sends path attribute with '"'. */
- len = strlen(new_path);
- if(new_path[0] == '\"') {
- memmove(new_path, new_path + 1, len);
+ /* some sites send path attribute within '"'. */
+ if(cookie_path[0] == '\"') {
+ cookie_path++;
len--;
}
- if(len && (new_path[len - 1] == '\"')) {
- new_path[--len] = 0x0;
- }
+ if(len && (cookie_path[len - 1] == '\"'))
+ len--;
/* RFC6265 5.2.4 The Path Attribute */
- if(new_path[0] != '/') {
+ if(cookie_path[0] != '/')
/* Let cookie-path be the default-path. */
- strstore(&new_path, "/", 1);
- return new_path;
- }
+ return strdup("/");
+ /* remove trailing slash */
/* convert /hoge/ to /hoge */
- if(len && new_path[len - 1] == '/') {
- new_path[len - 1] = 0x0;
- }
+ if(len && cookie_path[len - 1] == '/')
+ len--;
- return new_path;
+ return Curl_memdup0(cookie_path, len);
}
/*
*/
static void strstore(char **str, const char *newstr, size_t len)
{
- DEBUGASSERT(newstr);
DEBUGASSERT(str);
free(*str);
+ if(!len) {
+ len++;
+ newstr = "";
+ }
*str = Curl_memdup0(newstr, len);
}
now = time(NULL);
do {
- size_t vlen;
- size_t nlen;
-
- while(ISBLANK(*ptr))
- ptr++;
+ struct Curl_str name;
+ struct Curl_str val;
/* we have a <name>=<value> pair or a stand-alone word here */
- nlen = strcspn(ptr, ";\t\r\n=");
- if(nlen) {
+ if(!Curl_str_cspn(&ptr, &name, ";\t\r\n=")) {
bool done = FALSE;
bool sep = FALSE;
- const char *namep = ptr;
- const char *valuep;
-
- ptr += nlen;
+ Curl_str_trimblanks(&name);
- /* trim trailing spaces and tabs after name */
- while(nlen && ISBLANK(namep[nlen - 1]))
- nlen--;
+ if(!Curl_str_single(&ptr, '=')) {
+ sep = TRUE; /* a '=' was used */
+ if(!Curl_str_cspn(&ptr, &val, ";\r\n")) {
+ Curl_str_trimblanks(&val);
- if(*ptr == '=') {
- ptr++;
- /* Skip spaces and tabs before the value */
- while(ISBLANK(*ptr))
- ptr++;
-
- vlen = strcspn(ptr, ";\r\n");
- valuep = ptr;
- sep = TRUE;
- ptr = &valuep[vlen];
-
- /* Strip off trailing whitespace from the value */
- while(vlen && ISBLANK(valuep[vlen-1]))
- vlen--;
-
- /* Reject cookies with a TAB inside the value */
- if(memchr(valuep, '\t', vlen)) {
- infof(data, "cookie contains TAB, dropping");
- return CERR_TAB;
+ /* Reject cookies with a TAB inside the value */
+ if(memchr(val.str, '\t', val.len)) {
+ infof(data, "cookie contains TAB, dropping");
+ return CERR_TAB;
+ }
}
}
else {
- valuep = NULL;
- vlen = 0;
+ val.str = NULL;
+ val.len = 0;
}
/*
* combination of name + contents. Chrome and Firefox support 4095 or
* 4096 bytes combo
*/
- if(nlen >= (MAX_NAME-1) || vlen >= (MAX_NAME-1) ||
- ((nlen + vlen) > MAX_NAME)) {
+ if(name.len >= (MAX_NAME-1) || val.len >= (MAX_NAME-1) ||
+ ((name.len + val.len) > MAX_NAME)) {
infof(data, "oversized cookie dropped, name/val %zu + %zu bytes",
- nlen, vlen);
+ name.len, val.len);
return CERR_TOO_BIG;
}
* "the rest". Prefixes must start with '__' and end with a '-', so
* only test for names where that can possibly be true.
*/
- if(nlen >= 7 && namep[0] == '_' && namep[1] == '_') {
- if(strncasecompare("__Secure-", namep, 9))
- co->prefix_secure = TRUE;
- else if(strncasecompare("__Host-", namep, 7))
- co->prefix_host = TRUE;
- }
+ if(strncasecompare("__Secure-", name.str, 9))
+ co->prefix_secure = TRUE;
+ else if(strncasecompare("__Host-", name.str, 7))
+ co->prefix_host = TRUE;
/*
* Use strstore() below to properly deal with received cookie
/* Bad name/value pair. */
return CERR_NO_SEP;
- strstore(&co->name, namep, nlen);
- strstore(&co->value, valuep, vlen);
+ strstore(&co->name, name.str, name.len);
+ strstore(&co->value, val.str, val.len);
done = TRUE;
if(!co->name || !co->value)
return CERR_NO_NAME_VALUE;
return CERR_INVALID_OCTET;
}
}
- else if(!vlen) {
+ else if(!val.len) {
/*
* this was a "<name>=" with no content, and we must allow
* 'secure' and 'httponly' specified this weirdly
* using a secure protocol, or when the cookie is being set by
* reading from file
*/
- if((nlen == 6) && strncasecompare("secure", namep, 6)) {
+ if(Curl_str_casecompare(&name, "secure")) {
if(secure || !ci->running) {
co->secure = TRUE;
}
return CERR_BAD_SECURE;
}
}
- else if((nlen == 8) && strncasecompare("httponly", namep, 8))
+ else if(Curl_str_casecompare(&name, "httponly"))
co->httponly = TRUE;
else if(sep)
/* there was a '=' so we are not done parsing this field */
}
if(done)
;
- else if((nlen == 4) && strncasecompare("path", namep, 4)) {
- strstore(&co->path, valuep, vlen);
+ else if(Curl_str_casecompare(&name, "path")) {
+ strstore(&co->path, val.str, val.len);
if(!co->path)
return CERR_OUT_OF_MEMORY;
free(co->spath); /* if this is set again */
if(!co->spath)
return CERR_OUT_OF_MEMORY;
}
- else if((nlen == 6) &&
- strncasecompare("domain", namep, 6) && vlen) {
+ else if(Curl_str_casecompare(&name, "domain") && val.len) {
bool is_ip;
/*
* the given domain is not valid and thus cannot be set.
*/
- if('.' == valuep[0]) {
- valuep++; /* ignore preceding dot */
- vlen--;
- }
+ if('.' == val.str[0])
+ Curl_str_nudge(&val, 1);
#ifndef USE_LIBPSL
/*
* TLD or otherwise "protected" suffix. To reduce risk, we require a
* dot OR the exact hostname being "localhost".
*/
- if(bad_domain(valuep, vlen))
+ if(bad_domain(val.str, val.len))
domain = ":";
#endif
- is_ip = Curl_host_is_ipnum(domain ? domain : valuep);
+ is_ip = Curl_host_is_ipnum(domain ? domain : val.str);
if(!domain
- || (is_ip && !strncmp(valuep, domain, vlen) &&
- (vlen == strlen(domain)))
- || (!is_ip && cookie_tailmatch(valuep, vlen, domain))) {
- strstore(&co->domain, valuep, vlen);
+ || (is_ip && !strncmp(val.str, domain, val.len) &&
+ (val.len == strlen(domain)))
+ || (!is_ip && cookie_tailmatch(val.str, val.len, domain))) {
+ strstore(&co->domain, val.str, val.len);
if(!co->domain)
return CERR_OUT_OF_MEMORY;
* not a domain to which the current host belongs. Mark as bad.
*/
infof(data, "skipped cookie with bad tailmatch domain: %s",
- valuep);
+ val.str);
return CERR_NO_TAILMATCH;
}
}
- else if((nlen == 7) && strncasecompare("version", namep, 7)) {
+ else if(Curl_str_casecompare(&name, "version")) {
/* just ignore */
}
- else if((nlen == 7) && strncasecompare("max-age", namep, 7)) {
+ else if(Curl_str_casecompare(&name, "max-age") && val.len) {
/*
* Defined in RFC2109:
*
* cookie should be discarded immediately.
*/
int rc;
- const char *maxage = valuep;
+ const char *maxage = val.str;
if(*maxage == '\"')
maxage++;
rc = Curl_str_number(&maxage, &co->expires, CURL_OFF_T_MAX);
}
cap_expires(now, co);
}
- else if((nlen == 7) && strncasecompare("expires", namep, 7)) {
- if(!co->expires && (vlen < MAX_DATE_LENGTH)) {
+ else if(Curl_str_casecompare(&name, "expires") && val.len) {
+ if(!co->expires && (val.len < MAX_DATE_LENGTH)) {
/*
* Let max-age have priority.
*
* will be treated as a session cookie
*/
char dbuf[MAX_DATE_LENGTH + 1];
- memcpy(dbuf, valuep, vlen);
- dbuf[vlen] = 0;
+ memcpy(dbuf, val.str, val.len);
+ dbuf[val.len] = 0;
co->expires = Curl_getdate_capped(dbuf);
/*
* Else, this is the second (or more) name we do not know about!
*/
}
- else {
- /* this is an "illegal" <what>=<this> pair */
- }
- while(ISBLANK(*ptr))
- ptr++;
- if(*ptr == ';')
- ptr++;
- else
+ if(Curl_str_single(&ptr, ';'))
break;
} while(1);
if(!co->path && path) {
/*
- * No path was given in the header line, set the default. Note that the
- * passed-in path to this function MAY have a '?' and following part that
- * MUST NOT be stored as part of the path.
+ * No path was given in the header line, set the default.
*/
- char *queryp = strchr(path, '?');
-
- /*
- * queryp is where the interesting part of the path ends, so now we
- * want to the find the last
- */
- char *endslash;
- if(!queryp)
- endslash = strrchr(path, '/');
- else
- endslash = memrchr(path, '/', (queryp - path));
+ const char *endslash = strrchr(path, '/');
if(endslash) {
- size_t pathlen = (endslash-path + 1); /* include end slash */
+ size_t pathlen = (endslash - path + 1); /* include end slash */
co->path = Curl_memdup0(path, pathlen);
if(co->path) {
co->spath = sanitize_cookie_path(co->path);