aria2 sends the url in the progress if there is no response from the server, handle...
[platform/upstream/libzypp.git] / zypp / media / MediaAria2c.cc
index 9c48874..39f9e20 100644 (file)
@@ -13,7 +13,7 @@
 #include <iostream>
 #include <list>
 #include <vector>
-
+#include <fstream>
 #include <boost/lexical_cast.hpp>
 
 #include "zypp/base/Logger.h"
@@ -30,6 +30,8 @@
 #include "zypp/ZYppFactory.h"
 #include "zypp/ZConfig.h"
 
+#include "zypp/TmpPath.h"
+
 #include "zypp/media/MediaAria2c.h"
 #include "zypp/media/proxyinfo/ProxyInfos.h"
 #include "zypp/media/ProxyInfo.h"
@@ -84,10 +86,17 @@ MediaAria2c::existsAria2cmd()
  */
 void fillAriaCmdLine( const string &ariaver,
                       const TransferSettings &s,
+                      filesystem::TmpPath &credentials,
                       const Url &url,
                       const Pathname &destination,
                       ExternalProgram::Arguments &args )
 {
+    
+    // options that are not passed in the command line
+    // like credentials, every string is in the
+    // opt=val format
+    list<string> file_options;
+    
     args.push_back(ARIA_BINARY);
     args.push_back(str::form("--user-agent=%s", s.userAgentString().c_str()));
     args.push_back("--summary-interval=1");
@@ -148,18 +157,18 @@ void fillAriaCmdLine( const string &ariaver,
     else
     {
         if ( url.getScheme() == "ftp" )
-            args.push_back(str::form("--ftp-user=%s", s.username().c_str() ));
+            file_options.push_back(str::form("ftp-user=%s", s.username().c_str() ));
         else if ( url.getScheme() == "http" ||
                   url.getScheme() == "https" )
-            args.push_back(str::form("--http-user=%s", s.username().c_str() ));
+            file_options.push_back(str::form("http-user=%s", s.username().c_str() ));
 
         if ( s.password().size() )
         {
             if ( url.getScheme() == "ftp" )
-                args.push_back(str::form("--ftp-passwd=%s", s.password().c_str() ));
+                file_options.push_back(str::form("ftp-passwd=%s", s.password().c_str() ));
             else if ( url.getScheme() == "http" ||
                       url.getScheme() == "https" )
-                args.push_back(str::form("--http-passwd=%s", s.password().c_str() ));
+                file_options.push_back(str::form("http-passwd=%s", s.password().c_str() ));
         }
     }
 
@@ -168,15 +177,28 @@ void fillAriaCmdLine( const string &ariaver,
         args.push_back(str::form("--http-proxy=%s", s.proxy().c_str() ));
         if ( ! s.proxyUsername().empty() )
         {
-            args.push_back(str::form("--http-proxy-user=%s", s.proxyUsername().c_str() ));
+            file_options.push_back(str::form("http-proxy-user=%s", s.proxyUsername().c_str() ));
             if ( ! s.proxyPassword().empty() )
-                args.push_back(str::form("--http-proxy-passwd=%s", s.proxyPassword().c_str() ));
+                file_options.push_back(str::form("http-proxy-passwd=%s", s.proxyPassword().c_str() ));
         }
     }
 
     if ( ! destination.empty() )
         args.push_back(str::form("--dir=%s", destination.c_str()));
 
+    // now append the file if there are hidden options
+    if ( ! file_options.empty() )
+    {
+        filesystem::TmpFile tmp;
+        ofstream outs( tmp.path().c_str() );
+        for_( it, file_options.begin(), file_options.end() )
+            outs << *it << endl;
+        outs.close();
+
+        credentials = tmp;
+        args.push_back(str::form("--conf-path=%s", credentials.path().c_str()));
+    }
+    
     args.push_back(url.asString().c_str());
 }
 
@@ -193,7 +215,7 @@ const char *const MediaAria2c::agentString()
        "ZYpp %s (%s) %s"
        , VERSION
        , MediaAria2c::_aria2cVersion.c_str()
-       , target ? target->targetDistribution().c_str() : ""
+       , Target::targetDistribution( Pathname()/*guess root*/ ).c_str()
     )
   );
   return _value.c_str();
@@ -277,7 +299,8 @@ void MediaAria2c::getFileCopy( const Pathname & filename , const Pathname & targ
 
   ExternalProgram::Arguments args;
 
-  fillAriaCmdLine(_aria2cVersion, _settings, fileurl, target.dirname(), args);
+  filesystem::TmpPath credentials;
+  fillAriaCmdLine(_aria2cVersion, _settings, credentials, fileurl, target.dirname(), args);
 
   do
   {
@@ -292,6 +315,7 @@ void MediaAria2c::getFileCopy( const Pathname & filename , const Pathname & targ
       //       (bnc #513944) [#1 SIZE:8.3MiB/10.1MiB(82%) CN:5 SPD:3.8MiBs]
       // we save it until we find a string with FILE: later
       string progressLine;
+      int progress = 0;
       // file line, which tell which file is the previous progress
       // ie: FILE: ./packages.FL.gz
       double average_speed = 0;
@@ -300,6 +324,9 @@ void MediaAria2c::getFileCopy( const Pathname & filename , const Pathname & targ
       // here we capture aria output exceptions
       vector<string> ariaExceptions;
 
+      // TODO: Detect partial downloads!
+      bool partialDownload = false; // Whether it makes sense to retry with --continue!
+
       //Process response
       for(std::string ariaResponse( aria.receiveLine());
           ariaResponse.length();
@@ -331,18 +358,20 @@ void MediaAria2c::getFileCopy( const Pathname & filename , const Pathname & targ
         else if ( str::hasPrefix(line, "FILE: ") )
         {
           // get the FILE name
-          Pathname theFile(line.substr(6, line.size()));
+          string theFile(line.substr(6, line.size()));
           // is the report about the filename we are downloading?
           // aria may report progress about metalinks, torrent and
           // other stuff which is not the main transfer
-          if ( theFile == target )
+          // the reported file is the url before the server emits a response
+          // and then is reported as the target file
+          if ( Pathname(theFile) == target || theFile == fileurl.asCompleteString() )
           {
             // once we find the FILE: line, progress has to be
             // non empty
             if ( ! progressLine.empty() )
             {
               // get the percentage (progress) data
-              int progress = 0;
+              progress = 0;
               size_t left_bound = progressLine.find('(',0) + 1;
               size_t count = progressLine.find('%',left_bound) - left_bound;
               string progressStr = progressLine.substr(left_bound, count);
@@ -437,6 +466,22 @@ void MediaAria2c::getFileCopy( const Pathname & filename , const Pathname & targ
         case 1: // unknown
         default:
         {
+          if ( partialDownload )
+          {
+            // Ask for retry on partial downloads, when it makes sense to retry with --continue!
+            // Other errors are handled by the layers above.
+            MediaException e(str::form(_("Download interrupted at %d%%"), progress ));
+            for_(it, ariaExceptions.begin(), ariaExceptions.end())
+              e.addHistory(*it);
+
+            DownloadProgressReport::Action action = report->problem( _url, DownloadProgressReport::ERROR, e.asUserHistory() );
+            if ( action == DownloadProgressReport::RETRY )
+            {
+              retry = true;
+              continue;
+            }
+          }
+
           // TranslatorExplanation: Failed to download <FILENAME> from <SERVERURL>.
           MediaException e(str::form(_("Failed to download %s from %s"), filename.c_str(), _url.asString().c_str()));
           for_(it, ariaExceptions.begin(), ariaExceptions.end())
@@ -493,7 +538,6 @@ bool MediaAria2c::authenticate(const std::string & availAuthTypes, bool firstTry
     return false;
 }
 
-
 void MediaAria2c::getDirInfo( std::list<std::string> & retlist,
                                const Pathname & dirname, bool dots ) const
 {