From eab32f2e5d8114d08e392001f0004284267bebd5 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Sat, 1 Nov 2014 12:45:47 +0100
Subject: [PATCH] util/UriUtil: add uri_get_suffix() overload that ignores
 query string

---
 src/util/UriUtil.cxx | 17 +++++++++++++++++
 src/util/UriUtil.hxx | 11 +++++++++++
 test/test_util.cxx   | 19 +++++++++++++++++++
 3 files changed, 47 insertions(+)

diff --git a/src/util/UriUtil.cxx b/src/util/UriUtil.cxx
index fdca47c00..62977e91b 100644
--- a/src/util/UriUtil.cxx
+++ b/src/util/UriUtil.cxx
@@ -54,6 +54,23 @@ uri_get_suffix(const char *uri)
 	return suffix;
 }
 
+const char *
+uri_get_suffix(const char *uri, UriSuffixBuffer &buffer)
+{
+	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)
 {
diff --git a/src/util/UriUtil.hxx b/src/util/UriUtil.hxx
index c2cc97a63..d478d5b92 100644
--- a/src/util/UriUtil.hxx
+++ b/src/util/UriUtil.hxx
@@ -42,6 +42,17 @@ gcc_pure
 const char *
 uri_get_suffix(const char *uri);
 
+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);
+
 /**
  * Returns true if this is a safe "local" URI:
  *
diff --git a/test/test_util.cxx b/test/test_util.cxx
index aaadec68f..3e79aeca0 100644
--- a/test/test_util.cxx
+++ b/test/test_util.cxx
@@ -34,6 +34,25 @@ public:
 				     uri_get_suffix(".jpg"));
 		CPPUNIT_ASSERT_EQUAL((const char *)nullptr,
 				     uri_get_suffix("/foo/.jpg"));
+
+		/* the first overload does not eliminate the query
+		   string */
+		CPPUNIT_ASSERT_EQUAL(0, strcmp(uri_get_suffix("/foo/bar.jpg?query_string"),
+					       "jpg?query_string"));
+
+		/* ... but the second one does */
+		UriSuffixBuffer buffer;
+		CPPUNIT_ASSERT_EQUAL(0, strcmp(uri_get_suffix("/foo/bar.jpg?query_string",
+							      buffer),
+					       "jpg"));
+
+		/* repeat some of the above tests with the second overload */
+		CPPUNIT_ASSERT_EQUAL((const char *)nullptr,
+				     uri_get_suffix("/foo/bar", buffer));
+		CPPUNIT_ASSERT_EQUAL((const char *)nullptr,
+				     uri_get_suffix("/foo.jpg/bar", buffer));
+		CPPUNIT_ASSERT_EQUAL(0, strcmp(uri_get_suffix("/foo/bar.jpg", buffer),
+					       "jpg"));
 	}
 
 	void TestRemoveAuth() {