libzypp 17.31.23
metalinkinfo_p.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8----------------------------------------------------------------------*/
9
14
15#include "metalinkinfo_p.h"
16
17namespace zyppng {
18
19 namespace {
20
21 constexpr auto minMetalinkProbeSize = 256; //< The maximum probe size we download before we decide we really got no metalink file
22
23 MetaDataType looks_like_meta_data( const std::vector<char> &data )
24 {
25 if ( data.empty() )
26 return MetaDataType::None;
27
28 const char *p = data.data();
29 while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
30 p++;
31
32 // If we have a zsync file, it has to start with zsync:
33 if ( !strncasecmp( p, "zsync:", 6 ) ) {
35 }
36
37 if (!strncasecmp(p, "<?xml", 5))
38 {
39 while (*p && *p != '>')
40 p++;
41 if (*p == '>')
42 p++;
43 while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
44 p++;
45 }
46 bool ret = !strncasecmp( p, "<metalink", 9 ) ? true : false;
47 if ( ret )
49
50 return MetaDataType::None;
51 }
52
53 MetaDataType looks_like_meta_file( const zypp::Pathname &file )
54 {
55 std::unique_ptr<FILE, decltype(&fclose)> fd( fopen( file.c_str(), "r" ), &fclose );
56 if ( !fd )
57 return MetaDataType::None;
58 return looks_like_meta_data( zyppng::peek_data_fd( fd.get(), 0, minMetalinkProbeSize ) );
59 }
60 }
61
63 : BasicDownloaderStateBase( parent )
64 {
65 MIL << "Downloading metalink/zsync on " << parent._spec.url() << std::endl;
66 }
67
68 DlMetaLinkInfoState::DlMetaLinkInfoState(std::shared_ptr<Request> &&prevRequest, DownloadPrivate &parent)
69 : BasicDownloaderStateBase( std::move(prevRequest), parent )
70 {
71 MIL << "Downloading metalink/zsync on " << parent._spec.url() << std::endl;
72 }
73
74 std::shared_ptr<FinishedState> DlMetaLinkInfoState::transitionToFinished()
75 {
76 MIL << "Downloading on " << stateMachine()._spec.url() << " transition to final state. " << std::endl;
77 return std::make_shared<FinishedState>( std::move(_error), stateMachine() );
78 }
79
80 std::shared_ptr<PrepareMultiState> DlMetaLinkInfoState::transitionToPrepareMulti()
81 {
82 _request->disconnectSignals();
84 auto nState = std::make_shared<PrepareMultiState>( std::move( _request ), prepareMode, stateMachine() );
85 _request = nullptr;
86 return nState;
87 }
88
89 bool DlMetaLinkInfoState::initializeRequest(std::shared_ptr<Request> &r )
90 {
91 MIL << "Requesting Metadata info from server!" << std::endl;
92 r->transferSettings().addHeader("Accept: */*, application/x-zsync, application/metalink+xml, application/metalink4+xml");
94 }
95
97 {
98 // some proxies do not store the content type, so also look at the file to find
99 // out if we received a metalink (bnc#649925)
101 _detectedMetaType = looks_like_meta_file( _request->targetFilePath() );
103 // Move to finished state
104 MIL << "Downloading on " << stateMachine()._spec.url() << " was successful, no metalink/zsync data. " << std::endl;
106 }
107
108 auto &sm = stateMachine();
109 if ( sm._stopOnMetalink ) {
110 MIL << "Stopping after receiving MetaData as requested" << std::endl;
111 sm._stoppedOnMetalink = true;
113 }
114
115 // Move to Prepare Multi state
117 MIL << "Downloading on " << sm._spec.url() << " returned a Zsync file " << std::endl;
118 else
119 MIL << "Downloading on " << sm._spec.url() << " returned a Metalink file" << std::endl;
120 _sigGotMetadata.emit();
121 }
122
123 void DlMetaLinkInfoState::handleRequestProgress(NetworkRequest &req, off_t dltotal, off_t dlnow)
124 {
125 auto &sm = stateMachine();
126
127 if ( _detectedMetaType == MetaDataType::None && dlnow < minMetalinkProbeSize ) {
128 // can't tell yet, ...
129 return sm._sigAlive.emit( *sm.z_func(), dlnow );
130 }
131
133 std::string cType = req.contentType();
134 if ( cType.find("application/x-zsync") == 0 )
136 else if ( cType.find("application/metalink+xml") == 0 || cType.find("application/metalink4+xml") == 0 )
138 }
139
141 _detectedMetaType = looks_like_meta_data( req.peekData( 0, minMetalinkProbeSize ) );
142 }
143
145 // this is a metalink file change the expected filesize
147 WAR << "Metadata file exceeds 2MB in filesize, aborting."<<std::endl;
149 return;
150 }
151
152 return sm._sigAlive.emit( *sm.z_func(), dlnow );
153
154 } else {
155 // still no metalink, we assume a normal download, not perfect though
156 if ( !_fallbackMilWritten ) {
157 _fallbackMilWritten = true;
158 MIL << "No Metalink file detected after " << minMetalinkProbeSize << ", falling back to normal progress updates" << std::endl;
159 }
160 return BasicDownloaderStateBase::handleRequestProgress( req, dltotal, dlnow );
161 }
162 }
163
164
165}
Store and operate with byte count.
Definition: ByteCount.h:31
static const Unit MB
1000^2 Byte
Definition: ByteCount.h:60
const char * c_str() const
String representation.
Definition: Pathname.h:110
DownloadSpec _spec
Definition: base_p.h:98
const Url & url() const
Definition: downloadspec.cc:50
static zyppng::NetworkRequestError customError(NetworkRequestError::Type t, std::string &&errorMsg="", std::map< std::string, boost::any > &&extraInfo={})
zypp::ByteCount downloadedByteCount() const
Returns the number of already downloaded bytes as reported by the backend.
Definition: request.cc:1313
std::vector< char > peekData(off_t offset, size_t count) const
Definition: request.cc:1240
std::string contentType() const
Returns the content type as reported from the server.
Definition: request.cc:1291
Definition: Arch.h:361
std::vector< char > peek_data_fd(FILE *fd, off_t offset, size_t count)
Definition: request.cc:57
virtual void handleRequestProgress(NetworkRequest &req, off_t dltotal, off_t dlnow)
std::shared_ptr< Request > _request
virtual bool initializeRequest(std::shared_ptr< Request > &r)
virtual void gotFinished() override
Signal< void() > _sigGotMetadata
std::shared_ptr< FinishedState > transitionToFinished()
virtual void handleRequestProgress(NetworkRequest &req, off_t dltotal, off_t dlnow) override
bool initializeRequest(std::shared_ptr< Request > &r) override
DlMetaLinkInfoState(DownloadPrivate &parent)
std::shared_ptr< PrepareMultiState > transitionToPrepareMulti()
#define MIL
Definition: Logger.h:96
#define WAR
Definition: Logger.h:97