summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Instance.cxx2
-rw-r--r--src/LocateUri.cxx2
-rw-r--r--src/PlaylistFile.cxx2
-rw-r--r--src/PlaylistSave.cxx2
-rw-r--r--src/SongUpdate.cxx2
-rw-r--r--src/TagStream.cxx2
-rw-r--r--src/command/FileCommands.cxx2
-rw-r--r--src/command/FingerprintCommands.cxx2
-rw-r--r--src/command/PlaylistCommands.cxx2
-rw-r--r--src/db/update/Walk.cxx2
-rw-r--r--src/decoder/Thread.cxx1
-rw-r--r--src/decoder/plugins/GmeDecoderPlugin.cxx2
-rw-r--r--src/lib/upnp/ContentDirectoryService.cxx2
-rw-r--r--src/ls.cxx4
-rw-r--r--src/playlist/PlaylistRegistry.cxx2
-rw-r--r--src/playlist/PlaylistSong.cxx2
-rw-r--r--src/playlist/PlaylistStream.cxx2
-rw-r--r--src/song/BaseSongFilter.cxx2
-rw-r--r--src/song/DetachedSong.cxx2
-rw-r--r--src/storage/Configured.cxx2
-rw-r--r--src/storage/plugins/CurlStorage.cxx4
-rw-r--r--src/util/UriExtract.cxx140
-rw-r--r--src/util/UriExtract.hxx75
-rw-r--r--src/util/UriRelative.cxx82
-rw-r--r--src/util/UriRelative.hxx58
-rw-r--r--src/util/UriUtil.cxx156
-rw-r--r--src/util/UriUtil.hxx59
-rw-r--r--src/util/meson.build2
-rw-r--r--test/ContainerScan.cxx2
-rw-r--r--test/TestUriExtract.cxx33
-rw-r--r--test/TestUriUtil.cxx26
-rw-r--r--test/meson.build1
32 files changed, 415 insertions, 264 deletions
diff --git a/src/Instance.cxx b/src/Instance.cxx
index e0a40f6e2..4933ebd13 100644
--- a/src/Instance.cxx
+++ b/src/Instance.cxx
@@ -27,7 +27,7 @@
#ifdef ENABLE_CURL
#include "RemoteTagCache.hxx"
-#include "util/UriUtil.hxx"
+#include "util/UriExtract.hxx"
#endif
#ifdef ENABLE_DATABASE
diff --git a/src/LocateUri.cxx b/src/LocateUri.cxx
index dcb52bfde..2b8a14e9c 100644
--- a/src/LocateUri.cxx
+++ b/src/LocateUri.cxx
@@ -22,8 +22,8 @@
#include "client/Client.hxx"
#include "fs/AllocatedPath.hxx"
#include "ls.hxx"
-#include "util/UriUtil.hxx"
#include "util/ASCII.hxx"
+#include "util/UriExtract.hxx"
#ifdef ENABLE_DATABASE
#include "storage/StorageInterface.hxx"
diff --git a/src/PlaylistFile.cxx b/src/PlaylistFile.cxx
index 51955b3cc..3edee3aad 100644
--- a/src/PlaylistFile.cxx
+++ b/src/PlaylistFile.cxx
@@ -40,7 +40,7 @@
#include "fs/FileInfo.hxx"
#include "fs/DirectoryReader.hxx"
#include "util/StringCompare.hxx"
-#include "util/UriUtil.hxx"
+#include "util/UriExtract.hxx"
#include <assert.h>
#include <string.h>
diff --git a/src/PlaylistSave.cxx b/src/PlaylistSave.cxx
index cca47e0ba..9c0ec3706 100644
--- a/src/PlaylistSave.cxx
+++ b/src/PlaylistSave.cxx
@@ -30,7 +30,7 @@
#include "fs/FileSystem.hxx"
#include "fs/io/FileOutputStream.hxx"
#include "fs/io/BufferedOutputStream.hxx"
-#include "util/UriUtil.hxx"
+#include "util/UriExtract.hxx"
static void
playlist_print_path(BufferedOutputStream &os, const Path path)
diff --git a/src/SongUpdate.cxx b/src/SongUpdate.cxx
index d843f5ed2..aa9fe9c23 100644
--- a/src/SongUpdate.cxx
+++ b/src/SongUpdate.cxx
@@ -23,12 +23,12 @@
#include "db/plugins/simple/Directory.hxx"
#include "storage/StorageInterface.hxx"
#include "storage/FileInfo.hxx"
-#include "util/UriUtil.hxx"
#include "fs/AllocatedPath.hxx"
#include "fs/FileInfo.hxx"
#include "tag/Builder.hxx"
#include "TagFile.hxx"
#include "TagStream.hxx"
+#include "util/UriExtract.hxx"
#ifdef ENABLE_ARCHIVE
#include "TagArchive.hxx"
diff --git a/src/TagStream.cxx b/src/TagStream.cxx
index 9e23d9e8b..e1f8071eb 100644
--- a/src/TagStream.cxx
+++ b/src/TagStream.cxx
@@ -22,11 +22,11 @@
#include "tag/Handler.hxx"
#include "tag/Builder.hxx"
#include "util/MimeType.hxx"
-#include "util/UriUtil.hxx"
#include "decoder/DecoderList.hxx"
#include "decoder/DecoderPlugin.hxx"
#include "input/InputStream.hxx"
#include "thread/Mutex.hxx"
+#include "util/UriExtract.hxx"
#include <assert.h>
diff --git a/src/command/FileCommands.cxx b/src/command/FileCommands.cxx
index e19adb648..97b5d89fe 100644
--- a/src/command/FileCommands.cxx
+++ b/src/command/FileCommands.cxx
@@ -27,7 +27,7 @@
#include "client/Response.hxx"
#include "util/CharUtil.hxx"
#include "util/StringView.hxx"
-#include "util/UriUtil.hxx"
+#include "util/UriExtract.hxx"
#include "tag/Handler.hxx"
#include "tag/Generic.hxx"
#include "TagStream.hxx"
diff --git a/src/command/FingerprintCommands.cxx b/src/command/FingerprintCommands.cxx
index 460275afe..9b687df71 100644
--- a/src/command/FingerprintCommands.cxx
+++ b/src/command/FingerprintCommands.cxx
@@ -35,7 +35,7 @@
#include "thread/Cond.hxx"
#include "system/Error.hxx"
#include "util/MimeType.hxx"
-#include "util/UriUtil.hxx"
+#include "util/UriExtract.hxx"
class GetChromaprintCommand final
: public ThreadBackgroundCommand, ChromaprintDecoderClient, InputStreamHandler
diff --git a/src/command/PlaylistCommands.cxx b/src/command/PlaylistCommands.cxx
index 1aa630085..cf079c600 100644
--- a/src/command/PlaylistCommands.cxx
+++ b/src/command/PlaylistCommands.cxx
@@ -38,8 +38,8 @@
#include "Mapper.hxx"
#include "fs/AllocatedPath.hxx"
#include "time/ChronoUtil.hxx"
-#include "util/UriUtil.hxx"
#include "util/ConstBuffer.hxx"
+#include "util/UriExtract.hxx"
#include "LocateUri.hxx"
bool
diff --git a/src/db/update/Walk.cxx b/src/db/update/Walk.cxx
index 23db623e5..2c7e2a3e4 100644
--- a/src/db/update/Walk.cxx
+++ b/src/db/update/Walk.cxx
@@ -37,7 +37,7 @@
#include "input/Error.hxx"
#include "util/Alloc.hxx"
#include "util/StringCompare.hxx"
-#include "util/UriUtil.hxx"
+#include "util/UriExtract.hxx"
#include "Log.hxx"
#include <exception>
diff --git a/src/decoder/Thread.cxx b/src/decoder/Thread.cxx
index a37090ffe..747f2438a 100644
--- a/src/decoder/Thread.cxx
+++ b/src/decoder/Thread.cxx
@@ -31,6 +31,7 @@
#include "DecoderList.hxx"
#include "system/Error.hxx"
#include "util/MimeType.hxx"
+#include "util/UriExtract.hxx"
#include "util/UriUtil.hxx"
#include "util/RuntimeError.hxx"
#include "util/Domain.hxx"
diff --git a/src/decoder/plugins/GmeDecoderPlugin.cxx b/src/decoder/plugins/GmeDecoderPlugin.cxx
index b265fbee6..b72132d66 100644
--- a/src/decoder/plugins/GmeDecoderPlugin.cxx
+++ b/src/decoder/plugins/GmeDecoderPlugin.cxx
@@ -30,7 +30,7 @@
#include "util/ScopeExit.hxx"
#include "util/StringFormat.hxx"
#include "util/StringView.hxx"
-#include "util/UriUtil.hxx"
+#include "util/UriExtract.hxx"
#include "util/Domain.hxx"
#include "Log.hxx"
diff --git a/src/lib/upnp/ContentDirectoryService.cxx b/src/lib/upnp/ContentDirectoryService.cxx
index 9ea43ec03..e74f09405 100644
--- a/src/lib/upnp/ContentDirectoryService.cxx
+++ b/src/lib/upnp/ContentDirectoryService.cxx
@@ -21,7 +21,7 @@
#include "UniqueIxml.hxx"
#include "Device.hxx"
#include "ixmlwrap.hxx"
-#include "util/UriUtil.hxx"
+#include "util/UriRelative.hxx"
#include "util/RuntimeError.hxx"
#include "util/SplitString.hxx"
diff --git a/src/ls.cxx b/src/ls.cxx
index cbbe175dc..3826b2412 100644
--- a/src/ls.cxx
+++ b/src/ls.cxx
@@ -22,7 +22,7 @@
#include "input/Registry.hxx"
#include "input/InputPlugin.hxx"
#include "client/Response.hxx"
-#include "util/UriUtil.hxx"
+#include "util/UriExtract.hxx"
#include <assert.h>
@@ -38,7 +38,7 @@ void print_supported_uri_schemes_to_fp(FILE *fp)
plugin->ForeachSupportedUri([&](const char* uri) {
protocols.emplace(uri);
});
-
+
for (auto protocol : protocols) {
fprintf(fp, " %s", protocol.c_str());
}
diff --git a/src/playlist/PlaylistRegistry.cxx b/src/playlist/PlaylistRegistry.cxx
index f24b28201..0571cd904 100644
--- a/src/playlist/PlaylistRegistry.cxx
+++ b/src/playlist/PlaylistRegistry.cxx
@@ -33,9 +33,9 @@
#include "plugins/EmbeddedCuePlaylistPlugin.hxx"
#include "input/InputStream.hxx"
#include "util/MimeType.hxx"
-#include "util/UriUtil.hxx"
#include "util/StringUtil.hxx"
#include "util/StringView.hxx"
+#include "util/UriExtract.hxx"
#include "config/Data.hxx"
#include "config/Block.hxx"
diff --git a/src/playlist/PlaylistSong.cxx b/src/playlist/PlaylistSong.cxx
index f23cfee2b..9d759a934 100644
--- a/src/playlist/PlaylistSong.cxx
+++ b/src/playlist/PlaylistSong.cxx
@@ -22,8 +22,8 @@
#include "tag/Tag.hxx"
#include "tag/Builder.hxx"
#include "fs/Traits.hxx"
-#include "util/UriUtil.hxx"
#include "song/DetachedSong.hxx"
+#include "util/UriExtract.hxx"
#include <algorithm>
#include <string>
diff --git a/src/playlist/PlaylistStream.cxx b/src/playlist/PlaylistStream.cxx
index eb9c3e04d..cad5741a7 100644
--- a/src/playlist/PlaylistStream.cxx
+++ b/src/playlist/PlaylistStream.cxx
@@ -20,10 +20,10 @@
#include "PlaylistStream.hxx"
#include "PlaylistRegistry.hxx"
#include "SongEnumerator.hxx"
-#include "util/UriUtil.hxx"
#include "input/InputStream.hxx"
#include "input/LocalOpen.hxx"
#include "fs/Path.hxx"
+#include "util/UriExtract.hxx"
#include "Log.hxx"
#include <exception>
diff --git a/src/song/BaseSongFilter.cxx b/src/song/BaseSongFilter.cxx
index ab474a94d..ad055504b 100644
--- a/src/song/BaseSongFilter.cxx
+++ b/src/song/BaseSongFilter.cxx
@@ -20,7 +20,7 @@
#include "BaseSongFilter.hxx"
#include "Escape.hxx"
#include "LightSong.hxx"
-#include "util/UriUtil.hxx"
+#include "util/UriRelative.hxx"
std::string
BaseSongFilter::ToExpression() const noexcept
diff --git a/src/song/DetachedSong.cxx b/src/song/DetachedSong.cxx
index 2e3b6dd12..c93580006 100644
--- a/src/song/DetachedSong.cxx
+++ b/src/song/DetachedSong.cxx
@@ -19,7 +19,7 @@
#include "song/DetachedSong.hxx"
#include "song/LightSong.hxx"
-#include "util/UriUtil.hxx"
+#include "util/UriExtract.hxx"
#include "fs/Traits.hxx"
DetachedSong::DetachedSong(const LightSong &other)
diff --git a/src/storage/Configured.cxx b/src/storage/Configured.cxx
index e89a492dd..9052fea85 100644
--- a/src/storage/Configured.cxx
+++ b/src/storage/Configured.cxx
@@ -24,8 +24,8 @@
#include "config/Data.hxx"
#include "fs/StandardDirectory.hxx"
#include "fs/CheckFile.hxx"
-#include "util/UriUtil.hxx"
#include "util/RuntimeError.hxx"
+#include "util/UriExtract.hxx"
static std::unique_ptr<Storage>
CreateConfiguredStorageUri(EventLoop &event_loop, const char *uri)
diff --git a/src/storage/plugins/CurlStorage.cxx b/src/storage/plugins/CurlStorage.cxx
index 4d67b526e..664abb591 100644
--- a/src/storage/plugins/CurlStorage.cxx
+++ b/src/storage/plugins/CurlStorage.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2016 The Music Player Daemon Project
+ * Copyright 2003-2019 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -38,7 +38,7 @@
#include "util/RuntimeError.hxx"
#include "util/StringCompare.hxx"
#include "util/StringFormat.hxx"
-#include "util/UriUtil.hxx"
+#include "util/UriExtract.hxx"
#include <memory>
#include <string>
diff --git a/src/util/UriExtract.cxx b/src/util/UriExtract.cxx
new file mode 100644
index 000000000..ac9eba628
--- /dev/null
+++ b/src/util/UriExtract.cxx
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2008-2019 Max Kellermann <max.kellermann@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "UriExtract.hxx"
+#include "CharUtil.hxx"
+#include "StringView.hxx"
+
+#include <string.h>
+
+static constexpr bool
+IsValidSchemeStart(char ch)
+{
+ return IsLowerAlphaASCII(ch);
+}
+
+static constexpr bool
+IsValidSchemeChar(char ch)
+{
+ return IsLowerAlphaASCII(ch) || IsDigitASCII(ch) ||
+ ch == '+' || ch == '.' || ch == '-';
+}
+
+gcc_pure
+static bool
+IsValidScheme(StringView p) noexcept
+{
+ if (p.empty() || !IsValidSchemeStart(p.front()))
+ return false;
+
+ for (size_t i = 1; i < p.size; ++i)
+ if (!IsValidSchemeChar(p[i]))
+ return false;
+
+ return true;
+}
+
+/**
+ * Return the URI part after the scheme specification (and after the
+ * double slash).
+ */
+gcc_pure
+static const char *
+uri_after_scheme(const char *uri) noexcept
+{
+ if (uri[0] == '/' && uri[1] == '/' && uri[2] != '/')
+ return uri + 2;
+
+ const char *colon = strchr(uri, ':');
+ return colon != nullptr &&
+ IsValidScheme({uri, colon}) &&
+ colon[1] == '/' && colon[2] == '/'
+ ? colon + 3
+ : nullptr;
+}
+
+bool
+uri_has_scheme(const char *uri) noexcept
+{
+ return strstr(uri, "://") != nullptr;
+}
+
+std::string
+uri_get_scheme(const char *uri) noexcept
+{
+ const char *end = strstr(uri, "://");
+ if (end == nullptr)
+ end = uri;
+
+ return std::string(uri, end);
+}
+
+const char *
+uri_get_path(const char *uri) noexcept
+{
+ const char *ap = uri_after_scheme(uri);
+ if (ap != nullptr)
+ return strchr(ap, '/');
+
+ return uri;
+}
+
+/* suffixes should be ascii only characters */
+const char *
+uri_get_suffix(const char *uri) noexcept
+{
+ const char *suffix = strrchr(uri, '.');
+ if (suffix == nullptr || suffix == uri ||
+ suffix[-1] == '/' || suffix[-1] == '\\')
+ return nullptr;
+
+ ++suffix;
+
+ if (strpbrk(suffix, "/\\") != nullptr)
+ return nullptr;
+
+ return suffix;
+}
+
+const char *
+uri_get_suffix(const char *uri, UriSuffixBuffer &buffer) noexcept
+{
+ const char *suffix = uri_get_suffix(uri);
+ if (suffix == nullptr)
+ return nullptr;
+
+ const char *q = strchr(suffix, '?');
+ if (q != nullptr && size_t(q - suffix) < sizeof(buffer.data)) {
+ memcpy(buffer.data, suffix, q - suffix);
+ buffer.data[q - suffix] = 0;
+ suffix = buffer.data;
+ }
+
+ return suffix;
+}
diff --git a/src/util/UriExtract.hxx b/src/util/UriExtract.hxx
new file mode 100644
index 000000000..46af8ae1e
--- /dev/null
+++ b/src/util/UriExtract.hxx
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2008-2019 Max Kellermann <max.kellermann@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef URI_EXTRACT_HXX
+#define URI_EXTRACT_HXX
+
+#include "Compiler.h"
+
+#include <string>
+
+/**
+ * Checks whether the specified URI has a scheme in the form
+ * "scheme://".
+ */
+gcc_pure
+bool
+uri_has_scheme(const char *uri) noexcept;
+
+/**
+ * Returns the scheme name of the specified URI, or an empty string.
+ */
+gcc_pure
+std::string
+uri_get_scheme(const char *uri) noexcept;
+
+/**
+ * Returns the URI path (including the query string) or nullptr if the
+ * given URI has no path.
+ */
+gcc_pure gcc_nonnull_all
+const char *
+uri_get_path(const char *uri) noexcept;
+
+gcc_pure
+const char *
+uri_get_suffix(const char *uri) noexcept;
+
+struct UriSuffixBuffer {
+ char data[8];
+};
+
+/**
+ * Returns the file name suffix, ignoring the query string.
+ */
+gcc_pure
+const char *
+uri_get_suffix(const char *uri, UriSuffixBuffer &buffer) noexcept;
+
+#endif
diff --git a/src/util/UriRelative.cxx b/src/util/UriRelative.cxx
new file mode 100644
index 000000000..7424e052d
--- /dev/null
+++ b/src/util/UriRelative.cxx
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2008-2019 Max Kellermann <max.kellermann@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "UriRelative.hxx"
+
+#include <assert.h>
+#include <string.h>
+
+bool
+uri_is_child(const char *parent, const char *child) noexcept
+{
+#if !CLANG_CHECK_VERSION(3,6)
+ /* disabled on clang due to -Wtautological-pointer-compare */
+ assert(parent != nullptr);
+ assert(child != nullptr);
+#endif
+
+ const size_t parent_length = strlen(parent);
+ return memcmp(parent, child, parent_length) == 0 &&
+ child[parent_length] == '/';
+}
+
+
+bool
+uri_is_child_or_same(const char *parent, const char *child) noexcept
+{
+ return strcmp(parent, child) == 0 || uri_is_child(parent, child);
+}
+
+std::string
+uri_apply_base(const std::string &uri, const std::string &base) noexcept
+{
+ if (uri.front() == '/') {
+ /* absolute path: replace the whole URI path in base */
+
+ auto i = base.find("://");
+ if (i == base.npos)
+ /* no scheme: override base completely */
+ return uri;
+
+ /* find the first slash after the host part */
+ i = base.find('/', i + 3);
+ if (i == base.npos)
+ /* there's no URI path - simply append uri */
+ i = base.length();
+
+ return base.substr(0, i) + uri;
+ }
+
+ std::string out(base);
+ if (out.back() != '/')
+ out.push_back('/');
+
+ out += uri;
+ return out;
+}
diff --git a/src/util/UriRelative.hxx b/src/util/UriRelative.hxx
new file mode 100644
index 000000000..ccfa28e9d
--- /dev/null
+++ b/src/util/UriRelative.hxx
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2008-2019 Max Kellermann <max.kellermann@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef URI_RELATIVE_HXX
+#define URI_RELATIVE_HXX
+
+#include "Compiler.h"
+
+#include <string>
+
+/**
+ * Check whether #child specifies a resource "inside" the directory
+ * specified by #parent. If the strings are equal, the function
+ * returns false.
+ */
+gcc_pure gcc_nonnull_all
+bool
+uri_is_child(const char *parent, const char *child) noexcept;
+
+gcc_pure gcc_nonnull_all
+bool
+uri_is_child_or_same(const char *parent, const char *child) noexcept;
+
+/**
+ * Translate the given URI in the context of #base. For example,
+ * uri_apply_base("foo", "http://bar/a/")=="http://bar/a/foo".
+ */
+gcc_pure
+std::string
+uri_apply_base(const std::string &uri, const std::string &base) noexcept;
+
+#endif
diff --git a/src/util/UriUtil.cxx b/src/util/UriUtil.cxx
index f8ce72fd6..09ebafbd7 100644
--- a/src/util/UriUtil.cxx
+++ b/src/util/UriUtil.cxx
@@ -29,117 +29,10 @@
#include "UriUtil.hxx"
#include "ASCII.hxx"
-#include "CharUtil.hxx"
#include <assert.h>
#include <string.h>
-static constexpr bool
-IsValidSchemeStart(char ch)
-{
- return IsLowerAlphaASCII(ch);
-}
-
-static constexpr bool
-IsValidSchemeChar(char ch)
-{
- return IsLowerAlphaASCII(ch) || IsDigitASCII(ch) ||
- ch == '+' || ch == '.' || ch == '-';
-}
-
-gcc_pure
-static bool
-IsValidScheme(StringView p) noexcept
-{
- if (p.empty() || !IsValidSchemeStart(p.front()))
- return false;
-
- for (size_t i = 1; i < p.size; ++i)
- if (!IsValidSchemeChar(p[i]))
- return false;
-
- return true;
-}
-
-/**
- * Return the URI part after the scheme specification (and after the
- * double slash).
- */
-gcc_pure
-static const char *
-uri_after_scheme(const char *uri) noexcept
-{
- if (uri[0] == '/' && uri[1] == '/' && uri[2] != '/')
- return uri + 2;
-
- const char *colon = strchr(uri, ':');
- return colon != nullptr &&
- IsValidScheme({uri, colon}) &&
- colon[1] == '/' && colon[2] == '/'
- ? colon + 3
- : nullptr;
-}
-
-bool
-uri_has_scheme(const char *uri) noexcept
-{
- return strstr(uri, "://") != nullptr;
-}
-
-std::string
-uri_get_scheme(const char *uri) noexcept
-{
- const char *end = strstr(uri, "://");
- if (end == nullptr)
- end = uri;
-
- return std::string(uri, end);
-}
-
-const char *
-uri_get_path(const char *uri) noexcept
-{
- const char *ap = uri_after_scheme(uri);
- if (ap != nullptr)
- return strchr(ap, '/');
-
- return uri;
-}
-
-/* suffixes should be ascii only characters */
-const char *
-uri_get_suffix(const char *uri) noexcept
-{
- const char *suffix = strrchr(uri, '.');
- if (suffix == nullptr || suffix == uri ||
- suffix[-1] == '/' || suffix[-1] == '\\')
- return nullptr;
-
- ++suffix;
-
- if (strpbrk(suffix, "/\\") != nullptr)
- return nullptr;
-
- return suffix;
-}
-
-const char *
-uri_get_suffix(const char *uri, UriSuffixBuffer &buffer) noexcept
-{
- const char *suffix = uri_get_suffix(uri);
- if (suffix == nullptr)
- return nullptr;
-
- const char *q = strchr(suffix, '?');
- if (q != nullptr && size_t(q - suffix) < sizeof(buffer.data)) {
- memcpy(buffer.data, suffix, q - suffix);
- buffer.data[q - suffix] = 0;
- suffix = buffer.data;
- }
-
- return suffix;
-}
-
static const char *
verify_uri_segment(const char *p) noexcept
{
@@ -210,52 +103,3 @@ uri_remove_auth(const char *uri) noexcept
result.erase(auth - uri, at + 1 - auth);
return result;
}
-
-bool
-uri_is_child(const char *parent, const char *child) noexcept
-{
-#if !CLANG_CHECK_VERSION(3,6)
- /* disabled on clang due to -Wtautological-pointer-compare */
- assert(parent != nullptr);
- assert(child != nullptr);
-#endif
-
- const size_t parent_length = strlen(parent);
- return memcmp(parent, child, parent_length) == 0 &&
- child[parent_length] == '/';
-}
-
-
-bool
-uri_is_child_or_same(const char *parent, const char *child) noexcept
-{
- return strcmp(parent, child) == 0 || uri_is_child(parent, child);
-}
-
-std::string
-uri_apply_base(const std::string &uri, const std::string &base) noexcept
-{
- if (uri.front() == '/') {
- /* absolute path: replace the whole URI path in base */
-
- auto i = base.find("://");
- if (i == base.npos)
- /* no scheme: override base completely */
- return uri;
-
- /* find the first slash after the host part */
- i = base.find('/', i + 3);
- if (i == base.npos)
- /* there's no URI path - simply append uri */
- i = base.length();
-
- return base.substr(0, i) + uri;
- }
-
- std::string out(base);
- if (out.back() != '/')
- out.push_back('/');
-
- out += uri;
- return out;
-}
diff --git a/src/util/UriUtil.hxx b/src/util/UriUtil.hxx
index 835fe4685..528e7e872 100644
--- a/src/util/UriUtil.hxx
+++ b/src/util/UriUtil.hxx
@@ -35,44 +35,6 @@
#include <string>
/**
- * Checks whether the specified URI has a scheme in the form
- * "scheme://".
- */
-gcc_pure
-bool
-uri_has_scheme(const char *uri) noexcept;
-
-/**
- * Returns the scheme name of the specified URI, or an empty string.
- */
-gcc_pure
-std::string
-uri_get_scheme(const char *uri) noexcept;
-
-/**
- * Returns the URI path (including the query string) or nullptr if the
- * given URI has no path.
- */
-gcc_pure gcc_nonnull_all
-const char *
-uri_get_path(const char *uri) noexcept;
-
-gcc_pure
-const char *
-uri_get_suffix(const char *uri) noexcept;
-
-struct UriSuffixBuffer {
- char data[8];
-};
-
-/**
- * Returns the file name suffix, ignoring the query string.
- */
-gcc_pure
-const char *
-uri_get_suffix(const char *uri, UriSuffixBuffer &buffer) noexcept;
-
-/**
* Returns true if this is a safe "local" URI:
*
* - non-empty
@@ -94,25 +56,4 @@ gcc_pure
std::string
uri_remove_auth(const char *uri) noexcept;
-/**
- * Check whether #child specifies a resource "inside" the directory
- * specified by #parent. If the strings are equal, the function
- * returns false.
- */
-gcc_pure gcc_nonnull_all
-bool
-uri_is_child(const char *parent, const char *child) noexcept;
-
-gcc_pure gcc_nonnull_all
-bool
-uri_is_child_or_same(const char *parent, const char *child) noexcept;
-
-/**
- * Translate the given URI in the context of #base. For example,
- * uri_apply_base("foo", "http://bar/a/")=="http://bar/a/foo".
- */
-gcc_pure
-std::string
-uri_apply_base(const std::string &uri, const std::string &base) noexcept;
-
#endif
diff --git a/src/util/meson.build b/src/util/meson.build
index 1729d8588..da42d4362 100644
--- a/src/util/meson.build
+++ b/src/util/meson.build
@@ -17,6 +17,8 @@ util = static_library(
'SplitString.cxx',
'FormatString.cxx',
'Tokenizer.cxx',
+ 'UriExtract.cxx',
+ 'UriRelative.cxx',
'UriUtil.cxx',
'LazyRandomEngine.cxx',
'HugeAllocator.cxx',
diff --git a/test/ContainerScan.cxx b/test/ContainerScan.cxx
index 1c40806d6..952de4fb2 100644
--- a/test/ContainerScan.cxx
+++ b/test/ContainerScan.cxx
@@ -25,8 +25,8 @@
#include "fs/Path.hxx"
#include "fs/io/StdioOutputStream.hxx"
#include "fs/io/BufferedOutputStream.hxx"
-#include "util/UriUtil.hxx"
#include "util/PrintException.hxx"
+#include "util/UriExtract.hxx"
#include <stdexcept>
diff --git a/test/TestUriExtract.cxx b/test/TestUriExtract.cxx
new file mode 100644
index 000000000..b5e4c8656
--- /dev/null
+++ b/test/TestUriExtract.cxx
@@ -0,0 +1,33 @@
+/*
+ * Unit tests for src/util/
+ */
+
+#include "util/UriExtract.hxx"
+
+#include <gtest/gtest.h>
+
+TEST(UriExtract, Suffix)
+{
+ EXPECT_EQ((const char *)nullptr, uri_get_suffix("/foo/bar"));
+ EXPECT_EQ((const char *)nullptr, uri_get_suffix("/foo.jpg/bar"));
+ EXPECT_STREQ(uri_get_suffix("/foo/bar.jpg"), "jpg");
+ EXPECT_STREQ(uri_get_suffix("/foo.png/bar.jpg"), "jpg");
+ EXPECT_EQ((const char *)nullptr, uri_get_suffix(".jpg"));
+ EXPECT_EQ((const char *)nullptr, uri_get_suffix("/foo/.jpg"));
+
+ /* the first overload does not eliminate the query
+ string */
+ EXPECT_STREQ(uri_get_suffix("/foo/bar.jpg?query_string"),
+ "jpg?query_string");
+
+ /* ... but the second one does */
+ UriSuffixBuffer buffer;
+ EXPECT_STREQ(uri_get_suffix("/foo/bar.jpg?query_string", buffer),
+ "jpg");
+
+ /* repeat some of the above tests with the second overload */
+ EXPECT_EQ((const char *)nullptr, uri_get_suffix("/foo/bar", buffer));
+ EXPECT_EQ((const char *)nullptr,
+ uri_get_suffix("/foo.jpg/bar", buffer));
+ EXPECT_STREQ(uri_get_suffix("/foo/bar.jpg", buffer), "jpg");
+}
diff --git a/test/TestUriUtil.cxx b/test/TestUriUtil.cxx
index 21cbd2cdf..17a6189e9 100644
--- a/test/TestUriUtil.cxx
+++ b/test/TestUriUtil.cxx
@@ -6,32 +6,6 @@
#include <gtest/gtest.h>
-TEST(UriUtil, Suffix)
-{
- EXPECT_EQ((const char *)nullptr, uri_get_suffix("/foo/bar"));
- EXPECT_EQ((const char *)nullptr, uri_get_suffix("/foo.jpg/bar"));
- EXPECT_STREQ(uri_get_suffix("/foo/bar.jpg"), "jpg");
- EXPECT_STREQ(uri_get_suffix("/foo.png/bar.jpg"), "jpg");
- EXPECT_EQ((const char *)nullptr, uri_get_suffix(".jpg"));
- EXPECT_EQ((const char *)nullptr, uri_get_suffix("/foo/.jpg"));
-
- /* the first overload does not eliminate the query
- string */
- EXPECT_STREQ(uri_get_suffix("/foo/bar.jpg?query_string"),
- "jpg?query_string");
-
- /* ... but the second one does */
- UriSuffixBuffer buffer;
- EXPECT_STREQ(uri_get_suffix("/foo/bar.jpg?query_string", buffer),
- "jpg");
-
- /* repeat some of the above tests with the second overload */
- EXPECT_EQ((const char *)nullptr, uri_get_suffix("/foo/bar", buffer));
- EXPECT_EQ((const char *)nullptr,
- uri_get_suffix("/foo.jpg/bar", buffer));
- EXPECT_STREQ(uri_get_suffix("/foo/bar.jpg", buffer), "jpg");
-}
-
TEST(UriUtil, RemoveAuth)
{
EXPECT_EQ(std::string(),
diff --git a/test/meson.build b/test/meson.build
index d426731ac..4a146dcf9 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -37,6 +37,7 @@ test('TestUtil', executable(
'TestDivideString.cxx',
'TestMimeType.cxx',
'TestSplitString.cxx',
+ 'TestUriExtract.cxx',
'TestUriUtil.cxx',
'test_byte_reverse.cxx',
include_directories: inc,