You need to sign in or sign up before continuing.
Commit 4e2a551f authored by Eugene Gorodinsky's avatar Eugene Gorodinsky Committed by Eugene Gorodinsky

Add runtime enumeration of supported schemas.

Fix src/ls.cxx to only print unique schemas. Refactor src/ls.cxx to use src/input/InputPlugin functionality. Add dynamic enumeration support to curl plugin.
parent 38d0f02e
......@@ -21,15 +21,54 @@
#include "util/StringCompare.hxx"
#include <assert.h>
#include <algorithm>
#include <iterator>
bool
InputPlugin::SupportsUri(const char *uri) const noexcept
{
assert(prefixes != nullptr);
for (auto i = prefixes; *i != nullptr; ++i)
if (StringStartsWithIgnoreCase(uri, *i))
return true;
assert(prefixes || protocols);
if (prefixes != nullptr) {
for (auto i = prefixes; *i != nullptr; ++i)
if (StringStartsWithIgnoreCase(uri, *i))
return true;
} else {
for (auto schema : protocols()) {
if (StringStartsWithIgnoreCase(uri, schema.c_str())){
return true;
}
}
}
return false;
}
// Note: The whitelist has to be ordered alphabetically
constexpr static const char *whitelist[] = {
"ftp",
"ftps",
"gopher",
"http",
"https",
"mmsh",
"mmst",
"rtmp",
"rtmpe",
"rtmps",
"rtmpt",
"rtmpte",
"rtmpts",
"rtp",
"scp",
"sftp",
"smb",
"srtp",
};
bool
protocol_is_whitelisted(const char *proto) {
auto begin = std::begin(whitelist);
auto end = std::end(whitelist);
return std::binary_search(begin, end, proto, [](const char* a, const char* b) {
return strcasecmp(a,b) < 0;
});
}
\ No newline at end of file
......@@ -22,6 +22,9 @@
#include "Ptr.hxx"
#include "util/Compiler.h"
#include <assert.h>
#include <set>
#include <string>
struct ConfigBlock;
class Mutex;
......@@ -63,6 +66,11 @@ struct InputPlugin {
InputStreamPtr (*open)(const char *uri, Mutex &mutex);
/**
* return a set of supported protocols
*/
std::set<std::string> (*protocols)();
/**
* Prepare a #RemoteTagScanner. The operation must be started
* using RemoteTagScanner::Start(). Returns nullptr if the
* plugin does not support this URI.
......@@ -76,6 +84,25 @@ struct InputPlugin {
gcc_pure
bool SupportsUri(const char *uri) const noexcept;
template<typename F>
void ForeachSupportedUri(F lambda) const noexcept {
assert(prefixes || protocols);
if (prefixes != nullptr) {
for (auto schema = prefixes; *schema != nullptr; ++schema) {
lambda(*schema);
}
}
if (protocols != nullptr) {
for (auto schema : protocols()) {
lambda(schema.c_str());
}
}
}
};
bool
protocol_is_whitelisted(const char *proto);
#endif
......@@ -486,4 +486,5 @@ const struct InputPlugin input_plugin_alsa = {
alsa_input_init,
nullptr,
alsa_input_open,
nullptr
};
......@@ -357,4 +357,5 @@ const InputPlugin input_plugin_cdio_paranoia = {
input_cdio_init,
nullptr,
input_cdio_open,
nullptr
};
......@@ -471,16 +471,25 @@ input_curl_open(const char *url, Mutex &mutex)
return CurlInputStream::Open(url, {}, mutex);
}
static constexpr const char *curl_prefixes[] = {
"http://",
"https://",
nullptr
};
static std::set<std::string>
input_curl_protocols() {
std::set<std::string> protocols;
auto version_info = curl_version_info(CURLVERSION_FIRST);
for (auto proto_ptr = version_info->protocols; *proto_ptr != nullptr; proto_ptr++) {
if (protocol_is_whitelisted(*proto_ptr)) {
std::string schema(*proto_ptr);
schema.append("://");
protocols.emplace(schema);
}
}
return protocols;
}
const struct InputPlugin input_plugin_curl = {
"curl",
curl_prefixes,
nullptr,
input_curl_init,
input_curl_finish,
input_curl_open,
input_curl_protocols
};
......@@ -25,8 +25,13 @@
#include "lib/ffmpeg/Init.hxx"
#include "lib/ffmpeg/Error.hxx"
#include "../InputStream.hxx"
#include "../InputPlugin.hxx"
#include "PluginUnavailable.hxx"
#include "util/StringAPI.hxx"
#include "../InputPlugin.hxx"
#include <iostream>
#include <exception>
#include <typeinfo>
#include <stdexcept>
class FfmpegInputStream final : public InputStream {
Ffmpeg::IOContext io;
......@@ -71,6 +76,22 @@ input_ffmpeg_init(EventLoop &, const ConfigBlock &)
throw PluginUnavailable("No protocol");
}
static std::set<std::string>
input_ffmpeg_protocols() {
void *opaque = nullptr;
const char* protocol;
std::set<std::string> protocols;
while ((protocol = avio_enum_protocols(&opaque, 0))) {
if (protocol_is_whitelisted(protocol)) {
std::string schema(protocol);
schema.append("://");
protocols.emplace(schema);
}
}
return protocols;
}
static InputStreamPtr
input_ffmpeg_open(const char *uri,
Mutex &mutex)
......@@ -111,20 +132,11 @@ FfmpegInputStream::Seek(offset_type new_offset)
offset = result;
}
static constexpr const char *ffmpeg_prefixes[] = {
"gopher://",
"rtp://",
"rtsp://",
"rtmp://",
"rtmpt://",
"rtmps://",
nullptr
};
const InputPlugin input_plugin_ffmpeg = {
"ffmpeg",
ffmpeg_prefixes,
nullptr,
input_ffmpeg_init,
nullptr,
input_ffmpeg_open,
input_ffmpeg_protocols
};
......@@ -110,4 +110,5 @@ const InputPlugin input_plugin_mms = {
nullptr,
nullptr,
input_mms_open,
nullptr
};
......@@ -232,4 +232,5 @@ const InputPlugin input_plugin_nfs = {
input_nfs_init,
input_nfs_finish,
input_nfs_open,
nullptr
};
......@@ -219,5 +219,6 @@ const InputPlugin qobuz_input_plugin = {
InitQobuzInput,
FinishQobuzInput,
OpenQobuzInput,
nullptr,
ScanQobuzTags,
};
......@@ -162,4 +162,5 @@ const InputPlugin input_plugin_smbclient = {
input_smbclient_init,
nullptr,
input_smbclient_open,
nullptr
};
......@@ -249,5 +249,6 @@ const InputPlugin tidal_input_plugin = {
InitTidalInput,
FinishTidalInput,
OpenTidalInput,
nullptr,
ScanTidalTags,
};
......@@ -22,28 +22,41 @@
#include "input/Registry.hxx"
#include "input/InputPlugin.hxx"
#include "client/Response.hxx"
#include "util/ASCII.hxx"
#include "util/UriUtil.hxx"
#include <assert.h>
#include <string>
void print_supported_uri_schemes_to_fp(FILE *fp)
{
#ifdef HAVE_UN
fprintf(fp, " file://");
#endif
std::set<std::string> protocols;
input_plugins_for_each(plugin)
for (auto i = plugin->prefixes; *i != nullptr; ++i)
fprintf(fp, " %s", *i);
plugin->ForeachSupportedUri([&](const char* uri) {
protocols.emplace(uri);
});
for (auto protocol : protocols) {
fprintf(fp, " %s", protocol.c_str());
}
fprintf(fp,"\n");
}
void
print_supported_uri_schemes(Response &r)
{
std::set<std::string> protocols;
input_plugins_for_each_enabled(plugin)
for (auto i = plugin->prefixes; *i != nullptr; ++i)
r.Format("handler: %s\n", *i);
plugin->ForeachSupportedUri([&](const char* uri) {
protocols.emplace(uri);
});
for (auto protocol : protocols) {
r.Format("handler: %s\n", protocol.c_str());
}
}
bool
......@@ -52,9 +65,7 @@ uri_supported_scheme(const char *uri) noexcept
assert(uri_has_scheme(uri));
input_plugins_for_each_enabled(plugin)
for (auto i = plugin->prefixes; *i != nullptr; ++i)
if (StringStartsWithCaseASCII(uri, *i))
return true;
return plugin->SupportsUri(uri);
return false;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment