libzypp  17.37.5
MediaHandlerFactory.cc
Go to the documentation of this file.
1 #include "MediaHandlerFactory.h"
2 
3 #include <zypp-core/APIConfig.h>
4 #include <zypp/base/Logger.h>
5 #include <zypp/base/Env.h>
6 
7 #include <zypp-media/MediaException>
9 
10 #include <zypp/media/MediaNFS.h>
11 #include <zypp/media/MediaCD.h>
12 #include <zypp/media/MediaDIR.h>
13 #include <zypp/media/MediaDISK.h>
14 #include <zypp/media/MediaCIFS.h>
15 #include <zypp/media/MediaCurl.h>
16 #include <zypp/media/MediaCurl2.h>
17 #include <zypp/media/MediaISO.h>
18 #include <zypp/media/MediaPlugin.h>
20 
21 namespace zypp::media {
22 
24  {
25 
26  }
27 
28  std::optional<MediaHandlerFactory::MediaHandlerType> MediaHandlerFactory::handlerType(const Url &url)
29  {
30  std::string scheme = url.getScheme();
31  if (scheme == "cd" || scheme == "dvd")
32  return MediaCDType;
33  else if (scheme == "nfs" || scheme == "nfs4")
34  return MediaNFSType;
35  else if (scheme == "iso")
36  return MediaISOType;
37  else if (scheme == "file" || scheme == "dir")
38  return MediaFileType;
39  else if (scheme == "hd" )
40  return MediaDISKType;
41  else if (scheme == "cifs" || scheme == "smb")
42  return MediaCIFSType;
43  else if (scheme == "ftp" || scheme == "tftp" || scheme == "http" || scheme == "https")
44  return MediaCURLType;
45  else if (scheme == "plugin" )
46  return MediaPluginType;
47  return {};
48  }
49 
50  std::unique_ptr<MediaHandler> MediaHandlerFactory::createHandler(const std::vector<MediaUrl> &o_url, const Pathname &preferred_attach_point )
51  {
52  if ( o_url.empty() ) {
53  MIL << "Url list is empty" << std::endl;
54  ZYPP_THROW(MediaException("Can not create a MediaHandler without a Url."));
55  }
56 
57  std::optional<MediaUrl> primary; // primary URL, this one dictates the initial schmeme and so the handler to be used
58  std::vector<MediaUrl> resolved; // all Mirrors
59  std::optional<MediaHandlerFactory::MediaHandlerType> hdlType; // Handler type as detected from primary
60  std::for_each( o_url.begin (), o_url.end(), [&]( const MediaUrl &u ){
61 
62  if( !u.url().isValid() ) {
63  MIL << "Url is not valid" << std::endl;
65  }
66 
67  UrlResolverPlugin::HeaderList custom_headers;
68  if ( u.hasConfig("http-headers") )
69  custom_headers = u.getConfig<UrlResolverPlugin::HeaderList>( "http-headers" );
70 
71  Url url = UrlResolverPlugin::resolveUrl(u.url(), custom_headers);
72  MIL << "Trying scheme '" << url.getScheme() << "'" << std::endl;
73 
74  auto myHdlType = handlerType( url );
75  if ( !myHdlType ) {
77  }
78  if ( !hdlType )
79  hdlType = myHdlType;
80  else if ( myHdlType != hdlType ) {
81  // we ignore if we have a Url handler different than the primary one
82  // Urls should be grouped by type already from the calling code
83  MIL << "Different handler type than primary URL, ignoring" << std::endl;
84  return;
85  }
86 
87  MediaUrl newUrl( url, u.config()) ; // keep settings that were passed in
88  if ( !custom_headers.empty () ) {
89  newUrl.setConfig ( "http-headers", std::move(custom_headers) );
90  }
91 
92  if ( !primary )
93  primary = newUrl;
94 
95  resolved.push_back (std::move(newUrl));
96  });
97 
98  // should not happen, we will at least always have the primary Url here.
99  // But for completeness we check
100  if ( !primary ) {
101  ZYPP_THROW(MediaException("No valid Url left after resolving."));
102  }
103 
104  if ( resolved.size() > 1 && *hdlType != MediaCURLType )
105  ERR << "Got mirrors for handler type: " << *hdlType << " they will be ignored!" << std::endl;
106 
107  std::unique_ptr<MediaHandler> _handler;
108  switch(*hdlType) {
109  case MediaCDType: {
110  _handler = std::make_unique<MediaCD> (*primary,preferred_attach_point);
111  break;
112  }
113  case MediaNFSType: {
114  _handler = std::make_unique<MediaNFS> (*primary,preferred_attach_point);
115  break;
116  }
117  case MediaISOType: {
118  _handler = std::make_unique<MediaISO> (*primary,preferred_attach_point);
119  break;
120  }
121  case MediaFileType: {
122  _handler = std::make_unique<MediaDIR> (*primary,preferred_attach_point);
123  break;
124  }
125  case MediaDISKType: {
126  _handler = std::make_unique<MediaDISK> (*primary,preferred_attach_point);
127  break;
128  }
129  case MediaCIFSType: {
130  _handler = std::make_unique<MediaCIFS> (*primary,preferred_attach_point);
131  break;
132  }
133  case MediaCURLType: {
134  enum WhichHandler { choose, curl, curl2 };
135  WhichHandler which = choose;
136  // Leagcy: choose handler in Url query
137  if ( const std::string & queryparam = primary->url().getQueryParam("mediahandler"); ! queryparam.empty() ) {
138  if ( queryparam == "curl" )
139  which = curl;
140  else if ( queryparam == "curl2" )
141  which = curl2;
142  else if ( queryparam == "network" || queryparam == "multicurl" )
143  which = choose; // old backends, choose default
144  else
145  WAR << "Unknown mediahandler='" << queryparam << "' in URL; Choosing the default" << std::endl;
146  }
147  // Otherwise choose handler through ENV
148  if ( which == choose ) {
149  TriBool envstate = env::getenvBool( "ZYPP_CURL2" );
150  if ( indeterminate(envstate) ) {
151 #if APIConfig(LIBZYPP_CONFIG_USE_LEGACY_CURL_BACKEND_BY_DEFAULT)
152  which = curl;
153 #else
154  which = curl2;
155 #endif
156  } else {
157  which = bool(envstate) ? curl2 : curl;
158  }
159  }
160  // Finally use the default
161  std::unique_ptr<MediaNetworkCommonHandler> handler;
162  switch ( which ) {
163  default:
164  case curl2:
165  handler = std::make_unique<MediaCurl2>( *primary, resolved, preferred_attach_point );
166  break;
167  case curl:
168  handler = std::make_unique<MediaCurl>( *primary, resolved, preferred_attach_point );
169  break;
170  }
171  _handler = std::move(handler);
172  break;
173  }
174  case MediaPluginType: {
175  // bsc#1228208: MediaPluginType must be resolved to a valid schema by the
176  // above UrlResolverPlugin::resolveUrl call. MediaPlugin exists as a stub,
177  // but is not a usable handler type.
179  break;
180  }
181  }
182 
183  if ( !_handler ) {
185  }
186 
187  // check created handler
188  if ( !_handler ){
189  ERR << "Failed to create media handler" << std::endl;
190  ZYPP_THROW(MediaSystemException(primary->url(), "Failed to create media handler"));
191  }
192 
193  MIL << "Opened: " << *_handler << std::endl;
194  return _handler;
195  }
196 
197 }
std::string getScheme() const
Returns the scheme name of the URL.
Definition: Url.cc:551
#define MIL
Definition: Logger.h:100
boost::logic::tribool TriBool
3-state boolean logic (true, false and indeterminate).
Definition: String.h:31
#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 ...
std::unique_ptr< MediaHandler > _handler
#define ERR
Definition: Logger.h:102
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
Just inherits Exception to separate media exceptions.
#define WAR
Definition: Logger.h:101
static std::optional< MediaHandlerType > handlerType(const Url &url)
static std::unique_ptr< MediaHandler > createHandler(const std::vector< MediaUrl > &o_url, const Pathname &preferred_attach_point)
std::multimap< std::string, std::string > HeaderList
Url manipulation class.
Definition: Url.h:92