#include "config.h"
#include "CookieUtil.h"
#if USE(CURL)
#include "Cookie.h"
#include <wtf/DateMath.h>
#include <wtf/Optional.h>
#include <wtf/text/WTFString.h>
#define MAX_COOKIE_LINE 5000
#define MAX_COOKIE_LINE_TXT "4999"
#define MAX_NAME 1024
#define MAX_NAME_TXT "1023"
namespace WebCore {
namespace CookieUtil {
bool isIPAddress(const String& hostname)
{
return URL::hostIsIPAddress(hostname);
}
bool domainMatch(const String& cookieDomain, const String& host)
{
size_t index = host.find(cookieDomain);
bool tailMatch = (index != WTF::notFound && index + cookieDomain.length() == host.length());
if (tailMatch && !index)
return true;
if (tailMatch && index > 0 && host[index] == '.')
return true;
if (cookieDomain[0] == '.' && cookieDomain.find(host) == 1)
return true;
return false;
}
static std::optional<double> parseExpires(const char* expires)
{
double tmp = WTF::parseDateFromNullTerminatedCharacters(expires);
if (isnan(tmp))
return { };
return std::optional<double> {tmp / WTF::msPerSecond};
}
static void parseCookieAttributes(const String& attribute, const String& domain, bool& hasMaxAge, Cookie& result)
{
size_t assignmentPosition = attribute.find('=');
String attributeName;
String attributeValue;
if (assignmentPosition != notFound) {
attributeName = attribute.substring(0, assignmentPosition).stripWhiteSpace();
attributeValue = attribute.substring(assignmentPosition + 1).stripWhiteSpace();
} else
attributeName = attribute.stripWhiteSpace();
if (equalIgnoringASCIICase(attributeName, "httponly"))
result.httpOnly = true;
else if (equalIgnoringASCIICase(attributeName, "secure"))
result.secure = true;
else if (equalIgnoringASCIICase(attributeName, "domain")) {
if (attributeValue.isEmpty())
return;
if (!isIPAddress(attributeValue) && !attributeValue.startsWith('.') && attributeValue.find('.') != notFound)
attributeValue = "." + attributeValue;
if (domainMatch(attributeValue, domain))
result.domain = attributeValue;
} else if (equalIgnoringASCIICase(attributeName, "max-age")) {
bool ok;
time_t expiryTime = time(0) + attributeValue.toInt64(&ok);
if (ok) {
result.expires = (double)expiryTime;
result.session = false;
hasMaxAge = true;
}
} else if (equalIgnoringASCIICase(attributeName, "expires") && !hasMaxAge) {
if (auto expiryTime = parseExpires(attributeValue.utf8().data())) {
result.expires = expiryTime.value();
result.session = false;
}
} else if (equalIgnoringASCIICase(attributeName, "path")) {
if (!attributeValue.isEmpty() && attributeValue.startsWith('/'))
result.path = attributeValue;
}
}
bool parseCookieHeader(const String& cookieLine, const String& domain, Cookie& result)
{
if (cookieLine.length() >= MAX_COOKIE_LINE)
return false;
size_t separatorPosition = cookieLine.find(';');
String cookiePair = separatorPosition == notFound ? cookieLine : cookieLine.substring(0, separatorPosition);
String cookieName;
String cookieValue;
size_t assignmentPosition = cookieLine.find('=');
if (assignmentPosition == notFound)
cookieValue = cookiePair;
else {
cookieName = cookiePair.substring(0, assignmentPosition);
cookieValue = cookiePair.substring(assignmentPosition + 1);
}
result.name = cookieName.stripWhiteSpace();
result.value = cookieValue.stripWhiteSpace();
bool hasMaxAge = false;
result.session = true;
Vector<String> cookieAttributes;
cookieLine.split(';', true, cookieAttributes);
for (auto attribute : cookieAttributes)
parseCookieAttributes(attribute, domain, hasMaxAge, result);
return true;
}
}
}
#endif