2010-06-09 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

Made protected member variable private. Added accessor funcs.
	* src/AbstractCommand.cc
	* src/AbstractCommand.h
	* src/AbstractProxyRequestCommand.cc
	* src/AbstractProxyRequestCommand.h
	* src/AbstractProxyResponseCommand.cc
	* src/AbstractProxyResponseCommand.h
	* src/CreateRequestCommand.cc
	* src/DownloadCommand.cc
	* src/DownloadCommand.h
	* src/FtpDownloadCommand.cc
	* src/FtpDownloadCommand.h
	* src/FtpFinishDownloadCommand.cc
	* src/FtpInitiateConnectionCommand.cc
	* src/FtpNegotiationCommand.cc
	* src/FtpNegotiationCommand.h
	* src/FtpTunnelRequestCommand.cc
	* src/FtpTunnelResponseCommand.cc
	* src/HttpDownloadCommand.cc
	* src/HttpInitiateConnectionCommand.cc
	* src/HttpProxyRequestCommand.cc
	* src/HttpProxyResponseCommand.cc
	* src/HttpRequestCommand.cc
	* src/HttpResponseCommand.cc
	* src/HttpResponseCommand.h
	* src/HttpSkipResponseCommand.cc
	* src/InitiateConnectionCommand.cc
pull/1/head
Tatsuhiro Tsujikawa 2010-06-09 12:43:44 +00:00
parent 9afc36152a
commit 970e7f95a6
27 changed files with 823 additions and 668 deletions

View File

@ -1,3 +1,33 @@
2010-06-09 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Made protected member variable private. Added accessor funcs.
* src/AbstractCommand.cc
* src/AbstractCommand.h
* src/AbstractProxyRequestCommand.cc
* src/AbstractProxyRequestCommand.h
* src/AbstractProxyResponseCommand.cc
* src/AbstractProxyResponseCommand.h
* src/CreateRequestCommand.cc
* src/DownloadCommand.cc
* src/DownloadCommand.h
* src/FtpDownloadCommand.cc
* src/FtpDownloadCommand.h
* src/FtpFinishDownloadCommand.cc
* src/FtpInitiateConnectionCommand.cc
* src/FtpNegotiationCommand.cc
* src/FtpNegotiationCommand.h
* src/FtpTunnelRequestCommand.cc
* src/FtpTunnelResponseCommand.cc
* src/HttpDownloadCommand.cc
* src/HttpInitiateConnectionCommand.cc
* src/HttpProxyRequestCommand.cc
* src/HttpProxyResponseCommand.cc
* src/HttpRequestCommand.cc
* src/HttpResponseCommand.cc
* src/HttpResponseCommand.h
* src/HttpSkipResponseCommand.cc
* src/InitiateConnectionCommand.cc
2010-06-09 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net> 2010-06-09 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Made protected member variables of Command private. Added accessor Made protected member variables of Command private. Added accessor

View File

@ -77,15 +77,16 @@ AbstractCommand::AbstractCommand(cuid_t cuid,
RequestGroup* requestGroup, RequestGroup* requestGroup,
DownloadEngine* e, DownloadEngine* e,
const SocketHandle& s): const SocketHandle& s):
Command(cuid), checkPoint(global::wallclock), _requestGroup(requestGroup), Command(cuid), _checkPoint(global::wallclock),
req(req), _fileEntry(fileEntry), e(e), socket(s), _timeout(requestGroup->getTimeout()),
checkSocketIsReadable(false), checkSocketIsWritable(false), _requestGroup(requestGroup),
nameResolverCheck(false) _req(req), _fileEntry(fileEntry), _e(e), _socket(s),
_checkSocketIsReadable(false), _checkSocketIsWritable(false),
_nameResolverCheck(false)
{ {
if(!socket.isNull() && socket->isOpen()) { if(!_socket.isNull() && _socket->isOpen()) {
setReadCheckSocket(socket); setReadCheckSocket(_socket);
} }
timeout = _requestGroup->getTimeout();
_requestGroup->increaseStreamConnection(); _requestGroup->increaseStreamConnection();
_requestGroup->increaseNumCommand(); _requestGroup->increaseNumCommand();
} }
@ -113,19 +114,19 @@ bool AbstractCommand::execute() {
if(_requestGroup->downloadFinished() || _requestGroup->isHaltRequested()) { if(_requestGroup->downloadFinished() || _requestGroup->isHaltRequested()) {
return true; return true;
} }
if(!req.isNull() && req->removalRequested()) { if(!_req.isNull() && _req->removalRequested()) {
if(getLogger()->debug()) { if(getLogger()->debug()) {
getLogger()->debug getLogger()->debug
("CUID#%s - Discard original URI=%s because it is requested.", ("CUID#%s - Discard original URI=%s because it is requested.",
util::itos(getCuid()).c_str(), req->getUri().c_str()); util::itos(getCuid()).c_str(), _req->getUri().c_str());
} }
return prepareForRetry(0); return prepareForRetry(0);
} }
// TODO it is not needed to check other PeerStats every time. // TODO it is not needed to check other PeerStats every time.
// Find faster Request when no segment is available. // Find faster Request when no segment is available.
if(!req.isNull() && _fileEntry->countPooledRequest() > 0 && if(!_req.isNull() && _fileEntry->countPooledRequest() > 0 &&
!_requestGroup->getPieceStorage()->hasMissingUnusedPiece()) { !getPieceStorage()->hasMissingUnusedPiece()) {
SharedHandle<Request> fasterRequest = _fileEntry->findFasterRequest(req); SharedHandle<Request> fasterRequest = _fileEntry->findFasterRequest(_req);
if(!fasterRequest.isNull()) { if(!fasterRequest.isNull()) {
if(getLogger()->info()) { if(getLogger()->info()) {
getLogger()->info("CUID#%s - Use faster Request hostname=%s, port=%u", getLogger()->info("CUID#%s - Use faster Request hostname=%s, port=%u",
@ -134,29 +135,28 @@ bool AbstractCommand::execute() {
fasterRequest->getPort()); fasterRequest->getPort());
} }
// Cancel current Request object and use faster one. // Cancel current Request object and use faster one.
_fileEntry->removeRequest(req); _fileEntry->removeRequest(_req);
Command* command = Command* command =
InitiateConnectionCommandFactory::createInitiateConnectionCommand InitiateConnectionCommandFactory::createInitiateConnectionCommand
(getCuid(), fasterRequest, _fileEntry, _requestGroup, e); (getCuid(), fasterRequest, _fileEntry, _requestGroup, _e);
e->setNoWait(true); _e->setNoWait(true);
e->addCommand(command); _e->addCommand(command);
return true; return true;
} }
} }
if((checkSocketIsReadable && readEventEnabled()) || if((_checkSocketIsReadable && readEventEnabled()) ||
(checkSocketIsWritable && writeEventEnabled()) || (_checkSocketIsWritable && writeEventEnabled()) ||
hupEventEnabled() || hupEventEnabled() ||
#ifdef ENABLE_ASYNC_DNS #ifdef ENABLE_ASYNC_DNS
(nameResolverCheck && nameResolveFinished()) || (_nameResolverCheck && nameResolveFinished()) ||
#endif // ENABLE_ASYNC_DNS #endif // ENABLE_ASYNC_DNS
(!checkSocketIsReadable && !checkSocketIsWritable && (!_checkSocketIsReadable && !_checkSocketIsWritable &&
!nameResolverCheck)) { !_nameResolverCheck)) {
checkPoint = global::wallclock; _checkPoint = global::wallclock;
if(!_requestGroup->getPieceStorage().isNull()) { if(!getPieceStorage().isNull()) {
_segments.clear(); _segments.clear();
_requestGroup->getSegmentMan()->getInFlightSegment getSegmentMan()->getInFlightSegment(_segments, getCuid());
(_segments, getCuid()); if(!_req.isNull() && _segments.empty()) {
if(!req.isNull() && _segments.empty()) {
// This command previously has assigned segments, but it is // This command previously has assigned segments, but it is
// canceled. So discard current request chain. // canceled. So discard current request chain.
if(getLogger()->debug()) { if(getLogger()->debug()) {
@ -166,11 +166,11 @@ bool AbstractCommand::execute() {
} }
return prepareForRetry(0); return prepareForRetry(0);
} }
if(req.isNull() || req->getMaxPipelinedRequest() == 1 || if(_req.isNull() || _req->getMaxPipelinedRequest() == 1 ||
_requestGroup->getDownloadContext()->getFileEntries().size() == 1) { _requestGroup->getDownloadContext()->getFileEntries().size() == 1) {
if(_segments.empty()) { if(_segments.empty()) {
SharedHandle<Segment> segment = SharedHandle<Segment> segment =
_requestGroup->getSegmentMan()->getSegment(getCuid()); getSegmentMan()->getSegment(getCuid());
if(!segment.isNull()) { if(!segment.isNull()) {
_segments.push_back(segment); _segments.push_back(segment);
} }
@ -183,7 +183,7 @@ bool AbstractCommand::execute() {
} }
// When all segments are ignored in SegmentMan, there are // When all segments are ignored in SegmentMan, there are
// no URIs available, so don't retry. // no URIs available, so don't retry.
if(_requestGroup->getSegmentMan()->allSegmentsIgnored()) { if(getSegmentMan()->allSegmentsIgnored()) {
if(getLogger()->debug()) { if(getLogger()->debug()) {
getLogger()->debug("All segments are ignored."); getLogger()->debug("All segments are ignored.");
} }
@ -193,9 +193,9 @@ bool AbstractCommand::execute() {
} }
} }
} else { } else {
size_t maxSegments = req->getMaxPipelinedRequest(); size_t maxSegments = _req->getMaxPipelinedRequest();
if(_segments.size() < maxSegments) { if(_segments.size() < maxSegments) {
_requestGroup->getSegmentMan()->getSegment getSegmentMan()->getSegment
(_segments, getCuid(), _fileEntry, maxSegments); (_segments, getCuid(), _fileEntry, maxSegments);
} }
if(_segments.empty()) { if(_segments.empty()) {
@ -207,23 +207,23 @@ bool AbstractCommand::execute() {
} else if(errorEventEnabled()) { } else if(errorEventEnabled()) {
throw DL_RETRY_EX throw DL_RETRY_EX
(StringFormat(MSG_NETWORK_PROBLEM, (StringFormat(MSG_NETWORK_PROBLEM,
socket->getSocketError().c_str()).str()); _socket->getSocketError().c_str()).str());
} else { } else {
if(checkPoint.difference(global::wallclock) >= timeout) { if(_checkPoint.difference(global::wallclock) >= _timeout) {
// timeout triggers ServerStat error state. // timeout triggers ServerStat error state.
SharedHandle<ServerStat> ss = SharedHandle<ServerStat> ss =
e->getRequestGroupMan()->getOrCreateServerStat(req->getHost(), _e->getRequestGroupMan()->getOrCreateServerStat(_req->getHost(),
req->getProtocol()); _req->getProtocol());
ss->setError(); ss->setError();
throw DL_RETRY_EX2(EX_TIME_OUT, downloadresultcode::TIME_OUT); throw DL_RETRY_EX2(EX_TIME_OUT, downloadresultcode::TIME_OUT);
} }
e->addCommand(this); _e->addCommand(this);
return false; return false;
} }
} catch(DlAbortEx& err) { } catch(DlAbortEx& err) {
if(req.isNull()) { if(_req.isNull()) {
if(getLogger()->debug()) { if(getLogger()->debug()) {
getLogger()->debug(EX_EXCEPTION_CAUGHT, err); getLogger()->debug(EX_EXCEPTION_CAUGHT, err);
} }
@ -231,10 +231,10 @@ bool AbstractCommand::execute() {
getLogger()->error getLogger()->error
(MSG_DOWNLOAD_ABORTED, (MSG_DOWNLOAD_ABORTED,
DL_ABORT_EX2(StringFormat DL_ABORT_EX2(StringFormat
("URI=%s", req->getCurrentUri().c_str()).str(),err), ("URI=%s", _req->getCurrentUri().c_str()).str(),err),
util::itos(getCuid()).c_str(), req->getUri().c_str()); util::itos(getCuid()).c_str(), _req->getUri().c_str());
_fileEntry->addURIResult(req->getUri(), err.getCode()); _fileEntry->addURIResult(_req->getUri(), err.getCode());
_requestGroup->setLastUriResult(req->getUri(), err.getCode()); _requestGroup->setLastUriResult(_req->getUri(), err.getCode());
if(err.getCode() == downloadresultcode::CANNOT_RESUME) { if(err.getCode() == downloadresultcode::CANNOT_RESUME) {
_requestGroup->increaseResumeFailureCount(); _requestGroup->increaseResumeFailureCount();
} }
@ -243,29 +243,29 @@ bool AbstractCommand::execute() {
tryReserved(); tryReserved();
return true; return true;
} catch(DlRetryEx& err) { } catch(DlRetryEx& err) {
assert(!req.isNull()); assert(!_req.isNull());
if(getLogger()->info()) { if(getLogger()->info()) {
getLogger()->info getLogger()->info
(MSG_RESTARTING_DOWNLOAD, (MSG_RESTARTING_DOWNLOAD,
DL_RETRY_EX2(StringFormat DL_RETRY_EX2(StringFormat
("URI=%s", req->getCurrentUri().c_str()).str(), ("URI=%s", _req->getCurrentUri().c_str()).str(),
err), err),
util::itos(getCuid()).c_str(), req->getUri().c_str()); util::itos(getCuid()).c_str(), _req->getUri().c_str());
} }
req->addTryCount(); _req->addTryCount();
req->resetRedirectCount(); _req->resetRedirectCount();
const unsigned int maxTries = getOption()->getAsInt(PREF_MAX_TRIES); const unsigned int maxTries = getOption()->getAsInt(PREF_MAX_TRIES);
bool isAbort = maxTries != 0 && req->getTryCount() >= maxTries; bool isAbort = maxTries != 0 && _req->getTryCount() >= maxTries;
if(isAbort) { if(isAbort) {
if(getLogger()->info()) { if(getLogger()->info()) {
getLogger()->info(MSG_MAX_TRY, getLogger()->info(MSG_MAX_TRY,
util::itos(getCuid()).c_str(), req->getTryCount()); util::itos(getCuid()).c_str(), _req->getTryCount());
} }
getLogger()->error(MSG_DOWNLOAD_ABORTED, err, getLogger()->error(MSG_DOWNLOAD_ABORTED, err,
util::itos(getCuid()).c_str(), util::itos(getCuid()).c_str(),
req->getUri().c_str()); _req->getUri().c_str());
_fileEntry->addURIResult(req->getUri(), err.getCode()); _fileEntry->addURIResult(_req->getUri(), err.getCode());
_requestGroup->setLastUriResult(req->getUri(), err.getCode()); _requestGroup->setLastUriResult(_req->getUri(), err.getCode());
if(err.getCode() == downloadresultcode::CANNOT_RESUME) { if(err.getCode() == downloadresultcode::CANNOT_RESUME) {
_requestGroup->increaseResumeFailureCount(); _requestGroup->increaseResumeFailureCount();
} }
@ -277,9 +277,9 @@ bool AbstractCommand::execute() {
} }
} catch(DownloadFailureException& err) { } catch(DownloadFailureException& err) {
getLogger()->error(EX_EXCEPTION_CAUGHT, err); getLogger()->error(EX_EXCEPTION_CAUGHT, err);
if(!req.isNull()) { if(!_req.isNull()) {
_fileEntry->addURIResult(req->getUri(), err.getCode()); _fileEntry->addURIResult(_req->getUri(), err.getCode());
_requestGroup->setLastUriResult(req->getUri(), err.getCode()); _requestGroup->setLastUriResult(_req->getUri(), err.getCode());
} }
_requestGroup->setHaltRequested(true); _requestGroup->setHaltRequested(true);
return true; return true;
@ -308,59 +308,58 @@ void AbstractCommand::tryReserved() {
util::itos(getCuid()).c_str()); util::itos(getCuid()).c_str());
} }
std::vector<Command*> commands; std::vector<Command*> commands;
_requestGroup->createNextCommand(commands, e, 1); _requestGroup->createNextCommand(commands, _e, 1);
e->setNoWait(true); _e->setNoWait(true);
e->addCommand(commands); _e->addCommand(commands);
} }
bool AbstractCommand::prepareForRetry(time_t wait) { bool AbstractCommand::prepareForRetry(time_t wait) {
if(!_requestGroup->getPieceStorage().isNull()) { if(!getPieceStorage().isNull()) {
_requestGroup->getSegmentMan()->cancelSegment(getCuid()); getSegmentMan()->cancelSegment(getCuid());
} }
if(!req.isNull()) { if(!_req.isNull()) {
_fileEntry->poolRequest(req); _fileEntry->poolRequest(_req);
if(getLogger()->debug()) { if(getLogger()->debug()) {
getLogger()->debug("CUID#%s - Pooling request URI=%s", getLogger()->debug("CUID#%s - Pooling request URI=%s",
util::itos(getCuid()).c_str(), req->getUri().c_str()); util::itos(getCuid()).c_str(), _req->getUri().c_str());
} }
if(!_requestGroup->getSegmentMan().isNull()) { if(!getSegmentMan().isNull()) {
_requestGroup->getSegmentMan()->recognizeSegmentFor(_fileEntry); getSegmentMan()->recognizeSegmentFor(_fileEntry);
} }
} }
Command* command = new CreateRequestCommand(getCuid(), _requestGroup, e); Command* command = new CreateRequestCommand(getCuid(), _requestGroup, _e);
if(wait == 0) { if(wait == 0) {
e->setNoWait(true); _e->setNoWait(true);
e->addCommand(command); _e->addCommand(command);
} else { } else {
SleepCommand* scom = new SleepCommand(getCuid(), e, _requestGroup, SleepCommand* scom = new SleepCommand(getCuid(), _e, _requestGroup,
command, wait); command, wait);
e->addCommand(scom); _e->addCommand(scom);
} }
return true; return true;
} }
void AbstractCommand::onAbort() { void AbstractCommand::onAbort() {
if(!req.isNull()) { if(!_req.isNull()) {
// TODO This might be a problem if the failure is caused by proxy. // TODO This might be a problem if the failure is caused by proxy.
e->getRequestGroupMan()->getOrCreateServerStat _e->getRequestGroupMan()->getOrCreateServerStat
(req->getHost(), req->getProtocol())->setError(); (_req->getHost(), _req->getProtocol())->setError();
_fileEntry->removeIdenticalURI(req->getUri()); _fileEntry->removeIdenticalURI(_req->getUri());
_fileEntry->removeRequest(req); _fileEntry->removeRequest(_req);
} }
if(getLogger()->debug()) { if(getLogger()->debug()) {
getLogger()->debug("CUID#%s - Aborting download", getLogger()->debug("CUID#%s - Aborting download",
util::itos(getCuid()).c_str()); util::itos(getCuid()).c_str());
} }
if(!_requestGroup->getPieceStorage().isNull()) { if(!getPieceStorage().isNull()) {
SharedHandle<SegmentMan> segmentMan = _requestGroup->getSegmentMan(); getSegmentMan()->cancelSegment(getCuid());
segmentMan->cancelSegment(getCuid());
// Don't do following process if BitTorrent is involved or files // Don't do following process if BitTorrent is involved or files
// in DownloadContext is more than 1. The latter condition is // in DownloadContext is more than 1. The latter condition is
// limitation of current implementation. // limitation of current implementation.
if(!getOption()->getAsBool(PREF_ALWAYS_RESUME) && if(!getOption()->getAsBool(PREF_ALWAYS_RESUME) &&
!_fileEntry.isNull() && !_fileEntry.isNull() &&
segmentMan->calculateSessionDownloadLength() == 0 && getSegmentMan()->calculateSessionDownloadLength() == 0 &&
!_requestGroup->p2pInvolved() && !_requestGroup->p2pInvolved() &&
_requestGroup->getDownloadContext()->getFileEntries().size() == 1) { _requestGroup->getDownloadContext()->getFileEntries().size() == 1) {
const int maxTries = getOption()->getAsInt(PREF_MAX_RESUME_FAILURE_TRIES); const int maxTries = getOption()->getAsInt(PREF_MAX_RESUME_FAILURE_TRIES);
@ -383,9 +382,9 @@ void AbstractCommand::onAbort() {
std::deque<URIResult> res; std::deque<URIResult> res;
_fileEntry->extractURIResult(res, downloadresultcode::CANNOT_RESUME); _fileEntry->extractURIResult(res, downloadresultcode::CANNOT_RESUME);
if(!res.empty()) { if(!res.empty()) {
segmentMan->cancelAllSegments(); getSegmentMan()->cancelAllSegments();
segmentMan->eraseSegmentWrittenLengthMemo(); getSegmentMan()->eraseSegmentWrittenLengthMemo();
_requestGroup->getPieceStorage()->markPiecesDone(0); getPieceStorage()->markPiecesDone(0);
std::vector<std::string> uris; std::vector<std::string> uris;
uris.reserve(res.size()); uris.reserve(res.size());
std::transform(res.begin(), res.end(), std::back_inserter(uris), std::transform(res.begin(), res.end(), std::back_inserter(uris),
@ -396,7 +395,7 @@ void AbstractCommand::onAbort() {
static_cast<unsigned long int>(uris.size())); static_cast<unsigned long int>(uris.size()));
} }
_fileEntry->addUris(uris.begin(), uris.end()); _fileEntry->addUris(uris.begin(), uris.end());
segmentMan->recognizeSegmentFor(_fileEntry); getSegmentMan()->recognizeSegmentFor(_fileEntry);
} }
} }
} }
@ -404,10 +403,10 @@ void AbstractCommand::onAbort() {
} }
void AbstractCommand::disableReadCheckSocket() { void AbstractCommand::disableReadCheckSocket() {
if(checkSocketIsReadable) { if(_checkSocketIsReadable) {
e->deleteSocketForReadCheck(readCheckTarget, this); _e->deleteSocketForReadCheck(_readCheckTarget, this);
checkSocketIsReadable = false; _checkSocketIsReadable = false;
readCheckTarget = SocketHandle(); _readCheckTarget.reset();
} }
} }
@ -415,16 +414,16 @@ void AbstractCommand::setReadCheckSocket(const SocketHandle& socket) {
if(!socket->isOpen()) { if(!socket->isOpen()) {
disableReadCheckSocket(); disableReadCheckSocket();
} else { } else {
if(checkSocketIsReadable) { if(_checkSocketIsReadable) {
if(readCheckTarget != socket) { if(_readCheckTarget != socket) {
e->deleteSocketForReadCheck(readCheckTarget, this); _e->deleteSocketForReadCheck(_readCheckTarget, this);
e->addSocketForReadCheck(socket, this); _e->addSocketForReadCheck(socket, this);
readCheckTarget = socket; _readCheckTarget = socket;
} }
} else { } else {
e->addSocketForReadCheck(socket, this); _e->addSocketForReadCheck(socket, this);
checkSocketIsReadable = true; _checkSocketIsReadable = true;
readCheckTarget = socket; _readCheckTarget = socket;
} }
} }
} }
@ -440,10 +439,10 @@ void AbstractCommand::setReadCheckSocketIf
} }
void AbstractCommand::disableWriteCheckSocket() { void AbstractCommand::disableWriteCheckSocket() {
if(checkSocketIsWritable) { if(_checkSocketIsWritable) {
e->deleteSocketForWriteCheck(writeCheckTarget, this); _e->deleteSocketForWriteCheck(_writeCheckTarget, this);
checkSocketIsWritable = false; _checkSocketIsWritable = false;
writeCheckTarget = SocketHandle(); _writeCheckTarget.reset();
} }
} }
@ -451,16 +450,16 @@ void AbstractCommand::setWriteCheckSocket(const SocketHandle& socket) {
if(!socket->isOpen()) { if(!socket->isOpen()) {
disableWriteCheckSocket(); disableWriteCheckSocket();
} else { } else {
if(checkSocketIsWritable) { if(_checkSocketIsWritable) {
if(writeCheckTarget != socket) { if(_writeCheckTarget != socket) {
e->deleteSocketForWriteCheck(writeCheckTarget, this); _e->deleteSocketForWriteCheck(_writeCheckTarget, this);
e->addSocketForWriteCheck(socket, this); _e->addSocketForWriteCheck(socket, this);
writeCheckTarget = socket; _writeCheckTarget = socket;
} }
} else { } else {
e->addSocketForWriteCheck(socket, this); _e->addSocketForWriteCheck(socket, this);
checkSocketIsWritable = true; _checkSocketIsWritable = true;
writeCheckTarget = socket; _writeCheckTarget = socket;
} }
} }
} }
@ -570,17 +569,17 @@ static bool inNoProxy(const SharedHandle<Request>& req,
bool AbstractCommand::isProxyDefined() const bool AbstractCommand::isProxyDefined() const
{ {
return isProxyRequest(req->getProtocol(), getOption()) && return isProxyRequest(_req->getProtocol(), getOption()) &&
!inNoProxy(req, getOption()->get(PREF_NO_PROXY)); !inNoProxy(_req, getOption()->get(PREF_NO_PROXY));
} }
SharedHandle<Request> AbstractCommand::createProxyRequest() const SharedHandle<Request> AbstractCommand::createProxyRequest() const
{ {
SharedHandle<Request> proxyRequest; SharedHandle<Request> proxyRequest;
if(inNoProxy(req, getOption()->get(PREF_NO_PROXY))) { if(inNoProxy(_req, getOption()->get(PREF_NO_PROXY))) {
return proxyRequest; return proxyRequest;
} }
std::string proxy = getProxyUri(req->getProtocol(), getOption()); std::string proxy = getProxyUri(_req->getProtocol(), getOption());
if(!proxy.empty()) { if(!proxy.empty()) {
proxyRequest.reset(new Request()); proxyRequest.reset(new Request());
if(proxyRequest->setUri(proxy)) { if(proxyRequest->setUri(proxy)) {
@ -625,9 +624,9 @@ bool AbstractCommand::asyncResolveHostname()
return true; return true;
case AsyncNameResolver::STATUS_ERROR: case AsyncNameResolver::STATUS_ERROR:
disableNameResolverCheck(_asyncNameResolver); disableNameResolverCheck(_asyncNameResolver);
if(!isProxyRequest(req->getProtocol(), getOption())) { if(!isProxyRequest(_req->getProtocol(), getOption())) {
e->getRequestGroupMan()->getOrCreateServerStat _e->getRequestGroupMan()->getOrCreateServerStat
(req->getHost(), req->getProtocol())->setError(); (_req->getHost(), _req->getProtocol())->setError();
} }
throw DL_ABORT_EX throw DL_ABORT_EX
(StringFormat(MSG_NAME_RESOLUTION_FAILED, (StringFormat(MSG_NAME_RESOLUTION_FAILED,
@ -647,16 +646,16 @@ const std::vector<std::string>& AbstractCommand::getResolvedAddresses()
void AbstractCommand::setNameResolverCheck void AbstractCommand::setNameResolverCheck
(const SharedHandle<AsyncNameResolver>& resolver) { (const SharedHandle<AsyncNameResolver>& resolver) {
if(!resolver.isNull()) { if(!resolver.isNull()) {
nameResolverCheck = true; _nameResolverCheck = true;
e->addNameResolverCheck(resolver, this); _e->addNameResolverCheck(resolver, this);
} }
} }
void AbstractCommand::disableNameResolverCheck void AbstractCommand::disableNameResolverCheck
(const SharedHandle<AsyncNameResolver>& resolver) { (const SharedHandle<AsyncNameResolver>& resolver) {
if(!resolver.isNull()) { if(!resolver.isNull()) {
nameResolverCheck = false; _nameResolverCheck = false;
e->deleteNameResolverCheck(resolver, this); _e->deleteNameResolverCheck(resolver, this);
} }
} }
@ -670,7 +669,7 @@ bool AbstractCommand::nameResolveFinished() const {
std::string AbstractCommand::resolveHostname std::string AbstractCommand::resolveHostname
(std::vector<std::string>& addrs, const std::string& hostname, uint16_t port) (std::vector<std::string>& addrs, const std::string& hostname, uint16_t port)
{ {
e->findAllCachedIPAddresses(std::back_inserter(addrs), hostname, port); _e->findAllCachedIPAddresses(std::back_inserter(addrs), hostname, port);
std::string ipaddr; std::string ipaddr;
if(addrs.empty()) { if(addrs.empty()) {
#ifdef ENABLE_ASYNC_DNS #ifdef ENABLE_ASYNC_DNS
@ -688,7 +687,7 @@ std::string AbstractCommand::resolveHostname
{ {
NameResolver res; NameResolver res;
res.setSocktype(SOCK_STREAM); res.setSocktype(SOCK_STREAM);
if(e->getOption()->getAsBool(PREF_DISABLE_IPV6)) { if(_e->getOption()->getAsBool(PREF_DISABLE_IPV6)) {
res.setFamily(AF_INET); res.setFamily(AF_INET);
} }
res.resolve(addrs, hostname); res.resolve(addrs, hostname);
@ -701,9 +700,9 @@ std::string AbstractCommand::resolveHostname
} }
for(std::vector<std::string>::const_iterator i = addrs.begin(), for(std::vector<std::string>::const_iterator i = addrs.begin(),
eoi = addrs.end(); i != eoi; ++i) { eoi = addrs.end(); i != eoi; ++i) {
e->cacheIPAddress(hostname, *i, port); _e->cacheIPAddress(hostname, *i, port);
} }
ipaddr = e->findCachedIPAddress(hostname, port); ipaddr = _e->findCachedIPAddress(hostname, port);
} else { } else {
ipaddr = addrs.front(); ipaddr = addrs.front();
if(getLogger()->info()) { if(getLogger()->info()) {
@ -725,13 +724,13 @@ void AbstractCommand::prepareForNextAction(Command* nextCommand)
std::vector<Command*> commands; std::vector<Command*> commands;
try { try {
_requestGroup->processCheckIntegrityEntry(commands, entry, e); _requestGroup->processCheckIntegrityEntry(commands, entry, _e);
} catch(RecoverableException& e) { } catch(RecoverableException& e) {
std::for_each(commands.begin(), commands.end(), Deleter()); std::for_each(commands.begin(), commands.end(), Deleter());
throw; throw;
} }
e->addCommand(commands); _e->addCommand(commands);
e->setNoWait(true); _e->setNoWait(true);
} }
bool AbstractCommand::checkIfConnectionEstablished bool AbstractCommand::checkIfConnectionEstablished
@ -744,8 +743,8 @@ bool AbstractCommand::checkIfConnectionEstablished
std::string error = socket->getSocketError(); std::string error = socket->getSocketError();
if(!error.empty()) { if(!error.empty()) {
// See also InitiateConnectionCommand::executeInternal() // See also InitiateConnectionCommand::executeInternal()
e->markBadIPAddress(connectedHostname, connectedAddr, connectedPort); _e->markBadIPAddress(connectedHostname, connectedAddr, connectedPort);
if(!e->findCachedIPAddress(connectedHostname, connectedPort).empty()) { if(!_e->findCachedIPAddress(connectedHostname, connectedPort).empty()) {
if(getLogger()->info()) { if(getLogger()->info()) {
getLogger()->info(MSG_CONNECT_FAILED_AND_RETRY, getLogger()->info(MSG_CONNECT_FAILED_AND_RETRY,
util::itos(getCuid()).c_str(), util::itos(getCuid()).c_str(),
@ -753,17 +752,17 @@ bool AbstractCommand::checkIfConnectionEstablished
} }
Command* command = Command* command =
InitiateConnectionCommandFactory::createInitiateConnectionCommand InitiateConnectionCommandFactory::createInitiateConnectionCommand
(getCuid(), req, _fileEntry, _requestGroup, e); (getCuid(), _req, _fileEntry, _requestGroup, _e);
e->setNoWait(true); _e->setNoWait(true);
e->addCommand(command); _e->addCommand(command);
return false; return false;
} }
e->removeCachedIPAddress(connectedHostname, connectedPort); _e->removeCachedIPAddress(connectedHostname, connectedPort);
// Don't set error if proxy server is used and its method is GET. // Don't set error if proxy server is used and its method is GET.
if(resolveProxyMethod(req->getProtocol()) != V_GET || if(resolveProxyMethod(_req->getProtocol()) != V_GET ||
!isProxyRequest(req->getProtocol(), getOption())) { !isProxyRequest(_req->getProtocol(), getOption())) {
e->getRequestGroupMan()->getOrCreateServerStat _e->getRequestGroupMan()->getOrCreateServerStat
(req->getHost(), req->getProtocol())->setError(); (_req->getHost(), _req->getProtocol())->setError();
} }
throw DL_RETRY_EX throw DL_RETRY_EX
(StringFormat(MSG_ESTABLISHING_CONNECTION_FAILED, error.c_str()).str()); (StringFormat(MSG_ESTABLISHING_CONNECTION_FAILED, error.c_str()).str());
@ -788,4 +787,9 @@ const SharedHandle<Option>& AbstractCommand::getOption() const
return _requestGroup->getOption(); return _requestGroup->getOption();
} }
void AbstractCommand::createSocket()
{
_socket.reset(new SocketCore());
}
} // namespace aria2 } // namespace aria2

View File

@ -55,19 +55,83 @@ class AsyncNameResolver;
class AbstractCommand : public Command { class AbstractCommand : public Command {
private: private:
Timer checkPoint; Timer _checkPoint;
time_t timeout; time_t _timeout;
protected:
RequestGroup* _requestGroup; RequestGroup* _requestGroup;
SharedHandle<Request> req; SharedHandle<Request> _req;
SharedHandle<FileEntry> _fileEntry; SharedHandle<FileEntry> _fileEntry;
DownloadEngine* e; DownloadEngine* _e;
SharedHandle<SocketCore> socket; SharedHandle<SocketCore> _socket;
std::vector<SharedHandle<Segment> > _segments; std::vector<SharedHandle<Segment> > _segments;
#ifdef ENABLE_ASYNC_DNS #ifdef ENABLE_ASYNC_DNS
SharedHandle<AsyncNameResolver> _asyncNameResolver; SharedHandle<AsyncNameResolver> _asyncNameResolver;
#endif // ENABLE_ASYNC_DNS
bool _checkSocketIsReadable;
bool _checkSocketIsWritable;
SharedHandle<SocketCore> _readCheckTarget;
SharedHandle<SocketCore> _writeCheckTarget;
bool _nameResolverCheck;
#ifdef ENABLE_ASYNC_DNS
void setNameResolverCheck(const SharedHandle<AsyncNameResolver>& resolver);
void disableNameResolverCheck
(const SharedHandle<AsyncNameResolver>& resolver);
bool nameResolveFinished() const;
#endif // ENABLE_ASYNC_DNS
protected:
RequestGroup* getRequestGroup() const
{
return _requestGroup;
}
const SharedHandle<Request>& getRequest() const
{
return _req;
}
void setRequest(const SharedHandle<Request>& request)
{
_req = request;
}
const SharedHandle<FileEntry>& getFileEntry() const
{
return _fileEntry;
}
void setFileEntry(const SharedHandle<FileEntry>& fileEntry)
{
_fileEntry = fileEntry;
}
DownloadEngine* getDownloadEngine() const
{
return _e;
}
const SharedHandle<SocketCore>& getSocket() const
{
return _socket;
}
void setSocket(const SharedHandle<SocketCore>& s)
{
_socket = s;
}
void createSocket();
const std::vector<SharedHandle<Segment> >& getSegments() const
{
return _segments;
}
#ifdef ENABLE_ASYNC_DNS
bool isAsyncNameResolverInitialized() const; bool isAsyncNameResolverInitialized() const;
void initAsyncNameResolver(const std::string& hostname); void initAsyncNameResolver(const std::string& hostname);
@ -106,7 +170,7 @@ protected:
*/ */
void setWriteCheckSocketIf(const SharedHandle<SocketCore>& socket, bool pred); void setWriteCheckSocketIf(const SharedHandle<SocketCore>& socket, bool pred);
void setTimeout(time_t timeout) { this->timeout = timeout; } void setTimeout(time_t timeout) { _timeout = timeout; }
void prepareForNextAction(Command* nextCommand = 0); void prepareForNextAction(Command* nextCommand = 0);
@ -143,20 +207,16 @@ protected:
{ {
return _requestGroup->getDownloadContext(); return _requestGroup->getDownloadContext();
} }
private:
bool checkSocketIsReadable;
bool checkSocketIsWritable;
SharedHandle<SocketCore> readCheckTarget;
SharedHandle<SocketCore> writeCheckTarget;
bool nameResolverCheck;
#ifdef ENABLE_ASYNC_DNS const SharedHandle<SegmentMan>& getSegmentMan() const
{
return _requestGroup->getSegmentMan();
}
void setNameResolverCheck(const SharedHandle<AsyncNameResolver>& resolver); const SharedHandle<PieceStorage>& getPieceStorage() const
{
void disableNameResolverCheck(const SharedHandle<AsyncNameResolver>& resolver); return _requestGroup->getPieceStorage();
bool nameResolveFinished() const; }
#endif // ENABLE_ASYNC_DNS
public: public:
AbstractCommand(cuid_t cuid, const SharedHandle<Request>& req, AbstractCommand(cuid_t cuid, const SharedHandle<Request>& req,
const SharedHandle<FileEntry>& fileEntry, const SharedHandle<FileEntry>& fileEntry,

View File

@ -64,37 +64,37 @@ AbstractProxyRequestCommand::AbstractProxyRequestCommand
: :
AbstractCommand(cuid, req, fileEntry, requestGroup, e, s), AbstractCommand(cuid, req, fileEntry, requestGroup, e, s),
_proxyRequest(proxyRequest), _proxyRequest(proxyRequest),
httpConnection(new HttpConnection(cuid, s, getOption().get())) _httpConnection(new HttpConnection(cuid, s, getOption().get()))
{ {
setTimeout(getOption()->getAsInt(PREF_CONNECT_TIMEOUT)); setTimeout(getOption()->getAsInt(PREF_CONNECT_TIMEOUT));
disableReadCheckSocket(); disableReadCheckSocket();
setWriteCheckSocket(socket); setWriteCheckSocket(getSocket());
} }
AbstractProxyRequestCommand::~AbstractProxyRequestCommand() {} AbstractProxyRequestCommand::~AbstractProxyRequestCommand() {}
bool AbstractProxyRequestCommand::executeInternal() { bool AbstractProxyRequestCommand::executeInternal() {
//socket->setBlockingMode(); //socket->setBlockingMode();
if(httpConnection->sendBufferIsEmpty()) { if(_httpConnection->sendBufferIsEmpty()) {
if(!checkIfConnectionEstablished if(!checkIfConnectionEstablished
(socket, _connectedHostname, _connectedAddr, _connectedPort)) { (getSocket(), _connectedHostname, _connectedAddr, _connectedPort)) {
return true; return true;
} }
SharedHandle<HttpRequest> httpRequest(new HttpRequest()); SharedHandle<HttpRequest> httpRequest(new HttpRequest());
httpRequest->setUserAgent(getOption()->get(PREF_USER_AGENT)); httpRequest->setUserAgent(getOption()->get(PREF_USER_AGENT));
httpRequest->setRequest(req); httpRequest->setRequest(getRequest());
httpRequest->setProxyRequest(_proxyRequest); httpRequest->setProxyRequest(_proxyRequest);
httpConnection->sendProxyRequest(httpRequest); _httpConnection->sendProxyRequest(httpRequest);
} else { } else {
httpConnection->sendPendingData(); _httpConnection->sendPendingData();
} }
if(httpConnection->sendBufferIsEmpty()) { if(_httpConnection->sendBufferIsEmpty()) {
e->addCommand(getNextCommand()); getDownloadEngine()->addCommand(getNextCommand());
return true; return true;
} else { } else {
setWriteCheckSocket(socket); setWriteCheckSocket(getSocket());
e->addCommand(this); getDownloadEngine()->addCommand(this);
return false; return false;
} }
} }

View File

@ -43,16 +43,21 @@ class HttpConnection;
class SocketCore; class SocketCore;
class AbstractProxyRequestCommand : public AbstractCommand { class AbstractProxyRequestCommand : public AbstractCommand {
protected: private:
SharedHandle<Request> _proxyRequest; SharedHandle<Request> _proxyRequest;
SharedHandle<HttpConnection> httpConnection; SharedHandle<HttpConnection> _httpConnection;
std::string _connectedHostname; std::string _connectedHostname;
std::string _connectedAddr; std::string _connectedAddr;
uint16_t _connectedPort; uint16_t _connectedPort;
protected:
virtual bool executeInternal(); virtual bool executeInternal();
const SharedHandle<HttpConnection>& getHttpConnection() const
{
return _httpConnection;
}
public: public:
AbstractProxyRequestCommand(cuid_t cuid, AbstractProxyRequestCommand(cuid_t cuid,
const SharedHandle<Request>& req, const SharedHandle<Request>& req,

View File

@ -62,21 +62,21 @@ AbstractProxyResponseCommand::AbstractProxyResponseCommand
DownloadEngine* e, DownloadEngine* e,
const SocketHandle& s) const SocketHandle& s)
:AbstractCommand(cuid, req, fileEntry, requestGroup, e, s), :AbstractCommand(cuid, req, fileEntry, requestGroup, e, s),
httpConnection(httpConnection) {} _httpConnection(httpConnection) {}
AbstractProxyResponseCommand::~AbstractProxyResponseCommand() {} AbstractProxyResponseCommand::~AbstractProxyResponseCommand() {}
bool AbstractProxyResponseCommand::executeInternal() { bool AbstractProxyResponseCommand::executeInternal() {
SharedHandle<HttpResponse> httpResponse = httpConnection->receiveResponse(); SharedHandle<HttpResponse> httpResponse = _httpConnection->receiveResponse();
if(httpResponse.isNull()) { if(httpResponse.isNull()) {
// the server has not responded our request yet. // the server has not responded our request yet.
e->addCommand(this); getDownloadEngine()->addCommand(this);
return false; return false;
} }
if(httpResponse->getResponseStatus() != HttpHeader::S200) { if(httpResponse->getResponseStatus() != HttpHeader::S200) {
throw DL_RETRY_EX(EX_PROXY_CONNECTION_FAILED); throw DL_RETRY_EX(EX_PROXY_CONNECTION_FAILED);
} }
e->addCommand(getNextCommand()); getDownloadEngine()->addCommand(getNextCommand());
return true; return true;
} }

View File

@ -43,10 +43,15 @@ class HttpConnection;
class SocketCore; class SocketCore;
class AbstractProxyResponseCommand : public AbstractCommand { class AbstractProxyResponseCommand : public AbstractCommand {
private:
SharedHandle<HttpConnection> _httpConnection;
protected: protected:
SharedHandle<HttpConnection> httpConnection;
virtual bool executeInternal(); virtual bool executeInternal();
const SharedHandle<HttpConnection>& getHttpConnection() const
{
return _httpConnection;
}
public: public:
AbstractProxyResponseCommand AbstractProxyResponseCommand
(cuid_t cuid, (cuid_t cuid,

View File

@ -67,39 +67,41 @@ CreateRequestCommand::CreateRequestCommand(cuid_t cuid,
bool CreateRequestCommand::executeInternal() bool CreateRequestCommand::executeInternal()
{ {
if(_segments.empty()) { if(getSegments().empty()) {
_fileEntry = _requestGroup->getDownloadContext()->findFileEntryByOffset(0); setFileEntry(getDownloadContext()->findFileEntryByOffset(0));
} else { } else {
// We assume all segments belongs to same file. // We assume all segments belongs to same file.
_fileEntry = _requestGroup->getDownloadContext()->findFileEntryByOffset setFileEntry(getDownloadContext()->findFileEntryByOffset
(_segments.front()->getPositionToWrite()); (getSegments().front()->getPositionToWrite()));
} }
if(_fileEntry->getRemainingUris().empty() && if(getFileEntry()->getRemainingUris().empty() &&
getOption()->getAsBool(PREF_REUSE_URI) && getOption()->getAsBool(PREF_REUSE_URI) &&
_fileEntry->countPooledRequest() == 0) { getFileEntry()->countPooledRequest() == 0) {
_fileEntry->reuseUri(_requestGroup->getNumConcurrentCommand()); getFileEntry()->reuseUri(getRequestGroup()->getNumConcurrentCommand());
} }
req = _fileEntry->getRequest(_requestGroup->getURISelector(), setRequest
getOption()->get(PREF_REFERER), (getFileEntry()->getRequest(getRequestGroup()->getURISelector(),
// Don't use HEAD request when file getOption()->get(PREF_REFERER),
// size is known. // Don't use HEAD request when file
// Use HEAD for dry-run mode. // size is known.
(_fileEntry->getLength() == 0 && // Use HEAD for dry-run mode.
getOption()->getAsBool(PREF_USE_HEAD)) || (getFileEntry()->getLength() == 0 &&
getOption()->getAsBool(PREF_DRY_RUN)? getOption()->getAsBool(PREF_USE_HEAD)) ||
Request::METHOD_HEAD:Request::METHOD_GET); getOption()->getAsBool(PREF_DRY_RUN)?
if(req.isNull()) { Request::METHOD_HEAD:Request::METHOD_GET));
if(!_requestGroup->getSegmentMan().isNull()) { if(getRequest().isNull()) {
_requestGroup->getSegmentMan()->ignoreSegmentFor(_fileEntry); if(!getSegmentMan().isNull()) {
getSegmentMan()->ignoreSegmentFor(getFileEntry());
} }
throw DL_ABORT_EX("No URI available."); throw DL_ABORT_EX("No URI available.");
} }
Command* command = Command* command =
InitiateConnectionCommandFactory::createInitiateConnectionCommand InitiateConnectionCommandFactory::createInitiateConnectionCommand
(getCuid(), req, _fileEntry, _requestGroup, e); (getCuid(), getRequest(), getFileEntry(), getRequestGroup(),
e->setNoWait(true); getDownloadEngine());
e->addCommand(command); getDownloadEngine()->setNoWait(true);
getDownloadEngine()->addCommand(command);
return true; return true;
} }
@ -113,16 +115,16 @@ bool CreateRequestCommand::prepareForRetry(time_t wait)
// called repeatedly. This means that newly created // called repeatedly. This means that newly created
// CreateRequestCommand is deleted one second later: This is not // CreateRequestCommand is deleted one second later: This is not
// efficient. For this reason, reuse current CreateRequestCommand. // efficient. For this reason, reuse current CreateRequestCommand.
if(!_requestGroup->getPieceStorage().isNull()) { if(!getPieceStorage().isNull()) {
_requestGroup->getSegmentMan()->cancelSegment(getCuid()); getSegmentMan()->cancelSegment(getCuid());
} }
if(getLogger()->debug()) { if(getLogger()->debug()) {
getLogger()->debug("CUID#%s - Reusing CreateRequestCommand", getLogger()->debug("CUID#%s - Reusing CreateRequestCommand",
util::itos(getCuid()).c_str()); util::itos(getCuid()).c_str());
} }
SleepCommand* scom = new SleepCommand SleepCommand* scom = new SleepCommand
(getCuid(), e, _requestGroup, this, wait); (getCuid(), getDownloadEngine(), getRequestGroup(), this, wait);
e->addCommand(scom); getDownloadEngine()->addCommand(scom);
return false; return false;
} }

View File

@ -76,7 +76,9 @@ DownloadCommand::DownloadCommand(cuid_t cuid,
DownloadEngine* e, DownloadEngine* e,
const SocketHandle& s): const SocketHandle& s):
AbstractCommand(cuid, req, fileEntry, requestGroup, e, s), AbstractCommand(cuid, req, fileEntry, requestGroup, e, s),
_buf(new unsigned char[BUFSIZE]) _buf(new unsigned char[BUFSIZE]),
_startupIdleTime(10),
_lowestDownloadSpeedLimit(0)
#ifdef ENABLE_MESSAGE_DIGEST #ifdef ENABLE_MESSAGE_DIGEST
, _pieceHashValidationEnabled(false) , _pieceHashValidationEnabled(false)
#endif // ENABLE_MESSAGE_DIGEST #endif // ENABLE_MESSAGE_DIGEST
@ -84,8 +86,7 @@ DownloadCommand::DownloadCommand(cuid_t cuid,
#ifdef ENABLE_MESSAGE_DIGEST #ifdef ENABLE_MESSAGE_DIGEST
{ {
if(getOption()->getAsBool(PREF_REALTIME_CHUNK_CHECKSUM)) { if(getOption()->getAsBool(PREF_REALTIME_CHUNK_CHECKSUM)) {
std::string algo = const std::string& algo = getDownloadContext()->getPieceHashAlgo();
_requestGroup->getDownloadContext()->getPieceHashAlgo();
if(MessageDigestContext::supports(algo)) { if(MessageDigestContext::supports(algo)) {
_messageDigestContext.reset(new MessageDigestContext()); _messageDigestContext.reset(new MessageDigestContext());
_messageDigestContext->trySetAlgo(algo); _messageDigestContext->trySetAlgo(algo);
@ -97,46 +98,47 @@ DownloadCommand::DownloadCommand(cuid_t cuid,
} }
#endif // ENABLE_MESSAGE_DIGEST #endif // ENABLE_MESSAGE_DIGEST
peerStat = req->initPeerStat(); _peerStat = req->initPeerStat();
peerStat->downloadStart(); _peerStat->downloadStart();
_requestGroup->getSegmentMan()->registerPeerStat(peerStat); getSegmentMan()->registerPeerStat(_peerStat);
} }
DownloadCommand::~DownloadCommand() { DownloadCommand::~DownloadCommand() {
peerStat->downloadStop(); _peerStat->downloadStop();
_requestGroup->getSegmentMan()->updateFastestPeerStat(peerStat); getSegmentMan()->updateFastestPeerStat(_peerStat);
delete [] _buf; delete [] _buf;
} }
bool DownloadCommand::executeInternal() { bool DownloadCommand::executeInternal() {
if(e->getRequestGroupMan()->doesOverallDownloadSpeedExceed() || if(getDownloadEngine()->getRequestGroupMan()->doesOverallDownloadSpeedExceed()
_requestGroup->doesDownloadSpeedExceed()) { || getRequestGroup()->doesDownloadSpeedExceed()) {
e->addCommand(this); getDownloadEngine()->addCommand(this);
disableReadCheckSocket(); disableReadCheckSocket();
return false; return false;
} }
setReadCheckSocket(socket); setReadCheckSocket(getSocket());
SharedHandle<Segment> segment = _segments.front(); SharedHandle<Segment> segment = getSegments().front();
size_t bufSize; size_t bufSize;
if(segment->getLength() > 0) { if(segment->getLength() > 0) {
if(static_cast<uint64_t>(segment->getPosition()+segment->getLength()) <= if(static_cast<uint64_t>(segment->getPosition()+segment->getLength()) <=
static_cast<uint64_t>(_fileEntry->getLastOffset())) { static_cast<uint64_t>(getFileEntry()->getLastOffset())) {
bufSize = std::min(segment->getLength()-segment->getWrittenLength(), bufSize = std::min(segment->getLength()-segment->getWrittenLength(),
BUFSIZE); BUFSIZE);
} else { } else {
bufSize = bufSize =
std::min(static_cast<size_t> std::min
(_fileEntry->getLastOffset()-segment->getPositionToWrite()), (static_cast<size_t>
BUFSIZE); (getFileEntry()->getLastOffset()-segment->getPositionToWrite()),
BUFSIZE);
} }
} else { } else {
bufSize = BUFSIZE; bufSize = BUFSIZE;
} }
socket->readData(_buf, bufSize); getSocket()->readData(_buf, bufSize);
const SharedHandle<DiskAdaptor>& diskAdaptor = const SharedHandle<DiskAdaptor>& diskAdaptor =
_requestGroup->getPieceStorage()->getDiskAdaptor(); getPieceStorage()->getDiskAdaptor();
const unsigned char* bufFinal; const unsigned char* bufFinal;
size_t bufSizeFinal; size_t bufSizeFinal;
@ -173,24 +175,21 @@ bool DownloadCommand::executeInternal() {
if(bufSizeFinal > 0) { if(bufSizeFinal > 0) {
segment->updateWrittenLength(bufSizeFinal); segment->updateWrittenLength(bufSizeFinal);
} }
_peerStat->updateDownloadLength(bufSize);
peerStat->updateDownloadLength(bufSize); getSegmentMan()->updateDownloadSpeedFor(_peerStat);
_requestGroup->getSegmentMan()->updateDownloadSpeedFor(peerStat);
bool segmentPartComplete = false; bool segmentPartComplete = false;
// Note that GrowSegment::complete() always returns false. // Note that GrowSegment::complete() always returns false.
if(_transferEncodingDecoder.isNull() && _contentEncodingDecoder.isNull()) { if(_transferEncodingDecoder.isNull() && _contentEncodingDecoder.isNull()) {
if(segment->complete() || if(segment->complete() ||
segment->getPositionToWrite() == _fileEntry->getLastOffset()) { segment->getPositionToWrite() == getFileEntry()->getLastOffset()) {
segmentPartComplete = true; segmentPartComplete = true;
} else if(segment->getLength() == 0 && bufSize == 0 && } else if(segment->getLength() == 0 && bufSize == 0 &&
!socket->wantRead() && !socket->wantWrite()) { !getSocket()->wantRead() && !getSocket()->wantWrite()) {
segmentPartComplete = true; segmentPartComplete = true;
} }
} else if(!_transferEncodingDecoder.isNull() && } else if(!_transferEncodingDecoder.isNull() &&
(segment->complete() || (segment->complete() ||
segment->getPositionToWrite() == _fileEntry->getLastOffset())) { segment->getPositionToWrite() == getFileEntry()->getLastOffset())){
// In this case, transferEncodingDecoder is used and // In this case, transferEncodingDecoder is used and
// Content-Length is known. // Content-Length is known.
segmentPartComplete = true; segmentPartComplete = true;
@ -202,7 +201,7 @@ bool DownloadCommand::executeInternal() {
} }
if(!segmentPartComplete && bufSize == 0 && if(!segmentPartComplete && bufSize == 0 &&
!socket->wantRead() && !socket->wantWrite()) { !getSocket()->wantRead() && !getSocket()->wantWrite()) {
throw DL_RETRY_EX(EX_GOT_EOF); throw DL_RETRY_EX(EX_GOT_EOF);
} }
@ -219,8 +218,7 @@ bool DownloadCommand::executeInternal() {
{ {
const std::string& expectedPieceHash = const std::string& expectedPieceHash =
_requestGroup->getDownloadContext()->getPieceHash getDownloadContext()->getPieceHash(segment->getIndex());
(segment->getIndex());
if(_pieceHashValidationEnabled && !expectedPieceHash.empty()) { if(_pieceHashValidationEnabled && !expectedPieceHash.empty()) {
if(segment->isHashCalculated()) { if(segment->isHashCalculated()) {
if(getLogger()->debug()) { if(getLogger()->debug()) {
@ -236,31 +234,31 @@ bool DownloadCommand::executeInternal() {
(segment, expectedPieceHash, (segment, expectedPieceHash,
MessageDigestHelper::digest MessageDigestHelper::digest
(_messageDigestContext.get(), (_messageDigestContext.get(),
_requestGroup->getPieceStorage()->getDiskAdaptor(), getPieceStorage()->getDiskAdaptor(),
segment->getPosition(), segment->getPosition(),
segment->getLength())); segment->getLength()));
} }
} else { } else {
_requestGroup->getSegmentMan()->completeSegment(getCuid(), segment); getSegmentMan()->completeSegment(getCuid(), segment);
} }
} }
#else // !ENABLE_MESSAGE_DIGEST #else // !ENABLE_MESSAGE_DIGEST
_requestGroup->getSegmentMan()->completeSegment(getCuid(), segment); getSegmentMan()->completeSegment(getCuid(), segment);
#endif // !ENABLE_MESSAGE_DIGEST #endif // !ENABLE_MESSAGE_DIGEST
} else { } else {
// If segment is not canceled here, in the next pipelining // If segment is not canceled here, in the next pipelining
// request, aria2 requests bad range // request, aria2 requests bad range
// [FileEntry->getLastOffset(), FileEntry->getLastOffset()) // [FileEntry->getLastOffset(), FileEntry->getLastOffset())
_requestGroup->getSegmentMan()->cancelSegment(getCuid(), segment); getSegmentMan()->cancelSegment(getCuid(), segment);
} }
checkLowestDownloadSpeed(); checkLowestDownloadSpeed();
// this unit is going to download another segment. // this unit is going to download another segment.
return prepareForNextSegment(); return prepareForNextSegment();
} else { } else {
checkLowestDownloadSpeed(); checkLowestDownloadSpeed();
setWriteCheckSocketIf(socket, socket->wantWrite()); setWriteCheckSocketIf(getSocket(), getSocket()->wantWrite());
e->addCommand(this); getDownloadEngine()->addCommand(this);
return false; return false;
} }
} }
@ -268,67 +266,62 @@ bool DownloadCommand::executeInternal() {
void DownloadCommand::checkLowestDownloadSpeed() const void DownloadCommand::checkLowestDownloadSpeed() const
{ {
// calculate downloading speed // calculate downloading speed
if(peerStat->getDownloadStartTime().difference(global::wallclock) >= if(_peerStat->getDownloadStartTime().difference(global::wallclock) >=
startupIdleTime) { _startupIdleTime) {
unsigned int nowSpeed = peerStat->calculateDownloadSpeed(); unsigned int nowSpeed = _peerStat->calculateDownloadSpeed();
if(lowestDownloadSpeedLimit > 0 && nowSpeed <= lowestDownloadSpeedLimit) { if(_lowestDownloadSpeedLimit > 0 && nowSpeed <= _lowestDownloadSpeedLimit) {
throw DL_ABORT_EX2(StringFormat(EX_TOO_SLOW_DOWNLOAD_SPEED, throw DL_ABORT_EX2(StringFormat(EX_TOO_SLOW_DOWNLOAD_SPEED,
nowSpeed, nowSpeed,
lowestDownloadSpeedLimit, _lowestDownloadSpeedLimit,
req->getHost().c_str()).str(), getRequest()->getHost().c_str()).str(),
downloadresultcode::TOO_SLOW_DOWNLOAD_SPEED); downloadresultcode::TOO_SLOW_DOWNLOAD_SPEED);
} }
} }
} }
bool DownloadCommand::prepareForNextSegment() { bool DownloadCommand::prepareForNextSegment() {
if(_requestGroup->downloadFinished()) { if(getRequestGroup()->downloadFinished()) {
const SharedHandle<DownloadContext>& dctx =
_requestGroup->getDownloadContext();
// Remove in-flight request here. // Remove in-flight request here.
_fileEntry->poolRequest(req); getFileEntry()->poolRequest(getRequest());
// If this is a single file download, and file size becomes known // If this is a single file download, and file size becomes known
// just after downloading, set total length to FileEntry object // just after downloading, set total length to FileEntry object
// here. // here.
if(dctx->getFileEntries().size() == 1) { if(getDownloadContext()->getFileEntries().size() == 1) {
const SharedHandle<FileEntry>& fileEntry = dctx->getFirstFileEntry(); if(getFileEntry()->getLength() == 0) {
if(fileEntry->getLength() == 0) { getFileEntry()->setLength(getPieceStorage()->getCompletedLength());
fileEntry->setLength
(_requestGroup->getPieceStorage()->getCompletedLength());
} }
} }
#ifdef ENABLE_MESSAGE_DIGEST #ifdef ENABLE_MESSAGE_DIGEST
if(dctx->getPieceHashAlgo().empty()) { if(getDownloadContext()->getPieceHashAlgo().empty()) {
SharedHandle<CheckIntegrityEntry> entry SharedHandle<CheckIntegrityEntry> entry
(new ChecksumCheckIntegrityEntry(_requestGroup)); (new ChecksumCheckIntegrityEntry(getRequestGroup()));
if(entry->isValidationReady()) { if(entry->isValidationReady()) {
entry->initValidator(); entry->initValidator();
// TODO do we need cuttrailinggarbage here? // TODO do we need cuttrailinggarbage here?
e->getCheckIntegrityMan()->pushEntry(entry); getDownloadEngine()->getCheckIntegrityMan()->pushEntry(entry);
} }
} }
// Following 2lines are needed for DownloadEngine to detect // Following 2lines are needed for DownloadEngine to detect
// completed RequestGroups without 1sec delay. // completed RequestGroups without 1sec delay.
e->setNoWait(true); getDownloadEngine()->setNoWait(true);
e->setRefreshInterval(0); getDownloadEngine()->setRefreshInterval(0);
#endif // ENABLE_MESSAGE_DIGEST #endif // ENABLE_MESSAGE_DIGEST
return true; return true;
} else { } else {
// The number of segments should be 1 in order to pass through the next // The number of segments should be 1 in order to pass through the next
// segment. // segment.
if(_segments.size() == 1) { if(getSegments().size() == 1) {
SharedHandle<Segment> tempSegment = _segments.front(); SharedHandle<Segment> tempSegment = getSegments().front();
if(!tempSegment->complete()) { if(!tempSegment->complete()) {
return prepareForRetry(0); return prepareForRetry(0);
} }
SharedHandle<SegmentMan> segmentMan = _requestGroup->getSegmentMan();
SharedHandle<Segment> nextSegment = SharedHandle<Segment> nextSegment =
segmentMan->getCleanSegmentIfOwnerIsIdle getSegmentMan()->getCleanSegmentIfOwnerIsIdle
(getCuid(), tempSegment->getIndex()+1); (getCuid(), tempSegment->getIndex()+1);
if(nextSegment.isNull()) { if(nextSegment.isNull()) {
return prepareForRetry(0); return prepareForRetry(0);
} else { } else {
e->addCommand(this); getDownloadEngine()->addCommand(this);
return false; return false;
} }
} else { } else {
@ -345,7 +338,7 @@ void DownloadCommand::validatePieceHash(const SharedHandle<Segment>& segment,
{ {
if(actualPieceHash == expectedPieceHash) { if(actualPieceHash == expectedPieceHash) {
getLogger()->info(MSG_GOOD_CHUNK_CHECKSUM, actualPieceHash.c_str()); getLogger()->info(MSG_GOOD_CHUNK_CHECKSUM, actualPieceHash.c_str());
_requestGroup->getSegmentMan()->completeSegment(getCuid(), segment); getSegmentMan()->completeSegment(getCuid(), segment);
} else { } else {
getLogger()->info(EX_INVALID_CHUNK_CHECKSUM, getLogger()->info(EX_INVALID_CHUNK_CHECKSUM,
segment->getIndex(), segment->getIndex(),
@ -353,7 +346,7 @@ void DownloadCommand::validatePieceHash(const SharedHandle<Segment>& segment,
expectedPieceHash.c_str(), expectedPieceHash.c_str(),
actualPieceHash.c_str()); actualPieceHash.c_str());
segment->clear(); segment->clear();
_requestGroup->getSegmentMan()->cancelSegment(getCuid()); getSegmentMan()->cancelSegment(getCuid());
throw DL_RETRY_EX throw DL_RETRY_EX
(StringFormat("Invalid checksum index=%d", segment->getIndex()).str()); (StringFormat("Invalid checksum index=%d", segment->getIndex()).str());
} }

View File

@ -49,9 +49,9 @@ class DownloadCommand : public AbstractCommand {
private: private:
unsigned char* _buf; unsigned char* _buf;
time_t startupIdleTime; time_t _startupIdleTime;
unsigned int lowestDownloadSpeedLimit; unsigned int _lowestDownloadSpeedLimit;
SharedHandle<PeerStat> peerStat; SharedHandle<PeerStat> _peerStat;
#ifdef ENABLE_MESSAGE_DIGEST #ifdef ENABLE_MESSAGE_DIGEST
@ -66,15 +66,14 @@ private:
const std::string& actualPieceHash); const std::string& actualPieceHash);
void checkLowestDownloadSpeed() const; void checkLowestDownloadSpeed() const;
protected:
SharedHandle<Decoder> _transferEncodingDecoder; SharedHandle<Decoder> _transferEncodingDecoder;
SharedHandle<Decoder> _contentEncodingDecoder; SharedHandle<Decoder> _contentEncodingDecoder;
protected:
virtual bool executeInternal(); virtual bool executeInternal();
virtual bool prepareForNextSegment(); virtual bool prepareForNextSegment();
public: public:
DownloadCommand(cuid_t cuid, DownloadCommand(cuid_t cuid,
const SharedHandle<Request>& req, const SharedHandle<Request>& req,
@ -84,16 +83,28 @@ public:
const SharedHandle<SocketCore>& s); const SharedHandle<SocketCore>& s);
virtual ~DownloadCommand(); virtual ~DownloadCommand();
const SharedHandle<Decoder>& getTransferEncodingDecoder() const
{
return _transferEncodingDecoder;
}
void setTransferEncodingDecoder(const SharedHandle<Decoder>& decoder); void setTransferEncodingDecoder(const SharedHandle<Decoder>& decoder);
const SharedHandle<Decoder>& getContentEncodingDecoder() const
{
return _contentEncodingDecoder;
}
void setContentEncodingDecoder(const SharedHandle<Decoder>& decoder); void setContentEncodingDecoder(const SharedHandle<Decoder>& decoder);
void setStartupIdleTime(time_t startupIdleTime) { void setStartupIdleTime(time_t startupIdleTime)
this->startupIdleTime = startupIdleTime; {
_startupIdleTime = startupIdleTime;
} }
void setLowestDownloadSpeedLimit(unsigned int lowestDownloadSpeedLimit) { void setLowestDownloadSpeedLimit(unsigned int lowestDownloadSpeedLimit)
this->lowestDownloadSpeedLimit = lowestDownloadSpeedLimit; {
_lowestDownloadSpeedLimit = lowestDownloadSpeedLimit;
} }
}; };

View File

@ -62,7 +62,7 @@ FtpDownloadCommand::FtpDownloadCommand
const SocketHandle& ctrlSocket) const SocketHandle& ctrlSocket)
:DownloadCommand(cuid, req, fileEntry, requestGroup, e, dataSocket), :DownloadCommand(cuid, req, fileEntry, requestGroup, e, dataSocket),
_ftpConnection(ftpConnection), _ftpConnection(ftpConnection),
ctrlSocket(ctrlSocket) {} _ctrlSocket(ctrlSocket) {}
FtpDownloadCommand::~FtpDownloadCommand() {} FtpDownloadCommand::~FtpDownloadCommand() {}
@ -71,14 +71,14 @@ bool FtpDownloadCommand::prepareForNextSegment()
{ {
if(getOption()->getAsBool(PREF_FTP_REUSE_CONNECTION) && if(getOption()->getAsBool(PREF_FTP_REUSE_CONNECTION) &&
static_cast<uint64_t> static_cast<uint64_t>
(_fileEntry->gtoloff(_segments.front()->getPositionToWrite())) == (getFileEntry()->gtoloff(getSegments().front()->getPositionToWrite())) ==
_fileEntry->getLength()) { getFileEntry()->getLength()) {
Command* command = new FtpFinishDownloadCommand Command* command = new FtpFinishDownloadCommand
(getCuid(), req, _fileEntry, _requestGroup, _ftpConnection, e, (getCuid(), getRequest(), getFileEntry(), getRequestGroup(),
ctrlSocket); _ftpConnection, getDownloadEngine(), _ctrlSocket);
e->addCommand(command); getDownloadEngine()->addCommand(command);
if(_requestGroup->downloadFinished()) { if(getRequestGroup()->downloadFinished()) {
// To run checksum checking, we had to call following function here. // To run checksum checking, we had to call following function here.
DownloadCommand::prepareForNextSegment(); DownloadCommand::prepareForNextSegment();
} }

View File

@ -45,7 +45,7 @@ class FtpDownloadCommand : public DownloadCommand {
private: private:
SharedHandle<FtpConnection> _ftpConnection; SharedHandle<FtpConnection> _ftpConnection;
SharedHandle<SocketCore> ctrlSocket; SharedHandle<SocketCore> _ctrlSocket;
protected: protected:
virtual bool prepareForNextSegment(); virtual bool prepareForNextSegment();
public: public:

View File

@ -71,13 +71,13 @@ FtpFinishDownloadCommand::FtpFinishDownloadCommand
// AbstractCommand::_segments is empty. // AbstractCommand::_segments is empty.
bool FtpFinishDownloadCommand::execute() bool FtpFinishDownloadCommand::execute()
{ {
if(_requestGroup->isHaltRequested()) { if(getRequestGroup()->isHaltRequested()) {
return true; return true;
} }
try { try {
unsigned int status = _ftpConnection->receiveResponse(); unsigned int status = _ftpConnection->receiveResponse();
if(status == 0) { if(status == 0) {
e->addCommand(this); getDownloadEngine()->addCommand(this);
return false; return false;
} }
if(status != 226) { if(status != 226) {
@ -86,13 +86,14 @@ bool FtpFinishDownloadCommand::execute()
if(getOption()->getAsBool(PREF_FTP_REUSE_CONNECTION)) { if(getOption()->getAsBool(PREF_FTP_REUSE_CONNECTION)) {
std::map<std::string, std::string> options; std::map<std::string, std::string> options;
options["baseWorkingDir"] = _ftpConnection->getBaseWorkingDir(); options["baseWorkingDir"] = _ftpConnection->getBaseWorkingDir();
e->poolSocket(req, _ftpConnection->getUser(), createProxyRequest(), getDownloadEngine()->poolSocket
socket, options); (getRequest(), _ftpConnection->getUser(), createProxyRequest(),
getSocket(), options);
} }
} catch(RecoverableException& e) { } catch(RecoverableException& e) {
getLogger()->info(EX_EXCEPTION_CAUGHT, e); getLogger()->info(EX_EXCEPTION_CAUGHT, e);
} }
if(_requestGroup->downloadFinished()) { if(getRequestGroup()->downloadFinished()) {
return true; return true;
} else { } else {
return prepareForRetry(0); return prepareForRetry(0);

View File

@ -80,16 +80,16 @@ Command* FtpInitiateConnectionCommand::createNextCommand
if(!proxyRequest.isNull()) { if(!proxyRequest.isNull()) {
std::map<std::string, std::string> options; std::map<std::string, std::string> options;
SharedHandle<SocketCore> pooledSocket; SharedHandle<SocketCore> pooledSocket;
std::string proxyMethod = resolveProxyMethod(req->getProtocol()); std::string proxyMethod = resolveProxyMethod(getRequest()->getProtocol());
if(proxyMethod == V_GET) { if(proxyMethod == V_GET) {
pooledSocket = e->popPooledSocket pooledSocket = getDownloadEngine()->popPooledSocket
(req->getHost(), req->getPort(), (getRequest()->getHost(), getRequest()->getPort(),
proxyRequest->getHost(), proxyRequest->getPort()); proxyRequest->getHost(), proxyRequest->getPort());
} else { } else {
pooledSocket = e->popPooledSocket pooledSocket = getDownloadEngine()->popPooledSocket
(options, req->getHost(), req->getPort(), (options, getRequest()->getHost(), getRequest()->getPort(),
e->getAuthConfigFactory()->createAuthConfig getDownloadEngine()->getAuthConfigFactory()->createAuthConfig
(req, getOption().get())->getUser(), (getRequest(), getOption().get())->getUser(),
proxyRequest->getHost(), proxyRequest->getPort()); proxyRequest->getHost(), proxyRequest->getPort());
} }
if(pooledSocket.isNull()) { if(pooledSocket.isNull()) {
@ -97,26 +97,27 @@ Command* FtpInitiateConnectionCommand::createNextCommand
getLogger()->info(MSG_CONNECTING_TO_SERVER, getLogger()->info(MSG_CONNECTING_TO_SERVER,
util::itos(getCuid()).c_str(), addr.c_str(), port); util::itos(getCuid()).c_str(), addr.c_str(), port);
} }
socket.reset(new SocketCore()); createSocket();
socket->establishConnection(addr, port); getSocket()->establishConnection(addr, port);
if(proxyMethod == V_GET) { if(proxyMethod == V_GET) {
// Use GET for FTP via HTTP proxy. // Use GET for FTP via HTTP proxy.
req->setMethod(Request::METHOD_GET); getRequest()->setMethod(Request::METHOD_GET);
SharedHandle<HttpConnection> hc SharedHandle<HttpConnection> hc
(new HttpConnection(getCuid(), socket, getOption().get())); (new HttpConnection(getCuid(), getSocket(), getOption().get()));
HttpRequestCommand* c = HttpRequestCommand* c =
new HttpRequestCommand(getCuid(), req, _fileEntry, new HttpRequestCommand(getCuid(), getRequest(), getFileEntry(),
_requestGroup, hc, e, socket); getRequestGroup(), hc, getDownloadEngine(),
getSocket());
c->setConnectedAddr(hostname, addr, port); c->setConnectedAddr(hostname, addr, port);
c->setProxyRequest(proxyRequest); c->setProxyRequest(proxyRequest);
command = c; command = c;
} else if(proxyMethod == V_TUNNEL) { } else if(proxyMethod == V_TUNNEL) {
FtpTunnelRequestCommand* c = FtpTunnelRequestCommand* c =
new FtpTunnelRequestCommand(getCuid(), req, _fileEntry, new FtpTunnelRequestCommand(getCuid(), getRequest(), getFileEntry(),
_requestGroup, e, getRequestGroup(), getDownloadEngine(),
proxyRequest, socket); proxyRequest, getSocket());
c->setConnectedAddr(hostname, addr, port); c->setConnectedAddr(hostname, addr, port);
command = c; command = c;
} else { } else {
@ -126,19 +127,21 @@ Command* FtpInitiateConnectionCommand::createNextCommand
} else { } else {
if(proxyMethod == V_TUNNEL) { if(proxyMethod == V_TUNNEL) {
command = command =
new FtpNegotiationCommand(getCuid(), req, _fileEntry, new FtpNegotiationCommand(getCuid(), getRequest(), getFileEntry(),
_requestGroup, e, pooledSocket, getRequestGroup(), getDownloadEngine(),
pooledSocket,
FtpNegotiationCommand::SEQ_SEND_CWD, FtpNegotiationCommand::SEQ_SEND_CWD,
options["baseWorkingDir"]); options["baseWorkingDir"]);
} else if(proxyMethod == V_GET) { } else if(proxyMethod == V_GET) {
// Use GET for FTP via HTTP proxy. // Use GET for FTP via HTTP proxy.
req->setMethod(Request::METHOD_GET); getRequest()->setMethod(Request::METHOD_GET);
SharedHandle<HttpConnection> hc SharedHandle<HttpConnection> hc
(new HttpConnection(getCuid(), pooledSocket, getOption().get())); (new HttpConnection(getCuid(), pooledSocket, getOption().get()));
HttpRequestCommand* c = HttpRequestCommand* c =
new HttpRequestCommand(getCuid(), req, _fileEntry, new HttpRequestCommand(getCuid(), getRequest(), getFileEntry(),
_requestGroup, hc, e, pooledSocket); getRequestGroup(), hc, getDownloadEngine(),
pooledSocket);
c->setProxyRequest(proxyRequest); c->setProxyRequest(proxyRequest);
command = c; command = c;
} else { } else {
@ -149,25 +152,29 @@ Command* FtpInitiateConnectionCommand::createNextCommand
} else { } else {
std::map<std::string, std::string> options; std::map<std::string, std::string> options;
SharedHandle<SocketCore> pooledSocket = SharedHandle<SocketCore> pooledSocket =
e->popPooledSocket(options, resolvedAddresses, req->getPort(), getDownloadEngine()->popPooledSocket
e->getAuthConfigFactory()->createAuthConfig (options, resolvedAddresses,
(req, getOption().get())->getUser()); getRequest()->getPort(),
getDownloadEngine()->getAuthConfigFactory()->createAuthConfig
(getRequest(), getOption().get())->getUser());
if(pooledSocket.isNull()) { if(pooledSocket.isNull()) {
if(getLogger()->info()) { if(getLogger()->info()) {
getLogger()->info(MSG_CONNECTING_TO_SERVER, getLogger()->info(MSG_CONNECTING_TO_SERVER,
util::itos(getCuid()).c_str(), addr.c_str(), port); util::itos(getCuid()).c_str(), addr.c_str(), port);
} }
socket.reset(new SocketCore()); createSocket();
socket->establishConnection(addr, port); getSocket()->establishConnection(addr, port);
FtpNegotiationCommand* c = FtpNegotiationCommand* c =
new FtpNegotiationCommand(getCuid(), req, _fileEntry, new FtpNegotiationCommand(getCuid(), getRequest(), getFileEntry(),
_requestGroup, e, socket); getRequestGroup(), getDownloadEngine(),
getSocket());
c->setConnectedAddr(hostname, addr, port); c->setConnectedAddr(hostname, addr, port);
command = c; command = c;
} else { } else {
command = command =
new FtpNegotiationCommand(getCuid(), req, _fileEntry, new FtpNegotiationCommand(getCuid(), getRequest(), getFileEntry(),
_requestGroup, e, pooledSocket, getRequestGroup(), getDownloadEngine(),
pooledSocket,
FtpNegotiationCommand::SEQ_SEND_CWD, FtpNegotiationCommand::SEQ_SEND_CWD,
options["baseWorkingDir"]); options["baseWorkingDir"]);
} }

View File

@ -83,104 +83,105 @@ FtpNegotiationCommand::FtpNegotiationCommand
const SharedHandle<FileEntry>& fileEntry, const SharedHandle<FileEntry>& fileEntry,
RequestGroup* requestGroup, RequestGroup* requestGroup,
DownloadEngine* e, DownloadEngine* e,
const SocketHandle& s, const SocketHandle& socket,
Seq seq, Seq seq,
const std::string& baseWorkingDir): const std::string& baseWorkingDir):
AbstractCommand(cuid, req, fileEntry, requestGroup, e, s), sequence(seq), AbstractCommand(cuid, req, fileEntry, requestGroup, e, socket), _sequence(seq),
ftp(new FtpConnection(cuid, socket, req, _ftp(new FtpConnection(cuid, socket, req,
e->getAuthConfigFactory()->createAuthConfig e->getAuthConfigFactory()->createAuthConfig
(req, requestGroup->getOption().get()), (req, requestGroup->getOption().get()),
getOption().get())) getOption().get()))
{ {
ftp->setBaseWorkingDir(baseWorkingDir); _ftp->setBaseWorkingDir(baseWorkingDir);
if(seq == SEQ_RECV_GREETING) { if(seq == SEQ_RECV_GREETING) {
setTimeout(getOption()->getAsInt(PREF_CONNECT_TIMEOUT)); setTimeout(getOption()->getAsInt(PREF_CONNECT_TIMEOUT));
} }
disableReadCheckSocket(); disableReadCheckSocket();
setWriteCheckSocket(socket); setWriteCheckSocket(getSocket());
} }
FtpNegotiationCommand::~FtpNegotiationCommand() {} FtpNegotiationCommand::~FtpNegotiationCommand() {}
bool FtpNegotiationCommand::executeInternal() { bool FtpNegotiationCommand::executeInternal() {
while(processSequence(_segments.front())); while(processSequence(getSegments().front()));
if(sequence == SEQ_RETRY) { if(_sequence == SEQ_RETRY) {
return prepareForRetry(0); return prepareForRetry(0);
} else if(sequence == SEQ_NEGOTIATION_COMPLETED) { } else if(_sequence == SEQ_NEGOTIATION_COMPLETED) {
FtpDownloadCommand* command = FtpDownloadCommand* command =
new FtpDownloadCommand new FtpDownloadCommand
(getCuid(), req, _fileEntry, _requestGroup, ftp, e, dataSocket, socket); (getCuid(), getRequest(), getFileEntry(), getRequestGroup(), _ftp,
getDownloadEngine(), _dataSocket, getSocket());
command->setStartupIdleTime(getOption()->getAsInt(PREF_STARTUP_IDLE_TIME)); command->setStartupIdleTime(getOption()->getAsInt(PREF_STARTUP_IDLE_TIME));
command->setLowestDownloadSpeedLimit command->setLowestDownloadSpeedLimit
(getOption()->getAsInt(PREF_LOWEST_SPEED_LIMIT)); (getOption()->getAsInt(PREF_LOWEST_SPEED_LIMIT));
if(!_fileEntry->isSingleHostMultiConnectionEnabled()) { if(!getFileEntry()->isSingleHostMultiConnectionEnabled()) {
_fileEntry->removeURIWhoseHostnameIs(req->getHost()); getFileEntry()->removeURIWhoseHostnameIs(getRequest()->getHost());
} }
_requestGroup->getURISelector()->tuneDownloadCommand getRequestGroup()->getURISelector()->tuneDownloadCommand
(_fileEntry->getRemainingUris(), command); (getFileEntry()->getRemainingUris(), command);
e->addCommand(command); getDownloadEngine()->addCommand(command);
return true; return true;
} else if(sequence == SEQ_HEAD_OK || } else if(_sequence == SEQ_HEAD_OK ||
sequence == SEQ_DOWNLOAD_ALREADY_COMPLETED) { _sequence == SEQ_DOWNLOAD_ALREADY_COMPLETED) {
return true; return true;
} else if(sequence == SEQ_FILE_PREPARATION) { } else if(_sequence == SEQ_FILE_PREPARATION) {
if(getOption()->getAsBool(PREF_FTP_PASV)) { if(getOption()->getAsBool(PREF_FTP_PASV)) {
sequence = SEQ_SEND_PASV; _sequence = SEQ_SEND_PASV;
} else { } else {
sequence = SEQ_PREPARE_SERVER_SOCKET; _sequence = SEQ_PREPARE_SERVER_SOCKET;
} }
return false; return false;
} else if(sequence == SEQ_EXIT) { } else if(_sequence == SEQ_EXIT) {
return true; return true;
} else { } else {
e->addCommand(this); getDownloadEngine()->addCommand(this);
return false; return false;
} }
} }
bool FtpNegotiationCommand::recvGreeting() { bool FtpNegotiationCommand::recvGreeting() {
if(!checkIfConnectionEstablished if(!checkIfConnectionEstablished
(socket, _connectedHostname, _connectedAddr, _connectedPort)) { (getSocket(), _connectedHostname, _connectedAddr, _connectedPort)) {
sequence = SEQ_EXIT; _sequence = SEQ_EXIT;
return false; return false;
} }
setTimeout(_requestGroup->getTimeout()); setTimeout(getRequestGroup()->getTimeout());
//socket->setBlockingMode(); //socket->setBlockingMode();
disableWriteCheckSocket(); disableWriteCheckSocket();
setReadCheckSocket(socket); setReadCheckSocket(getSocket());
unsigned int status = ftp->receiveResponse(); unsigned int status = _ftp->receiveResponse();
if(status == 0) { if(status == 0) {
return false; return false;
} }
if(status != 220) { if(status != 220) {
throw DL_ABORT_EX(EX_CONNECTION_FAILED); throw DL_ABORT_EX(EX_CONNECTION_FAILED);
} }
sequence = SEQ_SEND_USER; _sequence = SEQ_SEND_USER;
return true; return true;
} }
bool FtpNegotiationCommand::sendUser() { bool FtpNegotiationCommand::sendUser() {
if(ftp->sendUser()) { if(_ftp->sendUser()) {
disableWriteCheckSocket(); disableWriteCheckSocket();
sequence = SEQ_RECV_USER; _sequence = SEQ_RECV_USER;
} else { } else {
setWriteCheckSocket(socket); setWriteCheckSocket(getSocket());
} }
return false; return false;
} }
bool FtpNegotiationCommand::recvUser() { bool FtpNegotiationCommand::recvUser() {
unsigned int status = ftp->receiveResponse(); unsigned int status = _ftp->receiveResponse();
switch(status) { switch(status) {
case 0: case 0:
return false; return false;
case 230: case 230:
sequence = SEQ_SEND_TYPE; _sequence = SEQ_SEND_TYPE;
break; break;
case 331: case 331:
sequence = SEQ_SEND_PASS; _sequence = SEQ_SEND_PASS;
break; break;
default: default:
throw DL_ABORT_EX(StringFormat(EX_BAD_STATUS, status).str()); throw DL_ABORT_EX(StringFormat(EX_BAD_STATUS, status).str());
@ -189,56 +190,56 @@ bool FtpNegotiationCommand::recvUser() {
} }
bool FtpNegotiationCommand::sendPass() { bool FtpNegotiationCommand::sendPass() {
if(ftp->sendPass()) { if(_ftp->sendPass()) {
disableWriteCheckSocket(); disableWriteCheckSocket();
sequence = SEQ_RECV_PASS; _sequence = SEQ_RECV_PASS;
} else { } else {
setWriteCheckSocket(socket); setWriteCheckSocket(getSocket());
} }
return false; return false;
} }
bool FtpNegotiationCommand::recvPass() { bool FtpNegotiationCommand::recvPass() {
unsigned int status = ftp->receiveResponse(); unsigned int status = _ftp->receiveResponse();
if(status == 0) { if(status == 0) {
return false; return false;
} }
if(status != 230) { if(status != 230) {
throw DL_ABORT_EX(StringFormat(EX_BAD_STATUS, status).str()); throw DL_ABORT_EX(StringFormat(EX_BAD_STATUS, status).str());
} }
sequence = SEQ_SEND_TYPE; _sequence = SEQ_SEND_TYPE;
return true; return true;
} }
bool FtpNegotiationCommand::sendType() { bool FtpNegotiationCommand::sendType() {
if(ftp->sendType()) { if(_ftp->sendType()) {
disableWriteCheckSocket(); disableWriteCheckSocket();
sequence = SEQ_RECV_TYPE; _sequence = SEQ_RECV_TYPE;
} else { } else {
setWriteCheckSocket(socket); setWriteCheckSocket(getSocket());
} }
return false; return false;
} }
bool FtpNegotiationCommand::recvType() { bool FtpNegotiationCommand::recvType() {
unsigned int status = ftp->receiveResponse(); unsigned int status = _ftp->receiveResponse();
if(status == 0) { if(status == 0) {
return false; return false;
} }
if(status != 200) { if(status != 200) {
throw DL_ABORT_EX(StringFormat(EX_BAD_STATUS, status).str()); throw DL_ABORT_EX(StringFormat(EX_BAD_STATUS, status).str());
} }
sequence = SEQ_SEND_PWD; _sequence = SEQ_SEND_PWD;
return true; return true;
} }
bool FtpNegotiationCommand::sendPwd() bool FtpNegotiationCommand::sendPwd()
{ {
if(ftp->sendPwd()) { if(_ftp->sendPwd()) {
disableWriteCheckSocket(); disableWriteCheckSocket();
sequence = SEQ_RECV_PWD; _sequence = SEQ_RECV_PWD;
} else { } else {
setWriteCheckSocket(socket); setWriteCheckSocket(getSocket());
} }
return false; return false;
} }
@ -246,42 +247,42 @@ bool FtpNegotiationCommand::sendPwd()
bool FtpNegotiationCommand::recvPwd() bool FtpNegotiationCommand::recvPwd()
{ {
std::string pwd; std::string pwd;
unsigned int status = ftp->receivePwdResponse(pwd); unsigned int status = _ftp->receivePwdResponse(pwd);
if(status == 0) { if(status == 0) {
return false; return false;
} }
if(status != 257) { if(status != 257) {
throw DL_ABORT_EX(StringFormat(EX_BAD_STATUS, status).str()); throw DL_ABORT_EX(StringFormat(EX_BAD_STATUS, status).str());
} }
ftp->setBaseWorkingDir(pwd); _ftp->setBaseWorkingDir(pwd);
if(getLogger()->info()) { if(getLogger()->info()) {
getLogger()->info("CUID#%s - base working directory is '%s'", getLogger()->info("CUID#%s - base working directory is '%s'",
util::itos(getCuid()).c_str(), pwd.c_str()); util::itos(getCuid()).c_str(), pwd.c_str());
} }
sequence = SEQ_SEND_CWD; _sequence = SEQ_SEND_CWD;
return true; return true;
} }
bool FtpNegotiationCommand::sendCwd() { bool FtpNegotiationCommand::sendCwd() {
// Calling setReadCheckSocket() is needed when the socket is reused, // Calling setReadCheckSocket() is needed when the socket is reused,
setReadCheckSocket(socket); setReadCheckSocket(getSocket());
if(ftp->sendCwd()) { if(_ftp->sendCwd()) {
disableWriteCheckSocket(); disableWriteCheckSocket();
sequence = SEQ_RECV_CWD; _sequence = SEQ_RECV_CWD;
} else { } else {
setWriteCheckSocket(socket); setWriteCheckSocket(getSocket());
} }
return false; return false;
} }
bool FtpNegotiationCommand::recvCwd() { bool FtpNegotiationCommand::recvCwd() {
unsigned int status = ftp->receiveResponse(); unsigned int status = _ftp->receiveResponse();
if(status == 0) { if(status == 0) {
return false; return false;
} }
if(status != 250) { if(status != 250) {
poolConnection(); poolConnection();
_requestGroup->increaseAndValidateFileNotFoundCount(); getRequestGroup()->increaseAndValidateFileNotFoundCount();
if (status == 550) if (status == 550)
throw DL_ABORT_EX2(MSG_RESOURCE_NOT_FOUND, throw DL_ABORT_EX2(MSG_RESOURCE_NOT_FOUND,
downloadresultcode::RESOURCE_NOT_FOUND); downloadresultcode::RESOURCE_NOT_FOUND);
@ -289,20 +290,20 @@ bool FtpNegotiationCommand::recvCwd() {
throw DL_ABORT_EX(StringFormat(EX_BAD_STATUS, status).str()); throw DL_ABORT_EX(StringFormat(EX_BAD_STATUS, status).str());
} }
if(getOption()->getAsBool(PREF_REMOTE_TIME)) { if(getOption()->getAsBool(PREF_REMOTE_TIME)) {
sequence = SEQ_SEND_MDTM; _sequence = SEQ_SEND_MDTM;
} else { } else {
sequence = SEQ_SEND_SIZE; _sequence = SEQ_SEND_SIZE;
} }
return true; return true;
} }
bool FtpNegotiationCommand::sendMdtm() bool FtpNegotiationCommand::sendMdtm()
{ {
if(ftp->sendMdtm()) { if(_ftp->sendMdtm()) {
disableWriteCheckSocket(); disableWriteCheckSocket();
sequence = SEQ_RECV_MDTM; _sequence = SEQ_RECV_MDTM;
} else { } else {
setWriteCheckSocket(socket); setWriteCheckSocket(getSocket());
} }
return false; return false;
} }
@ -310,13 +311,13 @@ bool FtpNegotiationCommand::sendMdtm()
bool FtpNegotiationCommand::recvMdtm() bool FtpNegotiationCommand::recvMdtm()
{ {
Time lastModifiedTime = Time::null(); Time lastModifiedTime = Time::null();
unsigned int status = ftp->receiveMdtmResponse(lastModifiedTime); unsigned int status = _ftp->receiveMdtmResponse(lastModifiedTime);
if(status == 0) { if(status == 0) {
return false; return false;
} }
if(status == 213) { if(status == 213) {
if(lastModifiedTime.good()) { if(lastModifiedTime.good()) {
_requestGroup->updateLastModifiedTime(lastModifiedTime); getRequestGroup()->updateLastModifiedTime(lastModifiedTime);
time_t t = lastModifiedTime.getTime(); time_t t = lastModifiedTime.getTime();
struct tm* tms = gmtime(&t); // returned struct is statically allocated. struct tm* tms = gmtime(&t); // returned struct is statically allocated.
if(tms) { if(tms) {
@ -340,84 +341,87 @@ bool FtpNegotiationCommand::recvMdtm()
util::itos(getCuid()).c_str()); util::itos(getCuid()).c_str());
} }
} }
sequence = SEQ_SEND_SIZE; _sequence = SEQ_SEND_SIZE;
return true; return true;
} }
bool FtpNegotiationCommand::sendSize() { bool FtpNegotiationCommand::sendSize() {
if(ftp->sendSize()) { if(_ftp->sendSize()) {
disableWriteCheckSocket(); disableWriteCheckSocket();
sequence = SEQ_RECV_SIZE; _sequence = SEQ_RECV_SIZE;
} else { } else {
setWriteCheckSocket(socket); setWriteCheckSocket(getSocket());
} }
return false; return false;
} }
bool FtpNegotiationCommand::onFileSizeDetermined(uint64_t totalLength) bool FtpNegotiationCommand::onFileSizeDetermined(uint64_t totalLength)
{ {
_fileEntry->setLength(totalLength); getFileEntry()->setLength(totalLength);
if(_fileEntry->getPath().empty()) { if(getFileEntry()->getPath().empty()) {
_fileEntry->setPath getFileEntry()->setPath
(util::applyDir (util::applyDir
(getDownloadContext()->getDir(), (getDownloadContext()->getDir(),
util::fixTaintedBasename(util::percentDecode(req->getFile())))); util::fixTaintedBasename
(util::percentDecode(getRequest()->getFile()))));
} }
_requestGroup->preDownloadProcessing(); getRequestGroup()->preDownloadProcessing();
if(e->getRequestGroupMan()->isSameFileBeingDownloaded(_requestGroup)) { if(getDownloadEngine()->getRequestGroupMan()->
isSameFileBeingDownloaded(getRequestGroup())) {
throw DOWNLOAD_FAILURE_EXCEPTION throw DOWNLOAD_FAILURE_EXCEPTION
(StringFormat(EX_DUPLICATE_FILE_DOWNLOAD, (StringFormat(EX_DUPLICATE_FILE_DOWNLOAD,
_requestGroup->getFirstFilePath().c_str()).str()); getRequestGroup()->getFirstFilePath().c_str()).str());
} }
if(totalLength == 0) { if(totalLength == 0) {
if(getOption()->getAsBool(PREF_FTP_PASV)) { if(getOption()->getAsBool(PREF_FTP_PASV)) {
sequence = SEQ_SEND_PASV; _sequence = SEQ_SEND_PASV;
} else { } else {
sequence = SEQ_PREPARE_SERVER_SOCKET; _sequence = SEQ_PREPARE_SERVER_SOCKET;
} }
if(getOption()->getAsBool(PREF_DRY_RUN)) { if(getOption()->getAsBool(PREF_DRY_RUN)) {
_requestGroup->initPieceStorage(); getRequestGroup()->initPieceStorage();
onDryRunFileFound(); onDryRunFileFound();
return false; return false;
} }
if(_requestGroup->downloadFinishedByFileLength()) { if(getRequestGroup()->downloadFinishedByFileLength()) {
_requestGroup->initPieceStorage(); getRequestGroup()->initPieceStorage();
_requestGroup->getPieceStorage()->markAllPiecesDone(); getPieceStorage()->markAllPiecesDone();
sequence = SEQ_DOWNLOAD_ALREADY_COMPLETED; _sequence = SEQ_DOWNLOAD_ALREADY_COMPLETED;
getLogger()->notice(MSG_DOWNLOAD_ALREADY_COMPLETED, getLogger()->notice(MSG_DOWNLOAD_ALREADY_COMPLETED,
util::itos(_requestGroup->getGID()).c_str(), util::itos(getRequestGroup()->getGID()).c_str(),
_requestGroup->getFirstFilePath().c_str()); getRequestGroup()->getFirstFilePath().c_str());
poolConnection(); poolConnection();
return false; return false;
} }
_requestGroup->shouldCancelDownloadForSafety(); getRequestGroup()->shouldCancelDownloadForSafety();
_requestGroup->initPieceStorage(); getRequestGroup()->initPieceStorage();
_requestGroup->getPieceStorage()->getDiskAdaptor()->initAndOpenFile(); getPieceStorage()->getDiskAdaptor()->initAndOpenFile();
if(getDownloadContext()->knowsTotalLength()) { if(getDownloadContext()->knowsTotalLength()) {
sequence = SEQ_DOWNLOAD_ALREADY_COMPLETED; _sequence = SEQ_DOWNLOAD_ALREADY_COMPLETED;
poolConnection(); poolConnection();
return false; return false;
} }
// We have to make sure that command that has Request object must // We have to make sure that command that has Request object must
// have segment after PieceStorage is initialized. See // have segment after PieceStorage is initialized. See
// AbstractCommand::execute() // AbstractCommand::execute()
_requestGroup->getSegmentMan()->getSegment(getCuid(), 0); getSegmentMan()->getSegment(getCuid(), 0);
return true; return true;
} else { } else {
_requestGroup->adjustFilename getRequestGroup()->adjustFilename
(SharedHandle<BtProgressInfoFile>(new DefaultBtProgressInfoFile (SharedHandle<BtProgressInfoFile>
(_requestGroup->getDownloadContext(), (new DefaultBtProgressInfoFile
SharedHandle<PieceStorage>(), (getDownloadContext(),
getOption().get()))); SharedHandle<PieceStorage>(),
_requestGroup->initPieceStorage(); getOption().get())));
getRequestGroup()->initPieceStorage();
if(getOption()->getAsBool(PREF_DRY_RUN)) { if(getOption()->getAsBool(PREF_DRY_RUN)) {
onDryRunFileFound(); onDryRunFileFound();
@ -425,27 +429,28 @@ bool FtpNegotiationCommand::onFileSizeDetermined(uint64_t totalLength)
} }
BtProgressInfoFileHandle infoFile BtProgressInfoFileHandle infoFile
(new DefaultBtProgressInfoFile(_requestGroup->getDownloadContext(), (new DefaultBtProgressInfoFile(getDownloadContext(),
_requestGroup->getPieceStorage(), getPieceStorage(),
getOption().get())); getOption().get()));
if(!infoFile->exists() && _requestGroup->downloadFinishedByFileLength()) { if(!infoFile->exists() &&
_requestGroup->getPieceStorage()->markAllPiecesDone(); getRequestGroup()->downloadFinishedByFileLength()) {
getPieceStorage()->markAllPiecesDone();
sequence = SEQ_DOWNLOAD_ALREADY_COMPLETED; _sequence = SEQ_DOWNLOAD_ALREADY_COMPLETED;
getLogger()->notice(MSG_DOWNLOAD_ALREADY_COMPLETED, getLogger()->notice(MSG_DOWNLOAD_ALREADY_COMPLETED,
util::itos(_requestGroup->getGID()).c_str(), util::itos(getRequestGroup()->getGID()).c_str(),
_requestGroup->getFirstFilePath().c_str()); getRequestGroup()->getFirstFilePath().c_str());
poolConnection(); poolConnection();
return false; return false;
} }
_requestGroup->loadAndOpenFile(infoFile); getRequestGroup()->loadAndOpenFile(infoFile);
// We have to make sure that command that has Request object must // We have to make sure that command that has Request object must
// have segment after PieceStorage is initialized. See // have segment after PieceStorage is initialized. See
// AbstractCommand::execute() // AbstractCommand::execute()
_requestGroup->getSegmentMan()->getSegment(getCuid(), 0); getSegmentMan()->getSegment(getCuid(), 0);
prepareForNextAction(this); prepareForNextAction(this);
@ -456,7 +461,7 @@ bool FtpNegotiationCommand::onFileSizeDetermined(uint64_t totalLength)
bool FtpNegotiationCommand::recvSize() { bool FtpNegotiationCommand::recvSize() {
uint64_t size = 0; uint64_t size = 0;
unsigned int status = ftp->receiveSizeResponse(size); unsigned int status = _ftp->receiveSizeResponse(size);
if(status == 0) { if(status == 0) {
return false; return false;
} }
@ -467,13 +472,13 @@ bool FtpNegotiationCommand::recvSize() {
(StringFormat(EX_TOO_LARGE_FILE, (StringFormat(EX_TOO_LARGE_FILE,
util::uitos(size, true).c_str()).str()); util::uitos(size, true).c_str()).str());
} }
if(_requestGroup->getPieceStorage().isNull()) { if(getPieceStorage().isNull()) {
sequence = SEQ_FILE_PREPARATION; _sequence = SEQ_FILE_PREPARATION;
return onFileSizeDetermined(size); return onFileSizeDetermined(size);
} else { } else {
_requestGroup->validateTotalLength(_fileEntry->getLength(), size); getRequestGroup()->validateTotalLength(getFileEntry()->getLength(), size);
} }
} else { } else {
@ -484,7 +489,7 @@ bool FtpNegotiationCommand::recvSize() {
// Even if one of the other servers waiting in the queue supports SIZE // Even if one of the other servers waiting in the queue supports SIZE
// command, resuming and segmented downloading are disabled when the first // command, resuming and segmented downloading are disabled when the first
// contacted FTP server doesn't support it. // contacted FTP server doesn't support it.
if(_requestGroup->getPieceStorage().isNull()) { if(getPieceStorage().isNull()) {
getDownloadContext()->markTotalLengthIsUnknown(); getDownloadContext()->markTotalLengthIsUnknown();
return onFileSizeDetermined(0); return onFileSizeDetermined(0);
@ -493,62 +498,62 @@ bool FtpNegotiationCommand::recvSize() {
// wrong file to be downloaded if user-specified URL is wrong. // wrong file to be downloaded if user-specified URL is wrong.
} }
if(getOption()->getAsBool(PREF_FTP_PASV)) { if(getOption()->getAsBool(PREF_FTP_PASV)) {
sequence = SEQ_SEND_PASV; _sequence = SEQ_SEND_PASV;
} else { } else {
sequence = SEQ_PREPARE_SERVER_SOCKET; _sequence = SEQ_PREPARE_SERVER_SOCKET;
} }
return true; return true;
} }
void FtpNegotiationCommand::afterFileAllocation() void FtpNegotiationCommand::afterFileAllocation()
{ {
setReadCheckSocket(socket); setReadCheckSocket(getSocket());
} }
bool FtpNegotiationCommand::prepareServerSocket() bool FtpNegotiationCommand::prepareServerSocket()
{ {
serverSocket = ftp->createServerSocket(); _serverSocket = _ftp->createServerSocket();
sequence = SEQ_SEND_PORT; _sequence = SEQ_SEND_PORT;
return true; return true;
} }
bool FtpNegotiationCommand::sendPort() { bool FtpNegotiationCommand::sendPort() {
afterFileAllocation(); afterFileAllocation();
if(ftp->sendPort(serverSocket)) { if(_ftp->sendPort(_serverSocket)) {
disableWriteCheckSocket(); disableWriteCheckSocket();
sequence = SEQ_RECV_PORT; _sequence = SEQ_RECV_PORT;
} else { } else {
setWriteCheckSocket(socket); setWriteCheckSocket(getSocket());
} }
return false; return false;
} }
bool FtpNegotiationCommand::recvPort() { bool FtpNegotiationCommand::recvPort() {
unsigned int status = ftp->receiveResponse(); unsigned int status = _ftp->receiveResponse();
if(status == 0) { if(status == 0) {
return false; return false;
} }
if(status != 200) { if(status != 200) {
throw DL_ABORT_EX(StringFormat(EX_BAD_STATUS, status).str()); throw DL_ABORT_EX(StringFormat(EX_BAD_STATUS, status).str());
} }
sequence = SEQ_SEND_REST; _sequence = SEQ_SEND_REST;
return true; return true;
} }
bool FtpNegotiationCommand::sendPasv() { bool FtpNegotiationCommand::sendPasv() {
afterFileAllocation(); afterFileAllocation();
if(ftp->sendPasv()) { if(_ftp->sendPasv()) {
disableWriteCheckSocket(); disableWriteCheckSocket();
sequence = SEQ_RECV_PASV; _sequence = SEQ_RECV_PASV;
} else { } else {
setWriteCheckSocket(socket); setWriteCheckSocket(getSocket());
} }
return false; return false;
} }
bool FtpNegotiationCommand::recvPasv() { bool FtpNegotiationCommand::recvPasv() {
std::pair<std::string, uint16_t> dest; std::pair<std::string, uint16_t> dest;
unsigned int status = ftp->receivePasvResponse(dest); unsigned int status = _ftp->receivePasvResponse(dest);
if(status == 0) { if(status == 0) {
return false; return false;
} }
@ -558,7 +563,7 @@ bool FtpNegotiationCommand::recvPasv() {
// TODO Should we check to see that dest.first is not in noProxy list? // TODO Should we check to see that dest.first is not in noProxy list?
if(isProxyDefined()) { if(isProxyDefined()) {
_dataConnAddr = dest; _dataConnAddr = dest;
sequence = SEQ_RESOLVE_PROXY; _sequence = SEQ_RESOLVE_PROXY;
return true; return true;
} else { } else {
// make a data connection to the server. // make a data connection to the server.
@ -567,11 +572,11 @@ bool FtpNegotiationCommand::recvPasv() {
dest.first.c_str(), dest.first.c_str(),
dest.second); dest.second);
} }
dataSocket.reset(new SocketCore()); _dataSocket.reset(new SocketCore());
dataSocket->establishConnection(dest.first, dest.second); _dataSocket->establishConnection(dest.first, dest.second);
disableReadCheckSocket(); disableReadCheckSocket();
setWriteCheckSocket(dataSocket); setWriteCheckSocket(_dataSocket);
sequence = SEQ_SEND_REST_PASV; _sequence = SEQ_SEND_REST_PASV;
return false; return false;
} }
} }
@ -589,27 +594,29 @@ bool FtpNegotiationCommand::resolveProxy()
getLogger()->info(MSG_CONNECTING_TO_SERVER, util::itos(getCuid()).c_str(), getLogger()->info(MSG_CONNECTING_TO_SERVER, util::itos(getCuid()).c_str(),
_proxyAddr.c_str(), proxyReq->getPort()); _proxyAddr.c_str(), proxyReq->getPort());
} }
dataSocket.reset(new SocketCore()); _dataSocket.reset(new SocketCore());
dataSocket->establishConnection(_proxyAddr, proxyReq->getPort()); _dataSocket->establishConnection(_proxyAddr, proxyReq->getPort());
disableReadCheckSocket(); disableReadCheckSocket();
setWriteCheckSocket(dataSocket); setWriteCheckSocket(_dataSocket);
_http.reset(new HttpConnection(getCuid(), dataSocket, getOption().get())); _http.reset(new HttpConnection(getCuid(), _dataSocket, getOption().get()));
sequence = SEQ_SEND_TUNNEL_REQUEST; _sequence = SEQ_SEND_TUNNEL_REQUEST;
return false; return false;
} }
bool FtpNegotiationCommand::sendTunnelRequest() bool FtpNegotiationCommand::sendTunnelRequest()
{ {
if(_http->sendBufferIsEmpty()) { if(_http->sendBufferIsEmpty()) {
if(dataSocket->isReadable(0)) { if(_dataSocket->isReadable(0)) {
std::string error = socket->getSocketError(); std::string error = getSocket()->getSocketError();
if(!error.empty()) { if(!error.empty()) {
SharedHandle<Request> proxyReq = createProxyRequest(); SharedHandle<Request> proxyReq = createProxyRequest();
e->markBadIPAddress(proxyReq->getHost(),_proxyAddr,proxyReq->getPort()); getDownloadEngine()->markBadIPAddress(proxyReq->getHost(),
std::string nextProxyAddr = e->findCachedIPAddress _proxyAddr,proxyReq->getPort());
std::string nextProxyAddr = getDownloadEngine()->findCachedIPAddress
(proxyReq->getHost(), proxyReq->getPort()); (proxyReq->getHost(), proxyReq->getPort());
if(nextProxyAddr.empty()) { if(nextProxyAddr.empty()) {
e->removeCachedIPAddress(proxyReq->getHost(), proxyReq->getPort()); getDownloadEngine()->removeCachedIPAddress(proxyReq->getHost(),
proxyReq->getPort());
throw DL_RETRY_EX throw DL_RETRY_EX
(StringFormat(MSG_ESTABLISHING_CONNECTION_FAILED, (StringFormat(MSG_ESTABLISHING_CONNECTION_FAILED,
error.c_str()).str()); error.c_str()).str());
@ -625,7 +632,7 @@ bool FtpNegotiationCommand::sendTunnelRequest()
util::itos(getCuid()).c_str(), util::itos(getCuid()).c_str(),
_proxyAddr.c_str(), proxyReq->getPort()); _proxyAddr.c_str(), proxyReq->getPort());
} }
dataSocket->establishConnection(_proxyAddr, proxyReq->getPort()); _dataSocket->establishConnection(_proxyAddr, proxyReq->getPort());
return false; return false;
} }
} }
@ -644,11 +651,11 @@ bool FtpNegotiationCommand::sendTunnelRequest()
} }
if(_http->sendBufferIsEmpty()) { if(_http->sendBufferIsEmpty()) {
disableWriteCheckSocket(); disableWriteCheckSocket();
setReadCheckSocket(dataSocket); setReadCheckSocket(_dataSocket);
sequence = SEQ_RECV_TUNNEL_RESPONSE; _sequence = SEQ_RECV_TUNNEL_RESPONSE;
return false; return false;
} else { } else {
setWriteCheckSocket(dataSocket); setWriteCheckSocket(_dataSocket);
return false; return false;
} }
} }
@ -662,29 +669,29 @@ bool FtpNegotiationCommand::recvTunnelResponse()
if(httpResponse->getResponseStatus() != HttpHeader::S200) { if(httpResponse->getResponseStatus() != HttpHeader::S200) {
throw DL_RETRY_EX(EX_PROXY_CONNECTION_FAILED); throw DL_RETRY_EX(EX_PROXY_CONNECTION_FAILED);
} }
sequence = SEQ_SEND_REST_PASV; _sequence = SEQ_SEND_REST_PASV;
return true; return true;
} }
bool FtpNegotiationCommand::sendRestPasv(const SharedHandle<Segment>& segment) { bool FtpNegotiationCommand::sendRestPasv(const SharedHandle<Segment>& segment) {
//dataSocket->setBlockingMode(); //_dataSocket->setBlockingMode();
setReadCheckSocket(socket); setReadCheckSocket(getSocket());
disableWriteCheckSocket(); disableWriteCheckSocket();
return sendRest(segment); return sendRest(segment);
} }
bool FtpNegotiationCommand::sendRest(const SharedHandle<Segment>& segment) { bool FtpNegotiationCommand::sendRest(const SharedHandle<Segment>& segment) {
if(ftp->sendRest(segment)) { if(_ftp->sendRest(segment)) {
disableWriteCheckSocket(); disableWriteCheckSocket();
sequence = SEQ_RECV_REST; _sequence = SEQ_RECV_REST;
} else { } else {
setWriteCheckSocket(socket); setWriteCheckSocket(getSocket());
} }
return false; return false;
} }
bool FtpNegotiationCommand::recvRest(const SharedHandle<Segment>& segment) { bool FtpNegotiationCommand::recvRest(const SharedHandle<Segment>& segment) {
unsigned int status = ftp->receiveResponse(); unsigned int status = _ftp->receiveResponse();
if(status == 0) { if(status == 0) {
return false; return false;
} }
@ -696,27 +703,27 @@ bool FtpNegotiationCommand::recvRest(const SharedHandle<Segment>& segment) {
downloadresultcode::CANNOT_RESUME); downloadresultcode::CANNOT_RESUME);
} }
} }
sequence = SEQ_SEND_RETR; _sequence = SEQ_SEND_RETR;
return true; return true;
} }
bool FtpNegotiationCommand::sendRetr() { bool FtpNegotiationCommand::sendRetr() {
if(ftp->sendRetr()) { if(_ftp->sendRetr()) {
disableWriteCheckSocket(); disableWriteCheckSocket();
sequence = SEQ_RECV_RETR; _sequence = SEQ_RECV_RETR;
} else { } else {
setWriteCheckSocket(socket); setWriteCheckSocket(getSocket());
} }
return false; return false;
} }
bool FtpNegotiationCommand::recvRetr() { bool FtpNegotiationCommand::recvRetr() {
unsigned int status = ftp->receiveResponse(); unsigned int status = _ftp->receiveResponse();
if(status == 0) { if(status == 0) {
return false; return false;
} }
if(status != 150 && status != 125) { if(status != 150 && status != 125) {
_requestGroup->increaseAndValidateFileNotFoundCount(); getRequestGroup()->increaseAndValidateFileNotFoundCount();
if (status == 550) if (status == 550)
throw DL_ABORT_EX2(MSG_RESOURCE_NOT_FOUND, throw DL_ABORT_EX2(MSG_RESOURCE_NOT_FOUND,
downloadresultcode::RESOURCE_NOT_FOUND); downloadresultcode::RESOURCE_NOT_FOUND);
@ -724,12 +731,12 @@ bool FtpNegotiationCommand::recvRetr() {
throw DL_ABORT_EX(StringFormat(EX_BAD_STATUS, status).str()); throw DL_ABORT_EX(StringFormat(EX_BAD_STATUS, status).str());
} }
if(getOption()->getAsBool(PREF_FTP_PASV)) { if(getOption()->getAsBool(PREF_FTP_PASV)) {
sequence = SEQ_NEGOTIATION_COMPLETED; _sequence = SEQ_NEGOTIATION_COMPLETED;
return false; return false;
} else { } else {
disableReadCheckSocket(); disableReadCheckSocket();
setReadCheckSocket(serverSocket); setReadCheckSocket(_serverSocket);
sequence = SEQ_WAIT_CONNECTION; _sequence = SEQ_WAIT_CONNECTION;
return false; return false;
} }
} }
@ -737,17 +744,17 @@ bool FtpNegotiationCommand::recvRetr() {
bool FtpNegotiationCommand::waitConnection() bool FtpNegotiationCommand::waitConnection()
{ {
disableReadCheckSocket(); disableReadCheckSocket();
setReadCheckSocket(socket); setReadCheckSocket(getSocket());
dataSocket.reset(serverSocket->acceptConnection()); _dataSocket.reset(_serverSocket->acceptConnection());
dataSocket->setNonBlockingMode(); _dataSocket->setNonBlockingMode();
sequence = SEQ_NEGOTIATION_COMPLETED; _sequence = SEQ_NEGOTIATION_COMPLETED;
return false; return false;
} }
bool FtpNegotiationCommand::processSequence bool FtpNegotiationCommand::processSequence
(const SharedHandle<Segment>& segment) { (const SharedHandle<Segment>& segment) {
bool doNextSequence = true; bool doNextSequence = true;
switch(sequence) { switch(_sequence) {
case SEQ_RECV_GREETING: case SEQ_RECV_GREETING:
return recvGreeting(); return recvGreeting();
case SEQ_SEND_USER: case SEQ_SEND_USER:
@ -816,16 +823,17 @@ void FtpNegotiationCommand::poolConnection() const
{ {
if(getOption()->getAsBool(PREF_FTP_REUSE_CONNECTION)) { if(getOption()->getAsBool(PREF_FTP_REUSE_CONNECTION)) {
std::map<std::string, std::string> options; std::map<std::string, std::string> options;
options["baseWorkingDir"] = ftp->getBaseWorkingDir(); options["baseWorkingDir"] = _ftp->getBaseWorkingDir();
e->poolSocket(req, ftp->getUser(), createProxyRequest(), socket, options); getDownloadEngine()->poolSocket(getRequest(), _ftp->getUser(),
createProxyRequest(), getSocket(), options);
} }
} }
void FtpNegotiationCommand::onDryRunFileFound() void FtpNegotiationCommand::onDryRunFileFound()
{ {
_requestGroup->getPieceStorage()->markAllPiecesDone(); getPieceStorage()->markAllPiecesDone();
poolConnection(); poolConnection();
sequence = SEQ_HEAD_OK; _sequence = SEQ_HEAD_OK;
} }
} // namespace aria2 } // namespace aria2

View File

@ -122,10 +122,10 @@ private:
void onDryRunFileFound(); void onDryRunFileFound();
SharedHandle<SocketCore> dataSocket; SharedHandle<SocketCore> _dataSocket;
SharedHandle<SocketCore> serverSocket; SharedHandle<SocketCore> _serverSocket;
Seq sequence; Seq _sequence;
SharedHandle<FtpConnection> ftp; SharedHandle<FtpConnection> _ftp;
// For tunneling // For tunneling
SharedHandle<HttpConnection> _http; SharedHandle<HttpConnection> _http;
// IP, Port pair in pasv response // IP, Port pair in pasv response

View File

@ -58,7 +58,8 @@ FtpTunnelRequestCommand::~FtpTunnelRequestCommand() {}
Command* FtpTunnelRequestCommand::getNextCommand() Command* FtpTunnelRequestCommand::getNextCommand()
{ {
return new FtpTunnelResponseCommand return new FtpTunnelResponseCommand
(getCuid(), req, _fileEntry, _requestGroup, httpConnection, e, socket); (getCuid(), getRequest(), getFileEntry(), getRequestGroup(),
getHttpConnection(), getDownloadEngine(), getSocket());
} }
} // namespace aria2 } // namespace aria2

View File

@ -59,8 +59,9 @@ FtpTunnelResponseCommand::~FtpTunnelResponseCommand() {}
Command* FtpTunnelResponseCommand::getNextCommand() Command* FtpTunnelResponseCommand::getNextCommand()
{ {
return new FtpNegotiationCommand(getCuid(), req, _fileEntry, return new FtpNegotiationCommand(getCuid(), getRequest(), getFileEntry(),
_requestGroup, e, socket); getRequestGroup(), getDownloadEngine(),
getSocket());
} }
} // namespace aria2 } // namespace aria2

View File

@ -71,29 +71,29 @@ HttpDownloadCommand::HttpDownloadCommand
HttpDownloadCommand::~HttpDownloadCommand() {} HttpDownloadCommand::~HttpDownloadCommand() {}
bool HttpDownloadCommand::prepareForNextSegment() { bool HttpDownloadCommand::prepareForNextSegment() {
bool downloadFinished = _requestGroup->downloadFinished(); bool downloadFinished = getRequestGroup()->downloadFinished();
if(req->isPipeliningEnabled() && !downloadFinished) { if(getRequest()->isPipeliningEnabled() && !downloadFinished) {
HttpRequestCommand* command = HttpRequestCommand* command =
new HttpRequestCommand(getCuid(), req, _fileEntry, new HttpRequestCommand(getCuid(), getRequest(), getFileEntry(),
_requestGroup, _httpConnection, e, getRequestGroup(), _httpConnection,
socket); getDownloadEngine(), getSocket());
// Set proxy request here. aria2 sends the HTTP request specialized for // Set proxy request here. aria2 sends the HTTP request specialized for
// proxy. // proxy.
if(resolveProxyMethod(req->getProtocol()) == V_GET) { if(resolveProxyMethod(getRequest()->getProtocol()) == V_GET) {
command->setProxyRequest(createProxyRequest()); command->setProxyRequest(createProxyRequest());
} }
e->addCommand(command); getDownloadEngine()->addCommand(command);
return true; return true;
} else { } else {
if(req->isPipeliningEnabled() || if(getRequest()->isPipeliningEnabled() ||
(req->isKeepAliveEnabled() && (getRequest()->isKeepAliveEnabled() &&
( (
((!_transferEncodingDecoder.isNull() && ((!getTransferEncodingDecoder().isNull() &&
_transferEncodingDecoder->finished()) || getTransferEncodingDecoder()->finished()) ||
(!_contentEncodingDecoder.isNull() && (!getContentEncodingDecoder().isNull() &&
_contentEncodingDecoder->finished())) || getContentEncodingDecoder()->finished())) ||
_fileEntry->getLastOffset() == getFileEntry()->getLastOffset() ==
_segments.front()->getPositionToWrite() getSegments().front()->getPositionToWrite()
) )
) )
) { ) {
@ -102,20 +102,23 @@ bool HttpDownloadCommand::prepareForNextSegment() {
// pool terminated socket. In HTTP/1.1, keep-alive is default, // pool terminated socket. In HTTP/1.1, keep-alive is default,
// so closing connection without Connection: close header means // so closing connection without Connection: close header means
// that server is broken or not configured properly. // that server is broken or not configured properly.
e->poolSocket(req, createProxyRequest(), socket); getDownloadEngine()->poolSocket
(getRequest(), createProxyRequest(), getSocket());
} }
// The request was sent assuming that server supported pipelining, but // The request was sent assuming that server supported pipelining, but
// it turned out that server didn't support it. // it turned out that server didn't support it.
// We detect this situation by comparing the end byte in range header // We detect this situation by comparing the end byte in range header
// of the response with the end byte of segment. // of the response with the end byte of segment.
// If it is the same, HTTP negotiation is necessary for the next request. // If it is the same, HTTP negotiation is necessary for the next request.
if(!req->isPipeliningEnabled() && req->isPipeliningHint() && if(!getRequest()->isPipeliningEnabled() &&
getRequest()->isPipeliningHint() &&
!downloadFinished) { !downloadFinished) {
const SharedHandle<Segment>& segment = _segments.front(); const SharedHandle<Segment>& segment = getSegments().front();
off_t lastOffset =_fileEntry->gtoloff off_t lastOffset =getFileEntry()->gtoloff
(std::min(static_cast<off_t>(segment->getPosition()+segment->getLength()), (std::min(static_cast<off_t>
_fileEntry->getLastOffset())); (segment->getPosition()+segment->getLength()),
getFileEntry()->getLastOffset()));
if(lastOffset == if(lastOffset ==
_httpResponse->getHttpHeader()->getRange()->getEndByte()+1) { _httpResponse->getHttpHeader()->getRange()->getEndByte()+1) {

View File

@ -73,32 +73,39 @@ Command* HttpInitiateConnectionCommand::createNextCommand
Command* command; Command* command;
if(!proxyRequest.isNull()) { if(!proxyRequest.isNull()) {
SharedHandle<SocketCore> pooledSocket = SharedHandle<SocketCore> pooledSocket =
e->popPooledSocket(req->getHost(), req->getPort(), getDownloadEngine()->popPooledSocket
proxyRequest->getHost(), proxyRequest->getPort()); (getRequest()->getHost(), getRequest()->getPort(),
std::string proxyMethod = resolveProxyMethod(req->getProtocol()); proxyRequest->getHost(), proxyRequest->getPort());
std::string proxyMethod = resolveProxyMethod(getRequest()->getProtocol());
if(pooledSocket.isNull()) { if(pooledSocket.isNull()) {
if(getLogger()->info()) { if(getLogger()->info()) {
getLogger()->info(MSG_CONNECTING_TO_SERVER, getLogger()->info(MSG_CONNECTING_TO_SERVER,
util::itos(getCuid()).c_str(), addr.c_str(), port); util::itos(getCuid()).c_str(), addr.c_str(), port);
} }
socket.reset(new SocketCore()); createSocket();
socket->establishConnection(addr, port); getSocket()->establishConnection(addr, port);
if(proxyMethod == V_TUNNEL) { if(proxyMethod == V_TUNNEL) {
HttpProxyRequestCommand* c = HttpProxyRequestCommand* c =
new HttpProxyRequestCommand(getCuid(), req, _fileEntry, new HttpProxyRequestCommand(getCuid(),
_requestGroup, e, getRequest(),
proxyRequest, socket); getFileEntry(),
getRequestGroup(),
getDownloadEngine(),
proxyRequest,
getSocket());
c->setConnectedAddr(hostname, addr, port); c->setConnectedAddr(hostname, addr, port);
command = c; command = c;
} else if(proxyMethod == V_GET) { } else if(proxyMethod == V_GET) {
SharedHandle<HttpConnection> httpConnection SharedHandle<HttpConnection> httpConnection
(new HttpConnection(getCuid(), socket, getOption().get())); (new HttpConnection(getCuid(), getSocket(), getOption().get()));
HttpRequestCommand* c = new HttpRequestCommand(getCuid(), req, HttpRequestCommand* c = new HttpRequestCommand(getCuid(),
_fileEntry, getRequest(),
_requestGroup, getFileEntry(),
httpConnection, e, getRequestGroup(),
socket); httpConnection,
getDownloadEngine(),
getSocket());
c->setConnectedAddr(hostname, addr, port); c->setConnectedAddr(hostname, addr, port);
c->setProxyRequest(proxyRequest); c->setProxyRequest(proxyRequest);
command = c; command = c;
@ -109,10 +116,12 @@ Command* HttpInitiateConnectionCommand::createNextCommand
} else { } else {
SharedHandle<HttpConnection> httpConnection SharedHandle<HttpConnection> httpConnection
(new HttpConnection(getCuid(), pooledSocket, getOption().get())); (new HttpConnection(getCuid(), pooledSocket, getOption().get()));
HttpRequestCommand* c = new HttpRequestCommand(getCuid(), req, HttpRequestCommand* c = new HttpRequestCommand(getCuid(),
_fileEntry, getRequest(),
_requestGroup, getFileEntry(),
httpConnection, e, getRequestGroup(),
httpConnection,
getDownloadEngine(),
pooledSocket); pooledSocket);
if(proxyMethod == V_GET) { if(proxyMethod == V_GET) {
c->setProxyRequest(proxyRequest); c->setProxyRequest(proxyRequest);
@ -121,22 +130,26 @@ Command* HttpInitiateConnectionCommand::createNextCommand
} }
} else { } else {
SharedHandle<SocketCore> pooledSocket = SharedHandle<SocketCore> pooledSocket =
e->popPooledSocket(resolvedAddresses, req->getPort()); getDownloadEngine()->popPooledSocket
(resolvedAddresses, getRequest()->getPort());
if(pooledSocket.isNull()) { if(pooledSocket.isNull()) {
if(getLogger()->info()) { if(getLogger()->info()) {
getLogger()->info(MSG_CONNECTING_TO_SERVER, getLogger()->info(MSG_CONNECTING_TO_SERVER,
util::itos(getCuid()).c_str(), addr.c_str(), port); util::itos(getCuid()).c_str(), addr.c_str(), port);
} }
socket.reset(new SocketCore()); createSocket();
socket->establishConnection(addr, port); getSocket()->establishConnection(addr, port);
} else { } else {
socket = pooledSocket; setSocket(pooledSocket);
} }
SharedHandle<HttpConnection> httpConnection SharedHandle<HttpConnection> httpConnection
(new HttpConnection(getCuid(), socket, getOption().get())); (new HttpConnection(getCuid(), getSocket(), getOption().get()));
HttpRequestCommand* c = HttpRequestCommand* c =
new HttpRequestCommand(getCuid(), req, _fileEntry, _requestGroup, new HttpRequestCommand(getCuid(), getRequest(), getFileEntry(),
httpConnection, e, socket); getRequestGroup(),
httpConnection,
getDownloadEngine(),
getSocket());
if(pooledSocket.isNull()) { if(pooledSocket.isNull()) {
c->setConnectedAddr(hostname, addr, port); c->setConnectedAddr(hostname, addr, port);
} }

View File

@ -58,7 +58,8 @@ HttpProxyRequestCommand::~HttpProxyRequestCommand() {}
Command* HttpProxyRequestCommand::getNextCommand() Command* HttpProxyRequestCommand::getNextCommand()
{ {
return new HttpProxyResponseCommand return new HttpProxyResponseCommand
(getCuid(), req, _fileEntry, _requestGroup, httpConnection, e, socket); (getCuid(), getRequest(), getFileEntry(), getRequestGroup(),
getHttpConnection(), getDownloadEngine(), getSocket());
} }
} // namespace aria2 } // namespace aria2

View File

@ -59,8 +59,9 @@ HttpProxyResponseCommand::~HttpProxyResponseCommand() {}
Command* HttpProxyResponseCommand::getNextCommand() Command* HttpProxyResponseCommand::getNextCommand()
{ {
return new HttpRequestCommand(getCuid(), req, _fileEntry, return new HttpRequestCommand(getCuid(), getRequest(), getFileEntry(),
_requestGroup, httpConnection, e, socket); getRequestGroup(), getHttpConnection(),
getDownloadEngine(), getSocket());
} }
} // namespace aria2 } // namespace aria2

View File

@ -73,7 +73,7 @@ HttpRequestCommand::HttpRequestCommand
{ {
setTimeout(getOption()->getAsInt(PREF_CONNECT_TIMEOUT)); setTimeout(getOption()->getAsInt(PREF_CONNECT_TIMEOUT));
disableReadCheckSocket(); disableReadCheckSocket();
setWriteCheckSocket(socket); setWriteCheckSocket(getSocket());
} }
HttpRequestCommand::~HttpRequestCommand() {} HttpRequestCommand::~HttpRequestCommand() {}
@ -115,47 +115,48 @@ createHttpRequest(const SharedHandle<Request>& req,
bool HttpRequestCommand::executeInternal() { bool HttpRequestCommand::executeInternal() {
//socket->setBlockingMode(); //socket->setBlockingMode();
if(req->getProtocol() == Request::PROTO_HTTPS) { if(getRequest()->getProtocol() == Request::PROTO_HTTPS) {
socket->prepareSecureConnection(); getSocket()->prepareSecureConnection();
if(!socket->initiateSecureConnection(req->getHost())) { if(!getSocket()->initiateSecureConnection(getRequest()->getHost())) {
setReadCheckSocketIf(socket, socket->wantRead()); setReadCheckSocketIf(getSocket(), getSocket()->wantRead());
setWriteCheckSocketIf(socket, socket->wantWrite()); setWriteCheckSocketIf(getSocket(), getSocket()->wantWrite());
e->addCommand(this); getDownloadEngine()->addCommand(this);
return false; return false;
} }
} }
if(_httpConnection->sendBufferIsEmpty()) { if(_httpConnection->sendBufferIsEmpty()) {
if(!checkIfConnectionEstablished if(!checkIfConnectionEstablished
(socket, _connectedHostname, _connectedAddr, _connectedPort)) { (getSocket(), _connectedHostname, _connectedAddr, _connectedPort)) {
return true; return true;
} }
if(_segments.empty()) { if(getSegments().empty()) {
SharedHandle<HttpRequest> httpRequest SharedHandle<HttpRequest> httpRequest
(createHttpRequest(req, (createHttpRequest(getRequest(),
_fileEntry, getFileEntry(),
SharedHandle<Segment>(), SharedHandle<Segment>(),
_requestGroup->getTotalLength(), getRequestGroup()->getTotalLength(),
getOption(), getOption(),
_requestGroup, getRequestGroup(),
e->getCookieStorage(), getDownloadEngine()->getCookieStorage(),
e->getAuthConfigFactory(), getDownloadEngine()->getAuthConfigFactory(),
_proxyRequest)); _proxyRequest));
_httpConnection->sendRequest(httpRequest); _httpConnection->sendRequest(httpRequest);
} else { } else {
for(std::vector<SharedHandle<Segment> >::const_iterator itr = for(std::vector<SharedHandle<Segment> >::const_iterator itr =
_segments.begin(), eoi = _segments.end(); itr != eoi; ++itr) { getSegments().begin(), eoi = getSegments().end();
itr != eoi; ++itr) {
const SharedHandle<Segment>& segment = *itr; const SharedHandle<Segment>& segment = *itr;
if(!_httpConnection->isIssued(segment)) { if(!_httpConnection->isIssued(segment)) {
SharedHandle<HttpRequest> httpRequest SharedHandle<HttpRequest> httpRequest
(createHttpRequest(req, (createHttpRequest(getRequest(),
_fileEntry, getFileEntry(),
segment, segment,
_requestGroup->getTotalLength(), getRequestGroup()->getTotalLength(),
getOption(), getOption(),
_requestGroup, getRequestGroup(),
e->getCookieStorage(), getDownloadEngine()->getCookieStorage(),
e->getAuthConfigFactory(), getDownloadEngine()->getAuthConfigFactory(),
_proxyRequest)); _proxyRequest));
_httpConnection->sendRequest(httpRequest); _httpConnection->sendRequest(httpRequest);
} }
@ -165,15 +166,19 @@ bool HttpRequestCommand::executeInternal() {
_httpConnection->sendPendingData(); _httpConnection->sendPendingData();
} }
if(_httpConnection->sendBufferIsEmpty()) { if(_httpConnection->sendBufferIsEmpty()) {
Command* command = new HttpResponseCommand(getCuid(), req, _fileEntry, Command* command = new HttpResponseCommand(getCuid(),
_requestGroup, getRequest(),
_httpConnection, e, socket); getFileEntry(),
e->addCommand(command); getRequestGroup(),
_httpConnection,
getDownloadEngine(),
getSocket());
getDownloadEngine()->addCommand(command);
return true; return true;
} else { } else {
setReadCheckSocketIf(socket, socket->wantRead()); setReadCheckSocketIf(getSocket(), getSocket()->wantRead());
setWriteCheckSocketIf(socket, socket->wantWrite()); setWriteCheckSocketIf(getSocket(), getSocket()->wantWrite());
e->addCommand(this); getDownloadEngine()->addCommand(this);
return false; return false;
} }
} }

View File

@ -87,21 +87,21 @@ HttpResponseCommand::HttpResponseCommand
DownloadEngine* e, DownloadEngine* e,
const SocketHandle& s) const SocketHandle& s)
:AbstractCommand(cuid, req, fileEntry, requestGroup, e, s), :AbstractCommand(cuid, req, fileEntry, requestGroup, e, s),
httpConnection(httpConnection) _httpConnection(httpConnection)
{} {}
HttpResponseCommand::~HttpResponseCommand() {} HttpResponseCommand::~HttpResponseCommand() {}
bool HttpResponseCommand::executeInternal() bool HttpResponseCommand::executeInternal()
{ {
SharedHandle<HttpRequest> httpRequest = httpConnection->getFirstHttpRequest(); SharedHandle<HttpRequest> httpRequest =_httpConnection->getFirstHttpRequest();
SharedHandle<HttpResponse> httpResponse = httpConnection->receiveResponse(); SharedHandle<HttpResponse> httpResponse = _httpConnection->receiveResponse();
if(httpResponse.isNull()) { if(httpResponse.isNull()) {
// The server has not responded to our request yet. // The server has not responded to our request yet.
// For socket->wantRead() == true, setReadCheckSocket(socket) is already // For socket->wantRead() == true, setReadCheckSocket(socket) is already
// done in the constructor. // done in the constructor.
setWriteCheckSocketIf(socket, socket->wantWrite()); setWriteCheckSocketIf(getSocket(), getSocket()->wantWrite());
e->addCommand(this); getDownloadEngine()->addCommand(this);
return false; return false;
} }
// check HTTP status number // check HTTP status number
@ -112,39 +112,40 @@ bool HttpResponseCommand::executeInternal()
// Disable persistent connection if: // Disable persistent connection if:
// Connection: close is received or the remote server is not HTTP/1.1. // Connection: close is received or the remote server is not HTTP/1.1.
// We don't care whether non-HTTP/1.1 server returns Connection: keep-alive. // We don't care whether non-HTTP/1.1 server returns Connection: keep-alive.
req->supportsPersistentConnection getRequest()->supportsPersistentConnection
(httpResponse->supportsPersistentConnection()); (httpResponse->supportsPersistentConnection());
if(req->isPipeliningEnabled()) { if(getRequest()->isPipeliningEnabled()) {
req->setMaxPipelinedRequest getRequest()->setMaxPipelinedRequest
(getOption()->getAsInt(PREF_MAX_HTTP_PIPELINING)); (getOption()->getAsInt(PREF_MAX_HTTP_PIPELINING));
} }
if(httpResponse->getResponseStatus() >= HttpHeader::S300) { if(httpResponse->getResponseStatus() >= HttpHeader::S300) {
if(httpResponse->getResponseStatus() == HttpHeader::S404) { if(httpResponse->getResponseStatus() == HttpHeader::S404) {
_requestGroup->increaseAndValidateFileNotFoundCount(); getRequestGroup()->increaseAndValidateFileNotFoundCount();
} }
return skipResponseBody(httpResponse); return skipResponseBody(httpResponse);
} }
if(!_fileEntry->isSingleHostMultiConnectionEnabled()) { if(!getFileEntry()->isSingleHostMultiConnectionEnabled()) {
// TODO redirection should be considered here. We need to parse // TODO redirection should be considered here. We need to parse
// original URI to get hostname. // original URI to get hostname.
_fileEntry->removeURIWhoseHostnameIs(req->getHost()); getFileEntry()->removeURIWhoseHostnameIs(getRequest()->getHost());
} }
if(_requestGroup->getPieceStorage().isNull()) { if(getPieceStorage().isNull()) {
uint64_t totalLength = httpResponse->getEntityLength(); uint64_t totalLength = httpResponse->getEntityLength();
_fileEntry->setLength(totalLength); getFileEntry()->setLength(totalLength);
if(_fileEntry->getPath().empty()) { if(getFileEntry()->getPath().empty()) {
_fileEntry->setPath getFileEntry()->setPath
(util::applyDir (util::applyDir
(getDownloadContext()->getDir(), (getDownloadContext()->getDir(),
util::fixTaintedBasename(httpResponse->determinFilename()))); util::fixTaintedBasename(httpResponse->determinFilename())));
} }
_fileEntry->setContentType(httpResponse->getContentType()); getFileEntry()->setContentType(httpResponse->getContentType());
_requestGroup->preDownloadProcessing(); getRequestGroup()->preDownloadProcessing();
if(e->getRequestGroupMan()->isSameFileBeingDownloaded(_requestGroup)) { if(getDownloadEngine()->getRequestGroupMan()->
isSameFileBeingDownloaded(getRequestGroup())) {
throw DOWNLOAD_FAILURE_EXCEPTION throw DOWNLOAD_FAILURE_EXCEPTION
(StringFormat(EX_DUPLICATE_FILE_DOWNLOAD, (StringFormat(EX_DUPLICATE_FILE_DOWNLOAD,
_requestGroup->getFirstFilePath().c_str()).str()); getRequestGroup()->getFirstFilePath().c_str()).str());
} }
// update last modified time // update last modified time
updateLastModifiedTime(httpResponse->getLastModifiedTime()); updateLastModifiedTime(httpResponse->getLastModifiedTime());
@ -153,8 +154,8 @@ bool HttpResponseCommand::executeInternal()
// assume we can do segmented downloading // assume we can do segmented downloading
if(totalLength == 0 || shouldInflateContentEncoding(httpResponse)) { if(totalLength == 0 || shouldInflateContentEncoding(httpResponse)) {
// we ignore content-length when inflate is required // we ignore content-length when inflate is required
_fileEntry->setLength(0); getFileEntry()->setLength(0);
if(req->getMethod() == Request::METHOD_GET && if(getRequest()->getMethod() == Request::METHOD_GET &&
(totalLength != 0 || (totalLength != 0 ||
!httpResponse->getHttpHeader()->defined(HttpHeader::CONTENT_LENGTH))){ !httpResponse->getHttpHeader()->defined(HttpHeader::CONTENT_LENGTH))){
// DownloadContext::knowsTotalLength() == true only when // DownloadContext::knowsTotalLength() == true only when
@ -167,22 +168,22 @@ bool HttpResponseCommand::executeInternal()
} }
} else { } else {
// validate totalsize // validate totalsize
_requestGroup->validateTotalLength(_fileEntry->getLength(), getRequestGroup()->validateTotalLength(getFileEntry()->getLength(),
httpResponse->getEntityLength()); httpResponse->getEntityLength());
// update last modified time // update last modified time
updateLastModifiedTime(httpResponse->getLastModifiedTime()); updateLastModifiedTime(httpResponse->getLastModifiedTime());
if(_requestGroup->getTotalLength() == 0) { if(getRequestGroup()->getTotalLength() == 0) {
// Since total length is unknown, the file size in previously // Since total length is unknown, the file size in previously
// failed download could be larger than the size this time. // failed download could be larger than the size this time.
// Also we can't resume in this case too. So truncate the file // Also we can't resume in this case too. So truncate the file
// anyway. // anyway.
_requestGroup->getPieceStorage()->getDiskAdaptor()->truncate(0); getPieceStorage()->getDiskAdaptor()->truncate(0);
e->addCommand getDownloadEngine()->addCommand
(createHttpDownloadCommand(httpResponse, (createHttpDownloadCommand(httpResponse,
getTransferEncodingDecoder(httpResponse), getTransferEncodingDecoder(httpResponse),
getContentEncodingDecoder(httpResponse))); getContentEncodingDecoder(httpResponse)));
} else { } else {
e->addCommand(createHttpDownloadCommand getDownloadEngine()->addCommand(createHttpDownloadCommand
(httpResponse, getTransferEncodingDecoder(httpResponse))); (httpResponse, getTransferEncodingDecoder(httpResponse)));
} }
return true; return true;
@ -192,7 +193,7 @@ bool HttpResponseCommand::executeInternal()
void HttpResponseCommand::updateLastModifiedTime(const Time& lastModified) void HttpResponseCommand::updateLastModifiedTime(const Time& lastModified)
{ {
if(getOption()->getAsBool(PREF_REMOTE_TIME)) { if(getOption()->getAsBool(PREF_REMOTE_TIME)) {
_requestGroup->updateLastModifiedTime(lastModified); getRequestGroup()->updateLastModifiedTime(lastModified);
} }
} }
@ -215,12 +216,12 @@ bool HttpResponseCommand::handleDefaultEncoding
(const SharedHandle<HttpResponse>& httpResponse) (const SharedHandle<HttpResponse>& httpResponse)
{ {
SharedHandle<HttpRequest> httpRequest = httpResponse->getHttpRequest(); SharedHandle<HttpRequest> httpRequest = httpResponse->getHttpRequest();
_requestGroup->adjustFilename getRequestGroup()->adjustFilename
(SharedHandle<BtProgressInfoFile>(new DefaultBtProgressInfoFile (SharedHandle<BtProgressInfoFile>(new DefaultBtProgressInfoFile
(_requestGroup->getDownloadContext(), (getDownloadContext(),
SharedHandle<PieceStorage>(), SharedHandle<PieceStorage>(),
getOption().get()))); getOption().get())));
_requestGroup->initPieceStorage(); getRequestGroup()->initPieceStorage();
if(getOption()->getAsBool(PREF_DRY_RUN)) { if(getOption()->getAsBool(PREF_DRY_RUN)) {
onDryRunFileFound(); onDryRunFileFound();
@ -228,47 +229,44 @@ bool HttpResponseCommand::handleDefaultEncoding
} }
BtProgressInfoFileHandle infoFile BtProgressInfoFileHandle infoFile
(new DefaultBtProgressInfoFile(_requestGroup->getDownloadContext(), (new DefaultBtProgressInfoFile(getDownloadContext(),
_requestGroup->getPieceStorage(), getPieceStorage(),
getOption().get())); getOption().get()));
if(!infoFile->exists() && _requestGroup->downloadFinishedByFileLength()) { if(!infoFile->exists() && getRequestGroup()->downloadFinishedByFileLength()) {
_requestGroup->getPieceStorage()->markAllPiecesDone(); getPieceStorage()->markAllPiecesDone();
getLogger()->notice(MSG_DOWNLOAD_ALREADY_COMPLETED, getLogger()->notice(MSG_DOWNLOAD_ALREADY_COMPLETED,
util::itos(_requestGroup->getGID()).c_str(), util::itos(getRequestGroup()->getGID()).c_str(),
_requestGroup->getFirstFilePath().c_str()); getRequestGroup()->getFirstFilePath().c_str());
return true; return true;
} }
_requestGroup->loadAndOpenFile(infoFile); getRequestGroup()->loadAndOpenFile(infoFile);
File file(_requestGroup->getFirstFilePath()); File file(getRequestGroup()->getFirstFilePath());
// We have to make sure that command that has Request object must // We have to make sure that command that has Request object must
// have segment after PieceStorage is initialized. See // have segment after PieceStorage is initialized. See
// AbstractCommand::execute() // AbstractCommand::execute()
SharedHandle<Segment> segment = SharedHandle<Segment> segment = getSegmentMan()->getSegment(getCuid(), 0);
_requestGroup->getSegmentMan()->getSegment(getCuid(), 0);
// pipelining requires implicit range specified. But the request for // pipelining requires implicit range specified. But the request for
// this response most likely dones't contains range header. This means // this response most likely dones't contains range header. This means
// we can't continue to use this socket because server sends all entity // we can't continue to use this socket because server sends all entity
// body instead of a segment. // body instead of a segment.
// Therefore, we shutdown the socket here if pipelining is enabled. // Therefore, we shutdown the socket here if pipelining is enabled.
DownloadCommand* command = 0; DownloadCommand* command = 0;
if(req->getMethod() == Request::METHOD_GET && if(getRequest()->getMethod() == Request::METHOD_GET &&
!segment.isNull() && segment->getPositionToWrite() == 0 && !segment.isNull() && segment->getPositionToWrite() == 0 &&
!req->isPipeliningEnabled()) { !getRequest()->isPipeliningEnabled()) {
command = createHttpDownloadCommand command = createHttpDownloadCommand
(httpResponse, getTransferEncodingDecoder(httpResponse)); (httpResponse, getTransferEncodingDecoder(httpResponse));
} else { } else {
_requestGroup->getSegmentMan()->cancelSegment(getCuid()); getSegmentMan()->cancelSegment(getCuid());
_fileEntry->poolRequest(req); getFileEntry()->poolRequest(getRequest());
} }
// After command is passed to prepareForNextAction(), it is managed // After command is passed to prepareForNextAction(), it is managed
// by CheckIntegrityEntry. // by CheckIntegrityEntry.
prepareForNextAction(command); prepareForNextAction(command);
command = 0; command = 0;
if(req->getMethod() == Request::METHOD_HEAD) { if(getRequest()->getMethod() == Request::METHOD_HEAD) {
poolConnection(); poolConnection();
req->setMethod(Request::METHOD_GET); getRequest()->setMethod(Request::METHOD_GET);
} }
return true; return true;
} }
@ -314,47 +312,43 @@ bool HttpResponseCommand::handleOtherEncoding
SharedHandle<HttpRequest> httpRequest = httpResponse->getHttpRequest(); SharedHandle<HttpRequest> httpRequest = httpResponse->getHttpRequest();
if(getOption()->getAsBool(PREF_DRY_RUN)) { if(getOption()->getAsBool(PREF_DRY_RUN)) {
_requestGroup->initPieceStorage(); getRequestGroup()->initPieceStorage();
onDryRunFileFound(); onDryRunFileFound();
return true; return true;
} }
if(req->getMethod() == Request::METHOD_HEAD) { if(getRequest()->getMethod() == Request::METHOD_HEAD) {
poolConnection(); poolConnection();
req->setMethod(Request::METHOD_GET); getRequest()->setMethod(Request::METHOD_GET);
return prepareForRetry(0); return prepareForRetry(0);
} }
// For zero-length file, check existing file comparing its size // For zero-length file, check existing file comparing its size
if(_requestGroup->downloadFinishedByFileLength()) { if(getRequestGroup()->downloadFinishedByFileLength()) {
_requestGroup->initPieceStorage(); getRequestGroup()->initPieceStorage();
_requestGroup->getPieceStorage()->markAllPiecesDone(); getPieceStorage()->markAllPiecesDone();
getLogger()->notice(MSG_DOWNLOAD_ALREADY_COMPLETED, getLogger()->notice(MSG_DOWNLOAD_ALREADY_COMPLETED,
util::itos(_requestGroup->getGID()).c_str(), util::itos(getRequestGroup()->getGID()).c_str(),
_requestGroup->getFirstFilePath().c_str()); getRequestGroup()->getFirstFilePath().c_str());
poolConnection(); poolConnection();
return true; return true;
} }
_requestGroup->shouldCancelDownloadForSafety(); getRequestGroup()->shouldCancelDownloadForSafety();
_requestGroup->initPieceStorage(); getRequestGroup()->initPieceStorage();
getPieceStorage()->getDiskAdaptor()->initAndOpenFile();
_requestGroup->getPieceStorage()->getDiskAdaptor()->initAndOpenFile();
// In this context, knowsTotalLength() is true only when the file is // In this context, knowsTotalLength() is true only when the file is
// really zero-length. // really zero-length.
if(_requestGroup->getDownloadContext()->knowsTotalLength()) { if(getDownloadContext()->knowsTotalLength()) {
poolConnection(); poolConnection();
return true; return true;
} }
// We have to make sure that command that has Request object must // We have to make sure that command that has Request object must
// have segment after PieceStorage is initialized. See // have segment after PieceStorage is initialized. See
// AbstractCommand::execute() // AbstractCommand::execute()
_requestGroup->getSegmentMan()->getSegment(getCuid(), 0); getSegmentMan()->getSegment(getCuid(), 0);
e->addCommand getDownloadEngine()->addCommand
(createHttpDownloadCommand(httpResponse, (createHttpDownloadCommand(httpResponse,
getTransferEncodingDecoder(httpResponse), getTransferEncodingDecoder(httpResponse),
getContentEncodingDecoder(httpResponse))); getContentEncodingDecoder(httpResponse)));
@ -369,22 +363,23 @@ bool HttpResponseCommand::skipResponseBody
// thrown away. // thrown away.
HttpSkipResponseCommand* command = new HttpSkipResponseCommand HttpSkipResponseCommand* command = new HttpSkipResponseCommand
(getCuid(), req, _fileEntry, _requestGroup, httpConnection, httpResponse, (getCuid(), getRequest(), getFileEntry(), getRequestGroup(),
e, socket); _httpConnection, httpResponse,
getDownloadEngine(), getSocket());
command->setTransferEncodingDecoder(decoder); command->setTransferEncodingDecoder(decoder);
// If request method is HEAD or the response body is zero-length, // If request method is HEAD or the response body is zero-length,
// set command's status to real time so that avoid read check blocking // set command's status to real time so that avoid read check blocking
if(req->getMethod() == Request::METHOD_HEAD || if(getRequest()->getMethod() == Request::METHOD_HEAD ||
(httpResponse->getEntityLength() == 0 && (httpResponse->getEntityLength() == 0 &&
!httpResponse->isTransferEncodingSpecified())) { !httpResponse->isTransferEncodingSpecified())) {
command->setStatusRealtime(); command->setStatusRealtime();
// If entity length == 0, then socket read/write check must be disabled. // If entity length == 0, then socket read/write check must be disabled.
command->disableSocketCheck(); command->disableSocketCheck();
e->setNoWait(true); getDownloadEngine()->setNoWait(true);
} }
e->addCommand(command); getDownloadEngine()->addCommand(command);
return true; return true;
} }
@ -395,8 +390,10 @@ HttpDownloadCommand* HttpResponseCommand::createHttpDownloadCommand
{ {
HttpDownloadCommand* command = HttpDownloadCommand* command =
new HttpDownloadCommand(getCuid(), req, _fileEntry, _requestGroup, new HttpDownloadCommand(getCuid(), getRequest(), getFileEntry(),
httpResponse, httpConnection, e, socket); getRequestGroup(),
httpResponse, _httpConnection,
getDownloadEngine(), getSocket());
command->setStartupIdleTime(getOption()->getAsInt(PREF_STARTUP_IDLE_TIME)); command->setStartupIdleTime(getOption()->getAsInt(PREF_STARTUP_IDLE_TIME));
command->setLowestDownloadSpeedLimit command->setLowestDownloadSpeedLimit
(getOption()->getAsInt(PREF_LOWEST_SPEED_LIMIT)); (getOption()->getAsInt(PREF_LOWEST_SPEED_LIMIT));
@ -407,25 +404,26 @@ HttpDownloadCommand* HttpResponseCommand::createHttpDownloadCommand
// Since the compressed file's length are returned in the response header // Since the compressed file's length are returned in the response header
// and the decompressed file size is unknown at this point, disable file // and the decompressed file size is unknown at this point, disable file
// allocation here. // allocation here.
_requestGroup->setFileAllocationEnabled(false); getRequestGroup()->setFileAllocationEnabled(false);
} }
_requestGroup->getURISelector()->tuneDownloadCommand getRequestGroup()->getURISelector()->tuneDownloadCommand
(_fileEntry->getRemainingUris(), command); (getFileEntry()->getRemainingUris(), command);
return command; return command;
} }
void HttpResponseCommand::poolConnection() void HttpResponseCommand::poolConnection()
{ {
if(req->supportsPersistentConnection()) { if(getRequest()->supportsPersistentConnection()) {
e->poolSocket(req, createProxyRequest(), socket); getDownloadEngine()->poolSocket(getRequest(), createProxyRequest(),
getSocket());
} }
} }
void HttpResponseCommand::onDryRunFileFound() void HttpResponseCommand::onDryRunFileFound()
{ {
_requestGroup->getPieceStorage()->markAllPiecesDone(); getPieceStorage()->markAllPiecesDone();
poolConnection(); poolConnection();
} }

View File

@ -48,7 +48,7 @@ class SocketCore;
class HttpResponseCommand : public AbstractCommand { class HttpResponseCommand : public AbstractCommand {
private: private:
SharedHandle<HttpConnection> httpConnection; SharedHandle<HttpConnection> _httpConnection;
bool handleDefaultEncoding(const SharedHandle<HttpResponse>& httpResponse); bool handleDefaultEncoding(const SharedHandle<HttpResponse>& httpResponse);
bool handleOtherEncoding(const SharedHandle<HttpResponse>& httpResponse); bool handleOtherEncoding(const SharedHandle<HttpResponse>& httpResponse);

View File

@ -87,13 +87,13 @@ void HttpSkipResponseCommand::setTransferEncodingDecoder
bool HttpSkipResponseCommand::executeInternal() bool HttpSkipResponseCommand::executeInternal()
{ {
if(req->getMethod() == Request::METHOD_HEAD || if(getRequest()->getMethod() == Request::METHOD_HEAD ||
(_totalLength == 0 && _transferEncodingDecoder.isNull())) { (_totalLength == 0 && _transferEncodingDecoder.isNull())) {
// If request method is HEAD or content-length header is present and // If request method is HEAD or content-length header is present and
// it's value is 0, then pool socket for reuse. // it's value is 0, then pool socket for reuse.
// If content-length header is not present, then EOF is expected in the end. // If content-length header is not present, then EOF is expected in the end.
// In this case, the content is thrown away and socket cannot be pooled. // In this case, the content is thrown away and socket cannot be pooled.
if(req->getMethod() == Request::METHOD_HEAD || if(getRequest()->getMethod() == Request::METHOD_HEAD ||
_httpResponse->getHttpHeader()->defined(HttpHeader::CONTENT_LENGTH)) { _httpResponse->getHttpHeader()->defined(HttpHeader::CONTENT_LENGTH)) {
poolConnection(); poolConnection();
} }
@ -104,7 +104,7 @@ bool HttpSkipResponseCommand::executeInternal()
size_t bufSize = BUFSIZE; size_t bufSize = BUFSIZE;
try { try {
socket->readData(buf, bufSize); getSocket()->readData(buf, bufSize);
if(_transferEncodingDecoder.isNull()) { if(_transferEncodingDecoder.isNull()) {
_receivedBytes += bufSize; _receivedBytes += bufSize;
@ -114,7 +114,7 @@ bool HttpSkipResponseCommand::executeInternal()
_transferEncodingDecoder->decode(buf, bufSize); _transferEncodingDecoder->decode(buf, bufSize);
} }
if(_totalLength != 0 && bufSize == 0 && if(_totalLength != 0 && bufSize == 0 &&
!socket->wantRead() && !socket->wantWrite()) { !getSocket()->wantRead() && !getSocket()->wantWrite()) {
throw DL_RETRY_EX(EX_GOT_EOF); throw DL_RETRY_EX(EX_GOT_EOF);
} }
} catch(RecoverableException& e) { } catch(RecoverableException& e) {
@ -127,7 +127,7 @@ bool HttpSkipResponseCommand::executeInternal()
bool finished = false; bool finished = false;
if(_transferEncodingDecoder.isNull()) { if(_transferEncodingDecoder.isNull()) {
if(bufSize == 0) { if(bufSize == 0) {
if(!socket->wantRead() && !socket->wantWrite()) { if(!getSocket()->wantRead() && !getSocket()->wantWrite()) {
return processResponse(); return processResponse();
} }
} else { } else {
@ -140,16 +140,17 @@ bool HttpSkipResponseCommand::executeInternal()
poolConnection(); poolConnection();
return processResponse(); return processResponse();
} else { } else {
setWriteCheckSocketIf(socket, socket->wantWrite()); setWriteCheckSocketIf(getSocket(), getSocket()->wantWrite());
e->addCommand(this); getDownloadEngine()->addCommand(this);
return false; return false;
} }
} }
void HttpSkipResponseCommand::poolConnection() const void HttpSkipResponseCommand::poolConnection() const
{ {
if(req->supportsPersistentConnection()) { if(getRequest()->supportsPersistentConnection()) {
e->poolSocket(req, createProxyRequest(), socket); getDownloadEngine()->poolSocket
(getRequest(), createProxyRequest(), getSocket());
} }
} }
@ -159,7 +160,8 @@ bool HttpSkipResponseCommand::processResponse()
unsigned int rnum = unsigned int rnum =
_httpResponse->getHttpRequest()->getRequest()->getRedirectCount(); _httpResponse->getHttpRequest()->getRequest()->getRedirectCount();
if(rnum >= Request::MAX_REDIRECT) { if(rnum >= Request::MAX_REDIRECT) {
throw DL_ABORT_EX(StringFormat("Too many redirects: count=%u", rnum).str()); throw DL_ABORT_EX
(StringFormat("Too many redirects: count=%u", rnum).str());
} }
_httpResponse->processRedirect(); _httpResponse->processRedirect();
return prepareForRetry(0); return prepareForRetry(0);
@ -167,8 +169,8 @@ bool HttpSkipResponseCommand::processResponse()
if(_httpResponse->getResponseStatus() == HttpHeader::S401) { if(_httpResponse->getResponseStatus() == HttpHeader::S401) {
if(getOption()->getAsBool(PREF_HTTP_AUTH_CHALLENGE) && if(getOption()->getAsBool(PREF_HTTP_AUTH_CHALLENGE) &&
!_httpResponse->getHttpRequest()->authenticationUsed() && !_httpResponse->getHttpRequest()->authenticationUsed() &&
e->getAuthConfigFactory()->activateBasicCred getDownloadEngine()->getAuthConfigFactory()->activateBasicCred
(req->getHost(), req->getDir(), getOption().get())) { (getRequest()->getHost(), getRequest()->getDir(), getOption().get())) {
return prepareForRetry(0); return prepareForRetry(0);
} else { } else {
throw DL_ABORT_EX(EX_AUTH_FAILED); throw DL_ABORT_EX(EX_AUTH_FAILED);
@ -177,7 +179,10 @@ bool HttpSkipResponseCommand::processResponse()
throw DL_ABORT_EX2(MSG_RESOURCE_NOT_FOUND, throw DL_ABORT_EX2(MSG_RESOURCE_NOT_FOUND,
downloadresultcode::RESOURCE_NOT_FOUND); downloadresultcode::RESOURCE_NOT_FOUND);
} else { } else {
throw DL_ABORT_EX(StringFormat(EX_BAD_STATUS, util::parseUInt(_httpResponse->getResponseStatus())).str()); throw DL_ABORT_EX
(StringFormat
(EX_BAD_STATUS,
util::parseUInt(_httpResponse->getResponseStatus())).str());
} }
} else { } else {
return prepareForRetry(0); return prepareForRetry(0);

View File

@ -77,8 +77,8 @@ bool InitiateConnectionCommand::executeInternal() {
uint16_t port; uint16_t port;
SharedHandle<Request> proxyRequest = createProxyRequest(); SharedHandle<Request> proxyRequest = createProxyRequest();
if(proxyRequest.isNull()) { if(proxyRequest.isNull()) {
hostname = req->getHost(); hostname = getRequest()->getHost();
port = req->getPort(); port = getRequest()->getPort();
} else { } else {
hostname = proxyRequest->getHost(); hostname = proxyRequest->getHost();
port = proxyRequest->getPort(); port = proxyRequest->getPort();
@ -86,21 +86,21 @@ bool InitiateConnectionCommand::executeInternal() {
std::vector<std::string> addrs; std::vector<std::string> addrs;
std::string ipaddr = resolveHostname(addrs, hostname, port); std::string ipaddr = resolveHostname(addrs, hostname, port);
if(ipaddr.empty()) { if(ipaddr.empty()) {
e->addCommand(this); getDownloadEngine()->addCommand(this);
return false; return false;
} }
try { try {
Command* command = createNextCommand(hostname, ipaddr, port, Command* command = createNextCommand(hostname, ipaddr, port,
addrs, proxyRequest); addrs, proxyRequest);
e->addCommand(command); getDownloadEngine()->addCommand(command);
return true; return true;
} catch(RecoverableException& ex) { } catch(RecoverableException& ex) {
// Catch exception and retry another address. // Catch exception and retry another address.
// See also AbstractCommand::checkIfConnectionEstablished // See also AbstractCommand::checkIfConnectionEstablished
// TODO ipaddr might not be used if pooled sockt was found. // TODO ipaddr might not be used if pooled sockt was found.
e->markBadIPAddress(hostname, ipaddr, port); getDownloadEngine()->markBadIPAddress(hostname, ipaddr, port);
if(!e->findCachedIPAddress(hostname, port).empty()) { if(!getDownloadEngine()->findCachedIPAddress(hostname, port).empty()) {
if(getLogger()->info()) { if(getLogger()->info()) {
getLogger()->info(EX_EXCEPTION_CAUGHT, ex); getLogger()->info(EX_EXCEPTION_CAUGHT, ex);
getLogger()->info(MSG_CONNECT_FAILED_AND_RETRY, getLogger()->info(MSG_CONNECT_FAILED_AND_RETRY,
@ -108,12 +108,13 @@ bool InitiateConnectionCommand::executeInternal() {
} }
Command* command = Command* command =
InitiateConnectionCommandFactory::createInitiateConnectionCommand InitiateConnectionCommandFactory::createInitiateConnectionCommand
(getCuid(), req, _fileEntry, _requestGroup, e); (getCuid(), getRequest(), getFileEntry(), getRequestGroup(),
e->setNoWait(true); getDownloadEngine());
e->addCommand(command); getDownloadEngine()->setNoWait(true);
getDownloadEngine()->addCommand(command);
return true; return true;
} }
e->removeCachedIPAddress(hostname, port); getDownloadEngine()->removeCachedIPAddress(hostname, port);
throw; throw;
} }
} }