6 #include <zypp/zyppng/base/Timer> 7 #include <zypp/zyppng/base/EventDispatcher> 24 #define BLKSIZE 131072 27 bool looks_like_metalink_data(
const std::vector<char> &data )
32 const char *p = data.data();
33 while (*p ==
' ' || *p ==
'\t' || *p ==
'\r' || *p ==
'\n')
36 if (!strncasecmp(p,
"<?xml", 5))
38 while (*p && *p !=
'>')
42 while (*p ==
' ' || *p ==
'\t' || *p ==
'\r' || *p ==
'\n')
45 bool ret = !strncasecmp( p,
"<metalink", 9 ) ? true :
false;
51 std::unique_ptr<FILE, decltype(&fclose)> fd( fopen( file.
c_str(),
"r" ), &fclose );
61 : _requestDispatcher ( requestDispatcher )
62 , _url(
std::move(file) )
63 , _targetPath(
std::move(targetPath) )
77 _sigStartedConn.disconnect();
78 _sigProgressConn.disconnect();
79 _sigFinishedConn.disconnect();
102 setFailed(
"Failed to read settings from URL " );
108 initialRequest->_originalUrl =
_url;
113 initialRequest->transferSettings().
addHeader(
"Accept: */*, application/metalink+xml, application/metalink4+xml");
147 if ( cType.find(
"application/metalink+xml") == 0 || cType.find(
"application/metalink4+xml") == 0 )
153 return _sigAlive.emit( *z_func(), dlnow );
168 return _sigAlive.emit( *z_func(), dlnow );
196 return ( r.get() == &req );
201 auto reqLocked = *it;
222 if ( cmcred && !reqLocked->_triedCredFromStore ) {
223 DBG <<
"got stored credentials:" << std::endl << *cmcred << std::endl;
227 reqLocked->_triedCredFromStore =
true;
237 auto authHintIt = err.
extraInfo().find(
"authHint");
238 std::string authHint;
240 if ( authHintIt != err.
extraInfo().end() ){
242 authHint = boost::any_cast<std::string>( authHintIt->second );
243 }
catch (
const boost::bad_any_cast &) { }
247 if ( cmcred && !cmcred->username().empty() )
251 if ( credFromUser.
valid() ) {
256 if ( credFromUser.
authType() == CURLAUTH_NONE )
260 if ( credFromUser.
authType() != CURLAUTH_NONE ) {
274 DBG <<
"Request failed " << reqLocked->_myBlock <<
" " << reqLocked->extendedErrorString() << std::endl;
280 newReq->_retryCount = reqLocked->_retryCount + 1;
286 DBG <<
"Adding to failed blocklist " << reqLocked->_myBlock <<std::endl;
307 req->disconnectSignals();
315 DBG <<
"Falling back to download from initial URL." << std::endl;
339 DBG <<
" Upgrading request for URL: "<< req.
url() <<
" to multipart download " << std::endl;
351 std::vector<Url> urllist = parser.
getUrls();
352 for (std::vector<Url>::iterator urliter = urllist.begin(); urliter != urllist.end(); ++urliter) {
354 std::string scheme = urliter->getScheme();
355 if (scheme ==
"http" || scheme ==
"https" || scheme ==
"ftp" || scheme ==
"tftp") {
381 DBG <<
"No blocklist and no filesize, falling back to normal download for URL " <<
_url << std::endl;
399 std::shared_ptr<zypp::Digest> fileDigest = std::make_shared<zypp::Digest>();
413 DBG <<
"Generate blocklist, since there was none in the metalink file." <<
_url << std::endl;
417 while ( currOff < filesize ) {
419 size_t blksize =
static_cast<size_t>( filesize - currOff );
427 XXX <<
"Generated blocklist: " << std::endl <<
_blockList << std::endl <<
" End blocklist " << std::endl;
436 if ( dFileInfo.
isFile() && dFileInfo.
isR() ) {
457 DBG <<
"Request finished " << reqLocked->_myBlock <<std::endl;
459 auto restartReqWithBlock = [ this ]( std::shared_ptr<Request> &req,
size_t block,
int retryCount ) {
461 req->_myBlock = block;
462 req->_retryCount = retryCount;
463 req->setRequestRange( blk.
off, static_cast<off_t>( blk.
size ) );
474 DBG <<
"Reusing to download block: " <<
_blockIter <<std::endl;
475 restartReqWithBlock( reqLocked,
_blockIter, 0 );
486 DBG <<
"Reusing to download failed block: " << blk.
_block <<std::endl;
540 setFailed(
"Unable to download all blocks." );
551 if ( !istrm.is_open() ) {
552 setFailed(
"Failed to verify file digest (Could not open target file)." );
555 if ( !dig.
update( istrm ) ) {
556 setFailed(
"Failed to verify file digest (Could not read target file)." );
560 setFailed(
"Failed to verify file digest (Checksum did not match)." );
572 req->connectSignals( *
this );
586 DBG <<
"Starting block " << block << std::endl;
589 req->_originalUrl = myUrl;
590 req->_myBlock = block;
592 req->transferSettings() = settings;
595 std::shared_ptr<zypp::Digest> dig = std::make_shared<zypp::Digest>();
597 req->setDigest( dig );
599 req->setExpectedChecksum( checksumVec );
602 DBG <<
"Block " << block <<
" has no checksum." << std::endl;
610 bool foundMirror =
false;
656 auto buildExtraInfo = [
this, &
url](){
657 std::map<std::string, boost::any> extraInfo;
658 extraInfo.insert( {
"requestUrl",
url } );
684 return d_func()->_url;
689 return d_func()->_targetPath;
694 return d_func()->_state;
699 return d_func()->_requestError;
705 if (! d->_requestError.isError() ) {
706 return d->_errorString;
709 return (
zypp::str::Format(
"%1%(%2% %3%)") % d->_errorString % d->_requestError.toString() % d->_requestError.nativeErrorString() );
714 return d_func()->_transferSettings;
724 d_func()->_isMultiPartEnabled = enable;
730 if ( d->_checkExistsOnly !=
set ) {
731 d_func()->_checkExistsOnly =
set;
733 d_func()->_isMultiPartEnabled =
false;
739 d_func()->_deltaFilePath = file;
744 return *d_func()->_requestDispatcher;
749 return d_func()->_sigStarted;
754 return d_func()->_sigStateChanged;
759 return d_func()->_sigAlive;
764 return d_func()->_sigProgress;
769 return d_func()->_sigFinished;
774 return d_func()->_sigAuthRequired;
792 return dl.get() == &download;
814 std::shared_ptr<Download> dl = std::make_shared<Download>( std::move( *
new DownloadPrivate( *
this, d->_requestDispatcher, std::move(file), std::move(targetPath), std::move(expectedFileSize) ) ) );
816 d->_runningDownloads.push_back( dl );
819 d->_requestDispatcher->run();
826 return d_func()->_requestDispatcher;
831 return d_func()->_sigStarted;
836 return d_func()->_sigFinished;
841 return d_func()->_queueEmpty;
void setFinished(bool success=true)
bool isError() const
isError Will return true if this is a actual error
static void unrefLater(T &&ptr)
TransferSettings & settings()
SignalProxy< void(Download &req, off_t dlnow)> sigAlive()
void onRequestStarted(NetworkRequest &)
std::deque< Url > _multiPartMirrors
signal< void(Downloader &parent, Download &download)> _sigFinished
std::shared_ptr< Request > initMultiRequest(size_t block, NetworkRequestError &err)
static ZConfig & instance()
Singleton ctor.
zypp::Url propagateQueryParams(zypp::Url url_r, const zypp::Url &template_r)
Compute Message Digests (MD5, SHA1 etc)
Store and operate with byte count.
SignalProxy< void(Download &req, NetworkAuthData &auth, const std::string &availAuth)> sigAuthRequired()
std::shared_ptr< NetworkRequestDispatcher > _requestDispatcher
Url clearQueryString(const Url &url)
static std::string digestVectorToString(const std::vector< unsigned char > &vec)
get hex string representation of the digest vector given as parameter
const char * c_str() const
String representation.
std::vector< std::shared_ptr< Request > > _runningRequests
zypp::media::MediaBlockList _blockList
static const Unit MB
1000^2 Byte
std::vector< std::shared_ptr< Download > > _runningDownloads
SignalProxy< void(Downloader &parent, Download &download)> sigStarted()
TransferSettings & transferSettings()
SignalProxy< void(Download &req)> sigFinished()
void setFailed(std::string &&reason)
off_t _downloadedMultiByteCount
DownloadPrivate(Downloader &parent, std::shared_ptr< NetworkRequestDispatcher > requestDispatcher, Url &&file, zypp::filesystem::Pathname &&targetPath, zypp::ByteCount &&expectedFileSize)
signal< void(Downloader &parent)> _queueEmpty
signal< void(Download &req, Download::State state)> _sigStateChanged
void onDownloadFinished(Download &download)
SignalProxy< void(Downloader &parent, Download &download)> sigFinished()
bool empty() const
Test for an empty path.
std::shared_ptr< NetworkRequestDispatcher > _requestDispatcher
const std::map< std::string, boost::any > & extraInfo() const
zypp::Pathname _deltaFilePath
void setDigest(std::shared_ptr< zypp::Digest > dig)
Set a.
void connectSignals(DownloadPrivate &dl)
void setCheckExistsOnly(bool set=true)
int unlink(const Pathname &path)
Like 'unlink'.
TransferSettings _transferSettings
const std::string & asString() const
String representation.
zypp::Pathname targetPath() const
std::string asString() const
Error message provided by dumpOn as string.
std::string asUserString() const
Translated error message as string suitable for the user.
The NetworkRequestError class Represents a error that occured in.
std::shared_ptr< NetworkRequestDispatcher > requestDispatcher() const
std::vector< char > peekData(off_t offset, size_t count) const
zypp::media::CurlAuthData_Ptr NetworkAuthData_Ptr
void fillSettingsFromUrl(const Url &url, media::TransferSettings &s)
Fills the settings structure using options passed on the url for example ?timeout=x&proxy=foo.
void setDeltaFile(const zypp::Pathname &file)
signal< void(Download &req, off_t dlnow)> _sigAlive
NetworkRequestDispatcher & dispatcher() const
Download(DownloadPrivate &&prv)
signal< void(Download &req, off_t dltotal, off_t dlnow)> _sigProgress
bool findNextMirror(Url &url, TransferSettings &set, NetworkRequestError &err)
std::shared_ptr< Download > downloadFile(Url file, zypp::filesystem::Pathname targetPath, zypp::ByteCount expectedFileSize=zypp::ByteCount())
NetworkRequestError safeFillSettingsFromURL(const Url &url, TransferSettings &set)
const zypp::Pathname & targetFilePath() const
Returns the target filename path.
void onRequestFinished(NetworkRequest &req, const NetworkRequestError &err)
signal< void(zyppng::Download &req, zyppng::NetworkAuthData &auth, const std::string &availAuth)> _sigAuthRequired
NetworkRequestError lastRequestError() const
signal< void(Downloader &parent, Download &download)> _sigStarted
std::vector< char > peek_data_fd(FILE *fd, off_t offset, size_t count)
void setState(Download::State newState)
zypp::media::CurlAuthData NetworkAuthData
SignalProxy< void(Downloader &parent)> queueEmpty()
std::string contentType() const
Returns the content type as reported from the server.
signal< void(Download &req)> _sigStarted
SignalProxy< void(Download &req)> sigStarted()
Base class for Exception.
void onDownloadStarted(Download &download)
std::deque< FailedBlock > _failedBlocks
std::string getHost(EEncoding eflag=zypp::url::E_DECODED) const
Returns the hostname or IP from the URL authority.
connection _sigFinishedConn
void setMultiPartHandlingEnabled(bool enable=true)
SignalProxy< void(Download &req, off_t dltotal, off_t dlnow)> sigProgress()
NetworkRequestError _requestError
Wrapper class for ::stat/::lstat.
zypp::ByteCount _expectedFileSize
SignalProxy< void(NetworkRequest &req, const NetworkRequestError &err)> sigFinished()
Signals that the download finished.
void fillSettingsSystemProxy(const Url &url, media::TransferSettings &s)
Reads the system proxy configuration and fills the settings structure proxy information.
signal< void(Download &req)> _sigFinished
Type type() const
type Returns the type of the error
connection _sigStartedConn
connection _sigProgressConn
SignalProxy< void(NetworkRequest &req)> sigStarted()
Signals that the dispatcher dequeued the request and actually starts downloading data.
void setExpectedChecksum(std::vector< unsigned char > checksum)
Enables automated checking of downloaded contents against a checksum.
zypp::filesystem::Pathname _targetPath
std::string errorString() const
off_t downloadedByteCount() const
Returns the number of already downloaded bytes as reported by the backend.
SignalProxy< void(Download &req, State state)> sigStateChanged()
bool update(const char *bytes, size_t len)
feed data into digest computation algorithm
static zyppng::NetworkRequestError customError(NetworkRequestError::Type t, std::string &&errorMsg="", std::map< std::string, boost::any > &&extraInfo={})
SignalProxy< void(NetworkRequest &req, off_t dltotal, off_t dlnow, off_t ultotal, off_t ulnow)> sigProgress()
Signals if there was data read from the download.
void addNewRequest(std::shared_ptr< Request > req)
void onRequestProgress(NetworkRequest &req, off_t dltotal, off_t dlnow, off_t, off_t)