static struct cookie *cookie_from_netscape_line(char *cookie_line) { struct cookie *new_cookie = NULL; if (cookie_line && cookie_line[0]) { /* Only parse the line if it is not a comment and it has the requisite number * of tabs. Comment lines begin with a leading # symbol. * Syntax checking is rudimentary, because these lines are * machine-generated. */ if (cookie_line[0] != '#' && count_tabs(cookie_line) == FIELDS_PER_COOKIE_LINE - 1) { char *start, *end; new_cookie = allocZeroMem(sizeof(struct cookie)); start = cookie_line; end = strchr(cookie_line, '\t'); new_cookie->domain = pullString1(start, end); start = end + 1; end = strchr(start, '\t'); if ((*start == 't') || (*start == 'T')) new_cookie->tail = true; else new_cookie->tail = false; start = end + 1; end = strchr(start, '\t'); new_cookie->path = pullString1(start, end); start = end + 1; if (*start == 'T' || *start == 't') new_cookie->secure = true; else new_cookie->secure = false; start = strchr(start, '\t') + 1; new_cookie->expires = strtol(start, &end, 10); /* Now end points to the tab following the expiration time. */ start = end + 1; end = strchr(start, '\t'); new_cookie->name = pullString1(start, end); start = end + 1; /* strcspn gives count of non-newline characters in string, which is the * length of the final field. Either CR or LF is considered a newline. */ new_cookie->value = pullString(start, strcspn(start, "\r\n")); /* Whenever new_cookie->tail is true, there's going to be a dot at the front of the * domain name. Libcurl even puts one there when it parses set-cookie * headers. But let's be sure. */ if (new_cookie->tail && (new_cookie->domain[0] != '.')) new_cookie->domain = prependString(new_cookie->domain, "."); } } return new_cookie; } /* cookie_from_netscape_line */
char *allocZeroString(size_t n) { return (char *)allocZeroMem(n); } /* allocZeroString */
/* Let's jump right into it - parse a cookie, as received from a website. */ bool receiveCookie(const char *url, const char *str) { struct cookie *c; const char *p, *q, *server; char *date, *s; debugPrint(3, "cookie %s", str); server = getHostURL(url); if (server == 0 || !*server) return false; /* Cookie starts with name=value. If we can't get that, go home. */ for (p = str; *p != ';' && *p; p++) ; for (q = str; *q != '='; q++) if (!*q || q >= p) return false; if (str == q) return false; c = allocZeroMem(sizeof(struct cookie)); c->tail = false; c->name = pullString1(str, q); ++q; if (p - q > 0) c->value = pullString1(q, p); else c->value = emptyString; c->server = cloneString(server); if (date = extractHeaderParam(str, "expires")) { c->expires = parseHeaderDate(date); nzFree(date); } else if (date = extractHeaderParam(str, "max-age")) { int n = stringIsNum(date); if (n >= 0) { time_t now = time(0); c->expires = now + n; } nzFree(date); } c->path = extractHeaderParam(str, "path"); if (!c->path) { /* The url indicates the path for this cookie, if a path is not explicitly given */ const char *dir, *dirend; getDirURL(url, &dir, &dirend); c->path = pullString1(dir, dirend); } else { if (!c->path[0] || c->path[strlen(c->path) - 1] != '/') c->path = appendString(c->path, "/"); if (c->path[0] != '/') c->path = prependString(c->path, "/"); } if (!(c->domain = extractHeaderParam(str, "domain"))) { c->domain = cloneString(server); } else { /* Is this safe for tail-matching? */ const char *domtemp = c->domain; if (domtemp[0] == '.') domtemp++; if (!domainSecurityCheck(server, domtemp)) { nzFree(c->domain); c->domain = cloneString(server); } else { /* It's safe to do tail-matching with this domain. */ c->tail = true; /* Guarantee that it does in fact start with dot, prepending if necessary.. */ if (c->domain[0] != '.') c->domain = prependString(c->domain, "."); } } if (s = extractHeaderParam(str, "secure")) { c->secure = true; nzFree(s); } cookieForLibcurl(c); freeCookie(c); nzFree(c); return true; } /* receiveCookie */