Rewrite CookieStorage

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

View File

@ -43,23 +43,23 @@
namespace aria2 {
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

View File

@ -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<typename InputIterator>
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<typename InputIterator>
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<typename InputIterator>
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<typename InputIterator>
void setPath(InputIterator first, InputIterator last)

View File

@ -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<Cookie>& out,
void DomainNode::findCookie
(std::vector<const Cookie*>& out,
const std::string& requestHost,
const std::string& requestPath,
time_t now, bool secure)
{
for(std::deque<Cookie>::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> cookie, time_t now)
{
using namespace std::placeholders;
setLastAccessTime(now);
std::deque<Cookie>::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<std::deque<std::unique_ptr<Cookie>>>();
cookies_->push_back(std::move(cookie));
return true;
}
}
auto i = std::find_if(std::begin(*cookies_), std::end(*cookies_),
[&](const std::unique_ptr<Cookie>& c)
{
return *c == *cookie;
});
if(i == std::end(*cookies_)) {
if(cookie->isExpired(now)) {
return false;
} else {
if(cookies_->size() >= CookieStorage::MAX_COOKIE_PER_DOMAIN) {
cookies_->erase
(std::remove_if(std::begin(*cookies_), std::end(*cookies_),
std::bind(&Cookie::isExpired, _1, now)),
cookies_.end());
if(cookies_.size() >= CookieStorage::MAX_COOKIE_PER_DOMAIN) {
std::deque<Cookie>::iterator m = std::min_element
(cookies_.begin(), cookies_.end(), LeastRecentAccess<Cookie>());
*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<Cookie>& lhs,
const std::unique_ptr<Cookie>& 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<Cookie>::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<DomainNode> node)
{
auto& res = next_[std::move(label)] = std::move(node);
return res.get();
}
const std::string& DomainNode::getLabel() const
{
return label_;
}
bool DomainNode::getInLru() const
{
return inLru_;
}
void DomainNode::setInLru(bool f)
{
inLru_ = f;
}
CookieStorage::CookieStorage()
: rootNode_{make_unique<DomainNode>("", nullptr)}
{}
namespace {
// 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<std::string> splitDomainLabel(const std::string& domain)
{
if(domains_.size() >= DOMAIN_EVICTION_TRIGGER) {
std::vector<std::shared_ptr<DomainEntry> > evictions(domains_.begin(),
domains_.end());
std::sort(evictions.begin(), evictions.end(),
LeastRecentAccess<DomainEntry>());
size_t delnum = (size_t)(evictions.size()*DOMAIN_EVICTION_RATE);
domains_.clear();
domains_.insert(evictions.begin()+delnum, evictions.end());
}
std::shared_ptr<DomainEntry> v(new DomainEntry(cookie.getDomain()));
DomainEntrySet::iterator i = domains_.lower_bound(v);
bool added = false;
if(i != domains_.end() && *(*i) == *v) {
added = (*i)->addCookie(cookie, now);
auto labels = std::vector<std::string>{};
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> cookie, time_t now)
{
if(lruTracker_.size() >= DOMAIN_EVICTION_TRIGGER) {
auto delnum = size_t(lruTracker_.size()*DOMAIN_EVICTION_RATE);
evictNode(delnum);
}
auto labels = splitDomainLabel(cookie->getDomain());
auto node = rootNode_.get();
for(auto i = labels.rbegin(), eoi = labels.rend(); i != eoi; ++i) {
auto nextNode = node->findNext(*i);
if(nextNode) {
node = nextNode;
} else {
node = node->addNext(*i, make_unique<DomainNode>(*i, node));
}
}
bool ok = node->addCookie(std::move(cookie), now);
if(ok) {
updateLru(node, now);
}
return ok;
}
void CookieStorage::updateLru(DomainNode* node, time_t now)
{
if(node->getInLru()) {
lruTracker_.erase({node->getLruAccessTime(), node});
} else {
node->setInLru(true);
}
node->setLruAccessTime(now);
lruTracker_.insert({node->getLruAccessTime(), node});
}
bool CookieStorage::parseAndStore
@ -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<Cookie>& 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<DomainEntry> 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<DomainEntry> 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<Cookie> CookieStorage::criteriaFind
std::vector<const Cookie*> CookieStorage::criteriaFind
(const std::string& requestHost,
const std::string& requestPath,
time_t now,
bool secure)
{
std::vector<Cookie> res;
auto res = std::vector<const Cookie*>{};
if(requestPath.empty()) {
return res;
}
if(util::isNumericHost(requestHost)) {
searchCookieByDomainSuffix
(res, requestHost, requestHost, requestPath, now, secure);
} else {
std::vector<Scip> levels;
util::splitIter(requestHost.begin(), requestHost.end(),
std::back_inserter(levels), '.');
std::string domain;
for(std::vector<Scip>::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<CookiePathDivider> 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<CookiePathDivider>{};
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<Cookie> 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<Cookie> 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>
(aria2::CookieStorage::DomainEntry& a,
aria2::CookieStorage::DomainEntry& b)
{
a.swap(b);
}
} // namespace std

View File

@ -2,7 +2,7 @@
/*
* aria2 - The high speed download utility
*
* 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 <vector>
#include <set>
#include <algorithm>
#include <unordered_map>
#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<const Cookie*>& out,
const std::string& requestHost,
const std::string& requestPath,
time_t now, bool secure);
// Returns the number of cookies this node has.
size_t countCookie() const;
// Add |cookie| using update time |now|. Returns true if the
// function succeeds.
bool addCookie(std::unique_ptr<Cookie> cookie, time_t now);
// Sets the last access time of this node.
void setLastAccessTime(time_t lastAccessTime);
// Returns the last access time of this node.
time_t getLastAccessTime() const;
// Sets the time |t| as a time used as key in LRU tracker.
void setLruAccessTime(time_t t);
time_t getLruAccessTime() const;
bool writeCookie(BufferedFile& fp) const;
// Returns true if this node contains the |cookie|.
bool contains(const Cookie& cookie) const;
// Returns true if this node contains no cookie.
bool empty() const;
// Returns true if this node has any next nodes.
bool hasNext() const;
// Returns the parent node. If this is the root node, returns
// nullptr.
DomainNode* getParent() const;
// Removes the child node |node|. Nothing happens if |node| is not a
// child of this node.
void removeNode(DomainNode* node);
// Returns the child node having label |label. Returns nullptr if
// there is no such node.
DomainNode* findNext(const std::string& label) const;
// Add the |node| as a child using label |label and returns the raw
// pointer of |node|.
DomainNode* addNext(std::string label, std::unique_ptr<DomainNode> node);
// Returns the |label|.
const std::string& getLabel() const;
// Deletes all cookies this node has.
void clearCookie();
// Returns value set by setInLru(). This is typically used to know
// this node is tracked by LRU tracker or not.
bool getInLru() const;
void setInLru(bool f);
template<typename OutputIterator>
OutputIterator dumpCookie(OutputIterator out) const
{
if(cookies_) {
for(auto& c : *cookies_) {
out++ = c.get();
}
}
return out;
}
private:
std::string label_;
DomainNode* parent_;
time_t lastAccessTime_;
time_t lruAccessTime_;
bool inLru_;
std::unique_ptr<std::deque<std::unique_ptr<Cookie>>> cookies_;
// domain label string to DomainNode
// e.g. net, sourceforge
// For numerical addresses, this is address itself.
// e.g. 192.168.0.1
std::unordered_map<std::string, std::unique_ptr<DomainNode>> next_;
};
class CookieStorage {
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<Cookie> cookies_;
public:
DomainEntry(const std::string& domain);
DomainEntry(const DomainEntry& c);
~DomainEntry();
void swap(DomainEntry& c);
DomainEntry& operator=(const DomainEntry& c);
const std::string& getKey() const
{
return key_;
}
void findCookie
(std::vector<Cookie>& out,
const std::string& requestHost,
const std::string& requestPath,
time_t now, bool secure);
size_t countCookie() const;
bool addCookie(const Cookie& cookie, time_t now);
void setLastAccessTime(time_t lastAccessTime)
{
lastAccessTime_ = lastAccessTime;
}
time_t getLastAccessTime() const
{
return lastAccessTime_;
}
bool writeCookie(BufferedFile& fp) const;
bool contains(const Cookie& cookie) const;
template<typename OutputIterator>
OutputIterator dumpCookie(OutputIterator out) const
{
return std::copy(cookies_.begin(), cookies_.end(), out);
}
bool operator==(const DomainEntry& de) const;
bool operator<(const DomainEntry& de) const;
};
private:
typedef std::set<std::shared_ptr<DomainEntry>,
DerefLess<std::shared_ptr<DomainEntry> > > DomainEntrySet;
DomainEntrySet domains_;
// typedef std::set<std::shared_ptr<DomainEntry>,
// DerefLess<std::shared_ptr<DomainEntry> > > DomainEntrySet;
// DomainEntrySet domains_;
template<typename InputIterator>
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> 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<Cookie> criteriaFind(const std::string& requestHost,
const std::string& requestPath,
time_t now, bool secure);
std::vector<const Cookie*>
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<Cookie>& out,
const std::string& domain,
const std::string& requestHost,
const std::string& requestPath,
time_t now, bool secure);
template<typename OutputIterator>
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<typename InputIterator>
void storeCookies(InputIterator first, InputIterator last, time_t now)
{
for(; first != last; ++first) {
store(*first, now);
}
}
void updateLru(DomainNode* node, time_t now);
// rootNode_ is a root node of tree structure of reversed domain
// labels. rootNode_ always contans no cookie. It has the child
// nodes of the top level domain label (e.g., net, com and org). And
// those top level domain nodes have 2nd doman label (e.g.,
// sourcforge, github), and so on. The numeric host name are always
// stored as a child node of rootNode_. So the domain name of a
// paricular node is constructed as follows. First traverse the
// target node from root node. The concatenation of the visited
// node's label in the reverse order, delimited by ".", is the
std::unique_ptr<DomainNode> rootNode_;
// This object tracks the node which has cookies or it once had. The
// order is sorted by the least recent updated node first. This
// object does not track the node which has not contan cookie. For
// example, adding cookies in aria2.sourceforge.net, and no node
// labeled "sourceforge" is present, only node labelded "aria2" is
// tracked and node labeled "sourceforge" and "net" are not.
std::set<std::pair<time_t, DomainNode*>> lruTracker_;
};
} // namespace aria2
namespace std {
template<>
void swap<aria2::CookieStorage::DomainEntry>
(aria2::CookieStorage::DomainEntry& a,
aria2::CookieStorage::DomainEntry& b);
} // namespace std
#endif // D_COOKIE_STORAGE_H

View File

@ -234,13 +234,11 @@ std::string HttpRequest::createRequest()
std::string cookiesValue;
std::string path = getDir();
path += getFile();
std::vector<Cookie> cookies =
cookieStorage_->criteriaFind(getHost(), path,
Time().getTime(),
getProtocol() == "https");
for(std::vector<Cookie>::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()) {

View File

@ -54,58 +54,59 @@ NsCookieParser::NsCookieParser() {}
NsCookieParser::~NsCookieParser() {}
namespace {
bool parseNsCookie
(Cookie& cookie, const std::string& cookieStr, time_t creationTime)
std::unique_ptr<Cookie> parseNsCookie
(const std::string& cookieStr, time_t creationTime)
{
std::vector<Scip> vs;
util::splitIter(cookieStr.begin(), cookieStr.end(), std::back_inserter(vs),
'\t', true);
if(vs.size() < 6) {
return false;
return std::unique_ptr<Cookie>{};
}
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<Cookie>{};
}
int64_t expiryTime;
if(!util::parseLLIntNoThrow(expiryTime,
std::string(vs[4].first, vs[4].second))) {
return false;
return std::unique_ptr<Cookie>{};
}
if(std::numeric_limits<time_t>::max() < expiryTime) {
expiryTime = std::numeric_limits<time_t>::max();
} else if(std::numeric_limits<time_t>::min() > expiryTime) {
expiryTime = std::numeric_limits<time_t>::min();
}
cookie.setName(vs[5].first, vs[5].second);
auto cookie = make_unique<Cookie>();
cookie->setName(vs[5].first, vs[5].second);
if(vs.size() >= 7) {
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<time_t>::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<Cookie> NsCookieParser::parse
std::vector<std::unique_ptr<Cookie>> 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<Cookie> cookies;
std::vector<std::unique_ptr<Cookie>> cookies;
while(1) {
std::string line = fp.getLine();
if(line.empty()) {
@ -120,9 +121,9 @@ std::vector<Cookie> 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;

View File

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

View File

@ -102,8 +102,8 @@ int cookieRowMapper(void* data, int columns, char** values, char** names)
if(columns != 7 || !values[0] || !values[1] || !values[4]) {
return 0;
}
std::vector<Cookie>& cookies =
*reinterpret_cast<std::vector<Cookie>*>(data);
std::vector<std::unique_ptr<Cookie>>& cookies =
*reinterpret_cast<std::vector<std::unique_ptr<Cookie>>*>(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<Cookie>
(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<Cookie>& cookies)
std::vector<std::unique_ptr<Cookie>> Sqlite3CookieParser::parse()
{
if(!db_) {
throw DL_ABORT_EX(fmt("SQLite3 database is not opened."));
}
std::vector<Cookie> tcookies;
auto tcookies = std::vector<std::unique_ptr<Cookie>>{};
char* sqlite3ErrMsg = 0;
int ret = sqlite3_exec(db_, getQuery(), cookieRowMapper,
&tcookies, &sqlite3ErrMsg);
@ -157,7 +157,7 @@ void Sqlite3CookieParser::parse(std::vector<Cookie>& cookies)
throw DL_ABORT_EX
(fmt("Failed to read SQLite3 database: %s", errMsg.c_str()));
}
cookies.swap(tcookies);
return tcookies;
}
} // namespace aria2

View File

@ -39,6 +39,7 @@
#include <string>
#include <vector>
#include <memory>
#include <sqlite3.h>
@ -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<Cookie>& cookies);
std::vector<std::unique_ptr<Cookie>> parse();
protected:
// Returns SQL select statement to get 1 record of cookie. The sql
// must return 6 columns in the following order: host, path,

View File

@ -216,9 +216,8 @@ bool parseDate
return time != -1;
}
bool parse
(Cookie& cookie,
const std::string& cookieStr,
std::unique_ptr<Cookie> 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<Cookie>{};
}
std::pair<std::string::const_iterator,
std::string::const_iterator> p =
util::stripIter(cookieStr.begin(), eq);
if(p.first == p.second) {
return false;
return std::unique_ptr<Cookie>{};
}
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<Cookie>{};
}
} else if(util::strieq(p.first, p.second, "max-age")) {
if(attrp.first == attrp.second ||
(!in(static_cast<unsigned char>(*attrp.first), 0x30u, 0x39u) &&
*attrp.first != '-')) {
return false;
return std::unique_ptr<Cookie>{};
}
for(std::string::const_iterator s = attrp.first+1,
eos = attrp.second; s != eos; ++s) {
if(!in(static_cast<unsigned char>(*s), 0x30u, 0x39u)) {
return false;
return std::unique_ptr<Cookie>{};
}
}
int64_t delta;
@ -306,17 +305,17 @@ bool parse
}
}
} else {
return false;
return std::unique_ptr<Cookie>{};
}
} else if(util::strieq(p.first, p.second, "domain")) {
if(attrp.first == attrp.second) {
return false;
return std::unique_ptr<Cookie>{};
}
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<Cookie>{};
}
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<Cookie>{};
}
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>();
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

View File

@ -38,6 +38,7 @@
#include "common.h"
#include <string>
#include <memory>
#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<Cookie> parse
(const std::string& cookieStr,
const std::string& requestHost,
const std::string& defaultPath,
time_t creationTime);

View File

@ -88,145 +88,145 @@ void CookieHelperTest::testParse()
{
std::string str = "ID=123456789; expires=Sun, 10-Jun-2007 11:00:00 GMT;"
"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<time_t>::max(), c.getExpiryTime());
CPPUNIT_ASSERT(c.getPersistent());
auto c = cookie::parse(str, "localhost", "/", creationDate);
CPPUNIT_ASSERT(c);
CPPUNIT_ASSERT_EQUAL(std::numeric_limits<time_t>::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());
}
}

View File

@ -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<Cookie>& 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<Cookie>& cookies, const CookieStorage& st)
namespace {
std::vector<const Cookie*> dumpCookie(const CookieStorage& st)
{
st.dumpCookie(std::back_inserter(cookies));
std::sort(cookies.begin(), cookies.end(), CookieSorter());
auto res = std::vector<const Cookie*>{};
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<Cookie> 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<Cookie> 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<Cookie> 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<Cookie> dlAria2 = st.criteriaFind("dl.aria2.org", "/", 0, false);
auto dlAria2 = st.criteriaFind("dl.aria2.org", "/", 0, false);
CPPUNIT_ASSERT_EQUAL((size_t)1, dlAria2.size());
CPPUNIT_ASSERT_EQUAL(std::string("alpha"), dlAria2[0].getName());
CPPUNIT_ASSERT_EQUAL(std::string("alpha"), dlAria2[0]->getName());
std::vector<Cookie> tailmatchAria2 = st.criteriaFind("myaria2.org", "/", 0,
false);
auto tailmatchAria2 = st.criteriaFind("myaria2.org", "/", 0, false);
CPPUNIT_ASSERT(tailmatchAria2.empty());
std::vector<Cookie> 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<Cookie> 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<Cookie> 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<Cookie> 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<Cookie> cookies = st.criteriaFind("host", "/foo/bar", 0, false);
auto cookies = st.criteriaFind("host", "/foo/bar", 0, false);
CPPUNIT_ASSERT_EQUAL((size_t)4, cookies.size());
CPPUNIT_ASSERT_EQUAL(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<Cookie> 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<time_t>::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<time_t>::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<Cookie> 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<Cookie> 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

View File

@ -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

View File

@ -368,6 +368,13 @@ void HttpRequestTest::testCreateRequest_ftp()
CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());
}
template<typename InputIterator>
void foo(CookieStorage& st, InputIterator first, InputIterator last, time_t t)
{
for(; first != last; ++first) {
st.store(*first, t);
}
}
void HttpRequestTest::testCreateRequest_with_cookie()
{
auto request = std::make_shared<Request>();
@ -376,19 +383,17 @@ void HttpRequestTest::testCreateRequest_with_cookie()
auto segment = std::make_shared<PiecedSegment>(1024*1024, p);
auto fileEntry = std::make_shared<FileEntry>("file", 1024*1024*10, 0);
std::vector<Cookie> 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;

View File

@ -4,6 +4,7 @@
#include <cppunit/extensions/HelperMacros.h>
#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<Cookie> cookies;
auto cookies = std::vector<const Cookie*>{};
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()

View File

@ -33,58 +33,58 @@ void NsCookieParserTest::testParse()
{
NsCookieParser parser;
time_t now = 0;
std::vector<Cookie> cookies = parser.parse(A2_TEST_DIR"/nscookietest.txt", now);
auto cookies = parser.parse(A2_TEST_DIR"/nscookietest.txt", now);
CPPUNIT_ASSERT_EQUAL((size_t)5, cookies.size());
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<time_t>::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<time_t>::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()

View File

@ -35,55 +35,53 @@ CPPUNIT_TEST_SUITE_REGISTRATION(Sqlite3CookieParserTest);
void Sqlite3CookieParserTest::testMozParse()
{
Sqlite3MozCookieParser parser(A2_TEST_DIR"/cookies.sqlite");
std::vector<Cookie> 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<Cookie> 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<Cookie> 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<Cookie> 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

View File

@ -50,7 +50,7 @@ std::string readFile(const std::string& path)
return ss.str();
}
Cookie createCookie
std::unique_ptr<Cookie> 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<Cookie>
(name, value, 0, false, domain, hostOnly, path, secure, false, 0);
}
Cookie createCookie
std::unique_ptr<Cookie> 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<Cookie>
(name, value, expiryTime, true, domain, hostOnly, path, secure, false, 0);
}

View File

@ -21,17 +21,17 @@ std::string readFile(const std::string& path);
class CookieSorter {
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<Cookie> 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<Cookie> createCookie
(const std::string& name,
const std::string& value,
time_t expiryTime,
@ -75,4 +75,17 @@ std::shared_ptr<RequestGroup> createRequestGroup(int32_t pieceLength,
std::shared_ptr<DownloadResult> createDownloadResult
(error_code::Value result, const std::string& uri);
namespace {
template<typename V, typename T>
bool derefFind(const V& v, const T& t)
{
for(auto i : v) {
if(*i == *t) {
return true;
}
}
return false;
}
} // namespace
} // namespace aria2