libzypp 17.32.2
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
24namespace 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 ) {
56 using T = std::decay_t<decltype (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);
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}
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:147
std::string asUserString() const
Translated error message as string suitable for the user.
Definition Exception.cc:101
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
const Url & url() const
SignalProxy< void()> sigNewMirrorsReady()
static zyppng::NetworkRequestError customError(NetworkRequestError::Type t, std::string &&errorMsg="", std::map< std::string, boost::any > &&extraInfo={})
#define MIL_MEDIA
zypp::Url propagateQueryParams(zypp::Url url_r, const zypp::Url &template_r)
Definition Arch.h:364
int unlink(const Pathname &path)
Like 'unlink'.
Definition PathInfo.cc:701
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
zypp::media::MediaBlockList _blockList
Signal< void() > _sigFallback
std::shared_ptr< Request > _oldRequest
#define MIL
Definition Logger.h:96
#define WAR
Definition Logger.h:97