libzypp 17.31.31
curlmultiparthandler.h
Go to the documentation of this file.
1#ifndef ZYPPNG_CURLMULTIPARTHANDLER_H
2#define ZYPPNG_CURLMULTIPARTHANDLER_H
3
4#include <zypp-core/zyppng/base/Base>
5#include <zypp-core/zyppng/core/ByteArray>
6#include <zypp-core/Digest.h>
7#include <zypp-core/zyppng/pipelines/Expected>
8#include <zypp-curl/ng/network/NetworkRequestError>
9
10#include <optional>
11#include <any>
12
13namespace zyppng {
14
19 public:
20 virtual ~CurlMultiPartDataReceiver() = default;
21
25 virtual size_t headerfunction ( char *ptr, size_t bytes ) = 0;
26
32 virtual size_t writefunction ( char *ptr, std::optional<off_t> offset, size_t bytes ) = 0;
33
41 virtual bool beginRange ( off_t range, std::string &cancelReason ) { return true; };
42
53 virtual bool finishedRange ( off_t range, bool validated, std::string &cancelReason ) { return true; };
54 };
55
64 {
65 public:
66
67 enum class ProtocolMode{
68 Basic, //< use this mode if no special checks are required in header or write callbacks
69 HTTP //< this mode is used for HTTP and HTTPS downloads
70 };
71
72 // when requesting ranges from the server, we need to make sure not to request
73 // too many at the same time. Instead we batch our requests and reuse the open
74 // connection until we have the full file.
75 // However different server have different maximum nr of ranges, so we start with
76 // a high number and decrease until we find a rangecount that works
77 constexpr static unsigned _rangeAttempt[] = {
78 255,
79 127,
80 63,
81 15,
82 5,
83 1
84 };
85
86 constexpr static unsigned _rangeAttemptSize = ( sizeof( _rangeAttempt ) / sizeof(unsigned) );
87
88 enum State {
89 Pending, //< waiting to be dispatched
90 Running, //< currently running
91 Finished, //< finished successfully
92 Error, //< Error, use error function to figure out the issue
93 };
94
95 using CheckSumBytes = UByteArray;
97
98 struct Range {
99 size_t start = 0;
100 size_t len = 0;
101 size_t bytesWritten = 0;
102 std::optional<zypp::Digest> _digest = {}; //< zypp::Digest that is updated when data is written, can be used to validate the file contents with a checksum
103
111 std::optional<size_t> _relevantDigestLen; //< If this is initialized , it defines how many bytes of the resulting checkum are compared
112 std::optional<size_t> _chksumPad; //< If initialized we need to pad the digest with zeros before calculating the final checksum
113 std::any userData; //< Custom data the user can associate with the Range
114
115 State _rangeState = State::Pending; //< Flag to know if this range has been already requested and if the request was successful
116
117 void restart();
118 Range clone() const;
119
120 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 = {} );
121 };
122
123 CurlMultiPartHandler( ProtocolMode mode, void *easyHandle, std::vector<Range> &ranges, CurlMultiPartDataReceiver &receiver );
125
126 void *easyHandle() const;
127 bool canRecover() const;
128 bool hasMoreWork() const;
129
130 bool hasError() const;
131
132 Code lastError() const;
133 const std::string &lastErrorMessage() const;
134
135 bool validateRange(Range &rng);
136
137 bool prepare( );
138 bool prepareToContinue( );
139 void finalize( );
140
141 bool verifyData( );
142
143 std::optional<size_t> reportedFileSize() const;
144 std::optional<off_t> currentRange() const;
145
146 private:
147
148 void setCode ( Code c, std::string msg, bool force = false );
149
150 static size_t curl_hdrcallback ( char *ptr, size_t size, size_t nmemb, void *userdata );
151 static size_t curl_wrtcallback ( char *ptr, size_t size, size_t nmemb, void *userdata );
152
153 size_t hdrcallback ( char *ptr, size_t size, size_t nmemb );
154 size_t wrtcallback ( char *ptr, size_t size, size_t nmemb );
155 bool parseContentRangeHeader(const std::string_view &line, size_t &start, size_t &len, size_t &fileLen);
156 bool parseContentTypeMultiRangeHeader(const std::string_view &line, std::string &boundary);
157 bool checkIfRangeChkSumIsValid( Range &rng );
158 void setRangeState ( Range &rng, State state );
159
161 void *_easyHandle = nullptr;
163
164 Code _lastCode = Code::NoError;
165 std::string _lastErrorMsg;
166
167 bool _allHeadersReceived = false; //< set to true once writefunc was called once e.g. all headers have been received
168 bool _gotContentRangeInfo = false; //< Set to true if the server indicates ranges
169 bool _isMuliPartResponse = false; //< Set to true if the respone is in multipart form
170
171 std::string _seperatorString;
172 std::vector<char> _rangePrefaceBuffer;
173
174 std::optional<off_t> _currentRange;
175 std::optional<Range> _currentSrvRange;
176 std::optional<size_t> _reportedFileSize;
177
178 unsigned _rangeAttemptIdx = 0;
179 std::vector<Range> &_requestedRanges;
180 };
181
182} // namespace zyppng
183
184#endif // ZYPPNG_CURLMULTIPARTHANDLER_H
virtual size_t headerfunction(char *ptr, size_t bytes)=0
virtual ~CurlMultiPartDataReceiver()=default
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)
static constexpr unsigned _rangeAttemptSize
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.
NetworkRequestError::Type Code
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)
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)
CurlMultiPartDataReceiver & _receiver
void setRangeState(Range &rng, State state)
std::optional< size_t > reportedFileSize() const
bool parseContentTypeMultiRangeHeader(const std::string_view &line, std::string &boundary)
std::vector< Range > & _requestedRanges
the requested ranges that need to be downloaded
std::optional< off_t > _currentRange
std::optional< zypp::Digest > _digest
CheckSumBytes _checksum
Enables automated checking of downloaded contents against a checksum.
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={})