mirror of
https://github.com/aria2/aria2.git
synced 2024-12-14 09:28:55 +00:00
2008-09-08 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
Implemented the ability to get timestamp from remote FTP server using MDTM command described in RFC3659. * src/FtpConnection.cc * src/FtpConnection.h * src/FtpNegotiationCommand.cc * src/FtpNegotiationCommand.h * test/FtpConnectionTest.cc * test/Makefile.am
This commit is contained in:
parent
dbc8f5b737
commit
eb652b570e
11
ChangeLog
11
ChangeLog
@ -1,3 +1,14 @@
|
|||||||
|
2008-09-08 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
|
||||||
|
|
||||||
|
Implemented the ability to get timestamp from remote FTP server using
|
||||||
|
MDTM command described in RFC3659.
|
||||||
|
* src/FtpConnection.cc
|
||||||
|
* src/FtpConnection.h
|
||||||
|
* src/FtpNegotiationCommand.cc
|
||||||
|
* src/FtpNegotiationCommand.h
|
||||||
|
* test/FtpConnectionTest.cc
|
||||||
|
* test/Makefile.am
|
||||||
|
|
||||||
2008-09-07 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
|
2008-09-07 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
|
||||||
|
|
||||||
Implemented the ability to get timestamp from remote HTTP server and
|
Implemented the ability to get timestamp from remote HTTP server and
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
#include "DlAbortEx.h"
|
#include "DlAbortEx.h"
|
||||||
#include "Socket.h"
|
#include "Socket.h"
|
||||||
#include "A2STR.h"
|
#include "A2STR.h"
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
@ -95,6 +96,13 @@ void FtpConnection::sendCwd() const
|
|||||||
socket->writeData(request);
|
socket->writeData(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FtpConnection::sendMdtm() const
|
||||||
|
{
|
||||||
|
std::string request = "MDTM "+Util::urlencode(req->getFile())+"\r\n";
|
||||||
|
logger->info(MSG_SENDING_REQUEST, cuid, request.c_str());
|
||||||
|
socket->writeData(request);
|
||||||
|
}
|
||||||
|
|
||||||
void FtpConnection::sendSize() const
|
void FtpConnection::sendSize() const
|
||||||
{
|
{
|
||||||
std::string request = "SIZE "+Util::urldecode(req->getFile())+"\r\n";
|
std::string request = "SIZE "+Util::urldecode(req->getFile())+"\r\n";
|
||||||
@ -257,6 +265,26 @@ unsigned int FtpConnection::receiveSizeResponse(uint64_t& size)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int FtpConnection::receiveMdtmResponse(Time& time)
|
||||||
|
{
|
||||||
|
// MDTM command, specified in RFC3659.
|
||||||
|
std::pair<unsigned int, std::string> response;
|
||||||
|
if(bulkReceiveResponse(response)) {
|
||||||
|
if(response.first == 213) {
|
||||||
|
char buf[15]; // YYYYMMDDhhmmss+\0, milli second part is dropped.
|
||||||
|
sscanf(response.second.c_str(), "%*u %14s", buf);
|
||||||
|
if(strlen(buf) == 14) {
|
||||||
|
time = Time::parse(buf, "%Y%m%d%H%M%S");
|
||||||
|
} else {
|
||||||
|
time.setTimeInSec(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return response.first;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int FtpConnection::receivePasvResponse(std::pair<std::string, uint16_t>& dest)
|
unsigned int FtpConnection::receivePasvResponse(std::pair<std::string, uint16_t>& dest)
|
||||||
{
|
{
|
||||||
std::pair<unsigned int, std::string> response;
|
std::pair<unsigned int, std::string> response;
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "SharedHandle.h"
|
#include "SharedHandle.h"
|
||||||
|
#include "TimeA2.h"
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@ -74,6 +75,7 @@ public:
|
|||||||
void sendPass() const;
|
void sendPass() const;
|
||||||
void sendType() const;
|
void sendType() const;
|
||||||
void sendCwd() const;
|
void sendCwd() const;
|
||||||
|
void sendMdtm() const;
|
||||||
void sendSize() const;
|
void sendSize() const;
|
||||||
void sendPasv() const;
|
void sendPasv() const;
|
||||||
SharedHandle<SocketCore> sendPort() const;
|
SharedHandle<SocketCore> sendPort() const;
|
||||||
@ -82,6 +84,13 @@ public:
|
|||||||
|
|
||||||
unsigned int receiveResponse();
|
unsigned int receiveResponse();
|
||||||
unsigned int receiveSizeResponse(uint64_t& size);
|
unsigned int receiveSizeResponse(uint64_t& size);
|
||||||
|
// Returns status code of MDTM reply. If the status code is 213, parses
|
||||||
|
// time-val and store it in time.
|
||||||
|
// If a code other than 213 is returned, time is not touched.
|
||||||
|
// Expect MDTM reply is YYYYMMDDhhmmss in GMT. If status is 213 but returned
|
||||||
|
// date cannot be parsed, then executes time.setTimeInSec(-1).
|
||||||
|
// If reply is not received yet, returns 0.
|
||||||
|
unsigned int receiveMdtmResponse(Time& time);
|
||||||
unsigned int receivePasvResponse(std::pair<std::string, uint16_t>& dest);
|
unsigned int receivePasvResponse(std::pair<std::string, uint16_t>& dest);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -202,6 +202,45 @@ bool FtpNegotiationCommand::recvCwd() {
|
|||||||
poolConnection();
|
poolConnection();
|
||||||
throw DlAbortEx(StringFormat(EX_BAD_STATUS, status).str());
|
throw DlAbortEx(StringFormat(EX_BAD_STATUS, status).str());
|
||||||
}
|
}
|
||||||
|
if(e->option->getAsBool(PREF_REMOTE_TIME)) {
|
||||||
|
sequence = SEQ_SEND_MDTM;
|
||||||
|
} else {
|
||||||
|
sequence = SEQ_SEND_SIZE;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FtpNegotiationCommand::sendMdtm()
|
||||||
|
{
|
||||||
|
ftp->sendMdtm();
|
||||||
|
sequence = SEQ_RECV_MDTM;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FtpNegotiationCommand::recvMdtm()
|
||||||
|
{
|
||||||
|
Time lastModifiedTime(-1);
|
||||||
|
unsigned int status = ftp->receiveMdtmResponse(lastModifiedTime);
|
||||||
|
if(status == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(status == 213) {
|
||||||
|
if(lastModifiedTime.good()) {
|
||||||
|
_requestGroup->updateLastModifiedTime(lastModifiedTime);
|
||||||
|
time_t t = lastModifiedTime.getTime();
|
||||||
|
struct tm* tms = gmtime(&t); // returned struct is statically allocated.
|
||||||
|
if(tms) {
|
||||||
|
logger->debug("MDTM result was parsed as: %s GMT", asctime(tms));
|
||||||
|
} else {
|
||||||
|
logger->debug("gmtime() failed for MDTM result.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger->debug("MDTM response was returned, but it seems not to be a time"
|
||||||
|
" value as in specified in RFC3659.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger->info("CUID#%d - MDTM command failed.", cuid);
|
||||||
|
}
|
||||||
sequence = SEQ_SEND_SIZE;
|
sequence = SEQ_SEND_SIZE;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -445,6 +484,10 @@ bool FtpNegotiationCommand::processSequence(const SegmentHandle& segment) {
|
|||||||
return sendCwd();
|
return sendCwd();
|
||||||
case SEQ_RECV_CWD:
|
case SEQ_RECV_CWD:
|
||||||
return recvCwd();
|
return recvCwd();
|
||||||
|
case SEQ_SEND_MDTM:
|
||||||
|
return sendMdtm();
|
||||||
|
case SEQ_RECV_MDTM:
|
||||||
|
return recvMdtm();
|
||||||
case SEQ_SEND_SIZE:
|
case SEQ_SEND_SIZE:
|
||||||
return sendSize();
|
return sendSize();
|
||||||
case SEQ_RECV_SIZE:
|
case SEQ_RECV_SIZE:
|
||||||
|
@ -54,6 +54,8 @@ public:
|
|||||||
SEQ_RECV_TYPE,
|
SEQ_RECV_TYPE,
|
||||||
SEQ_SEND_CWD,
|
SEQ_SEND_CWD,
|
||||||
SEQ_RECV_CWD,
|
SEQ_RECV_CWD,
|
||||||
|
SEQ_SEND_MDTM,
|
||||||
|
SEQ_RECV_MDTM,
|
||||||
SEQ_SEND_SIZE,
|
SEQ_SEND_SIZE,
|
||||||
SEQ_RECV_SIZE,
|
SEQ_RECV_SIZE,
|
||||||
SEQ_SEND_PORT,
|
SEQ_SEND_PORT,
|
||||||
@ -82,6 +84,8 @@ private:
|
|||||||
bool recvType();
|
bool recvType();
|
||||||
bool sendCwd();
|
bool sendCwd();
|
||||||
bool recvCwd();
|
bool recvCwd();
|
||||||
|
bool sendMdtm();
|
||||||
|
bool recvMdtm();
|
||||||
bool sendSize();
|
bool sendSize();
|
||||||
bool recvSize();
|
bool recvSize();
|
||||||
bool sendPort();
|
bool sendPort();
|
||||||
|
105
test/FtpConnectionTest.cc
Normal file
105
test/FtpConnectionTest.cc
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#include "FtpConnection.h"
|
||||||
|
#include "Exception.h"
|
||||||
|
#include "Util.h"
|
||||||
|
#include "SocketCore.h"
|
||||||
|
#include "Request.h"
|
||||||
|
#include "Option.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <cppunit/extensions/HelperMacros.h>
|
||||||
|
|
||||||
|
namespace aria2 {
|
||||||
|
|
||||||
|
class FtpConnectionTest:public CppUnit::TestFixture {
|
||||||
|
|
||||||
|
CPPUNIT_TEST_SUITE(FtpConnectionTest);
|
||||||
|
CPPUNIT_TEST(testSendMdtm);
|
||||||
|
CPPUNIT_TEST(testReceiveMdtmResponse);
|
||||||
|
CPPUNIT_TEST_SUITE_END();
|
||||||
|
private:
|
||||||
|
SharedHandle<SocketCore> _serverSocket;
|
||||||
|
uint16_t _listenPort;
|
||||||
|
SharedHandle<FtpConnection> _ftp;
|
||||||
|
Option _option;
|
||||||
|
public:
|
||||||
|
void setUp()
|
||||||
|
{
|
||||||
|
//_ftpServerSocket.reset(new SocketCore());
|
||||||
|
SharedHandle<SocketCore> listenSocket(new SocketCore());
|
||||||
|
listenSocket->bind(0);
|
||||||
|
listenSocket->beginListen();
|
||||||
|
std::pair<std::string, uint16_t> addrinfo;
|
||||||
|
listenSocket->getAddrInfo(addrinfo);
|
||||||
|
_listenPort = addrinfo.second;
|
||||||
|
|
||||||
|
SharedHandle<Request> req(new Request());
|
||||||
|
req->setUrl("ftp://localhost/dir/file.img");
|
||||||
|
|
||||||
|
SharedHandle<SocketCore> clientSocket(new SocketCore());
|
||||||
|
clientSocket->establishConnection("127.0.0.1", _listenPort);
|
||||||
|
|
||||||
|
while(!clientSocket->isWritable(0));
|
||||||
|
clientSocket->setBlockingMode();
|
||||||
|
|
||||||
|
_serverSocket.reset(listenSocket->acceptConnection());
|
||||||
|
_ftp.reset(new FtpConnection(1, clientSocket, req, &_option));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tearDown() {}
|
||||||
|
|
||||||
|
void testSendMdtm();
|
||||||
|
void testReceiveMdtmResponse();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
CPPUNIT_TEST_SUITE_REGISTRATION(FtpConnectionTest);
|
||||||
|
|
||||||
|
void FtpConnectionTest::testSendMdtm()
|
||||||
|
{
|
||||||
|
_ftp->sendMdtm();
|
||||||
|
char data[32];
|
||||||
|
size_t len = sizeof(data);
|
||||||
|
_serverSocket->readData(data, len);
|
||||||
|
CPPUNIT_ASSERT_EQUAL((size_t)15, len);
|
||||||
|
data[len] = '\0';
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("MDTM file.img\r\n"), std::string(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
void FtpConnectionTest::testReceiveMdtmResponse()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
Time t;
|
||||||
|
_serverSocket->writeData("213 20080908124312");
|
||||||
|
CPPUNIT_ASSERT_EQUAL((unsigned int)0, _ftp->receiveMdtmResponse(t));
|
||||||
|
_serverSocket->writeData("\r\n");
|
||||||
|
CPPUNIT_ASSERT_EQUAL((unsigned int)213, _ftp->receiveMdtmResponse(t));
|
||||||
|
CPPUNIT_ASSERT_EQUAL((time_t)1220877792, t.getTime());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// see milli second part is ignored
|
||||||
|
Time t;
|
||||||
|
_serverSocket->writeData("213 20080908124312.014\r\n");
|
||||||
|
CPPUNIT_ASSERT_EQUAL((unsigned int)213, _ftp->receiveMdtmResponse(t));
|
||||||
|
CPPUNIT_ASSERT_EQUAL((time_t)1220877792, t.getTime());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// hhmmss part is missing
|
||||||
|
Time t;
|
||||||
|
_serverSocket->writeData("213 20080908\r\n");
|
||||||
|
CPPUNIT_ASSERT_EQUAL((unsigned int)213, _ftp->receiveMdtmResponse(t));
|
||||||
|
CPPUNIT_ASSERT_EQUAL((time_t)-1, t.getTime());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// invalid month: 19
|
||||||
|
Time t;
|
||||||
|
_serverSocket->writeData("213 20081908124312\r\n");
|
||||||
|
CPPUNIT_ASSERT_EQUAL((unsigned int)213, _ftp->receiveMdtmResponse(t));
|
||||||
|
CPPUNIT_ASSERT_EQUAL((time_t)-1, t.getTime());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Time t;
|
||||||
|
_serverSocket->writeData("550 File Not Found\r\n");
|
||||||
|
CPPUNIT_ASSERT_EQUAL((unsigned int)550, _ftp->receiveMdtmResponse(t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace aria2
|
@ -62,7 +62,8 @@ aria2c_SOURCES = AllTest.cc\
|
|||||||
CookieTest.cc\
|
CookieTest.cc\
|
||||||
CookieStorageTest.cc\
|
CookieStorageTest.cc\
|
||||||
TimeTest.cc\
|
TimeTest.cc\
|
||||||
CopyDiskAdaptorTest.cc
|
CopyDiskAdaptorTest.cc\
|
||||||
|
FtpConnectionTest.cc
|
||||||
|
|
||||||
if HAVE_LIBZ
|
if HAVE_LIBZ
|
||||||
aria2c_SOURCES += GZipDecoderTest.cc
|
aria2c_SOURCES += GZipDecoderTest.cc
|
||||||
|
@ -194,8 +194,9 @@ am__aria2c_SOURCES_DIST = AllTest.cc TestUtil.cc TestUtil.h \
|
|||||||
ServerStatURISelectorTest.cc InOrderURISelectorTest.cc \
|
ServerStatURISelectorTest.cc InOrderURISelectorTest.cc \
|
||||||
ServerStatTest.cc NsCookieParserTest.cc \
|
ServerStatTest.cc NsCookieParserTest.cc \
|
||||||
DirectDiskAdaptorTest.cc CookieTest.cc CookieStorageTest.cc \
|
DirectDiskAdaptorTest.cc CookieTest.cc CookieStorageTest.cc \
|
||||||
TimeTest.cc CopyDiskAdaptorTest.cc GZipDecoderTest.cc \
|
TimeTest.cc CopyDiskAdaptorTest.cc FtpConnectionTest.cc \
|
||||||
Sqlite3MozCookieParserTest.cc MessageDigestHelperTest.cc \
|
GZipDecoderTest.cc Sqlite3MozCookieParserTest.cc \
|
||||||
|
MessageDigestHelperTest.cc \
|
||||||
IteratableChunkChecksumValidatorTest.cc \
|
IteratableChunkChecksumValidatorTest.cc \
|
||||||
IteratableChecksumValidatorTest.cc BtAllowedFastMessageTest.cc \
|
IteratableChecksumValidatorTest.cc BtAllowedFastMessageTest.cc \
|
||||||
BtBitfieldMessageTest.cc BtCancelMessageTest.cc \
|
BtBitfieldMessageTest.cc BtCancelMessageTest.cc \
|
||||||
@ -367,8 +368,8 @@ am_aria2c_OBJECTS = AllTest.$(OBJEXT) TestUtil.$(OBJEXT) \
|
|||||||
NsCookieParserTest.$(OBJEXT) DirectDiskAdaptorTest.$(OBJEXT) \
|
NsCookieParserTest.$(OBJEXT) DirectDiskAdaptorTest.$(OBJEXT) \
|
||||||
CookieTest.$(OBJEXT) CookieStorageTest.$(OBJEXT) \
|
CookieTest.$(OBJEXT) CookieStorageTest.$(OBJEXT) \
|
||||||
TimeTest.$(OBJEXT) CopyDiskAdaptorTest.$(OBJEXT) \
|
TimeTest.$(OBJEXT) CopyDiskAdaptorTest.$(OBJEXT) \
|
||||||
$(am__objects_1) $(am__objects_2) $(am__objects_3) \
|
FtpConnectionTest.$(OBJEXT) $(am__objects_1) $(am__objects_2) \
|
||||||
$(am__objects_4) $(am__objects_5)
|
$(am__objects_3) $(am__objects_4) $(am__objects_5)
|
||||||
aria2c_OBJECTS = $(am_aria2c_OBJECTS)
|
aria2c_OBJECTS = $(am_aria2c_OBJECTS)
|
||||||
am__DEPENDENCIES_1 =
|
am__DEPENDENCIES_1 =
|
||||||
aria2c_DEPENDENCIES = ../src/libaria2c.a $(am__DEPENDENCIES_1)
|
aria2c_DEPENDENCIES = ../src/libaria2c.a $(am__DEPENDENCIES_1)
|
||||||
@ -590,9 +591,9 @@ aria2c_SOURCES = AllTest.cc TestUtil.cc TestUtil.h SocketCoreTest.cc \
|
|||||||
ServerStatURISelectorTest.cc InOrderURISelectorTest.cc \
|
ServerStatURISelectorTest.cc InOrderURISelectorTest.cc \
|
||||||
ServerStatTest.cc NsCookieParserTest.cc \
|
ServerStatTest.cc NsCookieParserTest.cc \
|
||||||
DirectDiskAdaptorTest.cc CookieTest.cc CookieStorageTest.cc \
|
DirectDiskAdaptorTest.cc CookieTest.cc CookieStorageTest.cc \
|
||||||
TimeTest.cc CopyDiskAdaptorTest.cc $(am__append_1) \
|
TimeTest.cc CopyDiskAdaptorTest.cc FtpConnectionTest.cc \
|
||||||
$(am__append_2) $(am__append_3) $(am__append_4) \
|
$(am__append_1) $(am__append_2) $(am__append_3) \
|
||||||
$(am__append_5)
|
$(am__append_4) $(am__append_5)
|
||||||
|
|
||||||
#aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64
|
#aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64
|
||||||
#aria2c_LDFLAGS = ${CPPUNIT_LIBS}
|
#aria2c_LDFLAGS = ${CPPUNIT_LIBS}
|
||||||
@ -759,6 +760,7 @@ distclean-compile:
|
|||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FeatureConfigTest.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FeatureConfigTest.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileEntryTest.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileEntryTest.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileTest.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileTest.Po@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FtpConnectionTest.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GZipDecoderTest.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GZipDecoderTest.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GrowSegmentTest.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GrowSegmentTest.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HandshakeExtensionMessageTest.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HandshakeExtensionMessageTest.Po@am__quote@
|
||||||
|
Loading…
Reference in New Issue
Block a user