17 CurlMultiPartSetoptError ( CURLcode code ) :
_code(code){};
18 CURLcode code()
const;
23 CURLcode CurlMultiPartSetoptError::code()
const {
30 CurlMultInitRangeError ( std::string what ) :
zypp::Exception(
std::move(what) ){}
57 if ( _digest ) _digest->reset();
66 ._digest = _digest ? _digest->clone() : std::optional<zypp::Digest>{},
67 ._checksum = _checksum,
68 ._relevantDigestLen = _relevantDigestLen,
69 ._chksumPad = _chksumPad,
71 ._rangeState = _rangeState
81 ._digest = std::move( digest ),
85 .userData = std::move( userData ),
86 ._rangeState = State::Pending
91 : _protocolMode( mode )
92 , _easyHandle( easyHandle )
93 , _receiver( receiver )
94 , _requestedRanges(
ranges )
98 WAR <<
"!!!! Downloading ranges without HTTP might be slow !!!!" << std::endl;
117 if ( size *
nmemb == 0)
124 hdr.remove_prefix( std::min(
hdr.find_first_not_of(
" \t\r\n"),
hdr.size() ) );
129 hdr = std::string_view();
133 return ( size *
nmemb );
136 if ( zypp::strv::hasPrefixCI(
hdr,
"HTTP/" ) ) {
142 WAR <<
_easyHandle <<
" " <<
"Range FAIL, trying with a smaller batch" << std::endl;
144 setCode ( Code::RangeFail,
"Expected range status code 206, but got none." );
148 if ( range._rangeState == Running )
149 range._rangeState = Pending;
160 }
else if ( zypp::strv::hasPrefixCI(
hdr,
"Content-Range:") ) {
166 setCode( Code::InternalError,
"Invalid Content-Range header format." );
171 WAR <<
"Setting request filesize to " <<
fileLen << std::endl;
175 DBG <<
_easyHandle <<
" " <<
"Got content range :" <<
r.start <<
" len " <<
r.len << std::endl;
179 }
else if ( zypp::strv::hasPrefixCI(
hdr,
"Content-Type:") ) {
194 const auto max = ( size *
nmemb );
204 std::optional<off_t> seekTo;
213 setCode( Code::ServerReturnedError,
"Invalid data from server, range respone was announced but there was no range definiton." );
273 setCode( Code::InternalError,
"Unable to find a matching range for data returned by the server.");
288 std::string
errBuf =
"Receiver cancelled starting the current range.";
290 setCode( Code::InternalError,
"Receiver cancelled starting the current range.");
301 setCode( Code::InternalError,
"Received data but no range was marked as requested." );
332 if (
rng._digest &&
rng._checksum.size() ) {
341 if (
rng.len > 0 &&
rng.bytesWritten >=
rng.len ) {
342 std::string
errBuf =
"Receiver cancelled after finishing the current range.";
345 setCode( Code::InternalError,
"Receiver cancelled starting the current range.");
386 setCode( Code::InternalError,
"Invalid multirange header format, seperator string missing." );
391 std::vector<std::string_view> lines;
392 zypp::strv::split( data.substr(
startOfHeader ),
"\r\n", zypp::strv::Trim::trim, [&]( std::string_view strv ) { lines.push_back(strv); } );
393 for (
const auto &
hdrLine : lines ) {
394 if ( zypp::strv::hasPrefixCI(
hdrLine,
"Content-Range:") ) {
399 setCode( Code::InternalError,
"Invalid Content-Range header format." );
411 setCode( Code::InternalError,
"Could not read a server range from the response." );
465 setCode ( Code::RangeFail,
"No more range batch sizes available",
true );
473 setCode ( Code::NoError,
"Request has no more work",
true );
496 if (
r.len > 0 &&
r.bytesWritten !=
r.len )
497 setCode( Code::MissingData, (
zypp::str::Format(
"Did not receive all requested data from the server ( off: %1%, req: %2%, recv: %3% ).") %
r.start %
r.len %
r.bytesWritten ) );
522 setCode( Code::InternalError,
"Calling the CurlMultiPartHandler::prepare function without a range to download is not supported.");
526 const auto setCurlOption = [&](
CURLoption opt,
auto &&data )
530 throw CurlMultiPartSetoptError(
ret);
547 if( range.second > 0 )
562 if ( range._rangeState !=
Pending )
566 range.bytesWritten = 0;
571 throw CurlMultInitRangeError(
"It is not supported to request more ranges after a open range.");
573 const auto rangeEnd = range.len > 0 ? range.start + range.len - 1 : 0;
600 range.bytesWritten = 0;
602 range._digest->reset();
606 MIL <<
_easyHandle <<
" " <<
"Reached max nr of ranges (" << maxRanges <<
"), batching the request to not break the server" << std::endl;
619 }
catch(
const CurlMultiPartSetoptError &err ) {
620 setCode( Code::InternalError,
"" );
621 }
catch(
const CurlMultInitRangeError &err ) {
622 setCode( Code::InternalError, err.asUserString() );
624 setCode( Code::InternalError, err.asUserString() );
625 }
catch(
const std::exception &err ) {
649 DBG <<
_easyHandle <<
" " <<
"Invalid Content-Range Header format: '" << std::string(
line) << std::endl;
653 size_t s = zypp::str::strtonum<size_t>( what[1]);
654 size_t e = zypp::str::strtonum<size_t>( what[2]);
655 fileLen = zypp::str::strtonum<size_t>( what[3]);
667 if ( what.
size() >= 2 ) {
677 if (
rng._digest &&
rng._checksum.size() ) {
683 if (
rng.len == 0 ?
true :
rng.bytesWritten ==
rng.len )
693 if (
rng._digest &&
rng._checksum.size() ) {
694 auto bytesHashed =
rng._digest->bytesHashed ();
695 if (
rng._chksumPad && *
rng._chksumPad > bytesHashed ) {
700 auto digVec =
rng._digest->digestVector();
701 if (
rng._relevantDigestLen ) {
702 digVec.resize( *
rng._relevantDigestLen );
713 if (
rng._rangeState != state ) {
714 rng._rangeState = state;
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
void reset()
Reset to default Ctor values.
static std::string digestVectorToString(const UByteArray &vec)
get hex string representation of the digest vector given as parameter
Base class for Exception.
@ icase
Do not differentiate case.
@ rxdefault
These are enforced even if you don't pass them as flag argument.
Regular expression match result.
virtual size_t headerfunction(char *ptr, size_t bytes)=0
virtual void notifyErrorCodeChanged()
virtual size_t writefunction(char *ptr, std::optional< off_t > offset, size_t bytes)=0
virtual bool finishedRange(off_t range, bool validated, std::string &cancelReason)
virtual bool beginRange(off_t range, std::string &cancelReason)
The CurlMultiPartHandler class.
size_t wrtcallback(char *ptr, size_t size, size_t nmemb)
unsigned _rangeAttemptIdx
static constexpr unsigned _rangeAttemptSize
ProtocolMode _protocolMode
CurlMultiPartHandler(ProtocolMode mode, void *easyHandle, std::vector< Range > &ranges, CurlMultiPartDataReceiver &receiver)
std::optional< Range > _currentSrvRange
std::string _seperatorString
The seperator string for multipart responses as defined in RFC 7233 Section 4.1.
std::string _lastErrorMsg
bool _gotContentRangeInfo
static size_t curl_wrtcallback(char *ptr, size_t size, size_t nmemb, void *userdata)
static size_t curl_hdrcallback(char *ptr, size_t size, size_t nmemb, void *userdata)
~CurlMultiPartHandler() override
const std::string & lastErrorMessage() const
static constexpr unsigned _rangeAttempt[]
bool parseContentRangeHeader(const std::string_view &line, size_t &start, size_t &len, size_t &fileLen)
void setCode(Code c, std::string msg, bool force=false)
std::vector< char > _rangePrefaceBuffer
Here we buffer.
std::optional< off_t > currentRange() const
std::optional< size_t > _reportedFileSize
Filesize as reported by the content range or byte range headers.
size_t hdrcallback(char *ptr, size_t size, size_t nmemb)
bool validateRange(Range &rng)
CurlMultiPartDataReceiver & _receiver
void setRangeState(Range &rng, State state)
std::optional< size_t > reportedFileSize() const
bool parseContentTypeMultiRangeHeader(const std::string_view &line, std::string &boundary)
void * easyHandle() const
bool checkIfRangeChkSumIsValid(Range &rng)
std::vector< Range > & _requestedRanges
the requested ranges that need to be downloaded
std::optional< off_t > _currentRange
const std::string & asString(const std::string &t)
Global asString() that works with std::string too.
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.
Easy-to use interface to the ZYPP dependency resolver.
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={})