diff --git a/NEWS b/NEWS index 653fee008..3c7630132 100644 --- a/NEWS +++ b/NEWS @@ -45,6 +45,7 @@ ver 0.20.21 (not yet released) - simple: allow .mpdignore comments only at start of line * output - httpd: remove broken DLNA support code +* URI schemes are case insensitive ver 0.20.20 (2018/05/22) * protocol diff --git a/configure.ac b/configure.ac index 0904ab17b..5031c1715 100644 --- a/configure.ac +++ b/configure.ac @@ -316,7 +316,7 @@ else fi default_enable_daemon=yes -if test x$host_is_android = xyes || test x$host_is_android = xyes; then +if test x$host_is_android = xyes || test x$host_is_windows = xyes; then default_enable_daemon=no fi AC_ARG_ENABLE(daemon, diff --git a/src/LocateUri.cxx b/src/LocateUri.cxx index 3c0a88584..0c16921a0 100644 --- a/src/LocateUri.cxx +++ b/src/LocateUri.cxx @@ -23,7 +23,7 @@ #include "fs/AllocatedPath.hxx" #include "ls.hxx" #include "util/UriUtil.hxx" -#include "util/StringCompare.hxx" +#include "util/ASCII.hxx" #ifdef ENABLE_DATABASE #include "storage/StorageInterface.hxx" @@ -83,7 +83,7 @@ LocateUri(const char *uri, const Client *client ) { /* skip the obsolete "file://" prefix */ - const char *path_utf8 = StringAfterPrefix(uri, "file://"); + const char *path_utf8 = StringAfterPrefixCaseASCII(uri, "file://"); if (path_utf8 != nullptr) { if (!PathTraitsUTF8::IsAbsolute(path_utf8)) throw std::runtime_error("Malformed file:// URI"); diff --git a/src/input/InputStream.cxx b/src/input/InputStream.cxx index 6dd53456d..da04a6ce1 100644 --- a/src/input/InputStream.cxx +++ b/src/input/InputStream.cxx @@ -21,7 +21,7 @@ #include "InputStream.hxx" #include "Handler.hxx" #include "tag/Tag.hxx" -#include "util/StringCompare.hxx" +#include "util/ASCII.hxx" #include @@ -60,10 +60,10 @@ gcc_pure static bool ExpensiveSeeking(const char *uri) noexcept { - return StringStartsWith(uri, "http://") || - StringStartsWith(uri, "tidal://") || - StringStartsWith(uri, "qobuz://") || - StringStartsWith(uri, "https://"); + return StringStartsWithCaseASCII(uri, "http://") || + StringStartsWithCaseASCII(uri, "tidal://") || + StringStartsWithCaseASCII(uri, "qobuz://") || + StringStartsWithCaseASCII(uri, "https://"); } bool diff --git a/src/input/plugins/AlsaInputPlugin.cxx b/src/input/plugins/AlsaInputPlugin.cxx index 0cfdb59f5..f71261b1f 100644 --- a/src/input/plugins/AlsaInputPlugin.cxx +++ b/src/input/plugins/AlsaInputPlugin.cxx @@ -35,7 +35,7 @@ #include "util/RuntimeError.hxx" #include "util/StringCompare.hxx" #include "util/ReusableArray.hxx" - +#include "util/ASCII.hxx" #include "Log.hxx" #include "event/MultiSocketMonitor.hxx" #include "event/DeferEvent.hxx" @@ -150,7 +150,7 @@ inline InputStreamPtr AlsaInputStream::Create(EventLoop &event_loop, const char *uri, Mutex &mutex) { - const char *device = StringAfterPrefix(uri, "alsa://"); + const char *device = StringAfterPrefixCaseASCII(uri, "alsa://"); if (device == nullptr) return nullptr; diff --git a/src/input/plugins/CdioParanoiaInputPlugin.cxx b/src/input/plugins/CdioParanoiaInputPlugin.cxx index 34b4cdf07..4b08cf990 100644 --- a/src/input/plugins/CdioParanoiaInputPlugin.cxx +++ b/src/input/plugins/CdioParanoiaInputPlugin.cxx @@ -26,7 +26,7 @@ #include "../InputStream.hxx" #include "../InputPlugin.hxx" #include "util/TruncateString.hxx" -#include "util/StringCompare.hxx" +#include "util/ASCII.hxx" #include "util/RuntimeError.hxx" #include "util/Domain.hxx" #include "system/ByteOrder.hxx" @@ -128,7 +128,7 @@ struct cdio_uri { static bool parse_cdio_uri(struct cdio_uri *dest, const char *src) { - if (!StringStartsWith(src, "cdda://")) + if (!StringStartsWithCaseASCII(src, "cdda://")) return false; src += 7; diff --git a/src/input/plugins/CurlInputPlugin.cxx b/src/input/plugins/CurlInputPlugin.cxx index b3832c673..bdbdcac61 100644 --- a/src/input/plugins/CurlInputPlugin.cxx +++ b/src/input/plugins/CurlInputPlugin.cxx @@ -466,8 +466,8 @@ OpenCurlInputStream(const char *uri, static InputStreamPtr input_curl_open(const char *url, Mutex &mutex) { - if (strncmp(url, "http://", 7) != 0 && - strncmp(url, "https://", 8) != 0) + if (!StringStartsWithCaseASCII(url, "http://") && + !StringStartsWithCaseASCII(url, "https://")) return nullptr; return CurlInputStream::Open(url, {}, mutex); diff --git a/src/input/plugins/FfmpegInputPlugin.cxx b/src/input/plugins/FfmpegInputPlugin.cxx index 9a8dc9833..0f922650a 100644 --- a/src/input/plugins/FfmpegInputPlugin.cxx +++ b/src/input/plugins/FfmpegInputPlugin.cxx @@ -28,7 +28,7 @@ #include "../InputStream.hxx" #include "../InputPlugin.hxx" #include "PluginUnavailable.hxx" -#include "util/StringCompare.hxx" +#include "util/ASCII.hxx" extern "C" { #include @@ -85,12 +85,12 @@ static InputStreamPtr input_ffmpeg_open(const char *uri, Mutex &mutex) { - if (!StringStartsWith(uri, "gopher://") && - !StringStartsWith(uri, "rtp://") && - !StringStartsWith(uri, "rtsp://") && - !StringStartsWith(uri, "rtmp://") && - !StringStartsWith(uri, "rtmpt://") && - !StringStartsWith(uri, "rtmps://")) + if (!StringStartsWithCaseASCII(uri, "gopher://") && + !StringStartsWithCaseASCII(uri, "rtp://") && + !StringStartsWithCaseASCII(uri, "rtsp://") && + !StringStartsWithCaseASCII(uri, "rtmp://") && + !StringStartsWithCaseASCII(uri, "rtmpt://") && + !StringStartsWithCaseASCII(uri, "rtmps://")) return nullptr; AVIOContext *h; diff --git a/src/input/plugins/MmsInputPlugin.cxx b/src/input/plugins/MmsInputPlugin.cxx index 87cbcc520..9e600ee10 100644 --- a/src/input/plugins/MmsInputPlugin.cxx +++ b/src/input/plugins/MmsInputPlugin.cxx @@ -22,7 +22,7 @@ #include "input/ThreadInputStream.hxx" #include "input/InputPlugin.hxx" #include "system/Error.hxx" -#include "util/StringCompare.hxx" +#include "util/ASCII.hxx" #include @@ -72,10 +72,10 @@ static InputStreamPtr input_mms_open(const char *url, Mutex &mutex) { - if (!StringStartsWith(url, "mms://") && - !StringStartsWith(url, "mmsh://") && - !StringStartsWith(url, "mmst://") && - !StringStartsWith(url, "mmsu://")) + if (!StringStartsWithCaseASCII(url, "mms://") && + !StringStartsWithCaseASCII(url, "mmsh://") && + !StringStartsWithCaseASCII(url, "mmst://") && + !StringStartsWithCaseASCII(url, "mmsu://")) return nullptr; auto m = std::make_unique(url, mutex); diff --git a/src/input/plugins/NfsInputPlugin.cxx b/src/input/plugins/NfsInputPlugin.cxx index 35ee78f4c..8544243c9 100644 --- a/src/input/plugins/NfsInputPlugin.cxx +++ b/src/input/plugins/NfsInputPlugin.cxx @@ -23,9 +23,7 @@ #include "../InputPlugin.hxx" #include "lib/nfs/Glue.hxx" #include "lib/nfs/FileReader.hxx" -#include "util/StringCompare.hxx" - -#include +#include "util/ASCII.hxx" /** * Do not buffer more than this number of bytes. It should be a @@ -219,7 +217,7 @@ static InputStreamPtr input_nfs_open(const char *uri, Mutex &mutex) { - if (!StringStartsWith(uri, "nfs://")) + if (!StringStartsWithCaseASCII(uri, "nfs://")) return nullptr; auto is = std::make_unique(uri, mutex); diff --git a/src/input/plugins/SmbclientInputPlugin.cxx b/src/input/plugins/SmbclientInputPlugin.cxx index 00b421ee4..84ac47cae 100644 --- a/src/input/plugins/SmbclientInputPlugin.cxx +++ b/src/input/plugins/SmbclientInputPlugin.cxx @@ -25,7 +25,7 @@ #include "../InputPlugin.hxx" #include "PluginUnavailable.hxx" #include "system/Error.hxx" -#include "util/StringCompare.hxx" +#include "util/ASCII.hxx" #include @@ -87,7 +87,7 @@ static InputStreamPtr input_smbclient_open(const char *uri, Mutex &mutex) { - if (!StringStartsWith(uri, "smb://")) + if (!StringStartsWithCaseASCII(uri, "smb://")) return nullptr; const std::lock_guard protect(smbclient_mutex); diff --git a/src/lib/nfs/FileReader.cxx b/src/lib/nfs/FileReader.cxx index 82ce39152..b11a224af 100644 --- a/src/lib/nfs/FileReader.cxx +++ b/src/lib/nfs/FileReader.cxx @@ -23,7 +23,7 @@ #include "Base.hxx" #include "Connection.hxx" #include "event/Call.hxx" -#include "util/StringCompare.hxx" +#include "util/ASCII.hxx" #include @@ -92,7 +92,7 @@ NfsFileReader::Open(const char *uri) { assert(state == State::INITIAL); - if (!StringStartsWith(uri, "nfs://")) + if (!StringStartsWithCaseASCII(uri, "nfs://")) throw std::runtime_error("Malformed nfs:// URI"); uri += 6; diff --git a/src/ls.cxx b/src/ls.cxx index 77543492a..7768510c7 100644 --- a/src/ls.cxx +++ b/src/ls.cxx @@ -20,7 +20,7 @@ #include "config.h" #include "ls.hxx" #include "client/Response.hxx" -#include "util/StringCompare.hxx" +#include "util/ASCII.hxx" #include "util/UriUtil.hxx" #include @@ -103,7 +103,7 @@ uri_supported_scheme(const char *uri) noexcept assert(uri_has_scheme(uri)); while (*urlPrefixes) { - if (StringStartsWith(uri, *urlPrefixes)) + if (StringStartsWithCaseASCII(uri, *urlPrefixes)) return true; urlPrefixes++; } diff --git a/src/playlist/plugins/SoundCloudPlaylistPlugin.cxx b/src/playlist/plugins/SoundCloudPlaylistPlugin.cxx index 3a5df3946..b091003f9 100644 --- a/src/playlist/plugins/SoundCloudPlaylistPlugin.cxx +++ b/src/playlist/plugins/SoundCloudPlaylistPlugin.cxx @@ -27,6 +27,7 @@ #include "config/Block.hxx" #include "input/InputStream.hxx" #include "tag/Builder.hxx" +#include "util/ASCII.hxx" #include "util/StringCompare.hxx" #include "util/Alloc.hxx" #include "util/Domain.hxx" @@ -69,7 +70,7 @@ soundcloud_resolve(const char* uri) { char *u, *ru; - if (StringStartsWith(uri, "https://")) { + if (StringStartsWithCaseASCII(uri, "https://")) { u = xstrdup(uri); } else if (StringStartsWith(uri, "soundcloud.com")) { u = xstrcatdup("https://", uri); @@ -237,7 +238,7 @@ soundcloud_parse_json(const char *url, Yajl::Handle &handle, static std::unique_ptr soundcloud_open_uri(const char *uri, Mutex &mutex) { - assert(strncmp(uri, "soundcloud://", 13) == 0); + assert(StringEqualsCaseASCII(uri, "soundcloud://", 13)); uri += 13; char *u = nullptr; diff --git a/src/storage/plugins/CurlStorage.cxx b/src/storage/plugins/CurlStorage.cxx index 70942b05c..b924c7cd8 100644 --- a/src/storage/plugins/CurlStorage.cxx +++ b/src/storage/plugins/CurlStorage.cxx @@ -34,6 +34,7 @@ #include "event/DeferEvent.hxx" #include "thread/Mutex.hxx" #include "thread/Cond.hxx" +#include "util/ASCII.hxx" #include "util/ChronoUtil.hxx" #include "util/RuntimeError.hxx" #include "util/StringCompare.hxx" @@ -551,8 +552,8 @@ CurlStorage::OpenDirectory(const char *uri_utf8) static std::unique_ptr CreateCurlStorageURI(EventLoop &event_loop, const char *uri) { - if (strncmp(uri, "http://", 7) != 0 && - strncmp(uri, "https://", 8) != 0) + if (!StringStartsWithCaseASCII(uri, "http://") && + !StringStartsWithCaseASCII(uri, "https://")) return nullptr; return std::make_unique(event_loop, uri); diff --git a/src/storage/plugins/NfsStorage.cxx b/src/storage/plugins/NfsStorage.cxx index d43ffb416..fb6a0ffd3 100644 --- a/src/storage/plugins/NfsStorage.cxx +++ b/src/storage/plugins/NfsStorage.cxx @@ -35,6 +35,7 @@ #include "event/Call.hxx" #include "event/DeferEvent.hxx" #include "event/TimerEvent.hxx" +#include "util/ASCII.hxx" #include "util/StringCompare.hxx" extern "C" { @@ -404,11 +405,10 @@ NfsStorage::OpenDirectory(const char *uri_utf8) static std::unique_ptr CreateNfsStorageURI(EventLoop &event_loop, const char *base) { - if (strncmp(base, "nfs://", 6) != 0) + const char *p = StringAfterPrefixCaseASCII(base, "nfs://"); + if (p == nullptr) return nullptr; - const char *p = base + 6; - const char *mount = strchr(p, '/'); if (mount == nullptr) throw std::runtime_error("Malformed nfs:// URI"); diff --git a/src/storage/plugins/SmbclientStorage.cxx b/src/storage/plugins/SmbclientStorage.cxx index 3f393f3b5..cd611e1c0 100644 --- a/src/storage/plugins/SmbclientStorage.cxx +++ b/src/storage/plugins/SmbclientStorage.cxx @@ -27,6 +27,7 @@ #include "fs/Traits.hxx" #include "thread/Mutex.hxx" #include "system/Error.hxx" +#include "util/ASCII.hxx" #include "util/StringCompare.hxx" #include "util/ScopeExit.hxx" @@ -183,7 +184,7 @@ SmbclientDirectoryReader::GetInfo(gcc_unused bool follow) static std::unique_ptr CreateSmbclientStorageURI(gcc_unused EventLoop &event_loop, const char *base) { - if (strncmp(base, "smb://", 6) != 0) + if (!StringStartsWithCaseASCII(base, "smb://")) return nullptr; SmbclientInit(); diff --git a/src/util/ASCII.hxx b/src/util/ASCII.hxx index 6d31d836a..02bca648c 100644 --- a/src/util/ASCII.hxx +++ b/src/util/ASCII.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Max Kellermann + * Copyright (C) 2013-2018 Max Kellermann * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,6 +30,7 @@ #ifndef ASCII_HXX #define ASCII_HXX +#include "StringView.hxx" #include "Compiler.h" #include @@ -69,4 +70,20 @@ StringEqualsCaseASCII(const char *a, const char *b, size_t n) noexcept return strncasecmp(a, b, n) == 0; } +gcc_pure gcc_nonnull_all +static inline bool +StringStartsWithCaseASCII(const char *haystack, StringView needle) noexcept +{ + return StringEqualsCaseASCII(haystack, needle.data, needle.size); +} + +gcc_pure gcc_nonnull_all +static inline const char * +StringAfterPrefixCaseASCII(const char *haystack, StringView needle) noexcept +{ + return StringStartsWithCaseASCII(haystack, needle) + ? haystack + needle.size + : nullptr; +} + #endif diff --git a/src/util/UriUtil.cxx b/src/util/UriUtil.cxx index d976e6b2e..ead69fd0c 100644 --- a/src/util/UriUtil.cxx +++ b/src/util/UriUtil.cxx @@ -18,7 +18,7 @@ */ #include "UriUtil.hxx" -#include "StringCompare.hxx" +#include "ASCII.hxx" #include "CharUtil.hxx" #include @@ -169,7 +169,7 @@ SkipUriScheme(const char *uri) noexcept { const char *const schemes[] = { "http://", "https://", "ftp://" }; for (auto scheme : schemes) { - auto result = StringAfterPrefix(uri, scheme); + auto result = StringAfterPrefixCaseASCII(uri, scheme); if (result != nullptr) return result; }