libzypp  17.35.12
preparemulti_p.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 ----------------------------------------------------------------------*/
9 
14 #include <utility>
15 #include <zypp-curl/parser/ZsyncParser>
16 #include <zypp-core/fs/PathInfo.h>
17 
18 #include "preparemulti_p.h"
19 
20 #if ENABLE_ZCHUNK_COMPRESSION
21 #include "zck_p.h"
22 #endif
23 
24 namespace zyppng {
25 
26  PrepareMultiState::PrepareMultiState( std::shared_ptr<Request> oldReq, Mode m, DownloadPrivate &parent )
27  : SimpleState( parent )
28  , _mode(m)
29  , _oldRequest(std::move( oldReq ))
30  {
31  MIL << "About to enter PrepareMultiState for URL: " << parent._spec.url() << std::endl;
32  }
33 
35  {
36  auto &sm = stateMachine();
37  const auto &spec = sm._spec;
38  const auto &url = spec.url();
39  const auto &targetPath = spec.targetPath();
40 #if ENABLE_ZCHUNK_COMPRESSION
41  _haveZckData = (isZchunkFile( spec.deltaFile() ) && spec.headerSize() > 0);
42  MIL << " Upgrading request for URL: "<< url << " to multipart download , which zckunk=" << _haveZckData << std::endl;
43 #else
44  MIL << " Upgrading request for URL: "<< url << " to multipart download , which zckunk=false" << std::endl;
45 #endif
46 
47 
48  //we have a metalink download, lets parse it and see what we got
49  _mirrors.clear();
50 
51  std::vector<zypp::media::MetalinkMirror> mirrs;
52 
53  try {
54 
55  const auto &parseMetadata = [&]( auto &&parser ) {
57  constexpr auto metalinkMode = std::is_same< T, zypp::media::MetaLinkParser>();
58 
59  parser.parse( targetPath );
60 
61  // we only care about the metalink chunks if we have no zchunk data
62  #if ENABLE_ZCHUNK_COMPRESSION
63  if ( !_haveZckData ) {
64  #else
65  if ( true ) {
66  #endif
67  auto bl = parser.getBlockList();
68  if ( !bl.haveBlocks() )
69  MIL << "Got no blocks for URL " << spec.url() << " but got filesize? " << bl.getFilesize() << std::endl;
70  if ( bl.haveBlocks() || bl.haveFilesize() )
71  _blockList = std::move(bl);
72  }
73 
74  //migrate some settings from the base url to the mirror
75  if constexpr ( !metalinkMode ) {
76  const auto &urlList = parser.getUrls();
77  std::for_each( urlList.begin(), urlList.end(), [&]( const auto &url ) {
78  mirrs.push_back( { 0, -1, url } );
79  });
80  } else {
81  mirrs = parser.getMirrors();
82  }
83 
84  for ( auto urliter = mirrs.begin(); urliter != mirrs.end(); ++urliter ) {
85  try {
86  const std::string scheme = urliter->url.getScheme();
87  if (scheme == "http" || scheme == "https" || scheme == "ftp" || scheme == "tftp") {
88  if ( !sm._requestDispatcher->supportsProtocol( urliter->url )) {
89  urliter = mirrs.erase( urliter );
90  continue;
91  }
92  urliter->url = ::internal::propagateQueryParams( urliter->url, url );
93  _mirrors.push_back( urliter->url );
94  }
95  }
96  catch (...) { }
97  }
98 
99  if ( mirrs.empty() ) {
100  mirrs.push_back( { 0, -1, url } );
101  _mirrors.push_back( url );
102  }
103  };
104 
105  switch( _mode ) {
106  case Zsync: {
107  parseMetadata( zypp::media::ZsyncParser() );
108  break;
109  }
110  case Metalink: {
111  parseMetadata( zypp::media::MetaLinkParser() );
112  break;
113  }
114  }
115  } catch ( const zypp::Exception &ex ) {
116  std::string err = zypp::str::Format("Failed to parse metalink information.(%1%)" ) % ex.asUserString();
117  WAR << err << std::endl;
119  _sigFailed.emit();
120  return;
121  }
122 
123  if ( mirrs.size() == 0 ) {
124  std::string err = zypp::str::Format("Invalid metalink information.( No mirrors in metalink file)" );
125  WAR << err << std::endl;
127  _sigFailed.emit();
128  return;
129  }
130 
131  //remove the metalink file
132  zypp::filesystem::unlink( targetPath );
134 
135  // this will emit a mirrorsReady signal once some connection tests have been done
136  sm._mirrorControl->registerMirrors( mirrs );
137  }
138 
140  {
141  // if we did not pass on the existing request to the next state we destroy it here
142  if ( _oldRequest )
143  _oldRequest.reset();
144  }
145 
147  {
148  auto &sm = stateMachine();
149  const auto &spec = sm._spec;
150  const auto &url = spec.url();
151  _mirrorControlReadyConn.disconnect();
152 
153 #if ENABLE_ZCHUNK_COMPRESSION
154  if ( _haveZckData ) {
155  _sigFinished.emit();
156  return;
157  }
158 #endif
159 
160  // we have no zchunk data, so for a multi download we need a blocklist
161  if ( !_blockList.haveBlocks() ) {
162  //if we have no filesize we can not generate a blocklist, we need to fall back to normal download
163  if ( !_blockList.haveFilesize() ) {
164 
165  //fall back to normal download but use a mirror from the mirror list
166  //otherwise we get HTTPS to HTTP redirect errors
167  _sigFallback.emit();
168  return;
169  } else {
170  //we generate a blocklist on the fly based on the filesize
171 
172  MIL << "Generate blocklist, since there was none in the metalink file." << url << std::endl;
173 
174  off_t currOff = 0;
175  off_t filesize = _blockList.getFilesize();
176  const auto prefSize = std::max<zypp::ByteCount>( sm._spec.preferredChunkSize(), zypp::ByteCount(4, zypp::ByteCount::K) );
177 
178  while ( currOff < filesize ) {
179 
180  auto blksize = filesize - currOff ;
181  if ( blksize > prefSize )
182  blksize = prefSize;
183 
184  _blockList.addBlock( currOff, blksize );
185  currOff += blksize;
186  }
187 
188  MIL_MEDIA << "Generated blocklist: " << std::endl << _blockList << std::endl << " End blocklist " << std::endl;
189  }
190  }
191 
192  _sigFinished.emit();
193  }
194 
195  std::shared_ptr<DlNormalFileState> PrepareMultiState::fallbackToNormalTransition()
196  {
197  MIL << "No blocklist and no filesize, falling back to normal download for URL " << stateMachine()._spec.url() << std::endl;
198  std::shared_ptr<DlNormalFileState> ptr;
199  if ( _oldRequest ) {
200  ptr = std::make_shared<DlNormalFileState>( std::move(_oldRequest), stateMachine() );
201  } else {
202  ptr = std::make_shared<DlNormalFileState>( stateMachine() );
203  }
204 
205  ptr->_fileMirrors = std::move(_mirrors);
206  if ( _blockList.haveFileChecksum() ) {
207  ptr->_chksumtype = _blockList.fileChecksumType();
208  ptr->_chksumVec = _blockList.getFileChecksum();
209  }
210 
211  return ptr;
212  }
213 
214  std::shared_ptr<DlMetalinkState> PrepareMultiState::transitionToMetalinkDl()
215  {
216  return std::make_shared<DlMetalinkState>( std::move(_blockList), std::move(_mirrors), stateMachine() );
217  }
218 
219  std::shared_ptr<FinishedState> PrepareMultiState::transitionToFinished()
220  {
221  return std::make_shared<FinishedState>( std::move(_error), stateMachine() );
222  }
223 
224 #if ENABLE_ZCHUNK_COMPRESSION
225  std::shared_ptr<DLZckHeadState> PrepareMultiState::transitionToZckHeadDl()
226  {
227  if ( _oldRequest )
228  return std::make_shared<DLZckHeadState>( std::move(_mirrors), std::move(_oldRequest), stateMachine() );
229  return std::make_shared<DLZckHeadState>( std::move(_mirrors), stateMachine() );
230  }
231 
232  bool PrepareMultiState::toZckHeadDownloadGuard() const
233  {
234  return ( stateMachine().hasZckInfo() );
235  }
236 #endif
237 
239  {
240 #if ENABLE_ZCHUNK_COMPRESSION
241  return (!toZckHeadDownloadGuard());
242 #else
243  return true;
244 #endif
245  }
246 
247 }
size_t addBlock(off_t off, size_t size)
add a block with offset off and size size to the block list.
#define MIL
Definition: Logger.h:98
SignalProxy< void()> sigNewMirrorsReady()
std::shared_ptr< DlMetalinkState > transitionToMetalinkDl()
Signal< void() > _sigFailed
zypp::Url propagateQueryParams(zypp::Url url_r, const zypp::Url &template_r)
Definition: curlhelper.cc:401
DownloadSpec _spec
Definition: base_p.h:98
Store and operate with byte count.
Definition: ByteCount.h:31
sigc::connection _mirrorControlReadyConn
zypp::media::MediaBlockList _blockList
Definition: Arch.h:363
Convenient building of std::string with boost::format.
Definition: String.h:252
const UByteArray & getFileChecksum()
NetworkRequestError _error
std::shared_ptr< Request > _oldRequest
bool haveBlocks() const
do we have a blocklist describing the file? set to true when addBlock() is called ...
WeakPtr parent() const
Definition: base.cc:26
std::string asUserString() const
Translated error message as string suitable for the user.
Definition: Exception.cc:118
PrepareMultiState(std::shared_ptr< Request > oldReq, Mode m, DownloadPrivate &parent)
#define WAR
Definition: Logger.h:99
Signal< void() > _sigFallback
int unlink(const Pathname &path)
Like &#39;unlink&#39;.
Definition: PathInfo.cc:705
#define MIL_MEDIA
Definition: mediadebug_p.h:29
std::vector< Url > _mirrors
Signal< void() > _sigFinished
Base class for Exception.
Definition: Exception.h:146
static const Unit K
1024 Byte
Definition: ByteCount.h:46
typename decay< T >::type decay_t
Definition: TypeTraits.h:42
std::shared_ptr< DlNormalFileState > fallbackToNormalTransition()
static zyppng::NetworkRequestError customError(NetworkRequestError::Type t, std::string &&errorMsg="", std::map< std::string, boost::any > &&extraInfo={})
const Url & url() const
Definition: downloadspec.cc:48
bool toMetalinkDownloadGuard() const
std::string fileChecksumType() const
std::shared_ptr< FinishedState > transitionToFinished()