diff --git a/NEWS b/NEWS
index 2c68bfa10..4f1acfbc4 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,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/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 d17a95f1e..5e43c9a40 100644
--- a/src/input/InputStream.cxx
+++ b/src/input/InputStream.cxx
@@ -20,7 +20,7 @@
 #include "config.h"
 #include "InputStream.hxx"
 #include "thread/Cond.hxx"
-#include "util/StringCompare.hxx"
+#include "util/ASCII.hxx"
 
 #include <stdexcept>
 
@@ -77,8 +77,8 @@ gcc_pure
 static bool
 ExpensiveSeeking(const char *uri) noexcept
 {
-	return StringStartsWith(uri, "http://") ||
-		StringStartsWith(uri, "https://");
+	return StringStartsWithCaseASCII(uri, "http://") ||
+		StringStartsWithCaseASCII(uri, "https://");
 }
 
 bool
diff --git a/src/input/plugins/AlsaInputPlugin.cxx b/src/input/plugins/AlsaInputPlugin.cxx
index d38fcc5f8..c1620ff27 100644
--- a/src/input/plugins/AlsaInputPlugin.cxx
+++ b/src/input/plugins/AlsaInputPlugin.cxx
@@ -33,7 +33,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/DeferredMonitor.hxx"
@@ -147,7 +147,7 @@ private:
 inline InputStream *
 AlsaInputStream::Create(const char *uri, Mutex &mutex, Cond &cond)
 {
-	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 e5a63a8d6..595b0d875 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/StringUtil.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 d9887727f..d865c9b7a 100644
--- a/src/input/plugins/CurlInputPlugin.cxx
+++ b/src/input/plugins/CurlInputPlugin.cxx
@@ -458,8 +458,8 @@ CurlInputStream::Open(const char *url, Mutex &mutex, Cond &cond)
 static InputStream *
 input_curl_open(const char *url, Mutex &mutex, Cond &cond)
 {
-	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, cond);
diff --git a/src/input/plugins/FfmpegInputPlugin.cxx b/src/input/plugins/FfmpegInputPlugin.cxx
index 9ca16aa67..5a55d6e1d 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 <libavformat/avio.h>
@@ -85,12 +85,12 @@ static InputStream *
 input_ffmpeg_open(const char *uri,
 		  Mutex &mutex, Cond &cond)
 {
-	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 5f420af05..64e25860d 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 <libmms/mmsx.h>
 
@@ -74,10 +74,10 @@ static InputStream *
 input_mms_open(const char *url,
 	       Mutex &mutex, Cond &cond)
 {
-	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 = new MmsInputStream(url, mutex, cond);
diff --git a/src/input/plugins/NfsInputPlugin.cxx b/src/input/plugins/NfsInputPlugin.cxx
index 470cf0282..aeee03a29 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 <string.h>
+#include "util/ASCII.hxx"
 
 /**
  * Do not buffer more than this number of bytes.  It should be a
@@ -219,7 +217,7 @@ static InputStream *
 input_nfs_open(const char *uri,
 	       Mutex &mutex, Cond &cond)
 {
-	if (!StringStartsWith(uri, "nfs://"))
+	if (!StringStartsWithCaseASCII(uri, "nfs://"))
 		return nullptr;
 
 	NfsInputStream *is = new NfsInputStream(uri, mutex, cond);
diff --git a/src/input/plugins/SmbclientInputPlugin.cxx b/src/input/plugins/SmbclientInputPlugin.cxx
index 80d406692..57c828943 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 <libsmbclient.h>
 
@@ -87,7 +87,7 @@ static InputStream *
 input_smbclient_open(const char *uri,
 		     Mutex &mutex, Cond &cond)
 {
-	if (!StringStartsWith(uri, "smb://"))
+	if (!StringStartsWithCaseASCII(uri, "smb://"))
 		return nullptr;
 
 	const std::lock_guard<Mutex> protect(smbclient_mutex);
diff --git a/src/lib/nfs/FileReader.cxx b/src/lib/nfs/FileReader.cxx
index 4bf7a43da..1d030a28f 100644
--- a/src/lib/nfs/FileReader.cxx
+++ b/src/lib/nfs/FileReader.cxx
@@ -24,7 +24,7 @@
 #include "Connection.hxx"
 #include "event/Call.hxx"
 #include "IOThread.hxx"
-#include "util/StringCompare.hxx"
+#include "util/ASCII.hxx"
 
 #include <utility>
 
@@ -93,7 +93,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 72754dd7f..2f3cda603 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 <assert.h>
@@ -97,7 +97,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 88a9606c5..4b97376a8 100644
--- a/src/playlist/plugins/SoundCloudPlaylistPlugin.cxx
+++ b/src/playlist/plugins/SoundCloudPlaylistPlugin.cxx
@@ -24,6 +24,7 @@
 #include "config/Block.hxx"
 #include "input/InputStream.hxx"
 #include "tag/TagBuilder.hxx"
+#include "util/ASCII.hxx"
 #include "util/StringCompare.hxx"
 #include "util/Alloc.hxx"
 #include "util/Domain.hxx"
@@ -68,7 +69,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);
@@ -273,7 +274,7 @@ try {
 static SongEnumerator *
 soundcloud_open_uri(const char *uri, Mutex &mutex, Cond &cond)
 {
-	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 c077b8bb2..8e99f5c56 100644
--- a/src/storage/plugins/CurlStorage.cxx
+++ b/src/storage/plugins/CurlStorage.cxx
@@ -33,6 +33,7 @@
 #include "event/DeferredMonitor.hxx"
 #include "thread/Mutex.hxx"
 #include "thread/Cond.hxx"
+#include "util/ASCII.hxx"
 #include "util/RuntimeError.hxx"
 #include "util/StringCompare.hxx"
 #include "util/StringFormat.hxx"
@@ -590,8 +591,8 @@ CurlStorage::OpenDirectory(const char *uri_utf8)
 static Storage *
 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 new CurlStorage(event_loop, uri);
diff --git a/src/storage/plugins/NfsStorage.cxx b/src/storage/plugins/NfsStorage.cxx
index 6ef6266aa..b2eec24ff 100644
--- a/src/storage/plugins/NfsStorage.cxx
+++ b/src/storage/plugins/NfsStorage.cxx
@@ -35,6 +35,7 @@
 #include "event/Call.hxx"
 #include "event/DeferredMonitor.hxx"
 #include "event/TimeoutMonitor.hxx"
+#include "util/ASCII.hxx"
 #include "util/StringCompare.hxx"
 
 extern "C" {
@@ -401,11 +402,10 @@ NfsStorage::OpenDirectory(const char *uri_utf8)
 static Storage *
 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 67d8c3bca..8c279f300 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"
 
@@ -182,7 +183,7 @@ SmbclientDirectoryReader::GetInfo(gcc_unused bool follow)
 static Storage *
 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/UriUtil.cxx b/src/util/UriUtil.cxx
index 61b90da29..bf663cfcd 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 <assert.h>
@@ -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;
 	}