libzypp  17.37.18
MediaHandlerFactory.cc
Go to the documentation of this file.
1 #include "MediaHandlerFactory.h"
2 
3 #include <zypp-core/APIConfig.h>
7 #include <zypp-core/base/Env.h>
8 
9 #include <zypp-media/MediaException>
11 
12 #include <zypp/media/MediaNFS.h>
13 #include <zypp/media/MediaCD.h>
14 #include <zypp/media/MediaDIR.h>
15 #include <zypp/media/MediaDISK.h>
16 #include <zypp/media/MediaCIFS.h>
17 #include <zypp/media/MediaCurl.h>
18 #include <zypp/media/MediaCurl2.h>
19 #include <zypp/media/MediaISO.h>
20 #include <zypp/media/MediaPlugin.h>
22 
23 #include <optional>
24 
25 namespace zypp::media {
26 
28  {
29 
30  }
31 
32  std::optional<MediaHandlerFactory::MediaHandlerType> MediaHandlerFactory::handlerType(const Url &url)
33  {
34  std::string scheme = url.getScheme();
35  if (scheme == "cd" || scheme == "dvd")
36  return MediaCDType;
37  else if (scheme == "nfs" || scheme == "nfs4")
38  return MediaNFSType;
39  else if (scheme == "iso")
40  return MediaISOType;
41  else if (scheme == "file" || scheme == "dir")
42  return MediaFileType;
43  else if (scheme == "hd" )
44  return MediaDISKType;
45  else if (scheme == "cifs" || scheme == "smb")
46  return MediaCIFSType;
47  else if (scheme == "ftp" || scheme == "tftp" || scheme == "http" || scheme == "https")
48  return MediaCURLType;
49  else if (scheme == "plugin" )
50  return MediaPluginType;
51  return {};
52  }
53 
54  std::unique_ptr<MediaHandler> MediaHandlerFactory::createHandler( const MirroredOrigin &origin, const Pathname &preferred_attach_point )
55  {
56  using namespace zyppng::operators;
57 
58  if ( !origin.isValid() ) {
59  MIL << "MirroredOrigin is invalid" << std::endl;
60  ZYPP_THROW(MediaException("Can not create a MediaHandler without a authority Url."));
61  }
62 
63  std::optional<MirroredOrigin> resolvedOrigin;
64  std::optional<MediaHandlerFactory::MediaHandlerType> hdlType; // Handler type as detected from primary
65 
66  const auto &resolveEndpoint = [&]( const OriginEndpoint &u ) {
67  if( !u.isValid() ) {
68  MIL << "OriginEndpoint is not valid" << std::endl;
70  }
71 
72  UrlResolverPlugin::HeaderList custom_headers;
73  if ( u.hasConfig("http-headers") )
74  custom_headers = u.getConfig<UrlResolverPlugin::HeaderList>( "http-headers" );
75 
76  Url url = UrlResolverPlugin::resolveUrl(u.url(), custom_headers);
77  MIL << "Trying scheme '" << url.getScheme() << "'" << std::endl;
78 
79  if ( !handlerType( url ) ) {
81  }
82 
83  OriginEndpoint resolvedEndpoint( url, u.config() ); // keep settings that were passed in
84  if ( !custom_headers.empty () ) {
85  resolvedEndpoint.setConfig ( "http-headers", std::move(custom_headers) );
86  }
87 
88  return zyppng::expected<OriginEndpoint>::success(resolvedEndpoint);
89  };
90 
91  using zyppng::operators::operator |;
92  (resolveEndpoint( origin.authority() ) // first resolve the authority, that one needs to work always
93  | and_then([&]( OriginEndpoint ep ) {
94  hdlType = handlerType ( ep.url() );
95  resolvedOrigin = MirroredOrigin( std::move(ep) );
96 
97  // we have a valid origin, now resolve everything else
98  return zyppng::transform_collect( std::vector<OriginEndpoint>(origin.mirrors ()), resolveEndpoint );
99 
100  })
101  | and_then([&]( std::vector<OriginEndpoint> resolvedMirrs ) {
102  std::for_each( resolvedMirrs.begin (), resolvedMirrs.end(), [&]( const OriginEndpoint &rEp ){
103 
104  if ( handlerType (rEp.url()) != hdlType ) {
105  // we ignore if we have a Url handler different than the primary one
106  // Urls should be grouped by type already from the calling code
107  MIL << "Different handler type than primary URL, ignoring" << std::endl;
108  return;
109  }
110  resolvedOrigin->addMirror(rEp);
111 
112  });
114 
115  })).unwrap(); // throw on error
116 
117 
118  // should not happen, we will at least always have the primary Url here.
119  // But for completeness we check
120  if ( !resolvedOrigin ) {
121  ZYPP_THROW(MediaException("No valid Url left after resolving."));
122  }
123 
124  if ( resolvedOrigin->endpointCount() > 1 && *hdlType != MediaCURLType )
125  ERR << "Got mirrors for handler type: " << *hdlType << " they will be ignored!" << std::endl;
126 
127  std::unique_ptr<MediaHandler> _handler;
128  switch(*hdlType) {
129  case MediaCDType: {
130  _handler = std::make_unique<MediaCD> (*resolvedOrigin,preferred_attach_point);
131  break;
132  }
133  case MediaNFSType: {
134  _handler = std::make_unique<MediaNFS> (*resolvedOrigin,preferred_attach_point);
135  break;
136  }
137  case MediaISOType: {
138  _handler = std::make_unique<MediaISO> (*resolvedOrigin,preferred_attach_point);
139  break;
140  }
141  case MediaFileType: {
142  _handler = std::make_unique<MediaDIR> (*resolvedOrigin,preferred_attach_point);
143  break;
144  }
145  case MediaDISKType: {
146  _handler = std::make_unique<MediaDISK> (*resolvedOrigin,preferred_attach_point);
147  break;
148  }
149  case MediaCIFSType: {
150  _handler = std::make_unique<MediaCIFS> (*resolvedOrigin,preferred_attach_point);
151  break;
152  }
153  case MediaCURLType: {
154  enum WhichHandler { choose, curl, curl2 };
155  WhichHandler which = choose;
156  // Leagcy: choose handler in Url query
157  if ( const std::string & queryparam = resolvedOrigin->authority().url().getQueryParam("mediahandler"); ! queryparam.empty() ) {
158  if ( queryparam == "curl" )
159  which = curl;
160  else if ( queryparam == "curl2" )
161  which = curl2;
162  else if ( queryparam == "network" || queryparam == "multicurl" )
163  which = choose; // old backends, choose default
164  else
165  WAR << "Unknown mediahandler='" << queryparam << "' in URL; Choosing the default" << std::endl;
166  }
167  // Otherwise choose handler through ENV
168  if ( which == choose ) {
169  TriBool envstate = env::getenvBool( "ZYPP_CURL2" );
170  if ( indeterminate(envstate) ) {
171 #if APIConfig(LIBZYPP_CONFIG_USE_LEGACY_CURL_BACKEND_BY_DEFAULT)
172  which = curl;
173 #else
174  which = curl2;
175 #endif
176  } else {
177  which = bool(envstate) ? curl2 : curl;
178  }
179  }
180  // Finally use the default
181  std::unique_ptr<MediaNetworkCommonHandler> handler;
182  switch ( which ) {
183  default:
184  case curl2:
185  handler = std::make_unique<MediaCurl2>( *resolvedOrigin, preferred_attach_point );
186  break;
187  case curl:
188  handler = std::make_unique<MediaCurl>( *resolvedOrigin, preferred_attach_point );
189  break;
190  }
191  _handler = std::move(handler);
192  break;
193  }
194  case MediaPluginType: {
195  // bsc#1228208: MediaPluginType must be resolved to a valid schema by the
196  // above UrlResolverPlugin::resolveUrl call. MediaPlugin exists as a stub,
197  // but is not a usable handler type.
198  ZYPP_THROW(MediaUnsupportedUrlSchemeException(resolvedOrigin->authority().url()));
199  break;
200  }
201  }
202 
203  if ( !_handler ) {
204  ZYPP_THROW(MediaUnsupportedUrlSchemeException(resolvedOrigin->authority().url()));
205  }
206 
207  // check created handler
208  if ( !_handler ){
209  ERR << "Failed to create media handler" << std::endl;
210  ZYPP_THROW(MediaSystemException(resolvedOrigin->authority().url(), "Failed to create media handler"));
211  }
212 
213  MIL << "Opened: " << *_handler << std::endl;
214  return _handler;
215  }
216 
217 }
std::string getScheme() const
Returns the scheme name of the URL.
Definition: Url.cc:551
#define MIL
Definition: Logger.h:100
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:459
static Url resolveUrl(const Url &url, HeaderList &headers)
Resolves an url using the installed plugins If no plugin is found the url is resolved as its current ...
const zypp::Url & url() const
#define ZYPP_EXCPT_PTR(EXCPT)
Drops a logline and returns Exception as a std::exception_ptr.
Definition: Exception.h:463
std::unique_ptr< MediaHandler > _handler
#define ERR
Definition: Logger.h:102
boost::logic::tribool TriBool
3-state boolean logic (true, false and indeterminate).
Definition: String.h:31
TriBool getenvBool(const C_Str &var_r)
If the environment variable var_r is set to a legal true or false string return bool, else indeterminate.
Definition: Env.h:32
auto transform_collect(Container< Msg, CArgs... > &&in, Transformation &&f)
Definition: expected.h:666
Manages a data source characterized by an authoritative URL and a list of mirror URLs.
Just inherits Exception to separate media exceptions.
#define WAR
Definition: Logger.h:101
const std::vector< OriginEndpoint > & mirrors() const
static std::optional< MediaHandlerType > handlerType(const Url &url)
static expected success(ConsParams &&...params)
Definition: expected.h:115
std::multimap< std::string, std::string > HeaderList
static std::unique_ptr< MediaHandler > createHandler(const MirroredOrigin &origin, const Pathname &preferred_attach_point)
ResultType and_then(const expected< T, E > &exp, Function &&f)
Definition: expected.h:423
const OriginEndpoint & authority() const
Represents a single, configurable network endpoint, combining a URL with specific access settings...
Url manipulation class.
Definition: Url.h:92