diff options
| author | Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> | 2010-10-09 14:22:49 +0000 |
|---|---|---|
| committer | Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> | 2010-10-09 14:22:49 +0000 |
| commit | 8b17d4b276222b203722eea9ded9cd3797a4b656 (patch) | |
| tree | fd20f43edf2e3891707cbff18bd1f7160cf627d2 /src | |
| parent | 9b1280f7a3c0d0223ad8bbc20e108b776d9c53af (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.cc | 216 | ||||
| -rw-r--r-- | src/Cookie.h | 157 | ||||
| -rw-r--r-- | src/CookieParser.cc | 103 | ||||
| -rw-r--r-- | src/CookieStorage.cc | 139 | ||||
| -rw-r--r-- | src/CookieStorage.h | 56 | ||||
| -rw-r--r-- | src/HttpResponse.cc | 6 | ||||
| -rw-r--r-- | src/Makefile.am | 4 | ||||
| -rw-r--r-- | src/Makefile.in | 95 | ||||
| -rw-r--r-- | src/MultiUrlRequestInfo.cc | 3 | ||||
| -rw-r--r-- | src/NsCookieParser.cc | 64 | ||||
| -rw-r--r-- | src/NsCookieParser.h | 6 | ||||
| -rw-r--r-- | src/Sqlite3CookieParser.cc | 62 | ||||
| -rw-r--r-- | src/Sqlite3CookieParser.h | 2 | ||||
| -rw-r--r-- | src/a2functional.h | 10 | ||||
| -rw-r--r-- | src/cookie_helper.cc | 391 | ||||
| -rw-r--r-- | src/cookie_helper.h (renamed from src/CookieParser.h) | 52 | ||||
| -rw-r--r-- | src/util.cc | 76 | ||||
| -rw-r--r-- | src/util.h | 2 |
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(×pec, 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(×pec); + + 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), @@ -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); |
