libzypp 17.35.13
downloader.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8----------------------------------------------------------------------*/
13#include <utility>
14#include <zypp-curl/TransferSettings>
16#include <zypp-media/MediaException>
18
19namespace zyppng {
20
21 DownloadPrivateBase::DownloadPrivateBase(Downloader &parent, std::shared_ptr<NetworkRequestDispatcher> requestDispatcher, std::shared_ptr<MirrorControl> mirrors, DownloadSpec &&spec, Download &p)
22 : BasePrivate(p)
23 , _requestDispatcher ( std::move(requestDispatcher) )
24 , _mirrorControl( std::move(mirrors) )
25 , _spec( std::move(spec) )
26 , _parent( &parent )
27 {}
28
31
32 bool DownloadPrivateBase::handleRequestAuthError( const std::shared_ptr<Request>& req, const zyppng::NetworkRequestError &err )
33 {
34 //Handle the auth errors explicitly, we need to give the user a way to put in new credentials
35 //if we get valid new credentials we can retry the request
36 bool retry = false;
38
39 MIL << "Authentication failed for " << req->url() << " trying to recover." << std::endl;
40
41 TransferSettings &ts = req->transferSettings();
42 const auto &applyCredToSettings = [&ts]( const AuthData_Ptr& auth, const std::string &authHint ) {
43 ts.setUsername( auth->username() );
44 ts.setPassword( auth->password() );
45 auto nwCred = dynamic_cast<NetworkAuthData *>( auth.get() );
46 if ( nwCred ) {
47 // set available authentication types from the error
48 if ( nwCred->authType() == CURLAUTH_NONE )
49 nwCred->setAuthType( authHint );
50
51 // set auth type (seems this must be set _after_ setting the userpwd)
52 if ( nwCred->authType() != CURLAUTH_NONE ) {
53 // FIXME: only overwrite if not empty?
54 ts.setAuthType(nwCred->authTypeAsString());
55 }
56 }
57 };
58
59 // try to find one in the cache
61 vopt = vopt
62 - zypp::url::ViewOption::WITH_USERNAME
63 - zypp::url::ViewOption::WITH_PASSWORD
64 - zypp::url::ViewOption::WITH_QUERY_STR;
65
66 auto cachedCred = zypp::media::CredentialManager::findIn( _credCache, req->url(), vopt );
67
68 // only consider a cache entry if its newer than what we tried last time
69 if ( cachedCred && cachedCred->lastDatabaseUpdate() > req->_authTimestamp ) {
70 MIL << "Found a credential match in the cache!" << std::endl;
71 applyCredToSettings( cachedCred, "" );
72 _lastTriedAuthTime = req->_authTimestamp = cachedCred->lastDatabaseUpdate();
73 retry = true;
74 } else {
75
77 credFromUser->setUrl( req->url() );
78 credFromUser->setLastDatabaseUpdate ( req->_authTimestamp );
79
80 //in case we got a auth hint from the server the error object will contain it
81 std::string authHint = err.extraInfoValue("authHint", std::string());
82
83 _sigAuthRequired.emit( *z_func(), *credFromUser, authHint );
84 if ( credFromUser->valid() ) {
85 // remember for next time , we don't want to ask the user again for the same URL set
86 _credCache.insert( credFromUser );
87 applyCredToSettings( credFromUser, authHint );
88 _lastTriedAuthTime = req->_authTimestamp = credFromUser->lastDatabaseUpdate();
89 retry = true;
90 }
91 }
92 }
93 return retry;
94 }
95
96#if ENABLE_ZCHUNK_COMPRESSION
97 bool DownloadPrivateBase::hasZckInfo() const
98 {
99 if ( zypp::indeterminate(_specHasZckInfo) )
100 _specHasZckInfo = ( _spec.headerSize() > 0 && isZchunkFile( _spec.deltaFile() ) );
101 return bool(_specHasZckInfo);
102 }
103#endif
104
106 {
107 _sigStartedConn.disconnect();
108 _sigProgressConn.disconnect();
109 _sigFinishedConn.disconnect();
110 }
111
112 DownloadPrivate::DownloadPrivate(Downloader &parent, std::shared_ptr<NetworkRequestDispatcher> requestDispatcher, std::shared_ptr<MirrorControl> mirrors, DownloadSpec &&spec, Download &p)
113 : DownloadPrivateBase( parent, std::move(requestDispatcher), std::move(mirrors), std::move(spec), p )
114 { }
115
126
128 {
129 auto cState = currentState();
130 if ( !cState )
132
133 cState = currentState();
134 if ( *cState != Download::InitialState && *cState != Download::Finished ) {
135 // the state machine has advaned already, we can only restart it in a finished state
136 return;
137 }
138
139 //reset state variables
140 _specHasZckInfo = zypp::indeterminate;
141 _emittedSigStart = false;
142 _stoppedOnMetalink = false;
144
145 // restart the statemachine
146 if ( cState == Download::Finished )
148
149 //jumpstart the process
150 state<InitialState>()->initiate();
151 }
152
153
155 {
156 auto buildExtraInfo = [this, &url](){
157 std::map<std::string, boost::any> extraInfo;
158 extraInfo.insert( {"requestUrl", url } );
159 extraInfo.insert( {"filepath", _spec.targetPath() } );
160 return extraInfo;
161 };
162
164 try {
166 if ( _spec.settings().proxy().empty() )
168
169#if 0
170 /* Fixes bsc#1174011 "auth=basic ignored in some cases"
171 * We should proactively add the password to the request if basic auth is configured
172 * and a password is available in the credentials but not in the URL.
173 *
174 * We will be a bit paranoid here and require that the URL has a user embedded, otherwise we go the default route
175 * and ask the server first about the auth method
176 */
177 if ( set.authType() == "basic"
178 && set.username().size()
179 && !set.password().size() ) {
181 const auto cred = cm.getCred( url );
182 if ( cred && cred->valid() ) {
183 if ( !set.username().size() )
184 set.setUsername(cred->username());
185 set.setPassword(cred->password());
186 }
187 }
188#endif
189
190 } catch ( const zypp::media::MediaBadUrlException & e ) {
192 } catch ( const zypp::media::MediaUnauthorizedException & e ) {
194 } catch ( const zypp::Exception & e ) {
196 }
197 return res;
198 }
199
200 Download::Download(zyppng::Downloader &parent, std::shared_ptr<zyppng::NetworkRequestDispatcher> requestDispatcher, std::shared_ptr<zyppng::MirrorControl> mirrors, zyppng::DownloadSpec &&spec)
201 : Base( *new DownloadPrivate( parent, std::move(requestDispatcher), std::move(mirrors), std::move(spec), *this ) )
202 { }
203
205
207 {
208 if ( state() != InitialState && state() != Finished )
209 cancel();
210 }
211
213 {
214 const auto &s = d_func()->currentState();
215 if ( !s )
217 return *s;
218 }
219
221 {
222 if ( state() == Finished ) {
223 return d_func()->state<FinishedState>()->_error;
224 }
225 return NetworkRequestError();
226 }
227
229 {
230 return lastRequestError().isError();
231 }
232
233 std::string Download::errorString() const
234 {
235 const auto &lReq = lastRequestError();
236 if (! lReq.isError() ) {
237 return {};
238 }
239
240 return ( zypp::str::Format("%1%(%2%)") % lReq.toString() % lReq.nativeErrorString() );
241 }
242
244 {
245 d_func()->start();
246 }
247
249 {
250 Z_D();
251
252 if ( !d->_requestDispatcher )
253 return;
254
255 d->_defaultSubRequestPriority = NetworkRequest::Critical;
256
257 // we only reschedule requests when we are in a state that downloads in blocks
258 d->visitState( []( auto &s ){
259 using T = std::decay_t<decltype (s)>;
260 if constexpr ( std::is_same_v<T, DlMetalinkState>
261#if ENABLE_ZCHUNK_COMPRESSION
262 || std::is_same_v<T, DLZckState>
263#endif
264 ) {
265 s.reschedule();
266 }
267 });
268 }
269
271 {
272 Z_D();
273 d->forceState ( std::make_unique<FinishedState>( NetworkRequestErrorPrivate::customError( NetworkRequestError::Cancelled, "Download was cancelled explicitly" ), *d_func() ) );
274 }
275
276 void Download::setStopOnMetalink(const bool set)
277 {
278 d_func()->_stopOnMetalink = set;
279 }
280
282 {
283 return d_func()->_stoppedOnMetalink;
284 }
285
287 {
288 return d_func()->_spec;
289 }
290
292 {
293 return d_func()->_spec;
294 }
295
297 {
298 return d_func()->_lastTriedAuthTime;
299 }
300
301 zyppng::NetworkRequestDispatcher &Download::dispatcher() const
302 {
303 return *d_func()->_requestDispatcher;
304 }
305
307 {
308 return d_func()->_sigStarted;
309 }
310
312 {
313 return d_func()->DownloadPrivateBase::_sigStateChanged;
314 }
315
317 {
318 return d_func()->_sigAlive;
319 }
320
321 SignalProxy<void (Download &req, off_t dltotal, off_t dlnow)> Download::sigProgress()
322 {
323 return d_func()->_sigProgress;
324 }
325
327 {
328 return d_func()->DownloadPrivateBase::_sigFinished;
329 }
330
331 SignalProxy<void (zyppng::Download &req, zyppng::NetworkAuthData &auth, const std::string &availAuth)> Download::sigAuthRequired()
332 {
333 return d_func()->_sigAuthRequired;
334 }
335
336 DownloaderPrivate::DownloaderPrivate(std::shared_ptr<MirrorControl> mc, Downloader &p)
337 : BasePrivate(p)
338 , _mirrors( std::move(mc) )
339 {
340 _requestDispatcher = std::make_shared<NetworkRequestDispatcher>( );
341 if ( !_mirrors ) {
343 }
344 }
345
347 {
348 _sigStarted.emit( *z_func(), download );
349 }
350
352 {
353 _sigFinished.emit( *z_func(), download );
354
355 auto it = std::find_if( _runningDownloads.begin(), _runningDownloads.end(), [ &download ]( const std::shared_ptr<Download> &dl){
356 return dl.get() == &download;
357 });
358
359 if ( it != _runningDownloads.end() ) {
360 //make sure this is not deleted before all user code was done
361 _runningDownloads.erase( it );
362 }
363
364 if ( _runningDownloads.empty() )
365 _queueEmpty.emit( *z_func() );
366 }
367
369
371 : Base ( *new DownloaderPrivate( {}, *this ) )
372 {
373
374 }
375
376 Downloader::Downloader( std::shared_ptr<MirrorControl> mc )
377 : Base ( *new DownloaderPrivate( std::move(mc), *this ) )
378 { }
379
381 {
382 Z_D();
383 while ( d->_runningDownloads.size() ) {
384 d->_runningDownloads.back()->cancel();
385 d->_runningDownloads.pop_back();
386 }
387 }
388
389 std::shared_ptr<Download> Downloader::downloadFile(const zyppng::DownloadSpec &spec )
390 {
391 Z_D();
392 std::shared_ptr<Download> dl ( new Download ( *this, d->_requestDispatcher, d->_mirrors, DownloadSpec(spec) ) );
393
394 d->_runningDownloads.push_back( dl );
396 d->_requestDispatcher->run();
397
398 return dl;
399 }
400
401 std::shared_ptr<NetworkRequestDispatcher> Downloader::requestDispatcher() const
402 {
403 return d_func()->_requestDispatcher;
404 }
405
407 {
408 return d_func()->_sigStarted;
409 }
410
412 {
413 return d_func()->_sigFinished;
414 }
415
417 {
418 return d_func()->_queueEmpty;
419 }
420
421}
Base class for Exception.
Definition Exception.h:147
std::string asString() const
Error message provided by dumpOn as string.
Definition Exception.cc:111
Url manipulation class.
Definition Url.h:92
AuthData_Ptr getCred(const Url &url)
Get credentials for the specified url.
static AuthData_Ptr findIn(const CredentialManager::CredentialSet &set, const Url &url, url::ViewOption vopt)
Curl HTTP authentication data.
Holds transfer setting.
void setUsername(const std::string &val_r)
sets the auth username
const std::string & proxy() const
proxy host
void setPassword(const std::string &val_r)
sets the auth password
void setAuthType(const std::string &val_r)
set the allowed authentication types
Base::WeakPtr parent
Definition base_p.h:22
static auto connectFunc(typename internal::MemberFunction< SenderFunc >::ClassType &s, SenderFunc &&sFun, ReceiverFunc &&rFunc, const Tracker &...trackers)
Definition base.h:163
NetworkRequestError safeFillSettingsFromURL(const Url &url, TransferSettings &set)
Signal< void(Download &req, Download::State state)> _sigStateChanged
Definition base_p.h:109
zypp::media::CredentialManager::CredentialSet _credCache
Definition base_p.h:96
bool handleRequestAuthError(const std::shared_ptr< Request > &req, const zyppng::NetworkRequestError &err)
Definition downloader.cc:32
Signal< void(zyppng::Download &req, zyppng::NetworkAuthData &auth, const std::string &availAuth)> _sigAuthRequired
Definition base_p.h:113
zypp::TriBool _specHasZckInfo
Definition base_p.h:99
DownloadPrivateBase(Downloader &parent, std::shared_ptr< NetworkRequestDispatcher > requestDispatcher, std::shared_ptr< MirrorControl > mirrors, DownloadSpec &&spec, Download &p)
Definition downloader.cc:21
Signal< void(Download &req)> _sigFinished
Definition base_p.h:112
DownloadPrivate(Downloader &parent, std::shared_ptr< NetworkRequestDispatcher > requestDispatcher, std::shared_ptr< MirrorControl > mirrors, DownloadSpec &&spec, Download &p)
void init() override
const TransferSettings & settings() const
zypp::ByteCount headerSize() const
zypp::filesystem::Pathname deltaFile() const
const zypp::Pathname & targetPath() const
std::string errorString() const
void setStopOnMetalink(const bool set=true)
NetworkRequestDispatcher & dispatcher() const
~Download() override
SignalProxy< void(Download &req)> sigFinished()
SignalProxy< void(Download &req)> sigStarted()
SignalProxy< void(Download &req, State state)> sigStateChanged()
NetworkRequestError lastRequestError() const
SignalProxy< void(Download &req, off_t dlnow)> sigAlive()
DownloadSpec & spec()
uint64_t lastAuthTimestamp() const
SignalProxy< void(Download &req, NetworkAuthData &auth, const std::string &availAuth)> sigAuthRequired()
bool hasError() const
Download(Downloader &parent, std::shared_ptr< NetworkRequestDispatcher > requestDispatcher, std::shared_ptr< MirrorControl > mirrors, DownloadSpec &&spec)
SignalProxy< void(Download &req, off_t dltotal, off_t dlnow)> sigProgress()
bool stoppedOnMetalink() const
State state() const
std::shared_ptr< MirrorControl > _mirrors
Signal< void(Downloader &parent, Download &download)> _sigStarted
std::vector< std::shared_ptr< Download > > _runningDownloads
void onDownloadFinished(Download &download)
Signal< void(Downloader &parent)> _queueEmpty
std::shared_ptr< NetworkRequestDispatcher > _requestDispatcher
Signal< void(Downloader &parent, Download &download)> _sigFinished
void onDownloadStarted(Download &download)
DownloaderPrivate(std::shared_ptr< MirrorControl > mc, Downloader &p)
The Downloader class.
Definition downloader.h:39
SignalProxy< void(Downloader &parent)> queueEmpty()
~Downloader() override
std::shared_ptr< Download > downloadFile(const DownloadSpec &spec)
SignalProxy< void(Downloader &parent, Download &download)> sigStarted()
std::shared_ptr< NetworkRequestDispatcher > requestDispatcher() const
SignalProxy< void(Downloader &parent, Download &download)> sigFinished()
static zyppng::NetworkRequestError customError(NetworkRequestError::Type t, std::string &&errorMsg="", std::map< std::string, boost::any > &&extraInfo={})
The NetworkRequestError class Represents a error that occured in.
T extraInfoValue(const std::string &key, T &&defaultVal=T()) const
Type type() const
type Returns the type of the error
bool isError() const
isError Will return true if this is a actual error
This defines the actual StateMachine.
std::optional< StateId > currentState() const
std::shared_ptr< T > state()
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 fillSettingsSystemProxy(const Url &url, media::TransferSettings &s)
Reads the system proxy configuration and fills the settings structure proxy information.
Definition Arch.h:364
typename decay< T >::type decay_t
Definition TypeTraits.h:42
zypp::media::CurlAuthData NetworkAuthData
Definition authdata.h:24
zypp::media::AuthData_Ptr AuthData_Ptr
Definition authdata.h:22
zypp::media::CurlAuthData_Ptr NetworkAuthData_Ptr
Definition authdata.h:25
zypp::repo::RepoException _error
Convenient building of std::string with boost::format.
Definition String.h:253
Url::asString() view options.
Definition UrlBase.h:40
#define MIL
Definition Logger.h:100
#define ZYPP_IMPL_PRIVATE(Class)
Definition zyppglobal.h:92
#define Z_D()
Definition zyppglobal.h:105