summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Pipping <sebastian@pipping.org>2019-08-28 02:22:50 +0200
committerGitHub <noreply@github.com>2019-08-28 02:22:50 +0200
commit6b8fbc0ed55696450c3a16ea5bdb57ccc0c8d2fa (patch)
tree36bef386bfd9261eced2206cd3fa54c4bfcd901a
parentebeafbb70b10e2840ce8e8d2603c4a72d5600c82 (diff)
parentef714d723f81b758836f85a944b28af9f21435b3 (diff)
downloaduriparser-6b8fbc0ed55696450c3a16ea5bdb57ccc0c8d2fa.tar.gz
Merge pull request #78 from uriparser/issue-77-support-making-uri-independent
Support making UriUri* instance independent (for #77)
-rw-r--r--ChangeLog5
-rw-r--r--include/uriparser/Uri.h34
-rw-r--r--src/UriNormalize.c37
-rw-r--r--test/test.cpp77
4 files changed, 150 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index ad9a7e0..df65cb5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -11,6 +11,11 @@ NOTE: uriparser is looking for help with a few things:
Thanks to Scott Donelan for the patch!
* Improved: Make -DURIPARSER_BUILD_TESTS=OFF unlock compilation without
a C++ compiler; thanks to Fabrice Fontaine for the patch! (GitHub #69)
+ * Addded: Functions to make UriUri[AW] instances independent of the original
+ URI string (GitHub #77 and #78)
+ New functions:
+ uriMakeOwner[AW]
+ uriMakeOwnerMm[AW]
* Soname: TODO
2019-04-28 -- 0.9.3
diff --git a/include/uriparser/Uri.h b/include/uriparser/Uri.h
index 9315a12..8f86f41 100644
--- a/include/uriparser/Uri.h
+++ b/include/uriparser/Uri.h
@@ -1080,6 +1080,40 @@ URI_PUBLIC int URI_FUNC(FreeQueryListMm)(URI_TYPE(QueryList) * queryList,
+/**
+ * Makes the %URI hold copies of strings so that it no longer depends
+ * on the original %URI string. If the %URI is already owner of copies,
+ * this function returns <c>URI_TRUE</c> and does not modify the %URI further.
+ *
+ * Uses default libc-based memory manager.
+ *
+ * @param uri <b>INOUT</b>: %URI to make independent
+ * @return Error code or 0 on success
+ *
+ * @see uriMakeOwnerMmA
+ * @since 0.9.4
+ */
+URI_PUBLIC int URI_FUNC(MakeOwner)(URI_TYPE(Uri) * uri);
+
+
+
+/**
+ * Makes the %URI hold copies of strings so that it no longer depends
+ * on the original %URI string. If the %URI is already owner of copies,
+ * this function returns <c>URI_TRUE</c> and does not modify the %URI further.
+ *
+ * @param uri <b>INOUT</b>: %URI to make independent
+ * @param memory <b>IN</b>: Memory manager to use, NULL for default libc
+ * @return Error code or 0 on success
+ *
+ * @see uriMakeOwnerA
+ * @since 0.9.4
+ */
+URI_PUBLIC int URI_FUNC(MakeOwnerMm)(URI_TYPE(Uri) * uri,
+ UriMemoryManager * memory);
+
+
+
#ifdef __cplusplus
}
#endif
diff --git a/src/UriNormalize.c b/src/UriNormalize.c
index 0e798c0..01f2f9d 100644
--- a/src/UriNormalize.c
+++ b/src/UriNormalize.c
@@ -86,7 +86,7 @@ static int URI_FUNC(NormalizeSyntaxEngine)(URI_TYPE(Uri) * uri, unsigned int inM
static UriBool URI_FUNC(MakeRangeOwner)(unsigned int * doneMask,
unsigned int maskTest, URI_TYPE(TextRange) * range,
UriMemoryManager * memory);
-static UriBool URI_FUNC(MakeOwner)(URI_TYPE(Uri) * uri,
+static UriBool URI_FUNC(MakeOwnerEngine)(URI_TYPE(Uri) * uri,
unsigned int * doneMask, UriMemoryManager * memory);
static void URI_FUNC(FixPercentEncodingInplace)(const URI_CHAR * first,
@@ -391,7 +391,7 @@ static URI_INLINE UriBool URI_FUNC(MakeRangeOwner)(unsigned int * doneMask,
-static URI_INLINE UriBool URI_FUNC(MakeOwner)(URI_TYPE(Uri) * uri,
+static URI_INLINE UriBool URI_FUNC(MakeOwnerEngine)(URI_TYPE(Uri) * uri,
unsigned int * doneMask, UriMemoryManager * memory) {
URI_TYPE(PathSegment) * walker = uri->pathHead;
if (!URI_FUNC(MakeRangeOwner)(doneMask, URI_NORMALIZE_SCHEME,
@@ -756,7 +756,7 @@ static URI_INLINE int URI_FUNC(NormalizeSyntaxEngine)(URI_TYPE(Uri) * uri,
/* Dup all not duped yet */
if ((outMask == NULL) && !uri->owner) {
- if (!URI_FUNC(MakeOwner)(uri, &doneMask, memory)) {
+ if (!URI_FUNC(MakeOwnerEngine)(uri, &doneMask, memory)) {
URI_FUNC(PreventLeakage)(uri, doneMask, memory);
return URI_ERROR_MALLOC;
}
@@ -768,4 +768,35 @@ static URI_INLINE int URI_FUNC(NormalizeSyntaxEngine)(URI_TYPE(Uri) * uri,
+int URI_FUNC(MakeOwnerMm)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) {
+ unsigned int doneMask = URI_NORMALIZED;
+
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
+
+ if (uri == NULL) {
+ return URI_ERROR_NULL;
+ }
+
+ if (uri->owner == URI_TRUE) {
+ return URI_SUCCESS;
+ }
+
+ if (! URI_FUNC(MakeOwnerEngine)(uri, &doneMask, memory)) {
+ URI_FUNC(PreventLeakage)(uri, doneMask, memory);
+ return URI_ERROR_MALLOC;
+ }
+
+ uri->owner = URI_TRUE;
+
+ return URI_SUCCESS;
+}
+
+
+
+int URI_FUNC(MakeOwner)(URI_TYPE(Uri) * uri) {
+ return URI_FUNC(MakeOwnerMm)(uri, NULL);
+}
+
+
+
#endif
diff --git a/test/test.cpp b/test/test.cpp
index 728e57b..9a189f9 100644
--- a/test/test.cpp
+++ b/test/test.cpp
@@ -46,6 +46,24 @@ int uriCompareRangeA(const UriTextRangeA * a, const UriTextRangeA * b);
#define URI_TEST_IP_SIX_FAIL(x) ASSERT_TRUE(URI_FALSE == uri_TESTING_ONLY_ParseIpSixA(x "]"))
#define URI_TEST_IP_SIX_PASS(x) ASSERT_TRUE(URI_TRUE == uri_TESTING_ONLY_ParseIpSixA(x "]"))
+#define URI_EXPECT_BETWEEN(candidate, first, afterLast) \
+ EXPECT_TRUE((candidate >= first) && (candidate <= afterLast))
+
+#define URI_EXPECT_OUTSIDE(candidate, first, afterLast) \
+ EXPECT_TRUE((candidate < first) || (candidate > afterLast))
+
+#define URI_EXPECT_RANGE_BETWEEN(range, uriFirst, uriAfterLast) \
+ URI_EXPECT_BETWEEN(range.first, uriFirst, uriAfterLast); \
+ URI_EXPECT_BETWEEN(range.afterLast, uriFirst, uriAfterLast)
+
+#define URI_EXPECT_RANGE_OUTSIDE(range, uriFirst, uriAfterLast) \
+ URI_EXPECT_OUTSIDE(range.first, uriFirst, uriAfterLast); \
+ URI_EXPECT_OUTSIDE(range.afterLast, uriFirst, uriAfterLast)
+
+#define URI_EXPECT_RANGE_EMPTY(range) \
+ EXPECT_TRUE((range.first != NULL) \
+ && (range.afterLast != NULL) \
+ && (range.first == range.afterLast))
namespace {
bool testDistinctionHelper(const char * uriText, bool expectedHostSet,
@@ -2143,6 +2161,65 @@ TEST(FreeUriMembersSuite, MultiFreeWorksFine) {
uriFreeUriMembersA(&uri); // second time
}
+TEST(MakeOwnerSuite, MakeOwner) {
+ const char * const uriString = "scheme://user:pass@[v7.X]:55555/path/../path/?query#fragment";
+ UriUriA uri;
+ char * uriFirst = strdup(uriString);
+ const size_t uriLen = strlen(uriFirst);
+ char * uriAfterLast = uriFirst + uriLen;
+
+ EXPECT_EQ(uriParseSingleUriExA(&uri, uriFirst, uriAfterLast, NULL), URI_SUCCESS);
+
+ // After plain parse, all strings should point inside the original URI string
+ EXPECT_EQ(uri.owner, URI_FALSE);
+ URI_EXPECT_RANGE_BETWEEN(uri.scheme, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_BETWEEN(uri.userInfo, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_BETWEEN(uri.hostText, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_BETWEEN(uri.hostData.ipFuture, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_BETWEEN(uri.portText, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_BETWEEN(uri.pathHead->text, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_BETWEEN(uri.pathHead->next->text, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_BETWEEN(uri.pathHead->next->next->text, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_EMPTY(uri.pathHead->next->next->next->text);
+ EXPECT_TRUE(uri.pathHead->next->next->next->next == NULL);
+ URI_EXPECT_RANGE_BETWEEN(uri.query, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_BETWEEN(uri.fragment, uriFirst, uriAfterLast);
+
+ EXPECT_EQ(uriMakeOwnerA(&uri), URI_SUCCESS);
+
+ // After making owner, *none* of the strings should point inside the original URI string
+ EXPECT_EQ(uri.owner, URI_TRUE);
+ URI_EXPECT_RANGE_OUTSIDE(uri.scheme, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_OUTSIDE(uri.userInfo, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_OUTSIDE(uri.hostText, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_OUTSIDE(uri.hostData.ipFuture, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_OUTSIDE(uri.portText, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_OUTSIDE(uri.pathHead->text, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_OUTSIDE(uri.pathHead->next->text, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_OUTSIDE(uri.pathHead->next->next->text, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_EMPTY(uri.pathHead->next->next->next->text);
+ EXPECT_TRUE(uri.pathHead->next->next->next->next == NULL);
+ URI_EXPECT_RANGE_OUTSIDE(uri.query, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_OUTSIDE(uri.fragment, uriFirst, uriAfterLast);
+
+ // Free originally used memory so we'd get violations on access with ASan
+ uriAfterLast = NULL;
+ free(uriFirst);
+ uriFirst = NULL;
+
+ // Can we recompose the URI without accessing any old freed memory?
+ int charsRequired;
+ EXPECT_EQ(uriToStringCharsRequiredA(&uri, &charsRequired), URI_SUCCESS);
+ EXPECT_TRUE((charsRequired >= 0) && (charsRequired >= static_cast<int>(uriLen)));
+ char * const uriRemake = new char[charsRequired + 1];
+ EXPECT_TRUE(uriRemake != NULL);
+ EXPECT_EQ(uriToStringA(uriRemake, &uri, charsRequired + 1, NULL), URI_SUCCESS);
+ EXPECT_TRUE(! strcmp(uriString, uriRemake));
+ delete [] uriRemake;
+
+ uriFreeUriMembersA(&uri);
+}
+
TEST(ParseIpFourAddressSuite, FourSaneOctets) {
unsigned char octetOutput[4];
const char * const ipAddressText = "111.22.3.40";