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