From 5a223115e09cd568169fe2efd71d09689a980335 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Fri, 28 Jun 2013 00:25:06 +0900 Subject: [PATCH] Rewrite CookieStorage --- src/Cookie.cc | 71 ++--- src/Cookie.h | 24 +- src/CookieStorage.cc | 456 +++++++++++++++++++------------ src/CookieStorage.h | 221 ++++++++------- src/HttpRequest.cc | 12 +- src/NsCookieParser.cc | 47 ++-- src/NsCookieParser.h | 4 +- src/Sqlite3CookieParser.cc | 36 +-- src/Sqlite3CookieParser.h | 3 +- src/cookie_helper.cc | 48 ++-- src/cookie_helper.h | 6 +- test/CookieHelperTest.cc | 150 +++++----- test/CookieStorageTest.cc | 471 ++++++++++++++++++-------------- test/CookieTest.cc | 103 ++++--- test/HttpRequestTest.cc | 31 ++- test/HttpResponseTest.cc | 8 +- test/NsCookieParserTest.cc | 92 +++---- test/Sqlite3CookieParserTest.cc | 125 +++++---- test/TestUtil.cc | 8 +- test/TestUtil.h | 25 +- 20 files changed, 1059 insertions(+), 882 deletions(-) diff --git a/src/Cookie.cc b/src/Cookie.cc index 0628bc27..2c8b881e 100644 --- a/src/Cookie.cc +++ b/src/Cookie.cc @@ -43,23 +43,23 @@ namespace aria2 { Cookie::Cookie -(const std::string& name, - const std::string& value, +(std::string name, + std::string value, time_t expiryTime, bool persistent, - const std::string& domain, + std::string domain, bool hostOnly, - const std::string& path, + std::string path, bool secure, bool httpOnly, time_t creationTime): - name_(name), - value_(value), + name_(std::move(name)), + value_(std::move(value)), expiryTime_(expiryTime), persistent_(persistent), - domain_(domain), + domain_(std::move(domain)), hostOnly_(hostOnly), - path_(path), + path_(std::move(path)), secure_(secure), httpOnly_(httpOnly), creationTime_(creationTime), @@ -74,40 +74,6 @@ Cookie::Cookie(): creationTime_(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 s = name_; @@ -138,6 +104,11 @@ bool Cookie::operator==(const Cookie& cookie) const name_ == cookie.name_; } +bool Cookie::operator!=(const Cookie& cookie) const +{ + return !(*this == cookie); +} + bool Cookie::isExpired(time_t base) const { return persistent_ && base > expiryTime_; @@ -174,24 +145,24 @@ std::string Cookie::toNsCookieFormat() const 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 diff --git a/src/Cookie.h b/src/Cookie.h index e571225d..d97ddaeb 100644 --- a/src/Cookie.h +++ b/src/Cookie.h @@ -63,23 +63,17 @@ public: Cookie(); Cookie - (const std::string& name, - const std::string& value, + (std::string name, + std::string value, time_t expiryTime, bool persistent, - const std::string& domain, + std::string domain, bool hostOnly, - const std::string& path, + std::string path, bool secure, bool httpOnly, time_t creationTime); - Cookie(const Cookie& c); - - ~Cookie(); - - Cookie& operator=(const Cookie& c); - std::string toString() const; bool match @@ -88,6 +82,8 @@ public: bool operator==(const Cookie& cookie) const; + bool operator!=(const Cookie& cookie) const; + bool isExpired(time_t base) const; const std::string& getName() const @@ -95,7 +91,7 @@ public: return name_; } - void setName(const std::string& name); + void setName(std::string name); template void setName(InputIterator first, InputIterator last) @@ -108,7 +104,7 @@ public: return value_; } - void setValue(const std::string& value); + void setValue(std::string value); template void setValue(InputIterator first, InputIterator last) @@ -141,7 +137,7 @@ public: return domain_; } - void setDomain(const std::string& domain); + void setDomain(std::string domain); template void setDomain(InputIterator first, InputIterator last) @@ -164,7 +160,7 @@ public: return path_; } - void setPath(const std::string& path); + void setPath(std::string path); template void setPath(InputIterator first, InputIterator last) diff --git a/src/CookieStorage.cc b/src/CookieStorage.cc index e9353091..c21c4e6d 100644 --- a/src/CookieStorage.cc +++ b/src/CookieStorage.cc @@ -2,7 +2,7 @@ /* * 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 * it under the terms of the GNU General Public License as published by @@ -56,131 +56,196 @@ namespace aria2 { -CookieStorage::DomainEntry::DomainEntry(const std::string& domain) - : key_(util::isNumericHost(domain)?domain:cookie::reverseDomainLevel(domain)), - lastAccessTime_(0) +DomainNode::DomainNode(std::string label, DomainNode* parent) + : label_{std::move(label)}, parent_{parent}, lastAccessTime_{0}, + lruAccessTime_{0}, inLru_{false} {} -CookieStorage::DomainEntry::DomainEntry -(const DomainEntry& c) - : 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& out, +void DomainNode::findCookie +(std::vector& out, const std::string& requestHost, const std::string& requestPath, time_t now, bool secure) { - for(std::deque::iterator i = cookies_.begin(), - eoi = cookies_.end(); i != eoi; ++i) { - if((*i).match(requestHost, requestPath, now, secure)) { - (*i).setLastAccessTime(now); - out.push_back(*i); + if(cookies_) { + for(auto& c : *cookies_) { + if(c->match(requestHost, requestPath, now, secure)) { + c->setLastAccessTime(now); + out.push_back(c.get()); + } } } } -bool CookieStorage::DomainEntry::addCookie(const Cookie& cookie, time_t now) +bool DomainNode::addCookie(std::unique_ptr cookie, time_t now) { using namespace std::placeholders; setLastAccessTime(now); - std::deque::iterator i = - std::find(cookies_.begin(), cookies_.end(), cookie); - if(i == cookies_.end()) { - if(cookie.isExpired(now)) { + if(!cookies_) { + if(cookie->isExpired(now)) { return false; } else { - if(cookies_.size() >= CookieStorage::MAX_COOKIE_PER_DOMAIN) { - cookies_.erase - (std::remove_if(cookies_.begin(), cookies_.end(), + cookies_ = make_unique>>(); + cookies_->push_back(std::move(cookie)); + return true; + } + } + + auto i = std::find_if(std::begin(*cookies_), std::end(*cookies_), + [&](const std::unique_ptr& 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)), - cookies_.end()); - if(cookies_.size() >= CookieStorage::MAX_COOKIE_PER_DOMAIN) { - std::deque::iterator m = std::min_element - (cookies_.begin(), cookies_.end(), LeastRecentAccess()); - *m = cookie; + std::end(*cookies_)); + if(cookies_->size() >= CookieStorage::MAX_COOKIE_PER_DOMAIN) { + auto m = std::min_element(std::begin(*cookies_), std::end(*cookies_), + [](const std::unique_ptr& lhs, + const std::unique_ptr& rhs) + { + return lhs->getLastAccessTime() < + rhs->getLastAccessTime(); + }); + *m = std::move(cookie); } else { - cookies_.push_back(cookie); + cookies_->push_back(std::move(cookie)); } } else { - cookies_.push_back(cookie); + cookies_->push_back(std::move(cookie)); } return true; } - } else if(cookie.isExpired(now)) { - cookies_.erase(i); + } else if(cookie->isExpired(now)) { + cookies_->erase(i); return false; } else { - *i = cookie; + *i = std::move(cookie); 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::const_iterator i = cookies_.begin(), - eoi = cookies_.end(); i != eoi; ++i) { - std::string data = (*i).toNsCookieFormat(); - data += "\n"; - if(fp.write(data.data(), data.size()) != data.size()) { - return false; + if(cookies_) { + for(const auto& c : *cookies_) { + std::string data = c->toNsCookieFormat(); + data += "\n"; + if(fp.write(data.data(), data.size()) != data.size()) { + return false; + } } } 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 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("", nullptr)} +{} namespace { // See CookieStorageTest::testDomainIsFull() in CookieStorageTest.cc @@ -189,29 +254,86 @@ const size_t DOMAIN_EVICTION_TRIGGER = 2000; const double DOMAIN_EVICTION_RATE = 0.1; } // namespace -bool CookieStorage::store(const Cookie& cookie, time_t now) +namespace { +std::vector splitDomainLabel(const std::string& domain) { - if(domains_.size() >= DOMAIN_EVICTION_TRIGGER) { - std::vector > evictions(domains_.begin(), - domains_.end()); - std::sort(evictions.begin(), evictions.end(), - LeastRecentAccess()); - size_t delnum = (size_t)(evictions.size()*DOMAIN_EVICTION_RATE); - domains_.clear(); - domains_.insert(evictions.begin()+delnum, evictions.end()); - } - std::shared_ptr 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); + auto labels = std::vector{}; + if(util::isNumericHost(domain)) { + labels.push_back(domain); } else { - added = v->addCookie(cookie, now); - if(added) { - domains_.insert(i, v); + util::split(std::begin(domain), std::end(domain), + std::back_inserter(labels), '.'); + } + 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, 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(*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 @@ -220,20 +342,17 @@ bool CookieStorage::parseAndStore const std::string& defaultPath, time_t now) { - Cookie cookie; - if(cookie::parse(cookie, setCookieString, requestHost, defaultPath, now)) { - return store(cookie, now); - } else { - return false; - } + auto cookie = cookie::parse(setCookieString, requestHost, defaultPath, now); + return cookie && store(std::move(cookie), now); } +namespace { struct CookiePathDivider { - Cookie cookie_; + const Cookie* cookie_; 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()) { for(size_t i = 1, len = path.size(); i < len; ++i) { if(path[i] == '/' && path[i-1] != '/') { @@ -246,16 +365,17 @@ struct CookiePathDivider { } } }; +} // namespace namespace { class CookiePathDividerConverter { public: - CookiePathDivider operator()(const Cookie& cookie) const + CookiePathDivider operator()(const Cookie* cookie) const { return CookiePathDivider(cookie); } - Cookie operator()(const CookiePathDivider& cookiePathDivider) const + const Cookie* operator()(const CookiePathDivider& cookiePathDivider) const { return cookiePathDivider.cookie_; } @@ -280,80 +400,69 @@ public: // creation-times. return lhs.pathDepth_ > rhs.pathDepth_ || (!(rhs.pathDepth_ > lhs.pathDepth_) && - lhs.cookie_.getCreationTime() < rhs.cookie_.getCreationTime()); + lhs.cookie_->getCreationTime() < rhs.cookie_->getCreationTime()); } }; } // namespace -void CookieStorage::searchCookieByDomainSuffix -(std::vector& out, - const std::string& domain, - const std::string& requestHost, - const std::string& requestPath, - time_t now, bool secure) +namespace { +DomainNode* findNode(const std::string& domain, DomainNode* node) { - std::shared_ptr v(new DomainEntry(domain)); - DomainEntrySet::iterator i = domains_.lower_bound(v); - if(i != domains_.end() && *(*i) == *v) { - (*i)->setLastAccessTime(now); - (*i)->findCookie(out, requestHost, requestPath, now, secure); + auto labels = splitDomainLabel(domain); + for(auto i = labels.rbegin(), eoi = labels.rend(); i != eoi && node; ++i) { + node = node->findNext(*i); } + return node; } +} // namespace bool CookieStorage::contains(const Cookie& cookie) const { - std::shared_ptr v(new DomainEntry(cookie.getDomain())); - DomainEntrySet::iterator i = domains_.find(v); - if(i != domains_.end()) { - return (*i)->contains(cookie); - } else { - return false; - } + auto node = findNode(cookie.getDomain(), rootNode_.get()); + return node && node->contains(cookie); } -std::vector CookieStorage::criteriaFind +std::vector CookieStorage::criteriaFind (const std::string& requestHost, const std::string& requestPath, time_t now, bool secure) { - std::vector res; + auto res = std::vector{}; if(requestPath.empty()) { return res; } - if(util::isNumericHost(requestHost)) { - searchCookieByDomainSuffix - (res, requestHost, requestHost, requestPath, now, secure); - } else { - std::vector levels; - util::splitIter(requestHost.begin(), requestHost.end(), - std::back_inserter(levels), '.'); - std::string domain; - for(std::vector::const_reverse_iterator i = - levels.rbegin(), eoi = levels.rend(); - i != eoi; ++i, domain.insert(domain.begin(), '.')) { - domain.insert(domain.begin(), (*i).first, (*i).second); - searchCookieByDomainSuffix - (res, domain, requestHost, requestPath, now, secure); + auto labels = splitDomainLabel(requestHost); + auto node = rootNode_.get(); + for(auto i = labels.rbegin(), eoi = labels.rend(); i != eoi; ++i) { + auto nextNode = node->findNext(*i); + if(nextNode) { + nextNode->setLastAccessTime(now); + if(nextNode->getInLru()) { + updateLru(nextNode, now); + } + nextNode->findCookie(res, requestHost, requestPath, now, secure); + node = nextNode; + } else { + break; } } - std::vector divs; - std::transform(res.begin(), res.end(), std::back_inserter(divs), - CookiePathDividerConverter()); - std::sort(divs.begin(), divs.end(), OrderByPathDepthDesc()); - std::transform(divs.begin(), divs.end(), res.begin(), - CookiePathDividerConverter()); + auto divs = std::vector{}; + std::transform(std::begin(res), std::end(res), std::back_inserter(divs), + CookiePathDividerConverter{}); + std::sort(std::begin(divs), std::end(divs), OrderByPathDepthDesc{}); + std::transform(std::begin(divs), std::end(divs), std::begin(res), + CookiePathDividerConverter{}); return res; } size_t CookieStorage::size() const { - size_t numCookie = 0; - for(DomainEntrySet::iterator i = domains_.begin(), eoi = domains_.end(); - i != eoi; ++i) { - numCookie += (*i)->countCookie(); + size_t n = 0; + for(auto& p : lruTracker_) { + n += p.second->countCookie(); } - return numCookie; + return n; } 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 size_t headlen; { - BufferedFile fp(filename.c_str(), BufferedFile::READ); + BufferedFile fp{filename.c_str(), BufferedFile::READ}; if(!fp) { A2_LOG_ERROR(fmt("Failed to open cookie file %s", filename.c_str())); return false; @@ -371,25 +480,28 @@ bool CookieStorage::load(const std::string& filename, time_t now) try { if(headlen == 16 && memcmp(header, "SQLite format 3\0", 16) == 0) { #ifdef HAVE_SQLITE3 - std::vector cookies; 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) { A2_LOG_INFO_EX(EX_EXCEPTION_CAUGHT, e); A2_LOG_INFO("This does not look like Firefox3 cookie file." " Retrying, assuming it is Chromium cookie file."); // 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 throw DL_ABORT_EX ("Cannot read SQLite3 database because SQLite3 support is disabled by" " configuration."); #endif // !HAVE_SQLITE3 } else { - std::vector cookies = NsCookieParser().parse(filename, now); - storeCookies(cookies.begin(), cookies.end(), now); + auto cookies = NsCookieParser().parse(filename, now); + storeCookies(std::make_move_iterator(std::begin(cookies)), + std::make_move_iterator(std::end(cookies)), now); } return true; } catch(RecoverableException& e) { @@ -400,17 +512,16 @@ bool CookieStorage::load(const std::string& filename, time_t now) bool CookieStorage::saveNsFormat(const std::string& filename) { - std::string tempfilename = filename; + auto tempfilename = filename; tempfilename += "__temp"; { - BufferedFile fp(tempfilename.c_str(), BufferedFile::WRITE); + BufferedFile fp{tempfilename.c_str(), BufferedFile::WRITE}; if(!fp) { A2_LOG_ERROR(fmt("Cannot create cookie file %s", filename.c_str())); return false; } - for(DomainEntrySet::iterator i = domains_.begin(), eoi = domains_.end(); - i != eoi; ++i) { - if(!(*i)->writeCookie(fp)) { + for(auto& p : lruTracker_) { + if(!p.second->writeCookie(fp)) { A2_LOG_ERROR(fmt("Failed to save cookies to %s", filename.c_str())); return false; } @@ -431,14 +542,3 @@ bool CookieStorage::saveNsFormat(const std::string& filename) } } // namespace aria2 - -namespace std { -template<> -void swap -(aria2::CookieStorage::DomainEntry& a, - aria2::CookieStorage::DomainEntry& b) -{ - a.swap(b); -} -} // namespace std - diff --git a/src/CookieStorage.h b/src/CookieStorage.h index 530e0d62..de3eaebc 100644 --- a/src/CookieStorage.h +++ b/src/CookieStorage.h @@ -2,7 +2,7 @@ /* * 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 * it under the terms of the GNU General Public License as published by @@ -42,6 +42,7 @@ #include #include #include +#include #include "a2time.h" #include "Cookie.h" @@ -51,89 +52,97 @@ namespace aria2 { 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& 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, 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 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 + 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>> 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> next_; +}; + class CookieStorage { public: - 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 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& 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 - 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: - typedef std::set, - DerefLess > > DomainEntrySet; - DomainEntrySet domains_; + // typedef std::set, + // DerefLess > > DomainEntrySet; + // DomainEntrySet domains_; - template - void storeCookies(InputIterator first, InputIterator last, time_t now) - { - for(; first != last; ++first) { - store(*first, now); - } - } public: CookieStorage(); - ~CookieStorage(); - // Returns true if cookie is stored or updated existing cookie. // Returns false if cookie is expired. now is used as last access // time. - bool store(const Cookie& cookie, time_t now); + bool store(std::unique_ptr cookie, time_t now); // Returns true if cookie is stored or updated existing cookie. // 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. // Matched cookies' lastAccess_ property is updated. - std::vector criteriaFind(const std::string& requestHost, - const std::string& requestPath, - time_t now, bool secure); + std::vector + criteriaFind(const std::string& requestHost, + const std::string& requestPath, + time_t now, bool secure); // Loads Cookies from file denoted by filename. If compiled with // libsqlite3, this method automatically detects the specified file @@ -170,36 +180,51 @@ public: // satisfies. 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& out, - const std::string& domain, - const std::string& requestHost, - const std::string& requestPath, - time_t now, bool secure); - template OutputIterator dumpCookie(OutputIterator out) const { - for(DomainEntrySet::iterator i = domains_.begin(), eoi = domains_.end(); - i != eoi; ++i) { - out = (*i)->dumpCookie(out); + for(auto& i : lruTracker_) { + out = i.second->dumpCookie(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 + 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 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> lruTracker_; +}; } // namespace aria2 -namespace std { -template<> -void swap -(aria2::CookieStorage::DomainEntry& a, - aria2::CookieStorage::DomainEntry& b); -} // namespace std - #endif // D_COOKIE_STORAGE_H diff --git a/src/HttpRequest.cc b/src/HttpRequest.cc index 3e7d1a4b..33469813 100644 --- a/src/HttpRequest.cc +++ b/src/HttpRequest.cc @@ -234,13 +234,11 @@ std::string HttpRequest::createRequest() std::string cookiesValue; std::string path = getDir(); path += getFile(); - std::vector cookies = - cookieStorage_->criteriaFind(getHost(), path, - Time().getTime(), - getProtocol() == "https"); - for(std::vector::const_iterator itr = cookies.begin(), - eoi = cookies.end(); itr != eoi; ++itr) { - cookiesValue += (*itr).toString(); + auto cookies = cookieStorage_->criteriaFind(getHost(), path, + Time().getTime(), + getProtocol() == "https"); + for(auto c : cookies) { + cookiesValue += c->toString(); cookiesValue += ";"; } if(!cookiesValue.empty()) { diff --git a/src/NsCookieParser.cc b/src/NsCookieParser.cc index 61672d18..e107a295 100644 --- a/src/NsCookieParser.cc +++ b/src/NsCookieParser.cc @@ -54,58 +54,59 @@ NsCookieParser::NsCookieParser() {} NsCookieParser::~NsCookieParser() {} namespace { -bool parseNsCookie -(Cookie& cookie, const std::string& cookieStr, time_t creationTime) +std::unique_ptr parseNsCookie +(const std::string& cookieStr, time_t creationTime) { std::vector vs; util::splitIter(cookieStr.begin(), cookieStr.end(), std::back_inserter(vs), '\t', true); if(vs.size() < 6) { - return false; + return std::unique_ptr{}; } vs[0].first = util::lstripIter(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)) { - return false; + return std::unique_ptr{}; } int64_t expiryTime; if(!util::parseLLIntNoThrow(expiryTime, std::string(vs[4].first, vs[4].second))) { - return false; + return std::unique_ptr{}; } if(std::numeric_limits::max() < expiryTime) { expiryTime = std::numeric_limits::max(); } else if(std::numeric_limits::min() > expiryTime) { expiryTime = std::numeric_limits::min(); } - cookie.setName(vs[5].first, vs[5].second); + auto cookie = make_unique(); + cookie->setName(vs[5].first, vs[5].second); if(vs.size() >= 7) { - cookie.setValue(vs[6].first, vs[6].second); + cookie->setValue(vs[6].first, vs[6].second); } else { - cookie.setValue(A2STR::NIL.begin(), A2STR::NIL.end()); + cookie->setValue(""); } - cookie.setExpiryTime(expiryTime == 0? + cookie->setExpiryTime(expiryTime == 0? std::numeric_limits::max():expiryTime); - // aria2 treats expiryTime == 0 means session cookie. - cookie.setPersistent(expiryTime != 0); - cookie.setDomain(vs[0].first, vs[0].second); - cookie.setHostOnly(util::isNumericHost(cookie.getDomain()) || + // aria2 treats expiryTime == 0 means session cookie-> + cookie->setPersistent(expiryTime != 0); + cookie->setDomain(vs[0].first, vs[0].second); + cookie->setHostOnly(util::isNumericHost(cookie->getDomain()) || !util::streq(vs[1].first, vs[1].second, "TRUE")); - cookie.setPath(vs[2].first, vs[2].second); - cookie.setSecure(util::streq(vs[3].first, vs[3].second, "TRUE")); - cookie.setCreationTime(creationTime); - return true; + cookie->setPath(vs[2].first, vs[2].second); + cookie->setSecure(util::streq(vs[3].first, vs[3].second, "TRUE")); + cookie->setCreationTime(creationTime); + return cookie; } } // namespace -std::vector NsCookieParser::parse +std::vector> NsCookieParser::parse (const std::string& filename, time_t creationTime) { - BufferedFile fp(filename.c_str(), BufferedFile::READ); + BufferedFile fp{filename.c_str(), BufferedFile::READ}; if(!fp) { throw DL_ABORT_EX(fmt("Failed to open file %s", filename.c_str())); } - std::vector cookies; + std::vector> cookies; while(1) { std::string line = fp.getLine(); if(line.empty()) { @@ -120,9 +121,9 @@ std::vector NsCookieParser::parse if(line[0] == '#') { continue; } - Cookie c; - if(parseNsCookie(c, line, creationTime)) { - cookies.push_back(c); + auto c = parseNsCookie(line, creationTime); + if(c) { + cookies.push_back(std::move(c)); } } return cookies; diff --git a/src/NsCookieParser.h b/src/NsCookieParser.h index 5515692f..19668ed2 100644 --- a/src/NsCookieParser.h +++ b/src/NsCookieParser.h @@ -39,6 +39,7 @@ #include #include +#include namespace aria2 { @@ -50,7 +51,8 @@ public: ~NsCookieParser(); - std::vector parse(const std::string& filename, time_t creationTime); + std::vector> parse + (const std::string& filename, time_t creationTime); }; } // namespace aria2 diff --git a/src/Sqlite3CookieParser.cc b/src/Sqlite3CookieParser.cc index ed89aef7..08c2b836 100644 --- a/src/Sqlite3CookieParser.cc +++ b/src/Sqlite3CookieParser.cc @@ -102,8 +102,8 @@ int cookieRowMapper(void* data, int columns, char** values, char** names) if(columns != 7 || !values[0] || !values[1] || !values[4]) { return 0; } - std::vector& cookies = - *reinterpret_cast*>(data); + std::vector>& cookies = + *reinterpret_cast>*>(data); size_t val0len = strlen(values[0]); std::string cookieDomain (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])) { return 0; } - Cookie c(cookieName, - toString(values[5]), // value - expiryTime, - true, // persistent - cookieDomain, - util::isNumericHost(cookieDomain) || - (values[0] && values[0][0] != '.'), // hostOnly - cookiePath, - values[2] && strcmp(values[2], "1") == 0, //secure - false, - lastAccessTime // creation time. Set this later. - ); - cookies.push_back(c); + cookies.push_back(make_unique + (std::move(cookieName), + toString(values[5]), // value + expiryTime, + true, // persistent + std::move(cookieDomain), + util::isNumericHost(cookieDomain) || + (values[0] && values[0][0] != '.'), // hostOnly + std::move(cookiePath), + values[2] && strcmp(values[2], "1") == 0, //secure + false, + lastAccessTime // creation time. Set this later. + )); return 0; } } // namespace -void Sqlite3CookieParser::parse(std::vector& cookies) +std::vector> Sqlite3CookieParser::parse() { if(!db_) { throw DL_ABORT_EX(fmt("SQLite3 database is not opened.")); } - std::vector tcookies; + auto tcookies = std::vector>{}; char* sqlite3ErrMsg = 0; int ret = sqlite3_exec(db_, getQuery(), cookieRowMapper, &tcookies, &sqlite3ErrMsg); @@ -157,7 +157,7 @@ void Sqlite3CookieParser::parse(std::vector& cookies) throw DL_ABORT_EX (fmt("Failed to read SQLite3 database: %s", errMsg.c_str())); } - cookies.swap(tcookies); + return tcookies; } } // namespace aria2 diff --git a/src/Sqlite3CookieParser.h b/src/Sqlite3CookieParser.h index 24b590df..b83a2175 100644 --- a/src/Sqlite3CookieParser.h +++ b/src/Sqlite3CookieParser.h @@ -39,6 +39,7 @@ #include #include +#include #include @@ -55,7 +56,7 @@ public: // Loads cookies from sqlite3 database and stores them in cookies. // When loading is successful, cookies stored in cookies initially // are removed. Otherwise, the content of cookies is unchanged. - void parse(std::vector& cookies); + std::vector> parse(); protected: // Returns SQL select statement to get 1 record of cookie. The sql // must return 6 columns in the following order: host, path, diff --git a/src/cookie_helper.cc b/src/cookie_helper.cc index bec1dba0..58a4c69c 100644 --- a/src/cookie_helper.cc +++ b/src/cookie_helper.cc @@ -216,9 +216,8 @@ bool parseDate return time != -1; } -bool parse -(Cookie& cookie, - const std::string& cookieStr, +std::unique_ptr parse +(const std::string& cookieStr, const std::string& requestHost, const std::string& defaultPath, time_t creationTime) @@ -231,13 +230,13 @@ bool parse std::string::const_iterator eq = cookieStr.begin(); for(; eq != nvEnd && *eq != '='; ++eq); if(eq == nvEnd) { - return false; + return std::unique_ptr{}; } std::pair p = util::stripIter(cookieStr.begin(), eq); if(p.first == p.second) { - return false; + return std::unique_ptr{}; } Scip cookieName(p.first, p.second); p = util::stripIter(eq+1, nvEnd); @@ -276,18 +275,18 @@ bool parse if(parseDate(expiryTime, attrp.first, attrp.second)) { foundExpires = true; } else { - return false; + return std::unique_ptr{}; } } else if(util::strieq(p.first, p.second, "max-age")) { if(attrp.first == attrp.second || (!in(static_cast(*attrp.first), 0x30u, 0x39u) && *attrp.first != '-')) { - return false; + return std::unique_ptr{}; } for(std::string::const_iterator s = attrp.first+1, eos = attrp.second; s != eos; ++s) { if(!in(static_cast(*s), 0x30u, 0x39u)) { - return false; + return std::unique_ptr{}; } } int64_t delta; @@ -306,17 +305,17 @@ bool parse } } } else { - return false; + return std::unique_ptr{}; } } else if(util::strieq(p.first, p.second, "domain")) { if(attrp.first == attrp.second) { - return false; + return std::unique_ptr{}; } std::string::const_iterator noDot = attrp.first; std::string::const_iterator end = attrp.second; for(; noDot != end && *noDot == '.'; ++noDot); if(noDot == end) { - return false; + return std::unique_ptr{}; } cookieDomain.assign(noDot, end); } else if(util::strieq(p.first, p.second, "path")) { @@ -349,26 +348,27 @@ bool parse } else if(domainMatch(canonicalizedHost, cookieDomain)) { hostOnly = util::isNumericHost(canonicalizedHost); } else { - return false; + return std::unique_ptr{}; } if(cookiePath.empty()) { cookiePath = defaultPath; } - cookie.setName(cookieName.first, cookieName.second); - cookie.setValue(cookieValue.first, cookieValue.second); - cookie.setExpiryTime(expiryTime); - cookie.setPersistent(persistent); - cookie.setDomain(cookieDomain); - cookie.setHostOnly(hostOnly); - cookie.setPath(cookiePath); - cookie.setSecure(secure); - cookie.setHttpOnly(httpOnly); - cookie.setCreationTime(creationTime); - cookie.setLastAccessTime(creationTime); + auto cookie = make_unique(); + cookie->setName(cookieName.first, cookieName.second); + cookie->setValue(cookieValue.first, cookieValue.second); + cookie->setExpiryTime(expiryTime); + cookie->setPersistent(persistent); + cookie->setDomain(std::move(cookieDomain)); + cookie->setHostOnly(hostOnly); + cookie->setPath(std::move(cookiePath)); + cookie->setSecure(secure); + cookie->setHttpOnly(httpOnly); + cookie->setCreationTime(creationTime); + cookie->setLastAccessTime(creationTime); - return true; + return cookie; } bool goodPath diff --git a/src/cookie_helper.h b/src/cookie_helper.h index 7e481f53..79264b09 100644 --- a/src/cookie_helper.h +++ b/src/cookie_helper.h @@ -38,6 +38,7 @@ #include "common.h" #include +#include #include "a2time.h" @@ -52,9 +53,8 @@ bool parseDate std::string::const_iterator first, std::string::const_iterator last); -bool parse -(Cookie& cookie, - const std::string& cookieStr, +std::unique_ptr parse +(const std::string& cookieStr, const std::string& requestHost, const std::string& defaultPath, time_t creationTime); diff --git a/test/CookieHelperTest.cc b/test/CookieHelperTest.cc index 7574b3fe..a4c46612 100644 --- a/test/CookieHelperTest.cc +++ b/test/CookieHelperTest.cc @@ -88,145 +88,145 @@ void CookieHelperTest::testParse() { std::string str = "ID=123456789; expires=Sun, 10-Jun-2007 11:00:00 GMT;" "path=/foo; domain=localhost; secure;httpOnly "; - Cookie c; - CPPUNIT_ASSERT(cookie::parse(c, str, "localhost", "/", creationDate)); - CPPUNIT_ASSERT_EQUAL(std::string("ID"), c.getName()); - CPPUNIT_ASSERT_EQUAL(std::string("123456789"), c.getValue()); - CPPUNIT_ASSERT_EQUAL((time_t)1181473200, c.getExpiryTime()); - CPPUNIT_ASSERT(c.getPersistent()); - CPPUNIT_ASSERT_EQUAL(std::string("localhost"), c.getDomain()); - CPPUNIT_ASSERT(!c.getHostOnly()); - CPPUNIT_ASSERT_EQUAL(std::string("/foo"), c.getPath()); - CPPUNIT_ASSERT(c.getSecure()); - CPPUNIT_ASSERT(c.getHttpOnly()); - CPPUNIT_ASSERT_EQUAL((time_t)141, c.getCreationTime()); - CPPUNIT_ASSERT_EQUAL((time_t)141, c.getLastAccessTime()); + auto c = cookie::parse(str, "localhost", "/", creationDate); + CPPUNIT_ASSERT(c); + CPPUNIT_ASSERT_EQUAL(std::string("ID"), c->getName()); + CPPUNIT_ASSERT_EQUAL(std::string("123456789"), c->getValue()); + CPPUNIT_ASSERT_EQUAL((time_t)1181473200, c->getExpiryTime()); + CPPUNIT_ASSERT(c->getPersistent()); + CPPUNIT_ASSERT_EQUAL(std::string("localhost"), c->getDomain()); + CPPUNIT_ASSERT(!c->getHostOnly()); + CPPUNIT_ASSERT_EQUAL(std::string("/foo"), c->getPath()); + CPPUNIT_ASSERT(c->getSecure()); + CPPUNIT_ASSERT(c->getHttpOnly()); + CPPUNIT_ASSERT_EQUAL((time_t)141, c->getCreationTime()); + CPPUNIT_ASSERT_EQUAL((time_t)141, c->getLastAccessTime()); } { std::string str = "id=; Max-Age=0;"; - Cookie c; - CPPUNIT_ASSERT(cookie::parse(c, str, "localhost", "/", creationDate)); - CPPUNIT_ASSERT_EQUAL(std::string("id"), c.getName()); - CPPUNIT_ASSERT_EQUAL((time_t)0, c.getExpiryTime()); - CPPUNIT_ASSERT(c.getPersistent()); - CPPUNIT_ASSERT_EQUAL(std::string("localhost"), c.getDomain()); - CPPUNIT_ASSERT(c.getHostOnly()); - CPPUNIT_ASSERT_EQUAL(std::string("/"), c.getPath()); - CPPUNIT_ASSERT(!c.getSecure()); - CPPUNIT_ASSERT(!c.getHttpOnly()); + auto c = cookie::parse(str, "localhost", "/", creationDate); + CPPUNIT_ASSERT(c); + CPPUNIT_ASSERT_EQUAL(std::string("id"), c->getName()); + CPPUNIT_ASSERT_EQUAL((time_t)0, c->getExpiryTime()); + CPPUNIT_ASSERT(c->getPersistent()); + CPPUNIT_ASSERT_EQUAL(std::string("localhost"), c->getDomain()); + CPPUNIT_ASSERT(c->getHostOnly()); + CPPUNIT_ASSERT_EQUAL(std::string("/"), c->getPath()); + CPPUNIT_ASSERT(!c->getSecure()); + CPPUNIT_ASSERT(!c->getHttpOnly()); } { std::string str = "id=; Max-Age=-100;"; - Cookie c; - CPPUNIT_ASSERT(cookie::parse(c, str, "localhost", "/", creationDate)); - CPPUNIT_ASSERT_EQUAL((time_t)0, c.getExpiryTime()); - CPPUNIT_ASSERT(c.getPersistent()); + auto c = cookie::parse(str, "localhost", "/", creationDate); + CPPUNIT_ASSERT(c); + CPPUNIT_ASSERT_EQUAL((time_t)0, c->getExpiryTime()); + CPPUNIT_ASSERT(c->getPersistent()); } { std::string str = "id=; Max-Age=100;"; - Cookie c; - CPPUNIT_ASSERT(cookie::parse(c, str, "localhost", "/", creationDate)); - CPPUNIT_ASSERT_EQUAL((time_t)creationDate+100, c.getExpiryTime()); - CPPUNIT_ASSERT(c.getPersistent()); + auto c = cookie::parse(str, "localhost", "/", creationDate); + CPPUNIT_ASSERT(c); + CPPUNIT_ASSERT_EQUAL((time_t)creationDate+100, c->getExpiryTime()); + CPPUNIT_ASSERT(c->getPersistent()); } { std::string str = "id=; Max-Age=9223372036854775807;"; - Cookie c; - CPPUNIT_ASSERT(cookie::parse(c, str, "localhost", "/", creationDate)); - CPPUNIT_ASSERT_EQUAL(std::numeric_limits::max(), c.getExpiryTime()); - CPPUNIT_ASSERT(c.getPersistent()); + auto c = cookie::parse(str, "localhost", "/", creationDate); + CPPUNIT_ASSERT(c); + CPPUNIT_ASSERT_EQUAL(std::numeric_limits::max(), + c->getExpiryTime()); + CPPUNIT_ASSERT(c->getPersistent()); } { std::string str = "id=; Max-Age=X;"; - Cookie c; - CPPUNIT_ASSERT(!cookie::parse(c, str, "localhost", "/", creationDate)); + CPPUNIT_ASSERT(!cookie::parse(str, "localhost", "/", creationDate)); } { std::string str = "id=; Max-Age=100garbage;"; - Cookie c; - CPPUNIT_ASSERT(!cookie::parse(c, str, "localhost", "/", creationDate)); + CPPUNIT_ASSERT(!cookie::parse(str, "localhost", "/", creationDate)); } { std::string str = "id=; Max-Age=100;expires=Sun, 10-Jun-2007 11:00:00 GMT;"; - Cookie c; - CPPUNIT_ASSERT(cookie::parse(c, str, "localhost", "/", creationDate)); - CPPUNIT_ASSERT_EQUAL((time_t)creationDate+100, c.getExpiryTime()); - CPPUNIT_ASSERT(c.getPersistent()); + auto c = cookie::parse(str, "localhost", "/", creationDate); + CPPUNIT_ASSERT(c); + CPPUNIT_ASSERT_EQUAL((time_t)creationDate+100, c->getExpiryTime()); + CPPUNIT_ASSERT(c->getPersistent()); } { // Cookie data cannot be parsed. std::string str = "id=; expires=2007-10-01 11:00:00 GMT;"; - Cookie c; - CPPUNIT_ASSERT(!cookie::parse(c, str, "localhost", "/", creationDate)); + CPPUNIT_ASSERT(!cookie::parse(str, "localhost", "/", creationDate)); } { std::string str = "id=;"; - Cookie c; - CPPUNIT_ASSERT(cookie::parse(c, str, "localhost", "/", creationDate)); - CPPUNIT_ASSERT(!c.getPersistent()); + auto c = cookie::parse(str, "localhost", "/", creationDate); + CPPUNIT_ASSERT(c); + CPPUNIT_ASSERT(!c->getPersistent()); } { std::string str = "id=; path=abc"; - Cookie c; - CPPUNIT_ASSERT(cookie::parse(c, str, "localhost", "/", creationDate)); - CPPUNIT_ASSERT_EQUAL(std::string("/"), c.getPath()); + auto c = cookie::parse(str, "localhost", "/", creationDate); + CPPUNIT_ASSERT(c); + CPPUNIT_ASSERT_EQUAL(std::string("/"), c->getPath()); } { std::string str = "id=; domain=.example.org"; - Cookie c; - CPPUNIT_ASSERT(cookie::parse(c, str, "www.example.org", "/",creationDate)); + CPPUNIT_ASSERT(cookie::parse(str, "www.example.org", "/",creationDate)); } { // Fails because request host does not domain-match with cookie // domain. std::string str = "id=; domain=www.example.org"; - Cookie c; - CPPUNIT_ASSERT(!cookie::parse(c, str, "example.org", "/", creationDate)); + CPPUNIT_ASSERT(!cookie::parse(str, "example.org", "/", creationDate)); } { std::string str = "id=; domain=."; - Cookie c; - CPPUNIT_ASSERT(!cookie::parse(c, str, "localhost", "/",creationDate)); + CPPUNIT_ASSERT(!cookie::parse(str, "localhost", "/",creationDate)); } { std::string str = ""; - Cookie c; - CPPUNIT_ASSERT(!cookie::parse(c, str, "localhost", "/",creationDate)); + CPPUNIT_ASSERT(!cookie::parse(str, "localhost", "/",creationDate)); } { std::string str = "="; - Cookie c; - CPPUNIT_ASSERT(!cookie::parse(c, str, "localhost", "/",creationDate)); + CPPUNIT_ASSERT(!cookie::parse(str, "localhost", "/",creationDate)); } { // Use domain last time seen. std::string str = "id=;domain=a.example.org;domain=.example.org"; - Cookie c; - CPPUNIT_ASSERT(cookie::parse(c, str, "b.example.org", "/",creationDate)); - CPPUNIT_ASSERT_EQUAL(std::string("example.org"), c.getDomain()); + auto c = cookie::parse(str, "b.example.org", "/",creationDate); + CPPUNIT_ASSERT(c); + CPPUNIT_ASSERT_EQUAL(std::string("example.org"), c->getDomain()); } { // numeric host std::string str = "id=;"; - Cookie c; - CPPUNIT_ASSERT(cookie::parse(c, str, "192.168.0.1", "/",creationDate)); - CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), c.getDomain()); - CPPUNIT_ASSERT(c.getHostOnly()); + auto c = cookie::parse(str, "192.168.0.1", "/",creationDate); + CPPUNIT_ASSERT(c); + CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), c->getDomain()); + CPPUNIT_ASSERT(c->getHostOnly()); } { // numeric host std::string str = "id=; domain=192.168.0.1"; - Cookie c; - CPPUNIT_ASSERT(cookie::parse(c, str, "192.168.0.1", "/",creationDate)); - CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), c.getDomain()); - CPPUNIT_ASSERT(c.getHostOnly()); + auto c = cookie::parse(str, "192.168.0.1", "/",creationDate); + CPPUNIT_ASSERT(c); + CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), c->getDomain()); + CPPUNIT_ASSERT(c->getHostOnly()); } { // DQUOTE around cookie-value std::string str = "id=\"foo\";"; - Cookie c; - CPPUNIT_ASSERT(cookie::parse(c, str, "localhost", "/", creationDate)); - CPPUNIT_ASSERT_EQUAL(std::string("foo"), c.getValue()); + auto c = cookie::parse(str, "localhost", "/", creationDate); + CPPUNIT_ASSERT(c); + 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()); } } diff --git a/test/CookieStorageTest.cc b/test/CookieStorageTest.cc index 4740f969..e88332b8 100644 --- a/test/CookieStorageTest.cc +++ b/test/CookieStorageTest.cc @@ -12,6 +12,7 @@ #include "RecoverableException.h" #include "File.h" #include "TestUtil.h" +#include "TimerA2.h" namespace aria2 { @@ -29,14 +30,13 @@ class CookieStorageTest:public CppUnit::TestFixture { CPPUNIT_TEST(testSaveNsFormat_fail); CPPUNIT_TEST(testCookieIsFull); CPPUNIT_TEST(testDomainIsFull); + CPPUNIT_TEST(testEviction); CPPUNIT_TEST_SUITE_END(); public: void setUp() {} void tearDown() {} - void dumpCookie(std::vector& cookies, const CookieStorage& cs); - void testStore(); void testParseAndStore(); void testCriteriaFind(); @@ -48,56 +48,67 @@ public: void testSaveNsFormat_fail(); void testCookieIsFull(); void testDomainIsFull(); + void testEviction(); }; CPPUNIT_TEST_SUITE_REGISTRATION(CookieStorageTest); -void CookieStorageTest::dumpCookie -(std::vector& cookies, const CookieStorage& st) +namespace { +std::vector dumpCookie(const CookieStorage& st) { - st.dumpCookie(std::back_inserter(cookies)); - std::sort(cookies.begin(), cookies.end(), CookieSorter()); + auto res = std::vector{}; + st.dumpCookie(std::back_inserter(res)); + std::sort(res.begin(), res.end(), CookieSorter()); + return res; } +} // namespace void CookieStorageTest::testStore() { time_t now = 1000; - CookieStorage st; - Cookie goodCookie(createCookie("k", "v", "localhost", true, "/", false)); - CPPUNIT_ASSERT(st.store(goodCookie, now)); + auto st = CookieStorage{}; + auto goodCookie = []() { + return createCookie("k", "v", "localhost", true, "/", false); + }; + CPPUNIT_ASSERT(st.store(goodCookie(), now)); 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)); - CPPUNIT_ASSERT(st.store(anotherCookie, now)); + auto anotherCookie = []() { + return createCookie("k", "v", "mirror", true, "/", true); + }; + CPPUNIT_ASSERT(st.store(anotherCookie(), now)); CPPUNIT_ASSERT_EQUAL((size_t)2, st.size()); - CPPUNIT_ASSERT(st.contains(anotherCookie)); - CPPUNIT_ASSERT(st.contains(goodCookie)); + CPPUNIT_ASSERT(st.contains(*anotherCookie())); + CPPUNIT_ASSERT(st.contains(*goodCookie())); - Cookie updateGoodCookie(createCookie("k", "v2", "localhost", true, - "/", false)); - CPPUNIT_ASSERT(st.store(updateGoodCookie, now)); + auto updateGoodCookie = []() { + return createCookie("k", "v2", "localhost", true, "/", false); + }; + CPPUNIT_ASSERT(st.store(updateGoodCookie(), now)); CPPUNIT_ASSERT_EQUAL((size_t)2, st.size()); - CPPUNIT_ASSERT(st.contains(updateGoodCookie)); - CPPUNIT_ASSERT(st.contains(anotherCookie)); + CPPUNIT_ASSERT(st.contains(*updateGoodCookie())); + CPPUNIT_ASSERT(st.contains(*anotherCookie())); - Cookie expireGoodCookie(createCookie("k", "v3", 0, "localhost", true, - "/", false)); - CPPUNIT_ASSERT(!st.store(expireGoodCookie, now)); + auto expireGoodCookie = []() { + return createCookie("k", "v3", 0, "localhost", true, "/", false); + }; + CPPUNIT_ASSERT(!st.store(expireGoodCookie(), now)); 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, - "/", false)); - CPPUNIT_ASSERT(st.store(fromNumericHost, now)); + auto fromNumericHost = []() { + return createCookie("k", "v", "192.168.1.1", true, "/", false); + }; + CPPUNIT_ASSERT(st.store(fromNumericHost(), now)); CPPUNIT_ASSERT_EQUAL((size_t)2, st.size()); - CPPUNIT_ASSERT(st.contains(fromNumericHost)); + CPPUNIT_ASSERT(st.contains(*fromNumericHost())); } void CookieStorageTest::testParseAndStore() { - CookieStorage st; + auto st = CookieStorage{}; time_t now = 1000; std::string localhostCookieStr = "k=v;" " expires=Fri, 01 Jan 2038 00:00:00 GMT; path=/; domain=localhost;"; @@ -122,221 +133,233 @@ void CookieStorageTest::testParseAndStore() void CookieStorageTest::testCriteriaFind() { - CookieStorage st; + auto st = CookieStorage{}; time_t now = 1000; - Cookie alpha(createCookie("alpha", "ALPHA", "aria2.org", false, "/", false)); - Cookie bravo(createCookie("bravo", "BRAVO", 1060, "aria2.org", false, - "/foo", false)); - Cookie charlie(createCookie("charlie", "CHARLIE", "aria2.org", false, - "/", true)); - Cookie delta(createCookie("delta", "DELTA", "aria2.org", false, - "/foo/bar", false)); - Cookie echo(createCookie("echo", "ECHO", "www.dl.aria2.org", false, - "/", false)); - Cookie foxtrot(createCookie("foxtrot", "FOXTROT", "sf.net", false, - "/", false)); - Cookie golf(createCookie("golf", "GOLF", "192.168.1.1", true, - "/", false)); - Cookie hotel1(createCookie("hotel", "HOTEL1", "samename.x", false, - "/", false)); - Cookie hotel2(createCookie("hotel", "HOTEL2", "samename.x", false, - "/hotel", false)); - Cookie hotel3(createCookie("hotel", "HOTEL3", "samename.x", false, - "/bar/wine", false)); - Cookie hotel4(createCookie("hotel", "HOTEL4", "samename.x", false, - "/bar/", false)); - Cookie india1(createCookie("india", "INDIA1", "default.domain", true, - "/foo", false)); - Cookie india2(createCookie("india", "INDIA2", "default.domain", false, - "/", false)); - Cookie juliet1(createCookie("juliet", "JULIET1", "localhost", true, - "/foo", false)); + auto alpha = []() { + return createCookie("alpha", "ALPHA", "aria2.org", false, "/", false); + }; + auto bravo = []() { + return createCookie("bravo", "BRAVO", 1060, "aria2.org", false, + "/foo", false); + }; + auto charlie = []() { + return createCookie("charlie", "CHARLIE", "aria2.org", false, + "/", true); + }; + auto delta = []() { + return createCookie("delta", "DELTA", "aria2.org", false, + "/foo/bar", false); + }; + auto echo = []() { + return createCookie("echo", "ECHO", "www.dl.aria2.org", false, + "/", false); + }; + auto foxtrot = []() { + return createCookie("foxtrot", "FOXTROT", "sf.net", false, + "/", false); + }; + auto golf = []() { + return createCookie("golf", "GOLF", "192.168.1.1", true, + "/", 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(bravo, now)); - CPPUNIT_ASSERT(st.store(charlie, now)); - CPPUNIT_ASSERT(st.store(delta, now)); - CPPUNIT_ASSERT(st.store(echo, now)); - CPPUNIT_ASSERT(st.store(foxtrot, now)); - CPPUNIT_ASSERT(st.store(golf, now)); - CPPUNIT_ASSERT(st.store(hotel1, now)); - CPPUNIT_ASSERT(st.store(hotel2, now)); - CPPUNIT_ASSERT(st.store(hotel3, now)); - CPPUNIT_ASSERT(st.store(hotel4, now)); - CPPUNIT_ASSERT(st.store(india1, now)); - CPPUNIT_ASSERT(st.store(india2, now)); - CPPUNIT_ASSERT(st.store(juliet1, now)); + CPPUNIT_ASSERT(st.store(alpha(), now)); + CPPUNIT_ASSERT(st.store(bravo(), now)); + CPPUNIT_ASSERT(st.store(charlie(), now)); + CPPUNIT_ASSERT(st.store(delta(), now)); + CPPUNIT_ASSERT(st.store(echo(), now)); + CPPUNIT_ASSERT(st.store(foxtrot(), now)); + CPPUNIT_ASSERT(st.store(golf(), now)); + CPPUNIT_ASSERT(st.store(hotel1(), now)); + CPPUNIT_ASSERT(st.store(hotel2(), now)); + CPPUNIT_ASSERT(st.store(hotel3(), now)); + CPPUNIT_ASSERT(st.store(hotel4(), now)); + CPPUNIT_ASSERT(st.store(india1(), now)); + CPPUNIT_ASSERT(st.store(india2(), now)); + CPPUNIT_ASSERT(st.store(juliet1(), now)); - std::vector aria2Slash = st.criteriaFind("www.dl.aria2.org", "/", - 0, false); + auto aria2Slash = st.criteriaFind("www.dl.aria2.org", "/", 0, false); CPPUNIT_ASSERT_EQUAL((size_t)2, aria2Slash.size()); - CPPUNIT_ASSERT(std::find(aria2Slash.begin(), aria2Slash.end(), alpha) - != aria2Slash.end()); - CPPUNIT_ASSERT(std::find(aria2Slash.begin(), aria2Slash.end(), echo) - != aria2Slash.end()); + CPPUNIT_ASSERT(derefFind(aria2Slash, alpha())); + CPPUNIT_ASSERT(derefFind(aria2Slash, echo())); - std::vector aria2SlashFoo = st.criteriaFind("www.dl.aria2.org","/foo", - 0, false); + auto aria2SlashFoo = st.criteriaFind("www.dl.aria2.org","/foo", 0, false); CPPUNIT_ASSERT_EQUAL((size_t)3, aria2SlashFoo.size()); - CPPUNIT_ASSERT_EQUAL(std::string("bravo"), aria2SlashFoo[0].getName()); - CPPUNIT_ASSERT(std::find(aria2SlashFoo.begin(), aria2SlashFoo.end(), alpha) - != aria2SlashFoo.end()); - CPPUNIT_ASSERT(std::find(aria2SlashFoo.begin(), aria2SlashFoo.end(), echo) - != aria2SlashFoo.end()); + CPPUNIT_ASSERT_EQUAL(std::string("bravo"), aria2SlashFoo[0]->getName()); + CPPUNIT_ASSERT(derefFind(aria2SlashFoo, alpha())); + CPPUNIT_ASSERT(derefFind(aria2SlashFoo, echo())); - std::vector aria2Expires = st.criteriaFind("www.dl.aria2.org", "/foo", - 1120, - false); + auto aria2Expires = st.criteriaFind("www.dl.aria2.org", "/foo", 1120, false); CPPUNIT_ASSERT_EQUAL((size_t)2, aria2Expires.size()); - CPPUNIT_ASSERT(std::find(aria2Expires.begin(), aria2Expires.end(), alpha) - != aria2Expires.end()); - CPPUNIT_ASSERT(std::find(aria2Expires.begin(), aria2Expires.end(), echo) - != aria2Expires.end()); + CPPUNIT_ASSERT(derefFind(aria2Expires, alpha())); + CPPUNIT_ASSERT(derefFind(aria2Expires, echo())); - std::vector 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(std::string("alpha"), dlAria2[0].getName()); + CPPUNIT_ASSERT_EQUAL(std::string("alpha"), dlAria2[0]->getName()); - std::vector tailmatchAria2 = st.criteriaFind("myaria2.org", "/", 0, - false); + auto tailmatchAria2 = st.criteriaFind("myaria2.org", "/", 0, false); CPPUNIT_ASSERT(tailmatchAria2.empty()); - std::vector numericHostCookies = st.criteriaFind("192.168.1.1", "/",0, - false); + auto numericHostCookies = st.criteriaFind("192.168.1.1", "/",0, false); 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 sameNameCookies = - st.criteriaFind("samename.x", "/bar/wine", 0, false); + auto sameNameCookies = st.criteriaFind("samename.x", "/bar/wine", 0, false); CPPUNIT_ASSERT_EQUAL((size_t)3, sameNameCookies.size()); - CPPUNIT_ASSERT_EQUAL(std::string("HOTEL3"), sameNameCookies[0].getValue()); - CPPUNIT_ASSERT_EQUAL(std::string("HOTEL4"), sameNameCookies[1].getValue()); - CPPUNIT_ASSERT_EQUAL(std::string("HOTEL1"), sameNameCookies[2].getValue()); + CPPUNIT_ASSERT_EQUAL(std::string("HOTEL3"), sameNameCookies[0]->getValue()); + CPPUNIT_ASSERT_EQUAL(std::string("HOTEL4"), sameNameCookies[1]->getValue()); + CPPUNIT_ASSERT_EQUAL(std::string("HOTEL1"), sameNameCookies[2]->getValue()); - std::vector defaultDomainCookies = - st.criteriaFind("default.domain", "/foo", 0, false); + auto defaultDomainCookies = st.criteriaFind("default.domain", "/foo", 0, + false); CPPUNIT_ASSERT_EQUAL((size_t)2, defaultDomainCookies.size()); CPPUNIT_ASSERT_EQUAL(std::string("INDIA1"), - defaultDomainCookies[0].getValue()); + defaultDomainCookies[0]->getValue()); CPPUNIT_ASSERT_EQUAL(std::string("INDIA2"), - defaultDomainCookies[1].getValue()); + defaultDomainCookies[1]->getValue()); defaultDomainCookies = st.criteriaFind("sub.default.domain", "/foo", 0, false); CPPUNIT_ASSERT_EQUAL((size_t)1, defaultDomainCookies.size()); CPPUNIT_ASSERT_EQUAL(std::string("INDIA2"), - defaultDomainCookies[0].getValue()); + defaultDomainCookies[0]->getValue()); // localhost.local case - std::vector localDomainCookies = - st.criteriaFind("localhost", "/foo", 0, false); + auto localDomainCookies = st.criteriaFind("localhost", "/foo", 0, false); CPPUNIT_ASSERT_EQUAL((size_t)1, localDomainCookies.size()); CPPUNIT_ASSERT_EQUAL(std::string("JULIET1"), - localDomainCookies[0].getValue()); + localDomainCookies[0]->getValue()); } void CookieStorageTest::testCriteriaFind_cookieOrder() { - CookieStorage st; - Cookie a(createCookie("a", "0", "host", true, "/", false)); - a.setCreationTime(1000); - Cookie b(createCookie("b", "0", "host", true, "/foo", false)); - b.setCreationTime(5000); - Cookie c(createCookie("c", "0", "host", true, "/foo", false)); - c.setCreationTime(4000); - Cookie d(createCookie("d", "0", "host", true, "/foo/bar", false)); - d.setCreationTime(6000); + auto st = CookieStorage{}; + auto a = createCookie("a", "0", "host", true, "/", false); + a->setCreationTime(1000); + auto b = createCookie("b", "0", "host", true, "/foo", false); + b->setCreationTime(5000); + auto c = createCookie("c", "0", "host", true, "/foo", false); + c->setCreationTime(4000); + auto d = createCookie("d", "0", "host", true, "/foo/bar", false); + d->setCreationTime(6000); - st.store(a, 0); - st.store(b, 0); - st.store(c, 0); - st.store(d, 0); + st.store(std::move(a), 0); + st.store(std::move(b), 0); + st.store(std::move(c), 0); + st.store(std::move(d), 0); - std::vector 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(std::string("d"), cookies[0].getName()); - CPPUNIT_ASSERT_EQUAL(std::string("c"), cookies[1].getName()); - CPPUNIT_ASSERT_EQUAL(std::string("b"), cookies[2].getName()); - CPPUNIT_ASSERT_EQUAL(std::string("a"), cookies[3].getName()); + CPPUNIT_ASSERT_EQUAL(std::string("d"), cookies[0]->getName()); + CPPUNIT_ASSERT_EQUAL(std::string("c"), cookies[1]->getName()); + CPPUNIT_ASSERT_EQUAL(std::string("b"), cookies[2]->getName()); + CPPUNIT_ASSERT_EQUAL(std::string("a"), cookies[3]->getName()); } void CookieStorageTest::testLoad() { - CookieStorage st; + auto st = CookieStorage{}; st.load(A2_TEST_DIR"/nscookietest.txt", 1001); CPPUNIT_ASSERT_EQUAL((size_t)4, st.size()); - std::vector cookies; - dumpCookie(cookies, st); + auto cookies = dumpCookie(st); - Cookie c = cookies[0]; - CPPUNIT_ASSERT_EQUAL(std::string("passwd"), c.getName()); - CPPUNIT_ASSERT_EQUAL(std::string("secret"), c.getValue()); - CPPUNIT_ASSERT_EQUAL(std::numeric_limits::max(), c.getExpiryTime()); - CPPUNIT_ASSERT(!c.getPersistent()); - CPPUNIT_ASSERT_EQUAL(std::string("/cgi-bin"), c.getPath()); - CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), c.getDomain()); - CPPUNIT_ASSERT(c.getHostOnly()); - CPPUNIT_ASSERT(!c.getSecure()); + auto c = cookies[0]; + CPPUNIT_ASSERT_EQUAL(std::string("passwd"), c->getName()); + CPPUNIT_ASSERT_EQUAL(std::string("secret"), c->getValue()); + CPPUNIT_ASSERT_EQUAL(std::numeric_limits::max(), c->getExpiryTime()); + CPPUNIT_ASSERT(!c->getPersistent()); + CPPUNIT_ASSERT_EQUAL(std::string("/cgi-bin"), c->getPath()); + CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), c->getDomain()); + CPPUNIT_ASSERT(c->getHostOnly()); + CPPUNIT_ASSERT(!c->getSecure()); c = cookies[1]; - CPPUNIT_ASSERT_EQUAL(std::string("novalue"), c.getName()); - CPPUNIT_ASSERT_EQUAL(std::string(""), c.getValue()); - CPPUNIT_ASSERT_EQUAL((time_t)2147483647, c.getExpiryTime()); - CPPUNIT_ASSERT(c.getPersistent()); - CPPUNIT_ASSERT_EQUAL(std::string("/"), c.getPath()); - CPPUNIT_ASSERT_EQUAL(std::string("example.org"), c.getDomain()); - CPPUNIT_ASSERT(!c.getHostOnly()); - CPPUNIT_ASSERT(!c.getSecure()); + CPPUNIT_ASSERT_EQUAL(std::string("novalue"), c->getName()); + CPPUNIT_ASSERT_EQUAL(std::string(""), c->getValue()); + CPPUNIT_ASSERT_EQUAL((time_t)2147483647, c->getExpiryTime()); + CPPUNIT_ASSERT(c->getPersistent()); + CPPUNIT_ASSERT_EQUAL(std::string("/"), c->getPath()); + CPPUNIT_ASSERT_EQUAL(std::string("example.org"), c->getDomain()); + CPPUNIT_ASSERT(!c->getHostOnly()); + CPPUNIT_ASSERT(!c->getSecure()); c = cookies[2]; - CPPUNIT_ASSERT_EQUAL(std::string("JSESSIONID"), c.getName()); - CPPUNIT_ASSERT_EQUAL(std::string("123456789"), c.getValue()); - CPPUNIT_ASSERT_EQUAL((time_t)2147483647, c.getExpiryTime()); - CPPUNIT_ASSERT_EQUAL(std::string("/"), c.getPath()); - CPPUNIT_ASSERT_EQUAL(std::string("localhost"), c.getDomain()); - CPPUNIT_ASSERT(c.getHostOnly()); - CPPUNIT_ASSERT(c.getSecure()); + CPPUNIT_ASSERT_EQUAL(std::string("JSESSIONID"), c->getName()); + CPPUNIT_ASSERT_EQUAL(std::string("123456789"), c->getValue()); + CPPUNIT_ASSERT_EQUAL((time_t)2147483647, c->getExpiryTime()); + CPPUNIT_ASSERT_EQUAL(std::string("/"), c->getPath()); + CPPUNIT_ASSERT_EQUAL(std::string("localhost"), c->getDomain()); + CPPUNIT_ASSERT(c->getHostOnly()); + CPPUNIT_ASSERT(c->getSecure()); c = cookies[3]; - CPPUNIT_ASSERT_EQUAL(std::string("TAX"), c.getName()); - CPPUNIT_ASSERT_EQUAL(std::string("1000"), c.getValue()); - CPPUNIT_ASSERT((time_t)INT32_MAX <= c.getExpiryTime()); - CPPUNIT_ASSERT(c.getPersistent()); - CPPUNIT_ASSERT_EQUAL(std::string("/"), c.getPath()); - CPPUNIT_ASSERT_EQUAL(std::string("overflow"), c.getDomain()); - CPPUNIT_ASSERT(!c.getSecure()); + CPPUNIT_ASSERT_EQUAL(std::string("TAX"), c->getName()); + CPPUNIT_ASSERT_EQUAL(std::string("1000"), c->getValue()); + CPPUNIT_ASSERT((time_t)INT32_MAX <= c->getExpiryTime()); + CPPUNIT_ASSERT(c->getPersistent()); + CPPUNIT_ASSERT_EQUAL(std::string("/"), c->getPath()); + CPPUNIT_ASSERT_EQUAL(std::string("overflow"), c->getDomain()); + CPPUNIT_ASSERT(!c->getSecure()); } void CookieStorageTest::testLoad_sqlite3() { - CookieStorage st; + auto st = CookieStorage{}; #ifdef HAVE_SQLITE3 st.load(A2_TEST_DIR"/cookies.sqlite", 1000); CPPUNIT_ASSERT_EQUAL((size_t)2, st.size()); - std::vector cookies; - dumpCookie(cookies, st); - Cookie c = cookies[0]; - CPPUNIT_ASSERT_EQUAL(std::string("JSESSIONID"), c.getName()); - CPPUNIT_ASSERT_EQUAL(std::string("123456789"), c.getValue()); - CPPUNIT_ASSERT_EQUAL((time_t)INT32_MAX, c.getExpiryTime()); - CPPUNIT_ASSERT(c.getPersistent()); - CPPUNIT_ASSERT_EQUAL(std::string("localhost"), c.getDomain()); - CPPUNIT_ASSERT(c.getHostOnly()); - CPPUNIT_ASSERT_EQUAL(std::string("/"), c.getPath()); - CPPUNIT_ASSERT(c.getSecure()); + auto cookies = dumpCookie(st); + auto c = cookies[0]; + CPPUNIT_ASSERT_EQUAL(std::string("JSESSIONID"), c->getName()); + CPPUNIT_ASSERT_EQUAL(std::string("123456789"), c->getValue()); + CPPUNIT_ASSERT_EQUAL((time_t)INT32_MAX, c->getExpiryTime()); + CPPUNIT_ASSERT(c->getPersistent()); + CPPUNIT_ASSERT_EQUAL(std::string("localhost"), c->getDomain()); + CPPUNIT_ASSERT(c->getHostOnly()); + CPPUNIT_ASSERT_EQUAL(std::string("/"), c->getPath()); + CPPUNIT_ASSERT(c->getSecure()); c = cookies[1]; - CPPUNIT_ASSERT_EQUAL(std::string("foo"), c.getName()); - CPPUNIT_ASSERT_EQUAL(std::string("bar"), c.getValue()); - CPPUNIT_ASSERT((time_t)INT32_MAX <= c.getExpiryTime()); - CPPUNIT_ASSERT(c.getPersistent()); - CPPUNIT_ASSERT_EQUAL(std::string("overflow.time_t.org"), c.getDomain()); - CPPUNIT_ASSERT(!c.getHostOnly()); - CPPUNIT_ASSERT_EQUAL(std::string("/path/to"), c.getPath()); - CPPUNIT_ASSERT(!c.getSecure()); + CPPUNIT_ASSERT_EQUAL(std::string("foo"), c->getName()); + CPPUNIT_ASSERT_EQUAL(std::string("bar"), c->getValue()); + CPPUNIT_ASSERT((time_t)INT32_MAX <= c->getExpiryTime()); + CPPUNIT_ASSERT(c->getPersistent()); + CPPUNIT_ASSERT_EQUAL(std::string("overflow.time_t.org"), c->getDomain()); + CPPUNIT_ASSERT(!c->getHostOnly()); + CPPUNIT_ASSERT_EQUAL(std::string("/path/to"), c->getPath()); + CPPUNIT_ASSERT(!c->getSecure()); #else // !HAVE_SQLITE3 CPPUNIT_ASSERT(!st.load(A2_TEST_DIR"/cookies.sqlite", 1000)); @@ -345,7 +368,7 @@ void CookieStorageTest::testLoad_sqlite3() void CookieStorageTest::testLoad_fileNotfound() { - CookieStorage st; + auto st = CookieStorage{}; CPPUNIT_ASSERT(!st.load("./aria2_CookieStorageTest_testLoad_fileNotfound",0)); } @@ -354,22 +377,22 @@ void CookieStorageTest::testSaveNsFormat() // TODO add cookie with default domain std::string filename = A2_TEST_OUT_DIR"/aria2_CookieStorageTest_testSaveNsFormat"; File(filename).remove(); - CookieStorage st; + auto st = CookieStorage{}; time_t now = 1000; - st.store(Cookie(createCookie("favorite", "classic", "domain.org", false, - "/config",true)), now); - st.store(Cookie(createCookie("uid", "tujikawa", now, "domain.org", true, - "/",false)), now); + st.store(createCookie("favorite", "classic", "domain.org", false, + "/config",true), now); + st.store(createCookie("uid", "tujikawa", now, "domain.org", true, + "/",false), now); CPPUNIT_ASSERT(st.saveNsFormat(filename)); - CookieStorage loadst; + auto loadst = CookieStorage{}; loadst.load(filename, now); CPPUNIT_ASSERT_EQUAL((size_t)2, loadst.size()); - std::vector cookies; - dumpCookie(cookies, loadst); + auto cookies = dumpCookie(loadst); - CPPUNIT_ASSERT_EQUAL(std::string("favorite"), cookies[0].getName()); - CPPUNIT_ASSERT_EQUAL(std::string("uid"), cookies[1].getName()); + CPPUNIT_ASSERT_EQUAL((size_t)2, cookies.size()); + CPPUNIT_ASSERT_EQUAL(std::string("favorite"), cookies[0]->getName()); + CPPUNIT_ASSERT_EQUAL(std::string("uid"), cookies[1]->getName()); } void CookieStorageTest::testSaveNsFormat_fail() @@ -380,17 +403,16 @@ void CookieStorageTest::testSaveNsFormat_fail() f.remove(); f.mkdirs(); CPPUNIT_ASSERT(f.isDir()); - CookieStorage st; + auto st = CookieStorage{}; CPPUNIT_ASSERT(!st.saveNsFormat(filename)); } void CookieStorageTest::testCookieIsFull() { - CookieStorage st; + auto st = CookieStorage{}; for(size_t i = 0; i < CookieStorage::MAX_COOKIE_PER_DOMAIN+1; ++i) { - Cookie c(createCookie("k"+util::itos(i), "v", "aria2.org", false, - "/", false)); - st.store(c, 0); + st.store(createCookie("k"+util::itos(i), "v", "aria2.org", false, + "/", false), 0); } 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 // CookieStorage.cc - CookieStorage st; + auto st = CookieStorage{}; for(size_t i = 0; i < 2001; ++i) { - Cookie c(createCookie("k", "v", "domain"+util::itos(i), true, - "/", false)); - st.store(c, 0); + st.store(createCookie("k", "v", "domain"+util::itos(i), true, + "/", false), 0); } 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 diff --git a/test/CookieTest.cc b/test/CookieTest.cc index bf8f6595..d4d0c09e 100644 --- a/test/CookieTest.cc +++ b/test/CookieTest.cc @@ -35,67 +35,66 @@ CPPUNIT_TEST_SUITE_REGISTRATION(CookieTest); void CookieTest::testOperatorEqual() { - Cookie a(createCookie("k", "v", "localhost", true, "/", false)); - Cookie b(createCookie("k", "v", "localhost", true, "/", true)); - Cookie wrongPath(createCookie("k", "v", "localhost", true, "/a", false)); - Cookie wrongDomain(createCookie("k", "v", "mydomain", true, "/", false)); - Cookie wrongName(createCookie("h", "v", "localhost", true, "/a", false)); - Cookie caseSensitiveName(createCookie("K", "v", "localhost", true, - "/a", false)); - CPPUNIT_ASSERT(a == b); - CPPUNIT_ASSERT(!(a == wrongPath)); - CPPUNIT_ASSERT(!(a == wrongDomain)); - CPPUNIT_ASSERT(!(a == wrongName)); - CPPUNIT_ASSERT(!(a == caseSensitiveName)); + auto a = createCookie("k", "v", "localhost", true, "/", false); + auto b = createCookie("k", "v", "localhost", true, "/", true); + auto wrongPath = createCookie("k", "v", "localhost", true, "/a", false); + auto wrongDomain = createCookie("k", "v", "mydomain", true, "/", false); + auto wrongName = createCookie("h", "v", "localhost", true, "/a", false); + auto caseSensitiveName = createCookie("K", "v", "localhost", true, + "/a", false); + CPPUNIT_ASSERT(*a == *b); + CPPUNIT_ASSERT(!(*a == *wrongPath)); + CPPUNIT_ASSERT(!(*a == *wrongDomain)); + CPPUNIT_ASSERT(!(*a == *wrongName)); + CPPUNIT_ASSERT(!(*a == *caseSensitiveName)); } void CookieTest::testMatch() { - Cookie c(createCookie("k", "v", "aria2.org", false, "/downloads", false)); - Cookie c2(createCookie("k", "v", "aria2.org", false, "/downloads", false)); - Cookie c3(createCookie("k", "v", "aria2.org", true, "/downloads", false)); - Cookie c4(createCookie("k", "v", "localhost", true, "/downloads", false)); - CPPUNIT_ASSERT(c.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.aria2.org", "/examples", 0, false)); - 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", "/downloadss/latest", 0, false)); - CPPUNIT_ASSERT(!c.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)); + auto c = createCookie("k", "v", "aria2.org", false, "/downloads", false); + auto c2 = createCookie("k", "v", "aria2.org", false, "/downloads", false); + auto c3 = createCookie("k", "v", "aria2.org", true, "/downloads", false); + auto c4 = createCookie("k", "v", "localhost", true, "/downloads", false); + CPPUNIT_ASSERT(c->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.aria2.org", "/examples", 0, false)); + 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", "/downloadss/latest", 0, false)); + CPPUNIT_ASSERT(!c->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)); - Cookie secureCookie(createCookie("k", "v", "secure.aria2.org", false, - "/", true)); - CPPUNIT_ASSERT(secureCookie.match("secure.aria2.org", "/", 0, true)); - CPPUNIT_ASSERT(!secureCookie.match("secure.aria2.org", "/", 0, false)); - CPPUNIT_ASSERT(!secureCookie.match("ssecure.aria2.org", "/", 0, true)); - CPPUNIT_ASSERT(secureCookie.match("www.secure.aria2.org", "/", 0, true)); + auto secureCookie = createCookie("k", "v", "secure.aria2.org", false, + "/", true); + CPPUNIT_ASSERT(secureCookie->match("secure.aria2.org", "/", 0, true)); + CPPUNIT_ASSERT(!secureCookie->match("secure.aria2.org", "/", 0, false)); + CPPUNIT_ASSERT(!secureCookie->match("ssecure.aria2.org", "/", 0, true)); + CPPUNIT_ASSERT(secureCookie->match("www.secure.aria2.org", "/", 0, true)); - Cookie expireTest(createCookie("k", "v", 1000, "aria2.org", false, - "/", 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", "/", 1001, false)); + auto expireTest = createCookie("k", "v", 1000, "aria2.org", false, + "/", 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", "/", 1001, false)); - Cookie fromNumericHost(createCookie("k", "v", "192.168.1.1", true, - "/foo", 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("1.192.168.1.1", "/foo", 0, false)); - CPPUNIT_ASSERT(!fromNumericHost.match("192.168.1.1", "/", 0, false)); + auto fromNumericHost = createCookie("k", "v", "192.168.1.1", true, + "/foo", 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("1.192.168.1.1", "/foo", 0, false)); + CPPUNIT_ASSERT(!fromNumericHost->match("192.168.1.1", "/", 0, false)); } void CookieTest::testIsExpired() { - Cookie cookie(createCookie("k", "v", 1000, "localhost", true, - "/", false)); - CPPUNIT_ASSERT(cookie.isExpired(1001)); - CPPUNIT_ASSERT(!cookie.isExpired(1000)); - CPPUNIT_ASSERT(!cookie.isExpired(999)); - Cookie sessionCookie(createCookie("k", "v", "localhost", true, "/", false)); - CPPUNIT_ASSERT(!sessionCookie.isExpired(INT32_MAX)); + auto cookie = createCookie("k", "v", 1000, "localhost", true, "/", false); + CPPUNIT_ASSERT(cookie->isExpired(1001)); + CPPUNIT_ASSERT(!cookie->isExpired(1000)); + CPPUNIT_ASSERT(!cookie->isExpired(999)); + auto sessionCookie = createCookie("k", "v", "localhost", true, "/", false); + CPPUNIT_ASSERT(!sessionCookie->isExpired(INT32_MAX)); } void CookieTest::testToNsCookieFormat() @@ -103,12 +102,12 @@ void CookieTest::testToNsCookieFormat() CPPUNIT_ASSERT_EQUAL (std::string(".domain.org\tTRUE\t/\tFALSE\t12345678\thello\tworld"), createCookie("hello", "world", 12345678, "domain.org", false, "/",false) - .toNsCookieFormat()); + ->toNsCookieFormat()); // Session cookie CPPUNIT_ASSERT_EQUAL (std::string("domain.org\tFALSE\t/\tTRUE\t0\thello\tworld"), createCookie("hello", "world", "domain.org", true, "/", true) - .toNsCookieFormat()); + ->toNsCookieFormat()); } } // namespace aria2 diff --git a/test/HttpRequestTest.cc b/test/HttpRequestTest.cc index 5beb239b..6d93d4ae 100644 --- a/test/HttpRequestTest.cc +++ b/test/HttpRequestTest.cc @@ -368,6 +368,13 @@ void HttpRequestTest::testCreateRequest_ftp() CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest()); } +template +void foo(CookieStorage& st, InputIterator first, InputIterator last, time_t t) +{ + for(; first != last; ++first) { + st.store(*first, t); + } +} void HttpRequestTest::testCreateRequest_with_cookie() { auto request = std::make_shared(); @@ -376,19 +383,17 @@ void HttpRequestTest::testCreateRequest_with_cookie() auto segment = std::make_shared(1024*1024, p); auto fileEntry = std::make_shared("file", 1024*1024*10, 0); - std::vector cookies { - createCookie("name1", "value1", "localhost", true, "/archives", false), - createCookie("name2", "value2", "localhost", true, - "/archives/download", false), - createCookie("name3", "value3", "aria2.org", false, - "/archives/download", false), - createCookie("name4", "value4", "aria2.org", false, "/archives/", true), - createCookie("name5", "value5", "example.org", false, "/", false) - }; - CookieStorage st; - for(auto c : cookies) { - CPPUNIT_ASSERT(st.store(c, 0)); - } + auto st = CookieStorage{}; + CPPUNIT_ASSERT(st.store(createCookie("name1", "value1", "localhost", true, + "/archives", false), 0)); + CPPUNIT_ASSERT(st.store(createCookie("name2", "value2", "localhost", true, + "/archives/download", false), 0)); + CPPUNIT_ASSERT(st.store(createCookie("name3", "value3", "aria2.org", false, + "/archives/download", false), 0)); + CPPUNIT_ASSERT(st.store(createCookie("name4", "value4", "aria2.org", false, + "/archives/", true), 0)); + CPPUNIT_ASSERT(st.store(createCookie("name5", "value5", "example.org", false, + "/", false), 0)); HttpRequest httpRequest; diff --git a/test/HttpResponseTest.cc b/test/HttpResponseTest.cc index 08892144..ce6589f4 100644 --- a/test/HttpResponseTest.cc +++ b/test/HttpResponseTest.cc @@ -4,6 +4,7 @@ #include +#include "TestUtil.h" #include "prefs.h" #include "PiecedSegment.h" #include "Piece.h" @@ -511,10 +512,11 @@ void HttpResponseTest::testRetrieveCookie() CPPUNIT_ASSERT_EQUAL((size_t)2, st.size()); - std::vector cookies; + auto cookies = std::vector{}; st.dumpCookie(std::back_inserter(cookies)); - CPPUNIT_ASSERT_EQUAL(std::string("k2=v2"), cookies[0].toString()); - CPPUNIT_ASSERT_EQUAL(std::string("k3=v3"), cookies[1].toString()); + std::sort(std::begin(cookies), std::end(cookies), CookieSorter()); + CPPUNIT_ASSERT_EQUAL(std::string("k2=v2"), cookies[0]->toString()); + CPPUNIT_ASSERT_EQUAL(std::string("k3=v3"), cookies[1]->toString()); } void HttpResponseTest::testSupportsPersistentConnection() diff --git a/test/NsCookieParserTest.cc b/test/NsCookieParserTest.cc index 832badca..33003fc7 100644 --- a/test/NsCookieParserTest.cc +++ b/test/NsCookieParserTest.cc @@ -33,58 +33,58 @@ void NsCookieParserTest::testParse() { NsCookieParser parser; time_t now = 0; - std::vector 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()); - Cookie c = cookies[0]; - CPPUNIT_ASSERT_EQUAL(std::string("JSESSIONID"), c.getName()); - CPPUNIT_ASSERT_EQUAL(std::string("123456789"), c.getValue()); - CPPUNIT_ASSERT_EQUAL((time_t)INT32_MAX, c.getExpiryTime()); - CPPUNIT_ASSERT(c.getPersistent()); - CPPUNIT_ASSERT_EQUAL(std::string("localhost"), c.getDomain()); - CPPUNIT_ASSERT(c.getHostOnly()); - CPPUNIT_ASSERT_EQUAL(std::string("/"), c.getPath()); - CPPUNIT_ASSERT(c.getSecure()); + auto c = cookies[0].get(); + CPPUNIT_ASSERT_EQUAL(std::string("JSESSIONID"), c->getName()); + CPPUNIT_ASSERT_EQUAL(std::string("123456789"), c->getValue()); + CPPUNIT_ASSERT_EQUAL((time_t)INT32_MAX, c->getExpiryTime()); + CPPUNIT_ASSERT(c->getPersistent()); + CPPUNIT_ASSERT_EQUAL(std::string("localhost"), c->getDomain()); + CPPUNIT_ASSERT(c->getHostOnly()); + CPPUNIT_ASSERT_EQUAL(std::string("/"), c->getPath()); + CPPUNIT_ASSERT(c->getSecure()); - c = cookies[1]; - CPPUNIT_ASSERT_EQUAL(std::string("user"), c.getName()); - CPPUNIT_ASSERT_EQUAL(std::string("me"), c.getValue()); - CPPUNIT_ASSERT_EQUAL((time_t)1000, c.getExpiryTime()); - CPPUNIT_ASSERT(c.getPersistent()); - CPPUNIT_ASSERT_EQUAL(std::string("expired"), c.getDomain()); - CPPUNIT_ASSERT(c.getHostOnly()); - CPPUNIT_ASSERT_EQUAL(std::string("/"), c.getPath()); - CPPUNIT_ASSERT(!c.getSecure()); + c = cookies[1].get(); + CPPUNIT_ASSERT_EQUAL(std::string("user"), c->getName()); + CPPUNIT_ASSERT_EQUAL(std::string("me"), c->getValue()); + CPPUNIT_ASSERT_EQUAL((time_t)1000, c->getExpiryTime()); + CPPUNIT_ASSERT(c->getPersistent()); + CPPUNIT_ASSERT_EQUAL(std::string("expired"), c->getDomain()); + CPPUNIT_ASSERT(c->getHostOnly()); + CPPUNIT_ASSERT_EQUAL(std::string("/"), c->getPath()); + CPPUNIT_ASSERT(!c->getSecure()); - c = cookies[2]; - CPPUNIT_ASSERT_EQUAL(std::string("passwd"), c.getName()); - CPPUNIT_ASSERT_EQUAL(std::string("secret"), c.getValue()); - CPPUNIT_ASSERT_EQUAL(std::numeric_limits::max(), c.getExpiryTime()); - CPPUNIT_ASSERT(!c.getPersistent()); - CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), c.getDomain()); - CPPUNIT_ASSERT(c.getHostOnly()); - CPPUNIT_ASSERT_EQUAL(std::string("/cgi-bin"), c.getPath()); - CPPUNIT_ASSERT(!c.getSecure()); + c = cookies[2].get(); + CPPUNIT_ASSERT_EQUAL(std::string("passwd"), c->getName()); + CPPUNIT_ASSERT_EQUAL(std::string("secret"), c->getValue()); + CPPUNIT_ASSERT_EQUAL(std::numeric_limits::max(), c->getExpiryTime()); + CPPUNIT_ASSERT(!c->getPersistent()); + CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), c->getDomain()); + CPPUNIT_ASSERT(c->getHostOnly()); + CPPUNIT_ASSERT_EQUAL(std::string("/cgi-bin"), c->getPath()); + CPPUNIT_ASSERT(!c->getSecure()); - c = cookies[3]; - CPPUNIT_ASSERT_EQUAL(std::string("TAX"), c.getName()); - CPPUNIT_ASSERT_EQUAL(std::string("1000"), c.getValue()); - CPPUNIT_ASSERT((time_t)INT32_MAX <= c.getExpiryTime()); - CPPUNIT_ASSERT(c.getPersistent()); - CPPUNIT_ASSERT_EQUAL(std::string("overflow"), c.getDomain()); - CPPUNIT_ASSERT(c.getHostOnly()); - CPPUNIT_ASSERT_EQUAL(std::string("/"), c.getPath()); - CPPUNIT_ASSERT(!c.getSecure()); + c = cookies[3].get(); + CPPUNIT_ASSERT_EQUAL(std::string("TAX"), c->getName()); + CPPUNIT_ASSERT_EQUAL(std::string("1000"), c->getValue()); + CPPUNIT_ASSERT((time_t)INT32_MAX <= c->getExpiryTime()); + CPPUNIT_ASSERT(c->getPersistent()); + CPPUNIT_ASSERT_EQUAL(std::string("overflow"), c->getDomain()); + CPPUNIT_ASSERT(c->getHostOnly()); + CPPUNIT_ASSERT_EQUAL(std::string("/"), c->getPath()); + CPPUNIT_ASSERT(!c->getSecure()); - c = cookies[4]; - CPPUNIT_ASSERT_EQUAL(std::string("novalue"), c.getName()); - CPPUNIT_ASSERT_EQUAL(std::string(""), c.getValue()); - CPPUNIT_ASSERT_EQUAL((time_t)INT32_MAX, c.getExpiryTime()); - CPPUNIT_ASSERT(c.getPersistent()); - CPPUNIT_ASSERT_EQUAL(std::string("example.org"), c.getDomain()); - CPPUNIT_ASSERT(!c.getHostOnly()); - CPPUNIT_ASSERT_EQUAL(std::string("/"), c.getPath()); - CPPUNIT_ASSERT(!c.getSecure()); + c = cookies[4].get(); + CPPUNIT_ASSERT_EQUAL(std::string("novalue"), c->getName()); + CPPUNIT_ASSERT_EQUAL(std::string(""), c->getValue()); + CPPUNIT_ASSERT_EQUAL((time_t)INT32_MAX, c->getExpiryTime()); + CPPUNIT_ASSERT(c->getPersistent()); + CPPUNIT_ASSERT_EQUAL(std::string("example.org"), c->getDomain()); + CPPUNIT_ASSERT(!c->getHostOnly()); + CPPUNIT_ASSERT_EQUAL(std::string("/"), c->getPath()); + CPPUNIT_ASSERT(!c->getSecure()); } void NsCookieParserTest::testParse_fileNotFound() diff --git a/test/Sqlite3CookieParserTest.cc b/test/Sqlite3CookieParserTest.cc index 6f492082..b9998ee6 100644 --- a/test/Sqlite3CookieParserTest.cc +++ b/test/Sqlite3CookieParserTest.cc @@ -35,55 +35,53 @@ CPPUNIT_TEST_SUITE_REGISTRATION(Sqlite3CookieParserTest); void Sqlite3CookieParserTest::testMozParse() { - Sqlite3MozCookieParser parser(A2_TEST_DIR"/cookies.sqlite"); - std::vector cookies; - parser.parse(cookies); + auto parser = Sqlite3MozCookieParser{A2_TEST_DIR"/cookies.sqlite"}; + auto cookies = parser.parse(); CPPUNIT_ASSERT_EQUAL((size_t)3, cookies.size()); - const Cookie& localhost = cookies[0]; - CPPUNIT_ASSERT_EQUAL(std::string("JSESSIONID"), localhost.getName()); - CPPUNIT_ASSERT_EQUAL(std::string("123456789"), localhost.getValue()); - CPPUNIT_ASSERT_EQUAL((time_t)INT32_MAX, localhost.getExpiryTime()); - CPPUNIT_ASSERT(localhost.getPersistent()); - CPPUNIT_ASSERT_EQUAL(std::string("localhost"), localhost.getDomain()); - CPPUNIT_ASSERT(localhost.getHostOnly()); - CPPUNIT_ASSERT_EQUAL(std::string("/"), localhost.getPath()); - CPPUNIT_ASSERT(localhost.getSecure()); - CPPUNIT_ASSERT_EQUAL((time_t)3000, localhost.getLastAccessTime()); - CPPUNIT_ASSERT_EQUAL((time_t)3000, localhost.getCreationTime()); + auto& localhost = cookies[0]; + CPPUNIT_ASSERT_EQUAL(std::string("JSESSIONID"), localhost->getName()); + CPPUNIT_ASSERT_EQUAL(std::string("123456789"), localhost->getValue()); + CPPUNIT_ASSERT_EQUAL((time_t)INT32_MAX, localhost->getExpiryTime()); + CPPUNIT_ASSERT(localhost->getPersistent()); + CPPUNIT_ASSERT_EQUAL(std::string("localhost"), localhost->getDomain()); + CPPUNIT_ASSERT(localhost->getHostOnly()); + CPPUNIT_ASSERT_EQUAL(std::string("/"), localhost->getPath()); + CPPUNIT_ASSERT(localhost->getSecure()); + CPPUNIT_ASSERT_EQUAL((time_t)3000, localhost->getLastAccessTime()); + CPPUNIT_ASSERT_EQUAL((time_t)3000, localhost->getCreationTime()); - const Cookie& nullValue = cookies[1]; - CPPUNIT_ASSERT_EQUAL(std::string("uid"), nullValue.getName()); - CPPUNIT_ASSERT_EQUAL(std::string(""), nullValue.getValue()); - CPPUNIT_ASSERT_EQUAL((time_t)0, nullValue.getExpiryTime()); - CPPUNIT_ASSERT(nullValue.getPersistent()); - CPPUNIT_ASSERT_EQUAL(std::string("null_value.com"), nullValue.getDomain()); - CPPUNIT_ASSERT(!nullValue.getHostOnly()); - CPPUNIT_ASSERT_EQUAL(std::string("/path/to"), nullValue.getPath()); - CPPUNIT_ASSERT(!nullValue.getSecure()); + auto& nullValue = cookies[1]; + CPPUNIT_ASSERT_EQUAL(std::string("uid"), nullValue->getName()); + CPPUNIT_ASSERT_EQUAL(std::string(""), nullValue->getValue()); + CPPUNIT_ASSERT_EQUAL((time_t)0, nullValue->getExpiryTime()); + CPPUNIT_ASSERT(nullValue->getPersistent()); + CPPUNIT_ASSERT_EQUAL(std::string("null_value.com"), nullValue->getDomain()); + CPPUNIT_ASSERT(!nullValue->getHostOnly()); + CPPUNIT_ASSERT_EQUAL(std::string("/path/to"), nullValue->getPath()); + CPPUNIT_ASSERT(!nullValue->getSecure()); // See row id=3 has no name, so it is skipped. - const Cookie& overflowTime = cookies[2]; - CPPUNIT_ASSERT_EQUAL(std::string("foo"), overflowTime.getName()); - CPPUNIT_ASSERT_EQUAL(std::string("bar"), overflowTime.getValue()); - CPPUNIT_ASSERT((time_t)INT32_MAX <= overflowTime.getExpiryTime()); - CPPUNIT_ASSERT(overflowTime.getPersistent()); + auto& overflowTime = cookies[2]; + CPPUNIT_ASSERT_EQUAL(std::string("foo"), overflowTime->getName()); + CPPUNIT_ASSERT_EQUAL(std::string("bar"), overflowTime->getValue()); + CPPUNIT_ASSERT((time_t)INT32_MAX <= overflowTime->getExpiryTime()); + CPPUNIT_ASSERT(overflowTime->getPersistent()); CPPUNIT_ASSERT_EQUAL(std::string("overflow.time_t.org"), - overflowTime.getDomain()); - CPPUNIT_ASSERT(!overflowTime.getHostOnly()); - CPPUNIT_ASSERT_EQUAL(std::string("/path/to"), overflowTime.getPath()); - CPPUNIT_ASSERT(!overflowTime.getSecure()); + overflowTime->getDomain()); + CPPUNIT_ASSERT(!overflowTime->getHostOnly()); + CPPUNIT_ASSERT_EQUAL(std::string("/path/to"), overflowTime->getPath()); + CPPUNIT_ASSERT(!overflowTime->getSecure()); // See row id=5 has bad path, so it is skipped. } void Sqlite3CookieParserTest::testMozParse_fileNotFound() { - Sqlite3MozCookieParser parser("fileNotFound"); + auto parser = Sqlite3MozCookieParser{"fileNotFound"}; try { - std::vector cookies; - parser.parse(cookies); + parser.parse(); CPPUNIT_FAIL("exception must be thrown."); } catch(RecoverableException& e) { // SUCCESS @@ -95,10 +93,9 @@ void Sqlite3CookieParserTest::testMozParse_fileNotFound() void Sqlite3CookieParserTest::testMozParse_badfile() { - Sqlite3MozCookieParser parser(A2_TEST_DIR"/badcookies.sqlite"); + auto parser = Sqlite3MozCookieParser{A2_TEST_DIR"/badcookies.sqlite"}; try { - std::vector cookies; - parser.parse(cookies); + parser.parse(); CPPUNIT_FAIL("exception must be thrown."); } catch(RecoverableException& e) { // SUCCESS @@ -107,37 +104,37 @@ void Sqlite3CookieParserTest::testMozParse_badfile() void Sqlite3CookieParserTest::testChromumParse() { - Sqlite3ChromiumCookieParser parser(A2_TEST_DIR"/chromium_cookies.sqlite"); - std::vector cookies; - parser.parse(cookies); + auto parser = Sqlite3ChromiumCookieParser + {A2_TEST_DIR"/chromium_cookies.sqlite"}; + auto cookies = parser.parse(); CPPUNIT_ASSERT_EQUAL((size_t)3, cookies.size()); - const Cookie& sfnet = cookies[0]; - CPPUNIT_ASSERT_EQUAL(std::string("mykey"), sfnet.getName()); - CPPUNIT_ASSERT_EQUAL(std::string("pass"), sfnet.getValue()); - CPPUNIT_ASSERT_EQUAL((time_t)12345679, sfnet.getExpiryTime()); - CPPUNIT_ASSERT(sfnet.getPersistent()); + auto& sfnet = cookies[0]; + CPPUNIT_ASSERT_EQUAL(std::string("mykey"), sfnet->getName()); + CPPUNIT_ASSERT_EQUAL(std::string("pass"), sfnet->getValue()); + CPPUNIT_ASSERT_EQUAL((time_t)12345679, sfnet->getExpiryTime()); + CPPUNIT_ASSERT(sfnet->getPersistent()); CPPUNIT_ASSERT_EQUAL(std::string("aria2.sourceforge.net"), - sfnet.getDomain()); - CPPUNIT_ASSERT(!sfnet.getHostOnly()); - CPPUNIT_ASSERT_EQUAL(std::string("/"), sfnet.getPath()); - CPPUNIT_ASSERT(!sfnet.getSecure()); + sfnet->getDomain()); + CPPUNIT_ASSERT(!sfnet->getHostOnly()); + CPPUNIT_ASSERT_EQUAL(std::string("/"), sfnet->getPath()); + CPPUNIT_ASSERT(!sfnet->getSecure()); - const Cookie& sfjp = cookies[1]; - CPPUNIT_ASSERT_EQUAL(std::string("myseckey"), sfjp.getName()); - CPPUNIT_ASSERT_EQUAL(std::string("pass2"), sfjp.getValue()); - CPPUNIT_ASSERT_EQUAL((time_t)0, sfjp.getExpiryTime()); - CPPUNIT_ASSERT(sfjp.getPersistent()); - CPPUNIT_ASSERT_EQUAL(std::string("aria2.sourceforge.jp"), sfjp.getDomain()); - CPPUNIT_ASSERT(sfjp.getHostOnly()); - CPPUNIT_ASSERT_EQUAL(std::string("/profile"), sfjp.getPath()); - CPPUNIT_ASSERT(sfjp.getSecure()); + auto& sfjp = cookies[1]; + CPPUNIT_ASSERT_EQUAL(std::string("myseckey"), sfjp->getName()); + CPPUNIT_ASSERT_EQUAL(std::string("pass2"), sfjp->getValue()); + CPPUNIT_ASSERT_EQUAL((time_t)0, sfjp->getExpiryTime()); + CPPUNIT_ASSERT(sfjp->getPersistent()); + CPPUNIT_ASSERT_EQUAL(std::string("aria2.sourceforge.jp"), sfjp->getDomain()); + CPPUNIT_ASSERT(sfjp->getHostOnly()); + CPPUNIT_ASSERT_EQUAL(std::string("/profile"), sfjp->getPath()); + CPPUNIT_ASSERT(sfjp->getSecure()); - const Cookie& localnet = cookies[2]; - CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), localnet.getDomain()); - CPPUNIT_ASSERT(sfjp.getHostOnly()); - CPPUNIT_ASSERT_EQUAL((time_t)3000, localnet.getLastAccessTime()); - CPPUNIT_ASSERT_EQUAL((time_t)3000, localnet.getCreationTime()); + auto& localnet = cookies[2]; + CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), localnet->getDomain()); + CPPUNIT_ASSERT(localnet->getHostOnly()); + CPPUNIT_ASSERT_EQUAL((time_t)3000, localnet->getLastAccessTime()); + CPPUNIT_ASSERT_EQUAL((time_t)3000, localnet->getCreationTime()); } } // namespace aria2 diff --git a/test/TestUtil.cc b/test/TestUtil.cc index 74d2800c..f3ca8e03 100644 --- a/test/TestUtil.cc +++ b/test/TestUtil.cc @@ -50,7 +50,7 @@ std::string readFile(const std::string& path) return ss.str(); } -Cookie createCookie +std::unique_ptr createCookie (const std::string& name, const std::string& value, const std::string& domain, @@ -58,11 +58,11 @@ Cookie createCookie const std::string& path, bool secure) { - return Cookie + return make_unique (name, value, 0, false, domain, hostOnly, path, secure, false, 0); } -Cookie createCookie +std::unique_ptr createCookie (const std::string& name, const std::string& value, time_t expiryTime, @@ -71,7 +71,7 @@ Cookie createCookie const std::string& path, bool secure) { - return Cookie + return make_unique (name, value, expiryTime, true, domain, hostOnly, path, secure, false, 0); } diff --git a/test/TestUtil.h b/test/TestUtil.h index 51bff38d..b1e95ad8 100644 --- a/test/TestUtil.h +++ b/test/TestUtil.h @@ -21,17 +21,17 @@ std::string readFile(const std::string& path); class CookieSorter { public: - bool operator()(const Cookie& lhs, const Cookie& rhs) const + bool operator()(const Cookie* lhs, const Cookie* rhs) const { - if(lhs.getDomain() == rhs.getDomain()) { - return lhs.getName() < rhs.getName(); + if(lhs->getDomain() == rhs->getDomain()) { + return lhs->getName() < rhs->getName(); } else { - return lhs.getDomain() < rhs.getDomain(); + return lhs->getDomain() < rhs->getDomain(); } } }; -Cookie createCookie +std::unique_ptr createCookie (const std::string& name, const std::string& value, const std::string& domain, @@ -39,7 +39,7 @@ Cookie createCookie const std::string& path, bool secure); -Cookie createCookie +std::unique_ptr createCookie (const std::string& name, const std::string& value, time_t expiryTime, @@ -75,4 +75,17 @@ std::shared_ptr createRequestGroup(int32_t pieceLength, std::shared_ptr createDownloadResult (error_code::Value result, const std::string& uri); +namespace { +template +bool derefFind(const V& v, const T& t) +{ + for(auto i : v) { + if(*i == *t) { + return true; + } + } + return false; +} +} // namespace + } // namespace aria2