#include "config.h"
#include "PlatformCookieJar.h"
#if USE(CURL)
#include "Cookie.h"
#include "URL.h"
#include "ResourceHandleManager.h"
#include <wtf/DateMath.h>
#include <wtf/HashMap.h>
#include <wtf/text/StringBuilder.h>
#include <wtf/text/StringHash.h>
#include <wtf/text/WTFString.h>
namespace WebCore {
static void readCurlCookieToken(const char*& cookie, String& token)
{
while (cookie && cookie[0] && cookie[0] != '\t') {
token.append(cookie[0]);
cookie++;
}
if (cookie[0] == '\t')
cookie++;
}
static void addMatchingCurlCookie(const char* cookie, const String& domain, const String& path, StringBuilder& cookies, bool httponly)
{
if (!cookie)
return;
String cookieDomain;
readCurlCookieToken(cookie, cookieDomain);
bool subDomain = false;
if (cookieDomain.startsWith("#HttpOnly_")) {
if (httponly)
cookieDomain.remove(0, 10);
else
return;
}
if (cookieDomain[0] == '.') {
cookieDomain.remove(0);
int lenDiff = domain.length() - cookieDomain.length();
int index = domain.find(cookieDomain);
if (index == lenDiff)
subDomain = true;
}
if (!subDomain && cookieDomain != domain)
return;
String strBoolean;
readCurlCookieToken(cookie, strBoolean);
String strPath;
readCurlCookieToken(cookie, strPath);
int index = path.find(strPath);
if (index)
return;
String strSecure;
readCurlCookieToken(cookie, strSecure);
String strExpires;
readCurlCookieToken(cookie, strExpires);
int expires = strExpires.toInt();
time_t now = 0;
time(&now);
if (expires && now > expires)
return;
String strName;
readCurlCookieToken(cookie, strName);
String strValue;
readCurlCookieToken(cookie, strValue);
if (cookies.length() > 0)
cookies.append("; ");
cookies.append(strName);
cookies.append("=");
cookies.append(strValue);
}
static String getNetscapeCookieFormat(const URL& url, const String& value)
{
if (value.isEmpty())
return "";
String valueStr;
if (value.is8Bit())
valueStr = value;
else
valueStr = String::make8BitFrom16BitSource(value.characters16(), value.length());
Vector<String> attributes;
valueStr.split(';', false, attributes);
if (!attributes.size())
return "";
String cookieName, cookieValue;
Vector<String>::iterator attribute = attributes.begin();
if (attribute->contains('=')) {
Vector<String> nameValuePair;
attribute->split('=', true, nameValuePair);
cookieName = nameValuePair[0];
cookieValue = nameValuePair[1];
} else {
cookieName = *attribute;
}
int expires = 0;
String secure = "FALSE";
String path = url.baseAsString().substring(url.pathStart());
if (path.length() > 1 && path.endsWith('/'))
path.remove(path.length() - 1);
String domain = url.host();
for (++attribute; attribute != attributes.end(); ++attribute) {
if (attribute->contains('=')) {
Vector<String> keyValuePair;
attribute->split('=', true, keyValuePair);
String key = keyValuePair[0].stripWhiteSpace().lower();
String val = keyValuePair[1].stripWhiteSpace();
if (key == "expires") {
CString dateStr(reinterpret_cast<const char*>(val.characters8()), val.length());
expires = WTF::parseDateFromNullTerminatedCharacters(dateStr.data()) / WTF::msPerSecond;
} else if (key == "max-age")
expires = time(0) + val.toInt();
else if (key == "domain")
domain = val;
else if (key == "path")
path = val;
} else {
String key = attribute->stripWhiteSpace().lower();
if (key == "secure")
secure = "TRUE";
}
}
String allowSubdomains = domain.startsWith('.') ? "TRUE" : "FALSE";
String expiresStr = String::number(expires);
int finalStringLength = domain.length() + path.length() + expiresStr.length() + cookieName.length();
finalStringLength += cookieValue.length() + secure.length() + allowSubdomains.length();
finalStringLength += 6;
StringBuilder cookieStr;
cookieStr.reserveCapacity(finalStringLength);
cookieStr.append(domain + "\t");
cookieStr.append(allowSubdomains + "\t");
cookieStr.append(path + "\t");
cookieStr.append(secure + "\t");
cookieStr.append(expiresStr + "\t");
cookieStr.append(cookieName + "\t");
cookieStr.append(cookieValue);
return cookieStr.toString();
}
void setCookiesFromDOM(const NetworkStorageSession&, const URL&, const URL& url, const String& value)
{
CURL* curl = curl_easy_init();
if (!curl)
return;
const char* cookieJarFileName = ResourceHandleManager::sharedInstance()->getCookieJarFileName();
CURLSH* curlsh = ResourceHandleManager::sharedInstance()->getCurlShareHandle();
curl_easy_setopt(curl, CURLOPT_COOKIEJAR, cookieJarFileName);
curl_easy_setopt(curl, CURLOPT_SHARE, curlsh);
String cookie = getNetscapeCookieFormat(url, value);
if (!cookie.is8Bit())
cookie = String::make8BitFrom16BitSource(cookie.characters16(), cookie.length());
CString strCookie(reinterpret_cast<const char*>(cookie.characters8()), cookie.length());
curl_easy_setopt(curl, CURLOPT_COOKIELIST, strCookie.data());
curl_easy_cleanup(curl);
}
static String cookiesForSession(const NetworkStorageSession&, const URL&, const URL& url, bool httponly)
{
String cookies;
CURL* curl = curl_easy_init();
if (!curl)
return cookies;
CURLSH* curlsh = ResourceHandleManager::sharedInstance()->getCurlShareHandle();
curl_easy_setopt(curl, CURLOPT_SHARE, curlsh);
struct curl_slist* list = 0;
curl_easy_getinfo(curl, CURLINFO_COOKIELIST, &list);
if (list) {
String domain = url.host();
String path = url.path();
StringBuilder cookiesBuilder;
struct curl_slist* item = list;
while (item) {
const char* cookie = item->data;
addMatchingCurlCookie(cookie, domain, path, cookiesBuilder, httponly);
item = item->next;
}
cookies = cookiesBuilder.toString();
curl_slist_free_all(list);
}
curl_easy_cleanup(curl);
return cookies;
}
String cookiesForDOM(const NetworkStorageSession& session, const URL& firstParty, const URL& url)
{
return cookiesForSession(session, firstParty, url, false);
}
String cookieRequestHeaderFieldValue(const NetworkStorageSession& session, const URL& firstParty, const URL& url)
{
return cookiesForSession(session, firstParty, url, true);
}
bool cookiesEnabled(const NetworkStorageSession&, const URL& , const URL& )
{
return true;
}
bool getRawCookies(const NetworkStorageSession&, const URL& , const URL& , Vector<Cookie>& rawCookies)
{
rawCookies.clear();
return false; }
void deleteCookie(const NetworkStorageSession&, const URL&, const String&)
{
}
void getHostnamesWithCookies(const NetworkStorageSession&, HashSet<String>& hostnames)
{
}
void deleteCookiesForHostname(const NetworkStorageSession&, const String& hostname)
{
}
void deleteAllCookies(const NetworkStorageSession&)
{
}
void deleteAllCookiesModifiedAfterDate(const NetworkStorageSession&, double)
{
}
}
#endif