1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/media/MediaAria2c.cc
16 #include "zypp/base/Logger.h"
17 #include "zypp/ExternalProgram.h"
18 #include "zypp/ProgressData.h"
19 #include "zypp/base/String.h"
20 #include "zypp/base/Gettext.h"
21 #include "zypp/base/Sysconfig.h"
22 #include "zypp/base/Gettext.h"
23 #include "zypp/ZYppCallbacks.h"
25 #include "zypp/Edition.h"
26 #include "zypp/Target.h"
27 #include "zypp/ZYppFactory.h"
29 #include "zypp/media/MediaAria2c.h"
30 #include "zypp/media/proxyinfo/ProxyInfos.h"
31 #include "zypp/media/ProxyInfo.h"
32 #include "zypp/media/MediaUserAuth.h"
33 #include "zypp/media/MediaCurl.h"
34 #include "zypp/thread/Once.h"
36 #include <sys/types.h>
38 #include <sys/mount.h>
42 #include <boost/format.hpp>
44 #define DETECT_DIR_INDEX 0
45 #define CONNECT_TIMEOUT 60
46 #define TRANSFER_TIMEOUT 60 * 3
47 #define TRANSFER_TIMEOUT_MAX 60 * 60
51 using namespace zypp::base;
58 Pathname MediaAria2c::_cookieFile = "/var/lib/YaST2/cookies";
59 Pathname MediaAria2c::_aria2cPath = "/usr/local/bin/aria2c";
60 std::string MediaAria2c::_aria2cVersion = "WE DON'T KNOW ARIA2C VERSION";
62 //check if aria2c is present in the system
64 MediaAria2c::existsAria2cmd()
73 ExternalProgram aria(argv, ExternalProgram::Stderr_To_Stdout);
75 for(std::string ariaResponse( aria.receiveLine());
76 ariaResponse.length();
77 ariaResponse = aria.receiveLine())
82 return ( aria.close() == 0 );
86 * comannd line for aria.
87 * The argument list gets passed as reference
90 void fillAriaCmdLine( const Pathname &ariapath,
91 const string &ariaver,
92 const TransferSettings &s,
94 const Pathname &destination,
95 ExternalProgram::Arguments &args )
97 args.push_back(ariapath.c_str());
98 args.push_back(str::form("--user-agent=%s", s.userAgentString().c_str()));
99 args.push_back("--summary-interval=1");
100 args.push_back("--follow-metalink=mem");
101 args.push_back("--check-integrity=true");
102 args.push_back("--file-allocation=none");
104 // only present in recent aria lets find out the aria version
105 vector<string> fields;
106 // "aria2c version x.x"
107 str::split( ariaver, std::back_inserter(fields));
108 if ( fields.size() == 3 )
110 if ( Edition(fields[2]) >= Edition("1.1.2") )
111 args.push_back( "--use-head=false");
114 if ( s.maxDownloadSpeed() > 0 )
115 args.push_back(str::form("--max-download-limit=%ld", s.maxDownloadSpeed()));
116 if ( s.minDownloadSpeed() > 0 )
117 args.push_back(str::form("--lowest-speed-limit=%ld", s.minDownloadSpeed()));
119 args.push_back(str::form("--max-tries=%ld", s.maxSilentTries()));
121 if ( Edition(fields[2]) < Edition("1.2.0") )
122 WAR << "aria2c is older than 1.2.0, some features may be disabled" << endl;
124 // TODO make this one configurable
125 args.push_back(str::form("--max-concurrent-downloads=%ld", s.maxConcurrentConnections()));
127 // add the anonymous id.
128 for ( TransferSettings::Headers::const_iterator it = s.headersBegin();
129 it != s.headersEnd();
131 args.push_back(str::form("--header=%s", it->c_str() ));
133 args.push_back( str::form("--connect-timeout=%ld", s.timeout()));
135 if ( s.username().empty() )
137 if ( url.getScheme() == "ftp" )
140 args.push_back(str::form("--ftp-user=%s", "suseuser" ));
141 args.push_back(str::form("--ftp-passwd=%s", VERSION ));
145 DBG << "Anonymous FTP identification: '" << id << "'" << endl;
150 if ( url.getScheme() == "ftp" )
151 args.push_back(str::form("--ftp-user=%s", s.username().c_str() ));
152 else if ( url.getScheme() == "http" ||
153 url.getScheme() == "https" )
154 args.push_back(str::form("--http-user=%s", s.username().c_str() ));
156 if ( s.password().size() )
158 if ( url.getScheme() == "ftp" )
159 args.push_back(str::form("--ftp-passwd=%s", s.password().c_str() ));
160 else if ( url.getScheme() == "http" ||
161 url.getScheme() == "https" )
162 args.push_back(str::form("--http-passwd=%s", s.password().c_str() ));
166 if ( s.proxyEnabled() )
168 args.push_back(str::form("--http-proxy=%s", s.proxy().c_str() ));
169 if ( ! s.proxyUsername().empty() )
171 args.push_back(str::form("--http-proxy-user=%s", s.proxyUsername().c_str() ));
172 if ( ! s.proxyPassword().empty() )
173 args.push_back(str::form("--http-proxy-passwd=%s", s.proxyPassword().c_str() ));
177 if ( ! destination.empty() )
178 args.push_back(str::form("--dir=%s", destination.c_str()));
180 args.push_back(url.asString().c_str());
183 const char *const MediaAria2c::agentString()
185 // we need to add the release and identifier to the
187 // The target could be not initialized, and then this information
189 Target_Ptr target = zypp::getZYpp()->getTarget();
191 static const std::string _value(
195 , MediaAria2c::_aria2cVersion.c_str()
196 , target ? target->targetDistribution().c_str() : ""
199 return _value.c_str();
204 MediaAria2c::MediaAria2c( const Url & url_r,
205 const Pathname & attach_point_hint_r )
206 : MediaCurl( url_r, attach_point_hint_r )
208 MIL << "MediaAria2c::MediaAria2c(" << url_r << ", " << attach_point_hint_r << ")" << endl;
210 //At this point, we initialize aria2c path
211 _aria2cPath = Pathname( whereisAria2c().asString() );
214 _aria2cVersion = getAria2cVersion();
217 void MediaAria2c::attachTo (bool next)
219 MediaCurl::attachTo(next);
220 _settings.setUserAgentString(agentString());
224 MediaAria2c::checkAttachPoint(const Pathname &apoint) const
226 return MediaCurl::checkAttachPoint( apoint );
229 void MediaAria2c::disconnectFrom()
231 MediaCurl::disconnectFrom();
234 void MediaAria2c::releaseFrom( const std::string & ejectDev )
236 MediaCurl::releaseFrom(ejectDev);
239 static Url getFileUrl(const Url & url, const Pathname & filename)
242 string path = url.getPathName();
243 if ( !path.empty() && path != "/" && *path.rbegin() == '/' &&
244 filename.absolute() )
246 // If url has a path with trailing slash, remove the leading slash from
247 // the absolute file name
248 path += filename.asString().substr( 1, filename.asString().size() - 1 );
250 else if ( filename.relative() )
252 // Add trailing slash to path, if not already there
253 if (path.empty()) path = "/";
254 else if (*path.rbegin() != '/' ) path += "/";
255 // Remove "./" from begin of relative file name
256 path += filename.asString().substr( 2, filename.asString().size() - 2 );
260 path += filename.asString();
263 newurl.setPathName(path);
267 void MediaAria2c::getFile( const Pathname & filename ) const
269 // Use absolute file name to prevent access of files outside of the
270 // hierarchy below the attach point.
271 getFileCopy(filename, localPath(filename).absolutename());
274 void MediaAria2c::getFileCopy( const Pathname & filename , const Pathname & target) const
276 callback::SendReport<DownloadProgressReport> report;
278 Url fileurl(getFileUrl(_url, filename));
282 ExternalProgram::Arguments args;
284 fillAriaCmdLine(_aria2cPath, _aria2cVersion, _settings, fileurl, target.dirname(), args);
290 report->start(_url, target.asString() );
292 ExternalProgram aria(args, ExternalProgram::Stderr_To_Stdout);
296 for(std::string ariaResponse( aria.receiveLine());
297 ariaResponse.length();
298 ariaResponse = aria.receiveLine())
300 //cout << ariaResponse;
302 if (!ariaResponse.substr(0,31).compare("Exception: Authorization failed") )
304 ZYPP_THROW(MediaUnauthorizedException(
305 _url, "Login failed.", "Login failed", "auth hint"
308 if (!ariaResponse.substr(0,29).compare("Exception: Resource not found") )
310 ZYPP_THROW(MediaFileNotFoundException(_url, filename));
313 if (!ariaResponse.substr(0,9).compare("[#2 SIZE:"))
317 size_t left_bound = ariaResponse.find('(',0) + 1;
318 size_t count = ariaResponse.find('%',left_bound) - left_bound;
319 //cout << ariaResponse.substr(left_bound, count) << endl;
320 //progressData.toMax();
321 report->progress ( std::atoi(ariaResponse.substr(left_bound, count).c_str()), _url, -1, -1 );
333 report->finish( _url , zypp::media::DownloadProgressReport::NO_ERROR, "");
337 // retry with proper authentication data
338 catch (MediaUnauthorizedException & ex_r)
340 if(authenticate(ex_r.hint(), !retry))
344 report->finish(fileurl, zypp::media::DownloadProgressReport::ACCESS_DENIED, ex_r.asUserHistory());
349 // unexpected exception
350 catch (MediaException & excpt_r)
352 // FIXME: error number fix
353 report->finish(fileurl, zypp::media::DownloadProgressReport::ERROR, excpt_r.asUserHistory());
354 ZYPP_RETHROW(excpt_r);
359 report->finish(fileurl, zypp::media::DownloadProgressReport::NO_ERROR, "");
362 bool MediaAria2c::getDoesFileExist( const Pathname & filename ) const
364 return MediaCurl::getDoesFileExist(filename);
367 bool MediaAria2c::doGetDoesFileExist( const Pathname & filename ) const
369 return MediaCurl::doGetDoesFileExist(filename);
372 void MediaAria2c::getDir( const Pathname & dirname, bool recurse_r ) const
374 MediaCurl::getDir(dirname, recurse_r);
377 bool MediaAria2c::authenticate(const std::string & availAuthTypes, bool firstTry) const
383 void MediaAria2c::getDirInfo( std::list<std::string> & retlist,
384 const Pathname & dirname, bool dots ) const
386 getDirectoryYast( retlist, dirname, dots );
389 void MediaAria2c::getDirInfo( filesystem::DirContent & retlist,
390 const Pathname & dirname, bool dots ) const
392 getDirectoryYast( retlist, dirname, dots );
395 std::string MediaAria2c::getAria2cVersion()
404 ExternalProgram aria(argv, ExternalProgram::Stderr_To_Stdout);
406 std::string vResponse = aria.receiveLine();
408 return str::trim(vResponse);
411 #define ARIA_DEFAULT_BINARY "/usr/bin/aria2c"
413 Pathname MediaAria2c::whereisAria2c()
415 Pathname aria2cPathr(ARIA_DEFAULT_BINARY);
424 ExternalProgram aria(argv, ExternalProgram::Stderr_To_Stdout);
426 std::string ariaResponse( aria.receiveLine());
427 int code = aria.close();
431 aria2cPathr = str::trim(ariaResponse);
432 MIL << "We will use aria2c located here: " << aria2cPathr << endl;
436 MIL << "We don't know were is ari2ac binary. We will use aria2c located here: " << aria2cPathr << endl;