Browse Source

2010-05-21 Tatsuhiro Tsujikawa <[email protected]>

	Fixed the bug that FTP download may fail when control connection
	is reused. This happens because FTP server can offer different
	root directory for different account. If pooled connections has
	different root directory, then download will fail.
	* src/DownloadEngine.cc
	* src/DownloadEngine.h
	* src/FtpConnection.cc
	* src/FtpConnection.h
	* src/FtpFinishDownloadCommand.cc
	* src/FtpInitiateConnectionCommand.cc
	* src/FtpNegotiationCommand.cc
Tatsuhiro Tsujikawa 15 years ago
parent
commit
47adbe618c

+ 14 - 0
ChangeLog

@@ -1,3 +1,17 @@
+2010-05-21  Tatsuhiro Tsujikawa  <[email protected]>
+
+	Fixed the bug that FTP download may fail when control connection
+	is reused. This happens because FTP server can offer different
+	root directory for different account. If pooled connections has
+	different root directory, then download will fail.
+	* src/DownloadEngine.cc
+	* src/DownloadEngine.h
+	* src/FtpConnection.cc
+	* src/FtpConnection.h
+	* src/FtpFinishDownloadCommand.cc
+	* src/FtpInitiateConnectionCommand.cc
+	* src/FtpNegotiationCommand.cc
+
 2010-05-20  Tatsuhiro Tsujikawa  <[email protected]>
 2010-05-20  Tatsuhiro Tsujikawa  <[email protected]>
 
 
 	Removed DownloadResult's ctor because it has many args.
 	Removed DownloadResult's ctor because it has many args.

+ 31 - 10
src/DownloadEngine.cc

@@ -309,15 +309,26 @@ void DownloadEngine::poolSocket(const std::string& ipaddr,
   }
   }
 }
 }
 
 
+static std::string createSockPoolKey
+(const std::string& host, const std::string& username)
+{
+  std::string key;
+  key += util::percentEncode(username);
+  key += '@';
+  key += host;
+  return key;
+}
+
 void DownloadEngine::poolSocket
 void DownloadEngine::poolSocket
 (const std::string& ipaddr,
 (const std::string& ipaddr,
  uint16_t port,
  uint16_t port,
+ const std::string& username,
  const SharedHandle<SocketCore>& sock,
  const SharedHandle<SocketCore>& sock,
  const std::map<std::string, std::string>& options,
  const std::map<std::string, std::string>& options,
  time_t timeout)
  time_t timeout)
 {
 {
   SocketPoolEntry e(sock, options, timeout);
   SocketPoolEntry e(sock, options, timeout);
-  poolSocket(ipaddr, port, e);
+  poolSocket(createSockPoolKey(ipaddr, username), port, e);
 }
 }
 
 
 void DownloadEngine::poolSocket
 void DownloadEngine::poolSocket
@@ -326,7 +337,7 @@ void DownloadEngine::poolSocket
  const SharedHandle<SocketCore>& sock,
  const SharedHandle<SocketCore>& sock,
  time_t timeout)
  time_t timeout)
 {
 {
-  SocketPoolEntry e(sock, std::map<std::string, std::string>(), timeout);
+  SocketPoolEntry e(sock, timeout);
   poolSocket(ipaddr, port, e);
   poolSocket(ipaddr, port, e);
 }
 }
 
 
@@ -337,28 +348,31 @@ void DownloadEngine::poolSocket(const SharedHandle<Request>& request,
 {
 {
   if(proxyDefined) {
   if(proxyDefined) {
     // If proxy is defined, then pool socket with its hostname.
     // If proxy is defined, then pool socket with its hostname.
-    poolSocket(request->getHost(), request->getPort(), socket);
+    poolSocket(request->getHost(), request->getPort(), socket, timeout);
   } else {
   } else {
     std::pair<std::string, uint16_t> peerInfo;
     std::pair<std::string, uint16_t> peerInfo;
     socket->getPeerInfo(peerInfo);
     socket->getPeerInfo(peerInfo);
-    poolSocket(peerInfo.first, peerInfo.second, socket);
+    poolSocket(peerInfo.first, peerInfo.second, socket, timeout);
   }
   }
 }
 }
 
 
 void DownloadEngine::poolSocket
 void DownloadEngine::poolSocket
 (const SharedHandle<Request>& request,
 (const SharedHandle<Request>& request,
  bool proxyDefined,
  bool proxyDefined,
+ const std::string& username,
  const SharedHandle<SocketCore>& socket,
  const SharedHandle<SocketCore>& socket,
  const std::map<std::string, std::string>& options,                             
  const std::map<std::string, std::string>& options,                             
  time_t timeout)
  time_t timeout)
 {
 {
   if(proxyDefined) {
   if(proxyDefined) {
     // If proxy is defined, then pool socket with its hostname.
     // If proxy is defined, then pool socket with its hostname.
-    poolSocket(request->getHost(), request->getPort(), socket, options);
+    poolSocket(request->getHost(), request->getPort(), username,
+               socket, options, timeout);
   } else {
   } else {
     std::pair<std::string, uint16_t> peerInfo;
     std::pair<std::string, uint16_t> peerInfo;
     socket->getPeerInfo(peerInfo);
     socket->getPeerInfo(peerInfo);
-    poolSocket(peerInfo.first, peerInfo.second, socket, options);
+    poolSocket(peerInfo.first, peerInfo.second, username,
+               socket, options, timeout);
   }
   }
 }
 }
 
 
@@ -396,11 +410,12 @@ DownloadEngine::popPooledSocket(const std::string& ipaddr, uint16_t port)
 
 
 SharedHandle<SocketCore>
 SharedHandle<SocketCore>
 DownloadEngine::popPooledSocket(std::map<std::string, std::string>& options,
 DownloadEngine::popPooledSocket(std::map<std::string, std::string>& options,
-                                const std::string& ipaddr, uint16_t port)
+                                const std::string& ipaddr, uint16_t port,
+                                const std::string& username)
 {
 {
   SharedHandle<SocketCore> s;
   SharedHandle<SocketCore> s;
   std::multimap<std::string, SocketPoolEntry>::iterator i =
   std::multimap<std::string, SocketPoolEntry>::iterator i =
-    findSocketPoolEntry(ipaddr, port);
+    findSocketPoolEntry(createSockPoolKey(ipaddr, username), port);
   if(i != _socketPool.end()) {
   if(i != _socketPool.end()) {
     s = (*i).second.getSocket();
     s = (*i).second.getSocket();
     options = (*i).second.getOptions();
     options = (*i).second.getOptions();
@@ -427,12 +442,13 @@ DownloadEngine::popPooledSocket
 SharedHandle<SocketCore>
 SharedHandle<SocketCore>
 DownloadEngine::popPooledSocket
 DownloadEngine::popPooledSocket
 (std::map<std::string, std::string>& options,
 (std::map<std::string, std::string>& options,
- const std::vector<std::string>& ipaddrs, uint16_t port)
+ const std::vector<std::string>& ipaddrs, uint16_t port,
+ const std::string& username)
 {
 {
   SharedHandle<SocketCore> s;
   SharedHandle<SocketCore> s;
   for(std::vector<std::string>::const_iterator i = ipaddrs.begin(),
   for(std::vector<std::string>::const_iterator i = ipaddrs.begin(),
         eoi = ipaddrs.end(); i != eoi; ++i) {
         eoi = ipaddrs.end(); i != eoi; ++i) {
-    s = popPooledSocket(options, *i, port);
+    s = popPooledSocket(options, *i, port, username);
     if(!s.isNull()) {
     if(!s.isNull()) {
       break;
       break;
     }
     }
@@ -448,6 +464,11 @@ DownloadEngine::SocketPoolEntry::SocketPoolEntry
   _options(options),
   _options(options),
   _timeout(timeout) {}
   _timeout(timeout) {}
 
 
+DownloadEngine::SocketPoolEntry::SocketPoolEntry
+(const SharedHandle<SocketCore>& socket, time_t timeout):
+  _socket(socket),
+  _timeout(timeout) {}
+
 DownloadEngine::SocketPoolEntry::~SocketPoolEntry() {}
 DownloadEngine::SocketPoolEntry::~SocketPoolEntry() {}
 
 
 bool DownloadEngine::SocketPoolEntry::isTimeout() const
 bool DownloadEngine::SocketPoolEntry::isTimeout() const

+ 18 - 11
src/DownloadEngine.h

@@ -98,6 +98,9 @@ private:
                     const std::map<std::string, std::string>& option,
                     const std::map<std::string, std::string>& option,
                     time_t timeout);
                     time_t timeout);
 
 
+    SocketPoolEntry(const SharedHandle<SocketCore>& socket,
+                    time_t timeout);
+
     ~SocketPoolEntry();
     ~SocketPoolEntry();
 
 
     bool isTimeout() const;
     bool isTimeout() const;
@@ -151,6 +154,16 @@ private:
                   uint16_t port,
                   uint16_t port,
                   const SocketPoolEntry& entry);
                   const SocketPoolEntry& entry);
 
 
+  void poolSocket(const std::string& ipaddr, uint16_t port,
+                  const std::string& username,
+                  const SharedHandle<SocketCore>& sock,
+                  const std::map<std::string, std::string>& options,
+                  time_t timeout);
+
+  void poolSocket(const std::string& ipaddr, uint16_t port,
+                  const SharedHandle<SocketCore>& sock,
+                  time_t timeout);
+
   std::multimap<std::string, SocketPoolEntry>::iterator
   std::multimap<std::string, SocketPoolEntry>::iterator
   findSocketPoolEntry(const std::string& ipaddr, uint16_t port);
   findSocketPoolEntry(const std::string& ipaddr, uint16_t port);
 public:
 public:
@@ -202,17 +215,9 @@ public:
 
 
   void addRoutineCommand(Command* command);
   void addRoutineCommand(Command* command);
 
 
-  void poolSocket(const std::string& ipaddr, uint16_t port,
-                  const SharedHandle<SocketCore>& sock,
-                  const std::map<std::string, std::string>& options,
-                  time_t timeout = 15);
-
-  void poolSocket(const std::string& ipaddr, uint16_t port,
-                  const SharedHandle<SocketCore>& sock,
-                  time_t timeout = 15);
-  
   void poolSocket(const SharedHandle<Request>& request,
   void poolSocket(const SharedHandle<Request>& request,
                   bool proxyDefined,
                   bool proxyDefined,
+                  const std::string& username,
                   const SharedHandle<SocketCore>& socket,
                   const SharedHandle<SocketCore>& socket,
                   const std::map<std::string, std::string>& options,
                   const std::map<std::string, std::string>& options,
                   time_t timeout = 15);
                   time_t timeout = 15);
@@ -228,7 +233,8 @@ public:
   SharedHandle<SocketCore> popPooledSocket
   SharedHandle<SocketCore> popPooledSocket
   (std::map<std::string, std::string>& options,
   (std::map<std::string, std::string>& options,
    const std::string& ipaddr,
    const std::string& ipaddr,
-   uint16_t port);
+   uint16_t port,
+   const std::string& username);
 
 
   SharedHandle<SocketCore>
   SharedHandle<SocketCore>
   popPooledSocket(const std::vector<std::string>& ipaddrs, uint16_t port);
   popPooledSocket(const std::vector<std::string>& ipaddrs, uint16_t port);
@@ -237,7 +243,8 @@ public:
   popPooledSocket
   popPooledSocket
   (std::map<std::string, std::string>& options,
   (std::map<std::string, std::string>& options,
    const std::vector<std::string>& ipaddrs,
    const std::vector<std::string>& ipaddrs,
-   uint16_t port);
+   uint16_t port,
+   const std::string& username);
 
 
   const SharedHandle<CookieStorage>& getCookieStorage() const
   const SharedHandle<CookieStorage>& getCookieStorage() const
   {
   {

+ 5 - 0
src/FtpConnection.cc

@@ -517,4 +517,9 @@ void FtpConnection::setBaseWorkingDir(const std::string& baseWorkingDir)
   _baseWorkingDir = baseWorkingDir;
   _baseWorkingDir = baseWorkingDir;
 }
 }
 
 
+const std::string& FtpConnection::getUser() const
+{
+  return _authConfig->getUser();
+}
+
 } // namespace aria2
 } // namespace aria2

+ 2 - 0
src/FtpConnection.h

@@ -119,6 +119,8 @@ public:
   {
   {
     return _baseWorkingDir;
     return _baseWorkingDir;
   }
   }
+
+  const std::string& getUser() const;
 };
 };
 
 
 } // namespace aria2
 } // namespace aria2

+ 2 - 1
src/FtpFinishDownloadCommand.cc

@@ -82,7 +82,8 @@ 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, isProxyDefined(), socket, options);
+      e->poolSocket(req, isProxyDefined(), _ftpConnection->getUser(),
+                    socket, options);
     }
     }
   } catch(RecoverableException& e) {
   } catch(RecoverableException& e) {
     logger->info(EX_EXCEPTION_CAUGHT, e);
     logger->info(EX_EXCEPTION_CAUGHT, e);

+ 14 - 3
src/FtpInitiateConnectionCommand.cc

@@ -52,6 +52,8 @@
 #include "Socket.h"
 #include "Socket.h"
 #include "DownloadContext.h"
 #include "DownloadContext.h"
 #include "util.h"
 #include "util.h"
+#include "AuthConfigFactory.h"
+#include "AuthConfig.h"
 
 
 namespace aria2 {
 namespace aria2 {
 
 
@@ -73,9 +75,16 @@ Command* FtpInitiateConnectionCommand::createNextCommand
   Command* command;
   Command* command;
   if(!proxyRequest.isNull()) {
   if(!proxyRequest.isNull()) {
     std::map<std::string, std::string> options;
     std::map<std::string, std::string> options;
-    SharedHandle<SocketCore> pooledSocket =
-      e->popPooledSocket(options, req->getHost(), req->getPort());
+    SharedHandle<SocketCore> pooledSocket;
     std::string proxyMethod = resolveProxyMethod(req->getProtocol());
     std::string proxyMethod = resolveProxyMethod(req->getProtocol());
+    if(proxyMethod == V_GET) {
+      pooledSocket = e->popPooledSocket(req->getHost(), req->getPort());
+    } else {
+      pooledSocket = e->popPooledSocket
+        (options, req->getHost(), req->getPort(),
+         e->getAuthConfigFactory()->createAuthConfig
+         (req, getOption().get())->getUser());
+    }
     if(pooledSocket.isNull()) {
     if(pooledSocket.isNull()) {
       if(logger->info()) {
       if(logger->info()) {
         logger->info(MSG_CONNECTING_TO_SERVER,
         logger->info(MSG_CONNECTING_TO_SERVER,
@@ -133,7 +142,9 @@ 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());
+      e->popPooledSocket(options, resolvedAddresses, req->getPort(),
+                         e->getAuthConfigFactory()->createAuthConfig
+                         (req, getOption().get())->getUser());
     if(pooledSocket.isNull()) {
     if(pooledSocket.isNull()) {
       if(logger->info()) {
       if(logger->info()) {
         logger->info(MSG_CONNECTING_TO_SERVER,
         logger->info(MSG_CONNECTING_TO_SERVER,

+ 1 - 1
src/FtpNegotiationCommand.cc

@@ -806,7 +806,7 @@ 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, isProxyDefined(),  socket, options);
+    e->poolSocket(req, isProxyDefined(), ftp->getUser(), socket, options);
   }
   }
 }
 }