diff options
author | Sebastian Pipping <sebastian@pipping.org> | 2019-08-28 02:22:50 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-08-28 02:22:50 +0200 |
commit | 6b8fbc0ed55696450c3a16ea5bdb57ccc0c8d2fa (patch) | |
tree | 36bef386bfd9261eced2206cd3fa54c4bfcd901a | |
parent | ebeafbb70b10e2840ce8e8d2603c4a72d5600c82 (diff) | |
parent | ef714d723f81b758836f85a944b28af9f21435b3 (diff) | |
download | uriparser-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-- | ChangeLog | 5 | ||||
-rw-r--r-- | include/uriparser/Uri.h | 34 | ||||
-rw-r--r-- | src/UriNormalize.c | 37 | ||||
-rw-r--r-- | test/test.cpp | 77 |
4 files changed, 150 insertions, 3 deletions
@@ -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"; |