mirror of https://github.com/aria2/aria2
Merge branch 'master' into dynamic-select-file
commit
9727b5b256
6
AUTHORS
6
AUTHORS
|
@ -16,13 +16,17 @@ ITriskTI
|
|||
Igor Khomyakov
|
||||
Jarda Snajdr
|
||||
Kcchouette
|
||||
Kurt Kartaltepe
|
||||
Mingye Wang
|
||||
Nils Maier
|
||||
ORiON-
|
||||
ReadmeCritic
|
||||
Ross Smith II
|
||||
Ryan Steinmetz
|
||||
Ryo ONODERA
|
||||
Sarim Khan
|
||||
Sergey Zolotarev
|
||||
Sonny Piers
|
||||
Tatsuhiro Tsujikawa
|
||||
Vasilij Schneidermann
|
||||
Zoltan Toth-Czifra
|
||||
|
@ -36,6 +40,6 @@ luokar
|
|||
mozillazg
|
||||
multisnow
|
||||
oliviercommelarbre
|
||||
Sonny Piers
|
||||
rotor
|
||||
|
||||
[1] https://gist.github.com/tatsuhiro-t/deaffeb064652104ad11
|
||||
|
|
84
NEWS
84
NEWS
|
@ -1,37 +1,79 @@
|
|||
aria2 1.22.0
|
||||
aria2 1.23.0
|
||||
============
|
||||
|
||||
Release Note
|
||||
------------
|
||||
|
||||
This release adds new feature that manages the number of concurrent
|
||||
downloads dynamically. --stream-piece-selector option gets new value
|
||||
"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.
|
||||
This release fixes several bugs reported by users, and adds several
|
||||
new features. Read the following section for details.
|
||||
|
||||
Changes
|
||||
-------
|
||||
|
||||
* Add description about possible fragmentation with
|
||||
--file-allocation=trunc
|
||||
* Simplify cache write
|
||||
|
||||
* 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
|
||||
downloads as a function of the overall bandwidth observed
|
||||
* Adjust chromium cookie time
|
||||
|
||||
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
|
||||
|
|
|
@ -42,7 +42,7 @@ aria2c executable was generated using android-ndk-r10d.
|
|||
|
||||
The following libraries were statically linked.
|
||||
|
||||
* openssl 1.0.2g
|
||||
* openssl 1.0.2h
|
||||
* expat 2.1.0
|
||||
* c-ares 1.11.0
|
||||
* libssh2 1.7.0
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# Process this file with autoconf to produce a configure script.
|
||||
#
|
||||
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_TARGET
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -30,7 +30,7 @@ echo "Renaming po files..."
|
|||
mv "$WORK_DIR"/aria2/*.po "$WORK_DIR"
|
||||
|
||||
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
|
||||
sed -i -e 's/\\r//' "$file"
|
||||
bn=`basename "$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
|
||||
this writing. It includes all PO files translated at launchpad. To
|
||||
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``.
|
||||
|
|
|
@ -96,49 +96,10 @@ ssize_t AbstractSingleDiskAdaptor::readDataDropCache(unsigned char* data,
|
|||
|
||||
void AbstractSingleDiskAdaptor::writeCache(const WrDiskCacheEntry* entry)
|
||||
{
|
||||
// Write cached data in 4KiB aligned offset. This reduces disk
|
||||
// activity especially on Windows 7 NTFS. In this code, we assume
|
||||
// that maximum length of DataCell data is 16KiB to simplify the
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
for (auto& d : entry->getDataSet()) {
|
||||
A2_LOG_DEBUG(fmt("Cache flush goff=%" PRId64 ", len=%lu", d->goff, d->len));
|
||||
writeData(d->data + d->offset, d->len, d->goff);
|
||||
}
|
||||
writeData(buf + buffoffset, buflen - buffoffset, start);
|
||||
}
|
||||
|
||||
bool AbstractSingleDiskAdaptor::fileExists()
|
||||
|
|
|
@ -37,16 +37,13 @@
|
|||
#include <cstring>
|
||||
|
||||
#include "util.h"
|
||||
#include "BtConstants.h"
|
||||
#include "a2functional.h"
|
||||
|
||||
namespace aria2 {
|
||||
|
||||
const unsigned char BtHandshakeMessage::BT_PSTR[] = "BitTorrent protocol";
|
||||
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(const unsigned char* infoHash,
|
||||
|
@ -54,19 +51,17 @@ BtHandshakeMessage::BtHandshakeMessage(const unsigned char* infoHash,
|
|||
: SimpleBtMessage(ID, NAME)
|
||||
{
|
||||
init();
|
||||
memcpy(infoHash_, infoHash, INFO_HASH_LENGTH);
|
||||
memcpy(peerId_, peerId, PEER_ID_LENGTH);
|
||||
std::copy_n(infoHash, infoHash_.size(), std::begin(infoHash_));
|
||||
std::copy_n(peerId, peerId_.size(), std::begin(peerId_));
|
||||
}
|
||||
|
||||
BtHandshakeMessage::~BtHandshakeMessage() {}
|
||||
|
||||
void BtHandshakeMessage::init()
|
||||
{
|
||||
pstrlen_ = 19;
|
||||
pstr_ = new unsigned char[PSTR_LENGTH];
|
||||
reserved_ = new unsigned char[RESERVED_LENGTH];
|
||||
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);
|
||||
std::copy_n(BT_PSTR, pstr_.size(), std::begin(pstr_));
|
||||
std::fill(std::begin(reserved_), std::end(reserved_), 0);
|
||||
// fast extension
|
||||
reserved_[7] |= 0x04u;
|
||||
// extended messaging
|
||||
|
@ -76,23 +71,25 @@ void BtHandshakeMessage::init()
|
|||
std::unique_ptr<BtHandshakeMessage>
|
||||
BtHandshakeMessage::create(const unsigned char* data, size_t dataLength)
|
||||
{
|
||||
auto message = make_unique<BtHandshakeMessage>();
|
||||
message->pstrlen_ = data[0];
|
||||
memcpy(message->pstr_, &data[1], PSTR_LENGTH);
|
||||
memcpy(message->reserved_, &data[20], RESERVED_LENGTH);
|
||||
memcpy(message->infoHash_, &data[28], INFO_HASH_LENGTH);
|
||||
memcpy(message->peerId_, &data[48], PEER_ID_LENGTH);
|
||||
return message;
|
||||
auto msg = make_unique<BtHandshakeMessage>();
|
||||
msg->pstrlen_ = data[0];
|
||||
std::copy_n(&data[1], msg->pstr_.size(), std::begin(msg->pstr_));
|
||||
std::copy_n(&data[20], msg->reserved_.size(), std::begin(msg->reserved_));
|
||||
std::copy_n(&data[28], msg->infoHash_.size(), std::begin(msg->infoHash_));
|
||||
std::copy_n(&data[48], msg->peerId_.size(), std::begin(msg->peerId_));
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
unsigned char* BtHandshakeMessage::createMessage()
|
||||
{
|
||||
auto msg = new unsigned char[MESSAGE_LENGTH];
|
||||
msg[0] = pstrlen_;
|
||||
memcpy(msg + 1, pstr_, PSTR_LENGTH);
|
||||
memcpy(msg + 20, reserved_, RESERVED_LENGTH);
|
||||
memcpy(msg + 28, infoHash_, INFO_HASH_LENGTH);
|
||||
memcpy(msg + 48, peerId_, PEER_ID_LENGTH);
|
||||
auto dst = msg;
|
||||
*dst++ = pstrlen_;
|
||||
dst = std::copy(std::begin(pstr_), std::end(pstr_), dst);
|
||||
dst = std::copy(std::begin(reserved_), std::end(reserved_), dst);
|
||||
dst = std::copy(std::begin(infoHash_), std::end(infoHash_), dst);
|
||||
std::copy(std::begin(peerId_), std::end(peerId_), dst);
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
@ -101,8 +98,8 @@ size_t BtHandshakeMessage::getMessageLength() { return MESSAGE_LENGTH; }
|
|||
std::string BtHandshakeMessage::toString() const
|
||||
{
|
||||
return fmt("%s peerId=%s, reserved=%s", NAME,
|
||||
util::percentEncode(peerId_, PEER_ID_LENGTH).c_str(),
|
||||
util::toHex(reserved_, RESERVED_LENGTH).c_str());
|
||||
util::percentEncode(peerId_.data(), peerId_.size()).c_str(),
|
||||
util::toHex(reserved_.data(), reserved_.size()).c_str());
|
||||
}
|
||||
|
||||
bool BtHandshakeMessage::isFastExtensionSupported() const
|
||||
|
@ -119,12 +116,12 @@ bool BtHandshakeMessage::isDHTEnabled() const { return reserved_[7] & 0x01u; }
|
|||
|
||||
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)
|
||||
{
|
||||
memcpy(peerId_, peerId, PEER_ID_LENGTH);
|
||||
std::copy_n(peerId, peerId_.size(), std::begin(peerId_));
|
||||
}
|
||||
|
||||
} // namespace aria2
|
||||
|
|
|
@ -37,21 +37,26 @@
|
|||
|
||||
#include "SimpleBtMessage.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "BtConstants.h"
|
||||
|
||||
namespace aria2 {
|
||||
|
||||
class BtHandshakeMessage : public SimpleBtMessage {
|
||||
public:
|
||||
static const size_t PSTR_LENGTH = 19;
|
||||
static const unsigned char* BT_PSTR;
|
||||
static const size_t RESERVED_LENGTH = 8;
|
||||
static const size_t MESSAGE_LENGTH = 68;
|
||||
constexpr static size_t PSTR_LENGTH = 19;
|
||||
constexpr static size_t RESERVED_LENGTH = 8;
|
||||
constexpr static size_t MESSAGE_LENGTH = 68;
|
||||
const static unsigned char BT_PSTR[];
|
||||
|
||||
private:
|
||||
uint8_t pstrlen_;
|
||||
unsigned char* pstr_;
|
||||
unsigned char* reserved_;
|
||||
unsigned char* infoHash_;
|
||||
unsigned char* peerId_;
|
||||
std::array<unsigned char, PSTR_LENGTH> pstr_;
|
||||
std::array<unsigned char, RESERVED_LENGTH> reserved_;
|
||||
std::array<unsigned char, INFO_HASH_LENGTH> infoHash_;
|
||||
std::array<unsigned char, PEER_ID_LENGTH> peerId_;
|
||||
|
||||
void init();
|
||||
|
||||
public:
|
||||
|
@ -66,17 +71,11 @@ public:
|
|||
static std::unique_ptr<BtHandshakeMessage> create(const unsigned char* data,
|
||||
size_t dataLength);
|
||||
|
||||
virtual ~BtHandshakeMessage()
|
||||
{
|
||||
delete[] pstr_;
|
||||
delete[] reserved_;
|
||||
delete[] infoHash_;
|
||||
delete[] peerId_;
|
||||
}
|
||||
virtual ~BtHandshakeMessage();
|
||||
|
||||
static const uint8_t ID = INT8_MAX;
|
||||
|
||||
static const char NAME[];
|
||||
const static char NAME[];
|
||||
|
||||
virtual void doReceivedAction() CXX11_OVERRIDE{};
|
||||
|
||||
|
@ -104,15 +103,15 @@ public:
|
|||
|
||||
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);
|
||||
|
||||
const unsigned char* getPeerId() const { return peerId_; }
|
||||
const unsigned char* getPeerId() const { return peerId_.data(); }
|
||||
|
||||
void setPeerId(const unsigned char* peerId);
|
||||
};
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "DHTGetPeersReplyMessage.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <array>
|
||||
|
||||
#include "DHTNode.h"
|
||||
#include "DHTBucket.h"
|
||||
|
@ -81,24 +82,24 @@ std::unique_ptr<Dict> DHTGetPeersReplyMessage::getResponse()
|
|||
rDict->put(TOKEN, token_);
|
||||
// TODO want parameter
|
||||
if (!closestKNodes_.empty()) {
|
||||
unsigned char buffer[DHTBucket::K * 38];
|
||||
const int clen = bittorrent::getCompactLength(family_);
|
||||
const int unit = clen + 20;
|
||||
size_t offset = 0;
|
||||
std::array<unsigned char, DHTBucket::K * 38> buffer;
|
||||
const auto clen = bittorrent::getCompactLength(family_);
|
||||
const auto unit = clen + DHT_ID_LENGTH;
|
||||
auto last = std::begin(buffer);
|
||||
size_t k = 0;
|
||||
for (auto i = std::begin(closestKNodes_), eoi = std::end(closestKNodes_);
|
||||
i != eoi && k < DHTBucket::K; ++i) {
|
||||
memcpy(buffer + offset, (*i)->getID(), DHT_ID_LENGTH);
|
||||
unsigned char compact[COMPACT_LEN_IPV6];
|
||||
int compactlen = bittorrent::packcompact(compact, (*i)->getIPAddress(),
|
||||
(*i)->getPort());
|
||||
for (auto i = std::begin(closestKNodes_);
|
||||
i != std::end(closestKNodes_) && k < DHTBucket::K; ++i) {
|
||||
std::array<unsigned char, COMPACT_LEN_IPV6> compact;
|
||||
auto compactlen = bittorrent::packcompact(
|
||||
compact.data(), (*i)->getIPAddress(), (*i)->getPort());
|
||||
if (compactlen == clen) {
|
||||
memcpy(buffer + 20 + offset, compact, compactlen);
|
||||
offset += unit;
|
||||
last = std::copy_n((*i)->getID(), DHT_ID_LENGTH, last);
|
||||
last = std::copy_n(std::begin(compact), compactlen, last);
|
||||
++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()) {
|
||||
// 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
|
||||
// template may get bigger than 395 bytes. So we use 25 as maximum
|
||||
// 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();
|
||||
for (auto i = std::begin(values_), eoi = std::end(values_);
|
||||
i != eoi && valuesList->size() < MAX_VALUES_SIZE; ++i) {
|
||||
unsigned char compact[COMPACT_LEN_IPV6];
|
||||
const int clen = bittorrent::getCompactLength(family_);
|
||||
int compactlen = bittorrent::packcompact(compact, (*i)->getIPAddress(),
|
||||
(*i)->getPort());
|
||||
for (auto i = std::begin(values_);
|
||||
i != std::end(values_) && valuesList->size() < MAX_VALUES_SIZE; ++i) {
|
||||
std::array<unsigned char, COMPACT_LEN_IPV6> compact;
|
||||
const auto clen = bittorrent::getCompactLength(family_);
|
||||
auto compactlen = bittorrent::packcompact(
|
||||
compact.data(), (*i)->getIPAddress(), (*i)->getPort());
|
||||
if (compactlen == clen) {
|
||||
valuesList->append(String::g(compact, compactlen));
|
||||
valuesList->append(String::g(compact.data(), compactlen));
|
||||
}
|
||||
}
|
||||
rDict->put(VALUES, std::move(valuesList));
|
||||
|
|
|
@ -412,98 +412,10 @@ ssize_t MultiDiskAdaptor::readData(unsigned char* data, size_t len,
|
|||
|
||||
void MultiDiskAdaptor::writeCache(const WrDiskCacheEntry* entry)
|
||||
{
|
||||
// Write cached data in 4KiB aligned offset. This reduces disk
|
||||
// activity especially on Windows 7 NTFS.
|
||||
unsigned char buf[16_k];
|
||||
size_t buflen = 0;
|
||||
size_t buffoffset = 0;
|
||||
auto& dataSet = entry->getDataSet();
|
||||
if (dataSet.empty()) {
|
||||
return;
|
||||
for (auto& d : entry->getDataSet()) {
|
||||
A2_LOG_DEBUG(fmt("Cache flush goff=%" PRId64 ", len=%lu", d->goff, d->len));
|
||||
writeData(d->data + d->offset, d->len, d->goff);
|
||||
}
|
||||
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()
|
||||
|
|
|
@ -69,9 +69,14 @@ std::unique_ptr<Cookie> parseNsCookie(const std::string& cookieStr,
|
|||
return nullptr;
|
||||
}
|
||||
int64_t expiryTime;
|
||||
if (!util::parseLLIntNoThrow(expiryTime,
|
||||
std::string(vs[4].first, vs[4].second))) {
|
||||
return nullptr;
|
||||
{
|
||||
// chrome extension uses subsecond resolution for expiry time.
|
||||
double expiryTimeDouble;
|
||||
if (!util::parseDoubleNoThrow(expiryTimeDouble,
|
||||
std::string(vs[4].first, vs[4].second))) {
|
||||
return nullptr;
|
||||
}
|
||||
expiryTime = static_cast<int64_t>(expiryTimeDouble);
|
||||
}
|
||||
if (std::numeric_limits<time_t>::max() < expiryTime) {
|
||||
expiryTime = std::numeric_limits<time_t>::max();
|
||||
|
|
|
@ -59,8 +59,13 @@ Sqlite3ChromiumCookieParser::~Sqlite3ChromiumCookieParser() {}
|
|||
|
||||
const char* Sqlite3ChromiumCookieParser::getQuery() const
|
||||
{
|
||||
return "SELECT host_key, path, secure, expires_utc, name, value, "
|
||||
"last_access_utc"
|
||||
// chrome's time is microsecond resolution, and its epoc is Jan 1
|
||||
// 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";
|
||||
}
|
||||
|
||||
|
|
27
src/util.cc
27
src/util.cc
|
@ -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> sgl;
|
||||
|
|
|
@ -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);
|
||||
|
||||
// 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);
|
||||
|
||||
// Parses string which specifies the range of piece index for higher
|
||||
|
|
|
@ -328,10 +328,10 @@ void CookieStorageTest::testLoad()
|
|||
c = cookies[3];
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("TAX"), c->getName());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("1000"), c->getValue());
|
||||
CPPUNIT_ASSERT((time_t)INT32_MAX <= c->getExpiryTime());
|
||||
CPPUNIT_ASSERT_EQUAL((time_t)1463304912, c->getExpiryTime());
|
||||
CPPUNIT_ASSERT(c->getPersistent());
|
||||
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());
|
||||
}
|
||||
|
||||
|
|
|
@ -69,9 +69,9 @@ void NsCookieParserTest::testParse()
|
|||
c = cookies[3].get();
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("TAX"), c->getName());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("1000"), c->getValue());
|
||||
CPPUNIT_ASSERT((time_t)INT32_MAX <= c->getExpiryTime());
|
||||
CPPUNIT_ASSERT_EQUAL((time_t)1463304912, c->getExpiryTime());
|
||||
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_EQUAL(std::string("/"), c->getPath());
|
||||
CPPUNIT_ASSERT(!c->getSecure());
|
||||
|
|
|
@ -66,6 +66,7 @@ class UtilTest2 : public CppUnit::TestFixture {
|
|||
CPPUNIT_TEST(testInPrivateAddress);
|
||||
CPPUNIT_TEST(testSecfmt);
|
||||
CPPUNIT_TEST(testTlsHostnameMatch);
|
||||
CPPUNIT_TEST(testParseDoubleNoThrow);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
private:
|
||||
|
@ -115,6 +116,7 @@ public:
|
|||
void testInPrivateAddress();
|
||||
void testSecfmt();
|
||||
void testTlsHostnameMatch();
|
||||
void testParseDoubleNoThrow();
|
||||
};
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(UtilTest2);
|
||||
|
@ -978,4 +980,21 @@ void UtilTest2::testTlsHostnameMatch()
|
|||
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
|
||||
|
|
Binary file not shown.
|
@ -5,5 +5,5 @@ expired FALSE / FALSE 1000 user me
|
|||
|
||||
192.168.0.1 TRUE /cgi-bin FALSE 0 passwd secret
|
||||
badformat
|
||||
overflow FALSE / FALSE 9223372036854775807 TAX 1000
|
||||
.example.org TRUE / FALSE 2147483647 novalue
|
||||
something FALSE / FALSE 1463304912.5 TAX 1000
|
||||
.example.org TRUE / FALSE 2147483647.123 novalue
|
||||
|
|
Loading…
Reference in New Issue