Rewrite CookieStorage

pull/103/head
Tatsuhiro Tsujikawa 2013-06-28 00:25:06 +09:00
parent 0b1e05b13b
commit 5a223115e0
20 changed files with 1059 additions and 882 deletions

View File

@ -43,23 +43,23 @@
namespace aria2 { namespace aria2 {
Cookie::Cookie Cookie::Cookie
(const std::string& name, (std::string name,
const std::string& value, std::string value,
time_t expiryTime, time_t expiryTime,
bool persistent, bool persistent,
const std::string& domain, std::string domain,
bool hostOnly, bool hostOnly,
const std::string& path, std::string path,
bool secure, bool secure,
bool httpOnly, bool httpOnly,
time_t creationTime): time_t creationTime):
name_(name), name_(std::move(name)),
value_(value), value_(std::move(value)),
expiryTime_(expiryTime), expiryTime_(expiryTime),
persistent_(persistent), persistent_(persistent),
domain_(domain), domain_(std::move(domain)),
hostOnly_(hostOnly), hostOnly_(hostOnly),
path_(path), path_(std::move(path)),
secure_(secure), secure_(secure),
httpOnly_(httpOnly), httpOnly_(httpOnly),
creationTime_(creationTime), creationTime_(creationTime),
@ -74,40 +74,6 @@ Cookie::Cookie():
creationTime_(0), creationTime_(0),
lastAccessTime_(0) {} lastAccessTime_(0) {}
Cookie::Cookie(const Cookie& c)
: name_(c.name_),
value_(c.value_),
expiryTime_(c.expiryTime_),
persistent_(c.persistent_),
domain_(c.domain_),
hostOnly_(c.hostOnly_),
path_(c.path_),
secure_(c.secure_),
httpOnly_(c.httpOnly_),
creationTime_(c.creationTime_),
lastAccessTime_(c.lastAccessTime_)
{}
Cookie::~Cookie() {}
Cookie& Cookie::operator=(const Cookie& c)
{
if(this != &c) {
name_ = c.name_;
value_ = c.value_;
expiryTime_ = c.expiryTime_;
persistent_ = c.persistent_;
domain_ = c.domain_;
hostOnly_ = c.hostOnly_;
path_ = c.path_;
secure_ = c.secure_;
httpOnly_ = c.httpOnly_;
creationTime_ = c.creationTime_;
lastAccessTime_ = c.lastAccessTime_;
}
return *this;
}
std::string Cookie::toString() const std::string Cookie::toString() const
{ {
std::string s = name_; std::string s = name_;
@ -138,6 +104,11 @@ bool Cookie::operator==(const Cookie& cookie) const
name_ == cookie.name_; name_ == cookie.name_;
} }
bool Cookie::operator!=(const Cookie& cookie) const
{
return !(*this == cookie);
}
bool Cookie::isExpired(time_t base) const bool Cookie::isExpired(time_t base) const
{ {
return persistent_ && base > expiryTime_; return persistent_ && base > expiryTime_;
@ -174,24 +145,24 @@ std::string Cookie::toNsCookieFormat() const
return ss.str(); return ss.str();
} }
void Cookie::setName(const std::string& name) void Cookie::setName(std::string name)
{ {
name_ = name; name_ = std::move(name);
} }
void Cookie::setValue(const std::string& value) void Cookie::setValue(std::string value)
{ {
value_ = value; value_ = std::move(value);
} }
void Cookie::setDomain(const std::string& domain) void Cookie::setDomain(std::string domain)
{ {
domain_ = domain; domain_ = std::move(domain);
} }
void Cookie::setPath(const std::string& path) void Cookie::setPath(std::string path)
{ {
path_ = path; path_ = std::move(path);
} }
} // namespace aria2 } // namespace aria2

View File

@ -63,23 +63,17 @@ public:
Cookie(); Cookie();
Cookie Cookie
(const std::string& name, (std::string name,
const std::string& value, std::string value,
time_t expiryTime, time_t expiryTime,
bool persistent, bool persistent,
const std::string& domain, std::string domain,
bool hostOnly, bool hostOnly,
const std::string& path, std::string path,
bool secure, bool secure,
bool httpOnly, bool httpOnly,
time_t creationTime); time_t creationTime);
Cookie(const Cookie& c);
~Cookie();
Cookie& operator=(const Cookie& c);
std::string toString() const; std::string toString() const;
bool match bool match
@ -88,6 +82,8 @@ public:
bool operator==(const Cookie& cookie) const; bool operator==(const Cookie& cookie) const;
bool operator!=(const Cookie& cookie) const;
bool isExpired(time_t base) const; bool isExpired(time_t base) const;
const std::string& getName() const const std::string& getName() const
@ -95,7 +91,7 @@ public:
return name_; return name_;
} }
void setName(const std::string& name); void setName(std::string name);
template<typename InputIterator> template<typename InputIterator>
void setName(InputIterator first, InputIterator last) void setName(InputIterator first, InputIterator last)
@ -108,7 +104,7 @@ public:
return value_; return value_;
} }
void setValue(const std::string& value); void setValue(std::string value);
template<typename InputIterator> template<typename InputIterator>
void setValue(InputIterator first, InputIterator last) void setValue(InputIterator first, InputIterator last)
@ -141,7 +137,7 @@ public:
return domain_; return domain_;
} }
void setDomain(const std::string& domain); void setDomain(std::string domain);
template<typename InputIterator> template<typename InputIterator>
void setDomain(InputIterator first, InputIterator last) void setDomain(InputIterator first, InputIterator last)
@ -164,7 +160,7 @@ public:
return path_; return path_;
} }
void setPath(const std::string& path); void setPath(std::string path);
template<typename InputIterator> template<typename InputIterator>
void setPath(InputIterator first, InputIterator last) void setPath(InputIterator first, InputIterator last)

View File

@ -2,7 +2,7 @@
/* /*
* aria2 - The high speed download utility * aria2 - The high speed download utility
* *
* Copyright (C) 2006 Tatsuhiro Tsujikawa * Copyright (C) 2013 Tatsuhiro Tsujikawa
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -56,131 +56,196 @@
namespace aria2 { namespace aria2 {
CookieStorage::DomainEntry::DomainEntry(const std::string& domain) DomainNode::DomainNode(std::string label, DomainNode* parent)
: key_(util::isNumericHost(domain)?domain:cookie::reverseDomainLevel(domain)), : label_{std::move(label)}, parent_{parent}, lastAccessTime_{0},
lastAccessTime_(0) lruAccessTime_{0}, inLru_{false}
{} {}
CookieStorage::DomainEntry::DomainEntry void DomainNode::findCookie
(const DomainEntry& c) (std::vector<const Cookie*>& out,
: key_(c.key_),
lastAccessTime_(c.lastAccessTime_),
cookies_(c.cookies_)
{}
CookieStorage::DomainEntry::~DomainEntry() {}
CookieStorage::DomainEntry& CookieStorage::DomainEntry::operator=
(const DomainEntry& c)
{
if(this != &c) {
key_ = c.key_;
lastAccessTime_ = c.lastAccessTime_;
cookies_ = c.cookies_;
}
return *this;
}
void CookieStorage::DomainEntry::swap(CookieStorage::DomainEntry& c)
{
using std::swap;
swap(key_, c.key_);
swap(lastAccessTime_, c.lastAccessTime_);
swap(cookies_, c.cookies_);
}
void swap(CookieStorage::DomainEntry& a, CookieStorage::DomainEntry& b)
{
a.swap(b);
}
void CookieStorage::DomainEntry::findCookie
(std::vector<Cookie>& out,
const std::string& requestHost, const std::string& requestHost,
const std::string& requestPath, const std::string& requestPath,
time_t now, bool secure) time_t now, bool secure)
{ {
for(std::deque<Cookie>::iterator i = cookies_.begin(), if(cookies_) {
eoi = cookies_.end(); i != eoi; ++i) { for(auto& c : *cookies_) {
if((*i).match(requestHost, requestPath, now, secure)) { if(c->match(requestHost, requestPath, now, secure)) {
(*i).setLastAccessTime(now); c->setLastAccessTime(now);
out.push_back(*i); out.push_back(c.get());
}
} }
} }
} }
bool CookieStorage::DomainEntry::addCookie(const Cookie& cookie, time_t now) bool DomainNode::addCookie(std::unique_ptr<Cookie> cookie, time_t now)
{ {
using namespace std::placeholders; using namespace std::placeholders;
setLastAccessTime(now); setLastAccessTime(now);
std::deque<Cookie>::iterator i = if(!cookies_) {
std::find(cookies_.begin(), cookies_.end(), cookie); if(cookie->isExpired(now)) {
if(i == cookies_.end()) {
if(cookie.isExpired(now)) {
return false; return false;
} else { } else {
if(cookies_.size() >= CookieStorage::MAX_COOKIE_PER_DOMAIN) { cookies_ = make_unique<std::deque<std::unique_ptr<Cookie>>>();
cookies_.erase cookies_->push_back(std::move(cookie));
(std::remove_if(cookies_.begin(), cookies_.end(), return true;
}
}
auto i = std::find_if(std::begin(*cookies_), std::end(*cookies_),
[&](const std::unique_ptr<Cookie>& c)
{
return *c == *cookie;
});
if(i == std::end(*cookies_)) {
if(cookie->isExpired(now)) {
return false;
} else {
if(cookies_->size() >= CookieStorage::MAX_COOKIE_PER_DOMAIN) {
cookies_->erase
(std::remove_if(std::begin(*cookies_), std::end(*cookies_),
std::bind(&Cookie::isExpired, _1, now)), std::bind(&Cookie::isExpired, _1, now)),
cookies_.end()); std::end(*cookies_));
if(cookies_.size() >= CookieStorage::MAX_COOKIE_PER_DOMAIN) { if(cookies_->size() >= CookieStorage::MAX_COOKIE_PER_DOMAIN) {
std::deque<Cookie>::iterator m = std::min_element auto m = std::min_element(std::begin(*cookies_), std::end(*cookies_),
(cookies_.begin(), cookies_.end(), LeastRecentAccess<Cookie>()); [](const std::unique_ptr<Cookie>& lhs,
*m = cookie; const std::unique_ptr<Cookie>& rhs)
{
return lhs->getLastAccessTime() <
rhs->getLastAccessTime();
});
*m = std::move(cookie);
} else { } else {
cookies_.push_back(cookie); cookies_->push_back(std::move(cookie));
} }
} else { } else {
cookies_.push_back(cookie); cookies_->push_back(std::move(cookie));
} }
return true; return true;
} }
} else if(cookie.isExpired(now)) { } else if(cookie->isExpired(now)) {
cookies_.erase(i); cookies_->erase(i);
return false; return false;
} else { } else {
*i = cookie; *i = std::move(cookie);
return true; return true;
} }
} }
bool CookieStorage::DomainEntry::contains(const Cookie& cookie) const bool DomainNode::contains(const Cookie& cookie) const
{ {
return std::find(cookies_.begin(), cookies_.end(), cookie) != cookies_.end(); if(cookies_) {
for(auto& i : *cookies_) {
if(*i == cookie) {
return true;
}
}
}
return false;
} }
bool CookieStorage::DomainEntry::writeCookie(BufferedFile& fp) const bool DomainNode::writeCookie(BufferedFile& fp) const
{ {
for(std::deque<Cookie>::const_iterator i = cookies_.begin(), if(cookies_) {
eoi = cookies_.end(); i != eoi; ++i) { for(const auto& c : *cookies_) {
std::string data = (*i).toNsCookieFormat(); std::string data = c->toNsCookieFormat();
data += "\n"; data += "\n";
if(fp.write(data.data(), data.size()) != data.size()) { if(fp.write(data.data(), data.size()) != data.size()) {
return false; return false;
}
} }
} }
return true; return true;
} }
size_t CookieStorage::DomainEntry::countCookie() const size_t DomainNode::countCookie() const
{ {
return cookies_.size(); if(cookies_) {
return cookies_->size();
} else {
return 0;
}
} }
bool CookieStorage::DomainEntry::operator==(const DomainEntry& de) const void DomainNode::clearCookie()
{ {
return key_ == de.key_; cookies_->clear();
} }
bool CookieStorage::DomainEntry::operator<(const DomainEntry& de) const void DomainNode::setLastAccessTime(time_t lastAccessTime)
{ {
return key_ < de.key_; lastAccessTime_ = lastAccessTime;
} }
CookieStorage::CookieStorage() {} time_t DomainNode::getLastAccessTime() const
{
return lastAccessTime_;
}
CookieStorage::~CookieStorage() {} void DomainNode::setLruAccessTime(time_t t)
{
lruAccessTime_ = t;
}
time_t DomainNode::getLruAccessTime() const
{
return lruAccessTime_;
}
bool DomainNode::empty() const
{
return !cookies_ || cookies_->empty();
}
bool DomainNode::hasNext() const
{
return !next_.empty();
}
DomainNode* DomainNode::getParent() const
{
return parent_;
}
void DomainNode::removeNode(DomainNode* node)
{
next_.erase(node->getLabel());
}
DomainNode* DomainNode::findNext(const std::string& label) const
{
auto i = next_.find(label);
if(i == std::end(next_)) {
return nullptr;
} else {
return (*i).second.get();
}
}
DomainNode* DomainNode::addNext(std::string label,
std::unique_ptr<DomainNode> node)
{
auto& res = next_[std::move(label)] = std::move(node);
return res.get();
}
const std::string& DomainNode::getLabel() const
{
return label_;
}
bool DomainNode::getInLru() const
{
return inLru_;
}
void DomainNode::setInLru(bool f)
{
inLru_ = f;
}
CookieStorage::CookieStorage()
: rootNode_{make_unique<DomainNode>("", nullptr)}
{}
namespace { namespace {
// See CookieStorageTest::testDomainIsFull() in CookieStorageTest.cc // See CookieStorageTest::testDomainIsFull() in CookieStorageTest.cc
@ -189,29 +254,86 @@ const size_t DOMAIN_EVICTION_TRIGGER = 2000;
const double DOMAIN_EVICTION_RATE = 0.1; const double DOMAIN_EVICTION_RATE = 0.1;
} // namespace } // namespace
bool CookieStorage::store(const Cookie& cookie, time_t now) namespace {
std::vector<std::string> splitDomainLabel(const std::string& domain)
{ {
if(domains_.size() >= DOMAIN_EVICTION_TRIGGER) { auto labels = std::vector<std::string>{};
std::vector<std::shared_ptr<DomainEntry> > evictions(domains_.begin(), if(util::isNumericHost(domain)) {
domains_.end()); labels.push_back(domain);
std::sort(evictions.begin(), evictions.end(),
LeastRecentAccess<DomainEntry>());
size_t delnum = (size_t)(evictions.size()*DOMAIN_EVICTION_RATE);
domains_.clear();
domains_.insert(evictions.begin()+delnum, evictions.end());
}
std::shared_ptr<DomainEntry> v(new DomainEntry(cookie.getDomain()));
DomainEntrySet::iterator i = domains_.lower_bound(v);
bool added = false;
if(i != domains_.end() && *(*i) == *v) {
added = (*i)->addCookie(cookie, now);
} else { } else {
added = v->addCookie(cookie, now); util::split(std::begin(domain), std::end(domain),
if(added) { std::back_inserter(labels), '.');
domains_.insert(i, v); }
return labels;
}
} // namespace
size_t CookieStorage::getLruTrackerSize() const
{
return lruTracker_.size();
}
void CookieStorage::evictNode(size_t delnum)
{
for(; delnum > 0 && !lruTracker_.empty(); --delnum) {
auto node = (*lruTracker_.begin()).second;
lruTracker_.erase(lruTracker_.begin());
node->setInLru(false);
node->clearCookie();
while(node->empty() && !node->hasNext()) {
auto parent = node->getParent();
parent->removeNode(node);
if(!parent->empty() || parent->hasNext() ||
parent == rootNode_.get()) {
break;
}
node = parent;
if(node->getInLru()) {
lruTracker_.erase({node->getLruAccessTime(), node});
node->setInLru(false);
}
} }
} }
return added; }
const DomainNode* CookieStorage::getRootNode() const
{
return rootNode_.get();
}
bool CookieStorage::store(std::unique_ptr<Cookie> cookie, time_t now)
{
if(lruTracker_.size() >= DOMAIN_EVICTION_TRIGGER) {
auto delnum = size_t(lruTracker_.size()*DOMAIN_EVICTION_RATE);
evictNode(delnum);
}
auto labels = splitDomainLabel(cookie->getDomain());
auto node = rootNode_.get();
for(auto i = labels.rbegin(), eoi = labels.rend(); i != eoi; ++i) {
auto nextNode = node->findNext(*i);
if(nextNode) {
node = nextNode;
} else {
node = node->addNext(*i, make_unique<DomainNode>(*i, node));
}
}
bool ok = node->addCookie(std::move(cookie), now);
if(ok) {
updateLru(node, now);
}
return ok;
}
void CookieStorage::updateLru(DomainNode* node, time_t now)
{
if(node->getInLru()) {
lruTracker_.erase({node->getLruAccessTime(), node});
} else {
node->setInLru(true);
}
node->setLruAccessTime(now);
lruTracker_.insert({node->getLruAccessTime(), node});
} }
bool CookieStorage::parseAndStore bool CookieStorage::parseAndStore
@ -220,20 +342,17 @@ bool CookieStorage::parseAndStore
const std::string& defaultPath, const std::string& defaultPath,
time_t now) time_t now)
{ {
Cookie cookie; auto cookie = cookie::parse(setCookieString, requestHost, defaultPath, now);
if(cookie::parse(cookie, setCookieString, requestHost, defaultPath, now)) { return cookie && store(std::move(cookie), now);
return store(cookie, now);
} else {
return false;
}
} }
namespace {
struct CookiePathDivider { struct CookiePathDivider {
Cookie cookie_; const Cookie* cookie_;
int pathDepth_; int pathDepth_;
CookiePathDivider(const Cookie& cookie):cookie_(cookie), pathDepth_(0) CookiePathDivider(const Cookie* cookie):cookie_(cookie), pathDepth_(0)
{ {
const std::string& path = cookie_.getPath(); const std::string& path = cookie_->getPath();
if(!path.empty()) { if(!path.empty()) {
for(size_t i = 1, len = path.size(); i < len; ++i) { for(size_t i = 1, len = path.size(); i < len; ++i) {
if(path[i] == '/' && path[i-1] != '/') { if(path[i] == '/' && path[i-1] != '/') {
@ -246,16 +365,17 @@ struct CookiePathDivider {
} }
} }
}; };
} // namespace
namespace { namespace {
class CookiePathDividerConverter { class CookiePathDividerConverter {
public: public:
CookiePathDivider operator()(const Cookie& cookie) const CookiePathDivider operator()(const Cookie* cookie) const
{ {
return CookiePathDivider(cookie); return CookiePathDivider(cookie);
} }
Cookie operator()(const CookiePathDivider& cookiePathDivider) const const Cookie* operator()(const CookiePathDivider& cookiePathDivider) const
{ {
return cookiePathDivider.cookie_; return cookiePathDivider.cookie_;
} }
@ -280,80 +400,69 @@ public:
// creation-times. // creation-times.
return lhs.pathDepth_ > rhs.pathDepth_ || return lhs.pathDepth_ > rhs.pathDepth_ ||
(!(rhs.pathDepth_ > lhs.pathDepth_) && (!(rhs.pathDepth_ > lhs.pathDepth_) &&
lhs.cookie_.getCreationTime() < rhs.cookie_.getCreationTime()); lhs.cookie_->getCreationTime() < rhs.cookie_->getCreationTime());
} }
}; };
} // namespace } // namespace
void CookieStorage::searchCookieByDomainSuffix namespace {
(std::vector<Cookie>& out, DomainNode* findNode(const std::string& domain, DomainNode* node)
const std::string& domain,
const std::string& requestHost,
const std::string& requestPath,
time_t now, bool secure)
{ {
std::shared_ptr<DomainEntry> v(new DomainEntry(domain)); auto labels = splitDomainLabel(domain);
DomainEntrySet::iterator i = domains_.lower_bound(v); for(auto i = labels.rbegin(), eoi = labels.rend(); i != eoi && node; ++i) {
if(i != domains_.end() && *(*i) == *v) { node = node->findNext(*i);
(*i)->setLastAccessTime(now);
(*i)->findCookie(out, requestHost, requestPath, now, secure);
} }
return node;
} }
} // namespace
bool CookieStorage::contains(const Cookie& cookie) const bool CookieStorage::contains(const Cookie& cookie) const
{ {
std::shared_ptr<DomainEntry> v(new DomainEntry(cookie.getDomain())); auto node = findNode(cookie.getDomain(), rootNode_.get());
DomainEntrySet::iterator i = domains_.find(v); return node && node->contains(cookie);
if(i != domains_.end()) {
return (*i)->contains(cookie);
} else {
return false;
}
} }
std::vector<Cookie> CookieStorage::criteriaFind std::vector<const Cookie*> CookieStorage::criteriaFind
(const std::string& requestHost, (const std::string& requestHost,
const std::string& requestPath, const std::string& requestPath,
time_t now, time_t now,
bool secure) bool secure)
{ {
std::vector<Cookie> res; auto res = std::vector<const Cookie*>{};
if(requestPath.empty()) { if(requestPath.empty()) {
return res; return res;
} }
if(util::isNumericHost(requestHost)) { auto labels = splitDomainLabel(requestHost);
searchCookieByDomainSuffix auto node = rootNode_.get();
(res, requestHost, requestHost, requestPath, now, secure); for(auto i = labels.rbegin(), eoi = labels.rend(); i != eoi; ++i) {
} else { auto nextNode = node->findNext(*i);
std::vector<Scip> levels; if(nextNode) {
util::splitIter(requestHost.begin(), requestHost.end(), nextNode->setLastAccessTime(now);
std::back_inserter(levels), '.'); if(nextNode->getInLru()) {
std::string domain; updateLru(nextNode, now);
for(std::vector<Scip>::const_reverse_iterator i = }
levels.rbegin(), eoi = levels.rend(); nextNode->findCookie(res, requestHost, requestPath, now, secure);
i != eoi; ++i, domain.insert(domain.begin(), '.')) { node = nextNode;
domain.insert(domain.begin(), (*i).first, (*i).second); } else {
searchCookieByDomainSuffix break;
(res, domain, requestHost, requestPath, now, secure);
} }
} }
std::vector<CookiePathDivider> divs; auto divs = std::vector<CookiePathDivider>{};
std::transform(res.begin(), res.end(), std::back_inserter(divs), std::transform(std::begin(res), std::end(res), std::back_inserter(divs),
CookiePathDividerConverter()); CookiePathDividerConverter{});
std::sort(divs.begin(), divs.end(), OrderByPathDepthDesc()); std::sort(std::begin(divs), std::end(divs), OrderByPathDepthDesc{});
std::transform(divs.begin(), divs.end(), res.begin(), std::transform(std::begin(divs), std::end(divs), std::begin(res),
CookiePathDividerConverter()); CookiePathDividerConverter{});
return res; return res;
} }
size_t CookieStorage::size() const size_t CookieStorage::size() const
{ {
size_t numCookie = 0; size_t n = 0;
for(DomainEntrySet::iterator i = domains_.begin(), eoi = domains_.end(); for(auto& p : lruTracker_) {
i != eoi; ++i) { n += p.second->countCookie();
numCookie += (*i)->countCookie();
} }
return numCookie; return n;
} }
bool CookieStorage::load(const std::string& filename, time_t now) bool CookieStorage::load(const std::string& filename, time_t now)
@ -361,7 +470,7 @@ bool CookieStorage::load(const std::string& filename, time_t now)
char header[16]; // "SQLite format 3" plus \0 char header[16]; // "SQLite format 3" plus \0
size_t headlen; size_t headlen;
{ {
BufferedFile fp(filename.c_str(), BufferedFile::READ); BufferedFile fp{filename.c_str(), BufferedFile::READ};
if(!fp) { if(!fp) {
A2_LOG_ERROR(fmt("Failed to open cookie file %s", filename.c_str())); A2_LOG_ERROR(fmt("Failed to open cookie file %s", filename.c_str()));
return false; return false;
@ -371,25 +480,28 @@ bool CookieStorage::load(const std::string& filename, time_t now)
try { try {
if(headlen == 16 && memcmp(header, "SQLite format 3\0", 16) == 0) { if(headlen == 16 && memcmp(header, "SQLite format 3\0", 16) == 0) {
#ifdef HAVE_SQLITE3 #ifdef HAVE_SQLITE3
std::vector<Cookie> cookies;
try { try {
Sqlite3MozCookieParser(filename).parse(cookies); auto cookies = Sqlite3MozCookieParser(filename).parse();
storeCookies(std::make_move_iterator(std::begin(cookies)),
std::make_move_iterator(std::end(cookies)), now);
} catch(RecoverableException& e) { } catch(RecoverableException& e) {
A2_LOG_INFO_EX(EX_EXCEPTION_CAUGHT, e); A2_LOG_INFO_EX(EX_EXCEPTION_CAUGHT, e);
A2_LOG_INFO("This does not look like Firefox3 cookie file." A2_LOG_INFO("This does not look like Firefox3 cookie file."
" Retrying, assuming it is Chromium cookie file."); " Retrying, assuming it is Chromium cookie file.");
// Try chrome cookie format // Try chrome cookie format
Sqlite3ChromiumCookieParser(filename).parse(cookies); auto cookies = Sqlite3ChromiumCookieParser(filename).parse();
storeCookies(std::make_move_iterator(std::begin(cookies)),
std::make_move_iterator(std::end(cookies)), now);
} }
storeCookies(cookies.begin(), cookies.end(), now);
#else // !HAVE_SQLITE3 #else // !HAVE_SQLITE3
throw DL_ABORT_EX throw DL_ABORT_EX
("Cannot read SQLite3 database because SQLite3 support is disabled by" ("Cannot read SQLite3 database because SQLite3 support is disabled by"
" configuration."); " configuration.");
#endif // !HAVE_SQLITE3 #endif // !HAVE_SQLITE3
} else { } else {
std::vector<Cookie> cookies = NsCookieParser().parse(filename, now); auto cookies = NsCookieParser().parse(filename, now);
storeCookies(cookies.begin(), cookies.end(), now); storeCookies(std::make_move_iterator(std::begin(cookies)),
std::make_move_iterator(std::end(cookies)), now);
} }
return true; return true;
} catch(RecoverableException& e) { } catch(RecoverableException& e) {
@ -400,17 +512,16 @@ bool CookieStorage::load(const std::string& filename, time_t now)
bool CookieStorage::saveNsFormat(const std::string& filename) bool CookieStorage::saveNsFormat(const std::string& filename)
{ {
std::string tempfilename = filename; auto tempfilename = filename;
tempfilename += "__temp"; tempfilename += "__temp";
{ {
BufferedFile fp(tempfilename.c_str(), BufferedFile::WRITE); BufferedFile fp{tempfilename.c_str(), BufferedFile::WRITE};
if(!fp) { if(!fp) {
A2_LOG_ERROR(fmt("Cannot create cookie file %s", filename.c_str())); A2_LOG_ERROR(fmt("Cannot create cookie file %s", filename.c_str()));
return false; return false;
} }
for(DomainEntrySet::iterator i = domains_.begin(), eoi = domains_.end(); for(auto& p : lruTracker_) {
i != eoi; ++i) { if(!p.second->writeCookie(fp)) {
if(!(*i)->writeCookie(fp)) {
A2_LOG_ERROR(fmt("Failed to save cookies to %s", filename.c_str())); A2_LOG_ERROR(fmt("Failed to save cookies to %s", filename.c_str()));
return false; return false;
} }
@ -431,14 +542,3 @@ bool CookieStorage::saveNsFormat(const std::string& filename)
} }
} // namespace aria2 } // namespace aria2
namespace std {
template<>
void swap<aria2::CookieStorage::DomainEntry>
(aria2::CookieStorage::DomainEntry& a,
aria2::CookieStorage::DomainEntry& b)
{
a.swap(b);
}
} // namespace std

View File

@ -2,7 +2,7 @@
/* /*
* aria2 - The high speed download utility * aria2 - The high speed download utility
* *
* Copyright (C) 2006 Tatsuhiro Tsujikawa * Copyright (C) 2013 Tatsuhiro Tsujikawa
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -42,6 +42,7 @@
#include <vector> #include <vector>
#include <set> #include <set>
#include <algorithm> #include <algorithm>
#include <unordered_map>
#include "a2time.h" #include "a2time.h"
#include "Cookie.h" #include "Cookie.h"
@ -51,89 +52,97 @@ namespace aria2 {
class BufferedFile; class BufferedFile;
// This object represents one domain label.
class DomainNode {
public:
DomainNode(std::string label, DomainNode* parent);
// Stores the matching cookies in |out|. The |now| is used to update
// the last access time of this node.
void findCookie
(std::vector<const Cookie*>& out,
const std::string& requestHost,
const std::string& requestPath,
time_t now, bool secure);
// Returns the number of cookies this node has.
size_t countCookie() const;
// Add |cookie| using update time |now|. Returns true if the
// function succeeds.
bool addCookie(std::unique_ptr<Cookie> cookie, time_t now);
// Sets the last access time of this node.
void setLastAccessTime(time_t lastAccessTime);
// Returns the last access time of this node.
time_t getLastAccessTime() const;
// Sets the time |t| as a time used as key in LRU tracker.
void setLruAccessTime(time_t t);
time_t getLruAccessTime() const;
bool writeCookie(BufferedFile& fp) const;
// Returns true if this node contains the |cookie|.
bool contains(const Cookie& cookie) const;
// Returns true if this node contains no cookie.
bool empty() const;
// Returns true if this node has any next nodes.
bool hasNext() const;
// Returns the parent node. If this is the root node, returns
// nullptr.
DomainNode* getParent() const;
// Removes the child node |node|. Nothing happens if |node| is not a
// child of this node.
void removeNode(DomainNode* node);
// Returns the child node having label |label. Returns nullptr if
// there is no such node.
DomainNode* findNext(const std::string& label) const;
// Add the |node| as a child using label |label and returns the raw
// pointer of |node|.
DomainNode* addNext(std::string label, std::unique_ptr<DomainNode> node);
// Returns the |label|.
const std::string& getLabel() const;
// Deletes all cookies this node has.
void clearCookie();
// Returns value set by setInLru(). This is typically used to know
// this node is tracked by LRU tracker or not.
bool getInLru() const;
void setInLru(bool f);
template<typename OutputIterator>
OutputIterator dumpCookie(OutputIterator out) const
{
if(cookies_) {
for(auto& c : *cookies_) {
out++ = c.get();
}
}
return out;
}
private:
std::string label_;
DomainNode* parent_;
time_t lastAccessTime_;
time_t lruAccessTime_;
bool inLru_;
std::unique_ptr<std::deque<std::unique_ptr<Cookie>>> cookies_;
// domain label string to DomainNode
// e.g. net, sourceforge
// For numerical addresses, this is address itself.
// e.g. 192.168.0.1
std::unordered_map<std::string, std::unique_ptr<DomainNode>> next_;
};
class CookieStorage { class CookieStorage {
public: public:
static const size_t MAX_COOKIE_PER_DOMAIN = 50; static const size_t MAX_COOKIE_PER_DOMAIN = 50;
class DomainEntry {
private:
// This is reversed domain level string.
// e.g. net.sourceforge.aria2
// e.g. 192.168.0.1
std::string key_;
time_t lastAccessTime_;
std::deque<Cookie> cookies_;
public:
DomainEntry(const std::string& domain);
DomainEntry(const DomainEntry& c);
~DomainEntry();
void swap(DomainEntry& c);
DomainEntry& operator=(const DomainEntry& c);
const std::string& getKey() const
{
return key_;
}
void findCookie
(std::vector<Cookie>& out,
const std::string& requestHost,
const std::string& requestPath,
time_t now, bool secure);
size_t countCookie() const;
bool addCookie(const Cookie& cookie, time_t now);
void setLastAccessTime(time_t lastAccessTime)
{
lastAccessTime_ = lastAccessTime;
}
time_t getLastAccessTime() const
{
return lastAccessTime_;
}
bool writeCookie(BufferedFile& fp) const;
bool contains(const Cookie& cookie) const;
template<typename OutputIterator>
OutputIterator dumpCookie(OutputIterator out) const
{
return std::copy(cookies_.begin(), cookies_.end(), out);
}
bool operator==(const DomainEntry& de) const;
bool operator<(const DomainEntry& de) const;
};
private: private:
typedef std::set<std::shared_ptr<DomainEntry>, // typedef std::set<std::shared_ptr<DomainEntry>,
DerefLess<std::shared_ptr<DomainEntry> > > DomainEntrySet; // DerefLess<std::shared_ptr<DomainEntry> > > DomainEntrySet;
DomainEntrySet domains_; // DomainEntrySet domains_;
template<typename InputIterator>
void storeCookies(InputIterator first, InputIterator last, time_t now)
{
for(; first != last; ++first) {
store(*first, now);
}
}
public: public:
CookieStorage(); CookieStorage();
~CookieStorage();
// Returns true if cookie is stored or updated existing cookie. // Returns true if cookie is stored or updated existing cookie.
// Returns false if cookie is expired. now is used as last access // Returns false if cookie is expired. now is used as last access
// time. // time.
bool store(const Cookie& cookie, time_t now); bool store(std::unique_ptr<Cookie> cookie, time_t now);
// Returns true if cookie is stored or updated existing cookie. // Returns true if cookie is stored or updated existing cookie.
// Otherwise, returns false. now is used as creation time and last // Otherwise, returns false. now is used as creation time and last
@ -146,9 +155,10 @@ public:
// Finds cookies matched with given criteria and returns them. // Finds cookies matched with given criteria and returns them.
// Matched cookies' lastAccess_ property is updated. // Matched cookies' lastAccess_ property is updated.
std::vector<Cookie> criteriaFind(const std::string& requestHost, std::vector<const Cookie*>
const std::string& requestPath, criteriaFind(const std::string& requestHost,
time_t now, bool secure); const std::string& requestPath,
time_t now, bool secure);
// Loads Cookies from file denoted by filename. If compiled with // Loads Cookies from file denoted by filename. If compiled with
// libsqlite3, this method automatically detects the specified file // libsqlite3, this method automatically detects the specified file
@ -170,36 +180,51 @@ public:
// satisfies. // satisfies.
bool contains(const Cookie& cookie) const; bool contains(const Cookie& cookie) const;
// Searches Cookie using given domain, requestHost, requestPath,
// current time and secure flag. The found Cookies are stored in
// out.
void searchCookieByDomainSuffix
(std::vector<Cookie>& out,
const std::string& domain,
const std::string& requestHost,
const std::string& requestPath,
time_t now, bool secure);
template<typename OutputIterator> template<typename OutputIterator>
OutputIterator dumpCookie(OutputIterator out) const OutputIterator dumpCookie(OutputIterator out) const
{ {
for(DomainEntrySet::iterator i = domains_.begin(), eoi = domains_.end(); for(auto& i : lruTracker_) {
i != eoi; ++i) { out = i.second->dumpCookie(out);
out = (*i)->dumpCookie(out);
} }
return out; return out;
} }
};
void swap(CookieStorage::DomainEntry& a, CookieStorage::DomainEntry& b); // Force eviction of delnum nodes. Exposed for unittest
void evictNode(size_t delnum);
// Returns size of LRU tracker. Exposed for unittest
size_t getLruTrackerSize() const;
// Returns root node. Exposed for unittest
const DomainNode* getRootNode() const;
private:
template<typename InputIterator>
void storeCookies(InputIterator first, InputIterator last, time_t now)
{
for(; first != last; ++first) {
store(*first, now);
}
}
void updateLru(DomainNode* node, time_t now);
// rootNode_ is a root node of tree structure of reversed domain
// labels. rootNode_ always contans no cookie. It has the child
// nodes of the top level domain label (e.g., net, com and org). And
// those top level domain nodes have 2nd doman label (e.g.,
// sourcforge, github), and so on. The numeric host name are always
// stored as a child node of rootNode_. So the domain name of a
// paricular node is constructed as follows. First traverse the
// target node from root node. The concatenation of the visited
// node's label in the reverse order, delimited by ".", is the
std::unique_ptr<DomainNode> rootNode_;
// This object tracks the node which has cookies or it once had. The
// order is sorted by the least recent updated node first. This
// object does not track the node which has not contan cookie. For
// example, adding cookies in aria2.sourceforge.net, and no node
// labeled "sourceforge" is present, only node labelded "aria2" is
// tracked and node labeled "sourceforge" and "net" are not.
std::set<std::pair<time_t, DomainNode*>> lruTracker_;
};
} // namespace aria2 } // namespace aria2
namespace std {
template<>
void swap<aria2::CookieStorage::DomainEntry>
(aria2::CookieStorage::DomainEntry& a,
aria2::CookieStorage::DomainEntry& b);
} // namespace std
#endif // D_COOKIE_STORAGE_H #endif // D_COOKIE_STORAGE_H

View File

@ -234,13 +234,11 @@ std::string HttpRequest::createRequest()
std::string cookiesValue; std::string cookiesValue;
std::string path = getDir(); std::string path = getDir();
path += getFile(); path += getFile();
std::vector<Cookie> cookies = auto cookies = cookieStorage_->criteriaFind(getHost(), path,
cookieStorage_->criteriaFind(getHost(), path, Time().getTime(),
Time().getTime(), getProtocol() == "https");
getProtocol() == "https"); for(auto c : cookies) {
for(std::vector<Cookie>::const_iterator itr = cookies.begin(), cookiesValue += c->toString();
eoi = cookies.end(); itr != eoi; ++itr) {
cookiesValue += (*itr).toString();
cookiesValue += ";"; cookiesValue += ";";
} }
if(!cookiesValue.empty()) { if(!cookiesValue.empty()) {

View File

@ -54,58 +54,59 @@ NsCookieParser::NsCookieParser() {}
NsCookieParser::~NsCookieParser() {} NsCookieParser::~NsCookieParser() {}
namespace { namespace {
bool parseNsCookie std::unique_ptr<Cookie> parseNsCookie
(Cookie& cookie, const std::string& cookieStr, time_t creationTime) (const std::string& cookieStr, time_t creationTime)
{ {
std::vector<Scip> vs; std::vector<Scip> vs;
util::splitIter(cookieStr.begin(), cookieStr.end(), std::back_inserter(vs), util::splitIter(cookieStr.begin(), cookieStr.end(), std::back_inserter(vs),
'\t', true); '\t', true);
if(vs.size() < 6) { if(vs.size() < 6) {
return false; return std::unique_ptr<Cookie>{};
} }
vs[0].first = util::lstripIter(vs[0].first, vs[0].second, '.'); vs[0].first = util::lstripIter(vs[0].first, vs[0].second, '.');
if(vs[5].first == vs[5].second || vs[0].first == vs[0].second || if(vs[5].first == vs[5].second || vs[0].first == vs[0].second ||
!cookie::goodPath(vs[2].first, vs[2].second)) { !cookie::goodPath(vs[2].first, vs[2].second)) {
return false; return std::unique_ptr<Cookie>{};
} }
int64_t expiryTime; int64_t expiryTime;
if(!util::parseLLIntNoThrow(expiryTime, if(!util::parseLLIntNoThrow(expiryTime,
std::string(vs[4].first, vs[4].second))) { std::string(vs[4].first, vs[4].second))) {
return false; return std::unique_ptr<Cookie>{};
} }
if(std::numeric_limits<time_t>::max() < expiryTime) { if(std::numeric_limits<time_t>::max() < expiryTime) {
expiryTime = std::numeric_limits<time_t>::max(); expiryTime = std::numeric_limits<time_t>::max();
} else if(std::numeric_limits<time_t>::min() > expiryTime) { } else if(std::numeric_limits<time_t>::min() > expiryTime) {
expiryTime = std::numeric_limits<time_t>::min(); expiryTime = std::numeric_limits<time_t>::min();
} }
cookie.setName(vs[5].first, vs[5].second); auto cookie = make_unique<Cookie>();
cookie->setName(vs[5].first, vs[5].second);
if(vs.size() >= 7) { if(vs.size() >= 7) {
cookie.setValue(vs[6].first, vs[6].second); cookie->setValue(vs[6].first, vs[6].second);
} else { } else {
cookie.setValue(A2STR::NIL.begin(), A2STR::NIL.end()); cookie->setValue("");
} }
cookie.setExpiryTime(expiryTime == 0? cookie->setExpiryTime(expiryTime == 0?
std::numeric_limits<time_t>::max():expiryTime); std::numeric_limits<time_t>::max():expiryTime);
// aria2 treats expiryTime == 0 means session cookie. // aria2 treats expiryTime == 0 means session cookie->
cookie.setPersistent(expiryTime != 0); cookie->setPersistent(expiryTime != 0);
cookie.setDomain(vs[0].first, vs[0].second); cookie->setDomain(vs[0].first, vs[0].second);
cookie.setHostOnly(util::isNumericHost(cookie.getDomain()) || cookie->setHostOnly(util::isNumericHost(cookie->getDomain()) ||
!util::streq(vs[1].first, vs[1].second, "TRUE")); !util::streq(vs[1].first, vs[1].second, "TRUE"));
cookie.setPath(vs[2].first, vs[2].second); cookie->setPath(vs[2].first, vs[2].second);
cookie.setSecure(util::streq(vs[3].first, vs[3].second, "TRUE")); cookie->setSecure(util::streq(vs[3].first, vs[3].second, "TRUE"));
cookie.setCreationTime(creationTime); cookie->setCreationTime(creationTime);
return true; return cookie;
} }
} // namespace } // namespace
std::vector<Cookie> NsCookieParser::parse std::vector<std::unique_ptr<Cookie>> NsCookieParser::parse
(const std::string& filename, time_t creationTime) (const std::string& filename, time_t creationTime)
{ {
BufferedFile fp(filename.c_str(), BufferedFile::READ); BufferedFile fp{filename.c_str(), BufferedFile::READ};
if(!fp) { if(!fp) {
throw DL_ABORT_EX(fmt("Failed to open file %s", filename.c_str())); throw DL_ABORT_EX(fmt("Failed to open file %s", filename.c_str()));
} }
std::vector<Cookie> cookies; std::vector<std::unique_ptr<Cookie>> cookies;
while(1) { while(1) {
std::string line = fp.getLine(); std::string line = fp.getLine();
if(line.empty()) { if(line.empty()) {
@ -120,9 +121,9 @@ std::vector<Cookie> NsCookieParser::parse
if(line[0] == '#') { if(line[0] == '#') {
continue; continue;
} }
Cookie c; auto c = parseNsCookie(line, creationTime);
if(parseNsCookie(c, line, creationTime)) { if(c) {
cookies.push_back(c); cookies.push_back(std::move(c));
} }
} }
return cookies; return cookies;

View File

@ -39,6 +39,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <memory>
namespace aria2 { namespace aria2 {
@ -50,7 +51,8 @@ public:
~NsCookieParser(); ~NsCookieParser();
std::vector<Cookie> parse(const std::string& filename, time_t creationTime); std::vector<std::unique_ptr<Cookie>> parse
(const std::string& filename, time_t creationTime);
}; };
} // namespace aria2 } // namespace aria2

View File

@ -102,8 +102,8 @@ int cookieRowMapper(void* data, int columns, char** values, char** names)
if(columns != 7 || !values[0] || !values[1] || !values[4]) { if(columns != 7 || !values[0] || !values[1] || !values[4]) {
return 0; return 0;
} }
std::vector<Cookie>& cookies = std::vector<std::unique_ptr<Cookie>>& cookies =
*reinterpret_cast<std::vector<Cookie>*>(data); *reinterpret_cast<std::vector<std::unique_ptr<Cookie>>*>(data);
size_t val0len = strlen(values[0]); size_t val0len = strlen(values[0]);
std::string cookieDomain std::string cookieDomain
(util::lstripIter(&values[0][0], &values[0][val0len], '.'), (util::lstripIter(&values[0][0], &values[0][val0len], '.'),
@ -122,29 +122,29 @@ int cookieRowMapper(void* data, int columns, char** values, char** names)
if(!values[6] || !parseTime(lastAccessTime, values[6])) { if(!values[6] || !parseTime(lastAccessTime, values[6])) {
return 0; return 0;
} }
Cookie c(cookieName, cookies.push_back(make_unique<Cookie>
toString(values[5]), // value (std::move(cookieName),
expiryTime, toString(values[5]), // value
true, // persistent expiryTime,
cookieDomain, true, // persistent
util::isNumericHost(cookieDomain) || std::move(cookieDomain),
(values[0] && values[0][0] != '.'), // hostOnly util::isNumericHost(cookieDomain) ||
cookiePath, (values[0] && values[0][0] != '.'), // hostOnly
values[2] && strcmp(values[2], "1") == 0, //secure std::move(cookiePath),
false, values[2] && strcmp(values[2], "1") == 0, //secure
lastAccessTime // creation time. Set this later. false,
); lastAccessTime // creation time. Set this later.
cookies.push_back(c); ));
return 0; return 0;
} }
} // namespace } // namespace
void Sqlite3CookieParser::parse(std::vector<Cookie>& cookies) std::vector<std::unique_ptr<Cookie>> Sqlite3CookieParser::parse()
{ {
if(!db_) { if(!db_) {
throw DL_ABORT_EX(fmt("SQLite3 database is not opened.")); throw DL_ABORT_EX(fmt("SQLite3 database is not opened."));
} }
std::vector<Cookie> tcookies; auto tcookies = std::vector<std::unique_ptr<Cookie>>{};
char* sqlite3ErrMsg = 0; char* sqlite3ErrMsg = 0;
int ret = sqlite3_exec(db_, getQuery(), cookieRowMapper, int ret = sqlite3_exec(db_, getQuery(), cookieRowMapper,
&tcookies, &sqlite3ErrMsg); &tcookies, &sqlite3ErrMsg);
@ -157,7 +157,7 @@ void Sqlite3CookieParser::parse(std::vector<Cookie>& cookies)
throw DL_ABORT_EX throw DL_ABORT_EX
(fmt("Failed to read SQLite3 database: %s", errMsg.c_str())); (fmt("Failed to read SQLite3 database: %s", errMsg.c_str()));
} }
cookies.swap(tcookies); return tcookies;
} }
} // namespace aria2 } // namespace aria2

View File

@ -39,6 +39,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <memory>
#include <sqlite3.h> #include <sqlite3.h>
@ -55,7 +56,7 @@ public:
// Loads cookies from sqlite3 database and stores them in cookies. // Loads cookies from sqlite3 database and stores them in cookies.
// When loading is successful, cookies stored in cookies initially // When loading is successful, cookies stored in cookies initially
// are removed. Otherwise, the content of cookies is unchanged. // are removed. Otherwise, the content of cookies is unchanged.
void parse(std::vector<Cookie>& cookies); std::vector<std::unique_ptr<Cookie>> parse();
protected: protected:
// Returns SQL select statement to get 1 record of cookie. The sql // Returns SQL select statement to get 1 record of cookie. The sql
// must return 6 columns in the following order: host, path, // must return 6 columns in the following order: host, path,

View File

@ -216,9 +216,8 @@ bool parseDate
return time != -1; return time != -1;
} }
bool parse std::unique_ptr<Cookie> parse
(Cookie& cookie, (const std::string& cookieStr,
const std::string& cookieStr,
const std::string& requestHost, const std::string& requestHost,
const std::string& defaultPath, const std::string& defaultPath,
time_t creationTime) time_t creationTime)
@ -231,13 +230,13 @@ bool parse
std::string::const_iterator eq = cookieStr.begin(); std::string::const_iterator eq = cookieStr.begin();
for(; eq != nvEnd && *eq != '='; ++eq); for(; eq != nvEnd && *eq != '='; ++eq);
if(eq == nvEnd) { if(eq == nvEnd) {
return false; return std::unique_ptr<Cookie>{};
} }
std::pair<std::string::const_iterator, std::pair<std::string::const_iterator,
std::string::const_iterator> p = std::string::const_iterator> p =
util::stripIter(cookieStr.begin(), eq); util::stripIter(cookieStr.begin(), eq);
if(p.first == p.second) { if(p.first == p.second) {
return false; return std::unique_ptr<Cookie>{};
} }
Scip cookieName(p.first, p.second); Scip cookieName(p.first, p.second);
p = util::stripIter(eq+1, nvEnd); p = util::stripIter(eq+1, nvEnd);
@ -276,18 +275,18 @@ bool parse
if(parseDate(expiryTime, attrp.first, attrp.second)) { if(parseDate(expiryTime, attrp.first, attrp.second)) {
foundExpires = true; foundExpires = true;
} else { } else {
return false; return std::unique_ptr<Cookie>{};
} }
} else if(util::strieq(p.first, p.second, "max-age")) { } else if(util::strieq(p.first, p.second, "max-age")) {
if(attrp.first == attrp.second || if(attrp.first == attrp.second ||
(!in(static_cast<unsigned char>(*attrp.first), 0x30u, 0x39u) && (!in(static_cast<unsigned char>(*attrp.first), 0x30u, 0x39u) &&
*attrp.first != '-')) { *attrp.first != '-')) {
return false; return std::unique_ptr<Cookie>{};
} }
for(std::string::const_iterator s = attrp.first+1, for(std::string::const_iterator s = attrp.first+1,
eos = attrp.second; s != eos; ++s) { eos = attrp.second; s != eos; ++s) {
if(!in(static_cast<unsigned char>(*s), 0x30u, 0x39u)) { if(!in(static_cast<unsigned char>(*s), 0x30u, 0x39u)) {
return false; return std::unique_ptr<Cookie>{};
} }
} }
int64_t delta; int64_t delta;
@ -306,17 +305,17 @@ bool parse
} }
} }
} else { } else {
return false; return std::unique_ptr<Cookie>{};
} }
} else if(util::strieq(p.first, p.second, "domain")) { } else if(util::strieq(p.first, p.second, "domain")) {
if(attrp.first == attrp.second) { if(attrp.first == attrp.second) {
return false; return std::unique_ptr<Cookie>{};
} }
std::string::const_iterator noDot = attrp.first; std::string::const_iterator noDot = attrp.first;
std::string::const_iterator end = attrp.second; std::string::const_iterator end = attrp.second;
for(; noDot != end && *noDot == '.'; ++noDot); for(; noDot != end && *noDot == '.'; ++noDot);
if(noDot == end) { if(noDot == end) {
return false; return std::unique_ptr<Cookie>{};
} }
cookieDomain.assign(noDot, end); cookieDomain.assign(noDot, end);
} else if(util::strieq(p.first, p.second, "path")) { } else if(util::strieq(p.first, p.second, "path")) {
@ -349,26 +348,27 @@ bool parse
} else if(domainMatch(canonicalizedHost, cookieDomain)) { } else if(domainMatch(canonicalizedHost, cookieDomain)) {
hostOnly = util::isNumericHost(canonicalizedHost); hostOnly = util::isNumericHost(canonicalizedHost);
} else { } else {
return false; return std::unique_ptr<Cookie>{};
} }
if(cookiePath.empty()) { if(cookiePath.empty()) {
cookiePath = defaultPath; cookiePath = defaultPath;
} }
cookie.setName(cookieName.first, cookieName.second); auto cookie = make_unique<Cookie>();
cookie.setValue(cookieValue.first, cookieValue.second); cookie->setName(cookieName.first, cookieName.second);
cookie.setExpiryTime(expiryTime); cookie->setValue(cookieValue.first, cookieValue.second);
cookie.setPersistent(persistent); cookie->setExpiryTime(expiryTime);
cookie.setDomain(cookieDomain); cookie->setPersistent(persistent);
cookie.setHostOnly(hostOnly); cookie->setDomain(std::move(cookieDomain));
cookie.setPath(cookiePath); cookie->setHostOnly(hostOnly);
cookie.setSecure(secure); cookie->setPath(std::move(cookiePath));
cookie.setHttpOnly(httpOnly); cookie->setSecure(secure);
cookie.setCreationTime(creationTime); cookie->setHttpOnly(httpOnly);
cookie.setLastAccessTime(creationTime); cookie->setCreationTime(creationTime);
cookie->setLastAccessTime(creationTime);
return true; return cookie;
} }
bool goodPath bool goodPath

View File

@ -38,6 +38,7 @@
#include "common.h" #include "common.h"
#include <string> #include <string>
#include <memory>
#include "a2time.h" #include "a2time.h"
@ -52,9 +53,8 @@ bool parseDate
std::string::const_iterator first, std::string::const_iterator first,
std::string::const_iterator last); std::string::const_iterator last);
bool parse std::unique_ptr<Cookie> parse
(Cookie& cookie, (const std::string& cookieStr,
const std::string& cookieStr,
const std::string& requestHost, const std::string& requestHost,
const std::string& defaultPath, const std::string& defaultPath,
time_t creationTime); time_t creationTime);

View File

@ -88,145 +88,145 @@ void CookieHelperTest::testParse()
{ {
std::string str = "ID=123456789; expires=Sun, 10-Jun-2007 11:00:00 GMT;" std::string str = "ID=123456789; expires=Sun, 10-Jun-2007 11:00:00 GMT;"
"path=/foo; domain=localhost; secure;httpOnly "; "path=/foo; domain=localhost; secure;httpOnly ";
Cookie c; auto c = cookie::parse(str, "localhost", "/", creationDate);
CPPUNIT_ASSERT(cookie::parse(c, str, "localhost", "/", creationDate)); CPPUNIT_ASSERT(c);
CPPUNIT_ASSERT_EQUAL(std::string("ID"), c.getName()); CPPUNIT_ASSERT_EQUAL(std::string("ID"), c->getName());
CPPUNIT_ASSERT_EQUAL(std::string("123456789"), c.getValue()); CPPUNIT_ASSERT_EQUAL(std::string("123456789"), c->getValue());
CPPUNIT_ASSERT_EQUAL((time_t)1181473200, c.getExpiryTime()); CPPUNIT_ASSERT_EQUAL((time_t)1181473200, c->getExpiryTime());
CPPUNIT_ASSERT(c.getPersistent()); CPPUNIT_ASSERT(c->getPersistent());
CPPUNIT_ASSERT_EQUAL(std::string("localhost"), c.getDomain()); CPPUNIT_ASSERT_EQUAL(std::string("localhost"), c->getDomain());
CPPUNIT_ASSERT(!c.getHostOnly()); CPPUNIT_ASSERT(!c->getHostOnly());
CPPUNIT_ASSERT_EQUAL(std::string("/foo"), c.getPath()); CPPUNIT_ASSERT_EQUAL(std::string("/foo"), c->getPath());
CPPUNIT_ASSERT(c.getSecure()); CPPUNIT_ASSERT(c->getSecure());
CPPUNIT_ASSERT(c.getHttpOnly()); CPPUNIT_ASSERT(c->getHttpOnly());
CPPUNIT_ASSERT_EQUAL((time_t)141, c.getCreationTime()); CPPUNIT_ASSERT_EQUAL((time_t)141, c->getCreationTime());
CPPUNIT_ASSERT_EQUAL((time_t)141, c.getLastAccessTime()); CPPUNIT_ASSERT_EQUAL((time_t)141, c->getLastAccessTime());
} }
{ {
std::string str = "id=; Max-Age=0;"; std::string str = "id=; Max-Age=0;";
Cookie c; auto c = cookie::parse(str, "localhost", "/", creationDate);
CPPUNIT_ASSERT(cookie::parse(c, str, "localhost", "/", creationDate)); CPPUNIT_ASSERT(c);
CPPUNIT_ASSERT_EQUAL(std::string("id"), c.getName()); CPPUNIT_ASSERT_EQUAL(std::string("id"), c->getName());
CPPUNIT_ASSERT_EQUAL((time_t)0, c.getExpiryTime()); CPPUNIT_ASSERT_EQUAL((time_t)0, c->getExpiryTime());
CPPUNIT_ASSERT(c.getPersistent()); CPPUNIT_ASSERT(c->getPersistent());
CPPUNIT_ASSERT_EQUAL(std::string("localhost"), c.getDomain()); CPPUNIT_ASSERT_EQUAL(std::string("localhost"), c->getDomain());
CPPUNIT_ASSERT(c.getHostOnly()); CPPUNIT_ASSERT(c->getHostOnly());
CPPUNIT_ASSERT_EQUAL(std::string("/"), c.getPath()); CPPUNIT_ASSERT_EQUAL(std::string("/"), c->getPath());
CPPUNIT_ASSERT(!c.getSecure()); CPPUNIT_ASSERT(!c->getSecure());
CPPUNIT_ASSERT(!c.getHttpOnly()); CPPUNIT_ASSERT(!c->getHttpOnly());
} }
{ {
std::string str = "id=; Max-Age=-100;"; std::string str = "id=; Max-Age=-100;";
Cookie c; auto c = cookie::parse(str, "localhost", "/", creationDate);
CPPUNIT_ASSERT(cookie::parse(c, str, "localhost", "/", creationDate)); CPPUNIT_ASSERT(c);
CPPUNIT_ASSERT_EQUAL((time_t)0, c.getExpiryTime()); CPPUNIT_ASSERT_EQUAL((time_t)0, c->getExpiryTime());
CPPUNIT_ASSERT(c.getPersistent()); CPPUNIT_ASSERT(c->getPersistent());
} }
{ {
std::string str = "id=; Max-Age=100;"; std::string str = "id=; Max-Age=100;";
Cookie c; auto c = cookie::parse(str, "localhost", "/", creationDate);
CPPUNIT_ASSERT(cookie::parse(c, str, "localhost", "/", creationDate)); CPPUNIT_ASSERT(c);
CPPUNIT_ASSERT_EQUAL((time_t)creationDate+100, c.getExpiryTime()); CPPUNIT_ASSERT_EQUAL((time_t)creationDate+100, c->getExpiryTime());
CPPUNIT_ASSERT(c.getPersistent()); CPPUNIT_ASSERT(c->getPersistent());
} }
{ {
std::string str = "id=; Max-Age=9223372036854775807;"; std::string str = "id=; Max-Age=9223372036854775807;";
Cookie c; auto c = cookie::parse(str, "localhost", "/", creationDate);
CPPUNIT_ASSERT(cookie::parse(c, str, "localhost", "/", creationDate)); CPPUNIT_ASSERT(c);
CPPUNIT_ASSERT_EQUAL(std::numeric_limits<time_t>::max(), c.getExpiryTime()); CPPUNIT_ASSERT_EQUAL(std::numeric_limits<time_t>::max(),
CPPUNIT_ASSERT(c.getPersistent()); c->getExpiryTime());
CPPUNIT_ASSERT(c->getPersistent());
} }
{ {
std::string str = "id=; Max-Age=X;"; std::string str = "id=; Max-Age=X;";
Cookie c; CPPUNIT_ASSERT(!cookie::parse(str, "localhost", "/", creationDate));
CPPUNIT_ASSERT(!cookie::parse(c, str, "localhost", "/", creationDate));
} }
{ {
std::string str = "id=; Max-Age=100garbage;"; std::string str = "id=; Max-Age=100garbage;";
Cookie c; CPPUNIT_ASSERT(!cookie::parse(str, "localhost", "/", creationDate));
CPPUNIT_ASSERT(!cookie::parse(c, str, "localhost", "/", creationDate));
} }
{ {
std::string str = "id=; Max-Age=100;expires=Sun, 10-Jun-2007 11:00:00 GMT;"; std::string str = "id=; Max-Age=100;expires=Sun, 10-Jun-2007 11:00:00 GMT;";
Cookie c; auto c = cookie::parse(str, "localhost", "/", creationDate);
CPPUNIT_ASSERT(cookie::parse(c, str, "localhost", "/", creationDate)); CPPUNIT_ASSERT(c);
CPPUNIT_ASSERT_EQUAL((time_t)creationDate+100, c.getExpiryTime()); CPPUNIT_ASSERT_EQUAL((time_t)creationDate+100, c->getExpiryTime());
CPPUNIT_ASSERT(c.getPersistent()); CPPUNIT_ASSERT(c->getPersistent());
} }
{ {
// Cookie data cannot be parsed. // Cookie data cannot be parsed.
std::string str = "id=; expires=2007-10-01 11:00:00 GMT;"; std::string str = "id=; expires=2007-10-01 11:00:00 GMT;";
Cookie c; CPPUNIT_ASSERT(!cookie::parse(str, "localhost", "/", creationDate));
CPPUNIT_ASSERT(!cookie::parse(c, str, "localhost", "/", creationDate));
} }
{ {
std::string str = "id=;"; std::string str = "id=;";
Cookie c; auto c = cookie::parse(str, "localhost", "/", creationDate);
CPPUNIT_ASSERT(cookie::parse(c, str, "localhost", "/", creationDate)); CPPUNIT_ASSERT(c);
CPPUNIT_ASSERT(!c.getPersistent()); CPPUNIT_ASSERT(!c->getPersistent());
} }
{ {
std::string str = "id=; path=abc"; std::string str = "id=; path=abc";
Cookie c; auto c = cookie::parse(str, "localhost", "/", creationDate);
CPPUNIT_ASSERT(cookie::parse(c, str, "localhost", "/", creationDate)); CPPUNIT_ASSERT(c);
CPPUNIT_ASSERT_EQUAL(std::string("/"), c.getPath()); CPPUNIT_ASSERT_EQUAL(std::string("/"), c->getPath());
} }
{ {
std::string str = "id=; domain=.example.org"; std::string str = "id=; domain=.example.org";
Cookie c; CPPUNIT_ASSERT(cookie::parse(str, "www.example.org", "/",creationDate));
CPPUNIT_ASSERT(cookie::parse(c, str, "www.example.org", "/",creationDate));
} }
{ {
// Fails because request host does not domain-match with cookie // Fails because request host does not domain-match with cookie
// domain. // domain.
std::string str = "id=; domain=www.example.org"; std::string str = "id=; domain=www.example.org";
Cookie c; CPPUNIT_ASSERT(!cookie::parse(str, "example.org", "/", creationDate));
CPPUNIT_ASSERT(!cookie::parse(c, str, "example.org", "/", creationDate));
} }
{ {
std::string str = "id=; domain=."; std::string str = "id=; domain=.";
Cookie c; CPPUNIT_ASSERT(!cookie::parse(str, "localhost", "/",creationDate));
CPPUNIT_ASSERT(!cookie::parse(c, str, "localhost", "/",creationDate));
} }
{ {
std::string str = ""; std::string str = "";
Cookie c; CPPUNIT_ASSERT(!cookie::parse(str, "localhost", "/",creationDate));
CPPUNIT_ASSERT(!cookie::parse(c, str, "localhost", "/",creationDate));
} }
{ {
std::string str = "="; std::string str = "=";
Cookie c; CPPUNIT_ASSERT(!cookie::parse(str, "localhost", "/",creationDate));
CPPUNIT_ASSERT(!cookie::parse(c, str, "localhost", "/",creationDate));
} }
{ {
// Use domain last time seen. // Use domain last time seen.
std::string str = "id=;domain=a.example.org;domain=.example.org"; std::string str = "id=;domain=a.example.org;domain=.example.org";
Cookie c; auto c = cookie::parse(str, "b.example.org", "/",creationDate);
CPPUNIT_ASSERT(cookie::parse(c, str, "b.example.org", "/",creationDate)); CPPUNIT_ASSERT(c);
CPPUNIT_ASSERT_EQUAL(std::string("example.org"), c.getDomain()); CPPUNIT_ASSERT_EQUAL(std::string("example.org"), c->getDomain());
} }
{ {
// numeric host // numeric host
std::string str = "id=;"; std::string str = "id=;";
Cookie c; auto c = cookie::parse(str, "192.168.0.1", "/",creationDate);
CPPUNIT_ASSERT(cookie::parse(c, str, "192.168.0.1", "/",creationDate)); CPPUNIT_ASSERT(c);
CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), c.getDomain()); CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), c->getDomain());
CPPUNIT_ASSERT(c.getHostOnly()); CPPUNIT_ASSERT(c->getHostOnly());
} }
{ {
// numeric host // numeric host
std::string str = "id=; domain=192.168.0.1"; std::string str = "id=; domain=192.168.0.1";
Cookie c; auto c = cookie::parse(str, "192.168.0.1", "/",creationDate);
CPPUNIT_ASSERT(cookie::parse(c, str, "192.168.0.1", "/",creationDate)); CPPUNIT_ASSERT(c);
CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), c.getDomain()); CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), c->getDomain());
CPPUNIT_ASSERT(c.getHostOnly()); CPPUNIT_ASSERT(c->getHostOnly());
} }
{ {
// DQUOTE around cookie-value // DQUOTE around cookie-value
std::string str = "id=\"foo\";"; std::string str = "id=\"foo\";";
Cookie c; auto c = cookie::parse(str, "localhost", "/", creationDate);
CPPUNIT_ASSERT(cookie::parse(c, str, "localhost", "/", creationDate)); CPPUNIT_ASSERT(c);
CPPUNIT_ASSERT_EQUAL(std::string("foo"), c.getValue()); CPPUNIT_ASSERT_EQUAL(std::string("foo"), c->getValue());
}
{
// Default path
std::string str = "id=;";
auto c = cookie::parse(str, "localhost", "/foo", creationDate);
CPPUNIT_ASSERT(c);
CPPUNIT_ASSERT_EQUAL(std::string("/foo"), c->getPath());
} }
} }

View File

@ -12,6 +12,7 @@
#include "RecoverableException.h" #include "RecoverableException.h"
#include "File.h" #include "File.h"
#include "TestUtil.h" #include "TestUtil.h"
#include "TimerA2.h"
namespace aria2 { namespace aria2 {
@ -29,14 +30,13 @@ class CookieStorageTest:public CppUnit::TestFixture {
CPPUNIT_TEST(testSaveNsFormat_fail); CPPUNIT_TEST(testSaveNsFormat_fail);
CPPUNIT_TEST(testCookieIsFull); CPPUNIT_TEST(testCookieIsFull);
CPPUNIT_TEST(testDomainIsFull); CPPUNIT_TEST(testDomainIsFull);
CPPUNIT_TEST(testEviction);
CPPUNIT_TEST_SUITE_END(); CPPUNIT_TEST_SUITE_END();
public: public:
void setUp() {} void setUp() {}
void tearDown() {} void tearDown() {}
void dumpCookie(std::vector<Cookie>& cookies, const CookieStorage& cs);
void testStore(); void testStore();
void testParseAndStore(); void testParseAndStore();
void testCriteriaFind(); void testCriteriaFind();
@ -48,56 +48,67 @@ public:
void testSaveNsFormat_fail(); void testSaveNsFormat_fail();
void testCookieIsFull(); void testCookieIsFull();
void testDomainIsFull(); void testDomainIsFull();
void testEviction();
}; };
CPPUNIT_TEST_SUITE_REGISTRATION(CookieStorageTest); CPPUNIT_TEST_SUITE_REGISTRATION(CookieStorageTest);
void CookieStorageTest::dumpCookie namespace {
(std::vector<Cookie>& cookies, const CookieStorage& st) std::vector<const Cookie*> dumpCookie(const CookieStorage& st)
{ {
st.dumpCookie(std::back_inserter(cookies)); auto res = std::vector<const Cookie*>{};
std::sort(cookies.begin(), cookies.end(), CookieSorter()); st.dumpCookie(std::back_inserter(res));
std::sort(res.begin(), res.end(), CookieSorter());
return res;
} }
} // namespace
void CookieStorageTest::testStore() void CookieStorageTest::testStore()
{ {
time_t now = 1000; time_t now = 1000;
CookieStorage st; auto st = CookieStorage{};
Cookie goodCookie(createCookie("k", "v", "localhost", true, "/", false)); auto goodCookie = []() {
CPPUNIT_ASSERT(st.store(goodCookie, now)); return createCookie("k", "v", "localhost", true, "/", false);
};
CPPUNIT_ASSERT(st.store(goodCookie(), now));
CPPUNIT_ASSERT_EQUAL((size_t)1, st.size()); CPPUNIT_ASSERT_EQUAL((size_t)1, st.size());
CPPUNIT_ASSERT(st.contains(goodCookie)); CPPUNIT_ASSERT(st.contains(*goodCookie()));
Cookie anotherCookie(createCookie("k", "v", "mirror", true, "/", true)); auto anotherCookie = []() {
CPPUNIT_ASSERT(st.store(anotherCookie, now)); return createCookie("k", "v", "mirror", true, "/", true);
};
CPPUNIT_ASSERT(st.store(anotherCookie(), now));
CPPUNIT_ASSERT_EQUAL((size_t)2, st.size()); CPPUNIT_ASSERT_EQUAL((size_t)2, st.size());
CPPUNIT_ASSERT(st.contains(anotherCookie)); CPPUNIT_ASSERT(st.contains(*anotherCookie()));
CPPUNIT_ASSERT(st.contains(goodCookie)); CPPUNIT_ASSERT(st.contains(*goodCookie()));
Cookie updateGoodCookie(createCookie("k", "v2", "localhost", true, auto updateGoodCookie = []() {
"/", false)); return createCookie("k", "v2", "localhost", true, "/", false);
CPPUNIT_ASSERT(st.store(updateGoodCookie, now)); };
CPPUNIT_ASSERT(st.store(updateGoodCookie(), now));
CPPUNIT_ASSERT_EQUAL((size_t)2, st.size()); CPPUNIT_ASSERT_EQUAL((size_t)2, st.size());
CPPUNIT_ASSERT(st.contains(updateGoodCookie)); CPPUNIT_ASSERT(st.contains(*updateGoodCookie()));
CPPUNIT_ASSERT(st.contains(anotherCookie)); CPPUNIT_ASSERT(st.contains(*anotherCookie()));
Cookie expireGoodCookie(createCookie("k", "v3", 0, "localhost", true, auto expireGoodCookie = []() {
"/", false)); return createCookie("k", "v3", 0, "localhost", true, "/", false);
CPPUNIT_ASSERT(!st.store(expireGoodCookie, now)); };
CPPUNIT_ASSERT(!st.store(expireGoodCookie(), now));
CPPUNIT_ASSERT_EQUAL((size_t)1, st.size()); CPPUNIT_ASSERT_EQUAL((size_t)1, st.size());
CPPUNIT_ASSERT(st.contains(anotherCookie)); CPPUNIT_ASSERT(st.contains(*anotherCookie()));
Cookie fromNumericHost(createCookie("k", "v", "192.168.1.1", true, auto fromNumericHost = []() {
"/", false)); return createCookie("k", "v", "192.168.1.1", true, "/", false);
CPPUNIT_ASSERT(st.store(fromNumericHost, now)); };
CPPUNIT_ASSERT(st.store(fromNumericHost(), now));
CPPUNIT_ASSERT_EQUAL((size_t)2, st.size()); CPPUNIT_ASSERT_EQUAL((size_t)2, st.size());
CPPUNIT_ASSERT(st.contains(fromNumericHost)); CPPUNIT_ASSERT(st.contains(*fromNumericHost()));
} }
void CookieStorageTest::testParseAndStore() void CookieStorageTest::testParseAndStore()
{ {
CookieStorage st; auto st = CookieStorage{};
time_t now = 1000; time_t now = 1000;
std::string localhostCookieStr = "k=v;" std::string localhostCookieStr = "k=v;"
" expires=Fri, 01 Jan 2038 00:00:00 GMT; path=/; domain=localhost;"; " expires=Fri, 01 Jan 2038 00:00:00 GMT; path=/; domain=localhost;";
@ -122,221 +133,233 @@ void CookieStorageTest::testParseAndStore()
void CookieStorageTest::testCriteriaFind() void CookieStorageTest::testCriteriaFind()
{ {
CookieStorage st; auto st = CookieStorage{};
time_t now = 1000; time_t now = 1000;
Cookie alpha(createCookie("alpha", "ALPHA", "aria2.org", false, "/", false)); auto alpha = []() {
Cookie bravo(createCookie("bravo", "BRAVO", 1060, "aria2.org", false, return createCookie("alpha", "ALPHA", "aria2.org", false, "/", false);
"/foo", false)); };
Cookie charlie(createCookie("charlie", "CHARLIE", "aria2.org", false, auto bravo = []() {
"/", true)); return createCookie("bravo", "BRAVO", 1060, "aria2.org", false,
Cookie delta(createCookie("delta", "DELTA", "aria2.org", false, "/foo", false);
"/foo/bar", false)); };
Cookie echo(createCookie("echo", "ECHO", "www.dl.aria2.org", false, auto charlie = []() {
"/", false)); return createCookie("charlie", "CHARLIE", "aria2.org", false,
Cookie foxtrot(createCookie("foxtrot", "FOXTROT", "sf.net", false, "/", true);
"/", false)); };
Cookie golf(createCookie("golf", "GOLF", "192.168.1.1", true, auto delta = []() {
"/", false)); return createCookie("delta", "DELTA", "aria2.org", false,
Cookie hotel1(createCookie("hotel", "HOTEL1", "samename.x", false, "/foo/bar", false);
"/", false)); };
Cookie hotel2(createCookie("hotel", "HOTEL2", "samename.x", false, auto echo = []() {
"/hotel", false)); return createCookie("echo", "ECHO", "www.dl.aria2.org", false,
Cookie hotel3(createCookie("hotel", "HOTEL3", "samename.x", false, "/", false);
"/bar/wine", false)); };
Cookie hotel4(createCookie("hotel", "HOTEL4", "samename.x", false, auto foxtrot = []() {
"/bar/", false)); return createCookie("foxtrot", "FOXTROT", "sf.net", false,
Cookie india1(createCookie("india", "INDIA1", "default.domain", true, "/", false);
"/foo", false)); };
Cookie india2(createCookie("india", "INDIA2", "default.domain", false, auto golf = []() {
"/", false)); return createCookie("golf", "GOLF", "192.168.1.1", true,
Cookie juliet1(createCookie("juliet", "JULIET1", "localhost", true, "/", false);
"/foo", false)); };
auto hotel1 = []() {
return createCookie("hotel", "HOTEL1", "samename.x", false,
"/", false);
};
auto hotel2 = []() {
return createCookie("hotel", "HOTEL2", "samename.x", false,
"/hotel", false);
};
auto hotel3 = []() {
return createCookie("hotel", "HOTEL3", "samename.x", false,
"/bar/wine", false);
};
auto hotel4 = []() {
return createCookie("hotel", "HOTEL4", "samename.x", false,
"/bar/", false);
};
auto india1 = []() {
return createCookie("india", "INDIA1", "default.domain", true,
"/foo", false);
};
auto india2 = []() {
return createCookie("india", "INDIA2", "default.domain", false,
"/", false);
};
auto juliet1 = []() {
return createCookie("juliet", "JULIET1", "localhost", true,
"/foo", false);
};
CPPUNIT_ASSERT(st.store(alpha, now)); CPPUNIT_ASSERT(st.store(alpha(), now));
CPPUNIT_ASSERT(st.store(bravo, now)); CPPUNIT_ASSERT(st.store(bravo(), now));
CPPUNIT_ASSERT(st.store(charlie, now)); CPPUNIT_ASSERT(st.store(charlie(), now));
CPPUNIT_ASSERT(st.store(delta, now)); CPPUNIT_ASSERT(st.store(delta(), now));
CPPUNIT_ASSERT(st.store(echo, now)); CPPUNIT_ASSERT(st.store(echo(), now));
CPPUNIT_ASSERT(st.store(foxtrot, now)); CPPUNIT_ASSERT(st.store(foxtrot(), now));
CPPUNIT_ASSERT(st.store(golf, now)); CPPUNIT_ASSERT(st.store(golf(), now));
CPPUNIT_ASSERT(st.store(hotel1, now)); CPPUNIT_ASSERT(st.store(hotel1(), now));
CPPUNIT_ASSERT(st.store(hotel2, now)); CPPUNIT_ASSERT(st.store(hotel2(), now));
CPPUNIT_ASSERT(st.store(hotel3, now)); CPPUNIT_ASSERT(st.store(hotel3(), now));
CPPUNIT_ASSERT(st.store(hotel4, now)); CPPUNIT_ASSERT(st.store(hotel4(), now));
CPPUNIT_ASSERT(st.store(india1, now)); CPPUNIT_ASSERT(st.store(india1(), now));
CPPUNIT_ASSERT(st.store(india2, now)); CPPUNIT_ASSERT(st.store(india2(), now));
CPPUNIT_ASSERT(st.store(juliet1, now)); CPPUNIT_ASSERT(st.store(juliet1(), now));
std::vector<Cookie> aria2Slash = st.criteriaFind("www.dl.aria2.org", "/", auto aria2Slash = st.criteriaFind("www.dl.aria2.org", "/", 0, false);
0, false);
CPPUNIT_ASSERT_EQUAL((size_t)2, aria2Slash.size()); CPPUNIT_ASSERT_EQUAL((size_t)2, aria2Slash.size());
CPPUNIT_ASSERT(std::find(aria2Slash.begin(), aria2Slash.end(), alpha) CPPUNIT_ASSERT(derefFind(aria2Slash, alpha()));
!= aria2Slash.end()); CPPUNIT_ASSERT(derefFind(aria2Slash, echo()));
CPPUNIT_ASSERT(std::find(aria2Slash.begin(), aria2Slash.end(), echo)
!= aria2Slash.end());
std::vector<Cookie> aria2SlashFoo = st.criteriaFind("www.dl.aria2.org","/foo", auto aria2SlashFoo = st.criteriaFind("www.dl.aria2.org","/foo", 0, false);
0, false);
CPPUNIT_ASSERT_EQUAL((size_t)3, aria2SlashFoo.size()); CPPUNIT_ASSERT_EQUAL((size_t)3, aria2SlashFoo.size());
CPPUNIT_ASSERT_EQUAL(std::string("bravo"), aria2SlashFoo[0].getName()); CPPUNIT_ASSERT_EQUAL(std::string("bravo"), aria2SlashFoo[0]->getName());
CPPUNIT_ASSERT(std::find(aria2SlashFoo.begin(), aria2SlashFoo.end(), alpha) CPPUNIT_ASSERT(derefFind(aria2SlashFoo, alpha()));
!= aria2SlashFoo.end()); CPPUNIT_ASSERT(derefFind(aria2SlashFoo, echo()));
CPPUNIT_ASSERT(std::find(aria2SlashFoo.begin(), aria2SlashFoo.end(), echo)
!= aria2SlashFoo.end());
std::vector<Cookie> aria2Expires = st.criteriaFind("www.dl.aria2.org", "/foo", auto aria2Expires = st.criteriaFind("www.dl.aria2.org", "/foo", 1120, false);
1120,
false);
CPPUNIT_ASSERT_EQUAL((size_t)2, aria2Expires.size()); CPPUNIT_ASSERT_EQUAL((size_t)2, aria2Expires.size());
CPPUNIT_ASSERT(std::find(aria2Expires.begin(), aria2Expires.end(), alpha) CPPUNIT_ASSERT(derefFind(aria2Expires, alpha()));
!= aria2Expires.end()); CPPUNIT_ASSERT(derefFind(aria2Expires, echo()));
CPPUNIT_ASSERT(std::find(aria2Expires.begin(), aria2Expires.end(), echo)
!= aria2Expires.end());
std::vector<Cookie> dlAria2 = st.criteriaFind("dl.aria2.org", "/", 0, false); auto dlAria2 = st.criteriaFind("dl.aria2.org", "/", 0, false);
CPPUNIT_ASSERT_EQUAL((size_t)1, dlAria2.size()); CPPUNIT_ASSERT_EQUAL((size_t)1, dlAria2.size());
CPPUNIT_ASSERT_EQUAL(std::string("alpha"), dlAria2[0].getName()); CPPUNIT_ASSERT_EQUAL(std::string("alpha"), dlAria2[0]->getName());
std::vector<Cookie> tailmatchAria2 = st.criteriaFind("myaria2.org", "/", 0, auto tailmatchAria2 = st.criteriaFind("myaria2.org", "/", 0, false);
false);
CPPUNIT_ASSERT(tailmatchAria2.empty()); CPPUNIT_ASSERT(tailmatchAria2.empty());
std::vector<Cookie> numericHostCookies = st.criteriaFind("192.168.1.1", "/",0, auto numericHostCookies = st.criteriaFind("192.168.1.1", "/",0, false);
false);
CPPUNIT_ASSERT_EQUAL((size_t)1, numericHostCookies.size()); CPPUNIT_ASSERT_EQUAL((size_t)1, numericHostCookies.size());
CPPUNIT_ASSERT_EQUAL(std::string("golf"), numericHostCookies[0].getName()); CPPUNIT_ASSERT_EQUAL(std::string("golf"), numericHostCookies[0]->getName());
std::vector<Cookie> sameNameCookies = auto sameNameCookies = st.criteriaFind("samename.x", "/bar/wine", 0, false);
st.criteriaFind("samename.x", "/bar/wine", 0, false);
CPPUNIT_ASSERT_EQUAL((size_t)3, sameNameCookies.size()); CPPUNIT_ASSERT_EQUAL((size_t)3, sameNameCookies.size());
CPPUNIT_ASSERT_EQUAL(std::string("HOTEL3"), sameNameCookies[0].getValue()); CPPUNIT_ASSERT_EQUAL(std::string("HOTEL3"), sameNameCookies[0]->getValue());
CPPUNIT_ASSERT_EQUAL(std::string("HOTEL4"), sameNameCookies[1].getValue()); CPPUNIT_ASSERT_EQUAL(std::string("HOTEL4"), sameNameCookies[1]->getValue());
CPPUNIT_ASSERT_EQUAL(std::string("HOTEL1"), sameNameCookies[2].getValue()); CPPUNIT_ASSERT_EQUAL(std::string("HOTEL1"), sameNameCookies[2]->getValue());
std::vector<Cookie> defaultDomainCookies = auto defaultDomainCookies = st.criteriaFind("default.domain", "/foo", 0,
st.criteriaFind("default.domain", "/foo", 0, false); false);
CPPUNIT_ASSERT_EQUAL((size_t)2, defaultDomainCookies.size()); CPPUNIT_ASSERT_EQUAL((size_t)2, defaultDomainCookies.size());
CPPUNIT_ASSERT_EQUAL(std::string("INDIA1"), CPPUNIT_ASSERT_EQUAL(std::string("INDIA1"),
defaultDomainCookies[0].getValue()); defaultDomainCookies[0]->getValue());
CPPUNIT_ASSERT_EQUAL(std::string("INDIA2"), CPPUNIT_ASSERT_EQUAL(std::string("INDIA2"),
defaultDomainCookies[1].getValue()); defaultDomainCookies[1]->getValue());
defaultDomainCookies = defaultDomainCookies =
st.criteriaFind("sub.default.domain", "/foo", 0, false); st.criteriaFind("sub.default.domain", "/foo", 0, false);
CPPUNIT_ASSERT_EQUAL((size_t)1, defaultDomainCookies.size()); CPPUNIT_ASSERT_EQUAL((size_t)1, defaultDomainCookies.size());
CPPUNIT_ASSERT_EQUAL(std::string("INDIA2"), CPPUNIT_ASSERT_EQUAL(std::string("INDIA2"),
defaultDomainCookies[0].getValue()); defaultDomainCookies[0]->getValue());
// localhost.local case // localhost.local case
std::vector<Cookie> localDomainCookies = auto localDomainCookies = st.criteriaFind("localhost", "/foo", 0, false);
st.criteriaFind("localhost", "/foo", 0, false);
CPPUNIT_ASSERT_EQUAL((size_t)1, localDomainCookies.size()); CPPUNIT_ASSERT_EQUAL((size_t)1, localDomainCookies.size());
CPPUNIT_ASSERT_EQUAL(std::string("JULIET1"), CPPUNIT_ASSERT_EQUAL(std::string("JULIET1"),
localDomainCookies[0].getValue()); localDomainCookies[0]->getValue());
} }
void CookieStorageTest::testCriteriaFind_cookieOrder() void CookieStorageTest::testCriteriaFind_cookieOrder()
{ {
CookieStorage st; auto st = CookieStorage{};
Cookie a(createCookie("a", "0", "host", true, "/", false)); auto a = createCookie("a", "0", "host", true, "/", false);
a.setCreationTime(1000); a->setCreationTime(1000);
Cookie b(createCookie("b", "0", "host", true, "/foo", false)); auto b = createCookie("b", "0", "host", true, "/foo", false);
b.setCreationTime(5000); b->setCreationTime(5000);
Cookie c(createCookie("c", "0", "host", true, "/foo", false)); auto c = createCookie("c", "0", "host", true, "/foo", false);
c.setCreationTime(4000); c->setCreationTime(4000);
Cookie d(createCookie("d", "0", "host", true, "/foo/bar", false)); auto d = createCookie("d", "0", "host", true, "/foo/bar", false);
d.setCreationTime(6000); d->setCreationTime(6000);
st.store(a, 0); st.store(std::move(a), 0);
st.store(b, 0); st.store(std::move(b), 0);
st.store(c, 0); st.store(std::move(c), 0);
st.store(d, 0); st.store(std::move(d), 0);
std::vector<Cookie> cookies = st.criteriaFind("host", "/foo/bar", 0, false); auto cookies = st.criteriaFind("host", "/foo/bar", 0, false);
CPPUNIT_ASSERT_EQUAL((size_t)4, cookies.size()); CPPUNIT_ASSERT_EQUAL((size_t)4, cookies.size());
CPPUNIT_ASSERT_EQUAL(std::string("d"), cookies[0].getName()); CPPUNIT_ASSERT_EQUAL(std::string("d"), cookies[0]->getName());
CPPUNIT_ASSERT_EQUAL(std::string("c"), cookies[1].getName()); CPPUNIT_ASSERT_EQUAL(std::string("c"), cookies[1]->getName());
CPPUNIT_ASSERT_EQUAL(std::string("b"), cookies[2].getName()); CPPUNIT_ASSERT_EQUAL(std::string("b"), cookies[2]->getName());
CPPUNIT_ASSERT_EQUAL(std::string("a"), cookies[3].getName()); CPPUNIT_ASSERT_EQUAL(std::string("a"), cookies[3]->getName());
} }
void CookieStorageTest::testLoad() void CookieStorageTest::testLoad()
{ {
CookieStorage st; auto st = CookieStorage{};
st.load(A2_TEST_DIR"/nscookietest.txt", 1001); st.load(A2_TEST_DIR"/nscookietest.txt", 1001);
CPPUNIT_ASSERT_EQUAL((size_t)4, st.size()); CPPUNIT_ASSERT_EQUAL((size_t)4, st.size());
std::vector<Cookie> cookies; auto cookies = dumpCookie(st);
dumpCookie(cookies, st);
Cookie c = cookies[0]; auto c = cookies[0];
CPPUNIT_ASSERT_EQUAL(std::string("passwd"), c.getName()); CPPUNIT_ASSERT_EQUAL(std::string("passwd"), c->getName());
CPPUNIT_ASSERT_EQUAL(std::string("secret"), c.getValue()); CPPUNIT_ASSERT_EQUAL(std::string("secret"), c->getValue());
CPPUNIT_ASSERT_EQUAL(std::numeric_limits<time_t>::max(), c.getExpiryTime()); CPPUNIT_ASSERT_EQUAL(std::numeric_limits<time_t>::max(), c->getExpiryTime());
CPPUNIT_ASSERT(!c.getPersistent()); CPPUNIT_ASSERT(!c->getPersistent());
CPPUNIT_ASSERT_EQUAL(std::string("/cgi-bin"), c.getPath()); CPPUNIT_ASSERT_EQUAL(std::string("/cgi-bin"), c->getPath());
CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), c.getDomain()); CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), c->getDomain());
CPPUNIT_ASSERT(c.getHostOnly()); CPPUNIT_ASSERT(c->getHostOnly());
CPPUNIT_ASSERT(!c.getSecure()); CPPUNIT_ASSERT(!c->getSecure());
c = cookies[1]; c = cookies[1];
CPPUNIT_ASSERT_EQUAL(std::string("novalue"), c.getName()); CPPUNIT_ASSERT_EQUAL(std::string("novalue"), c->getName());
CPPUNIT_ASSERT_EQUAL(std::string(""), c.getValue()); CPPUNIT_ASSERT_EQUAL(std::string(""), c->getValue());
CPPUNIT_ASSERT_EQUAL((time_t)2147483647, c.getExpiryTime()); CPPUNIT_ASSERT_EQUAL((time_t)2147483647, c->getExpiryTime());
CPPUNIT_ASSERT(c.getPersistent()); CPPUNIT_ASSERT(c->getPersistent());
CPPUNIT_ASSERT_EQUAL(std::string("/"), c.getPath()); CPPUNIT_ASSERT_EQUAL(std::string("/"), c->getPath());
CPPUNIT_ASSERT_EQUAL(std::string("example.org"), c.getDomain()); CPPUNIT_ASSERT_EQUAL(std::string("example.org"), c->getDomain());
CPPUNIT_ASSERT(!c.getHostOnly()); CPPUNIT_ASSERT(!c->getHostOnly());
CPPUNIT_ASSERT(!c.getSecure()); CPPUNIT_ASSERT(!c->getSecure());
c = cookies[2]; c = cookies[2];
CPPUNIT_ASSERT_EQUAL(std::string("JSESSIONID"), c.getName()); CPPUNIT_ASSERT_EQUAL(std::string("JSESSIONID"), c->getName());
CPPUNIT_ASSERT_EQUAL(std::string("123456789"), c.getValue()); CPPUNIT_ASSERT_EQUAL(std::string("123456789"), c->getValue());
CPPUNIT_ASSERT_EQUAL((time_t)2147483647, c.getExpiryTime()); CPPUNIT_ASSERT_EQUAL((time_t)2147483647, c->getExpiryTime());
CPPUNIT_ASSERT_EQUAL(std::string("/"), c.getPath()); CPPUNIT_ASSERT_EQUAL(std::string("/"), c->getPath());
CPPUNIT_ASSERT_EQUAL(std::string("localhost"), c.getDomain()); CPPUNIT_ASSERT_EQUAL(std::string("localhost"), c->getDomain());
CPPUNIT_ASSERT(c.getHostOnly()); CPPUNIT_ASSERT(c->getHostOnly());
CPPUNIT_ASSERT(c.getSecure()); CPPUNIT_ASSERT(c->getSecure());
c = cookies[3]; c = cookies[3];
CPPUNIT_ASSERT_EQUAL(std::string("TAX"), c.getName()); CPPUNIT_ASSERT_EQUAL(std::string("TAX"), c->getName());
CPPUNIT_ASSERT_EQUAL(std::string("1000"), c.getValue()); CPPUNIT_ASSERT_EQUAL(std::string("1000"), c->getValue());
CPPUNIT_ASSERT((time_t)INT32_MAX <= c.getExpiryTime()); CPPUNIT_ASSERT((time_t)INT32_MAX <= c->getExpiryTime());
CPPUNIT_ASSERT(c.getPersistent()); CPPUNIT_ASSERT(c->getPersistent());
CPPUNIT_ASSERT_EQUAL(std::string("/"), c.getPath()); CPPUNIT_ASSERT_EQUAL(std::string("/"), c->getPath());
CPPUNIT_ASSERT_EQUAL(std::string("overflow"), c.getDomain()); CPPUNIT_ASSERT_EQUAL(std::string("overflow"), c->getDomain());
CPPUNIT_ASSERT(!c.getSecure()); CPPUNIT_ASSERT(!c->getSecure());
} }
void CookieStorageTest::testLoad_sqlite3() void CookieStorageTest::testLoad_sqlite3()
{ {
CookieStorage st; auto st = CookieStorage{};
#ifdef HAVE_SQLITE3 #ifdef HAVE_SQLITE3
st.load(A2_TEST_DIR"/cookies.sqlite", 1000); st.load(A2_TEST_DIR"/cookies.sqlite", 1000);
CPPUNIT_ASSERT_EQUAL((size_t)2, st.size()); CPPUNIT_ASSERT_EQUAL((size_t)2, st.size());
std::vector<Cookie> cookies; auto cookies = dumpCookie(st);
dumpCookie(cookies, st); auto c = cookies[0];
Cookie c = cookies[0]; CPPUNIT_ASSERT_EQUAL(std::string("JSESSIONID"), c->getName());
CPPUNIT_ASSERT_EQUAL(std::string("JSESSIONID"), c.getName()); CPPUNIT_ASSERT_EQUAL(std::string("123456789"), c->getValue());
CPPUNIT_ASSERT_EQUAL(std::string("123456789"), c.getValue()); CPPUNIT_ASSERT_EQUAL((time_t)INT32_MAX, c->getExpiryTime());
CPPUNIT_ASSERT_EQUAL((time_t)INT32_MAX, c.getExpiryTime()); CPPUNIT_ASSERT(c->getPersistent());
CPPUNIT_ASSERT(c.getPersistent()); CPPUNIT_ASSERT_EQUAL(std::string("localhost"), c->getDomain());
CPPUNIT_ASSERT_EQUAL(std::string("localhost"), c.getDomain()); CPPUNIT_ASSERT(c->getHostOnly());
CPPUNIT_ASSERT(c.getHostOnly()); CPPUNIT_ASSERT_EQUAL(std::string("/"), c->getPath());
CPPUNIT_ASSERT_EQUAL(std::string("/"), c.getPath()); CPPUNIT_ASSERT(c->getSecure());
CPPUNIT_ASSERT(c.getSecure());
c = cookies[1]; c = cookies[1];
CPPUNIT_ASSERT_EQUAL(std::string("foo"), c.getName()); CPPUNIT_ASSERT_EQUAL(std::string("foo"), c->getName());
CPPUNIT_ASSERT_EQUAL(std::string("bar"), c.getValue()); CPPUNIT_ASSERT_EQUAL(std::string("bar"), c->getValue());
CPPUNIT_ASSERT((time_t)INT32_MAX <= c.getExpiryTime()); CPPUNIT_ASSERT((time_t)INT32_MAX <= c->getExpiryTime());
CPPUNIT_ASSERT(c.getPersistent()); CPPUNIT_ASSERT(c->getPersistent());
CPPUNIT_ASSERT_EQUAL(std::string("overflow.time_t.org"), c.getDomain()); CPPUNIT_ASSERT_EQUAL(std::string("overflow.time_t.org"), c->getDomain());
CPPUNIT_ASSERT(!c.getHostOnly()); CPPUNIT_ASSERT(!c->getHostOnly());
CPPUNIT_ASSERT_EQUAL(std::string("/path/to"), c.getPath()); CPPUNIT_ASSERT_EQUAL(std::string("/path/to"), c->getPath());
CPPUNIT_ASSERT(!c.getSecure()); CPPUNIT_ASSERT(!c->getSecure());
#else // !HAVE_SQLITE3 #else // !HAVE_SQLITE3
CPPUNIT_ASSERT(!st.load(A2_TEST_DIR"/cookies.sqlite", 1000)); CPPUNIT_ASSERT(!st.load(A2_TEST_DIR"/cookies.sqlite", 1000));
@ -345,7 +368,7 @@ void CookieStorageTest::testLoad_sqlite3()
void CookieStorageTest::testLoad_fileNotfound() void CookieStorageTest::testLoad_fileNotfound()
{ {
CookieStorage st; auto st = CookieStorage{};
CPPUNIT_ASSERT(!st.load("./aria2_CookieStorageTest_testLoad_fileNotfound",0)); CPPUNIT_ASSERT(!st.load("./aria2_CookieStorageTest_testLoad_fileNotfound",0));
} }
@ -354,22 +377,22 @@ void CookieStorageTest::testSaveNsFormat()
// TODO add cookie with default domain // TODO add cookie with default domain
std::string filename = A2_TEST_OUT_DIR"/aria2_CookieStorageTest_testSaveNsFormat"; std::string filename = A2_TEST_OUT_DIR"/aria2_CookieStorageTest_testSaveNsFormat";
File(filename).remove(); File(filename).remove();
CookieStorage st; auto st = CookieStorage{};
time_t now = 1000; time_t now = 1000;
st.store(Cookie(createCookie("favorite", "classic", "domain.org", false, st.store(createCookie("favorite", "classic", "domain.org", false,
"/config",true)), now); "/config",true), now);
st.store(Cookie(createCookie("uid", "tujikawa", now, "domain.org", true, st.store(createCookie("uid", "tujikawa", now, "domain.org", true,
"/",false)), now); "/",false), now);
CPPUNIT_ASSERT(st.saveNsFormat(filename)); CPPUNIT_ASSERT(st.saveNsFormat(filename));
CookieStorage loadst; auto loadst = CookieStorage{};
loadst.load(filename, now); loadst.load(filename, now);
CPPUNIT_ASSERT_EQUAL((size_t)2, loadst.size()); CPPUNIT_ASSERT_EQUAL((size_t)2, loadst.size());
std::vector<Cookie> cookies; auto cookies = dumpCookie(loadst);
dumpCookie(cookies, loadst);
CPPUNIT_ASSERT_EQUAL(std::string("favorite"), cookies[0].getName()); CPPUNIT_ASSERT_EQUAL((size_t)2, cookies.size());
CPPUNIT_ASSERT_EQUAL(std::string("uid"), cookies[1].getName()); CPPUNIT_ASSERT_EQUAL(std::string("favorite"), cookies[0]->getName());
CPPUNIT_ASSERT_EQUAL(std::string("uid"), cookies[1]->getName());
} }
void CookieStorageTest::testSaveNsFormat_fail() void CookieStorageTest::testSaveNsFormat_fail()
@ -380,17 +403,16 @@ void CookieStorageTest::testSaveNsFormat_fail()
f.remove(); f.remove();
f.mkdirs(); f.mkdirs();
CPPUNIT_ASSERT(f.isDir()); CPPUNIT_ASSERT(f.isDir());
CookieStorage st; auto st = CookieStorage{};
CPPUNIT_ASSERT(!st.saveNsFormat(filename)); CPPUNIT_ASSERT(!st.saveNsFormat(filename));
} }
void CookieStorageTest::testCookieIsFull() void CookieStorageTest::testCookieIsFull()
{ {
CookieStorage st; auto st = CookieStorage{};
for(size_t i = 0; i < CookieStorage::MAX_COOKIE_PER_DOMAIN+1; ++i) { for(size_t i = 0; i < CookieStorage::MAX_COOKIE_PER_DOMAIN+1; ++i) {
Cookie c(createCookie("k"+util::itos(i), "v", "aria2.org", false, st.store(createCookie("k"+util::itos(i), "v", "aria2.org", false,
"/", false)); "/", false), 0);
st.store(c, 0);
} }
CPPUNIT_ASSERT_EQUAL((size_t)CookieStorage::MAX_COOKIE_PER_DOMAIN, st.size()); CPPUNIT_ASSERT_EQUAL((size_t)CookieStorage::MAX_COOKIE_PER_DOMAIN, st.size());
} }
@ -399,13 +421,58 @@ void CookieStorageTest::testDomainIsFull()
{ {
// See DOMAIN_EVICTION_TRIGGER and DOMAIN_EVICTION_RATE in // See DOMAIN_EVICTION_TRIGGER and DOMAIN_EVICTION_RATE in
// CookieStorage.cc // CookieStorage.cc
CookieStorage st; auto st = CookieStorage{};
for(size_t i = 0; i < 2001; ++i) { for(size_t i = 0; i < 2001; ++i) {
Cookie c(createCookie("k", "v", "domain"+util::itos(i), true, st.store(createCookie("k", "v", "domain"+util::itos(i), true,
"/", false)); "/", false), 0);
st.store(c, 0);
} }
CPPUNIT_ASSERT_EQUAL((size_t)1801, st.size()); CPPUNIT_ASSERT_EQUAL((size_t)1801, st.size());
} }
void CookieStorageTest::testEviction()
{
auto st = CookieStorage{};
auto alpha = []() {
return createCookie("a", "alpha", "aria2.sf.net", false, "/", false);
};
auto bravo = []() {
return createCookie("b", "bravo", "d.aria2.sf.net", false, "/", false);
};
auto charlie = []() {
return createCookie("c", "charlie", "a2.github.com", false, "/", false);
};
auto delta = []() {
return createCookie("d", "delta", "aria2.sf.net", false, "/", false);
};
st.store(alpha(), 0);
CPPUNIT_ASSERT_EQUAL((size_t)1, st.getLruTrackerSize());
st.store(bravo(), 1);
CPPUNIT_ASSERT_EQUAL((size_t)2, st.getLruTrackerSize());
st.store(charlie(), 2);
CPPUNIT_ASSERT_EQUAL((size_t)3, st.getLruTrackerSize());
st.store(delta(), 0);
CPPUNIT_ASSERT_EQUAL((size_t)3, st.getLruTrackerSize());
// aria2.sf.net will be evicted
st.evictNode(1);
CPPUNIT_ASSERT_EQUAL((size_t)2, st.getLruTrackerSize());
CPPUNIT_ASSERT(!st.contains(*alpha()));
CPPUNIT_ASSERT(st.contains(*bravo()));
CPPUNIT_ASSERT(st.contains(*charlie()));
CPPUNIT_ASSERT(!st.contains(*delta()));
// d.aria2.sf.net will be evicted
st.evictNode(1);
CPPUNIT_ASSERT_EQUAL((size_t)1, st.getLruTrackerSize());
CPPUNIT_ASSERT(!st.contains(*bravo()));
CPPUNIT_ASSERT(st.contains(*charlie()));
// a2.github.com will be evicted
st.evictNode(1);
CPPUNIT_ASSERT_EQUAL((size_t)0, st.getLruTrackerSize());
CPPUNIT_ASSERT(!st.contains(*charlie()));
CPPUNIT_ASSERT_EQUAL((size_t)0, st.size());
CPPUNIT_ASSERT(!st.getRootNode()->hasNext());
}
} // namespace aria2 } // namespace aria2

View File

@ -35,67 +35,66 @@ CPPUNIT_TEST_SUITE_REGISTRATION(CookieTest);
void CookieTest::testOperatorEqual() void CookieTest::testOperatorEqual()
{ {
Cookie a(createCookie("k", "v", "localhost", true, "/", false)); auto a = createCookie("k", "v", "localhost", true, "/", false);
Cookie b(createCookie("k", "v", "localhost", true, "/", true)); auto b = createCookie("k", "v", "localhost", true, "/", true);
Cookie wrongPath(createCookie("k", "v", "localhost", true, "/a", false)); auto wrongPath = createCookie("k", "v", "localhost", true, "/a", false);
Cookie wrongDomain(createCookie("k", "v", "mydomain", true, "/", false)); auto wrongDomain = createCookie("k", "v", "mydomain", true, "/", false);
Cookie wrongName(createCookie("h", "v", "localhost", true, "/a", false)); auto wrongName = createCookie("h", "v", "localhost", true, "/a", false);
Cookie caseSensitiveName(createCookie("K", "v", "localhost", true, auto caseSensitiveName = createCookie("K", "v", "localhost", true,
"/a", false)); "/a", false);
CPPUNIT_ASSERT(a == b); CPPUNIT_ASSERT(*a == *b);
CPPUNIT_ASSERT(!(a == wrongPath)); CPPUNIT_ASSERT(!(*a == *wrongPath));
CPPUNIT_ASSERT(!(a == wrongDomain)); CPPUNIT_ASSERT(!(*a == *wrongDomain));
CPPUNIT_ASSERT(!(a == wrongName)); CPPUNIT_ASSERT(!(*a == *wrongName));
CPPUNIT_ASSERT(!(a == caseSensitiveName)); CPPUNIT_ASSERT(!(*a == *caseSensitiveName));
} }
void CookieTest::testMatch() void CookieTest::testMatch()
{ {
Cookie c(createCookie("k", "v", "aria2.org", false, "/downloads", false)); auto c = createCookie("k", "v", "aria2.org", false, "/downloads", false);
Cookie c2(createCookie("k", "v", "aria2.org", false, "/downloads", false)); auto c2 = createCookie("k", "v", "aria2.org", false, "/downloads", false);
Cookie c3(createCookie("k", "v", "aria2.org", true, "/downloads", false)); auto c3 = createCookie("k", "v", "aria2.org", true, "/downloads", false);
Cookie c4(createCookie("k", "v", "localhost", true, "/downloads", false)); auto c4 = createCookie("k", "v", "localhost", true, "/downloads", false);
CPPUNIT_ASSERT(c.match("www.aria2.org", "/downloads", 0, false)); CPPUNIT_ASSERT(c->match("www.aria2.org", "/downloads", 0, false));
CPPUNIT_ASSERT(c2.match("www.aria2.org", "/downloads", 0, false)); CPPUNIT_ASSERT(c2->match("www.aria2.org", "/downloads", 0, false));
CPPUNIT_ASSERT(!c.match("www.aria.org", "/downloads", 0, false)); CPPUNIT_ASSERT(!c->match("www.aria.org", "/downloads", 0, false));
CPPUNIT_ASSERT(!c.match("www.aria2.org", "/examples", 0, false)); CPPUNIT_ASSERT(!c->match("www.aria2.org", "/examples", 0, false));
CPPUNIT_ASSERT(c.match("www.aria2.org", "/downloads", 0, true)); CPPUNIT_ASSERT(c->match("www.aria2.org", "/downloads", 0, true));
CPPUNIT_ASSERT(c.match("www.aria2.org", "/downloads/latest", 0, false)); CPPUNIT_ASSERT(c->match("www.aria2.org", "/downloads/latest", 0, false));
CPPUNIT_ASSERT(!c.match("www.aria2.org", "/downloadss/latest", 0, false)); CPPUNIT_ASSERT(!c->match("www.aria2.org", "/downloadss/latest", 0, false));
CPPUNIT_ASSERT(!c.match("www.aria2.org", "/DOWNLOADS", 0, false)); CPPUNIT_ASSERT(!c->match("www.aria2.org", "/DOWNLOADS", 0, false));
CPPUNIT_ASSERT(!c3.match("www.aria2.org", "/downloads", 0, false)); CPPUNIT_ASSERT(!c3->match("www.aria2.org", "/downloads", 0, false));
CPPUNIT_ASSERT(c4.match("localhost", "/downloads", 0, false)); CPPUNIT_ASSERT(c4->match("localhost", "/downloads", 0, false));
Cookie secureCookie(createCookie("k", "v", "secure.aria2.org", false, auto secureCookie = createCookie("k", "v", "secure.aria2.org", false,
"/", true)); "/", true);
CPPUNIT_ASSERT(secureCookie.match("secure.aria2.org", "/", 0, true)); CPPUNIT_ASSERT(secureCookie->match("secure.aria2.org", "/", 0, true));
CPPUNIT_ASSERT(!secureCookie.match("secure.aria2.org", "/", 0, false)); CPPUNIT_ASSERT(!secureCookie->match("secure.aria2.org", "/", 0, false));
CPPUNIT_ASSERT(!secureCookie.match("ssecure.aria2.org", "/", 0, true)); CPPUNIT_ASSERT(!secureCookie->match("ssecure.aria2.org", "/", 0, true));
CPPUNIT_ASSERT(secureCookie.match("www.secure.aria2.org", "/", 0, true)); CPPUNIT_ASSERT(secureCookie->match("www.secure.aria2.org", "/", 0, true));
Cookie expireTest(createCookie("k", "v", 1000, "aria2.org", false, auto expireTest = createCookie("k", "v", 1000, "aria2.org", false,
"/", false)); "/", false);
CPPUNIT_ASSERT(expireTest.match("www.aria2.org", "/", 999, false)); CPPUNIT_ASSERT(expireTest->match("www.aria2.org", "/", 999, false));
CPPUNIT_ASSERT(expireTest.match("www.aria2.org", "/", 1000, false)); CPPUNIT_ASSERT(expireTest->match("www.aria2.org", "/", 1000, false));
CPPUNIT_ASSERT(!expireTest.match("www.aria2.org", "/", 1001, false)); CPPUNIT_ASSERT(!expireTest->match("www.aria2.org", "/", 1001, false));
Cookie fromNumericHost(createCookie("k", "v", "192.168.1.1", true, auto fromNumericHost = createCookie("k", "v", "192.168.1.1", true,
"/foo", false)); "/foo", false);
CPPUNIT_ASSERT(fromNumericHost.match("192.168.1.1", "/foo", 0, false)); CPPUNIT_ASSERT(fromNumericHost->match("192.168.1.1", "/foo", 0, false));
CPPUNIT_ASSERT(!fromNumericHost.match("www.aria2.org", "/foo", 0, false)); CPPUNIT_ASSERT(!fromNumericHost->match("www.aria2.org", "/foo", 0, false));
CPPUNIT_ASSERT(!fromNumericHost.match("1.192.168.1.1", "/foo", 0, false)); CPPUNIT_ASSERT(!fromNumericHost->match("1.192.168.1.1", "/foo", 0, false));
CPPUNIT_ASSERT(!fromNumericHost.match("192.168.1.1", "/", 0, false)); CPPUNIT_ASSERT(!fromNumericHost->match("192.168.1.1", "/", 0, false));
} }
void CookieTest::testIsExpired() void CookieTest::testIsExpired()
{ {
Cookie cookie(createCookie("k", "v", 1000, "localhost", true, auto cookie = createCookie("k", "v", 1000, "localhost", true, "/", false);
"/", false)); CPPUNIT_ASSERT(cookie->isExpired(1001));
CPPUNIT_ASSERT(cookie.isExpired(1001)); CPPUNIT_ASSERT(!cookie->isExpired(1000));
CPPUNIT_ASSERT(!cookie.isExpired(1000)); CPPUNIT_ASSERT(!cookie->isExpired(999));
CPPUNIT_ASSERT(!cookie.isExpired(999)); auto sessionCookie = createCookie("k", "v", "localhost", true, "/", false);
Cookie sessionCookie(createCookie("k", "v", "localhost", true, "/", false)); CPPUNIT_ASSERT(!sessionCookie->isExpired(INT32_MAX));
CPPUNIT_ASSERT(!sessionCookie.isExpired(INT32_MAX));
} }
void CookieTest::testToNsCookieFormat() void CookieTest::testToNsCookieFormat()
@ -103,12 +102,12 @@ void CookieTest::testToNsCookieFormat()
CPPUNIT_ASSERT_EQUAL CPPUNIT_ASSERT_EQUAL
(std::string(".domain.org\tTRUE\t/\tFALSE\t12345678\thello\tworld"), (std::string(".domain.org\tTRUE\t/\tFALSE\t12345678\thello\tworld"),
createCookie("hello", "world", 12345678, "domain.org", false, "/",false) createCookie("hello", "world", 12345678, "domain.org", false, "/",false)
.toNsCookieFormat()); ->toNsCookieFormat());
// Session cookie // Session cookie
CPPUNIT_ASSERT_EQUAL CPPUNIT_ASSERT_EQUAL
(std::string("domain.org\tFALSE\t/\tTRUE\t0\thello\tworld"), (std::string("domain.org\tFALSE\t/\tTRUE\t0\thello\tworld"),
createCookie("hello", "world", "domain.org", true, "/", true) createCookie("hello", "world", "domain.org", true, "/", true)
.toNsCookieFormat()); ->toNsCookieFormat());
} }
} // namespace aria2 } // namespace aria2

View File

@ -368,6 +368,13 @@ void HttpRequestTest::testCreateRequest_ftp()
CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest()); CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());
} }
template<typename InputIterator>
void foo(CookieStorage& st, InputIterator first, InputIterator last, time_t t)
{
for(; first != last; ++first) {
st.store(*first, t);
}
}
void HttpRequestTest::testCreateRequest_with_cookie() void HttpRequestTest::testCreateRequest_with_cookie()
{ {
auto request = std::make_shared<Request>(); auto request = std::make_shared<Request>();
@ -376,19 +383,17 @@ void HttpRequestTest::testCreateRequest_with_cookie()
auto segment = std::make_shared<PiecedSegment>(1024*1024, p); auto segment = std::make_shared<PiecedSegment>(1024*1024, p);
auto fileEntry = std::make_shared<FileEntry>("file", 1024*1024*10, 0); auto fileEntry = std::make_shared<FileEntry>("file", 1024*1024*10, 0);
std::vector<Cookie> cookies { auto st = CookieStorage{};
createCookie("name1", "value1", "localhost", true, "/archives", false), CPPUNIT_ASSERT(st.store(createCookie("name1", "value1", "localhost", true,
createCookie("name2", "value2", "localhost", true, "/archives", false), 0));
"/archives/download", false), CPPUNIT_ASSERT(st.store(createCookie("name2", "value2", "localhost", true,
createCookie("name3", "value3", "aria2.org", false, "/archives/download", false), 0));
"/archives/download", false), CPPUNIT_ASSERT(st.store(createCookie("name3", "value3", "aria2.org", false,
createCookie("name4", "value4", "aria2.org", false, "/archives/", true), "/archives/download", false), 0));
createCookie("name5", "value5", "example.org", false, "/", false) CPPUNIT_ASSERT(st.store(createCookie("name4", "value4", "aria2.org", false,
}; "/archives/", true), 0));
CookieStorage st; CPPUNIT_ASSERT(st.store(createCookie("name5", "value5", "example.org", false,
for(auto c : cookies) { "/", false), 0));
CPPUNIT_ASSERT(st.store(c, 0));
}
HttpRequest httpRequest; HttpRequest httpRequest;

View File

@ -4,6 +4,7 @@
#include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/HelperMacros.h>
#include "TestUtil.h"
#include "prefs.h" #include "prefs.h"
#include "PiecedSegment.h" #include "PiecedSegment.h"
#include "Piece.h" #include "Piece.h"
@ -511,10 +512,11 @@ void HttpResponseTest::testRetrieveCookie()
CPPUNIT_ASSERT_EQUAL((size_t)2, st.size()); CPPUNIT_ASSERT_EQUAL((size_t)2, st.size());
std::vector<Cookie> cookies; auto cookies = std::vector<const Cookie*>{};
st.dumpCookie(std::back_inserter(cookies)); st.dumpCookie(std::back_inserter(cookies));
CPPUNIT_ASSERT_EQUAL(std::string("k2=v2"), cookies[0].toString()); std::sort(std::begin(cookies), std::end(cookies), CookieSorter());
CPPUNIT_ASSERT_EQUAL(std::string("k3=v3"), cookies[1].toString()); CPPUNIT_ASSERT_EQUAL(std::string("k2=v2"), cookies[0]->toString());
CPPUNIT_ASSERT_EQUAL(std::string("k3=v3"), cookies[1]->toString());
} }
void HttpResponseTest::testSupportsPersistentConnection() void HttpResponseTest::testSupportsPersistentConnection()

View File

@ -33,58 +33,58 @@ void NsCookieParserTest::testParse()
{ {
NsCookieParser parser; NsCookieParser parser;
time_t now = 0; time_t now = 0;
std::vector<Cookie> cookies = parser.parse(A2_TEST_DIR"/nscookietest.txt", now); auto cookies = parser.parse(A2_TEST_DIR"/nscookietest.txt", now);
CPPUNIT_ASSERT_EQUAL((size_t)5, cookies.size()); CPPUNIT_ASSERT_EQUAL((size_t)5, cookies.size());
Cookie c = cookies[0]; auto c = cookies[0].get();
CPPUNIT_ASSERT_EQUAL(std::string("JSESSIONID"), c.getName()); CPPUNIT_ASSERT_EQUAL(std::string("JSESSIONID"), c->getName());
CPPUNIT_ASSERT_EQUAL(std::string("123456789"), c.getValue()); CPPUNIT_ASSERT_EQUAL(std::string("123456789"), c->getValue());
CPPUNIT_ASSERT_EQUAL((time_t)INT32_MAX, c.getExpiryTime()); CPPUNIT_ASSERT_EQUAL((time_t)INT32_MAX, c->getExpiryTime());
CPPUNIT_ASSERT(c.getPersistent()); CPPUNIT_ASSERT(c->getPersistent());
CPPUNIT_ASSERT_EQUAL(std::string("localhost"), c.getDomain()); CPPUNIT_ASSERT_EQUAL(std::string("localhost"), c->getDomain());
CPPUNIT_ASSERT(c.getHostOnly()); CPPUNIT_ASSERT(c->getHostOnly());
CPPUNIT_ASSERT_EQUAL(std::string("/"), c.getPath()); CPPUNIT_ASSERT_EQUAL(std::string("/"), c->getPath());
CPPUNIT_ASSERT(c.getSecure()); CPPUNIT_ASSERT(c->getSecure());
c = cookies[1]; c = cookies[1].get();
CPPUNIT_ASSERT_EQUAL(std::string("user"), c.getName()); CPPUNIT_ASSERT_EQUAL(std::string("user"), c->getName());
CPPUNIT_ASSERT_EQUAL(std::string("me"), c.getValue()); CPPUNIT_ASSERT_EQUAL(std::string("me"), c->getValue());
CPPUNIT_ASSERT_EQUAL((time_t)1000, c.getExpiryTime()); CPPUNIT_ASSERT_EQUAL((time_t)1000, c->getExpiryTime());
CPPUNIT_ASSERT(c.getPersistent()); CPPUNIT_ASSERT(c->getPersistent());
CPPUNIT_ASSERT_EQUAL(std::string("expired"), c.getDomain()); CPPUNIT_ASSERT_EQUAL(std::string("expired"), c->getDomain());
CPPUNIT_ASSERT(c.getHostOnly()); CPPUNIT_ASSERT(c->getHostOnly());
CPPUNIT_ASSERT_EQUAL(std::string("/"), c.getPath()); CPPUNIT_ASSERT_EQUAL(std::string("/"), c->getPath());
CPPUNIT_ASSERT(!c.getSecure()); CPPUNIT_ASSERT(!c->getSecure());
c = cookies[2]; c = cookies[2].get();
CPPUNIT_ASSERT_EQUAL(std::string("passwd"), c.getName()); CPPUNIT_ASSERT_EQUAL(std::string("passwd"), c->getName());
CPPUNIT_ASSERT_EQUAL(std::string("secret"), c.getValue()); CPPUNIT_ASSERT_EQUAL(std::string("secret"), c->getValue());
CPPUNIT_ASSERT_EQUAL(std::numeric_limits<time_t>::max(), c.getExpiryTime()); CPPUNIT_ASSERT_EQUAL(std::numeric_limits<time_t>::max(), c->getExpiryTime());
CPPUNIT_ASSERT(!c.getPersistent()); CPPUNIT_ASSERT(!c->getPersistent());
CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), c.getDomain()); CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), c->getDomain());
CPPUNIT_ASSERT(c.getHostOnly()); CPPUNIT_ASSERT(c->getHostOnly());
CPPUNIT_ASSERT_EQUAL(std::string("/cgi-bin"), c.getPath()); CPPUNIT_ASSERT_EQUAL(std::string("/cgi-bin"), c->getPath());
CPPUNIT_ASSERT(!c.getSecure()); CPPUNIT_ASSERT(!c->getSecure());
c = cookies[3]; c = cookies[3].get();
CPPUNIT_ASSERT_EQUAL(std::string("TAX"), c.getName()); CPPUNIT_ASSERT_EQUAL(std::string("TAX"), c->getName());
CPPUNIT_ASSERT_EQUAL(std::string("1000"), c.getValue()); CPPUNIT_ASSERT_EQUAL(std::string("1000"), c->getValue());
CPPUNIT_ASSERT((time_t)INT32_MAX <= c.getExpiryTime()); CPPUNIT_ASSERT((time_t)INT32_MAX <= c->getExpiryTime());
CPPUNIT_ASSERT(c.getPersistent()); CPPUNIT_ASSERT(c->getPersistent());
CPPUNIT_ASSERT_EQUAL(std::string("overflow"), c.getDomain()); CPPUNIT_ASSERT_EQUAL(std::string("overflow"), c->getDomain());
CPPUNIT_ASSERT(c.getHostOnly()); CPPUNIT_ASSERT(c->getHostOnly());
CPPUNIT_ASSERT_EQUAL(std::string("/"), c.getPath()); CPPUNIT_ASSERT_EQUAL(std::string("/"), c->getPath());
CPPUNIT_ASSERT(!c.getSecure()); CPPUNIT_ASSERT(!c->getSecure());
c = cookies[4]; c = cookies[4].get();
CPPUNIT_ASSERT_EQUAL(std::string("novalue"), c.getName()); CPPUNIT_ASSERT_EQUAL(std::string("novalue"), c->getName());
CPPUNIT_ASSERT_EQUAL(std::string(""), c.getValue()); CPPUNIT_ASSERT_EQUAL(std::string(""), c->getValue());
CPPUNIT_ASSERT_EQUAL((time_t)INT32_MAX, c.getExpiryTime()); CPPUNIT_ASSERT_EQUAL((time_t)INT32_MAX, c->getExpiryTime());
CPPUNIT_ASSERT(c.getPersistent()); CPPUNIT_ASSERT(c->getPersistent());
CPPUNIT_ASSERT_EQUAL(std::string("example.org"), c.getDomain()); CPPUNIT_ASSERT_EQUAL(std::string("example.org"), c->getDomain());
CPPUNIT_ASSERT(!c.getHostOnly()); CPPUNIT_ASSERT(!c->getHostOnly());
CPPUNIT_ASSERT_EQUAL(std::string("/"), c.getPath()); CPPUNIT_ASSERT_EQUAL(std::string("/"), c->getPath());
CPPUNIT_ASSERT(!c.getSecure()); CPPUNIT_ASSERT(!c->getSecure());
} }
void NsCookieParserTest::testParse_fileNotFound() void NsCookieParserTest::testParse_fileNotFound()

View File

@ -35,55 +35,53 @@ CPPUNIT_TEST_SUITE_REGISTRATION(Sqlite3CookieParserTest);
void Sqlite3CookieParserTest::testMozParse() void Sqlite3CookieParserTest::testMozParse()
{ {
Sqlite3MozCookieParser parser(A2_TEST_DIR"/cookies.sqlite"); auto parser = Sqlite3MozCookieParser{A2_TEST_DIR"/cookies.sqlite"};
std::vector<Cookie> cookies; auto cookies = parser.parse();
parser.parse(cookies);
CPPUNIT_ASSERT_EQUAL((size_t)3, cookies.size()); CPPUNIT_ASSERT_EQUAL((size_t)3, cookies.size());
const Cookie& localhost = cookies[0]; auto& localhost = cookies[0];
CPPUNIT_ASSERT_EQUAL(std::string("JSESSIONID"), localhost.getName()); CPPUNIT_ASSERT_EQUAL(std::string("JSESSIONID"), localhost->getName());
CPPUNIT_ASSERT_EQUAL(std::string("123456789"), localhost.getValue()); CPPUNIT_ASSERT_EQUAL(std::string("123456789"), localhost->getValue());
CPPUNIT_ASSERT_EQUAL((time_t)INT32_MAX, localhost.getExpiryTime()); CPPUNIT_ASSERT_EQUAL((time_t)INT32_MAX, localhost->getExpiryTime());
CPPUNIT_ASSERT(localhost.getPersistent()); CPPUNIT_ASSERT(localhost->getPersistent());
CPPUNIT_ASSERT_EQUAL(std::string("localhost"), localhost.getDomain()); CPPUNIT_ASSERT_EQUAL(std::string("localhost"), localhost->getDomain());
CPPUNIT_ASSERT(localhost.getHostOnly()); CPPUNIT_ASSERT(localhost->getHostOnly());
CPPUNIT_ASSERT_EQUAL(std::string("/"), localhost.getPath()); CPPUNIT_ASSERT_EQUAL(std::string("/"), localhost->getPath());
CPPUNIT_ASSERT(localhost.getSecure()); CPPUNIT_ASSERT(localhost->getSecure());
CPPUNIT_ASSERT_EQUAL((time_t)3000, localhost.getLastAccessTime()); CPPUNIT_ASSERT_EQUAL((time_t)3000, localhost->getLastAccessTime());
CPPUNIT_ASSERT_EQUAL((time_t)3000, localhost.getCreationTime()); CPPUNIT_ASSERT_EQUAL((time_t)3000, localhost->getCreationTime());
const Cookie& nullValue = cookies[1]; auto& nullValue = cookies[1];
CPPUNIT_ASSERT_EQUAL(std::string("uid"), nullValue.getName()); CPPUNIT_ASSERT_EQUAL(std::string("uid"), nullValue->getName());
CPPUNIT_ASSERT_EQUAL(std::string(""), nullValue.getValue()); CPPUNIT_ASSERT_EQUAL(std::string(""), nullValue->getValue());
CPPUNIT_ASSERT_EQUAL((time_t)0, nullValue.getExpiryTime()); CPPUNIT_ASSERT_EQUAL((time_t)0, nullValue->getExpiryTime());
CPPUNIT_ASSERT(nullValue.getPersistent()); CPPUNIT_ASSERT(nullValue->getPersistent());
CPPUNIT_ASSERT_EQUAL(std::string("null_value.com"), nullValue.getDomain()); CPPUNIT_ASSERT_EQUAL(std::string("null_value.com"), nullValue->getDomain());
CPPUNIT_ASSERT(!nullValue.getHostOnly()); CPPUNIT_ASSERT(!nullValue->getHostOnly());
CPPUNIT_ASSERT_EQUAL(std::string("/path/to"), nullValue.getPath()); CPPUNIT_ASSERT_EQUAL(std::string("/path/to"), nullValue->getPath());
CPPUNIT_ASSERT(!nullValue.getSecure()); CPPUNIT_ASSERT(!nullValue->getSecure());
// See row id=3 has no name, so it is skipped. // See row id=3 has no name, so it is skipped.
const Cookie& overflowTime = cookies[2]; auto& overflowTime = cookies[2];
CPPUNIT_ASSERT_EQUAL(std::string("foo"), overflowTime.getName()); CPPUNIT_ASSERT_EQUAL(std::string("foo"), overflowTime->getName());
CPPUNIT_ASSERT_EQUAL(std::string("bar"), overflowTime.getValue()); CPPUNIT_ASSERT_EQUAL(std::string("bar"), overflowTime->getValue());
CPPUNIT_ASSERT((time_t)INT32_MAX <= overflowTime.getExpiryTime()); CPPUNIT_ASSERT((time_t)INT32_MAX <= overflowTime->getExpiryTime());
CPPUNIT_ASSERT(overflowTime.getPersistent()); CPPUNIT_ASSERT(overflowTime->getPersistent());
CPPUNIT_ASSERT_EQUAL(std::string("overflow.time_t.org"), CPPUNIT_ASSERT_EQUAL(std::string("overflow.time_t.org"),
overflowTime.getDomain()); overflowTime->getDomain());
CPPUNIT_ASSERT(!overflowTime.getHostOnly()); CPPUNIT_ASSERT(!overflowTime->getHostOnly());
CPPUNIT_ASSERT_EQUAL(std::string("/path/to"), overflowTime.getPath()); CPPUNIT_ASSERT_EQUAL(std::string("/path/to"), overflowTime->getPath());
CPPUNIT_ASSERT(!overflowTime.getSecure()); CPPUNIT_ASSERT(!overflowTime->getSecure());
// See row id=5 has bad path, so it is skipped. // See row id=5 has bad path, so it is skipped.
} }
void Sqlite3CookieParserTest::testMozParse_fileNotFound() void Sqlite3CookieParserTest::testMozParse_fileNotFound()
{ {
Sqlite3MozCookieParser parser("fileNotFound"); auto parser = Sqlite3MozCookieParser{"fileNotFound"};
try { try {
std::vector<Cookie> cookies; parser.parse();
parser.parse(cookies);
CPPUNIT_FAIL("exception must be thrown."); CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) { } catch(RecoverableException& e) {
// SUCCESS // SUCCESS
@ -95,10 +93,9 @@ void Sqlite3CookieParserTest::testMozParse_fileNotFound()
void Sqlite3CookieParserTest::testMozParse_badfile() void Sqlite3CookieParserTest::testMozParse_badfile()
{ {
Sqlite3MozCookieParser parser(A2_TEST_DIR"/badcookies.sqlite"); auto parser = Sqlite3MozCookieParser{A2_TEST_DIR"/badcookies.sqlite"};
try { try {
std::vector<Cookie> cookies; parser.parse();
parser.parse(cookies);
CPPUNIT_FAIL("exception must be thrown."); CPPUNIT_FAIL("exception must be thrown.");
} catch(RecoverableException& e) { } catch(RecoverableException& e) {
// SUCCESS // SUCCESS
@ -107,37 +104,37 @@ void Sqlite3CookieParserTest::testMozParse_badfile()
void Sqlite3CookieParserTest::testChromumParse() void Sqlite3CookieParserTest::testChromumParse()
{ {
Sqlite3ChromiumCookieParser parser(A2_TEST_DIR"/chromium_cookies.sqlite"); auto parser = Sqlite3ChromiumCookieParser
std::vector<Cookie> cookies; {A2_TEST_DIR"/chromium_cookies.sqlite"};
parser.parse(cookies); auto cookies = parser.parse();
CPPUNIT_ASSERT_EQUAL((size_t)3, cookies.size()); CPPUNIT_ASSERT_EQUAL((size_t)3, cookies.size());
const Cookie& sfnet = cookies[0]; auto& sfnet = cookies[0];
CPPUNIT_ASSERT_EQUAL(std::string("mykey"), sfnet.getName()); CPPUNIT_ASSERT_EQUAL(std::string("mykey"), sfnet->getName());
CPPUNIT_ASSERT_EQUAL(std::string("pass"), sfnet.getValue()); CPPUNIT_ASSERT_EQUAL(std::string("pass"), sfnet->getValue());
CPPUNIT_ASSERT_EQUAL((time_t)12345679, sfnet.getExpiryTime()); CPPUNIT_ASSERT_EQUAL((time_t)12345679, sfnet->getExpiryTime());
CPPUNIT_ASSERT(sfnet.getPersistent()); CPPUNIT_ASSERT(sfnet->getPersistent());
CPPUNIT_ASSERT_EQUAL(std::string("aria2.sourceforge.net"), CPPUNIT_ASSERT_EQUAL(std::string("aria2.sourceforge.net"),
sfnet.getDomain()); sfnet->getDomain());
CPPUNIT_ASSERT(!sfnet.getHostOnly()); CPPUNIT_ASSERT(!sfnet->getHostOnly());
CPPUNIT_ASSERT_EQUAL(std::string("/"), sfnet.getPath()); CPPUNIT_ASSERT_EQUAL(std::string("/"), sfnet->getPath());
CPPUNIT_ASSERT(!sfnet.getSecure()); CPPUNIT_ASSERT(!sfnet->getSecure());
const Cookie& sfjp = cookies[1]; auto& sfjp = cookies[1];
CPPUNIT_ASSERT_EQUAL(std::string("myseckey"), sfjp.getName()); CPPUNIT_ASSERT_EQUAL(std::string("myseckey"), sfjp->getName());
CPPUNIT_ASSERT_EQUAL(std::string("pass2"), sfjp.getValue()); CPPUNIT_ASSERT_EQUAL(std::string("pass2"), sfjp->getValue());
CPPUNIT_ASSERT_EQUAL((time_t)0, sfjp.getExpiryTime()); CPPUNIT_ASSERT_EQUAL((time_t)0, sfjp->getExpiryTime());
CPPUNIT_ASSERT(sfjp.getPersistent()); CPPUNIT_ASSERT(sfjp->getPersistent());
CPPUNIT_ASSERT_EQUAL(std::string("aria2.sourceforge.jp"), sfjp.getDomain()); CPPUNIT_ASSERT_EQUAL(std::string("aria2.sourceforge.jp"), sfjp->getDomain());
CPPUNIT_ASSERT(sfjp.getHostOnly()); CPPUNIT_ASSERT(sfjp->getHostOnly());
CPPUNIT_ASSERT_EQUAL(std::string("/profile"), sfjp.getPath()); CPPUNIT_ASSERT_EQUAL(std::string("/profile"), sfjp->getPath());
CPPUNIT_ASSERT(sfjp.getSecure()); CPPUNIT_ASSERT(sfjp->getSecure());
const Cookie& localnet = cookies[2]; auto& localnet = cookies[2];
CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), localnet.getDomain()); CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), localnet->getDomain());
CPPUNIT_ASSERT(sfjp.getHostOnly()); CPPUNIT_ASSERT(localnet->getHostOnly());
CPPUNIT_ASSERT_EQUAL((time_t)3000, localnet.getLastAccessTime()); CPPUNIT_ASSERT_EQUAL((time_t)3000, localnet->getLastAccessTime());
CPPUNIT_ASSERT_EQUAL((time_t)3000, localnet.getCreationTime()); CPPUNIT_ASSERT_EQUAL((time_t)3000, localnet->getCreationTime());
} }
} // namespace aria2 } // namespace aria2

View File

@ -50,7 +50,7 @@ std::string readFile(const std::string& path)
return ss.str(); return ss.str();
} }
Cookie createCookie std::unique_ptr<Cookie> createCookie
(const std::string& name, (const std::string& name,
const std::string& value, const std::string& value,
const std::string& domain, const std::string& domain,
@ -58,11 +58,11 @@ Cookie createCookie
const std::string& path, const std::string& path,
bool secure) bool secure)
{ {
return Cookie return make_unique<Cookie>
(name, value, 0, false, domain, hostOnly, path, secure, false, 0); (name, value, 0, false, domain, hostOnly, path, secure, false, 0);
} }
Cookie createCookie std::unique_ptr<Cookie> createCookie
(const std::string& name, (const std::string& name,
const std::string& value, const std::string& value,
time_t expiryTime, time_t expiryTime,
@ -71,7 +71,7 @@ Cookie createCookie
const std::string& path, const std::string& path,
bool secure) bool secure)
{ {
return Cookie return make_unique<Cookie>
(name, value, expiryTime, true, domain, hostOnly, path, secure, false, 0); (name, value, expiryTime, true, domain, hostOnly, path, secure, false, 0);
} }

View File

@ -21,17 +21,17 @@ std::string readFile(const std::string& path);
class CookieSorter { class CookieSorter {
public: public:
bool operator()(const Cookie& lhs, const Cookie& rhs) const bool operator()(const Cookie* lhs, const Cookie* rhs) const
{ {
if(lhs.getDomain() == rhs.getDomain()) { if(lhs->getDomain() == rhs->getDomain()) {
return lhs.getName() < rhs.getName(); return lhs->getName() < rhs->getName();
} else { } else {
return lhs.getDomain() < rhs.getDomain(); return lhs->getDomain() < rhs->getDomain();
} }
} }
}; };
Cookie createCookie std::unique_ptr<Cookie> createCookie
(const std::string& name, (const std::string& name,
const std::string& value, const std::string& value,
const std::string& domain, const std::string& domain,
@ -39,7 +39,7 @@ Cookie createCookie
const std::string& path, const std::string& path,
bool secure); bool secure);
Cookie createCookie std::unique_ptr<Cookie> createCookie
(const std::string& name, (const std::string& name,
const std::string& value, const std::string& value,
time_t expiryTime, time_t expiryTime,
@ -75,4 +75,17 @@ std::shared_ptr<RequestGroup> createRequestGroup(int32_t pieceLength,
std::shared_ptr<DownloadResult> createDownloadResult std::shared_ptr<DownloadResult> createDownloadResult
(error_code::Value result, const std::string& uri); (error_code::Value result, const std::string& uri);
namespace {
template<typename V, typename T>
bool derefFind(const V& v, const T& t)
{
for(auto i : v) {
if(*i == *t) {
return true;
}
}
return false;
}
} // namespace
} // namespace aria2 } // namespace aria2