Merge branch 'master' into dynamic-select-file

dynamic-select-file
Tatsuhiro Tsujikawa 2016-05-16 12:27:14 +09:00
commit 9727b5b256
21 changed files with 217 additions and 241 deletions

View File

@ -16,13 +16,17 @@ ITriskTI
Igor Khomyakov Igor Khomyakov
Jarda Snajdr Jarda Snajdr
Kcchouette Kcchouette
Kurt Kartaltepe
Mingye Wang
Nils Maier Nils Maier
ORiON- ORiON-
ReadmeCritic
Ross Smith II Ross Smith II
Ryan Steinmetz Ryan Steinmetz
Ryo ONODERA Ryo ONODERA
Sarim Khan Sarim Khan
Sergey Zolotarev Sergey Zolotarev
Sonny Piers
Tatsuhiro Tsujikawa Tatsuhiro Tsujikawa
Vasilij Schneidermann Vasilij Schneidermann
Zoltan Toth-Czifra Zoltan Toth-Czifra
@ -36,6 +40,6 @@ luokar
mozillazg mozillazg
multisnow multisnow
oliviercommelarbre oliviercommelarbre
Sonny Piers rotor
[1] https://gist.github.com/tatsuhiro-t/deaffeb064652104ad11 [1] https://gist.github.com/tatsuhiro-t/deaffeb064652104ad11

84
NEWS
View File

@ -1,37 +1,79 @@
aria2 1.22.0 aria2 1.23.0
============ ============
Release Note Release Note
------------ ------------
This release adds new feature that manages the number of concurrent This release fixes several bugs reported by users, and adds several
downloads dynamically. --stream-piece-selector option gets new value new features. Read the following section for details.
"random" which randomizes the piece selection for HTTP/FTP downloads.
This effectively randomizes the order of files on multi-file Web
Seeding. Now all contributor's names are in AUTHORS file.
Previously, aria2 shows error when it sees floating point number in a
torrent file because torrent file specification does not allow
floating point number. In this release, they are just ignored, and
aria2 continues to parse the rest of the torrent file as if there is
nothing wrong.
Changes Changes
------- -------
* Add description about possible fragmentation with * Simplify cache write
--file-allocation=trunc
* Make single-entry metalink download with multi-file torrent work The previous cache write routine was too complex. I'm sure I can
rewrite it to more elegantly. But the primary motivation of this
complex logic is for disk activity reduction on Windows 7, and I
observed it on my old IDE disk. I checked it again recently, and
there is no difference between with and without this complex logic.
For this reason, it was removed. Will revert this change if many of
users are not happy with this.
* Add all contributor's names in AUTHORS * Allow subsecond value in ns cookie.txt file's expiry time field
* Ignore floating number in torrent file Fixes GH-655
* Added support for a dynamic management of the number of concurrent * Adjust chromium cookie time
downloads as a function of the overall bandwidth observed
This change adds --optimize-concurrent-downloads option. * import-po: iterate on glob, not ls output
Patch from oliviercommelarbre Patch from Mingye Wang
* Add --stream-piece-selector=random * Add --stderr option to redirect all stdout log output to stderr
Fixes GH-638
* Add "hide" to --download-result option
Fixes GH-639
* Fix downloaded metaurl torrent filename
* Add a little bit of color to have a better visual of important
informations
Patch from rotor
* Update README URLs based on HTTP redirects
Patch from ReadmeCritic
* Relocate from github.com/tatsuhiro-t/aria2 to github.com/aria2/aria2
Fixes GH-602
* mingw: Defer the falloc warning until falloc is specified by option
Fixes GH-594
* Add bittorrent key to aria2.tellStopped status
Fixes GH-612
* Addsystem.listNotifications RPC method
Merges GH-620
Patch from Sonny Piers
* Report CheckIntegrity info in tellStatus
- Adds verifiedLength to tellStatus. Reports the length of data that
has been verified of the current RequestGroup being verified.
- Adds verifyPending to tellStatus. Reports if the RequestGroup has
a verification of integrity pending.
Closes GH-561
Patch from Kurt Kartaltepe

View File

@ -42,7 +42,7 @@ aria2c executable was generated using android-ndk-r10d.
The following libraries were statically linked. The following libraries were statically linked.
* openssl 1.0.2g * openssl 1.0.2h
* expat 2.1.0 * expat 2.1.0
* c-ares 1.11.0 * c-ares 1.11.0
* libssh2 1.7.0 * libssh2 1.7.0

View File

@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script. # Process this file with autoconf to produce a configure script.
# #
AC_PREREQ([2.67]) AC_PREREQ([2.67])
AC_INIT([aria2],[1.22.0],[https://github.com/aria2/aria2/issues],[aria2],[https://aria2.github.io/]) AC_INIT([aria2],[1.23.0],[https://github.com/aria2/aria2/issues],[aria2],[https://aria2.github.io/])
AC_CANONICAL_HOST AC_CANONICAL_HOST
AC_CANONICAL_TARGET AC_CANONICAL_TARGET

File diff suppressed because one or more lines are too long

View File

@ -30,7 +30,7 @@ echo "Renaming po files..."
mv "$WORK_DIR"/aria2/*.po "$WORK_DIR" mv "$WORK_DIR"/aria2/*.po "$WORK_DIR"
echo -n "en@quot en@boldquot" > "$PO_DIR"/LINGUAS echo -n "en@quot en@boldquot" > "$PO_DIR"/LINGUAS
for file in `ls "$WORK_DIR"/*.po`; do for file in "$WORK_DIR"/*.po; do
# First remove useless '\r' in messages # First remove useless '\r' in messages
sed -i -e 's/\\r//' "$file" sed -i -e 's/\\r//' "$file"
bn=`basename "$file"` bn=`basename "$file"`

View File

@ -21,5 +21,5 @@ Importing PO files from launchpad-export.tar.gz
The downloaded file is named as launchpad-export.tar.gz at the time of The downloaded file is named as launchpad-export.tar.gz at the time of
this writing. It includes all PO files translated at launchpad. To this writing. It includes all PO files translated at launchpad. To
import those files, use ``import-po`` script in the top directory. It import those files, use ``import-po`` script in the top directory. It
will deflate the tar.gz file and rename PO files and move them to po will inflate the tar.gz file and rename PO files and move them to po
directory and run ``make update-po``. directory and run ``make update-po``.

View File

@ -96,49 +96,10 @@ ssize_t AbstractSingleDiskAdaptor::readDataDropCache(unsigned char* data,
void AbstractSingleDiskAdaptor::writeCache(const WrDiskCacheEntry* entry) void AbstractSingleDiskAdaptor::writeCache(const WrDiskCacheEntry* entry)
{ {
// Write cached data in 4KiB aligned offset. This reduces disk for (auto& d : entry->getDataSet()) {
// activity especially on Windows 7 NTFS. In this code, we assume A2_LOG_DEBUG(fmt("Cache flush goff=%" PRId64 ", len=%lu", d->goff, d->len));
// that maximum length of DataCell data is 16KiB to simplify the writeData(d->data + d->offset, d->len, d->goff);
// code.
unsigned char buf[16_k];
int64_t start = 0;
size_t buflen = 0;
size_t buffoffset = 0;
const WrDiskCacheEntry::DataCellSet& dataSet = entry->getDataSet();
for (auto& d : dataSet) {
if (start + static_cast<ssize_t>(buflen) < d->goff) {
A2_LOG_DEBUG(fmt("Cache flush goff=%" PRId64 ", len=%lu", start,
static_cast<unsigned long>(buflen)));
writeData(buf + buffoffset, buflen - buffoffset, start);
start = d->goff;
buflen = buffoffset = 0;
} }
if (buflen == 0 && (d->goff & 0xfff) == 0 && (d->len & 0xfff) == 0) {
// Already aligned. Write it without copy.
A2_LOG_DEBUG(fmt("Cache flush goff=%" PRId64 ", len=%lu", start,
static_cast<unsigned long>(d->len)));
writeData(d->data + d->offset, d->len, start);
start += d->len;
}
else {
if (buflen == 0) {
buflen = buffoffset = d->goff & 0xfff;
}
size_t wlen = std::min(sizeof(buf) - buflen, d->len);
memcpy(buf + buflen, d->data + d->offset, wlen);
buflen += wlen;
if (buflen == sizeof(buf)) {
A2_LOG_DEBUG(fmt("Cache flush goff=%" PRId64 ", len=%lu", start,
static_cast<unsigned long>(buflen)));
writeData(buf + buffoffset, buflen - buffoffset, start);
memcpy(buf, d->data + d->offset + wlen, d->len - wlen);
start += sizeof(buf) - buffoffset;
buflen = d->len - wlen;
buffoffset = 0;
}
}
}
writeData(buf + buffoffset, buflen - buffoffset, start);
} }
bool AbstractSingleDiskAdaptor::fileExists() bool AbstractSingleDiskAdaptor::fileExists()

View File

@ -37,16 +37,13 @@
#include <cstring> #include <cstring>
#include "util.h" #include "util.h"
#include "BtConstants.h"
#include "a2functional.h" #include "a2functional.h"
namespace aria2 { namespace aria2 {
const unsigned char BtHandshakeMessage::BT_PSTR[] = "BitTorrent protocol";
const char BtHandshakeMessage::NAME[] = "handshake"; const char BtHandshakeMessage::NAME[] = "handshake";
const unsigned char* BtHandshakeMessage::BT_PSTR =
reinterpret_cast<const unsigned char*>("BitTorrent protocol");
BtHandshakeMessage::BtHandshakeMessage() : SimpleBtMessage(ID, NAME) { init(); } BtHandshakeMessage::BtHandshakeMessage() : SimpleBtMessage(ID, NAME) { init(); }
BtHandshakeMessage::BtHandshakeMessage(const unsigned char* infoHash, BtHandshakeMessage::BtHandshakeMessage(const unsigned char* infoHash,
@ -54,19 +51,17 @@ BtHandshakeMessage::BtHandshakeMessage(const unsigned char* infoHash,
: SimpleBtMessage(ID, NAME) : SimpleBtMessage(ID, NAME)
{ {
init(); init();
memcpy(infoHash_, infoHash, INFO_HASH_LENGTH); std::copy_n(infoHash, infoHash_.size(), std::begin(infoHash_));
memcpy(peerId_, peerId, PEER_ID_LENGTH); std::copy_n(peerId, peerId_.size(), std::begin(peerId_));
} }
BtHandshakeMessage::~BtHandshakeMessage() {}
void BtHandshakeMessage::init() void BtHandshakeMessage::init()
{ {
pstrlen_ = 19; pstrlen_ = 19;
pstr_ = new unsigned char[PSTR_LENGTH]; std::copy_n(BT_PSTR, pstr_.size(), std::begin(pstr_));
reserved_ = new unsigned char[RESERVED_LENGTH]; std::fill(std::begin(reserved_), std::end(reserved_), 0);
infoHash_ = new unsigned char[INFO_HASH_LENGTH];
peerId_ = new unsigned char[PEER_ID_LENGTH];
memcpy(pstr_, BT_PSTR, PSTR_LENGTH);
memset(reserved_, 0, RESERVED_LENGTH);
// fast extension // fast extension
reserved_[7] |= 0x04u; reserved_[7] |= 0x04u;
// extended messaging // extended messaging
@ -76,23 +71,25 @@ void BtHandshakeMessage::init()
std::unique_ptr<BtHandshakeMessage> std::unique_ptr<BtHandshakeMessage>
BtHandshakeMessage::create(const unsigned char* data, size_t dataLength) BtHandshakeMessage::create(const unsigned char* data, size_t dataLength)
{ {
auto message = make_unique<BtHandshakeMessage>(); auto msg = make_unique<BtHandshakeMessage>();
message->pstrlen_ = data[0]; msg->pstrlen_ = data[0];
memcpy(message->pstr_, &data[1], PSTR_LENGTH); std::copy_n(&data[1], msg->pstr_.size(), std::begin(msg->pstr_));
memcpy(message->reserved_, &data[20], RESERVED_LENGTH); std::copy_n(&data[20], msg->reserved_.size(), std::begin(msg->reserved_));
memcpy(message->infoHash_, &data[28], INFO_HASH_LENGTH); std::copy_n(&data[28], msg->infoHash_.size(), std::begin(msg->infoHash_));
memcpy(message->peerId_, &data[48], PEER_ID_LENGTH); std::copy_n(&data[48], msg->peerId_.size(), std::begin(msg->peerId_));
return message;
return msg;
} }
unsigned char* BtHandshakeMessage::createMessage() unsigned char* BtHandshakeMessage::createMessage()
{ {
auto msg = new unsigned char[MESSAGE_LENGTH]; auto msg = new unsigned char[MESSAGE_LENGTH];
msg[0] = pstrlen_; auto dst = msg;
memcpy(msg + 1, pstr_, PSTR_LENGTH); *dst++ = pstrlen_;
memcpy(msg + 20, reserved_, RESERVED_LENGTH); dst = std::copy(std::begin(pstr_), std::end(pstr_), dst);
memcpy(msg + 28, infoHash_, INFO_HASH_LENGTH); dst = std::copy(std::begin(reserved_), std::end(reserved_), dst);
memcpy(msg + 48, peerId_, PEER_ID_LENGTH); dst = std::copy(std::begin(infoHash_), std::end(infoHash_), dst);
std::copy(std::begin(peerId_), std::end(peerId_), dst);
return msg; return msg;
} }
@ -101,8 +98,8 @@ size_t BtHandshakeMessage::getMessageLength() { return MESSAGE_LENGTH; }
std::string BtHandshakeMessage::toString() const std::string BtHandshakeMessage::toString() const
{ {
return fmt("%s peerId=%s, reserved=%s", NAME, return fmt("%s peerId=%s, reserved=%s", NAME,
util::percentEncode(peerId_, PEER_ID_LENGTH).c_str(), util::percentEncode(peerId_.data(), peerId_.size()).c_str(),
util::toHex(reserved_, RESERVED_LENGTH).c_str()); util::toHex(reserved_.data(), reserved_.size()).c_str());
} }
bool BtHandshakeMessage::isFastExtensionSupported() const bool BtHandshakeMessage::isFastExtensionSupported() const
@ -119,12 +116,12 @@ bool BtHandshakeMessage::isDHTEnabled() const { return reserved_[7] & 0x01u; }
void BtHandshakeMessage::setInfoHash(const unsigned char* infoHash) void BtHandshakeMessage::setInfoHash(const unsigned char* infoHash)
{ {
memcpy(infoHash_, infoHash, INFO_HASH_LENGTH); std::copy_n(infoHash, infoHash_.size(), std::begin(infoHash_));
} }
void BtHandshakeMessage::setPeerId(const unsigned char* peerId) void BtHandshakeMessage::setPeerId(const unsigned char* peerId)
{ {
memcpy(peerId_, peerId, PEER_ID_LENGTH); std::copy_n(peerId, peerId_.size(), std::begin(peerId_));
} }
} // namespace aria2 } // namespace aria2

View File

@ -37,21 +37,26 @@
#include "SimpleBtMessage.h" #include "SimpleBtMessage.h"
#include <array>
#include "BtConstants.h"
namespace aria2 { namespace aria2 {
class BtHandshakeMessage : public SimpleBtMessage { class BtHandshakeMessage : public SimpleBtMessage {
public: public:
static const size_t PSTR_LENGTH = 19; constexpr static size_t PSTR_LENGTH = 19;
static const unsigned char* BT_PSTR; constexpr static size_t RESERVED_LENGTH = 8;
static const size_t RESERVED_LENGTH = 8; constexpr static size_t MESSAGE_LENGTH = 68;
static const size_t MESSAGE_LENGTH = 68; const static unsigned char BT_PSTR[];
private: private:
uint8_t pstrlen_; uint8_t pstrlen_;
unsigned char* pstr_; std::array<unsigned char, PSTR_LENGTH> pstr_;
unsigned char* reserved_; std::array<unsigned char, RESERVED_LENGTH> reserved_;
unsigned char* infoHash_; std::array<unsigned char, INFO_HASH_LENGTH> infoHash_;
unsigned char* peerId_; std::array<unsigned char, PEER_ID_LENGTH> peerId_;
void init(); void init();
public: public:
@ -66,17 +71,11 @@ public:
static std::unique_ptr<BtHandshakeMessage> create(const unsigned char* data, static std::unique_ptr<BtHandshakeMessage> create(const unsigned char* data,
size_t dataLength); size_t dataLength);
virtual ~BtHandshakeMessage() virtual ~BtHandshakeMessage();
{
delete[] pstr_;
delete[] reserved_;
delete[] infoHash_;
delete[] peerId_;
}
static const uint8_t ID = INT8_MAX; static const uint8_t ID = INT8_MAX;
static const char NAME[]; const static char NAME[];
virtual void doReceivedAction() CXX11_OVERRIDE{}; virtual void doReceivedAction() CXX11_OVERRIDE{};
@ -104,15 +103,15 @@ public:
uint8_t getPstrlen() const { return pstrlen_; } uint8_t getPstrlen() const { return pstrlen_; }
const unsigned char* getPstr() const { return pstr_; } const unsigned char* getPstr() const { return pstr_.data(); }
const unsigned char* getReserved() const { return reserved_; } const unsigned char* getReserved() const { return reserved_.data(); }
const unsigned char* getInfoHash() const { return infoHash_; } const unsigned char* getInfoHash() const { return infoHash_.data(); }
void setInfoHash(const unsigned char* infoHash); void setInfoHash(const unsigned char* infoHash);
const unsigned char* getPeerId() const { return peerId_; } const unsigned char* getPeerId() const { return peerId_.data(); }
void setPeerId(const unsigned char* peerId); void setPeerId(const unsigned char* peerId);
}; };

View File

@ -35,6 +35,7 @@
#include "DHTGetPeersReplyMessage.h" #include "DHTGetPeersReplyMessage.h"
#include <cstring> #include <cstring>
#include <array>
#include "DHTNode.h" #include "DHTNode.h"
#include "DHTBucket.h" #include "DHTBucket.h"
@ -81,24 +82,24 @@ std::unique_ptr<Dict> DHTGetPeersReplyMessage::getResponse()
rDict->put(TOKEN, token_); rDict->put(TOKEN, token_);
// TODO want parameter // TODO want parameter
if (!closestKNodes_.empty()) { if (!closestKNodes_.empty()) {
unsigned char buffer[DHTBucket::K * 38]; std::array<unsigned char, DHTBucket::K * 38> buffer;
const int clen = bittorrent::getCompactLength(family_); const auto clen = bittorrent::getCompactLength(family_);
const int unit = clen + 20; const auto unit = clen + DHT_ID_LENGTH;
size_t offset = 0; auto last = std::begin(buffer);
size_t k = 0; size_t k = 0;
for (auto i = std::begin(closestKNodes_), eoi = std::end(closestKNodes_); for (auto i = std::begin(closestKNodes_);
i != eoi && k < DHTBucket::K; ++i) { i != std::end(closestKNodes_) && k < DHTBucket::K; ++i) {
memcpy(buffer + offset, (*i)->getID(), DHT_ID_LENGTH); std::array<unsigned char, COMPACT_LEN_IPV6> compact;
unsigned char compact[COMPACT_LEN_IPV6]; auto compactlen = bittorrent::packcompact(
int compactlen = bittorrent::packcompact(compact, (*i)->getIPAddress(), compact.data(), (*i)->getIPAddress(), (*i)->getPort());
(*i)->getPort());
if (compactlen == clen) { if (compactlen == clen) {
memcpy(buffer + 20 + offset, compact, compactlen); last = std::copy_n((*i)->getID(), DHT_ID_LENGTH, last);
offset += unit; last = std::copy_n(std::begin(compact), compactlen, last);
++k; ++k;
} }
} }
rDict->put(family_ == AF_INET ? NODES : NODES6, String::g(buffer, offset)); rDict->put(family_ == AF_INET ? NODES : NODES6,
String::g(std::begin(buffer), last));
} }
if (!values_.empty()) { if (!values_.empty()) {
// Limit the size of values list. The maximum size of UDP datagram // Limit the size of values list. The maximum size of UDP datagram
@ -123,16 +124,16 @@ std::unique_ptr<Dict> DHTGetPeersReplyMessage::getResponse()
// doesn't specify the maximum size of token, reply message // doesn't specify the maximum size of token, reply message
// template may get bigger than 395 bytes. So we use 25 as maximum // template may get bigger than 395 bytes. So we use 25 as maximum
// number of peer info that a message can carry. // number of peer info that a message can carry.
static const size_t MAX_VALUES_SIZE = 25; constexpr size_t MAX_VALUES_SIZE = 25;
auto valuesList = List::g(); auto valuesList = List::g();
for (auto i = std::begin(values_), eoi = std::end(values_); for (auto i = std::begin(values_);
i != eoi && valuesList->size() < MAX_VALUES_SIZE; ++i) { i != std::end(values_) && valuesList->size() < MAX_VALUES_SIZE; ++i) {
unsigned char compact[COMPACT_LEN_IPV6]; std::array<unsigned char, COMPACT_LEN_IPV6> compact;
const int clen = bittorrent::getCompactLength(family_); const auto clen = bittorrent::getCompactLength(family_);
int compactlen = bittorrent::packcompact(compact, (*i)->getIPAddress(), auto compactlen = bittorrent::packcompact(
(*i)->getPort()); compact.data(), (*i)->getIPAddress(), (*i)->getPort());
if (compactlen == clen) { if (compactlen == clen) {
valuesList->append(String::g(compact, compactlen)); valuesList->append(String::g(compact.data(), compactlen));
} }
} }
rDict->put(VALUES, std::move(valuesList)); rDict->put(VALUES, std::move(valuesList));

View File

@ -412,98 +412,10 @@ ssize_t MultiDiskAdaptor::readData(unsigned char* data, size_t len,
void MultiDiskAdaptor::writeCache(const WrDiskCacheEntry* entry) void MultiDiskAdaptor::writeCache(const WrDiskCacheEntry* entry)
{ {
// Write cached data in 4KiB aligned offset. This reduces disk for (auto& d : entry->getDataSet()) {
// activity especially on Windows 7 NTFS. A2_LOG_DEBUG(fmt("Cache flush goff=%" PRId64 ", len=%lu", d->goff, d->len));
unsigned char buf[16_k]; writeData(d->data + d->offset, d->len, d->goff);
size_t buflen = 0;
size_t buffoffset = 0;
auto& dataSet = entry->getDataSet();
if (dataSet.empty()) {
return;
} }
auto dent =
findFirstDiskWriterEntry(diskWriterEntries_, (*dataSet.begin())->goff),
eod = diskWriterEntries_.cend();
auto i = std::begin(dataSet), eoi = std::end(dataSet);
size_t celloff = 0;
for (; dent != eod; ++dent) {
int64_t lstart = 0, lp = 0;
auto& fent = (*dent)->getFileEntry();
if (fent->getLength() == 0) {
continue;
}
for (; i != eoi;) {
if (std::max(fent->getOffset(),
static_cast<int64_t>((*i)->goff + celloff)) <
std::min(fent->getLastOffset(),
static_cast<int64_t>((*i)->goff + (*i)->len))) {
openIfNot((*dent).get(), &DiskWriterEntry::openFile);
if (!(*dent)->isOpen()) {
throwOnDiskWriterNotOpened((*dent).get(), (*i)->goff + celloff);
}
}
else {
A2_LOG_DEBUG(fmt("%s Cache flush loff=%" PRId64 ", len=%lu",
fent->getPath().c_str(), lstart,
static_cast<unsigned long>(buflen - buffoffset)));
(*dent)->getDiskWriter()->writeData(buf + buffoffset,
buflen - buffoffset, lstart);
buflen = buffoffset = 0;
break;
}
int64_t loff = fent->gtoloff((*i)->goff + celloff);
if (static_cast<int64_t>(lstart + buflen) < loff) {
A2_LOG_DEBUG(fmt("%s Cache flush loff=%" PRId64 ", len=%lu",
fent->getPath().c_str(), lstart,
static_cast<unsigned long>(buflen - buffoffset)));
(*dent)->getDiskWriter()->writeData(buf + buffoffset,
buflen - buffoffset, lstart);
lstart = lp = loff;
buflen = buffoffset = 0;
}
// If the position of the cache data is not aligned, offset
// buffer so that next write can be aligned.
if (buflen == 0) {
buflen = buffoffset = loff & 0xfff;
}
assert((*i)->len > celloff);
for (;;) {
size_t wlen = std::min(static_cast<int64_t>((*i)->len - celloff),
fent->getLength() - lp);
wlen = std::min(wlen, sizeof(buf) - buflen);
memcpy(buf + buflen, (*i)->data + (*i)->offset + celloff, wlen);
buflen += wlen;
celloff += wlen;
lp += wlen;
if (lp == fent->getLength() || buflen == sizeof(buf)) {
A2_LOG_DEBUG(fmt("%s Cache flush loff=%" PRId64 ", len=%lu",
fent->getPath().c_str(), lstart,
static_cast<unsigned long>(buflen - buffoffset)));
(*dent)->getDiskWriter()->writeData(buf + buffoffset,
buflen - buffoffset, lstart);
lstart += buflen - buffoffset;
lp = lstart;
buflen = buffoffset = 0;
}
if (lp == fent->getLength() || celloff == (*i)->len) {
break;
}
}
if (celloff == (*i)->len) {
++i;
celloff = 0;
}
}
if (i == eoi) {
A2_LOG_DEBUG(fmt("%s Cache flush loff=%" PRId64 ", len=%lu",
fent->getPath().c_str(), lstart,
static_cast<unsigned long>(buflen - buffoffset)));
(*dent)->getDiskWriter()->writeData(buf + buffoffset, buflen - buffoffset,
lstart);
break;
}
}
assert(i == eoi);
} }
bool MultiDiskAdaptor::fileExists() bool MultiDiskAdaptor::fileExists()

View File

@ -69,10 +69,15 @@ std::unique_ptr<Cookie> parseNsCookie(const std::string& cookieStr,
return nullptr; return nullptr;
} }
int64_t expiryTime; int64_t expiryTime;
if (!util::parseLLIntNoThrow(expiryTime, {
// chrome extension uses subsecond resolution for expiry time.
double expiryTimeDouble;
if (!util::parseDoubleNoThrow(expiryTimeDouble,
std::string(vs[4].first, vs[4].second))) { std::string(vs[4].first, vs[4].second))) {
return nullptr; return nullptr;
} }
expiryTime = static_cast<int64_t>(expiryTimeDouble);
}
if (std::numeric_limits<time_t>::max() < expiryTime) { if (std::numeric_limits<time_t>::max() < expiryTime) {
expiryTime = std::numeric_limits<time_t>::max(); expiryTime = std::numeric_limits<time_t>::max();
} }

View File

@ -59,8 +59,13 @@ Sqlite3ChromiumCookieParser::~Sqlite3ChromiumCookieParser() {}
const char* Sqlite3ChromiumCookieParser::getQuery() const const char* Sqlite3ChromiumCookieParser::getQuery() const
{ {
return "SELECT host_key, path, secure, expires_utc, name, value, " // chrome's time is microsecond resolution, and its epoc is Jan 1
"last_access_utc" // 00:00:00 +0000 1601, so we have to convert it to second from UNIX
// epoc. 11644473600 is the second between chrome's epoc and UNIX
// epoc. e.g., date +%s -d 'Jan 1 00:00:00 +0000 1601'
return "SELECT host_key, path, secure, expires_utc / 1000000 - 11644473600 "
"as expires_utc, name, value, "
"last_access_utc / 1000000 - 11644473600 as last_access_utc"
" FROM cookies"; " FROM cookies";
} }

View File

@ -596,6 +596,33 @@ bool parseLLIntNoThrow(int64_t& res, const std::string& s, int base)
} }
} }
bool parseDoubleNoThrow(double& res, const std::string& s)
{
if (s.empty()) {
return false;
}
errno = 0;
char* endptr;
auto d = strtod(s.c_str(), &endptr);
if (errno == ERANGE) {
return false;
}
if (endptr != s.c_str() + s.size()) {
for (auto i = std::begin(s) + (endptr - s.c_str()); i != std::end(s); ++i) {
if (!isspace(*i)) {
return false;
}
}
}
res = d;
return true;
}
SegList<int> parseIntSegments(const std::string& src) SegList<int> parseIntSegments(const std::string& src)
{ {
SegList<int> sgl; SegList<int> sgl;

View File

@ -280,6 +280,10 @@ bool parseUIntNoThrow(uint32_t& res, const std::string& s, int base = 10);
bool parseLLIntNoThrow(int64_t& res, const std::string& s, int base = 10); bool parseLLIntNoThrow(int64_t& res, const std::string& s, int base = 10);
// Parses |s| as floating point number, and stores the result into
// |res|. This function returns true if it succeeds.
bool parseDoubleNoThrow(double& res, const std::string& s);
SegList<int> parseIntSegments(const std::string& src); SegList<int> parseIntSegments(const std::string& src);
// Parses string which specifies the range of piece index for higher // Parses string which specifies the range of piece index for higher

View File

@ -328,10 +328,10 @@ void CookieStorageTest::testLoad()
c = cookies[3]; c = cookies[3];
CPPUNIT_ASSERT_EQUAL(std::string("TAX"), c->getName()); CPPUNIT_ASSERT_EQUAL(std::string("TAX"), c->getName());
CPPUNIT_ASSERT_EQUAL(std::string("1000"), c->getValue()); CPPUNIT_ASSERT_EQUAL(std::string("1000"), c->getValue());
CPPUNIT_ASSERT((time_t)INT32_MAX <= c->getExpiryTime()); CPPUNIT_ASSERT_EQUAL((time_t)1463304912, c->getExpiryTime());
CPPUNIT_ASSERT(c->getPersistent()); CPPUNIT_ASSERT(c->getPersistent());
CPPUNIT_ASSERT_EQUAL(std::string("/"), c->getPath()); CPPUNIT_ASSERT_EQUAL(std::string("/"), c->getPath());
CPPUNIT_ASSERT_EQUAL(std::string("overflow"), c->getDomain()); CPPUNIT_ASSERT_EQUAL(std::string("something"), c->getDomain());
CPPUNIT_ASSERT(!c->getSecure()); CPPUNIT_ASSERT(!c->getSecure());
} }

View File

@ -69,9 +69,9 @@ void NsCookieParserTest::testParse()
c = cookies[3].get(); c = cookies[3].get();
CPPUNIT_ASSERT_EQUAL(std::string("TAX"), c->getName()); CPPUNIT_ASSERT_EQUAL(std::string("TAX"), c->getName());
CPPUNIT_ASSERT_EQUAL(std::string("1000"), c->getValue()); CPPUNIT_ASSERT_EQUAL(std::string("1000"), c->getValue());
CPPUNIT_ASSERT((time_t)INT32_MAX <= c->getExpiryTime()); CPPUNIT_ASSERT_EQUAL((time_t)1463304912, c->getExpiryTime());
CPPUNIT_ASSERT(c->getPersistent()); CPPUNIT_ASSERT(c->getPersistent());
CPPUNIT_ASSERT_EQUAL(std::string("overflow"), c->getDomain()); CPPUNIT_ASSERT_EQUAL(std::string("something"), c->getDomain());
CPPUNIT_ASSERT(c->getHostOnly()); CPPUNIT_ASSERT(c->getHostOnly());
CPPUNIT_ASSERT_EQUAL(std::string("/"), c->getPath()); CPPUNIT_ASSERT_EQUAL(std::string("/"), c->getPath());
CPPUNIT_ASSERT(!c->getSecure()); CPPUNIT_ASSERT(!c->getSecure());

View File

@ -66,6 +66,7 @@ class UtilTest2 : public CppUnit::TestFixture {
CPPUNIT_TEST(testInPrivateAddress); CPPUNIT_TEST(testInPrivateAddress);
CPPUNIT_TEST(testSecfmt); CPPUNIT_TEST(testSecfmt);
CPPUNIT_TEST(testTlsHostnameMatch); CPPUNIT_TEST(testTlsHostnameMatch);
CPPUNIT_TEST(testParseDoubleNoThrow);
CPPUNIT_TEST_SUITE_END(); CPPUNIT_TEST_SUITE_END();
private: private:
@ -115,6 +116,7 @@ public:
void testInPrivateAddress(); void testInPrivateAddress();
void testSecfmt(); void testSecfmt();
void testTlsHostnameMatch(); void testTlsHostnameMatch();
void testParseDoubleNoThrow();
}; };
CPPUNIT_TEST_SUITE_REGISTRATION(UtilTest2); CPPUNIT_TEST_SUITE_REGISTRATION(UtilTest2);
@ -978,4 +980,21 @@ void UtilTest2::testTlsHostnameMatch()
CPPUNIT_ASSERT(!util::tlsHostnameMatch("xn--*.a.b", "xn--c.a.b")); CPPUNIT_ASSERT(!util::tlsHostnameMatch("xn--*.a.b", "xn--c.a.b"));
} }
void UtilTest2::testParseDoubleNoThrow()
{
double n;
CPPUNIT_ASSERT(util::parseDoubleNoThrow(n, " 123 "));
CPPUNIT_ASSERT_EQUAL(123., n);
CPPUNIT_ASSERT(util::parseDoubleNoThrow(n, "3.14"));
CPPUNIT_ASSERT_EQUAL(3.14, n);
CPPUNIT_ASSERT(util::parseDoubleNoThrow(n, "-3.14"));
CPPUNIT_ASSERT_EQUAL(-3.14, n);
CPPUNIT_ASSERT(!util::parseDoubleNoThrow(n, ""));
CPPUNIT_ASSERT(!util::parseDoubleNoThrow(n, "123x"));
}
} // namespace aria2 } // namespace aria2

Binary file not shown.

View File

@ -5,5 +5,5 @@ expired FALSE / FALSE 1000 user me
192.168.0.1 TRUE /cgi-bin FALSE 0 passwd secret 192.168.0.1 TRUE /cgi-bin FALSE 0 passwd secret
badformat badformat
overflow FALSE / FALSE 9223372036854775807 TAX 1000 something FALSE / FALSE 1463304912.5 TAX 1000
.example.org TRUE / FALSE 2147483647 novalue .example.org TRUE / FALSE 2147483647.123 novalue