13#include <zypp-core/zyppng/base/EventDispatcher>
14#include <zypp-core/zyppng/base/private/linuxhelpers_p.h>
15#include <zypp-core/zyppng/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/Pathname.h>
31#include <boost/variant.hpp>
32#include <boost/variant/polymorphic_get.hpp>
38 static size_t nwr_headerCallback (
char *ptr,
size_t size,
size_t nmemb,
void *userdata ) {
42 NetworkRequestPrivate *that =
reinterpret_cast<NetworkRequestPrivate *
>( userdata );
43 return that->headerCallback( ptr, size, nmemb );
45 static size_t nwr_writeCallback (
char *ptr,
size_t size,
size_t nmemb,
void *userdata ) {
49 NetworkRequestPrivate *that =
reinterpret_cast<NetworkRequestPrivate *
>( userdata );
50 return that->writeCallback( ptr, size, nmemb );
54 template<
class T>
struct always_false : std::false_type {};
57 std::vector<char>
peek_data_fd( FILE *fd, off_t offset,
size_t count )
64 std::vector<char> data( count + 1 ,
'\0' );
67 while ((l = pread( fileno( fd ), data.data(), count, offset ) ) == -1 && errno == EINTR)
81 ._digest = std::move( digest ),
82 ._checksum = std::move( expectedChkSum ),
83 ._relevantDigestLen = std::move( digestCompareLen ),
84 ._chksumPad = std::move( dataBlockPadding ),
91 : _outFile(
std::move(prevState._outFile) )
92 , _downloaded( prevState._downloaded )
93 , _rangeAttemptIdx( prevState._rangeAttemptIdx )
97 : _requireStatusPartial( prevState._requireStatusPartial )
101 : _outFile(
std::move(prevState._outFile) )
102 , _requireStatusPartial( true )
103 , _downloaded( prevState._downloaded )
104 , _rangeAttemptIdx( prevState._rangeAttemptIdx )
112 ,
_headers(
std::unique_ptr< curl_slist, decltype (&curl_slist_free_all) >(
nullptr, &curl_slist_free_all ) )
142 const std::string urlScheme =
_url.getScheme();
143 if ( urlScheme ==
"http" || urlScheme ==
"https" )
155 std::string urlBuffer(
_url.asString() );
182 std::visit( [&](
auto &arg ){
183 using T = std::decay_t<
decltype(arg)>;
184 if constexpr ( std::is_same_v<T, pending_t> ) {
185 arg._requireStatusPartial =
false;
187 DBG <<
_easyHandle <<
" " <<
"NetworkRequestPrivate::setupHandle called in unexpected state" << std::endl;
202 const auto &cHeaders =
_dispatcher->hostSpecificHeaders();
203 if (
auto i = cHeaders.find(
_url.getHost()); i != cHeaders.end() ) {
204 for (
const auto &[key, value] : i->second ) {
206 "%s: %s", key.c_str(), value.c_str() )
217 case 4:
setCurlOption( CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );
break;
218 case 6:
setCurlOption( CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6 );
break;
222 setCurlOption( CURLOPT_HEADERFUNCTION, &nwr_headerCallback );
237 if ( urlScheme ==
"https" )
239#if CURLVERSION_AT_LEAST(7,19,4)
241 if (
_url.getHost() ==
"download.opensuse.org" ) {
242#if CURLVERSION_AT_LEAST(7,85,0)
245 setCurlOption( CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS );
248#if CURLVERSION_AT_LEAST(7,85,0)
271#ifdef CURLSSLOPT_ALLOW_BEAST
273 setCurlOption( CURLOPT_SSL_OPTIONS, CURLSSLOPT_ALLOW_BEAST );
300 if (use_auth.empty())
301 use_auth =
"digest,basic";
303 if( auth != CURLAUTH_NONE)
305 DBG <<
_easyHandle <<
" " <<
"Enabling HTTP authentication methods: " << use_auth
306 <<
" (CURLOPT_HTTPAUTH=" << auth <<
")" << std::endl;
315 setCurlOption(CURLOPT_PROXYAUTH, CURLAUTH_BASIC|CURLAUTH_DIGEST|CURLAUTH_NTLM );
326 if ( proxyuserpwd.empty() )
331 DBG <<
_easyHandle <<
" " <<
"Proxy: ~/.curlrc does not contain the proxy-user option" << std::endl;
335 DBG <<
_easyHandle <<
" " <<
"Proxy: using proxy-user from ~/.curlrc" << std::endl;
343 if ( ! proxyuserpwd.empty() )
348#if CURLVERSION_AT_LEAST(7,19,4)
353 DBG <<
_easyHandle <<
" " <<
"Proxy: explicitly NOPROXY" << std::endl;
368#if CURLVERSION_AT_LEAST(7,15,5)
380#if CURLVERSION_AT_LEAST(7,18,0)
387 for (
const auto &header : locSet.
headers() ) {
388 if ( !z_func()->addRequestHeader( header.c_str() ) )
406 auto rmode = std::get_if<NetworkRequestPrivate::running_t>( &
_runningMode );
408 DBG <<
_easyHandle <<
"Can only create output file in running mode" << std::endl;
412 if ( !rmode->_outFile ) {
413 std::string openMode =
"w+b";
424 if ( !rmode->_outFile ) {
437 auto rmode = std::get_if<NetworkRequestPrivate::running_t>( &
_runningMode );
445 auto rmode = std::get_if<NetworkRequestPrivate::running_t>( &
_runningMode );
450 if ( rmode->_rangeAttemptIdx + 1 >=
sizeof(
_rangeAttempt ) ) {
451 errBuf =
"No more range batch sizes available";
454 rmode->_rangeAttemptIdx++;
470 errBuf =
"Request has no more work";
478 errBuf =
"Calling the prepareNextRangeBatch function without a range to download is not supported.";
482 std::string rangeDesc;
483 uint rangesAdded = 0;
485 errBuf =
"Using more than one range is not supported with protocols other than HTTP/HTTPS";
491 if ( !std::holds_alternative<pending_t>(
_runningMode ) ) {
497 std::get<pending_t>(
_runningMode )._requireStatusPartial =
false;
501 return ( elem1.start < elem2.start );
504 if ( std::holds_alternative<pending_t>(
_runningMode ) )
505 std::get<pending_t>(
_runningMode )._requireStatusPartial =
true;
508 if ( std::holds_alternative<prepareNextRangeBatch_t>(
_runningMode ) )
512 auto addRangeString = [ &rangeDesc, &rangesAdded ](
const std::pair<size_t, size_t> &range ) {
513 std::string rangeD =
zypp::str::form(
"%llu-",
static_cast<unsigned long long>( range.first ) );
514 if( range.second > 0 )
515 rangeD.append(
zypp::str::form(
"%llu",
static_cast<unsigned long long>( range.second ) ) );
517 if ( rangeDesc.size() )
518 rangeDesc.append(
",").append( rangeD );
520 rangeDesc = std::move( rangeD );
525 std::optional<std::pair<size_t, size_t>> currentZippedRange;
526 bool closedRange =
true;
533 range.bytesWritten = 0;
537 if ( !closedRange ) {
538 errBuf =
"It is not supported to request more ranges after a open range.";
542 const auto rangeEnd = range.len > 0 ? range.start + range.len - 1 : 0;
543 closedRange = (rangeEnd > 0);
547 range.bytesWritten = 0;
549 range._digest->reset();
553 if ( !currentZippedRange ) {
554 currentZippedRange = std::make_pair( range.start, rangeEnd );
557 if ( currentZippedRange->second + 1 == range.start ) {
558 currentZippedRange->second = rangeEnd;
561 addRangeString( *currentZippedRange );
562 currentZippedRange = std::make_pair( range.start, rangeEnd );
566 if ( rangesAdded >= maxRanges ) {
567 MIL <<
_easyHandle <<
" " <<
"Reached max nr of ranges (" << maxRanges <<
"), batching the request to not break the server" << std::endl;
573 if ( currentZippedRange )
574 addRangeString( *currentZippedRange );
576 MIL <<
_easyHandle <<
" " <<
"Requesting Ranges: " << rangeDesc << std::endl;
592 bool isRangeContinuation = std::holds_alternative<prepareNextRangeBatch_t>(
_runningMode );
593 if ( isRangeContinuation ) {
594 MIL <<
_easyHandle <<
" " <<
"Continuing a previously started range batch." << std::endl;
599 mode._currentRange = 0;
606 if ( m._activityTimer ) {
612 if ( !isRangeContinuation )
618 if ( std::holds_alternative<running_t>(
_runningMode) ) {
621 if ( rmode._currentRange >= 0 ) {
623 rmode._currentRange = -1;
633 resState.
_result = std::move(err);
635 if ( std::holds_alternative<running_t>(
_runningMode) ) {
638 rmode._outFile.reset();
646 if ( r.len > 0 && r.bytesWritten != r.len )
671 range._rangeState = NetworkRequest::Pending;
679 MIL_MEDIA <<
_easyHandle <<
" Request timeout interval: " << t.interval()<<
" remaining: " << t.remaining() << std::endl;
680 std::map<std::string, boost::any> extraInfo;
681 extraInfo.insert( {
"requestUrl",
_url } );
689 auto bytesHashed = rng.
_digest->bytesHashed ();
693 rng.
_digest->update( padding.data(), padding.size() );
695 auto digVec = rng.
_digest->digestVector();
727 DBG <<
_easyHandle <<
" " <<
"Invalid Content-Range Header format: '" << std::string(line) << std::endl;
731 size_t s = zypp::str::strtonum<size_t>( what[1]);
732 size_t e = zypp::str::strtonum<size_t>( what[2]);
733 start = std::move(s);
744 if ( what.
size() >= 2 ) {
759 if ( std::holds_alternative<running_t>(
_runningMode ) ){
761 if ( rmode._activityTimer && rmode._activityTimer->isRunning() )
762 rmode._activityTimer->start();
772 if ( !std::holds_alternative<running_t>(that->
_runningMode) ){
773 DBG << that->
_easyHandle <<
" " <<
"Curl progress callback was called in invalid state "<< that->z_func()->state() << std::endl;
777 auto &rmode = std::get<running_t>( that->
_runningMode );
782 rmode._isInCallback =
true;
783 if ( rmode._lastProgressNow != dlnow ) {
784 rmode._lastProgressNow = dlnow;
785 that->
_sigProgress.emit( *that->z_func(), dltotal, dlnow, ultotal, ulnow );
787 rmode._isInCallback =
false;
789 return rmode._cachedResult ? CURLE_ABORTED_BY_CALLBACK : CURLE_OK;
795 if ( size * nmemb == 0)
802 std::string_view hdr( ptr, size*nmemb );
804 hdr.remove_prefix( std::min( hdr.find_first_not_of(
" \t\r\n"), hdr.size() ) );
805 const auto lastNonWhitespace = hdr.find_last_not_of(
" \t\r\n");
806 if ( lastNonWhitespace != hdr.npos )
807 hdr.remove_suffix( hdr.size() - (lastNonWhitespace + 1) );
809 hdr = std::string_view();
813 return ( size * nmemb );
815 if ( zypp::strv::hasPrefixCI( hdr,
"HTTP/" ) ) {
818 (void)curl_easy_getinfo(
_easyHandle, CURLINFO_RESPONSE_CODE, &statuscode);
820 const auto &doRangeFail = [&](){
821 WAR <<
_easyHandle <<
" " <<
"Range FAIL, trying with a smaller batch" << std::endl;
826 if ( range._rangeState == NetworkRequest::Running )
827 range._rangeState = NetworkRequest::Pending;
836 if ( rmode._requireStatusPartial ) {
838 if ( ( statuscode >= 200 && statuscode <= 299 && statuscode != 206 )
839 || statuscode == 416 ) {
840 return doRangeFail();
844 }
else if ( zypp::strv::hasPrefixCI( hdr,
"Location:" ) ) {
848 }
else if ( zypp::strv::hasPrefixCI( hdr,
"Content-Type:") ) {
851 rmode._gotMultiRangeHeader =
true;
852 rmode._seperatorString =
"--"+sep;
854 }
else if ( zypp::strv::hasPrefixCI( hdr,
"Content-Range:") ) {
861 rmode._gotContentRangeHeader =
true;
862 rmode._currentSrvRange = r;
864 }
else if ( zypp::strv::hasPrefixCI( hdr,
"Content-Length:") ) {
866 auto str = std::string ( lenStr.data(), lenStr.length() );
867 auto len = zypp::str::strtonum<typename zypp::ByteCount::SizeType>(
str.data() );
869 DBG <<
_easyHandle <<
" " <<
"Got Content-Length Header: " << len << std::endl;
875 return ( size * nmemb );
880 const auto max = ( size * nmemb );
890 return ( size * nmemb );
895 auto writeDataToFile = [
this, &rmode ]( off_t offset,
const char *data,
size_t len ) -> off_t {
897 if ( rmode._currentRange < 0 ) {
898 DBG <<
_easyHandle <<
" " <<
"Current range is zero in write request" << std::endl;
908 if ( fseek( rmode._outFile, offset, SEEK_SET ) != 0 ) {
910 "Unable to set output file pointer." );
916 const auto bytesToWrite = rng.len > 0 ? std::min( rng.len - rng.bytesWritten, len ) : len;
924 auto written = fwrite( data, 1, bytesToWrite, rmode._outFile );
928 if ( rng._digest && rng._checksum.size() ) {
929 if ( !rng._digest->update( data, written ) )
933 rng.bytesWritten += written;
934 if ( rmode._currentSrvRange ) rmode._currentSrvRange->bytesWritten += written;
936 if ( rng.len > 0 && rng.bytesWritten >= rng.len ) {
937 rmode._currentRange = -1;
941 if ( rmode._currentSrvRange && rmode._currentSrvRange->len > 0 && rmode._currentSrvRange->bytesWritten >= rmode._currentSrvRange->len ) {
942 rmode._currentSrvRange.reset();
945 rmode._currentRange = -1;
949 rmode._downloaded += written;
956 size_t bytesWrittenSoFar = 0;
958 while ( bytesWrittenSoFar != max ) {
963 if ( !rmode._allHeadersReceived ) {
964 rmode._allHeadersReceived =
true;
967 if ( !rmode._gotMultiRangeHeader && !rmode._gotContentRangeHeader ) {
969 if ( rmode._requireStatusPartial ) {
972 "Invalid data from server, range respone was announced but there was no range definiton." );
982 rmode._currentRange = 0;
987 if ( rmode._currentSrvRange && rmode._currentRange == -1 ) {
993 std::optional<uint> foundRange;
994 const size_t beginRange = rmode._currentSrvRange->start + rmode._currentSrvRange->bytesWritten;
995 const size_t endRange = beginRange + (rmode._currentSrvRange->len - rmode._currentSrvRange->bytesWritten);
996 auto currDist = ULONG_MAX;
1005 if ( currR.len == currR.bytesWritten )
1008 const auto currRBegin = currR.start + currR.bytesWritten;
1009 if ( !( beginRange <= currRBegin && endRange >= currRBegin ) )
1013 const auto newDist = currRBegin - beginRange;
1015 if ( !foundRange ) {
1020 if ( newDist < currDist ) {
1026 if ( !foundRange ) {
1028 ,
"Unable to find a matching range for data returned by the server." );
1033 rmode._currentRange = *foundRange;
1039 const auto skipBytes = seekTo - beginRange;
1040 bytesWrittenSoFar += skipBytes;
1041 rmode._currentSrvRange->bytesWritten += skipBytes;
1044 if ( rmode._currentRange >= 0 ) {
1045 auto availableData = max - bytesWrittenSoFar;
1046 if ( rmode._currentSrvRange ) {
1047 availableData = std::min( availableData, rmode._currentSrvRange->len - rmode._currentSrvRange->bytesWritten );
1049 auto bw = writeDataToFile( seekTo, ptr + bytesWrittenSoFar, availableData );
1053 bytesWrittenSoFar += bw;
1056 if ( bytesWrittenSoFar == max )
1059 if ( rmode._currentRange == -1 ) {
1062 if ( rmode._currentSrvRange )
1065 std::string_view incoming( ptr + bytesWrittenSoFar, max - bytesWrittenSoFar );
1066 auto hdrEnd = incoming.find(
"\r\n\r\n");
1067 if ( hdrEnd == incoming.npos ) {
1069 rmode._rangePrefaceBuffer.insert( rmode._rangePrefaceBuffer.end(), incoming.begin(), incoming.end() );
1074 rmode._rangePrefaceBuffer.insert( rmode._rangePrefaceBuffer.end(), incoming.begin(), incoming.begin() + ( hdrEnd + 4 ) );
1075 bytesWrittenSoFar += ( hdrEnd + 4 );
1077 std::string_view data( rmode._rangePrefaceBuffer.data(), rmode._rangePrefaceBuffer.size() );
1078 auto sepStrIndex = data.find( rmode._seperatorString );
1079 if ( sepStrIndex == data.npos ) {
1081 "Invalid multirange header format, seperator string missing." );
1085 auto startOfHeader = sepStrIndex + rmode._seperatorString.length();
1086 std::vector<std::string_view> lines;
1087 zypp::strv::split( data.substr( startOfHeader ),
"\r\n", zypp::strv::Trim::trim, [&]( std::string_view strv ) { lines.push_back(strv); } );
1088 for (
const auto &hdrLine : lines ) {
1089 if ( zypp::strv::hasPrefixCI(hdrLine,
"Content-Range:") ) {
1096 rmode._currentSrvRange = r;
1101 rmode._rangePrefaceBuffer.clear();
1104 return bytesWrittenSoFar;
1118 if ( d->_dispatcher )
1119 d->_dispatcher->cancel( *
this,
"Request destroyed while still running" );
1124 d_func()->_expectedFileSize = std::move( expectedFileSize );
1130 d->_priority = prio;
1131 if ( state() == Pending && triggerReschedule && d->_dispatcher )
1132 d->_dispatcher->reschedule();
1137 return d_func()->_priority;
1142 d_func()->_options = opt;
1147 return d_func()->_options;
1153 if ( state() == Running )
1156 d->_requestedRanges.push_back( Range::make( start, len, std::move(digest), std::move( expectedChkSum ), std::move( userData ), digestCompareLen, chksumpad ) );
1162 if ( state() == Running )
1165 d->_requestedRanges.push_back( range );
1166 auto &rng = d->_requestedRanges.back();
1168 rng.bytesWritten = 0;
1170 rng._digest->reset();
1176 if ( state() == Running )
1178 d->_requestedRanges.clear();
1183 const auto mystate = state();
1184 if ( mystate != Finished && mystate != Error )
1189 std::vector<Range> failed;
1190 for (
const auto &r : d->_requestedRanges ) {
1192 failed.push_back( r );
1199 return d_func()->_requestedRanges;
1204 return d_func()->_lastRedirect;
1209 return d_func()->_easyHandle;
1214 const auto myerr = error();
1215 const auto mystate = state();
1216 if ( mystate != Finished )
1221 auto getMeasurement = [ this ](
const CURLINFO info, std::chrono::microseconds &target ){
1222 using FPSeconds = std::chrono::duration<double, std::chrono::seconds::period>;
1224 const auto res = curl_easy_getinfo( d_func()->
_easyHandle, info, &val );
1225 if ( CURLE_OK == res ) {
1226 target = std::chrono::duration_cast<std::chrono::microseconds>( FPSeconds(val) );
1230 getMeasurement( CURLINFO_NAMELOOKUP_TIME, t.
namelookup );
1231 getMeasurement( CURLINFO_CONNECT_TIME, t.
connect);
1232 getMeasurement( CURLINFO_APPCONNECT_TIME, t.
appconnect);
1233 getMeasurement( CURLINFO_PRETRANSFER_TIME , t.
pretransfer);
1234 getMeasurement( CURLINFO_TOTAL_TIME, t.
total);
1235 getMeasurement( CURLINFO_REDIRECT_TIME, t.
redirect);
1244 if ( !std::holds_alternative<NetworkRequestPrivate::running_t>( d->_runningMode) )
1247 const auto &rmode = std::get<NetworkRequestPrivate::running_t>( d->_runningMode );
1253 return d_func()->_url;
1267 return d_func()->_targetFile;
1275 d->_targetFile = path;
1280 return d_func()->_fMode;
1288 d->_fMode = std::move( mode );
1294 if ( curl_easy_getinfo( d_func()->
_easyHandle, CURLINFO_CONTENT_TYPE, &ptr ) == CURLE_OK && ptr )
1295 return std::string(ptr);
1296 return std::string();
1302 using T = std::decay_t<
decltype(arg)>;
1303 if constexpr (std::is_same_v<T, NetworkRequestPrivate::pending_t> || std::is_same_v<T, NetworkRequestPrivate::prepareNextRangeBatch_t> )
1305 else if constexpr (std::is_same_v<T, NetworkRequestPrivate::running_t>
1306 || std::is_same_v<T, NetworkRequestPrivate::finished_t>)
1307 return arg._contentLenght;
1309 static_assert(always_false<T>::value,
"Unhandled state type");
1310 }, d_func()->_runningMode);
1316 using T = std::decay_t<
decltype(arg)>;
1317 if constexpr (std::is_same_v<T, NetworkRequestPrivate::pending_t>)
1319 else if constexpr (std::is_same_v<T, NetworkRequestPrivate::running_t>
1320 || std::is_same_v<T, NetworkRequestPrivate::prepareNextRangeBatch_t>
1321 || std::is_same_v<T, NetworkRequestPrivate::finished_t>)
1322 return arg._downloaded;
1324 static_assert(always_false<T>::value,
"Unhandled state type");
1325 }, d_func()->_runningMode);
1330 return d_func()->_settings;
1335 return std::visit([
this](
auto& arg) {
1336 using T = std::decay_t<
decltype(arg)>;
1337 if constexpr (std::is_same_v<T, NetworkRequestPrivate::pending_t>)
1339 else if constexpr (std::is_same_v<T, NetworkRequestPrivate::running_t> || std::is_same_v<T, NetworkRequestPrivate::prepareNextRangeBatch_t> )
1341 else if constexpr (std::is_same_v<T, NetworkRequestPrivate::finished_t>) {
1342 if ( std::get<NetworkRequestPrivate::finished_t>( d_func()->_runningMode ).
_result.isError() )
1348 static_assert(always_false<T>::value,
"Unhandled state type");
1349 }, d_func()->_runningMode);
1354 const auto s = state();
1355 if ( s != Error && s != Finished )
1357 return std::get<NetworkRequestPrivate::finished_t>( d_func()->
_runningMode)._result;
1363 return std::string();
1365 return error().nativeErrorString();
1370 return error().isError();
1377 curl_slist *res = curl_slist_append( d->_headers ? d->_headers.get() :
nullptr, header.c_str() );
1382 d->_headers = std::unique_ptr< curl_slist, decltype (&curl_slist_free_all) >( res, &curl_slist_free_all );
1389 return d_func()->_sigStarted;
1394 return d_func()->_sigBytesDownloaded;
1399 return d_func()->_sigProgress;
1404 return d_func()->_sigFinished;
ZYppCommitResult & _result
Store and operate with byte count.
static const Unit B
1 Byte
static std::string digestVectorToString(const UByteArray &vec)
get hex string representation of the digest vector given as parameter
Base class for Exception.
std::string asString() const
Error message provided by dumpOn as string.
const char * c_str() const
String representation.
const std::string & asString() const
String representation.
bool empty() const
Test for an empty path.
@ icase
Do not differentiate case.
@ rxdefault
These are enforced even if you don't pass them as flag argument.
Regular expression match result.
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.
Type type() const
type Returns the type of the error
enum zyppng::NetworkRequestPrivate::ProtocolMode _protocolMode
const std::string _currentCookieFile
zypp::Pathname _targetFile
void resetActivityTimer()
bool parseContentTypeMultiRangeHeader(const std::string_view &line, std::string &boundary)
Signal< void(NetworkRequest &req, zypp::ByteCount count)> _sigBytesDownloaded
NetworkRequestDispatcher * _dispatcher
std::vector< NetworkRequest::Range > _requestedRanges
the requested ranges that need to be downloaded
static int curlProgressCallback(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
std::string errorMessage() const
Signal< void(NetworkRequest &req)> _sigStarted
NetworkRequest::FileMode _fMode
std::variant< pending_t, running_t, prepareNextRangeBatch_t, finished_t > _runningMode
bool initialize(std::string &errBuf)
void validateRange(NetworkRequest::Range &rng)
void onActivityTimeout(Timer &)
Signal< void(NetworkRequest &req, off_t dltotal, off_t dlnow, off_t ultotal, off_t ulnow)> _sigProgress
size_t writeCallback(char *ptr, size_t size, size_t nmemb)
std::string _lastRedirect
to log/report redirections
NetworkRequest::Options _options
static constexpr int _rangeAttempt[]
bool prepareToContinue(std::string &errBuf)
bool prepareNextRangeBatch(std::string &errBuf)
size_t headerCallback(char *ptr, size_t size, size_t nmemb)
void setResult(NetworkRequestError &&err)
std::array< char, CURL_ERROR_SIZE+1 > _errorBuf
virtual ~NetworkRequestPrivate()
bool setupHandle(std::string &errBuf)
NetworkRequestPrivate(Url &&url, zypp::Pathname &&targetFile, NetworkRequest::FileMode fMode, NetworkRequest &p)
TransferSettings _settings
void setCurlOption(CURLoption opt, T data)
zypp::ByteCount _expectedFileSize
Signal< void(NetworkRequest &req, const NetworkRequestError &err)> _sigFinished
std::unique_ptr< curl_slist, decltype(&curl_slist_free_all) > _headers
bool checkIfRangeChkSumIsValid(const NetworkRequest::Range &rng)
bool parseContentRangeHeader(const std::string_view &line, size_t &start, size_t &len)
zypp::ByteCount reportedByteCount() const
Returns the number of bytes that are reported from the backend as the full download size,...
const zypp::Pathname & targetFilePath() const
Returns the target filename path.
zypp::ByteCount downloadedByteCount() const
Returns the number of already downloaded bytes as reported by the backend.
void resetRequestRanges()
void setUrl(const Url &url)
This will change the URL of the request.
void setExpectedFileSize(zypp::ByteCount expectedFileSize)
virtual ~NetworkRequest()
void setPriority(Priority prio, bool triggerReschedule=true)
std::vector< char > peekData(off_t offset, size_t count) const
std::string contentType() const
Returns the content type as reported from the server.
void setFileOpenMode(FileMode mode)
Sets the file open mode to mode.
std::shared_ptr< zypp::Digest > DigestPtr
bool addRequestHeader(const std::string &header)
void setOptions(Options opt)
FileMode fileOpenMode() const
Returns the currently configured file open mode.
bool hasError() const
Checks if there was a error with the request.
State state() const
Returns the current state the HttpDownloadRequest is in.
SignalProxy< void(NetworkRequest &req, const NetworkRequestError &err)> sigFinished()
Signals that the download finished.
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...
void addRequestRange(size_t start, size_t len=0, DigestPtr digest=nullptr, CheckSumBytes expectedChkSum=CheckSumBytes(), std::any userData=std::any(), std::optional< size_t > digestCompareLen={}, std::optional< size_t > chksumpad={})
std::optional< Timings > timings() const
After the request is finished query the timings that were collected during download.
std::string extendedErrorString() const
In some cases, curl can provide extended error information collected at runtime.
Priority priority() const
NetworkRequestError error() const
Returns the last set Error.
void setTargetFilePath(const zypp::Pathname &path)
Changes the target file path of the download.
void * nativeHandle() const
std::vector< Range > failedRanges() const
const std::vector< Range > & requestedRanges() const
SignalProxy< void(NetworkRequest &req)> sigStarted()
Signals that the dispatcher dequeued the request and actually starts downloading data.
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.
TransferSettings & transferSettings()
const std::string & lastRedirectInfo() const
#define EXPLICITLY_NO_PROXY
std::string curlUnEscape(std::string text_r)
void setupZYPP_MEDIA_CURL_DEBUG(CURL *curl)
Setup CURLOPT_VERBOSE and CURLOPT_DEBUGFUNCTION according to env::ZYPP_MEDIA_CURL_DEBUG.
String related utilities and Regular expression matching.
int ZYPP_MEDIA_CURL_IPRESOLVE()
4/6 to force IPv4/v6
int assert_file_mode(const Pathname &path, unsigned mode)
Like assert_file but enforce mode even if the file already exists.
constexpr bool always_false
bool regex_match(const std::string &s, smatch &matches, const regex ®ex)
\relates regex \ingroup ZYPP_STR_REGEX \relates regex \ingroup ZYPP_STR_REGEX
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
bool strToBool(const C_Str &str, bool default_r)
Parse str into a bool depending on the default value.
std::string trim(const std::string &s, const Trim trim_r)
Easy-to use interface to the ZYPP dependency resolver.
std::vector< char > peek_data_fd(FILE *fd, off_t offset, size_t count)
ZYPP_IMPL_PRIVATE(Provide)
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...
NetworkRequestError _result
zypp::ByteCount _contentLenght
running_t(pending_t &&prevState)
CheckSumBytes _checksum
Enables automated checking of downloaded contents against a checksum.
static Range make(size_t start, size_t len=0, DigestPtr &&digest=nullptr, CheckSumBytes &&expectedChkSum=CheckSumBytes(), std::any &&userData=std::any(), std::optional< size_t > digestCompareLen={}, std::optional< size_t > _dataBlockPadding={})
std::optional< size_t > _relevantDigestLen
std::optional< size_t > _chksumPad
std::chrono::microseconds appconnect
std::chrono::microseconds redirect
std::chrono::microseconds pretransfer
std::chrono::microseconds total
std::chrono::microseconds namelookup
std::chrono::microseconds connect
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.