summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>2010-10-09 14:22:49 +0000
committerTatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>2010-10-09 14:22:49 +0000
commit8b17d4b276222b203722eea9ded9cd3797a4b656 (patch)
treefd20f43edf2e3891707cbff18bd1f7160cf627d2 /src
parent9b1280f7a3c0d0223ad8bbc20e108b776d9c53af (diff)
2010-10-09 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Rewritten Cookie class and Cookie parser based on http://tools.ietf.org/html/draft-ietf-httpstate-cookie-14 with some modifications. When parsing cookie date, match time first so that it parses asctime() format. The request-path must be ends with '/' so that request-path '/foo/' path-matches cookie-path '/foo' and '/foo/' in the proposed algorithm. * src/Cookie.cc * src/Cookie.h * src/CookieParser.cc: Removed * src/CookieParser.h: Removed * src/CookieStorage.cc * src/CookieStorage.h * src/HttpResponse.cc * src/Makefile.am * src/Makefile.in * src/MultiUrlRequestInfo.cc * src/NsCookieParser.cc * src/NsCookieParser.h * src/Sqlite3CookieParser.cc * src/Sqlite3CookieParser.h * src/a2functional.h * src/cookie_helper.cc * src/cookie_helper.h * src/util.cc * src/util.h * test/CookieBoxFactoryTest.cc: Removed * test/CookieHelperTest.cc * test/CookieParserTest.cc: Removed * test/CookieStorageTest.cc * test/CookieTest.cc * test/HttpRequestTest.cc * test/Makefile.am * test/Makefile.in * test/NsCookieParserTest.cc * test/Sqlite3CookieParserTest.cc * test/TestUtil.cc * test/TestUtil.h * test/a2functionalTest.cc * test/chromium_cookies.sqlite * test/cookies.sqlite * test/nscookietest.txt
Diffstat (limited to 'src')
-rw-r--r--src/Cookie.cc216
-rw-r--r--src/Cookie.h157
-rw-r--r--src/CookieParser.cc103
-rw-r--r--src/CookieStorage.cc139
-rw-r--r--src/CookieStorage.h56
-rw-r--r--src/HttpResponse.cc6
-rw-r--r--src/Makefile.am4
-rw-r--r--src/Makefile.in95
-rw-r--r--src/MultiUrlRequestInfo.cc3
-rw-r--r--src/NsCookieParser.cc64
-rw-r--r--src/NsCookieParser.h6
-rw-r--r--src/Sqlite3CookieParser.cc62
-rw-r--r--src/Sqlite3CookieParser.h2
-rw-r--r--src/a2functional.h10
-rw-r--r--src/cookie_helper.cc391
-rw-r--r--src/cookie_helper.h (renamed from src/CookieParser.h)52
-rw-r--r--src/util.cc76
-rw-r--r--src/util.h2
18 files changed, 862 insertions, 582 deletions
diff --git a/src/Cookie.cc b/src/Cookie.cc
index 6ae29a3c..c8ea1ffb 100644
--- a/src/Cookie.cc
+++ b/src/Cookie.cc
@@ -2,7 +2,7 @@
/*
* aria2 - The high speed download utility
*
- * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ * Copyright (C) 2010 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
@@ -34,173 +34,67 @@
/* copyright --> */
#include "Cookie.h"
-#include <algorithm>
#include <sstream>
-#include "util.h"
#include "A2STR.h"
-#include "TimeA2.h"
#include "a2functional.h"
+#include "cookie_helper.h"
namespace aria2 {
-static std::string prependDotIfNotExists(const std::string& domain)
-{
- // From RFC2965:
- // * Domain=value
- // OPTIONAL. The value of the Domain attribute specifies the domain
- // for which the cookie is valid. If an explicitly specified value
- // does not start with a dot, the user agent supplies a leading dot.
- return (!domain.empty() && domain[0] != '.') ? A2STR::DOT_C+domain : domain;
-}
-
-std::string Cookie::normalizeDomain(const std::string& domain)
-{
- if(domain.empty() || util::isNumericHost(domain)) {
- return domain;
- }
- std::string md = prependDotIfNotExists(domain);
- // TODO use util::split to strict verification
- std::string::size_type p = md.find_last_of(A2STR::DOT_C);
- if(p == 0 || p == std::string::npos) {
- md += ".local";
- }
- return util::toLower(prependDotIfNotExists(md));
-}
-
-Cookie::Cookie(const std::string& name,
- const std::string& value,
- time_t expiry,
- const std::string& path,
- const std::string& domain,
- bool secure):
+Cookie::Cookie
+(const std::string& name,
+ const std::string& value,
+ time_t expiryTime,
+ bool persistent,
+ const std::string& domain,
+ bool hostOnly,
+ const std::string& path,
+ bool secure,
+ bool httpOnly,
+ time_t creationTime):
name_(name),
value_(value),
- expiry_(expiry),
+ expiryTime_(expiryTime),
+ persistent_(persistent),
+ domain_(domain),
+ hostOnly_(hostOnly),
path_(path),
- domain_(normalizeDomain(domain)),
secure_(secure),
- creationTime_(time(0)),
- lastAccess_(creationTime_) {}
-
-Cookie::Cookie(const std::string& name,
- const std::string& value,
- const std::string& path,
- const std::string& domain,
- bool secure):
- name_(name),
- value_(value),
- expiry_(0),
- path_(path),
- domain_(normalizeDomain(domain)),
- secure_(secure),
- creationTime_(time(0)),
- lastAccess_(creationTime_) {}
-
-Cookie::Cookie():expiry_(0), secure_(false), lastAccess_(time(0)) {}
+ httpOnly_(httpOnly),
+ creationTime_(creationTime),
+ lastAccessTime_(creationTime) {}
+
+Cookie::Cookie():
+ expiryTime_(0),
+ persistent_(false),
+ hostOnly_(false),
+ secure_(false),
+ httpOnly_(false),
+ creationTime_(0),
+ lastAccessTime_(0) {}
Cookie::~Cookie() {}
std::string Cookie::toString() const
{
- return strconcat(name_, "=", value_);
-}
-
-bool Cookie::good() const
-{
- return !name_.empty();
+ return strconcat(name_, '=', value_);
}
-static bool pathInclude(const std::string& requestPath, const std::string& path)
+bool Cookie::match
+(const std::string& requestHost,
+ const std::string& requestPath,
+ time_t date, bool secure) const
{
- if(requestPath == path) {
- return true;
- }
- if(util::startsWith(requestPath, path)) {
- if(*path.rbegin() != '/' && requestPath[path.size()] != '/') {
- return false;
- }
- } else if(*path.rbegin() != '/' || *requestPath.rbegin() == '/' ||
- !util::startsWith(requestPath+"/", path)) {
+ if((secure_ && !secure) || isExpired(date) ||
+ !cookie::pathMatch(requestPath, path_)) {
return false;
}
- return true;
-}
-
-static bool domainMatch(const std::string& normReqHost,
- const std::string& domain)
-{
- // RFC2965 stated that:
- //
- // A Set-Cookie2 with Domain=ajax.com will be accepted, and the
- // value for Domain will be taken to be .ajax.com, because a dot
- // gets prepended to the value.
- //
- // Also original Netscape implementation behaves exactly the same.
-
- // domain_ always starts ".". See Cookie::Cookie().
- return util::endsWith(normReqHost, domain);
-}
-
-bool Cookie::match(const std::string& requestHost,
- const std::string& requestPath,
- time_t date, bool secure) const
-{
- if((secure || (!secure_ && !secure)) &&
- (requestHost == domain_ || // For default domain or IP address
- domainMatch(normalizeDomain(requestHost), domain_)) &&
- pathInclude(requestPath, path_) &&
- (isSessionCookie() || (date < expiry_))) {
- return true;
+ if(hostOnly_) {
+ return requestHost == domain_ ;
} else {
- return false;
- }
-}
-
-bool Cookie::validate(const std::string& requestHost,
- const std::string& requestPath) const
-{
- // 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(A2STR::DOT_C, 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
- // * The value for the Path attribute is not a prefix of the request-URI.
- if(!pathInclude(requestPath, path_)) {
- return false;
- }
+ return cookie::domainMatch(requestHost, domain_);
}
- return good();
}
bool Cookie::operator==(const Cookie& cookie) const
@@ -209,19 +103,22 @@ bool Cookie::operator==(const Cookie& cookie) const
name_ == cookie.name_;
}
-bool Cookie::isExpired() const
+bool Cookie::isExpired(time_t base) const
{
- return !expiry_ == 0 && Time().getTime() >= expiry_;
+ return persistent_ && base > expiryTime_;
}
std::string Cookie::toNsCookieFormat() const
{
std::stringstream ss;
+ if(!hostOnly_) {
+ ss << A2STR::DOT_C;
+ }
ss << domain_ << "\t";
- if(util::startsWith(domain_, A2STR::DOT_C)) {
- ss << "TRUE";
- } else {
+ if(hostOnly_) {
ss << "FALSE";
+ } else {
+ ss << "TRUE";
}
ss << "\t";
ss << path_ << "\t";
@@ -231,22 +128,15 @@ std::string Cookie::toNsCookieFormat() const
ss << "FALSE";
}
ss << "\t";
- ss << expiry_ << "\t";
+ if(persistent_) {
+ ss << expiryTime_;
+ } else {
+ ss << 0;
+ }
+ ss << "\t";
ss << name_ << "\t";
ss << value_;
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
diff --git a/src/Cookie.h b/src/Cookie.h
index 02a34054..5c4bc4e3 100644
--- a/src/Cookie.h
+++ b/src/Cookie.h
@@ -2,7 +2,7 @@
/*
* aria2 - The high speed download utility
*
- * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ * Copyright (C) 2010 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
@@ -32,8 +32,8 @@
* files in the program, then also delete it here.
*/
/* copyright --> */
-#ifndef _D_COOKIE_H_
-#define _D_COOKIE_H_
+#ifndef D_COOKIE_H
+#define D_COOKIE_H
#include "common.h"
@@ -47,70 +47,83 @@ class Cookie {
private:
std::string name_;
std::string value_;
- time_t expiry_;
- std::string path_;
+ time_t expiryTime_;
+ // If persistent_ is false, this is a session scope cookie and it is
+ // never expired during session. So isExpired() always returns
+ // false.
+ bool persistent_;
std::string domain_;
+ bool hostOnly_;
+ std::string path_;
bool secure_;
+ bool httpOnly_;
time_t creationTime_;
- time_t lastAccess_;
+ time_t lastAccessTime_;
public:
- /*
- * If expires = 0 is given, then the cookie becomes session cookie.
- * domain is normalized using normalizeDomain() function and
- * assigned to domain_. If domain is not specified in cookie, call
- * markOriginServerOnly() after construction.
- */
- Cookie(const std::string& name,
- const std::string& value,
- time_t expires,
- const std::string& path,
- const std::string& domain,
- bool secure);
-
- /*
- * Creates session cookie. This is equivalent to Cookie(name, value,
- * 0, path, domain, secure); domain is normalized using
- * normalizeDomain() function and assigned to domain_. If domain is
- * not specified in cookie, call markOriginServerOnly() after
- * construction.
- */
- Cookie(const std::string& name,
- const std::string& value,
- const std::string& path,
- const std::string& domain,
- bool secure);
-
Cookie();
+ Cookie
+ (const std::string& name,
+ const std::string& value,
+ time_t expiryTime,
+ bool persistent,
+ const std::string& domain,
+ bool hostOnly,
+ const std::string& path,
+ bool secure,
+ bool httpOnly,
+ time_t creationTime);
+
~Cookie();
std::string toString() const;
- bool good() const;
-
- bool match(const std::string& requestHost, const std::string& requestPath,
- time_t date, bool secure) const;
-
- bool validate(const std::string& requestHost,
- const std::string& requestPath) const;
+ bool match
+ (const std::string& requestHost, const std::string& requestPath,
+ time_t date, bool secure) const;
bool operator==(const Cookie& cookie) const;
- bool isExpired() const;
+ bool isExpired(time_t base) const;
const std::string& getName() const
{
return name_;
}
+ void setName(const std::string& name)
+ {
+ name_ = name;
+ }
+
const std::string& getValue() const
{
return value_;
}
- const std::string& getPath() const
+ void setValue(const std::string& value)
{
- return path_;
+ value_ = value;
+ }
+
+ time_t getExpiryTime() const
+ {
+ return expiryTime_;
+ }
+
+ void setExpiryTime(time_t expiryTime)
+ {
+ expiryTime_ = expiryTime;
+ }
+
+ bool getPersistent() const
+ {
+ return persistent_;
+ }
+
+ void setPersistent(bool persistent)
+ {
+ persistent_ = persistent;
}
const std::string& getDomain() const
@@ -118,42 +131,74 @@ public:
return domain_;
}
- time_t getExpiry() const
+ void setDomain(const std::string& domain)
+ {
+ domain_ = domain;
+ }
+
+ bool getHostOnly() const
+ {
+ return hostOnly_;
+ }
+
+ void setHostOnly(bool hostOnly)
+ {
+ hostOnly_ = hostOnly;
+ }
+
+ const std::string& getPath() const
+ {
+ return path_;
+ }
+
+ void setPath(const std::string& path)
{
- return expiry_;
+ path_ = path;
}
- bool isSecureCookie() const
+ bool getSecure() const
{
return secure_;
}
- bool isSessionCookie() const
+ void setSecure(bool secure)
{
- return expiry_ == 0;
+ secure_ = secure;
}
- std::string toNsCookieFormat() const;
+ bool getHttpOnly() const
+ {
+ return httpOnly_;
+ }
- // Makes this Cookie only sent to the origin server. This function
- // removes first "." from domain_ if domain_ starts with ".".
- void markOriginServerOnly();
+ void setHttpOnly(bool httpOnly)
+ {
+ httpOnly_ = httpOnly;
+ }
time_t getCreationTime() const
{
return creationTime_;
}
- void updateLastAccess();
+ void setCreationTime(time_t creationTime)
+ {
+ creationTime_ = creationTime;
+ }
+
+ time_t getLastAccessTime() const
+ {
+ return lastAccessTime_;
+ }
- time_t getLastAccess() const
+ void setLastAccessTime(time_t lastAccessTime)
{
- return lastAccess_;
+ lastAccessTime_ = lastAccessTime;
}
- static std::string normalizeDomain(const std::string& domain);
+ std::string toNsCookieFormat() const;
};
} // namespace aria2
-#endif // _D_COOKIE_H_
+#endif // D_COOKIE_H
diff --git a/src/CookieParser.cc b/src/CookieParser.cc
deleted file mode 100644
index 1933b983..00000000
--- a/src/CookieParser.cc
+++ /dev/null
@@ -1,103 +0,0 @@
-/* <!-- copyright */
-/*
- * aria2 - The high speed download utility
- *
- * Copyright (C) 2006 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
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * In addition, as a special exception, the copyright holders give
- * permission to link the code of portions of this program with the
- * OpenSSL library under certain conditions as described in each
- * individual source file, and distribute linked combinations
- * including the two.
- * You must obey the GNU General Public License in all respects
- * for all of the code used other than OpenSSL. If you modify
- * file(s) with this exception, you may extend this exception to your
- * version of the file(s), but you are not obligated to do so. If you
- * do not wish to do so, delete this exception statement from your
- * version. If you delete this exception statement from all source
- * files in the program, then also delete it here.
- */
-/* copyright --> */
-#include "CookieParser.h"
-
-#include <strings.h>
-
-#include <utility>
-#include <istream>
-#include <map>
-#include <vector>
-
-#include "util.h"
-#include "A2STR.h"
-#include "TimeA2.h"
-
-namespace aria2 {
-
-const std::string CookieParser::C_SECURE("secure");
-
-const std::string CookieParser::C_DOMAIN("domain");
-
-const std::string CookieParser::C_PATH("path");
-
-const std::string CookieParser::C_EXPIRES("expires");
-
-Cookie CookieParser::parse(const std::string& cookieStr, const std::string& defaultDomain, const std::string& defaultPath) const
-{
- std::vector<std::string> terms;
- util::split(cookieStr, std::back_inserter(terms), ";", true);
- if(terms.empty()) {
- return Cookie();
- }
- std::pair<std::string, std::string> nameValue;
- util::split(nameValue, terms.front(), '=');
-
- std::map<std::string, std::string> values;
- for(std::vector<std::string>::iterator itr = terms.begin()+1,
- eoi = terms.end(); itr != eoi; ++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.count(C_EXPIRES)) {
- Time expiryTime = Time::parseHTTPDate(values[C_EXPIRES]);
- if(expiryTime.good()) {
- expiry = expiryTime.getTime();
- }
- }
- 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;
-}
-
-} // namespace aria2
diff --git a/src/CookieStorage.cc b/src/CookieStorage.cc
index ce619413..5cdd9d7c 100644
--- a/src/CookieStorage.cc
+++ b/src/CookieStorage.cc
@@ -48,6 +48,7 @@
#include "a2functional.h"
#include "A2STR.h"
#include "message.h"
+#include "cookie_helper.h"
#ifdef HAVE_SQLITE3
# include "Sqlite3CookieParserImpl.h"
#endif // HAVE_SQLITE3
@@ -55,26 +56,21 @@
namespace aria2 {
CookieStorage::DomainEntry::DomainEntry
-(const std::string& domain):key_(domain)
-{
- std::reverse(key_.begin(), key_.end());
-}
-
-void CookieStorage::DomainEntry::updateLastAccess()
-{
- lastAccess_ = time(0);
-}
+(const std::string& domain):
+ key_(util::isNumericHost(domain)?domain:cookie::reverseDomainLevel(domain))
+{}
-bool CookieStorage::DomainEntry::addCookie(const Cookie& cookie)
+bool CookieStorage::DomainEntry::addCookie(const Cookie& cookie, time_t now)
{
- updateLastAccess();
- std::deque<Cookie>::iterator i = std::find(cookies_.begin(), cookies_.end(),
- cookie);
+ setLastAccessTime(now);
+ std::deque<Cookie>::iterator i =
+ std::find(cookies_.begin(), cookies_.end(), cookie);
if(i == cookies_.end()) {
- if(cookie.isExpired()) {
+ if(cookie.isExpired(now)) {
return false;
} else {
if(cookies_.size() >= CookieStorage::MAX_COOKIE_PER_DOMAIN) {
+ // TODO First remove expired cookie
std::deque<Cookie>::iterator m = std::min_element
(cookies_.begin(), cookies_.end(), LeastRecentAccess<Cookie>());
*m = cookie;
@@ -83,7 +79,7 @@ bool CookieStorage::DomainEntry::addCookie(const Cookie& cookie)
}
return true;
}
- } else if(cookie.isExpired()) {
+ } else if(cookie.isExpired(now)) {
cookies_.erase(i);
return false;
} else {
@@ -114,12 +110,11 @@ static const size_t DOMAIN_EVICTION_TRIGGER = 2000;
static const double DOMAIN_EVICTION_RATE = 0.1;
-bool CookieStorage::store(const Cookie& cookie)
+bool CookieStorage::store(const Cookie& cookie, time_t now)
{
- if(!cookie.good()) {
- return false;
- }
if(domains_.size() >= DOMAIN_EVICTION_TRIGGER) {
+ // TODO Do this in a separete Command.
+ // TODO Erase expired cookie first
std::sort(domains_.begin(), domains_.end(),
LeastRecentAccess<DomainEntry>());
size_t delnum = (size_t)(domains_.size()*DOMAIN_EVICTION_RATE);
@@ -131,9 +126,9 @@ bool CookieStorage::store(const Cookie& cookie)
std::lower_bound(domains_.begin(), domains_.end(), v);
bool added = false;
if(i != domains_.end() && (*i).getKey() == v.getKey()) {
- added = (*i).addCookie(cookie);
+ added = (*i).addCookie(cookie, now);
} else {
- added = v.addCookie(cookie);
+ added = v.addCookie(cookie, now);
if(added) {
domains_.insert(i, v);
}
@@ -141,13 +136,15 @@ bool CookieStorage::store(const Cookie& cookie)
return added;
}
-bool CookieStorage::parseAndStore(const std::string& setCookieString,
- const std::string& requestHost,
- const std::string& requestPath)
+bool CookieStorage::parseAndStore
+(const std::string& setCookieString,
+ const std::string& requestHost,
+ const std::string& defaultPath,
+ time_t now)
{
- Cookie cookie = parser_.parse(setCookieString, requestHost, requestPath);
- if(cookie.validate(requestHost, requestPath)) {
- return store(cookie);
+ Cookie cookie;
+ if(cookie::parse(cookie, setCookieString, requestHost, defaultPath, now)) {
+ return store(cookie, now);
} else {
return false;
}
@@ -198,32 +195,34 @@ public:
// "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;
- }
+ //
+ // See also http://tools.ietf.org/html/draft-ietf-httpstate-cookie-14
+ // section5.4
+ return lhs.pathDepth_ > rhs.pathDepth_ ||
+ (!(rhs.pathDepth_ > lhs.pathDepth_) &&
+ lhs.cookie_.getCreationTime() < rhs.cookie_.getCreationTime());
}
};
}
+namespace {
template<typename DomainInputIterator, typename CookieOutputIterator>
-static void searchCookieByDomainSuffix
+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)
+ time_t now, 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);
+ (*i).setLastAccessTime(now);
+ (*i).findCookie(out, requestHost, requestPath, now, secure);
}
}
+}
bool CookieStorage::contains(const Cookie& cookie) const
{
@@ -237,36 +236,34 @@ bool CookieStorage::contains(const Cookie& cookie) const
}
}
-std::vector<Cookie> CookieStorage::criteriaFind(const std::string& requestHost,
- const std::string& requestPath,
- time_t date, bool secure)
+std::vector<Cookie> CookieStorage::criteriaFind
+(const std::string& requestHost,
+ const std::string& requestPath,
+ time_t now,
+ bool secure)
{
std::vector<Cookie> res;
- bool numericHost = util::isNumericHost(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, eoi = domainComponents.end();
- di != eoi; ++di) {
- domain = strconcat(A2STR::DOT_C, *di, domain);
- searchCookieByDomainSuffix(domain, domains_.begin(), domains_.end(),
- std::back_inserter(res),
- normRequestHost, requestPath, date, secure);
+ if(requestPath.empty()) {
+ return res;
+ }
+ std::string normRequestPath =
+ requestPath == A2STR::SLASH_C?requestPath:requestPath+A2STR::SLASH_C;
+ if(util::isNumericHost(requestHost)) {
+ searchCookieByDomainSuffix
+ (requestHost, domains_.begin(), domains_.end(), std::back_inserter(res),
+ requestHost, normRequestPath, now, secure);
+ } else {
+ std::vector<std::string> levels;
+ util::split(requestHost, std::back_inserter(levels),A2STR::DOT_C);
+ std::reverse(levels.begin(), levels.end());
+ std::string domain;
+ for(std::vector<std::string>::const_iterator i =
+ levels.begin(), eoi = levels.end();
+ i != eoi; ++i, domain.insert(domain.begin(), '.')) {
+ domain.insert(domain.begin(), (*i).begin(), (*i).end());
+ searchCookieByDomainSuffix
+ (domain, domains_.begin(), domains_.end(),
+ std::back_inserter(res), requestHost, normRequestPath, now, secure);
}
}
std::vector<CookiePathDivider> divs;
@@ -288,7 +285,7 @@ size_t CookieStorage::size() const
return numCookie;
}
-bool CookieStorage::load(const std::string& filename)
+bool CookieStorage::load(const std::string& filename, time_t now)
{
char header[16]; // "SQLite format 3" plus \0
std::ifstream s(filename.c_str(), std::ios::binary);
@@ -307,7 +304,7 @@ bool CookieStorage::load(const std::string& filename)
#ifdef HAVE_SQLITE3
std::vector<Cookie> cookies;
try {
- Sqlite3MozCookieParser(filename).parse(cookies);
+ Sqlite3MozCookieParser(filename).parse(cookies, now);
} catch(RecoverableException& e) {
if(logger_->info()) {
logger_->info(EX_EXCEPTION_CAUGHT, e);
@@ -315,17 +312,17 @@ bool CookieStorage::load(const std::string& filename)
" Retrying, assuming it is Chromium cookie file.");
}
// Try chrome cookie format
- Sqlite3ChromiumCookieParser(filename).parse(cookies);
+ Sqlite3ChromiumCookieParser(filename).parse(cookies, now);
}
- storeCookies(cookies.begin(), cookies.end());
+ 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);
- storeCookies(cookies.begin(), cookies.end());
+ std::vector<Cookie> cookies = NsCookieParser().parse(filename, now);
+ storeCookies(cookies.begin(), cookies.end(), now);
}
return true;
} catch(RecoverableException& e) {
diff --git a/src/CookieStorage.h b/src/CookieStorage.h
index 4e03b99b..5d7da6f4 100644
--- a/src/CookieStorage.h
+++ b/src/CookieStorage.h
@@ -44,7 +44,6 @@
#include "a2time.h"
#include "Cookie.h"
-#include "CookieParser.h"
namespace aria2 {
@@ -57,9 +56,12 @@ public:
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 lastAccess_;
+ time_t lastAccessTime_;
std::deque<Cookie> cookies_;
public:
@@ -75,12 +77,12 @@ public:
(OutputIterator out,
const std::string& requestHost,
const std::string& requestPath,
- time_t date, bool secure)
+ time_t now, bool secure)
{
- for(std::deque<Cookie>::iterator i = cookies_.begin();
- i != cookies_.end(); ++i) {
- if((*i).match(requestHost, requestPath, date, secure)) {
- (*i).updateLastAccess();
+ 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++ = *i;
}
}
@@ -92,13 +94,16 @@ public:
return cookies_.size();
}
- bool addCookie(const Cookie& cookie);
+ bool addCookie(const Cookie& cookie, time_t now);
- void updateLastAccess();
+ void setLastAccessTime(time_t lastAccessTime)
+ {
+ lastAccessTime_ = lastAccessTime;
+ }
- time_t getLastAccess() const
+ time_t getLastAccessTime() const
{
- return lastAccess_;
+ return lastAccessTime_;
}
void writeCookie(std::ostream& o) const;
@@ -119,15 +124,13 @@ public:
private:
std::deque<DomainEntry> domains_;
- CookieParser parser_;
-
Logger* logger_;
template<typename InputIterator>
- void storeCookies(InputIterator first, InputIterator last)
+ void storeCookies(InputIterator first, InputIterator last, time_t now)
{
for(; first != last; ++first) {
- store(*first);
+ store(*first, now);
}
}
public:
@@ -136,27 +139,32 @@ public:
~CookieStorage();
// Returns true if cookie is stored or updated existing cookie.
- // Returns false if cookie is expired.
- bool store(const Cookie& cookie);
+ // Returns false if cookie is expired. now is used as last access
+ // time.
+ bool store(const Cookie& cookie, time_t now);
// Returns true if cookie is stored or updated existing cookie.
- // Otherwise, returns false.
- bool parseAndStore(const std::string& setCookieString,
- const std::string& requestHost,
- const std::string& requestPath);
+ // Otherwise, returns false. now is used as creation time and last
+ // access time.
+ bool parseAndStore
+ (const std::string& setCookieString,
+ const std::string& requestHost,
+ const std::string& requestPath,
+ time_t now);
// 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 date, bool secure);
+ time_t now, bool secure);
// Loads Cookies from file denoted by filename. If compiled with
// libsqlite3, this method automatically detects the specified file
// is sqlite3 or just plain text file and calls appropriate parser
// implementation class. If Cookies are successfully loaded, this
- // method returns true. Otherwise, this method returns false.
- bool load(const std::string& filename);
+ // method returns true. Otherwise, this method returns false. now
+ // is used as creation time and last access time.
+ bool load(const std::string& filename, time_t now);
// Saves Cookies in Netspace format which is used in
// Firefox1.2/Netscape/Mozilla. If Cookies are successfully saved,
diff --git a/src/HttpResponse.cc b/src/HttpResponse.cc
index fd406b4a..1f5ea7a9 100644
--- a/src/HttpResponse.cc
+++ b/src/HttpResponse.cc
@@ -129,12 +129,12 @@ std::string HttpResponse::determinFilename() const
void HttpResponse::retrieveCookie()
{
+ Time now;
std::vector<std::string> v = httpHeader_->get(HttpHeader::SET_COOKIE);
for(std::vector<std::string>::const_iterator itr = v.begin(), eoi = v.end();
itr != eoi; ++itr) {
- httpRequest_->getCookieStorage()->parseAndStore(*itr,
- httpRequest_->getHost(),
- httpRequest_->getDir());
+ httpRequest_->getCookieStorage()->parseAndStore
+ (*itr, httpRequest_->getHost(), httpRequest_->getDir(), now.getTime());
}
}
diff --git a/src/Makefile.am b/src/Makefile.am
index eb26512a..6bf75de4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -94,7 +94,6 @@ SRCS = Socket.h\
ProgressAwareEntry.h\
RequestGroupEntry.cc RequestGroupEntry.h\
Cookie.cc Cookie.h\
- CookieParser.cc CookieParser.h\
HttpHeaderProcessor.cc HttpHeaderProcessor.h\
FileEntry.cc FileEntry.h\
Platform.cc Platform.h\
@@ -211,7 +210,8 @@ SRCS = Socket.h\
ChunkedDecodingStreamFilter.cc ChunkedDecodingStreamFilter.h\
NullSinkStreamFilter.cc NullSinkStreamFilter.h\
uri.cc uri.h\
- Triplet.h
+ Triplet.h\
+ cookie_helper.cc cookie_helper.h
if ENABLE_XML_RPC
SRCS += XmlRpcRequestParserController.cc XmlRpcRequestParserController.h\
diff --git a/src/Makefile.in b/src/Makefile.in
index 65151a70..a606c362 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -379,16 +379,15 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
MultiUrlRequestInfo.h UriListParser.cc UriListParser.h \
RealtimeCommand.cc RealtimeCommand.h ProgressAwareEntry.h \
RequestGroupEntry.cc RequestGroupEntry.h Cookie.cc Cookie.h \
- CookieParser.cc CookieParser.h HttpHeaderProcessor.cc \
- HttpHeaderProcessor.h FileEntry.cc FileEntry.h Platform.cc \
- Platform.h PStringDatum.h PStringSegment.cc PStringSegment.h \
- PStringNumLoop.h PStringSelect.h PStringVisitor.h \
- PStringBuildVisitor.cc PStringBuildVisitor.h \
- ParameterizedStringParser.cc ParameterizedStringParser.h \
- FixedWidthNumberDecorator.h NumberDecorator.h \
- AlphaNumberDecorator.h TimeBasedCommand.cc TimeBasedCommand.h \
- AutoSaveCommand.cc AutoSaveCommand.h PieceStorage.h \
- DefaultPieceStorage.cc DefaultPieceStorage.h \
+ HttpHeaderProcessor.cc HttpHeaderProcessor.h FileEntry.cc \
+ FileEntry.h Platform.cc Platform.h PStringDatum.h \
+ PStringSegment.cc PStringSegment.h PStringNumLoop.h \
+ PStringSelect.h PStringVisitor.h PStringBuildVisitor.cc \
+ PStringBuildVisitor.h ParameterizedStringParser.cc \
+ ParameterizedStringParser.h FixedWidthNumberDecorator.h \
+ NumberDecorator.h AlphaNumberDecorator.h TimeBasedCommand.cc \
+ TimeBasedCommand.h AutoSaveCommand.cc AutoSaveCommand.h \
+ PieceStorage.h DefaultPieceStorage.cc DefaultPieceStorage.h \
UnknownLengthPieceStorage.cc UnknownLengthPieceStorage.h \
PieceStatMan.cc PieceStatMan.h StatCalc.h ConsoleStatCalc.cc \
ConsoleStatCalc.h TransferStat.cc TransferStat.h Dependency.h \
@@ -448,7 +447,8 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
StreamFilter.h SinkStreamFilter.cc SinkStreamFilter.h \
ChunkedDecodingStreamFilter.cc ChunkedDecodingStreamFilter.h \
NullSinkStreamFilter.cc NullSinkStreamFilter.h uri.cc uri.h \
- Triplet.h XmlRpcRequestParserController.cc \
+ Triplet.h cookie_helper.cc cookie_helper.h \
+ XmlRpcRequestParserController.cc \
XmlRpcRequestParserController.h \
XmlRpcRequestParserStateMachine.cc \
XmlRpcRequestParserStateMachine.h XmlRpcRequestParserState.h \
@@ -854,10 +854,9 @@ am__objects_32 = SocketCore.$(OBJEXT) Command.$(OBJEXT) \
StreamFileAllocationEntry.$(OBJEXT) \
MultiUrlRequestInfo.$(OBJEXT) UriListParser.$(OBJEXT) \
RealtimeCommand.$(OBJEXT) RequestGroupEntry.$(OBJEXT) \
- Cookie.$(OBJEXT) CookieParser.$(OBJEXT) \
- HttpHeaderProcessor.$(OBJEXT) FileEntry.$(OBJEXT) \
- Platform.$(OBJEXT) PStringSegment.$(OBJEXT) \
- PStringBuildVisitor.$(OBJEXT) \
+ Cookie.$(OBJEXT) HttpHeaderProcessor.$(OBJEXT) \
+ FileEntry.$(OBJEXT) Platform.$(OBJEXT) \
+ PStringSegment.$(OBJEXT) PStringBuildVisitor.$(OBJEXT) \
ParameterizedStringParser.$(OBJEXT) TimeBasedCommand.$(OBJEXT) \
AutoSaveCommand.$(OBJEXT) DefaultPieceStorage.$(OBJEXT) \
UnknownLengthPieceStorage.$(OBJEXT) PieceStatMan.$(OBJEXT) \
@@ -896,17 +895,18 @@ am__objects_32 = SocketCore.$(OBJEXT) Command.$(OBJEXT) \
ValueBase.$(OBJEXT) AdaptiveFileAllocationIterator.$(OBJEXT) \
StreamFilter.$(OBJEXT) SinkStreamFilter.$(OBJEXT) \
ChunkedDecodingStreamFilter.$(OBJEXT) \
- NullSinkStreamFilter.$(OBJEXT) uri.$(OBJEXT) $(am__objects_1) \
- $(am__objects_2) $(am__objects_3) $(am__objects_4) \
- $(am__objects_5) $(am__objects_6) $(am__objects_7) \
- $(am__objects_8) $(am__objects_9) $(am__objects_10) \
- $(am__objects_11) $(am__objects_12) $(am__objects_13) \
- $(am__objects_14) $(am__objects_15) $(am__objects_16) \
- $(am__objects_17) $(am__objects_18) $(am__objects_19) \
- $(am__objects_20) $(am__objects_21) $(am__objects_22) \
- $(am__objects_23) $(am__objects_24) $(am__objects_25) \
- $(am__objects_26) $(am__objects_27) $(am__objects_28) \
- $(am__objects_29) $(am__objects_30) $(am__objects_31)
+ NullSinkStreamFilter.$(OBJEXT) uri.$(OBJEXT) \
+ cookie_helper.$(OBJEXT) $(am__objects_1) $(am__objects_2) \
+ $(am__objects_3) $(am__objects_4) $(am__objects_5) \
+ $(am__objects_6) $(am__objects_7) $(am__objects_8) \
+ $(am__objects_9) $(am__objects_10) $(am__objects_11) \
+ $(am__objects_12) $(am__objects_13) $(am__objects_14) \
+ $(am__objects_15) $(am__objects_16) $(am__objects_17) \
+ $(am__objects_18) $(am__objects_19) $(am__objects_20) \
+ $(am__objects_21) $(am__objects_22) $(am__objects_23) \
+ $(am__objects_24) $(am__objects_25) $(am__objects_26) \
+ $(am__objects_27) $(am__objects_28) $(am__objects_29) \
+ $(am__objects_30) $(am__objects_31)
am_libaria2c_a_OBJECTS = $(am__objects_32)
libaria2c_a_OBJECTS = $(am_libaria2c_a_OBJECTS)
am__installdirs = "$(DESTDIR)$(bindir)"
@@ -1175,16 +1175,15 @@ SRCS = Socket.h SocketCore.cc SocketCore.h BinaryStream.h Command.cc \
MultiUrlRequestInfo.h UriListParser.cc UriListParser.h \
RealtimeCommand.cc RealtimeCommand.h ProgressAwareEntry.h \
RequestGroupEntry.cc RequestGroupEntry.h Cookie.cc Cookie.h \
- CookieParser.cc CookieParser.h HttpHeaderProcessor.cc \
- HttpHeaderProcessor.h FileEntry.cc FileEntry.h Platform.cc \
- Platform.h PStringDatum.h PStringSegment.cc PStringSegment.h \
- PStringNumLoop.h PStringSelect.h PStringVisitor.h \
- PStringBuildVisitor.cc PStringBuildVisitor.h \
- ParameterizedStringParser.cc ParameterizedStringParser.h \
- FixedWidthNumberDecorator.h NumberDecorator.h \
- AlphaNumberDecorator.h TimeBasedCommand.cc TimeBasedCommand.h \
- AutoSaveCommand.cc AutoSaveCommand.h PieceStorage.h \
- DefaultPieceStorage.cc DefaultPieceStorage.h \
+ HttpHeaderProcessor.cc HttpHeaderProcessor.h FileEntry.cc \
+ FileEntry.h Platform.cc Platform.h PStringDatum.h \
+ PStringSegment.cc PStringSegment.h PStringNumLoop.h \
+ PStringSelect.h PStringVisitor.h PStringBuildVisitor.cc \
+ PStringBuildVisitor.h ParameterizedStringParser.cc \
+ ParameterizedStringParser.h FixedWidthNumberDecorator.h \
+ NumberDecorator.h AlphaNumberDecorator.h TimeBasedCommand.cc \
+ TimeBasedCommand.h AutoSaveCommand.cc AutoSaveCommand.h \
+ PieceStorage.h DefaultPieceStorage.cc DefaultPieceStorage.h \
UnknownLengthPieceStorage.cc UnknownLengthPieceStorage.h \
PieceStatMan.cc PieceStatMan.h StatCalc.h ConsoleStatCalc.cc \
ConsoleStatCalc.h TransferStat.cc TransferStat.h Dependency.h \
@@ -1244,17 +1243,17 @@ SRCS = Socket.h SocketCore.cc SocketCore.h BinaryStream.h Command.cc \
StreamFilter.h SinkStreamFilter.cc SinkStreamFilter.h \
ChunkedDecodingStreamFilter.cc ChunkedDecodingStreamFilter.h \
NullSinkStreamFilter.cc NullSinkStreamFilter.h uri.cc uri.h \
- Triplet.h $(am__append_1) $(am__append_2) $(am__append_3) \
- $(am__append_4) $(am__append_5) $(am__append_6) \
- $(am__append_7) $(am__append_8) $(am__append_9) \
- $(am__append_10) $(am__append_11) $(am__append_12) \
- $(am__append_13) $(am__append_14) $(am__append_15) \
- $(am__append_16) $(am__append_17) $(am__append_18) \
- $(am__append_19) $(am__append_20) $(am__append_21) \
- $(am__append_22) $(am__append_23) $(am__append_24) \
- $(am__append_25) $(am__append_26) $(am__append_27) \
- $(am__append_28) $(am__append_29) $(am__append_30) \
- $(am__append_31)
+ Triplet.h cookie_helper.cc cookie_helper.h $(am__append_1) \
+ $(am__append_2) $(am__append_3) $(am__append_4) \
+ $(am__append_5) $(am__append_6) $(am__append_7) \
+ $(am__append_8) $(am__append_9) $(am__append_10) \
+ $(am__append_11) $(am__append_12) $(am__append_13) \
+ $(am__append_14) $(am__append_15) $(am__append_16) \
+ $(am__append_17) $(am__append_18) $(am__append_19) \
+ $(am__append_20) $(am__append_21) $(am__append_22) \
+ $(am__append_23) $(am__append_24) $(am__append_25) \
+ $(am__append_26) $(am__append_27) $(am__append_28) \
+ $(am__append_29) $(am__append_30) $(am__append_31)
noinst_LIBRARIES = libaria2c.a
libaria2c_a_SOURCES = $(SRCS)
aria2c_LDADD = libaria2c.a @LIBINTL@ @ALLOCA@ @LIBGNUTLS_LIBS@\
@@ -1417,7 +1416,6 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ConsoleStatCalc.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ContentTypeRequestGroupCriteria.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Cookie.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CookieParser.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CookieStorage.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CreateRequestCommand.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DHTAbstractMessage.Po@am__quote@
@@ -1674,6 +1672,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bittorrent_helper.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clock_gettime_mingw.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clock_gettime_osx.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cookie_helper.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemon.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/download_helper.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gai_strerror.Po@am__quote@
diff --git a/src/MultiUrlRequestInfo.cc b/src/MultiUrlRequestInfo.cc
index 89dcf0d6..30d8ce60 100644
--- a/src/MultiUrlRequestInfo.cc
+++ b/src/MultiUrlRequestInfo.cc
@@ -59,6 +59,7 @@
#include "ServerStatMan.h"
#include "FileAllocationEntry.h"
#include "CheckIntegrityEntry.h"
+#include "TimeA2.h"
#ifdef ENABLE_SSL
# include "SocketCore.h"
# include "TLSContext.h"
@@ -128,7 +129,7 @@ downloadresultcode::RESULT MultiUrlRequestInfo::execute()
if(!option_->blank(PREF_LOAD_COOKIES)) {
File cookieFile(option_->get(PREF_LOAD_COOKIES));
if(cookieFile.isFile()) {
- e->getCookieStorage()->load(cookieFile.getPath());
+ e->getCookieStorage()->load(cookieFile.getPath(), Time().getTime());
logger_->info("Loaded cookies from '%s'.",
cookieFile.getPath().c_str());
} else {
diff --git a/src/NsCookieParser.cc b/src/NsCookieParser.cc
index ed08ff8f..1a4f13ed 100644
--- a/src/NsCookieParser.cc
+++ b/src/NsCookieParser.cc
@@ -40,6 +40,8 @@
#include "A2STR.h"
#include "DlAbortEx.h"
#include "StringFormat.h"
+#include "Cookie.h"
+#include "cookie_helper.h"
namespace aria2 {
@@ -47,35 +49,46 @@ NsCookieParser::NsCookieParser() {}
NsCookieParser::~NsCookieParser() {}
-static const std::string C_TRUE("TRUE");
+namespace {
+const std::string C_TRUE("TRUE");
+}
-static Cookie parseNsCookie(const std::string& nsCookieStr)
+namespace {
+bool parseNsCookie
+(Cookie& cookie, const std::string& nsCookieStr, time_t creationTime)
{
std::vector<std::string> vs;
util::split(nsCookieStr, std::back_inserter(vs), "\t", true);
- if(vs.size() < 6 ) {
- return Cookie();
+ if(vs.size() < 6) {
+ return false;
}
-
- int64_t expireDate = util::parseLLInt(vs[4]);
- // TODO assuming time_t is int32_t...
- if(expireDate > INT32_MAX) {
- expireDate = INT32_MAX;
+ std::string cookieDomain = cookie::removePrecedingDots(vs[0]);
+ if(vs[5].empty() || cookieDomain.empty() || !cookie::goodPath(vs[2])) {
+ return false;
}
-
- Cookie c(vs[5], // name
- vs.size() >= 7? vs[6]:A2STR::NIL, // value
- expireDate, // expires
- vs[2], // path
- vs[0], // domain
- vs[3] == C_TRUE ? true : false);
- if(!util::startsWith(vs[0], A2STR::DOT_C)) {
- c.markOriginServerOnly();
+ int64_t expiryTime;
+ if(!util::parseLLIntNoThrow(expiryTime, vs[4])) {
+ return false;
}
- return c;
+ if(sizeof(time_t) == 4 && expiryTime > INT32_MAX) {
+ expiryTime = INT32_MAX;
+ }
+ cookie.setName(vs[5]);
+ cookie.setValue(vs.size() >= 7? vs[6]:A2STR::NIL);
+ cookie.setExpiryTime(expiryTime == 0?INT32_MAX:expiryTime);
+ // aria2 treats expiryTime == 0 means session cookie.
+ cookie.setPersistent(expiryTime != 0);
+ cookie.setDomain(cookieDomain);
+ cookie.setHostOnly(util::isNumericHost(cookieDomain) || vs[1] != C_TRUE);
+ cookie.setPath(vs[2]);
+ cookie.setSecure(vs[3] == C_TRUE);
+ cookie.setCreationTime(creationTime);
+ return true;
+}
}
-std::vector<Cookie> NsCookieParser::parse(const std::string& filename)
+std::vector<Cookie> NsCookieParser::parse
+(const std::string& filename, time_t creationTime)
{
std::ifstream s(filename.c_str(), std::ios::binary);
if(!s) {
@@ -88,14 +101,9 @@ std::vector<Cookie> NsCookieParser::parse(const std::string& filename)
if(util::startsWith(line, A2STR::SHARP_C)) {
continue;
}
- try {
- Cookie c = parseNsCookie(line);
- if(c.good()) {
- cookies.push_back(c);
- }
- } catch(RecoverableException& e) {
- // ignore malformed cookie entry
- // TODO better to log it
+ Cookie c;
+ if(parseNsCookie(c, line, creationTime)) {
+ cookies.push_back(c);
}
}
return cookies;
diff --git a/src/NsCookieParser.h b/src/NsCookieParser.h
index 5395ec80..7d2b2bb8 100644
--- a/src/NsCookieParser.h
+++ b/src/NsCookieParser.h
@@ -40,17 +40,17 @@
#include <string>
#include <vector>
-#include "Cookie.h"
-
namespace aria2 {
+class Cookie;
+
class NsCookieParser {
public:
NsCookieParser();
~NsCookieParser();
- std::vector<Cookie> parse(const std::string& filename);
+ std::vector<Cookie> parse(const std::string& filename, time_t creationTime);
};
} // namespace aria2
diff --git a/src/Sqlite3CookieParser.cc b/src/Sqlite3CookieParser.cc
index 45d98f4e..81525f8a 100644
--- a/src/Sqlite3CookieParser.cc
+++ b/src/Sqlite3CookieParser.cc
@@ -40,6 +40,7 @@
#include "util.h"
#include "StringFormat.h"
#include "A2STR.h"
+#include "cookie_helper.h"
#ifndef HAVE_SQLITE3_OPEN_V2
# include "File.h"
#endif // !HAVE_SQLITE3_OPEN_V2
@@ -80,34 +81,40 @@ static std::string toString(const char* str)
static int cookieRowMapper(void* data, int rowIndex,
char** values, char** names)
{
- try {
- std::vector<Cookie>& cookies =
- *reinterpret_cast<std::vector<Cookie>*>(data);
- int64_t expireDate = util::parseLLInt(toString(values[3]));
- // TODO assuming time_t is int32_t...
- if(expireDate > INT32_MAX) {
- expireDate = INT32_MAX;
- }
- Cookie c(toString(values[4]), // name
- toString(values[5]), // value
- expireDate, // expires
- toString(values[1]), // path
- toString(values[0]), // domain
- strcmp(toString(values[2]).c_str(), "1") == 0 ? true:false //secure
- );
- if(!util::startsWith(values[0], A2STR::DOT_C)) {
- c.markOriginServerOnly();
- }
- if(c.good()) {
- cookies.push_back(c);
- }
- } catch(RecoverableException& e) {
- //failed to parse expiry.
+ std::vector<Cookie>& cookies =
+ *reinterpret_cast<std::vector<Cookie>*>(data);
+ std::string cookieDomain = cookie::removePrecedingDots(toString(values[0]));
+ std::string cookieName = toString(values[4]);
+ std::string cookiePath = toString(values[1]);
+ if(cookieName.empty() || cookieDomain.empty() ||
+ !cookie::goodPath(cookiePath)) {
+ return 0;
}
+ int64_t expiryTime;
+ if(!util::parseLLIntNoThrow(expiryTime, toString(values[3]))) {
+ return 0;
+ }
+ if(sizeof(time_t) == 4 && expiryTime > INT32_MAX) {
+ expiryTime = INT32_MAX;
+ }
+ // TODO get last access, creation date(chrome only)
+ Cookie c(cookieName,
+ toString(values[5]), // value
+ expiryTime,
+ true, // persistent
+ cookieDomain,
+ util::isNumericHost(cookieDomain) || values[0][0] != '.', // hostOnly
+ cookiePath,
+ strcmp(toString(values[2]).c_str(), "1") == 0, //secure
+ false,
+ 0 // creation time. Set this later.
+ );
+ cookies.push_back(c);
return 0;
}
-void Sqlite3CookieParser::parse(std::vector<Cookie>& cookies)
+void Sqlite3CookieParser::parse
+(std::vector<Cookie>& cookies, time_t creationTime)
{
if(!db_) {
throw DL_ABORT_EX(StringFormat("SQLite3 database is not opened.").str());
@@ -116,6 +123,13 @@ void Sqlite3CookieParser::parse(std::vector<Cookie>& cookies)
char* sqlite3ErrMsg = 0;
int ret = sqlite3_exec(db_, getQuery().c_str(), cookieRowMapper,
&tcookies, &sqlite3ErrMsg);
+ // TODO If last access, creation date are retrieved from database,
+ // following for loop must be removed.
+ for(std::vector<Cookie>::iterator i = tcookies.begin(), eoi = tcookies.end();
+ i != eoi; ++i) {
+ (*i).setCreationTime(creationTime);
+ (*i).setLastAccessTime(creationTime);
+ }
std::string errMsg;
if(sqlite3ErrMsg) {
errMsg = sqlite3ErrMsg;
diff --git a/src/Sqlite3CookieParser.h b/src/Sqlite3CookieParser.h
index 355e30a3..ecf55521 100644
--- a/src/Sqlite3CookieParser.h
+++ b/src/Sqlite3CookieParser.h
@@ -55,7 +55,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);
+ void parse(std::vector<Cookie>& cookies, time_t creationTime);
protected:
// Returns SQL select statement to get 1 record of cookie. The sql
// must return 6 columns in the following order: host, path,
diff --git a/src/a2functional.h b/src/a2functional.h
index d75e01e9..6e552dc3 100644
--- a/src/a2functional.h
+++ b/src/a2functional.h
@@ -421,10 +421,18 @@ class LeastRecentAccess:public std::binary_function<T, T, bool> {
public:
bool operator()(const T& lhs, const T& rhs) const
{
- return lhs.getLastAccess() < rhs.getLastAccess();
+ return lhs.getLastAccessTime() < rhs.getLastAccessTime();
}
};
+namespace {
+template<typename T, typename S>
+bool in(T x, S s, S t)
+{
+ return s <= x && x <= t;
+}
+}
+
} // namespace aria2
#endif // _D_A2_FUNCTIONAL_H_
diff --git a/src/cookie_helper.cc b/src/cookie_helper.cc
new file mode 100644
index 00000000..114f2e1e
--- /dev/null
+++ b/src/cookie_helper.cc
@@ -0,0 +1,391 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2010 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "cookie_helper.h"
+
+#include <cstring>
+#include <vector>
+
+#include "util.h"
+#include "array_fun.h"
+#include "Cookie.h"
+#include "a2functional.h"
+
+namespace aria2 {
+
+namespace cookie {
+
+namespace {
+bool isDelimiter(unsigned char c)
+{
+ return c == 0x09U || in(c, 0x20U, 0x2fU) || in(c, 0x3bU, 0x40U) ||
+ in(c, 0x5bU, 0x60U) || in(c, 0x7bU, 0x7eU);
+}
+} // namespace
+
+namespace {
+std::string::const_iterator getNextDigit
+(std::string::const_iterator first, std::string::const_iterator last)
+{
+ for(; first != last && in(static_cast<unsigned char>(*first), 0x30U, 0x39U);
+ ++first);
+ return first;
+}
+}
+
+bool parseDate(time_t& time, const std::string& cookieDate)
+{
+ std::vector<std::string> dateTokens;
+ for(std::string::const_iterator i = cookieDate.begin(),
+ eoi = cookieDate.end(); i != eoi;) {
+ unsigned char c = *i;
+ if(isDelimiter(c)) {
+ ++i;
+ continue;
+ }
+ std::string::const_iterator s = i;
+ for(; s != eoi && !isDelimiter(static_cast<unsigned char>(*s)); ++s);
+ dateTokens.push_back(std::string(i, s));
+ i = s;
+ }
+ int dayOfMonth = 0;
+ bool foundDayOfMonth = false;
+ int month = 0;
+ bool foundMonth = false;
+ int year = 0;
+ bool foundYear = false;
+ int hour = 0;
+ int minute = 0;
+ int second = 0;
+ bool foundTime = false;
+ for(std::vector<std::string>::const_iterator i = dateTokens.begin(),
+ eoi = dateTokens.end(); i != eoi; ++i) {
+ if(!foundTime) {
+ std::string::const_iterator hEnd;
+ std::string::const_iterator mEnd;
+ std::string::const_iterator sEnd;
+ hEnd = getNextDigit((*i).begin(),(*i).end());
+ size_t len = std::distance((*i).begin(), hEnd);
+ if(len == 0 || 2 < len || hEnd == (*i).end() || *hEnd != ':') {
+ goto NOT_TIME;
+ }
+ mEnd = getNextDigit(hEnd+1, (*i).end());
+ len = std::distance(hEnd+1, mEnd);
+ if(len == 0 || 2 < len || mEnd == (*i).end() || *mEnd != ':') {
+ goto NOT_TIME;
+ }
+ sEnd = getNextDigit(mEnd+1, (*i).end());
+ len = std::distance(mEnd+1, sEnd);
+ if(len == 0 || 2 < len) {
+ goto NOT_TIME;
+ }
+ foundTime = true;
+ hour = util::parseInt(std::string((*i).begin(), hEnd));
+ minute = util::parseInt(std::string(hEnd+1, mEnd));
+ second = util::parseInt(std::string(mEnd+1, sEnd));
+ continue;
+ NOT_TIME:
+ ;
+ }
+ if(!foundDayOfMonth) {
+ std::string::const_iterator j = getNextDigit((*i).begin(), (*i).end());
+ size_t len = std::distance((*i).begin(), j);
+ if(1 <= len && len <= 2) {
+ foundDayOfMonth = true;
+ dayOfMonth = util::parseInt(std::string((*i).begin(), j));
+ continue;
+ }
+ }
+ if(!foundMonth) {
+ static std::string MONTH[] = {
+ "jan", "feb", "mar", "apr",
+ "may", "jun", "jul", "aug",
+ "sep", "oct", "nov", "dec" };
+ if((*i).size() >= 3) {
+ std::string head = util::toLower((*i).substr(0, 3));
+ std::string* mptr = std::find(vbegin(MONTH), vend(MONTH), head);
+ if(mptr != vend(MONTH)) {
+ foundMonth = true;
+ month = std::distance(vbegin(MONTH), mptr)+1;
+ continue;
+ }
+ }
+ }
+ if(!foundYear) {
+ std::string::const_iterator j = getNextDigit((*i).begin(), (*i).end());
+ size_t len = std::distance((*i).begin(), j);
+ if(1 <= len && len <= 4) {
+ foundYear = true;
+ year = util::parseInt(std::string((*i).begin(), j));
+ continue;
+ }
+ }
+ }
+ if(in(year, 70, 99)) {
+ year += 1900;
+ } else if(in(year, 0, 69)) {
+ year += 2000;
+ }
+ if(!foundDayOfMonth || !foundMonth || !foundYear || !foundTime ||
+ !in(dayOfMonth, 1, 31) || year < 1601 || hour > 23 ||
+ minute > 59 || second > 59) {
+ return false;
+ }
+ if((month == 4 || month == 6 || month == 9 || month == 11) &&
+ dayOfMonth > 30) {
+ return false;
+ }
+ if(month == 2) {
+ if((year%4 == 0 && year%100 != 0) || year%400 == 0) {
+ if(dayOfMonth > 29) {
+ return false;
+ }
+ } else if(dayOfMonth > 28) {
+ return false;
+ }
+ }
+
+ tm timespec;
+ memset(&timespec, 0, sizeof(timespec));
+ timespec.tm_sec = second;
+ timespec.tm_min = minute;
+ timespec.tm_hour = hour;
+ timespec.tm_mday = dayOfMonth;
+ timespec.tm_mon = month-1;
+ timespec.tm_year = year-1900;
+ time = timegm(&timespec);
+
+ return time != -1;
+}
+
+bool parse
+(Cookie& cookie,
+ const std::string& cookieStr,
+ const std::string& requestHost,
+ const std::string& defaultPath,
+ time_t creationTime)
+{
+ std::string::const_iterator nvEnd = cookieStr.begin();
+ std::string::const_iterator end = cookieStr.end();
+ for(; nvEnd != end && *nvEnd != ';'; ++nvEnd);
+ std::string::const_iterator eq = cookieStr.begin();
+ for(; eq != nvEnd && *eq != '='; ++eq);
+ if(eq == nvEnd) {
+ return false;
+ }
+ std::string cookieName = util::trim(std::string(cookieStr.begin(), eq));
+ if(cookieName.empty()) {
+ return false;
+ }
+ std::string cookieValue = util::trim(std::string(eq+1, nvEnd));
+ time_t expiryTime = 0;
+ bool foundExpires = false;
+ bool persistent = false;
+ time_t maxAge = 0;
+ bool foundMaxAge = false;
+ std::string cookieDomain;
+ bool hostOnly = false;
+ std::string cookiePath;
+ bool secure = false;
+ bool httpOnly = false;
+
+ for(std::string::const_iterator i = nvEnd; i != end;) {
+ std::string::const_iterator j = i;
+ for(; j != end && *j != ';'; ++j);
+ std::string::const_iterator eq = i;
+ for(; eq != j && *eq != '='; ++eq);
+ std::string attrName = util::toLower(util::trim(std::string(i, eq)));
+ std::string attrValue;
+ if(eq != j) {
+ attrValue = util::trim(std::string(eq+1, j));
+ }
+ i = j;
+ if(j != end) {
+ ++i;
+ }
+ if(attrName == "expires") {
+ if(parseDate(expiryTime, attrValue)) {
+ foundExpires = true;
+ } else {
+ return false;
+ }
+ } else if(attrName == "max-age") {
+ if(attrValue.empty() ||
+ (!in(static_cast<unsigned char>(attrValue[0]), 0x30u, 0x39u) &&
+ attrValue[0] != '-')) {
+ return false;
+ }
+ for(std::string::const_iterator s = attrValue.begin()+1,
+ eos = attrValue.end(); s != eos; ++s) {
+ if(!in(static_cast<unsigned char>(*s), 0x30u, 0x39u)) {
+ return false;
+ }
+ }
+ int64_t delta;
+ if(util::parseLLIntNoThrow(delta, attrValue)) {
+ foundMaxAge = true;
+ if(delta <= 0) {
+ maxAge = 0;
+ } else {
+ int64_t n = creationTime;
+ n += delta;
+ if(n < 0 || (sizeof(time_t) < 8 && n > INT32_MAX)) {
+ maxAge = INT32_MAX;
+ } else {
+ maxAge = n;
+ }
+ }
+ } else {
+ return false;
+ }
+ } else if(attrName == "domain") {
+ if(attrValue.empty()) {
+ return false;
+ }
+ std::string::const_iterator noDot = attrValue.begin();
+ std::string::const_iterator end = attrValue.end();
+ for(; noDot != end && *noDot == '.'; ++noDot);
+ if(noDot == end) {
+ return false;
+ }
+ cookieDomain = std::string(noDot, end);
+ } else if(attrName == "path") {
+ if(goodPath(attrValue)) {
+ cookiePath = attrValue;
+ } else {
+ cookiePath = defaultPath;
+ }
+ } else if(attrName == "secure") {
+ secure = true;
+ } else if(attrName == "httponly") {
+ httpOnly = true;
+ }
+ }
+
+ if(foundMaxAge) {
+ expiryTime = maxAge;
+ persistent = true;
+ } else if(foundExpires) {
+ persistent = true;
+ } else {
+ expiryTime = INT32_MAX;
+ persistent = false;
+ }
+
+ std::string canonicalizedHost = canonicalizeHost(requestHost);
+ if(cookieDomain.empty()) {
+ hostOnly = true;
+ cookieDomain = canonicalizedHost;
+ } else if(domainMatch(canonicalizedHost, cookieDomain)) {
+ hostOnly = util::isNumericHost(canonicalizedHost);
+ } else {
+ return false;
+ }
+
+ if(cookiePath.empty()) {
+ cookiePath = defaultPath;
+ }
+
+ cookie.setName(cookieName);
+ cookie.setValue(cookieValue);
+ 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);
+
+ return true;
+}
+
+std::string removePrecedingDots(const std::string& host)
+{
+ std::string::const_iterator noDot = host.begin();
+ std::string::const_iterator end = host.end();
+ for(; noDot != end && *noDot == '.'; ++noDot);
+ return std::string(noDot, end);
+}
+
+bool goodPath(const std::string& cookiePath)
+{
+ return !cookiePath.empty() && cookiePath[0] == '/';
+}
+
+std::string canonicalizeHost(const std::string& host)
+{
+ std::string ch = util::toLower(host);
+ return ch;
+}
+
+bool domainMatch(const std::string& requestHost, const std::string& domain)
+{
+ return requestHost == domain ||
+ (util::endsWith(requestHost, domain) &&
+ requestHost[requestHost.size()-domain.size()-1] == '.' &&
+ !util::isNumericHost(requestHost));
+}
+
+bool pathMatch(const std::string& requestPath, const std::string& path)
+{
+ return requestPath == path ||
+ (util::startsWith(requestPath, path) &&
+ (path[path.size()-1] == '/' || requestPath[path.size()] == '/'));
+}
+
+std::string reverseDomainLevel(const std::string& domain)
+{
+ std::string r;
+ for(std::string::const_iterator i = domain.begin(), eoi = domain.end();
+ i != eoi;) {
+ std::string::const_iterator j = i;
+ for(; j != eoi && *j != '.'; ++j);
+ r.insert(r.begin(), '.');
+ r.insert(r.begin(), i, j);
+ i = j;
+ if(j != eoi) {
+ ++i;
+ }
+ }
+ if(!r.empty()) {
+ r.erase(r.size()-1, 1);
+ }
+ return r;
+}
+
+} // namespace cookie
+
+} // namespace aria2
diff --git a/src/CookieParser.h b/src/cookie_helper.h
index 6fd8641a..6dc249eb 100644
--- a/src/CookieParser.h
+++ b/src/cookie_helper.h
@@ -2,7 +2,7 @@
/*
* aria2 - The high speed download utility
*
- * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ * Copyright (C) 2010 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
@@ -32,34 +32,44 @@
* files in the program, then also delete it here.
*/
/* copyright --> */
-#ifndef _D_COOKIE_PARSER_H_
-#define _D_COOKIE_PARSER_H_
+#ifndef D_COOKIE_HELPER_H
+#define D_COOKIE_HELPER_H
#include "common.h"
#include <string>
-#include "SharedHandle.h"
-#include "Cookie.h"
+#include "a2time.h"
namespace aria2 {
-class CookieParser {
-public:
- Cookie parse(const std::string& cookieStr, const std::string& defaultDomain,
- const std::string& defaultPath) const;
-private:
- static const std::string C_SECURE;
-
- static const std::string C_DOMAIN;
-
- static const std::string C_PATH;
-
- static const std::string C_EXPIRES;
-};
-
-typedef SharedHandle<CookieParser> CookieParserHandle;
+class Cookie;
+
+namespace cookie {
+
+bool parseDate(time_t& time, const std::string& cookieDate);
+
+bool parse
+(Cookie& cookie,
+ const std::string& cookieStr,
+ const std::string& requestHost,
+ const std::string& defaultPath,
+ time_t creationTime);
+
+std::string removePrecedingDots(const std::string& host);
+
+bool goodPath(const std::string& cookiePath);
+
+std::string canonicalizeHost(const std::string& host);
+
+bool domainMatch(const std::string& requestHost, const std::string& domain);
+
+bool pathMatch(const std::string& requestPath, const std::string& path);
+
+std::string reverseDomainLevel(const std::string& domain);
+
+} // namespace cookie
} // namespace aria2
-#endif // _D_COOKIE_PARSER_H_
+#endif // D_COOKIE_HELPER_H
diff --git a/src/util.cc b/src/util.cc
index 1bf42d4f..d0e3d9a8 100644
--- a/src/util.cc
+++ b/src/util.cc
@@ -74,7 +74,6 @@
#include "StringFormat.h"
#include "A2STR.h"
#include "array_fun.h"
-#include "a2functional.h"
#include "bitfield.h"
#include "DownloadHandlerConstants.h"
#include "RequestGroup.h"
@@ -292,16 +291,9 @@ bool inRFC2616HttpToken(const char c)
}
namespace {
-bool in(unsigned char ch, unsigned char s, unsigned char t)
-{
- return s <= ch && ch <= t;
-}
-}
-
-namespace {
bool isUtf8Tail(unsigned char ch)
{
- return in(ch, 0x80, 0xbf);
+ return in(ch, 0x80u, 0xbfu);
}
}
@@ -311,49 +303,49 @@ bool isUtf8(const std::string& str)
++s) {
unsigned char firstChar = *s;
// See ABNF in http://tools.ietf.org/search/rfc3629#section-4
- if(in(firstChar, 0x20, 0x7e) ||
- firstChar == 0x09 || firstChar == 0x0a ||firstChar == 0x0d) {
+ if(in(firstChar, 0x20u, 0x7eu) ||
+ firstChar == 0x09u || firstChar == 0x0au ||firstChar == 0x0du) {
// UTF8-1 (without ctrl chars)
- } else if(in(firstChar, 0xc2, 0xdf)) {
+ } else if(in(firstChar, 0xc2u, 0xdfu)) {
// UTF8-2
if(++s == eos || !isUtf8Tail(*s)) {
return false;
}
- } else if(0xe0 == firstChar) {
+ } else if(0xe0u == firstChar) {
// UTF8-3
- if(++s == eos || !in(*s, 0xa0, 0xbf) ||
+ if(++s == eos || !in(static_cast<unsigned char>(*s), 0xa0u, 0xbfu) ||
++s == eos || !isUtf8Tail(*s)) {
return false;
}
- } else if(in(firstChar, 0xe1, 0xec) || in(firstChar, 0xee, 0xef)) {
+ } else if(in(firstChar, 0xe1u, 0xecu) || in(firstChar, 0xeeu, 0xefu)) {
// UTF8-3
if(++s == eos || !isUtf8Tail(*s) ||
++s == eos || !isUtf8Tail(*s)) {
return false;
}
- } else if(0xed == firstChar) {
+ } else if(0xedu == firstChar) {
// UTF8-3
- if(++s == eos || !in(*s, 0x80, 0x9f) ||
+ if(++s == eos || !in(static_cast<unsigned char>(*s), 0x80u, 0x9fu) ||
++s == eos || !isUtf8Tail(*s)) {
return false;
}
- } else if(0xf0 == firstChar) {
+ } else if(0xf0u == firstChar) {
// UTF8-4
- if(++s == eos || !in(*s, 0x90, 0xbf) ||
+ if(++s == eos || !in(static_cast<unsigned char>(*s), 0x90u, 0xbfu) ||
++s == eos || !isUtf8Tail(*s) ||
++s == eos || !isUtf8Tail(*s)) {
return false;
}
- } else if(in(firstChar, 0xf1, 0xf3)) {
+ } else if(in(firstChar, 0xf1u, 0xf3u)) {
// UTF8-4
if(++s == eos || !isUtf8Tail(*s) ||
++s == eos || !isUtf8Tail(*s) ||
++s == eos || !isUtf8Tail(*s)) {
return false;
}
- } else if(0xf4 == firstChar) {
+ } else if(0xf4u == firstChar) {
// UTF8-4
- if(++s == eos || !in(*s, 0x80, 0x8f) ||
+ if(++s == eos || !in(static_cast<unsigned char>(*s), 0x80u, 0x8fu) ||
++s == eos || !isUtf8Tail(*s) ||
++s == eos || !isUtf8Tail(*s)) {
return false;
@@ -427,7 +419,7 @@ std::string toHex(const unsigned char* src, size_t len) {
const unsigned char* last = src+len;
for(const unsigned char* i = src; i != last; ++i) {
*o = (*i >> 4);
- *(o+1) = (*i)&0x0f;
+ *(o+1) = (*i)&0x0fu;
for(int j = 0; j < 2; ++j) {
if(*o < 10) {
*o += '0';
@@ -598,6 +590,24 @@ int64_t parseLLInt(const std::string& s, int32_t base)
return v;
}
+bool parseLLIntNoThrow(int64_t& result, const std::string& s, int base)
+{
+ std::string trimed = trim(s);
+ if(trimed.empty()) {
+ return false;
+ }
+ char* stop;
+ errno = 0;
+ int64_t v = strtoll(trimed.c_str(), &stop, base);
+ if(*stop != '\0') {
+ return false;
+ } else if(((v == INT64_MIN) || (v == INT64_MAX)) && (errno == ERANGE)) {
+ return false;
+ }
+ result = v;
+ return true;
+}
+
uint64_t parseULLInt(const std::string& s, int base)
{
std::string trimed = trim(s);
@@ -740,14 +750,14 @@ std::string iso8859ToUtf8(const std::string& src)
for(std::string::const_iterator itr = src.begin(), eoi = src.end();
itr != eoi; ++itr) {
unsigned char c = *itr;
- if(0xa0 <= c) {
- if(c <= 0xbf) {
- dest += 0xc2;
+ if(0xa0u <= c) {
+ if(c <= 0xbfu) {
+ dest += 0xc2u;
} else {
- dest += 0xc3;
+ dest += 0xc3u;
}
- dest += c&(~0x40);
- } else if(0x80 <= c && c <= 0x9f) {
+ dest += c&(~0x40u);
+ } else if(0x80u <= c && c <= 0x9fu) {
return A2STR::NIL;
} else {
dest += c;
@@ -1000,10 +1010,10 @@ std::string abbrevSize(int64_t size)
char units[] = { 'K', 'M' };
size_t numUnit = sizeof(units)/sizeof(char);
size_t i = 0;
- int r = size&0x3ff;
+ int r = size&0x3ffu;
size >>= 10;
for(; i < numUnit-1 && size >= 1024; ++i) {
- r = size&0x3ff;
+ r = size&0x3ffu;
size >>= 10;
}
std::string result = itos(size, true);
@@ -1332,7 +1342,7 @@ bool detectDirTraversal(const std::string& s)
{
for(std::string::const_iterator i = s.begin(), eoi = s.end(); i != eoi; ++i) {
unsigned char c = *i;
- if(in(c, 0x00, 0x1f) || c == 0x7f) {
+ if(in(c, 0x00u, 0x1fu) || c == 0x7fu) {
return true;
}
}
@@ -1367,7 +1377,7 @@ std::string escapePath(const std::string& s)
std::string d;
for(std::string::const_iterator i = s.begin(), eoi = s.end(); i != eoi; ++i) {
unsigned char c = *i;
- if(in(c, 0x00, 0x1f) || c == 0x7f
+ if(in(c, 0x00u, 0x1fu) || c == 0x7fu
#ifdef __MINGW32__
|| std::find(vbegin(WIN_INVALID_PATH_CHARS),
vend(WIN_INVALID_PATH_CHARS),
diff --git a/src/util.h b/src/util.h
index e47d6a67..49c7c578 100644
--- a/src/util.h
+++ b/src/util.h
@@ -181,6 +181,8 @@ bool parseUIntNoThrow(uint32_t& result, const std::string& s, int base = 10);
int64_t parseLLInt(const std::string& s, int32_t base = 10);
+bool parseLLIntNoThrow(int64_t& result, const std::string& s, int base = 10);
+
uint64_t parseULLInt(const std::string& s, int base = 10);
IntSequence parseIntRange(const std::string& src);