libzypp  17.35.16
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 
13 namespace 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 
58  virtual void notifyErrorCodeChanged () {};
59  };
60 
68  class CurlMultiPartHandler : public Base
69  {
70  public:
71 
72  enum class ProtocolMode{
73  Basic, //< use this mode if no special checks are required in header or write callbacks
74  HTTP //< this mode is used for HTTP and HTTPS downloads
75  };
76 
77  // when requesting ranges from the server, we need to make sure not to request
78  // too many at the same time. Instead we batch our requests and reuse the open
79  // connection until we have the full file.
80  // However different server have different maximum nr of ranges, so we start with
81  // a high number and decrease until we find a rangecount that works
82  constexpr static unsigned _rangeAttempt[] = {
83  255,
84  127,
85  63,
86  15,
87  5,
88  1
89  };
90 
91  constexpr static unsigned _rangeAttemptSize = ( sizeof( _rangeAttempt ) / sizeof(unsigned) );
92 
93  enum State {
94  Pending, //< waiting to be dispatched
95  Running, //< currently running
96  Finished, //< finished successfully
97  Error, //< Error, use error function to figure out the issue
98  };
99 
102 
103  struct Range {
104  size_t start = 0;
105  size_t len = 0;
106  size_t bytesWritten = 0;
107  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
108 
116  std::optional<size_t> _relevantDigestLen; //< If this is initialized , it defines how many bytes of the resulting checkum are compared
117  std::optional<size_t> _chksumPad; //< If initialized we need to pad the digest with zeros before calculating the final checksum
118  std::any userData; //< Custom data the user can associate with the Range
119 
120  State _rangeState = State::Pending; //< Flag to know if this range has been already requested and if the request was successful
121 
122  void restart();
123  Range clone() const;
124 
125  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 = {} );
126  };
127 
128  CurlMultiPartHandler( ProtocolMode mode, void *easyHandle, std::vector<Range> &ranges, CurlMultiPartDataReceiver &receiver );
129  ~CurlMultiPartHandler() override;
130 
131  void *easyHandle() const;
132  bool canRecover() const;
133  bool hasMoreWork() const;
134 
135  bool hasError() const;
136 
137  Code lastError() const;
138  const std::string &lastErrorMessage() const;
139 
140  bool validateRange(Range &rng);
141 
142  bool prepare( );
143  bool prepareToContinue( );
144  void finalize( );
145 
146  bool verifyData( );
147 
148  std::optional<size_t> reportedFileSize() const;
149  std::optional<off_t> currentRange() const;
150 
151  private:
152 
153  void setCode ( Code c, std::string msg, bool force = false );
154 
155  static size_t curl_hdrcallback ( char *ptr, size_t size, size_t nmemb, void *userdata );
156  static size_t curl_wrtcallback ( char *ptr, size_t size, size_t nmemb, void *userdata );
157 
158  size_t hdrcallback ( char *ptr, size_t size, size_t nmemb );
159  size_t wrtcallback ( char *ptr, size_t size, size_t nmemb );
160  bool parseContentRangeHeader(const std::string_view &line, size_t &start, size_t &len, size_t &fileLen);
161  bool parseContentTypeMultiRangeHeader(const std::string_view &line, std::string &boundary);
162  bool checkIfRangeChkSumIsValid( Range &rng );
163  void setRangeState ( Range &rng, State state );
164 
166  void *_easyHandle = nullptr;
168 
169  Code _lastCode = Code::NoError;
170  std::string _lastErrorMsg;
171 
172  bool _allHeadersReceived = false; //< set to true once writefunc was called once e.g. all headers have been received
173  bool _gotContentRangeInfo = false; //< Set to true if the server indicates ranges
174  bool _isMuliPartResponse = false; //< Set to true if the respone is in multipart form
175 
176  std::string _seperatorString;
177  std::vector<char> _rangePrefaceBuffer;
178 
179  std::optional<off_t> _currentRange;
180  std::optional<Range> _currentSrvRange;
181  std::optional<size_t> _reportedFileSize;
182 
183  unsigned _rangeAttemptIdx = 0;
184  std::vector<Range> &_requestedRanges;
185  };
186 
187 } // namespace zyppng
188 
189 #endif // ZYPPNG_CURLMULTIPARTHANDLER_H
std::optional< size_t > reportedFileSize() const
CurlMultiPartDataReceiver & _receiver
std::string _seperatorString
The seperator string for multipart responses as defined in RFC 7233 Section 4.1.
The CurlMultiPartHandler class.
virtual ~CurlMultiPartDataReceiver()=default
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={})
size_t hdrcallback(char *ptr, size_t size, size_t nmemb)
NetworkRequestError::Type Code
void setRangeState(Range &rng, State state)
const std::string & lastErrorMessage() const
std::optional< Range > _currentSrvRange
void setCode(Code c, std::string msg, bool force=false)
virtual size_t headerfunction(char *ptr, size_t bytes)=0
CheckSumBytes _checksum
Enables automated checking of downloaded contents against a checksum.
virtual size_t writefunction(char *ptr, std::optional< off_t > offset, size_t bytes)=0
std::vector< Range > & _requestedRanges
the requested ranges that need to be downloaded
static constexpr unsigned _rangeAttemptSize
CurlMultiPartHandler(ProtocolMode mode, void *easyHandle, std::vector< Range > &ranges, CurlMultiPartDataReceiver &receiver)
virtual bool finishedRange(off_t range, bool validated, std::string &cancelReason)
zypp::UByteArray UByteArray
Definition: bytearray.h:22
static size_t curl_wrtcallback(char *ptr, size_t size, size_t nmemb, void *userdata)
std::optional< off_t > currentRange() const
std::optional< size_t > _relevantDigestLen
virtual bool beginRange(off_t range, std::string &cancelReason)
std::vector< char > _rangePrefaceBuffer
Here we buffer.
std::optional< zypp::Digest > _digest
std::optional< off_t > _currentRange
std::optional< size_t > _reportedFileSize
Filesize as reported by the content range or byte range headers.
bool parseContentRangeHeader(const std::string_view &line, size_t &start, size_t &len, size_t &fileLen)
static constexpr unsigned _rangeAttempt[]
static size_t curl_hdrcallback(char *ptr, size_t size, size_t nmemb, void *userdata)
bool parseContentTypeMultiRangeHeader(const std::string_view &line, std::string &boundary)
size_t wrtcallback(char *ptr, size_t size, size_t nmemb)