mirror of https://github.com/aria2/aria2
2010-01-28 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Rewritten Cookie storage. * src/Cookie.cc * src/Cookie.h * src/CookieParser.cc * src/CookieStorage.cc * src/CookieStorage.h * src/a2functional.h * test/CookieParserTest.cc * test/CookieStorageTest.cc * test/CookieTest.cc * test/HttpResponseTest.cc * test/TestUtil.h * test/a2functionalTest.ccpull/1/head
parent
60c16887e6
commit
4043b6ccae
16
ChangeLog
16
ChangeLog
|
@ -1,3 +1,19 @@
|
|||
2010-01-28 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
|
||||
|
||||
Rewritten Cookie storage.
|
||||
* src/Cookie.cc
|
||||
* src/Cookie.h
|
||||
* src/CookieParser.cc
|
||||
* src/CookieStorage.cc
|
||||
* src/CookieStorage.h
|
||||
* src/a2functional.h
|
||||
* test/CookieParserTest.cc
|
||||
* test/CookieStorageTest.cc
|
||||
* test/CookieTest.cc
|
||||
* test/HttpResponseTest.cc
|
||||
* test/TestUtil.h
|
||||
* test/a2functionalTest.cc
|
||||
|
||||
2010-01-26 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
|
||||
|
||||
Handle redirected URI which is not properly percent encoded.
|
||||
|
|
|
@ -54,7 +54,7 @@ static std::string prependDotIfNotExists(const std::string& domain)
|
|||
return (!domain.empty() && domain[0] != '.') ? "."+domain : domain;
|
||||
}
|
||||
|
||||
static std::string normalizeDomain(const std::string& domain)
|
||||
std::string Cookie::normalizeDomain(const std::string& domain)
|
||||
{
|
||||
if(domain.empty() || util::isNumbersAndDotsNotation(domain)) {
|
||||
return domain;
|
||||
|
@ -79,7 +79,9 @@ Cookie::Cookie(const std::string& name,
|
|||
_expiry(expiry),
|
||||
_path(path),
|
||||
_domain(normalizeDomain(domain)),
|
||||
_secure(secure) {}
|
||||
_secure(secure),
|
||||
_creationTime(time(0)),
|
||||
_lastAccess(_creationTime) {}
|
||||
|
||||
Cookie::Cookie(const std::string& name,
|
||||
const std::string& value,
|
||||
|
@ -91,9 +93,11 @@ Cookie::Cookie(const std::string& name,
|
|||
_expiry(0),
|
||||
_path(path),
|
||||
_domain(normalizeDomain(domain)),
|
||||
_secure(secure) {}
|
||||
_secure(secure),
|
||||
_creationTime(time(0)),
|
||||
_lastAccess(_creationTime) {}
|
||||
|
||||
Cookie::Cookie():_expiry(0), _secure(false) {}
|
||||
Cookie::Cookie():_expiry(0), _secure(false), _lastAccess(time(0)) {}
|
||||
|
||||
Cookie::~Cookie() {}
|
||||
|
||||
|
@ -142,9 +146,9 @@ bool Cookie::match(const std::string& requestHost,
|
|||
const std::string& requestPath,
|
||||
time_t date, bool secure) const
|
||||
{
|
||||
std::string normReqHost = normalizeDomain(requestHost);
|
||||
if((secure || (!_secure && !secure)) &&
|
||||
domainMatch(normReqHost, _domain) &&
|
||||
(requestHost == _domain || // For default domain or IP address
|
||||
domainMatch(normalizeDomain(requestHost), _domain)) &&
|
||||
pathInclude(requestPath, _path) &&
|
||||
(isSessionCookie() || (date < _expiry))) {
|
||||
return true;
|
||||
|
@ -156,35 +160,37 @@ bool Cookie::match(const std::string& requestHost,
|
|||
bool Cookie::validate(const std::string& requestHost,
|
||||
const std::string& requestPath) const
|
||||
{
|
||||
std::string normReqHost = normalizeDomain(requestHost);
|
||||
// If _domain is IP address, then it should be matched to requestHost.
|
||||
// In other words, _domain == normReqHost
|
||||
if(normReqHost != _domain) {
|
||||
// domain must start with '.'
|
||||
if(*_domain.begin() != '.') {
|
||||
return false;
|
||||
// If _domain doesn't start with "." or it is IP address, then it
|
||||
// must equal to requestHost. Otherwise, do domain tail match.
|
||||
if(requestHost != _domain) {
|
||||
std::string normReqHost = normalizeDomain(requestHost);
|
||||
if(normReqHost != _domain) {
|
||||
// domain must start with '.'
|
||||
if(*_domain.begin() != '.') {
|
||||
return false;
|
||||
}
|
||||
// domain must not end with '.'
|
||||
if(*_domain.rbegin() == '.') {
|
||||
return false;
|
||||
}
|
||||
// domain must include at least one embeded '.'
|
||||
if(_domain.size() < 4 || _domain.find(".", 1) == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
if(!util::endsWith(normReqHost, _domain)) {
|
||||
return false;
|
||||
}
|
||||
// From RFC2965 3.3.2 Rejecting Cookies
|
||||
// * The request-host is a HDN (not IP address) and has the form HD,
|
||||
// where D is the value of the Domain attribute, and H is a string
|
||||
// that contains one or more dots.
|
||||
size_t dotCount = std::count(normReqHost.begin(),
|
||||
normReqHost.begin()+
|
||||
(normReqHost.size()-_domain.size()), '.');
|
||||
if(dotCount > 1 || (dotCount == 1 && normReqHost[0] != '.')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// domain must not end with '.'
|
||||
if(*_domain.rbegin() == '.') {
|
||||
return false;
|
||||
}
|
||||
// domain must include at least one embeded '.'
|
||||
if(_domain.size() < 4 || _domain.find(".", 1) == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
if(!util::endsWith(normReqHost, _domain)) {
|
||||
return false;
|
||||
}
|
||||
// From RFC2965 3.3.2 Rejecting Cookies
|
||||
// * The request-host is a HDN (not IP address) and has the form HD,
|
||||
// where D is the value of the Domain attribute, and H is a string
|
||||
// that contains one or more dots.
|
||||
size_t dotCount = std::count(normReqHost.begin(),
|
||||
normReqHost.begin()+
|
||||
(normReqHost.size()-_domain.size()), '.');
|
||||
if(dotCount > 1 || (dotCount == 1 && normReqHost[0] != '.')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(requestPath != _path) {
|
||||
// From RFC2965 3.3.2 Rejecting Cookies
|
||||
|
@ -230,4 +236,16 @@ std::string Cookie::toNsCookieFormat() const
|
|||
return ss.str();
|
||||
}
|
||||
|
||||
void Cookie::markOriginServerOnly()
|
||||
{
|
||||
if(util::startsWith(_domain, A2STR::DOT_C)) {
|
||||
_domain.erase(_domain.begin(), _domain.begin()+1);
|
||||
}
|
||||
}
|
||||
|
||||
void Cookie::updateLastAccess()
|
||||
{
|
||||
_lastAccess = time(0);
|
||||
}
|
||||
|
||||
} // namespace aria2
|
||||
|
|
20
src/Cookie.h
20
src/Cookie.h
|
@ -52,6 +52,8 @@ private:
|
|||
std::string _path;
|
||||
std::string _domain;
|
||||
bool _secure;
|
||||
time_t _creationTime;
|
||||
time_t _lastAccess;
|
||||
public:
|
||||
/*
|
||||
* If expires = 0 is given, then the cookie becomes session cookie.
|
||||
|
@ -127,6 +129,24 @@ public:
|
|||
}
|
||||
|
||||
std::string toNsCookieFormat() const;
|
||||
|
||||
// Makes this Cookie only sent to the origin server. This function
|
||||
// removes first "." from _domain if _domain starts with ".".
|
||||
void markOriginServerOnly();
|
||||
|
||||
time_t getCreationTime() const
|
||||
{
|
||||
return _creationTime;
|
||||
}
|
||||
|
||||
void updateLastAccess();
|
||||
|
||||
time_t getLastAccess() const
|
||||
{
|
||||
return _lastAccess;
|
||||
}
|
||||
|
||||
static std::string normalizeDomain(const std::string& domain);
|
||||
};
|
||||
|
||||
typedef std::deque<Cookie> Cookies;
|
||||
|
|
|
@ -71,26 +71,38 @@ Cookie CookieParser::parse(const std::string& cookieStr, const std::string& defa
|
|||
util::split(nameValue, terms.front(), '=');
|
||||
|
||||
std::map<std::string, std::string> values;
|
||||
values[C_DOMAIN] = defaultDomain;
|
||||
values[C_PATH] = defaultPath;
|
||||
|
||||
for(std::vector<std::string>::iterator itr = terms.begin()+1;
|
||||
itr != terms.end(); ++itr) {
|
||||
std::pair<std::string, std::string> nv;
|
||||
util::split(nv, *itr, '=');
|
||||
values[nv.first] = nv.second;
|
||||
}
|
||||
bool useDefaultDomain = false;
|
||||
std::map<std::string, std::string>::iterator mitr;
|
||||
mitr = values.find(C_DOMAIN);
|
||||
if(mitr == values.end() || (*mitr).second.empty()) {
|
||||
useDefaultDomain = true;
|
||||
values[C_DOMAIN] = defaultDomain;
|
||||
}
|
||||
mitr = values.find(C_PATH);
|
||||
if(mitr == values.end() || (*mitr).second.empty()) {
|
||||
values[C_PATH] = defaultPath;
|
||||
}
|
||||
time_t expiry = 0;
|
||||
if(values.find(C_EXPIRES) != values.end()) {
|
||||
if(values.count(C_EXPIRES)) {
|
||||
Time expiryTime = Time::parseHTTPDate(values[C_EXPIRES]);
|
||||
if(expiryTime.good()) {
|
||||
expiry = expiryTime.getTime();
|
||||
}
|
||||
}
|
||||
return Cookie(nameValue.first, nameValue.second,
|
||||
Cookie cookie(nameValue.first, nameValue.second,
|
||||
expiry,
|
||||
values[C_PATH], values[C_DOMAIN],
|
||||
values.find(C_SECURE) != values.end());
|
||||
if(useDefaultDomain) {
|
||||
cookie.markOriginServerOnly();
|
||||
}
|
||||
return cookie;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -45,28 +45,40 @@
|
|||
#include "StringFormat.h"
|
||||
#include "NsCookieParser.h"
|
||||
#include "File.h"
|
||||
#include "a2functional.h"
|
||||
#ifdef HAVE_SQLITE3
|
||||
# include "Sqlite3MozCookieParser.h"
|
||||
#endif // HAVE_SQLITE3
|
||||
|
||||
namespace aria2 {
|
||||
|
||||
CookieStorage::CookieStorage():_logger(LogFactory::getInstance()) {}
|
||||
|
||||
CookieStorage::~CookieStorage() {}
|
||||
|
||||
bool CookieStorage::store(const Cookie& cookie)
|
||||
CookieStorage::DomainEntry::DomainEntry
|
||||
(const std::string& domain):_key(domain)
|
||||
{
|
||||
if(!cookie.good()) {
|
||||
return false;
|
||||
}
|
||||
std::reverse(_key.begin(), _key.end());
|
||||
}
|
||||
|
||||
void CookieStorage::DomainEntry::updateLastAccess()
|
||||
{
|
||||
_lastAccess = time(0);
|
||||
}
|
||||
|
||||
bool CookieStorage::DomainEntry::addCookie(const Cookie& cookie)
|
||||
{
|
||||
updateLastAccess();
|
||||
std::deque<Cookie>::iterator i = std::find(_cookies.begin(), _cookies.end(),
|
||||
cookie);
|
||||
if(i == _cookies.end()) {
|
||||
if(cookie.isExpired()) {
|
||||
return false;
|
||||
} else {
|
||||
_cookies.push_back(cookie);
|
||||
if(_cookies.size() >= CookieStorage::MAX_COOKIE_PER_DOMAIN) {
|
||||
std::deque<Cookie>::iterator m = std::min_element
|
||||
(_cookies.begin(), _cookies.end(), LeastRecentAccess<Cookie>());
|
||||
*m = cookie;
|
||||
} else {
|
||||
_cookies.push_back(cookie);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} else if(cookie.isExpired()) {
|
||||
|
@ -78,6 +90,55 @@ bool CookieStorage::store(const Cookie& cookie)
|
|||
}
|
||||
}
|
||||
|
||||
bool CookieStorage::DomainEntry::contains(const Cookie& cookie) const
|
||||
{
|
||||
return std::find(_cookies.begin(), _cookies.end(), cookie) != _cookies.end();
|
||||
}
|
||||
|
||||
void CookieStorage::DomainEntry::writeCookie(std::ostream& o) const
|
||||
{
|
||||
for(std::deque<Cookie>::const_iterator i = _cookies.begin();
|
||||
i != _cookies.end(); ++i) {
|
||||
o << (*i).toNsCookieFormat() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
CookieStorage::CookieStorage():_logger(LogFactory::getInstance()) {}
|
||||
|
||||
CookieStorage::~CookieStorage() {}
|
||||
|
||||
// See CookieStorageTest::testDomainIsFull() in CookieStorageTest.cc
|
||||
static const size_t DOMAIN_EVICTION_TRIGGER = 600;
|
||||
|
||||
static const double DOMAIN_EVICTION_RATE = 0.1;
|
||||
|
||||
bool CookieStorage::store(const Cookie& cookie)
|
||||
{
|
||||
if(!cookie.good()) {
|
||||
return false;
|
||||
}
|
||||
if(_domains.size() >= DOMAIN_EVICTION_TRIGGER) {
|
||||
std::sort(_domains.begin(), _domains.end(),
|
||||
LeastRecentAccess<DomainEntry>());
|
||||
size_t delnum = _domains.size()*DOMAIN_EVICTION_RATE;
|
||||
_domains.erase(_domains.begin(), _domains.begin()+delnum);
|
||||
std::sort(_domains.begin(), _domains.end());
|
||||
}
|
||||
DomainEntry v(cookie.getDomain());
|
||||
std::deque<DomainEntry>::iterator i =
|
||||
std::lower_bound(_domains.begin(), _domains.end(), v);
|
||||
bool added = false;
|
||||
if(i != _domains.end() && (*i).getKey() == v.getKey()) {
|
||||
added = (*i).addCookie(cookie);
|
||||
} else {
|
||||
added = v.addCookie(cookie);
|
||||
if(added) {
|
||||
_domains.insert(i, v);
|
||||
}
|
||||
}
|
||||
return added;
|
||||
}
|
||||
|
||||
void CookieStorage::storeCookies(const std::deque<Cookie>& cookies)
|
||||
{
|
||||
for(std::deque<Cookie>::const_iterator i = cookies.begin();
|
||||
|
@ -98,48 +159,138 @@ bool CookieStorage::parseAndStore(const std::string& setCookieString,
|
|||
}
|
||||
}
|
||||
|
||||
class CriteriaMatch:public std::unary_function<Cookie, bool> {
|
||||
private:
|
||||
std::string _requestHost;
|
||||
std::string _requestPath;
|
||||
time_t _date;
|
||||
bool _secure;
|
||||
public:
|
||||
CriteriaMatch(const std::string& requestHost, const std::string& requestPath,
|
||||
time_t date, bool secure):
|
||||
_requestHost(requestHost),
|
||||
_requestPath(requestPath),
|
||||
_date(date),
|
||||
_secure(secure) {}
|
||||
|
||||
bool operator()(const Cookie& cookie) const
|
||||
struct CookiePathDivider {
|
||||
Cookie _cookie;
|
||||
int _pathDepth;
|
||||
CookiePathDivider(const Cookie& cookie):_cookie(cookie)
|
||||
{
|
||||
return cookie.match(_requestHost, _requestPath, _date, _secure);
|
||||
std::vector<std::string> paths;
|
||||
util::split(_cookie.getPath(), std::back_inserter(paths), A2STR::SLASH_C);
|
||||
_pathDepth = paths.size();
|
||||
}
|
||||
};
|
||||
|
||||
class OrderByPathDesc:public std::binary_function<Cookie, Cookie, bool> {
|
||||
class CookiePathDividerConverter {
|
||||
public:
|
||||
bool operator()(const Cookie& lhs, const Cookie& rhs) const
|
||||
CookiePathDivider operator()(const Cookie& cookie) const
|
||||
{
|
||||
return lhs.getPath() > rhs.getPath();
|
||||
return CookiePathDivider(cookie);
|
||||
}
|
||||
|
||||
Cookie operator()(const CookiePathDivider& cookiePathDivider) const
|
||||
{
|
||||
return cookiePathDivider._cookie;
|
||||
}
|
||||
};
|
||||
|
||||
class OrderByPathDepthDesc:public std::binary_function<Cookie, Cookie, bool> {
|
||||
public:
|
||||
bool operator()
|
||||
(const CookiePathDivider& lhs, const CookiePathDivider& rhs) const
|
||||
{
|
||||
// Sort by path-length.
|
||||
//
|
||||
// RFC2965 says: Note that the NAME=VALUE pair for the cookie with
|
||||
// the more specific Path attribute, /acme/ammo, comes before the
|
||||
// one with the less specific Path attribute, /acme. Further note
|
||||
// that the same cookie name appears more than once.
|
||||
//
|
||||
// Netscape spec says: When sending cookies to a server, all
|
||||
// cookies with a more specific path mapping should be sent before
|
||||
// cookies with less specific path mappings. For example, a cookie
|
||||
// "name1=foo" with a path mapping of "/" should be sent after a
|
||||
// cookie "name1=foo2" with a path mapping of "/bar" if they are
|
||||
// both to be sent.
|
||||
int comp = lhs._pathDepth-rhs._pathDepth;
|
||||
if(comp == 0) {
|
||||
return lhs._cookie.getCreationTime() < rhs._cookie.getCreationTime();
|
||||
} else {
|
||||
return comp > 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename DomainInputIterator, typename CookieOutputIterator>
|
||||
static void searchCookieByDomainSuffix
|
||||
(const std::string& domain,
|
||||
DomainInputIterator first, DomainInputIterator last, CookieOutputIterator out,
|
||||
const std::string& requestHost,
|
||||
const std::string& requestPath,
|
||||
time_t date, bool secure)
|
||||
{
|
||||
CookieStorage::DomainEntry v(domain);
|
||||
std::deque<CookieStorage::DomainEntry>::iterator i =
|
||||
std::lower_bound(first, last, v);
|
||||
if(i != last && (*i).getKey() == v.getKey()) {
|
||||
(*i).updateLastAccess();
|
||||
(*i).findCookie(out, requestHost, requestPath, date, secure);
|
||||
}
|
||||
}
|
||||
|
||||
bool CookieStorage::contains(const Cookie& cookie) const
|
||||
{
|
||||
CookieStorage::DomainEntry v(cookie.getDomain());
|
||||
std::deque<CookieStorage::DomainEntry>::const_iterator i =
|
||||
std::lower_bound(_domains.begin(), _domains.end(), v);
|
||||
if(i != _domains.end() && (*i).getKey() == v.getKey()) {
|
||||
return (*i).contains(cookie);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::deque<Cookie> CookieStorage::criteriaFind(const std::string& requestHost,
|
||||
const std::string& requestPath,
|
||||
time_t date, bool secure) const
|
||||
time_t date, bool secure)
|
||||
{
|
||||
std::deque<Cookie> res;
|
||||
std::remove_copy_if(_cookies.begin(), _cookies.end(), std::back_inserter(res),
|
||||
std::not1(CriteriaMatch(requestHost, requestPath, date, secure)));
|
||||
std::sort(res.begin(), res.end(), OrderByPathDesc());
|
||||
bool numericHost = util::isNumbersAndDotsNotation(requestHost);
|
||||
searchCookieByDomainSuffix
|
||||
((!numericHost && requestHost.find(A2STR::DOT_C) == std::string::npos)?
|
||||
requestHost+".local":requestHost,
|
||||
_domains.begin(), _domains.end(),
|
||||
std::back_inserter(res),
|
||||
requestHost, requestPath, date, secure);
|
||||
if(!numericHost) {
|
||||
std::string normRequestHost = Cookie::normalizeDomain(requestHost);
|
||||
std::vector<std::string> domainComponents;
|
||||
util::split(normRequestHost, std::back_inserter(domainComponents),
|
||||
A2STR::DOT_C);
|
||||
if(domainComponents.size() <= 1) {
|
||||
return res;
|
||||
}
|
||||
std::reverse(domainComponents.begin(), domainComponents.end());
|
||||
std::string domain = A2STR::DOT_C;
|
||||
domain += domainComponents[0];
|
||||
for(std::vector<std::string>::const_iterator di =
|
||||
domainComponents.begin()+1; di != domainComponents.end(); ++di) {
|
||||
domain = strconcat(A2STR::DOT_C, *di, domain);
|
||||
const size_t prenum = res.size();
|
||||
searchCookieByDomainSuffix(domain, _domains.begin(), _domains.end(),
|
||||
std::back_inserter(res),
|
||||
normRequestHost, requestPath, date, secure);
|
||||
if(prenum == res.size()) {
|
||||
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());
|
||||
return res;
|
||||
}
|
||||
|
||||
size_t CookieStorage::size() const
|
||||
{
|
||||
return _cookies.size();
|
||||
size_t numCookie = 0;
|
||||
for(std::deque<DomainEntry>::const_iterator i = _domains.begin();
|
||||
i != _domains.end(); ++i) {
|
||||
numCookie += (*i).countCookie();
|
||||
}
|
||||
return numCookie;
|
||||
}
|
||||
|
||||
bool CookieStorage::load(const std::string& filename)
|
||||
|
@ -185,14 +336,9 @@ bool CookieStorage::saveNsFormat(const std::string& filename)
|
|||
filename.c_str(), strerror(errno));
|
||||
return false;
|
||||
}
|
||||
for(std::deque<Cookie>::const_iterator i = _cookies.begin();
|
||||
i != _cookies.end(); ++i) {
|
||||
o << (*i).toNsCookieFormat() << "\n";
|
||||
if(!o) {
|
||||
_logger->error("Failed to save cookies to %s, cause %s",
|
||||
filename.c_str(), strerror(errno));
|
||||
return false;
|
||||
}
|
||||
for(std::deque<DomainEntry>::const_iterator i = _domains.begin();
|
||||
i != _domains.end(); ++i) {
|
||||
(*i).writeCookie(o);
|
||||
}
|
||||
o.flush();
|
||||
if(!o) {
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
|
||||
#include <string>
|
||||
#include <deque>
|
||||
#include <algorithm>
|
||||
|
||||
#include "a2time.h"
|
||||
#include "Cookie.h"
|
||||
|
@ -49,8 +50,96 @@ namespace aria2 {
|
|||
class Logger;
|
||||
|
||||
class CookieStorage {
|
||||
public:
|
||||
|
||||
static const size_t MAX_COOKIE_PER_DOMAIN = 50;
|
||||
|
||||
class FindCookie:public std::unary_function<Cookie&, bool> {
|
||||
private:
|
||||
std::string _requestHost;
|
||||
std::string _requestPath;
|
||||
time_t _date;
|
||||
bool _secure;
|
||||
public:
|
||||
FindCookie(const std::string& requestHost,
|
||||
const std::string& requestPath,
|
||||
time_t date, bool secure):
|
||||
_requestHost(requestHost),
|
||||
_requestPath(requestPath),
|
||||
_date(date),
|
||||
_secure(secure) {}
|
||||
|
||||
bool operator()(Cookie& cookie) const
|
||||
{
|
||||
if(cookie.match(_requestHost, _requestPath, _date, _secure)) {
|
||||
cookie.updateLastAccess();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class DomainEntry {
|
||||
private:
|
||||
std::string _key;
|
||||
|
||||
time_t _lastAccess;
|
||||
|
||||
std::deque<Cookie> _cookies;
|
||||
public:
|
||||
DomainEntry(const std::string& domain);
|
||||
|
||||
const std::string& getKey() const
|
||||
{
|
||||
return _key;
|
||||
}
|
||||
|
||||
template<typename OutputIterator>
|
||||
OutputIterator findCookie
|
||||
(OutputIterator out,
|
||||
const std::string& requestHost,
|
||||
const std::string& requestPath,
|
||||
time_t date, bool secure)
|
||||
{
|
||||
OutputIterator last =
|
||||
std::remove_copy_if
|
||||
(_cookies.begin(), _cookies.end(), out,
|
||||
std::not1(FindCookie(requestHost, requestPath, date, secure)));
|
||||
return last;
|
||||
}
|
||||
|
||||
size_t countCookie() const
|
||||
{
|
||||
return _cookies.size();
|
||||
}
|
||||
|
||||
bool addCookie(const Cookie& cookie);
|
||||
|
||||
void updateLastAccess();
|
||||
|
||||
time_t getLastAccess() const
|
||||
{
|
||||
return _lastAccess;
|
||||
}
|
||||
|
||||
void writeCookie(std::ostream& o) 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
|
||||
{
|
||||
return _key < de._key;
|
||||
}
|
||||
};
|
||||
private:
|
||||
std::deque<Cookie> _cookies;
|
||||
std::deque<DomainEntry> _domains;
|
||||
|
||||
CookieParser _parser;
|
||||
|
||||
|
@ -72,9 +161,11 @@ public:
|
|||
const std::string& requestHost,
|
||||
const std::string& requestPath);
|
||||
|
||||
// Finds cookies matched with given criteria and returns them.
|
||||
// Matched cookies' _lastAccess property is updated.
|
||||
std::deque<Cookie> criteriaFind(const std::string& requestHost,
|
||||
const std::string& requestPath,
|
||||
time_t date, bool secure) const;
|
||||
time_t date, bool secure);
|
||||
|
||||
// Loads Cookies from file denoted by filename. If compiled with
|
||||
// libsqlite3, this method automatically detects the specified file
|
||||
|
@ -88,18 +179,22 @@ public:
|
|||
// this method returns true, otherwise returns false.
|
||||
bool saveNsFormat(const std::string& filename);
|
||||
|
||||
// Returns the number of cookies this object stores.
|
||||
size_t size() const;
|
||||
|
||||
std::deque<Cookie>::const_iterator begin() const
|
||||
{
|
||||
return _cookies.begin();
|
||||
}
|
||||
// Returns true if this object contains a cookie x where x == cookie
|
||||
// satisfies.
|
||||
bool contains(const Cookie& cookie) const;
|
||||
|
||||
std::deque<Cookie>::const_iterator end() const
|
||||
template<typename OutputIterator>
|
||||
OutputIterator dumpCookie(OutputIterator out) const
|
||||
{
|
||||
return _cookies.end();
|
||||
for(std::deque<DomainEntry>::const_iterator i = _domains.begin();
|
||||
i != _domains.end(); ++i) {
|
||||
out = (*i).dumpCookie(out);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace aria2
|
||||
|
|
|
@ -381,6 +381,15 @@ inline void strappend(std::string& base,
|
|||
base += a7; base += a8;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class LeastRecentAccess:public std::binary_function<T, T, bool> {
|
||||
public:
|
||||
bool operator()(const T& lhs, const T& rhs) const
|
||||
{
|
||||
return lhs.getLastAccess() < rhs.getLastAccess();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace aria2
|
||||
|
||||
#endif // _D_A2_FUNCTIONAL_H_
|
||||
|
|
|
@ -43,7 +43,7 @@ void CookieParserTest::testParse()
|
|||
CPPUNIT_ASSERT_EQUAL(std::string("JSESSIONID"), c.getName());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("123456789"), c.getValue());
|
||||
CPPUNIT_ASSERT_EQUAL((time_t)0, c.getExpiry());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(".default.domain"), c.getDomain());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("default.domain"), c.getDomain());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("/default/path"), c.getPath());
|
||||
CPPUNIT_ASSERT_EQUAL(false, c.isSecureCookie());
|
||||
CPPUNIT_ASSERT_EQUAL(true, c.isSessionCookie());
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "CookieParser.h"
|
||||
#include "RecoverableException.h"
|
||||
#include "File.h"
|
||||
#include "TestUtil.h"
|
||||
|
||||
namespace aria2 {
|
||||
|
||||
|
@ -25,12 +26,16 @@ class CookieStorageTest:public CppUnit::TestFixture {
|
|||
CPPUNIT_TEST(testLoad_fileNotfound);
|
||||
CPPUNIT_TEST(testSaveNsFormat);
|
||||
CPPUNIT_TEST(testSaveNsFormat_fail);
|
||||
CPPUNIT_TEST(testCookieIsFull);
|
||||
CPPUNIT_TEST(testDomainIsFull);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
public:
|
||||
void setUp() {}
|
||||
|
||||
void tearDown() {}
|
||||
|
||||
void dumpCookie(std::vector<Cookie>& cookies, const CookieStorage& cs);
|
||||
|
||||
void testStore();
|
||||
void testParseAndStore();
|
||||
void testCriteriaFind();
|
||||
|
@ -39,57 +44,64 @@ public:
|
|||
void testLoad_fileNotfound();
|
||||
void testSaveNsFormat();
|
||||
void testSaveNsFormat_fail();
|
||||
void testCookieIsFull();
|
||||
void testDomainIsFull();
|
||||
};
|
||||
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(CookieStorageTest);
|
||||
|
||||
void CookieStorageTest::dumpCookie
|
||||
(std::vector<Cookie>& cookies, const CookieStorage& st)
|
||||
{
|
||||
st.dumpCookie(std::back_inserter(cookies));
|
||||
std::sort(cookies.begin(), cookies.end(), CookieSorter());
|
||||
}
|
||||
|
||||
void CookieStorageTest::testStore()
|
||||
{
|
||||
CookieStorage st;
|
||||
Cookie goodCookie("k", "v", "/", "localhost", false);
|
||||
CPPUNIT_ASSERT(st.store(goodCookie));
|
||||
CPPUNIT_ASSERT_EQUAL((size_t)1, st.size());
|
||||
CPPUNIT_ASSERT(std::find(st.begin(), st.end(), goodCookie) != st.end());
|
||||
CPPUNIT_ASSERT(st.contains(goodCookie));
|
||||
|
||||
Cookie anotherCookie("k", "v", "/", "mirror", true);
|
||||
CPPUNIT_ASSERT(st.store(anotherCookie));
|
||||
CPPUNIT_ASSERT_EQUAL((size_t)2, st.size());
|
||||
CPPUNIT_ASSERT(std::find(st.begin(), st.end(), anotherCookie) != st.end());
|
||||
CPPUNIT_ASSERT(std::find(st.begin(), st.end(), goodCookie) != st.end());
|
||||
CPPUNIT_ASSERT(st.contains(anotherCookie));
|
||||
CPPUNIT_ASSERT(st.contains(goodCookie));
|
||||
|
||||
Cookie updateGoodCookie("k", "v2", "/", "localhost", false);
|
||||
CPPUNIT_ASSERT(st.store(goodCookie));
|
||||
CPPUNIT_ASSERT_EQUAL((size_t)2, st.size());
|
||||
CPPUNIT_ASSERT(std::find(st.begin(), st.end(), updateGoodCookie) != st.end());
|
||||
CPPUNIT_ASSERT(std::find(st.begin(), st.end(), anotherCookie) != st.end());
|
||||
CPPUNIT_ASSERT(st.contains(updateGoodCookie));
|
||||
CPPUNIT_ASSERT(st.contains(anotherCookie));
|
||||
|
||||
Cookie expireGoodCookie("k", "v3", 1, "/", "localhost", false);
|
||||
CPPUNIT_ASSERT(!st.store(expireGoodCookie));
|
||||
CPPUNIT_ASSERT_EQUAL((size_t)1, st.size());
|
||||
CPPUNIT_ASSERT(std::find(st.begin(), st.end(), anotherCookie) != st.end());
|
||||
CPPUNIT_ASSERT(st.contains(anotherCookie));
|
||||
|
||||
Cookie badCookie("", "", "/", "localhost", false);
|
||||
CPPUNIT_ASSERT(!st.store(badCookie));
|
||||
CPPUNIT_ASSERT_EQUAL((size_t)1, st.size());
|
||||
CPPUNIT_ASSERT(std::find(st.begin(), st.end(), anotherCookie) != st.end());
|
||||
CPPUNIT_ASSERT(st.contains(anotherCookie));
|
||||
|
||||
Cookie fromNumericHost("k", "v", "/", "192.168.1.1", false);
|
||||
CPPUNIT_ASSERT(st.store(fromNumericHost));
|
||||
CPPUNIT_ASSERT_EQUAL((size_t)2, st.size());
|
||||
CPPUNIT_ASSERT(std::find(st.begin(), st.end(), fromNumericHost) != st.end());
|
||||
CPPUNIT_ASSERT(st.contains(fromNumericHost));
|
||||
|
||||
Cookie sessionScopedGoodCookie("k", "v3", 0, "/", "localhost", false);
|
||||
CPPUNIT_ASSERT(st.store(sessionScopedGoodCookie));
|
||||
CPPUNIT_ASSERT_EQUAL((size_t)3, st.size());
|
||||
CPPUNIT_ASSERT(std::find(st.begin(), st.end(),
|
||||
sessionScopedGoodCookie) != st.end());
|
||||
CPPUNIT_ASSERT(st.contains(sessionScopedGoodCookie));
|
||||
|
||||
Cookie sessionScopedGoodCookie2("k2", "v3", "/", "localhost", false);
|
||||
CPPUNIT_ASSERT(st.store(sessionScopedGoodCookie2));
|
||||
CPPUNIT_ASSERT_EQUAL((size_t)4, st.size());
|
||||
CPPUNIT_ASSERT(std::find(st.begin(), st.end(),
|
||||
sessionScopedGoodCookie2) != st.end());
|
||||
CPPUNIT_ASSERT(st.contains(sessionScopedGoodCookie2));
|
||||
}
|
||||
|
||||
void CookieStorageTest::testParseAndStore()
|
||||
|
@ -111,6 +123,10 @@ void CookieStorageTest::testParseAndStore()
|
|||
" expires=Fri, 2038-01-01 00:00:00 GMT; path=/; domain=192.168.1.1;";
|
||||
CPPUNIT_ASSERT(st.parseAndStore(numericHostCookieStr, "192.168.1.1", "/"));
|
||||
|
||||
// No domain and no path are specified.
|
||||
std::string noDomainPathCookieStr = "k=v";
|
||||
CPPUNIT_ASSERT
|
||||
(st.parseAndStore(noDomainPathCookieStr, "aria2.sf.net", "/downloads"));
|
||||
}
|
||||
|
||||
void CookieStorageTest::testCriteriaFind()
|
||||
|
@ -125,6 +141,16 @@ void CookieStorageTest::testCriteriaFind()
|
|||
Cookie echo("echo", "ECHO", "/", "www.aria2.org", false);
|
||||
Cookie foxtrot("foxtrot", "FOXTROT", "/", ".sf.net", false);
|
||||
Cookie golf("golf", "GOLF", "/", "192.168.1.1", false);
|
||||
Cookie hotel1("hotel", "HOTEL1", "/", "samename.x", false);
|
||||
Cookie hotel2("hotel", "HOTEL2", "/hotel", "samename.x", false);
|
||||
Cookie hotel3("hotel", "HOTEL3", "/bar/wine", "samename.x", false);
|
||||
Cookie hotel4("hotel", "HOTEL4", "/bar/", "samename.x", false);
|
||||
Cookie india1("india", "INDIA1", "/foo", "default.domain", false);
|
||||
india1.markOriginServerOnly();
|
||||
Cookie india2("india", "INDIA2", "/", "default.domain", false);
|
||||
Cookie juliet1("juliet", "JULIET1", "/foo", "localhost", false);
|
||||
juliet1.markOriginServerOnly();
|
||||
Cookie juliet2("juliet", "JULIET2", "/", "localhost", false);
|
||||
|
||||
CPPUNIT_ASSERT(st.store(alpha));
|
||||
CPPUNIT_ASSERT(st.store(bravo));
|
||||
|
@ -133,7 +159,15 @@ void CookieStorageTest::testCriteriaFind()
|
|||
CPPUNIT_ASSERT(st.store(echo));
|
||||
CPPUNIT_ASSERT(st.store(foxtrot));
|
||||
CPPUNIT_ASSERT(st.store(golf));
|
||||
|
||||
CPPUNIT_ASSERT(st.store(hotel1));
|
||||
CPPUNIT_ASSERT(st.store(hotel2));
|
||||
CPPUNIT_ASSERT(st.store(hotel3));
|
||||
CPPUNIT_ASSERT(st.store(hotel4));
|
||||
CPPUNIT_ASSERT(st.store(india1));
|
||||
CPPUNIT_ASSERT(st.store(india2));
|
||||
CPPUNIT_ASSERT(st.store(juliet1));
|
||||
CPPUNIT_ASSERT(st.store(juliet2));
|
||||
|
||||
std::deque<Cookie> aria2Slash = st.criteriaFind("www.aria2.org", "/",
|
||||
0, false);
|
||||
CPPUNIT_ASSERT_EQUAL((size_t)2, aria2Slash.size());
|
||||
|
@ -168,6 +202,30 @@ void CookieStorageTest::testCriteriaFind()
|
|||
false);
|
||||
CPPUNIT_ASSERT_EQUAL((size_t)1, numericHostCookies.size());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("golf"), numericHostCookies[0].getName());
|
||||
|
||||
std::deque<Cookie> 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());
|
||||
|
||||
std::deque<Cookie> 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());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("INDIA2"),
|
||||
defaultDomainCookies[1].getValue());
|
||||
|
||||
// localhost.local case
|
||||
std::deque<Cookie> localDomainCookies =
|
||||
st.criteriaFind("localhost", "/foo", 0, false);
|
||||
CPPUNIT_ASSERT_EQUAL((size_t)2, localDomainCookies.size());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("JULIET1"),
|
||||
localDomainCookies[0].getValue());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("JULIET2"),
|
||||
localDomainCookies[1].getValue());
|
||||
}
|
||||
|
||||
void CookieStorageTest::testLoad()
|
||||
|
@ -178,7 +236,10 @@ void CookieStorageTest::testLoad()
|
|||
|
||||
CPPUNIT_ASSERT_EQUAL((size_t)4, st.size());
|
||||
|
||||
Cookie c = *st.begin();
|
||||
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)2147483647, c.getExpiry());
|
||||
|
@ -186,7 +247,15 @@ void CookieStorageTest::testLoad()
|
|||
CPPUNIT_ASSERT_EQUAL(std::string(".localhost.local"), c.getDomain());
|
||||
CPPUNIT_ASSERT(c.isSecureCookie());
|
||||
|
||||
c = *(st.begin()+1);
|
||||
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.getExpiry());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("/"), c.getPath());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(".localhost.local"), c.getDomain());
|
||||
CPPUNIT_ASSERT(!c.isSecureCookie());
|
||||
|
||||
c = cookies[2];
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("passwd"), c.getName());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("secret"), c.getValue());
|
||||
CPPUNIT_ASSERT_EQUAL((time_t)2147483647, c.getExpiry());
|
||||
|
@ -194,21 +263,13 @@ void CookieStorageTest::testLoad()
|
|||
CPPUNIT_ASSERT_EQUAL(std::string(".localhost.local"), c.getDomain());
|
||||
CPPUNIT_ASSERT(!c.isSecureCookie());
|
||||
|
||||
c = *(st.begin()+2);
|
||||
c = cookies[3];
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("TAX"), c.getName());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("1000"), c.getValue());
|
||||
CPPUNIT_ASSERT_EQUAL((time_t)2147483647, c.getExpiry());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("/"), c.getPath());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(".overflow.local"), c.getDomain());
|
||||
CPPUNIT_ASSERT(!c.isSecureCookie());
|
||||
|
||||
c = *(st.begin()+3);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("novalue"), c.getName());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(""), c.getValue());
|
||||
CPPUNIT_ASSERT_EQUAL((time_t)2147483647, c.getExpiry());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("/"), c.getPath());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(".localhost.local"), c.getDomain());
|
||||
CPPUNIT_ASSERT(!c.isSecureCookie());
|
||||
}
|
||||
|
||||
void CookieStorageTest::testLoad_sqlite3()
|
||||
|
@ -217,8 +278,9 @@ void CookieStorageTest::testLoad_sqlite3()
|
|||
#ifdef HAVE_SQLITE3
|
||||
st.load("cookies.sqlite");
|
||||
CPPUNIT_ASSERT_EQUAL((size_t)3, st.size());
|
||||
std::deque<Cookie>::const_iterator i = st.begin();
|
||||
Cookie c = *i++;
|
||||
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)2147483647, c.getExpiry());
|
||||
|
@ -227,7 +289,7 @@ void CookieStorageTest::testLoad_sqlite3()
|
|||
CPPUNIT_ASSERT(c.isSecureCookie());
|
||||
CPPUNIT_ASSERT(!c.isSessionCookie());
|
||||
|
||||
c = *i++;
|
||||
c = cookies[1];
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("uid"), c.getName());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(""), c.getValue());
|
||||
CPPUNIT_ASSERT_EQUAL((time_t)0, c.getExpiry());
|
||||
|
@ -236,7 +298,7 @@ void CookieStorageTest::testLoad_sqlite3()
|
|||
CPPUNIT_ASSERT(!c.isSecureCookie());
|
||||
CPPUNIT_ASSERT(c.isSessionCookie());
|
||||
|
||||
c = *i++;
|
||||
c = cookies[2];
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("foo"), c.getName());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("bar"), c.getValue());
|
||||
CPPUNIT_ASSERT_EQUAL((time_t)2147483647, c.getExpiry());
|
||||
|
@ -258,19 +320,24 @@ void CookieStorageTest::testLoad_fileNotfound()
|
|||
|
||||
void CookieStorageTest::testSaveNsFormat()
|
||||
{
|
||||
// TODO add cookie with default domain
|
||||
std::string filename = "/tmp/aria2_CookieStorageTest_testSaveNsFormat";
|
||||
File(filename).remove();
|
||||
CookieStorage st;
|
||||
st.store(Cookie("uid","tujikawa","/",".domain.org",true));
|
||||
st.store(Cookie("favorite","classic","/config",".domain.org",false));
|
||||
st.store(Cookie("favorite","classic","/config",".domain.org",true));
|
||||
st.store(Cookie("uid","tujikawa","/",".domain.org",false));
|
||||
st.saveNsFormat(filename);
|
||||
CookieStorage loadst;
|
||||
loadst.load(filename);
|
||||
CPPUNIT_ASSERT_EQUAL((size_t)2, loadst.size());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("uid"), (*loadst.begin()).getName());
|
||||
CPPUNIT_ASSERT_EQUAL((time_t)0, (*loadst.begin()).getExpiry());
|
||||
CPPUNIT_ASSERT((*loadst.begin()).isSessionCookie());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("favorite"), (*(loadst.begin()+1)).getName());
|
||||
|
||||
std::vector<Cookie> cookies;
|
||||
dumpCookie(cookies, loadst);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("favorite"), cookies[0].getName());
|
||||
CPPUNIT_ASSERT_EQUAL((time_t)0, cookies[0].getExpiry());
|
||||
CPPUNIT_ASSERT(cookies[0].isSessionCookie());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("uid"), cookies[1].getName());
|
||||
}
|
||||
|
||||
void CookieStorageTest::testSaveNsFormat_fail()
|
||||
|
@ -284,4 +351,26 @@ void CookieStorageTest::testSaveNsFormat_fail()
|
|||
CPPUNIT_ASSERT(!st.saveNsFormat(filename));
|
||||
}
|
||||
|
||||
void CookieStorageTest::testCookieIsFull()
|
||||
{
|
||||
CookieStorage st;
|
||||
for(size_t i = 0; i < CookieStorage::MAX_COOKIE_PER_DOMAIN+1; ++i) {
|
||||
Cookie c("k"+util::itos(i), "v", "/", ".aria2.org", false);
|
||||
st.store(c);
|
||||
}
|
||||
CPPUNIT_ASSERT_EQUAL((size_t)CookieStorage::MAX_COOKIE_PER_DOMAIN, st.size());
|
||||
}
|
||||
|
||||
void CookieStorageTest::testDomainIsFull()
|
||||
{
|
||||
// See DOMAIN_EVICTION_TRIGGER and DOMAIN_EVICTION_RATE in
|
||||
// CookieStorage.cc
|
||||
CookieStorage st;
|
||||
for(size_t i = 0; i < 601; ++i) {
|
||||
Cookie c("k", "v", "/", "domain"+util::itos(i), false);
|
||||
st.store(c);
|
||||
}
|
||||
CPPUNIT_ASSERT_EQUAL((size_t)541, st.size());
|
||||
}
|
||||
|
||||
} // namespace aria2
|
||||
|
|
|
@ -19,6 +19,7 @@ class CookieTest:public CppUnit::TestFixture {
|
|||
CPPUNIT_TEST(testIsExpired);
|
||||
CPPUNIT_TEST(testNormalizeDomain);
|
||||
CPPUNIT_TEST(testToNsCookieFormat);
|
||||
CPPUNIT_TEST(testMarkOriginServerOnly);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
public:
|
||||
void setUp() {}
|
||||
|
@ -31,6 +32,7 @@ public:
|
|||
void testIsExpired();
|
||||
void testNormalizeDomain();
|
||||
void testToNsCookieFormat();
|
||||
void testMarkOriginServerOnly();
|
||||
};
|
||||
|
||||
|
||||
|
@ -189,4 +191,14 @@ void CookieTest::testToNsCookieFormat()
|
|||
Cookie("hello","world","/","domain.org",true).toNsCookieFormat());
|
||||
}
|
||||
|
||||
void CookieTest::testMarkOriginServerOnly()
|
||||
{
|
||||
Cookie c("k", "v", "/", "aria2.sf.net", false);
|
||||
c.markOriginServerOnly();
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("aria2.sf.net"), c.getDomain());
|
||||
Cookie ip("k", "v", "/", "192.168.0.1", false);
|
||||
ip.markOriginServerOnly();
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), ip.getDomain());
|
||||
}
|
||||
|
||||
} // namespace aria2
|
||||
|
|
|
@ -495,9 +495,10 @@ void HttpResponseTest::testRetrieveCookie()
|
|||
|
||||
CPPUNIT_ASSERT_EQUAL((size_t)2, st->size());
|
||||
|
||||
std::deque<Cookie>::const_iterator citer = st->begin();
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("k2=v2"), (*(st->begin())).toString());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("k3=v3"), (*(st->begin()+1)).toString());
|
||||
std::vector<Cookie> cookies;
|
||||
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());
|
||||
}
|
||||
|
||||
void HttpResponseTest::testSupportsPersistentConnection()
|
||||
|
|
|
@ -1,10 +1,25 @@
|
|||
#include "common.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "Cookie.h"
|
||||
|
||||
namespace aria2 {
|
||||
|
||||
void createFile(const std::string& filename, size_t length);
|
||||
|
||||
std::string readFile(const std::string& path);
|
||||
|
||||
class CookieSorter {
|
||||
public:
|
||||
bool operator()(const Cookie& lhs, const Cookie& rhs) const
|
||||
{
|
||||
if(lhs.getDomain() == rhs.getDomain()) {
|
||||
return lhs.getName() < rhs.getName();
|
||||
} else {
|
||||
return lhs.getDomain() < rhs.getDomain();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace aria2
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
#include "a2functional.h"
|
||||
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
|
||||
#include <string>
|
||||
#include <numeric>
|
||||
#include <algorithm>
|
||||
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
|
||||
namespace aria2 {
|
||||
|
||||
|
@ -15,6 +16,7 @@ class a2functionalTest:public CppUnit::TestFixture {
|
|||
CPPUNIT_TEST(testStrjoin);
|
||||
CPPUNIT_TEST(testStrconcat);
|
||||
CPPUNIT_TEST(testStrappend);
|
||||
CPPUNIT_TEST(testLeastRecentAccess);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
public:
|
||||
void testMemFunSh();
|
||||
|
@ -22,7 +24,8 @@ public:
|
|||
void testStrjoin();
|
||||
void testStrconcat();
|
||||
void testStrappend();
|
||||
|
||||
void testLeastRecentAccess();
|
||||
|
||||
class Greeting {
|
||||
public:
|
||||
virtual ~Greeting() {}
|
||||
|
@ -48,6 +51,15 @@ public:
|
|||
|
||||
};
|
||||
|
||||
struct LastAccess {
|
||||
time_t _lastAccess;
|
||||
LastAccess(time_t lastAccess):_lastAccess(lastAccess) {}
|
||||
|
||||
time_t getLastAccess() const
|
||||
{
|
||||
return _lastAccess;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
@ -100,4 +112,16 @@ void a2functionalTest::testStrappend()
|
|||
CPPUNIT_ASSERT_EQUAL(std::string("X=3,Y=5"), str);
|
||||
}
|
||||
|
||||
void a2functionalTest::testLeastRecentAccess()
|
||||
{
|
||||
std::vector<LastAccess> v;
|
||||
for(int i = 99; i >= 0; --i) {
|
||||
v.push_back(LastAccess(i));
|
||||
}
|
||||
std::sort(v.begin(), v.end(), LeastRecentAccess<LastAccess>());
|
||||
for(int i = 0; i < 100; ++i) {
|
||||
CPPUNIT_ASSERT_EQUAL((time_t)i, v[i]._lastAccess);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace aria2
|
||||
|
|
Loading…
Reference in New Issue