libzypp  17.38.7
request.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 ----------------------------------------------------------------------*/
13 #include <zypp-core/ng/base/EventDispatcher>
15 #include <zypp-core/ng/core/String>
16 #include <zypp-core/fs/PathInfo.h>
18 #include <zypp-curl/CurlConfig>
19 #include <zypp-curl/auth/CurlAuthData>
20 #include <zypp-media/MediaConfig>
21 #include <zypp-core/base/String.h>
22 #include <zypp-core/base/StringV.h>
23 #include <zypp-core/base/IOTools.h>
24 #include <zypp-core/Pathname.h>
25 #include <curl/curl.h>
26 #include <stdio.h>
27 #include <fcntl.h>
28 #include <utility>
29 
30 #include <iostream>
31 #include <boost/variant.hpp>
32 #include <boost/variant/polymorphic_get.hpp>
33 
34 
35 namespace zyppng {
36 
37  namespace {
38  static size_t nwr_headerCallback ( char *ptr, size_t size, size_t nmemb, void *userdata ) {
39  if ( !userdata )
40  return 0;
41 
42  NetworkRequestPrivate *that = reinterpret_cast<NetworkRequestPrivate *>( userdata );
43  return that->headerfunction( ptr, size * nmemb );
44  }
45  static size_t nwr_writeCallback ( char *ptr, size_t size, size_t nmemb, void *userdata ) {
46  if ( !userdata )
47  return 0;
48 
49  NetworkRequestPrivate *that = reinterpret_cast<NetworkRequestPrivate *>( userdata );
50  return that->writefunction( ptr, {}, size * nmemb );
51  }
52 
53  //helper for std::visit
54  template<class T> struct always_false : std::false_type {};
55  }
56 
58  : _outFile( std::move(prevState._outFile) )
59  , _downloaded( prevState._downloaded )
60  , _partialHelper( std::move(prevState._partialHelper) )
61  { }
62 
64  : _partialHelper( std::move(prevState._partialHelper) )
65  { }
66 
68  : _outFile( std::move(prevState._outFile) )
69  , _partialHelper( std::move(prevState._partialHelper) )
70  , _downloaded( prevState._downloaded )
71  { }
72 
74  : BasePrivate(p)
75  , _url ( std::move(url) )
76  , _targetFile ( std::move( targetFile) )
77  , _fMode ( std::move(fMode) )
78  , _headers( std::unique_ptr< curl_slist, decltype (&curl_slist_free_all) >( nullptr, &curl_slist_free_all ) )
79  { }
80 
82  {
83  if ( _easyHandle ) {
84  //clean up for now, later we might reuse handles
85  curl_easy_cleanup( _easyHandle );
86  MIL << _easyHandle << " curl_easy_cleanup" << std::endl;
87  //reset in request but make sure the request was not enqueued again and got a new handle
88  _easyHandle = nullptr;
89  }
90  }
91 
92  bool NetworkRequestPrivate::initialize( std::string &errBuf )
93  {
94  reset();
95 
96  if ( _easyHandle ) {
97  //will reset to defaults but keep live connections, session ID and DNS caches
98  curl_easy_reset( _easyHandle );
99  MIL << _easyHandle << " curl_easy_reset" << std::endl;
100  } else
101  _easyHandle = curl_easy_init();
102  return setupHandle ( errBuf );
103  }
104 
105  bool NetworkRequestPrivate::setupHandle( std::string &errBuf )
106  {
108  curl_easy_setopt( _easyHandle, CURLOPT_ERRORBUFFER, this->_errorBuf.data() );
109  MIL << _easyHandle << " " << "URL: " << _url << std::endl;
110 
111  const std::string urlScheme = _url.getScheme();
112  if ( urlScheme == "http" || urlScheme == "https" )
114 
115  try {
116 
117  setCurlOption( CURLOPT_PRIVATE, this );
118  setCurlOption( CURLOPT_XFERINFOFUNCTION, NetworkRequestPrivate::curlProgressCallback );
119  setCurlOption( CURLOPT_XFERINFODATA, this );
120  setCurlOption( CURLOPT_NOPROGRESS, 0L);
121  setCurlOption( CURLOPT_FAILONERROR, 1L);
122  setCurlOption( CURLOPT_NOSIGNAL, 1L);
123 
124  std::string urlBuffer( _url.asString() );
125  setCurlOption( CURLOPT_URL, urlBuffer.c_str() );
126 
127  setCurlOption( CURLOPT_WRITEFUNCTION, nwr_writeCallback );
128  setCurlOption( CURLOPT_WRITEDATA, this );
129 
131  setCurlOption( CURLOPT_CONNECT_ONLY, 1L );
132  setCurlOption( CURLOPT_FRESH_CONNECT, 1L );
133  }
135  // instead of returning no data with NOBODY, we return
136  // little data, that works with broken servers, and
137  // works for ftp as well, because retrieving only headers
138  // ftp will return always OK code ?
139  // See http://curl.haxx.se/docs/knownbugs.html #58
141  setCurlOption( CURLOPT_NOBODY, 1L );
142  else
143  setCurlOption( CURLOPT_RANGE, "0-1" );
144  }
145 
146  //make a local copy of the settings, so headers are not added multiple times
147  TransferSettings locSet = _settings;
148 
149  if ( _dispatcher ) {
150  locSet.setUserAgentString( _dispatcher->agentString().c_str() );
151 
152  // add custom headers as configured (bsc#955801)
153  const auto &cHeaders = _dispatcher->hostSpecificHeaders();
154  if ( auto i = cHeaders.find(_url.getHost()); i != cHeaders.end() ) {
155  for ( const auto &[key, value] : i->second ) {
157  "%s: %s", key.c_str(), value.c_str() )
158  ));
159  }
160  }
161  }
162 
163  locSet.addHeader("Pragma:");
164 
167  {
168  case 4: setCurlOption( CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 ); break;
169  case 6: setCurlOption( CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6 ); break;
170  default: break;
171  }
172 
173  setCurlOption( CURLOPT_HEADERFUNCTION, &nwr_headerCallback );
174  setCurlOption( CURLOPT_HEADERDATA, this );
175 
179  setCurlOption( CURLOPT_CONNECTTIMEOUT, locSet.connectTimeout() );
180  // If a transfer timeout is set, also set CURLOPT_TIMEOUT to an upper limit
181  // just in case curl does not trigger its progress callback frequently
182  // enough.
183  if ( locSet.timeout() )
184  {
185  setCurlOption( CURLOPT_TIMEOUT, 3600L );
186  }
187 
188  if ( urlScheme == "https" )
189  {
190  if ( :: internal::setCurlRedirProtocols ( _easyHandle ) != CURLE_OK ) {
192  }
193 
194  if( locSet.verifyPeerEnabled() ||
195  locSet.verifyHostEnabled() )
196  {
197  setCurlOption(CURLOPT_CAPATH, locSet.certificateAuthoritiesPath().c_str());
198  }
199 
200  if( ! locSet.clientCertificatePath().empty() )
201  {
202  setCurlOption(CURLOPT_SSLCERT, locSet.clientCertificatePath().c_str());
203  }
204  if( ! locSet.clientKeyPath().empty() )
205  {
206  setCurlOption(CURLOPT_SSLKEY, locSet.clientKeyPath().c_str());
207  }
208 
209 #ifdef CURLSSLOPT_ALLOW_BEAST
210  // see bnc#779177
211  setCurlOption( CURLOPT_SSL_OPTIONS, CURLSSLOPT_ALLOW_BEAST );
212 #endif
213  setCurlOption(CURLOPT_SSL_VERIFYPEER, locSet.verifyPeerEnabled() ? 1L : 0L);
214  setCurlOption(CURLOPT_SSL_VERIFYHOST, locSet.verifyHostEnabled() ? 2L : 0L);
215  // bnc#903405 - POODLE: libzypp should only talk TLS
216  setCurlOption(CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
217  }
218 
219  // follow any Location: header that the server sends as part of
220  // an HTTP header (#113275)
221  setCurlOption( CURLOPT_FOLLOWLOCATION, 1L);
222  // 3 redirects seem to be too few in some cases (bnc #465532)
223  setCurlOption( CURLOPT_MAXREDIRS, 6L );
224 
225  //set the user agent
226  setCurlOption(CURLOPT_USERAGENT, locSet.userAgentString().c_str() );
227 
228 
229  /*---------------------------------------------------------------*
230  CURLOPT_USERPWD: [user name]:[password]
231  Url::username/password -> CURLOPT_USERPWD
232  If not provided, anonymous FTP identification
233  *---------------------------------------------------------------*/
234  if ( locSet.hasCredentials() )
235  {
236  locSet.logCredentials( DBG << "Credentials: " ) << std::endl;
237  setCurlOption(CURLOPT_USERNAME, locSet.username().c_str());
238  setCurlOption(CURLOPT_PASSWORD, locSet.password().c_str());
239  std::string use_auth = _settings.authType();
240  if (use_auth.empty())
241  use_auth = "digest,basic"; // our default
242  long auth = zypp::media::CurlAuthData::auth_type_str2long(use_auth);
243  if( auth != CURLAUTH_NONE)
244  {
245  DBG << _easyHandle << " " << "Enabling HTTP authentication methods: " << use_auth
246  << " (CURLOPT_HTTPAUTH=" << auth << ")" << std::endl;
247  setCurlOption(CURLOPT_HTTPAUTH, auth);
248  }
249  }
250 
251  if ( locSet.proxyEnabled() && ! locSet.proxy().empty() )
252  {
253  DBG << _easyHandle << " " << "Proxy: '" << locSet.proxy() << "'" << std::endl;
254  setCurlOption(CURLOPT_PROXY, locSet.proxy().c_str());
255  setCurlOption(CURLOPT_PROXYAUTH, CURLAUTH_BASIC|CURLAUTH_DIGEST|CURLAUTH_NTLM );
256 
257  /*---------------------------------------------------------------*
258  * CURLOPT_PROXYUSERPWD: [user name]:[password]
259  *
260  * Url::option(proxyuser and proxypassword) -> CURLOPT_PROXYUSERPWD
261  * If not provided, $HOME/.curlrc is evaluated
262  *---------------------------------------------------------------*/
263 
264  std::string proxyuserpwd = locSet.proxyUserPassword();
265 
266  if ( proxyuserpwd.empty() )
267  {
268  zypp::media::CurlConfig curlconf;
269  zypp::media::CurlConfig::parseConfig(curlconf); // parse ~/.curlrc
270  if ( curlconf.proxyuserpwd.empty() )
271  DBG << _easyHandle << " " << "Proxy: ~/.curlrc does not contain the proxy-user option" << std::endl;
272  else
273  {
274  proxyuserpwd = curlconf.proxyuserpwd;
275  DBG << _easyHandle << " " << "Proxy: using proxy-user from ~/.curlrc" << std::endl;
276  }
277  }
278  else
279  {
280  DBG << _easyHandle << " " << "Proxy: using provided proxy-user '" << _settings.proxyUsername() << "'" << std::endl;
281  }
282 
283  if ( ! proxyuserpwd.empty() )
284  {
285  setCurlOption(CURLOPT_PROXYUSERPWD, ::internal::curlUnEscape( proxyuserpwd ).c_str());
286  }
287  }
288 #if CURLVERSION_AT_LEAST(7,19,4)
289  else if ( locSet.proxy() == EXPLICITLY_NO_PROXY )
290  {
291  // Explicitly disabled in URL (see fillSettingsFromUrl()).
292  // This should also prevent libcurl from looking into the environment.
293  DBG << _easyHandle << " " << "Proxy: explicitly NOPROXY" << std::endl;
294  setCurlOption(CURLOPT_NOPROXY, "*");
295  }
296 
297 #endif
298  // else: Proxy: not explicitly set; libcurl may look into the environment
299 
301  if ( locSet.minDownloadSpeed() != 0 )
302  {
303  setCurlOption(CURLOPT_LOW_SPEED_LIMIT, locSet.minDownloadSpeed());
304  // default to 10 seconds at low speed
305  setCurlOption(CURLOPT_LOW_SPEED_TIME, 60L);
306  }
307 
308 #if CURLVERSION_AT_LEAST(7,15,5)
309  if ( locSet.maxDownloadSpeed() != 0 )
310  setCurlOption(CURLOPT_MAX_RECV_SPEED_LARGE, locSet.maxDownloadSpeed());
311 #endif
312 
313  if ( locSet.cookieFileEnabled() ) {
314  DBG << _easyHandle << " " << "Cookie file enabled: " << _currentCookieFile << std::endl;
316  setCurlOption( CURLOPT_COOKIEFILE, _currentCookieFile.c_str() );
317  setCurlOption(CURLOPT_COOKIEJAR, _currentCookieFile.c_str() );
318  }
319 
320 #if CURLVERSION_AT_LEAST(7,18,0)
321  // bnc #306272
322  setCurlOption(CURLOPT_PROXY_TRANSFER_MODE, 1L );
323 #endif
324 
325  // Append settings custom headers to curl.
326  // TransferSettings assert strings are trimmed (HTTP/2 RFC 9113)
327  for ( const auto &header : locSet.headers() ) {
328  if ( !z_func()->addRequestHeader( header.c_str() ) )
330  }
331 
332  if ( _headers )
333  setCurlOption( CURLOPT_HTTPHEADER, _headers.get() );
334 
335  // set up ranges if required
337  if ( _requestedRanges.size() ) {
338 
339  std::sort( _requestedRanges.begin(), _requestedRanges.end(), []( const auto &elem1, const auto &elem2 ){
340  return ( elem1._start < elem2._start );
341  });
342 
343  CurlMultiPartHandler *helper = nullptr;
344  if ( auto initState = std::get_if<pending_t>(&_runningMode) ) {
345 
347  initState->_partialHelper = std::make_unique<CurlMultiPartHandler>(
348  multiPartMode
349  , _easyHandle
351  , *this
352  );
353  helper = initState->_partialHelper.get();
354 
355  } else if ( auto pendingState = std::get_if<prepareNextRangeBatch_t>(&_runningMode) ) {
356  helper = pendingState->_partialHelper.get();
357  } else {
358  errBuf = "Request is in invalid state to call setupHandle";
359  return false;
360  }
361 
362  if ( !helper->prepare () ) {
363  errBuf = helper->lastErrorMessage ();
364  return false;
365  }
366  }
367  }
368 
369  return true;
370 
371  } catch ( const zypp::Exception &excp ) {
372  ZYPP_CAUGHT(excp);
373  errBuf = excp.asString();
374  }
375  return false;
376  }
377 
379  {
380  auto rmode = std::get_if<NetworkRequestPrivate::running_t>( &_runningMode );
381  if ( !rmode ) {
382  DBG << _easyHandle << "Can only create output file in running mode" << std::endl;
383  return false;
384  }
385  // if we have no open file create or open it
386  if ( !rmode->_outFile ) {
387  std::string openMode = "w+b";
389  openMode = "r+b";
390 
391  rmode->_outFile = fopen( _targetFile.asString().c_str() , openMode.c_str() );
392 
393  //if the file does not exist create a new one
394  if ( !rmode->_outFile && _fMode == NetworkRequest::WriteShared ) {
395  rmode->_outFile = fopen( _targetFile.asString().c_str() , "w+b" );
396  }
397 
398  if ( !rmode->_outFile ) {
400  ,zypp::str::Format("Unable to open target file (%1%). Errno: (%2%:%3%)") % _targetFile.asString() % errno % strerr_cxx() );
401  return false;
402  }
403  }
404 
405  return true;
406  }
407 
409  {
410  // We can recover from RangeFail errors if the helper indicates it
411  auto rmode = std::get_if<NetworkRequestPrivate::running_t>( &_runningMode );
412  if ( rmode->_partialHelper ) return rmode->_partialHelper->canRecover();
413  return false;
414  }
415 
416  bool NetworkRequestPrivate::prepareToContinue( std::string &errBuf )
417  {
418  auto rmode = std::get_if<NetworkRequestPrivate::running_t>( &_runningMode );
419  if ( !rmode ) {
420  errBuf = "NetworkRequestPrivate::prepareToContinue called in invalid state";
421  return false;
422  }
423 
424  if ( rmode->_partialHelper && rmode->_partialHelper->hasMoreWork() ) {
425 
426  bool hadRangeFail = rmode->_partialHelper->lastError () == NetworkRequestError::RangeFail;
427 
428  _runningMode = prepareNextRangeBatch_t( std::move(std::get<running_t>( _runningMode )) );
429 
430  auto &prepMode = std::get<prepareNextRangeBatch_t>(_runningMode);
431  if ( !prepMode._partialHelper->prepareToContinue() ) {
432  errBuf = prepMode._partialHelper->lastErrorMessage();
433  return false;
434  }
435 
436  if ( hadRangeFail ) {
437  // we reset the handle to default values. We do this to not run into
438  // "transfer closed with outstanding read data remaining" error CURL sometimes returns when
439  // we cancel a connection because of a range error to request a smaller batch.
440  // The error will still happen but much less frequently than without resetting the handle.
441  //
442  // Note: Even creating a new handle will NOT fix the issue
443  curl_easy_reset( _easyHandle );
444  MIL << _easyHandle << " curl_easy_reset after hadRangeFail" << std::endl;
445  }
446  if ( !setupHandle(errBuf))
447  return false;
448 
449  return true;
450  }
451  errBuf = "Request has no more work";
452  return false;
453 
454  }
455 
457  {
458  // check if we have ranges that have never been requested
459  return std::any_of( _requestedRanges.begin(), _requestedRanges.end(), []( const auto &range ){ return range._rangeState == CurlMultiPartHandler::Pending; });
460  }
461 
463  {
464  bool isRangeContinuation = std::holds_alternative<prepareNextRangeBatch_t>( _runningMode );
465  if ( isRangeContinuation ) {
466  MIL << _easyHandle << " " << "Continuing a previously started range batch." << std::endl;
467  _runningMode = running_t( std::move(std::get<prepareNextRangeBatch_t>( _runningMode )) );
468  } else {
469  _runningMode = running_t( std::move(std::get<pending_t>( _runningMode )) );
470  }
471 
472  auto &m = std::get<running_t>( _runningMode );
473 
474  if ( m._activityTimer ) {
475  DBG_MEDIA << _easyHandle << " Setting activity timeout to: " << _settings.timeout() << std::endl;
476  m._activityTimer->connect( &Timer::sigExpired, *this, &NetworkRequestPrivate::onActivityTimeout );
477  m._activityTimer->start( static_cast<uint64_t>( _settings.timeout() * 1000 ) );
478  }
479 
480  if ( !isRangeContinuation )
481  _sigStarted.emit( *z_func() );
482  }
483 
485  {
486  if ( std::holds_alternative<running_t>(_runningMode) ) {
487  auto &rmode = std::get<running_t>( _runningMode );
488  if ( rmode._partialHelper )
489  rmode._partialHelper->finalize();
490  }
491  }
492 
494  {
495  finished_t resState;
496  resState._result = std::move(err);
497 
498  if ( std::holds_alternative<running_t>(_runningMode) ) {
499 
500  auto &rmode = std::get<running_t>( _runningMode );
501  resState._downloaded = rmode._downloaded;
502  resState._contentLenght = rmode._contentLenght;
503 
505  if ( _requestedRanges.size( ) ) {
506  //we have a successful download lets see if we got everything we needed
507  if ( !rmode._partialHelper->verifyData() ){
508  NetworkRequestError::Type err = rmode._partialHelper->lastError();
509  resState._result = NetworkRequestErrorPrivate::customError( err, std::string(rmode._partialHelper->lastErrorMessage()) );
510  }
511 
512  // if we have ranges we need to fill our digest from the full file
514  if ( fseek( rmode._outFile, 0, SEEK_SET ) != 0 ) {
515  resState._result = NetworkRequestErrorPrivate::customError( NetworkRequestError::InternalError, "Unable to set output file pointer." );
516  } else {
517  constexpr size_t bufSize = 4096;
518  char buf[bufSize];
519  while( auto cnt = fread(buf, 1, bufSize, rmode._outFile ) > 0 ) {
520  _fileVerification->_fileDigest.update(buf, cnt);
521  }
522  }
523  }
524  } // if ( _requestedRanges.size( ) )
525  }
526 
527  // finally check the file digest if we have one
529  const UByteArray &calcSum = _fileVerification->_fileDigest.digestVector ();
530  const UByteArray &expSum = zypp::Digest::hexStringToUByteArray( _fileVerification->_fileChecksum.checksum () );
531  if ( calcSum != expSum ) {
534  , (zypp::str::Format("Invalid file checksum %1%, expected checksum %2%")
535  % _fileVerification->_fileDigest.digest()
536  % _fileVerification->_fileChecksum.checksum () ) );
537  }
538  }
539 
540  rmode._outFile.reset();
541  }
542 
543  _runningMode = std::move( resState );
544  _sigFinished.emit( *z_func(), std::get<finished_t>(_runningMode)._result );
545  }
546 
548  {
550  _headers.reset( nullptr );
551  _errorBuf.fill( 0 );
553 
554  if ( _fileVerification )
555  _fileVerification->_fileDigest.reset ();
556 
557  std::for_each( _requestedRanges.begin (), _requestedRanges.end(), []( CurlMultiPartHandler::Range &range ) {
558  range.restart();
559  });
560  }
561 
563  {
564  MIL_MEDIA << _easyHandle << " Request timeout interval: " << t.interval()<< " remaining: " << t.remaining() << std::endl;
565  std::map<std::string, boost::any> extraInfo;
566  extraInfo.insert( {"requestUrl", _url } );
567  extraInfo.insert( {"filepath", _targetFile } );
568  _dispatcher->cancel( *z_func(), NetworkRequestErrorPrivate::customError( NetworkRequestError::Timeout, "Download timed out", std::move(extraInfo) ) );
569  }
570 
572  {
573  return std::string( _errorBuf.data() );
574  }
575 
577  {
578  if ( std::holds_alternative<running_t>( _runningMode ) ){
579  auto &rmode = std::get<running_t>( _runningMode );
580  if ( rmode._activityTimer && rmode._activityTimer->isRunning() )
581  rmode._activityTimer->start();
582  }
583  }
584 
585  int NetworkRequestPrivate::curlProgressCallback( void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow )
586  {
587  if ( !clientp )
588  return CURLE_OK;
589  NetworkRequestPrivate *that = reinterpret_cast<NetworkRequestPrivate *>( clientp );
590 
591  if ( !std::holds_alternative<running_t>(that->_runningMode) ){
592  DBG << that->_easyHandle << " " << "Curl progress callback was called in invalid state "<< that->z_func()->state() << std::endl;
593  return -1;
594  }
595  auto &rmode = std::get<running_t>( that->_runningMode );
596 
597  //reset the timer
598  that->resetActivityTimer();
599 
600  rmode._isInCallback = true;
601  if ( rmode._lastProgressNow != dlnow ) {
602  rmode._lastProgressNow = dlnow;
603  that->_sigProgress.emit( *that->z_func(), dltotal, dlnow, ultotal, ulnow );
604  }
605  rmode._isInCallback = false;
606 
607  return rmode._cachedResult ? CURLE_ABORTED_BY_CALLBACK : CURLE_OK;
608  }
609 
610  size_t NetworkRequestPrivate::headerfunction( char *ptr, size_t bytes )
611  {
612  //it is valid to call this function with no data to write, just return OK
613  if ( bytes == 0)
614  return 0;
615 
617 
619 
620  std::string_view hdr( ptr, bytes );
621 
622  hdr.remove_prefix( std::min( hdr.find_first_not_of(" \t\r\n"), hdr.size() ) );
623  const auto lastNonWhitespace = hdr.find_last_not_of(" \t\r\n");
624  if ( lastNonWhitespace != hdr.npos )
625  hdr.remove_suffix( hdr.size() - (lastNonWhitespace + 1) );
626  else
627  hdr = std::string_view();
628 
629  if ( !std::holds_alternative<running_t>(_runningMode) ){
630  DBG << _easyHandle << " " << "Curl headerfunction callback was called in invalid state "<< z_func()->state() << std::endl;
631  return -1;
632  }
633  auto &rmode = std::get<running_t>( _runningMode );
634  if ( !hdr.size() ) {
635  return ( bytes );
636  }
637  if ( _expectedFileSize && rmode._partialHelper ) {
638  const auto &repSize = rmode._partialHelper->reportedFileSize ();
639  if ( repSize && repSize != _expectedFileSize ) {
640  rmode._cachedResult = NetworkRequestErrorPrivate::customError( NetworkRequestError::InternalError, "Reported downloaded data length is not what was expected." );
641  return 0;
642  }
643  }
644  if ( zypp::strv::hasPrefixCI( hdr, "HTTP/" ) ) {
645 
646  long statuscode = 0;
647  (void)curl_easy_getinfo( _easyHandle, CURLINFO_RESPONSE_CODE, &statuscode);
648 
649  // if we have a status 204 we need to create a empty file
650  if( statuscode == 204 && !( _options & NetworkRequest::ConnectionTest ) && !( _options & NetworkRequest::HeadRequest ) )
652 
653  } else if ( zypp::strv::hasPrefixCI( hdr, "Location:" ) ) {
654  _lastRedirect = hdr.substr( 9 );
655  DBG << _easyHandle << " " << "redirecting to " << _lastRedirect << std::endl;
656 
657  } else if ( zypp::strv::hasPrefixCI( hdr, "Content-Length:") ) {
658  auto lenStr = str::trim( hdr.substr( 15 ), zypp::str::TRIM );
659  auto str = std::string ( lenStr.data(), lenStr.length() );
660  auto len = zypp::str::strtonum<typename zypp::ByteCount::SizeType>( str.data() );
661  if ( len > 0 ) {
662  DBG << _easyHandle << " " << "Got Content-Length Header: " << len << std::endl;
663  rmode._contentLenght = zypp::ByteCount(len, zypp::ByteCount::B);
664  }
665  }
666  }
667 
668  return bytes;
669  }
670 
671  size_t NetworkRequestPrivate::writefunction( char *data, std::optional<off_t> offset, size_t max )
672  {
673  //it is valid to call this function with no data to write, just return OK
674  if ( max == 0)
675  return 0;
676 
678 
679  //in case of a HEAD request, we do not write anything
681  return ( max );
682  }
683 
684  if ( !std::holds_alternative<running_t>(_runningMode) ){
685  DBG << _easyHandle << " " << "Curl writefunction callback was called in invalid state "<< z_func()->state() << std::endl;
686  return -1;
687  }
688  auto &rmode = std::get<running_t>( _runningMode );
689 
690  // if we have no open file create or open it
691  if ( !assertOutputFile() )
692  return 0;
693 
694  if ( offset ) {
695  // seek to the given offset
696  if ( fseek( rmode._outFile, *offset, SEEK_SET ) != 0 ) {
698  "Unable to set output file pointer." );
699  return 0;
700  }
701  rmode._currentFileOffset = *offset;
702  }
703 
704  if ( _expectedFileSize && rmode._partialHelper ) {
705  const auto &repSize = rmode._partialHelper->reportedFileSize ();
706  if ( repSize && repSize != _expectedFileSize ) {
707  rmode._cachedResult = NetworkRequestErrorPrivate::customError( NetworkRequestError::InternalError, "Reported downloaded data length is not what was expected." );
708  return 0;
709  }
710  }
711 
712  //make sure we do not write after the expected file size
713  if ( _expectedFileSize && static_cast<zypp::ByteCount::SizeType>( rmode._currentFileOffset + max) > _expectedFileSize ) {
714  rmode._cachedResult = NetworkRequestErrorPrivate::customError( NetworkRequestError::ExceededMaxLen, "Downloaded data exceeds expected length." );
715  return 0;
716  }
717 
718  auto written = fwrite( data, 1, max, rmode._outFile );
719  if ( written == 0 )
720  return 0;
721 
722  // if we are not downloading in ranges, we can update the file digest on the fly if we have one
723  if ( !rmode._partialHelper && _fileVerification ) {
724  _fileVerification->_fileDigest.update( data, written );
725  }
726 
727  rmode._currentFileOffset += written;
728 
729  // count the number of real bytes we have downloaded so far
730  rmode._downloaded += written;
731  _sigBytesDownloaded.emit( *z_func(), rmode._downloaded );
732 
733  return written;
734  }
735 
737  {
738  auto rmode = std::get_if<NetworkRequestPrivate::running_t>( &_runningMode );
739  if ( !rmode || !rmode->_partialHelper || !rmode->_partialHelper->hasError() )
740  return;
741 
742  // oldest cached result wins
743  if ( rmode->_cachedResult )
744  return;
745 
746  auto lastErr = NetworkRequestErrorPrivate::customError( rmode->_partialHelper->lastError() , std::string(rmode->_partialHelper->lastErrorMessage()) );
747  MIL_MEDIA << _easyHandle << " Multipart handler announced error code " << lastErr.toString () << std::endl;
748  rmode->_cachedResult = lastErr;
749  }
750 
752 
754  : Base ( *new NetworkRequestPrivate( std::move(url), std::move(targetFile), std::move(fMode), *this ) )
755  {
756  }
757 
759  {
760  Z_D();
761 
762  if ( d->_dispatcher )
763  d->_dispatcher->cancel( *this, "Request destroyed while still running" );
764  }
765 
767  {
768  d_func()->_expectedFileSize = std::move( expectedFileSize );
769  }
770 
772  {
773  return d_func()->_expectedFileSize;
774  }
775 
776  void NetworkRequest::setPriority( NetworkRequest::Priority prio, bool triggerReschedule )
777  {
778  Z_D();
779  d->_priority = prio;
780  if ( state() == Pending && triggerReschedule && d->_dispatcher )
781  d->_dispatcher->reschedule();
782  }
783 
785  {
786  return d_func()->_priority;
787  }
788 
789  void NetworkRequest::setOptions( Options opt )
790  {
791  d_func()->_options = opt;
792  }
793 
794  NetworkRequest::Options NetworkRequest::options() const
795  {
796  return d_func()->_options;
797  }
798 
799  void NetworkRequest::addRequestRange(size_t start, size_t len, std::optional<zypp::Digest> &&digest, CheckSumBytes expectedChkSum , std::any userData, std::optional<size_t> digestCompareLen, std::optional<size_t> chksumpad )
800  {
801  Z_D();
802  if ( state() == Running )
803  return;
804 
805  d->_requestedRanges.push_back( Range::make( start, len, std::move(digest), std::move( expectedChkSum ), std::move( userData ), digestCompareLen, chksumpad ) );
806  }
807 
809  {
810  Z_D();
811  if ( state() == Running )
812  return;
813 
814  d->_requestedRanges.push_back( std::move(range) );
815  auto &rng = d->_requestedRanges.back();
816  rng._rangeState = CurlMultiPartHandler::Pending;
817  rng.bytesWritten = 0;
818  if ( rng._digest )
819  rng._digest->reset();
820  }
821 
823  {
824  Z_D();
825  if ( state() == Running )
826  return false;
827 
828  zypp::Digest fDig;
829  if ( !fDig.create( expected.type () ) )
830  return false;
831 
832  d->_fileVerification = NetworkRequestPrivate::FileVerifyInfo{
833  ._fileDigest = std::move(fDig),
834  ._fileChecksum = expected
835  };
836  return true;
837  }
838 
840  {
841  Z_D();
842  if ( state() == Running )
843  return;
844  d->_requestedRanges.clear();
845  }
846 
847  std::vector<NetworkRequest::Range> NetworkRequest::failedRanges() const
848  {
849  const auto mystate = state();
850  if ( mystate != Finished && mystate != Error )
851  return {};
852 
853  Z_D();
854 
855  std::vector<Range> failed;
856  for ( auto &r : d->_requestedRanges ) {
857  if ( r._rangeState != CurlMultiPartHandler::Finished ) {
858  failed.push_back( r.clone() );
859  }
860  }
861  return failed;
862  }
863 
864  const std::vector<NetworkRequest::Range> &NetworkRequest::requestedRanges() const
865  {
866  return d_func()->_requestedRanges;
867  }
868 
869  const std::string &NetworkRequest::lastRedirectInfo() const
870  {
871  return d_func()->_lastRedirect;
872  }
873 
875  {
876  return d_func()->_easyHandle;
877  }
878 
879  std::optional<zyppng::NetworkRequest::Timings> NetworkRequest::timings() const
880  {
881  const auto myerr = error();
882  const auto mystate = state();
883  if ( mystate != Finished )
884  return {};
885 
886  Timings t;
887 
888  auto getMeasurement = [ this ]( const CURLINFO info, std::chrono::microseconds &target ){
889  using FPSeconds = std::chrono::duration<double, std::chrono::seconds::period>;
890  double val = 0;
891  const auto res = curl_easy_getinfo( d_func()->_easyHandle, info, &val );
892  if ( CURLE_OK == res ) {
893  target = std::chrono::duration_cast<std::chrono::microseconds>( FPSeconds(val) );
894  }
895  };
896 
897  getMeasurement( CURLINFO_NAMELOOKUP_TIME, t.namelookup );
898  getMeasurement( CURLINFO_CONNECT_TIME, t.connect);
899  getMeasurement( CURLINFO_APPCONNECT_TIME, t.appconnect);
900  getMeasurement( CURLINFO_PRETRANSFER_TIME , t.pretransfer);
901  getMeasurement( CURLINFO_TOTAL_TIME, t.total);
902  getMeasurement( CURLINFO_REDIRECT_TIME, t.redirect);
903 
904  return t;
905  }
906 
907  std::vector<char> NetworkRequest::peekData( off_t offset, size_t count ) const
908  {
909  Z_D();
910 
911  if ( !std::holds_alternative<NetworkRequestPrivate::running_t>( d->_runningMode) )
912  return {};
913 
914  const auto &rmode = std::get<NetworkRequestPrivate::running_t>( d->_runningMode );
915  return zypp::io::peek_data_fd( rmode._outFile, offset, count );
916  }
917 
919  {
920  return d_func()->_url;
921  }
922 
923  void NetworkRequest::setUrl(const Url &url)
924  {
925  Z_D();
926  if ( state() == NetworkRequest::Running )
927  return;
928 
929  d->_url = url;
930  }
931 
933  {
934  return d_func()->_targetFile;
935  }
936 
938  {
939  Z_D();
940  if ( state() == NetworkRequest::Running )
941  return;
942  d->_targetFile = path;
943  }
944 
946  {
947  return d_func()->_fMode;
948  }
949 
951  {
952  Z_D();
953  if ( state() == NetworkRequest::Running )
954  return;
955  d->_fMode = std::move( mode );
956  }
957 
958  std::string NetworkRequest::contentType() const
959  {
960  char *ptr = NULL;
961  if ( curl_easy_getinfo( d_func()->_easyHandle, CURLINFO_CONTENT_TYPE, &ptr ) == CURLE_OK && ptr )
962  return std::string(ptr);
963  return std::string();
964  }
965 
967  {
968  return std::visit([](auto& arg) -> zypp::ByteCount {
969  using T = std::decay_t<decltype(arg)>;
970  if constexpr (std::is_same_v<T, NetworkRequestPrivate::pending_t> || std::is_same_v<T, NetworkRequestPrivate::prepareNextRangeBatch_t> )
971  return zypp::ByteCount(0);
972  else if constexpr (std::is_same_v<T, NetworkRequestPrivate::running_t>
973  || std::is_same_v<T, NetworkRequestPrivate::finished_t>)
974  return arg._contentLenght;
975  else
976  static_assert(always_false<T>::value, "Unhandled state type");
977  }, d_func()->_runningMode);
978  }
979 
981  {
982  return std::visit([](auto& arg) -> zypp::ByteCount {
983  using T = std::decay_t<decltype(arg)>;
984  if constexpr (std::is_same_v<T, NetworkRequestPrivate::pending_t>)
985  return zypp::ByteCount();
986  else if constexpr (std::is_same_v<T, NetworkRequestPrivate::running_t>
987  || std::is_same_v<T, NetworkRequestPrivate::prepareNextRangeBatch_t>
988  || std::is_same_v<T, NetworkRequestPrivate::finished_t>)
989  return arg._downloaded;
990  else
991  static_assert(always_false<T>::value, "Unhandled state type");
992  }, d_func()->_runningMode);
993  }
994 
996  {
997  return d_func()->_settings;
998  }
999 
1001  {
1002  return std::visit([this](auto& arg) {
1003  using T = std::decay_t<decltype(arg)>;
1004  if constexpr (std::is_same_v<T, NetworkRequestPrivate::pending_t>)
1005  return Pending;
1006  else if constexpr (std::is_same_v<T, NetworkRequestPrivate::running_t> || std::is_same_v<T, NetworkRequestPrivate::prepareNextRangeBatch_t> )
1007  return Running;
1008  else if constexpr (std::is_same_v<T, NetworkRequestPrivate::finished_t>) {
1009  if ( std::get<NetworkRequestPrivate::finished_t>( d_func()->_runningMode )._result.isError() )
1010  return Error;
1011  else
1012  return Finished;
1013  }
1014  else
1015  static_assert(always_false<T>::value, "Unhandled state type");
1016  }, d_func()->_runningMode);
1017  }
1018 
1020  {
1021  const auto s = state();
1022  if ( s != Error && s != Finished )
1023  return NetworkRequestError();
1024  return std::get<NetworkRequestPrivate::finished_t>( d_func()->_runningMode)._result;
1025  }
1026 
1028  {
1029  if ( !hasError() )
1030  return std::string();
1031 
1032  return error().nativeErrorString();
1033  }
1034 
1036  {
1037  return error().isError();
1038  }
1039 
1040  bool NetworkRequest::addRequestHeader( const std::string &header )
1041  {
1042  Z_D();
1043 
1044  curl_slist *res = curl_slist_append( d->_headers ? d->_headers.get() : nullptr, header.c_str() );
1045  if ( !res )
1046  return false;
1047 
1048  if ( !d->_headers )
1049  d->_headers = std::unique_ptr< curl_slist, decltype (&curl_slist_free_all) >( res, &curl_slist_free_all );
1050 
1051  return true;
1052  }
1053 
1055  {
1056  return d_func()->_currentCookieFile;
1057  }
1058 
1060  {
1061  d_func()->_currentCookieFile = std::move(cookieFile);
1062  }
1063 
1065  {
1066  return d_func()->_sigStarted;
1067  }
1068 
1070  {
1071  return d_func()->_sigBytesDownloaded;
1072  }
1073 
1075  {
1076  return d_func()->_sigProgress;
1077  }
1078 
1080  {
1081  return d_func()->_sigFinished;
1082  }
1083 
1084 }
std::string getScheme() const
Returns the scheme name of the URL.
Definition: Url.cc:560
Signal< void(NetworkRequest &req)> _sigStarted
Definition: request_p.h:129
long timeout() const
transfer timeout
const Pathname & certificateAuthoritiesPath() const
SSL certificate authorities path ( default: /etc/ssl/certs )
std::string errorMessage() const
Definition: request.cc:571
bool isError() const
isError Will return true if this is a actual error
T trim(StrType &&s, const Trim trim_r)
Definition: string.h:35
#define MIL
Definition: Logger.h:103
void setCurlOption(CURLoption opt, T data)
Definition: request_p.h:98
std::string curlUnEscape(const std::string &text_r)
Definition: curlhelper.cc:394
std::optional< Timings > timings() const
After the request is finished query the timings that were collected during download.
Definition: request.cc:879
void * nativeHandle() const
Definition: request.cc:874
#define DBG_MEDIA
Definition: mediadebug_p.h:28
zypp::ByteCount reportedByteCount() const
Returns the number of bytes that are reported from the backend as the full download size...
Definition: request.cc:966
const std::vector< Range > & requestedRanges() const
Definition: request.cc:864
const Pathname & clientCertificatePath() const
SSL client certificate file.
std::chrono::microseconds connect
Definition: request.h:80
std::array< char, CURL_ERROR_SIZE+1 > _errorBuf
Definition: request_p.h:95
void addHeader(std::string &&val_r)
add a header, on the form "Foo: Bar" (trims)
uint64_t interval() const
Definition: timer.cc:94
std::optional< FileVerifyInfo > _fileVerification
The digest for the full file.
Definition: request_p.h:117
The CurlMultiPartHandler class.
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:459
void addRequestRange(size_t start, size_t len=0, std::optional< zypp::Digest > &&digest={}, CheckSumBytes expectedChkSum=CheckSumBytes(), std::any userData=std::any(), std::optional< size_t > digestCompareLen={}, std::optional< size_t > chksumpad={})
Definition: request.cc:799
std::string proxyUserPassword() const
returns the proxy user and password as a user:pass string
SignalProxy< void(NetworkRequest &req, zypp::ByteCount count)> sigBytesDownloaded()
Signals that new data has been downloaded, this is only the payload and does not include control data...
Definition: request.cc:1069
int assert_file_mode(const Pathname &path, unsigned mode)
Like assert_file but enforce mode even if the file already exists.
Definition: PathInfo.cc:1224
bool hasPrefixCI(const C_Str &str_r, const C_Str &prefix_r)
Definition: String.h:1101
Compute Message Digests (MD5, SHA1 etc)
Definition: Digest.h:37
NetworkRequest::FileMode _fMode
Definition: request_p.h:119
Store and operate with byte count.
Definition: ByteCount.h:31
const std::string & lastRedirectInfo() const
Definition: request.cc:869
long maxDownloadSpeed() const
Maximum download speed (bytes per second)
static Range make(size_t start, size_t len=0, std::optional< zypp::Digest > &&digest={}, CheckSumBytes &&expectedChkSum=CheckSumBytes(), std::any &&userData=std::any(), std::optional< size_t > digestCompareLen={}, std::optional< size_t > _dataBlockPadding={})
std::chrono::microseconds pretransfer
Definition: request.h:82
Holds transfer setting.
zypp::ByteCount downloadedByteCount() const
Returns the number of already downloaded bytes as reported by the backend.
Definition: request.cc:980
const std::string & authType() const
get the allowed authentication types
NetworkRequest::Options _options
Definition: request_p.h:109
bool verifyHostEnabled() const
Whether to verify host for ssl.
const std::string & proxyUsername() const
proxy auth username
const char * c_str() const
String representation.
Definition: Pathname.h:113
String related utilities and Regular expression matching.
Definition: ansi.h:854
std::chrono::microseconds appconnect
Definition: request.h:81
constexpr bool always_false
Definition: PathInfo.cc:563
running_t(pending_t &&prevState)
Definition: request.cc:63
std::string nativeErrorString() const
Signal< void(NetworkRequest &req, zypp::ByteCount count)> _sigBytesDownloaded
Definition: request_p.h:130
Convenient building of std::string with boost::format.
Definition: String.h:253
Structure holding values of curlrc options.
Definition: curlconfig.h:26
void setOptions(Options opt)
Definition: request.cc:789
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition: String.cc:39
~NetworkRequestPrivate() override
Definition: request.cc:81
TransferSettings & transferSettings()
Definition: request.cc:995
enum zyppng::NetworkRequestPrivate::ProtocolMode _protocolMode
void setExpectedFileSize(zypp::ByteCount expectedFileSize)
Definition: request.cc:766
const std::string & password() const
auth password
const std::string & username() const
auth username
void setFileOpenMode(FileMode mode)
Sets the file open mode to mode.
Definition: request.cc:950
bool hasError() const
Checks if there was a error with the request.
Definition: request.cc:1035
void onActivityTimeout(Timer &)
Definition: request.cc:562
SignalProxy< void(Timer &t)> sigExpired()
This signal is always emitted when the timer expires.
Definition: timer.cc:120
const Headers & headers() const
returns a list of all added headers (trimmed)
#define Z_D()
Definition: zyppglobal.h:98
int ZYPP_MEDIA_CURL_IPRESOLVE()
4/6 to force IPv4/v6
Definition: curlhelper.cc:45
const zypp::Pathname & cookieFile() const
Definition: request.cc:1054
zypp::Pathname _targetFile
Definition: request_p.h:107
bool verifyPeerEnabled() const
Whether to verify peer for ssl.
bool empty() const
Test for an empty path.
Definition: Pathname.h:117
void setUrl(const Url &url)
This will change the URL of the request.
Definition: request.cc:923
std::chrono::microseconds namelookup
Definition: request.h:79
static int parseConfig(CurlConfig &config, const std::string &filename="")
Parse a curlrc file and store the result in the config structure.
Definition: curlconfig.cc:24
std::string asString() const
Returns a default string representation of the Url object.
Definition: Url.cc:524
zypp::Pathname _currentCookieFile
Definition: request_p.h:123
bool hasCredentials() const
has a username, maybe even the password
bool addRequestHeader(const std::string &header)
Definition: request.cc:1040
std::string trim(const std::string &s, const Trim trim_r)
Definition: String.cc:226
const std::string & asString() const
String representation.
Definition: Pathname.h:94
Signal< void(NetworkRequest &req, off_t dltotal, off_t dlnow, off_t ultotal, off_t ulnow)> _sigProgress
Definition: request_p.h:131
std::string asString() const
Error message provided by dumpOn as string.
Definition: Exception.cc:124
long connectTimeout() const
connection timeout
void notifyErrorCodeChanged() override
Definition: request.cc:736
bool initialize(std::string &errBuf)
Definition: request.cc:92
The NetworkRequestError class Represents a error that occured in.
The Timer class provides repetitive and single-shot timers.
Definition: timer.h:44
std::vector< char > peekData(off_t offset, size_t count) const
Definition: request.cc:907
NetworkRequestError error() const
Returns the last set Error.
Definition: request.cc:1019
zypp::ByteCount _expectedFileSize
Definition: request_p.h:110
std::string extendedErrorString() const
In some cases, curl can provide extended error information collected at runtime.
Definition: request.cc:1027
Priority priority() const
Definition: request.cc:784
std::string proxyuserpwd
Definition: curlconfig.h:49
bool setupHandle(std::string &errBuf)
Definition: request.cc:105
const Pathname & clientKeyPath() const
SSL client key file.
std::vector< char > peek_data_fd(FILE *fd, off_t offset, size_t count)
Definition: IOTools.cc:171
bool create(const std::string &name)
initialize creation of a new message digest
Definition: Digest.cc:198
const zypp::Pathname & targetFilePath() const
Returns the target filename path.
Definition: request.cc:932
size_t writefunction(char *ptr, std::optional< off_t > offset, size_t bytes) override
Definition: request.cc:671
std::unique_ptr< curl_slist, decltype(&curl_slist_free_all) > _headers
Definition: request_p.h:140
uint64_t remaining() const
Definition: timer.cc:99
long minDownloadSpeed() const
Minimum download speed (bytes per second) until the connection is dropped.
#define MIL_MEDIA
Definition: mediadebug_p.h:29
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition: Exception.h:475
bool proxyEnabled() const
proxy is enabled
void setTargetFilePath(const zypp::Pathname &path)
Changes the target file path of the download.
Definition: request.cc:937
void setCookieFile(zypp::Pathname cookieFile)
Definition: request.cc:1059
static int curlProgressCallback(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
Definition: request.cc:585
std::string contentType() const
Returns the content type as reported from the server.
Definition: request.cc:958
std::string strerr_cxx(const int err=-1)
static const Unit B
1 Byte
Definition: ByteCount.h:43
bool setExpectedFileChecksum(const zypp::CheckSum &expected)
Definition: request.cc:822
Base class for Exception.
Definition: Exception.h:152
std::string _lastRedirect
to log/report redirections
Definition: request_p.h:122
std::chrono::microseconds total
Definition: request.h:83
bool any_of(const Container &c, Fnc &&cb)
Definition: Algorithm.h:76
std::string getHost(EEncoding eflag=zypp::url::E_DECODED) const
Returns the hostname or IP from the URL authority.
Definition: Url.cc:615
void setupZYPP_MEDIA_CURL_DEBUG(CURL *curl)
Setup CURLOPT_VERBOSE and CURLOPT_DEBUGFUNCTION according to env::ZYPP_MEDIA_CURL_DEBUG.
Definition: curlhelper.cc:130
void setPriority(Priority prio, bool triggerReschedule=true)
Definition: request.cc:776
State state() const
Returns the current state the HttpDownloadRequest is in.
Definition: request.cc:1000
std::ostream & logCredentials(std::ostream &str) const
log credentials to stream hiding the password.
TransferSettings _settings
Definition: request_p.h:108
NetworkRequestDispatcher * _dispatcher
Definition: request_p.h:126
ZYPP_IMPL_PRIVATE(UnixSignalSource)
static long auth_type_str2long(std::string &auth_type_str)
Converts a string of comma separated list of authetication type names into a long of ORed CURLAUTH_* ...
Definition: curlauthdata.cc:50
void setUserAgentString(std::string &&val_r)
sets the user agent ie: "Mozilla v3" (trims)
Options options() const
Definition: request.cc:794
std::vector< NetworkRequest::Range > _requestedRanges
the requested ranges that need to be downloaded
Definition: request_p.h:111
std::chrono::microseconds redirect
Definition: request.h:84
SignalProxy< void(NetworkRequest &req, const NetworkRequestError &err)> sigFinished()
Signals that the download finished.
Definition: request.cc:1079
typename decay< T >::type decay_t
Definition: TypeTraits.h:42
Signal< void(NetworkRequest &req, const NetworkRequestError &err)> _sigFinished
Definition: request_p.h:132
size_t headerfunction(char *ptr, size_t bytes) override
Definition: request.cc:610
Type type() const
type Returns the type of the error
SignalProxy< void(NetworkRequest &req)> sigStarted()
Signals that the dispatcher dequeued the request and actually starts downloading data.
Definition: request.cc:1064
zypp::ByteCount expectedFileSize() const
Definition: request.cc:771
#define EXPLICITLY_NO_PROXY
Definition: curlhelper_p.h:23
FileMode fileOpenMode() const
Returns the currently configured file open mode.
Definition: request.cc:945
std::vector< Range > failedRanges() const
Definition: request.cc:847
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:1
NetworkRequestPrivate(Url &&url, zypp::Pathname &&targetFile, NetworkRequest::FileMode fMode, NetworkRequest &p)
Definition: request.cc:73
CURLcode setCurlRedirProtocols(CURL *curl)
Definition: curlhelper.cc:544
void setResult(NetworkRequestError &&err)
Definition: request.cc:493
const std::string & proxy() const
proxy host
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.
Definition: request.cc:1074
bool prepareToContinue(std::string &errBuf)
Definition: request.cc:416
~NetworkRequest() override
Definition: request.cc:758
const std::string & userAgentString() const
user agent string (trimmed)
Url manipulation class.
Definition: Url.h:92
bool headRequestsAllowed() const
whether HEAD requests are allowed
#define DBG
Definition: Logger.h:102
ZYppCommitResult & _result
Definition: TargetImpl.cc:1726
std::variant< pending_t, running_t, prepareNextRangeBatch_t, finished_t > _runningMode
Definition: request_p.h:188