Documentation can be found here: http://en.opensuse.org/openSUSE:Libzypp_plugins
TmpDir tmpCachePath;
RepoManagerOptions opts( RepoManagerOptions::makeTestSetup( tmpCachePath ) ) ;
- filesystem::mkdir( opts.knownReposPath );
- filesystem::mkdir( opts.servicePluginsPath );
+ filesystem::assert_dir( opts.knownReposPath );
+ filesystem::assert_dir( opts.pluginsPath / "services");
- opts.servicePluginsPath = DATADIR + "/plugin-service-lib-1";
- BOOST_CHECK(PathInfo(opts.servicePluginsPath / "service").isExist());
+ opts.pluginsPath = DATADIR + "/plugin-service-lib-1";
+ BOOST_CHECK(PathInfo(opts.pluginsPath / "services/service").isExist());
{
RepoManager manager(opts);
ServiceInfo service(*manager.serviceBegin());
BOOST_CHECK_EQUAL("service", service.alias());
- BOOST_CHECK_EQUAL( "file:" + DATADIR.asString() + "/plugin-service-lib-1/service", service.url().asString());
+ BOOST_CHECK_EQUAL( "file:" + DATADIR.asString() + "/plugin-service-lib-1/services/service", service.url().asString());
// now refresh the service
manager.refreshServices();
}
// Now simulate the service changed
- opts.servicePluginsPath = DATADIR + "/plugin-service-lib-2";
+ opts.pluginsPath = DATADIR + "/plugin-service-lib-2";
{
RepoManager manager(opts);
BOOST_REQUIRE_EQUAL(1, manager.serviceSize());
ServiceInfo service(*manager.serviceBegin());
BOOST_CHECK_EQUAL("service", service.alias());
- BOOST_CHECK_EQUAL( "file:" + DATADIR.asString() + "/plugin-service-lib-2/service", service.url().asString());
+ BOOST_CHECK_EQUAL( "file:" + DATADIR.asString() + "/plugin-service-lib-2/services/service", service.url().asString());
// now refresh the service
manager.refreshServices();
BOOST_CHECK_EQUAL((unsigned) 1, manager.repoSize());
media/MetaLinkParser.cc
media/ZsyncParser.cc
media/MediaBlockList.cc
+ media/UrlResolverPlugin.cc
)
SET( zypp_media_HEADERS
media/MetaLinkParser.h
media/ZsyncParser.h
media/MediaBlockList.h
+ media/UrlResolverPlugin.h
)
INSTALL( FILES
repoPackagesCachePath = Pathname::assertprefix( root_r, ZConfig::instance().repoPackagesPath() );
knownReposPath = Pathname::assertprefix( root_r, ZConfig::instance().knownReposPath() );
knownServicesPath = Pathname::assertprefix( root_r, ZConfig::instance().knownServicesPath() );
- servicePluginsPath = Pathname::assertprefix( root_r, ZConfig::instance().servicePluginsPath() );
+ pluginsPath = Pathname::assertprefix( root_r, ZConfig::instance().pluginsPath() );
probe = ZConfig::instance().repo_add_probe();
rootDir = root_r;
ret.repoPackagesCachePath = root_r/"packages";
ret.knownReposPath = root_r/"repos.d";
ret.knownServicesPath = root_r/"services.d";
- ret.servicePluginsPath = root_r/"plugin-services";
+ ret.pluginsPath = root_r/"plugins";
ret.rootDir = root_r;
return ret;
}
}
}
- repo::PluginServices(options.servicePluginsPath, ServiceCollector(services));
+ repo::PluginServices(options.pluginsPath/"services", ServiceCollector(services));
}
void RepoManager::Impl::init_knownRepositories()
Pathname repoPackagesCachePath;
Pathname knownReposPath;
Pathname knownServicesPath;
- Pathname servicePluginsPath;
+ Pathname pluginsPath;
bool probe;
/**
* Target distro ID to be used when refreshing repo index services.
Pathname ZConfig::pluginsPath() const
{ return _pimpl->pluginsPath.get(); }
- Pathname ZConfig::mediaPluginsPath() const
- { return pluginsPath() / "media"; }
-
- Pathname ZConfig::servicePluginsPath() const
- { return pluginsPath() / "services"; }
-
///////////////////////////////////////////////////////////////////
std::ostream & ZConfig::about( std::ostream & str ) const
*/
Pathname pluginsPath() const;
- /**
- * Defaults to \ref pluginsPath()/media
- */
- Pathname mediaPluginsPath() const;
-
- /**
- * Defaults to \ref pluginsPath()/services
- */
- Pathname servicePluginsPath() const;
//@}
public:
class Impl;
#include <ctype.h>
#include <iostream>
+#include <map>
#include "zypp/base/Logger.h"
+#include "zypp/ZConfig.h"
+#include "zypp/PluginScript.h"
#include "zypp/ExternalProgram.h"
#include "zypp/media/MediaException.h"
#include "zypp/media/MediaMultiCurl.h"
#include "zypp/media/MediaISO.h"
#include "zypp/media/MediaPlugin.h"
+#include "zypp/media/UrlResolverPlugin.h"
using namespace std;
// open URL
void
-MediaAccess::open (const Url& url, const Pathname & preferred_attach_point)
+MediaAccess::open (const Url& o_url, const Pathname & preferred_attach_point)
{
- if(!url.isValid()) {
+ if(!o_url.isValid()) {
MIL << "Url is not valid" << endl;
- ZYPP_THROW(MediaBadUrlException(url));
+ ZYPP_THROW(MediaBadUrlException(o_url));
}
close();
+ UrlResolverPlugin::HeaderList custom_headers;
+ Url url = UrlResolverPlugin::resolveUrl(o_url, custom_headers);
+
std::string scheme = url.getScheme();
-
MIL << "Trying scheme '" << scheme << "'" << endl;
+
/*
** WARNING: Don't forget to update MediaAccess::downloads(url)
** if you are adding a new url scheme / handler!
use_aria = false;
}
+ MediaCurl *curl;
+
if ( use_aria )
- _handler = new MediaAria2c (url,preferred_attach_point);
- else if ( use_multicurl )
- _handler = new MediaMultiCurl (url,preferred_attach_point);
+ curl = new MediaAria2c (url,preferred_attach_point);
+ else if ( use_multicurl )
+ curl = new MediaMultiCurl (url,preferred_attach_point);
else
- _handler = new MediaCurl (url,preferred_attach_point);
+ curl = new MediaCurl (url,preferred_attach_point);
+
+ UrlResolverPlugin::HeaderList::const_iterator it;
+ for (it = custom_headers.begin();
+ it != custom_headers.end();
+ ++it) {
+ std::string header = it->first + ": " + it->second;
+ MIL << "Added custom header -> " << header << endl;
+ curl->settings().addHeader(header);
+ }
+ _handler = curl;
}
else if (scheme == "plugin" )
_handler = new MediaPlugin (url,preferred_attach_point);
}
s.setAuthType(use_auth);
}
+
+ // workarounds
+ std::string head_requests( url.getQueryParam("head_requests"));
+ if( !head_requests.empty() && head_requests == "no")
+ s.setHeadRequestsAllowed(false);
}
/**
}
}
+TransferSettings & MediaCurl::settings()
+{
+ return _settings;
+}
+
+
void MediaCurl::setCookieFile( const Pathname &fileName )
{
_cookieFile = fileName;
SET_OPTION(CURLOPT_FAILONERROR, 1L);
SET_OPTION(CURLOPT_NOSIGNAL, 1L);
- // reset settings in case we are re-attaching
- _settings.reset();
+ // create non persistant settings
+ // so that we don't add headers twice
+ TransferSettings vol_settings(_settings);
// add custom headers
- _settings.addHeader(anonymousIdHeader());
- _settings.addHeader(distributionFlavorHeader());
- _settings.addHeader("Pragma:");
+ vol_settings.addHeader(anonymousIdHeader());
+ vol_settings.addHeader(distributionFlavorHeader());
+ vol_settings.addHeader("Pragma:");
_settings.setTimeout(TRANSFER_TIMEOUT);
_settings.setConnectTimeout(CONNECT_TIMEOUT);
SET_OPTION(CURLOPT_PROXY_TRANSFER_MODE, 1L );
// append settings custom headers to curl
- for ( TransferSettings::Headers::const_iterator it = _settings.headersBegin();
- it != _settings.headersEnd();
+ for ( TransferSettings::Headers::const_iterator it = vol_settings.headersBegin();
+ it != vol_settings.headersEnd();
++it )
{
-
+ MIL << "HEADER " << *it << std::endl;
+
_customHeaders = curl_slist_append(_customHeaders, it->c_str());
if ( !_customHeaders )
ZYPP_THROW(MediaCurlInitException(_url));
bool MediaCurl::doGetDoesFileExist( const Pathname & filename ) const
{
DBG << filename.asString() << endl;
-
+
if(!_url.isValid())
ZYPP_THROW(MediaBadUrlException(_url));
// works for ftp as well, because retrieving only headers
// ftp will return always OK code ?
// See http://curl.haxx.se/docs/knownbugs.html #58
- if ( _url.getScheme() == "http" || _url.getScheme() == "https" )
+ if ( (_url.getScheme() == "http" || _url.getScheme() == "https") &&
+ _settings.headRequestsAllowed() )
ret = curl_easy_setopt( _curl, CURLOPT_NOBODY, 1L );
else
ret = curl_easy_setopt( _curl, CURLOPT_RANGE, "0-1" );
virtual ~MediaCurl() { try { release(); } catch(...) {} }
+ TransferSettings & settings();
+
static void setCookieFile( const Pathname & );
class Callbacks
, _verify_host(false)
, _verify_peer(false)
, _ca_path("/etc/ssl/certs")
+ , _head_requests_allowed(true)
{}
virtual ~Impl()
bool _verify_host;
bool _verify_peer;
Pathname _ca_path;
+
+ // workarounds
+ bool _head_requests_allowed;
};
TransferSettings::TransferSettings()
return _impl->_authtype;
}
+void TransferSettings::setHeadRequestsAllowed(bool allowed)
+{
+ _impl->_head_requests_allowed = allowed;
+}
+bool TransferSettings::headRequestsAllowed() const
+{
+ return _impl->_head_requests_allowed;
+}
} // ns media
} // ns zypp
*/
std::string authType() const;
+ /**
+ * set whether HEAD requests are allowed
+ */
+ void setHeadRequestsAllowed(bool allowed);
+
+ /**
+ * whether HEAD requests are allowed
+ */
+ bool headRequestsAllowed() const;
+
protected:
class Impl;
RWCOW_pointer<Impl> _impl;
--- /dev/null
+/*---------------------------------------------------------------------\
+| ____ _ __ __ ___ |
+| |__ / \ / / . \ . \ |
+| / / \ V /| _/ _/ |
+| / /__ | | | | | | |
+| /_____||_| |_| |_| |
+| |
+\---------------------------------------------------------------------*/
+/** \file zypp/media/UrlResolverPlugin.cc
+ *
+*/
+#include <iostream>
+#include "zypp/base/Logger.h"
+#include "zypp/media/UrlResolverPlugin.h"
+#include "zypp/media/MediaException.h"
+#include "zypp/PluginScript.h"
+#include "zypp/ZConfig.h"
+
+using std::endl;
+
+///////////////////////////////////////////////////////////////////
+namespace zypp
+{ /////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////
+ namespace media
+ { /////////////////////////////////////////////////////////////////
+
+ /** UrlResolverPlugin implementation. */
+ struct UrlResolverPlugin::Impl
+ {
+
+
+ };
+ ///////////////////////////////////////////////////////////////////
+
+ Url UrlResolverPlugin::resolveUrl(const Url & o_url, HeaderList &headers)
+ {
+ if (o_url.getScheme() != "plugin")
+ return o_url;
+
+ Url url(o_url);
+ std::string name = url.getPathName();
+ Pathname plugin_path = (ZConfig::instance().pluginsPath()/"urlresolver")/name;
+ if (PathInfo(plugin_path).isExist()) {
+ PluginScript scr;
+ scr.open(plugin_path);
+ // send frame to plugin
+ PluginFrame f("RESOLVEURL");
+
+ url::ParamMap params = url.getQueryStringMap();
+ url::ParamMap::const_iterator param_it;
+ for( param_it = params.begin();
+ param_it != params.end();
+ ++param_it)
+ f.setHeader(param_it->first, param_it->second);
+
+ scr.send(f);
+
+ PluginFrame r(scr.receive());
+ if (r.command() == "RESOLVEDURL") {
+ // now set
+ url = Url(r.body());
+ PluginFrame::HeaderListIterator it;
+
+ for (it = r.headerBegin();
+ it != r.headerEnd();
+ ++it) {
+ std::pair<std::string, std::string> values(*it);
+ // curl resets headers that are empty, so we use a workaround
+ if (values.second.empty()) {
+ values.second = "\nX-libcurl-Empty-Header-Workaround: *";
+ }
+ headers.insert(values);
+ }
+ }
+ else if (r.command() == "ERROR") {
+ ZYPP_THROW(MediaException(r.body()));
+ }
+ }
+ return url;
+ }
+
+ /** \relates UrlResolverPlugin::Impl Stream output */
+ inline std::ostream & operator<<( std::ostream & str, const UrlResolverPlugin::Impl & obj )
+ {
+ return str << "UrlResolverPlugin::Impl";
+ }
+
+ UrlResolverPlugin::~UrlResolverPlugin()
+ {}
+
+ std::ostream & operator<<( std::ostream & str, const UrlResolverPlugin & obj )
+ {
+ return str << *obj._pimpl;
+ }
+
+ /////////////////////////////////////////////////////////////////
+ } // namespace media
+ ///////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////
+} // namespace zypp
+///////////////////////////////////////////////////////////////////
--- /dev/null
+/*---------------------------------------------------------------------\
+| ____ _ __ __ ___ |
+| |__ / \ / / . \ . \ |
+| / / \ V /| _/ _/ |
+| / /__ | | | | | | |
+| /_____||_| |_| |_| |
+| |
+\---------------------------------------------------------------------*/
+/** \file zypp/media/UrlResolverPlugin.h
+ *
+*/
+#ifndef ZYPP_MEDIA_URLRESOLVERPLUGIN_H
+#define ZYPP_MEDIA_URLRESOLVERPLUGIN_H
+
+#include <iosfwd>
+#include <map>
+#include <string>
+
+#include "zypp/base/PtrTypes.h"
+#include "zypp/Url.h"
+#include "zypp/PathInfo.h"
+
+///////////////////////////////////////////////////////////////////
+namespace zypp
+{ /////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////
+ namespace media
+ { /////////////////////////////////////////////////////////////////
+
+ /**
+ *
+ */
+ class UrlResolverPlugin
+ {
+ friend std::ostream & operator<<( std::ostream & str, const UrlResolverPlugin & obj );
+
+ public:
+
+ class Impl;
+
+ typedef std::multimap<std::string, std::string> HeaderList;
+
+ /**
+ * Resolves an url using the installed plugins
+ * If no plugin is found the url is resolved as
+ * its current value.
+ *
+ * Custom headers are inserted in the provided header list
+ */
+ static Url resolveUrl(const Url &url, HeaderList &headers);
+
+ public:
+ /** Dtor */
+ ~UrlResolverPlugin();
+
+ private:
+
+ /** Default ctor */
+ UrlResolverPlugin();
+
+ /** Pointer to implementation */
+ RW_pointer<Impl> _pimpl;
+ };
+ ///////////////////////////////////////////////////////////////////
+
+ /** \relates UrlResolverPlugin Stream output */
+ std::ostream & operator<<( std::ostream & str, const UrlResolverPlugin & obj );
+
+ /////////////////////////////////////////////////////////////////
+ } // namespace media
+ ///////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////
+} // namespace zypp
+///////////////////////////////////////////////////////////////////
+#endif // ZYPP_MEDIA_URLRESOLVERPLUGIN_H