summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Kellermann <max@musicpd.org>2019-07-01 09:48:33 +0200
committerMax Kellermann <max@musicpd.org>2019-07-01 09:48:33 +0200
commit44aaf5134556c29fa675169bb3ae3b07efc7a665 (patch)
tree002e381ce5eebc49ba60629470362c81796bb366
parent5b013733568786cf0f508a7935769e9bef7fb2e1 (diff)
parent4e2a551f30c1e1db13933d15c44d9186a2f37959 (diff)
Merge branch 'runtime_enumeration' of git://github.com/eugene2k/MPD
-rw-r--r--src/input/InputPlugin.cxx51
-rw-r--r--src/input/InputPlugin.hxx27
-rw-r--r--src/input/plugins/AlsaInputPlugin.cxx1
-rw-r--r--src/input/plugins/CdioParanoiaInputPlugin.cxx1
-rw-r--r--src/input/plugins/CurlInputPlugin.cxx21
-rw-r--r--src/input/plugins/FfmpegInputPlugin.cxx36
-rw-r--r--src/input/plugins/MmsInputPlugin.cxx1
-rw-r--r--src/input/plugins/NfsInputPlugin.cxx1
-rw-r--r--src/input/plugins/QobuzInputPlugin.cxx1
-rw-r--r--src/input/plugins/SmbclientInputPlugin.cxx1
-rw-r--r--src/input/plugins/TidalInputPlugin.cxx1
-rw-r--r--src/ls.cxx27
12 files changed, 137 insertions, 32 deletions
diff --git a/src/input/InputPlugin.cxx b/src/input/InputPlugin.cxx
index 9af8a6ca8..3b6b58cbe 100644
--- a/src/input/InputPlugin.cxx
+++ b/src/input/InputPlugin.cxx
@@ -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
diff --git a/src/input/InputPlugin.hxx b/src/input/InputPlugin.hxx
index 7834b181a..92aa1ee77 100644
--- a/src/input/InputPlugin.hxx
+++ b/src/input/InputPlugin.hxx
@@ -23,6 +23,9 @@
#include "Ptr.hxx"
#include "thread/Mutex.hxx"
#include "util/Compiler.h"
+#include <assert.h>
+#include <set>
+#include <string>
struct ConfigBlock;
class EventLoop;
@@ -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
diff --git a/src/input/plugins/AlsaInputPlugin.cxx b/src/input/plugins/AlsaInputPlugin.cxx
index ae8ff50cc..552fe8fd0 100644
--- a/src/input/plugins/AlsaInputPlugin.cxx
+++ b/src/input/plugins/AlsaInputPlugin.cxx
@@ -486,4 +486,5 @@ const struct InputPlugin input_plugin_alsa = {
alsa_input_init,
nullptr,
alsa_input_open,
+ nullptr
};
diff --git a/src/input/plugins/CdioParanoiaInputPlugin.cxx b/src/input/plugins/CdioParanoiaInputPlugin.cxx
index fb7a276b3..166feb935 100644
--- a/src/input/plugins/CdioParanoiaInputPlugin.cxx
+++ b/src/input/plugins/CdioParanoiaInputPlugin.cxx
@@ -360,4 +360,5 @@ const InputPlugin input_plugin_cdio_paranoia = {
input_cdio_init,
nullptr,
input_cdio_open,
+ nullptr
};
diff --git a/src/input/plugins/CurlInputPlugin.cxx b/src/input/plugins/CurlInputPlugin.cxx
index 395965335..f43da9a84 100644
--- a/src/input/plugins/CurlInputPlugin.cxx
+++ b/src/input/plugins/CurlInputPlugin.cxx
@@ -470,16 +470,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
};
diff --git a/src/input/plugins/FfmpegInputPlugin.cxx b/src/input/plugins/FfmpegInputPlugin.cxx
index e08caef73..e3ef77fc3 100644
--- a/src/input/plugins/FfmpegInputPlugin.cxx
+++ b/src/input/plugins/FfmpegInputPlugin.cxx
@@ -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;
@@ -73,6 +78,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)
@@ -114,20 +135,11 @@ FfmpegInputStream::Seek(std::unique_lock<Mutex> &, 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
};
diff --git a/src/input/plugins/MmsInputPlugin.cxx b/src/input/plugins/MmsInputPlugin.cxx
index 775b83155..11e2c98c4 100644
--- a/src/input/plugins/MmsInputPlugin.cxx
+++ b/src/input/plugins/MmsInputPlugin.cxx
@@ -110,4 +110,5 @@ const InputPlugin input_plugin_mms = {
nullptr,
nullptr,
input_mms_open,
+ nullptr
};
diff --git a/src/input/plugins/NfsInputPlugin.cxx b/src/input/plugins/NfsInputPlugin.cxx
index 520653924..9ab91397f 100644
--- a/src/input/plugins/NfsInputPlugin.cxx
+++ b/src/input/plugins/NfsInputPlugin.cxx
@@ -232,4 +232,5 @@ const InputPlugin input_plugin_nfs = {
input_nfs_init,
input_nfs_finish,
input_nfs_open,
+ nullptr
};
diff --git a/src/input/plugins/QobuzInputPlugin.cxx b/src/input/plugins/QobuzInputPlugin.cxx
index 0f90903a3..8053f5638 100644
--- a/src/input/plugins/QobuzInputPlugin.cxx
+++ b/src/input/plugins/QobuzInputPlugin.cxx
@@ -219,5 +219,6 @@ const InputPlugin qobuz_input_plugin = {
InitQobuzInput,
FinishQobuzInput,
OpenQobuzInput,
+ nullptr,
ScanQobuzTags,
};
diff --git a/src/input/plugins/SmbclientInputPlugin.cxx b/src/input/plugins/SmbclientInputPlugin.cxx
index a72552d8d..7a20820ad 100644
--- a/src/input/plugins/SmbclientInputPlugin.cxx
+++ b/src/input/plugins/SmbclientInputPlugin.cxx
@@ -166,4 +166,5 @@ const InputPlugin input_plugin_smbclient = {
input_smbclient_init,
nullptr,
input_smbclient_open,
+ nullptr
};
diff --git a/src/input/plugins/TidalInputPlugin.cxx b/src/input/plugins/TidalInputPlugin.cxx
index 7a47d6902..c2c89af4f 100644
--- a/src/input/plugins/TidalInputPlugin.cxx
+++ b/src/input/plugins/TidalInputPlugin.cxx
@@ -251,5 +251,6 @@ const InputPlugin tidal_input_plugin = {
InitTidalInput,
FinishTidalInput,
OpenTidalInput,
+ nullptr,
ScanTidalTags,
};
diff --git a/src/ls.cxx b/src/ls.cxx
index 46ae325d7..c73fd77ac 100644
--- a/src/ls.cxx
+++ b/src/ls.cxx
@@ -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;
}