From 21ce7e27a89c3f9c2fb4bc8bd59877dc2d8cd6b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Sat, 8 Sep 2018 10:21:00 +0200 Subject: New upstream version 0.8.6 --- ChangeLog | 19 +++++ Makefile.am | 2 +- Makefile.in | 2 +- THANKS | 4 ++ configure | 20 +++--- configure.ac | 2 +- doc/Mainpage.txt | 12 ++-- include/uriparser/Uri.h | 30 ++++---- include/uriparser/UriBase.h | 2 +- src/UriFile.c | 30 +++++--- src/UriParse.c | 1 + src/UriRecompose.c | 2 +- src/UriShorten.c | 24 ++----- test/test.cpp | 166 ++++++++++++++++++++++++++++++++++++++++++-- 14 files changed, 249 insertions(+), 67 deletions(-) diff --git a/ChangeLog b/ChangeLog index 08ee3ef..fc5be8a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +2018-08-18 -- 0.8.6 + + * Fixed: Bad/NULL .hostText.afterLast when parsing certain rather pathologic + but well-formed URIs with empty host (e.g. "//:%aa@") (GitHub #15) + Thanks to Kurt Schwehr for the report! + * Fixed: Fix uriRemoveBaseUri for case where scheme, host name, + IPvFuture address or path segments of the source address were + string prefixes of the related counterpart in the base URI. + Thanks to Yang Yu for the patch! (GitHub #19, #20) + * Fixed: Make UriStringToUnixFilename and UriStringToWindowsFilename + support minimal representation a la RFC 8089, e.g. file:/bin/bash + (compare to file:///bin/bash with three slashes) (GitHub #12, #14) + Thanks to Zane van Iperen for the report! + * Fixed: Documentation typos (GitHub #10, #11) + Thanks to Graham Percival! + * Improved: Made API docs of uriRemoveBaseUri more clear + (related to GitHub #19) + * Soname: 1:22:0 + 2018-02-07 -- 0.8.5 * Changed: The uriparser project has moved from SourceForge to GitHub: diff --git a/Makefile.am b/Makefile.am index 7ef28f5..828723a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -34,7 +34,7 @@ pkginclude_HEADERS = \ include/uriparser/UriIp4.h -liburiparser_la_LDFLAGS = -version-info 1:21:0 +liburiparser_la_LDFLAGS = -version-info 1:22:0 if WIN32 liburiparser_la_LDFLAGS += -no-undefined endif diff --git a/Makefile.in b/Makefile.in index b20ac8c..190b353 100644 --- a/Makefile.in +++ b/Makefile.in @@ -655,7 +655,7 @@ pkginclude_HEADERS = \ include/uriparser/UriDefsUnicode.h \ include/uriparser/UriIp4.h -liburiparser_la_LDFLAGS = -version-info 1:21:0 $(am__append_1) +liburiparser_la_LDFLAGS = -version-info 1:22:0 $(am__append_1) liburiparser_la_SOURCES = \ src/UriCommon.c \ src/UriCommon.h \ diff --git a/THANKS b/THANKS index 4dc0a5c..1f2ca8d 100644 --- a/THANKS +++ b/THANKS @@ -17,10 +17,12 @@ Edward Z. Yang Eren Türkay Friedrich Delgado Friedrichs Gary Mazzaferro +Graham Percival Harvey Vrsalovic Jerome Custodio Joel Cunningham Juan Pablo González Tognarelli +Kurt Schwehr Marc Novakowski Marcin Juszkiewicz Martin Michlmayr @@ -39,3 +41,5 @@ Ryan Schmidt Sezai Tekin Valentin Haenel Vitaly Lipatov +Yang Yu +Zane van Iperen diff --git a/configure b/configure index 1aeed5f..5ee2f56 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for uriparser 0.8.5. +# Generated by GNU Autoconf 2.69 for uriparser 0.8.6. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -587,8 +587,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='uriparser' PACKAGE_TARNAME='uriparser' -PACKAGE_VERSION='0.8.5' -PACKAGE_STRING='uriparser 0.8.5' +PACKAGE_VERSION='0.8.6' +PACKAGE_STRING='uriparser 0.8.6' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -1346,7 +1346,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures uriparser 0.8.5 to adapt to many kinds of systems. +\`configure' configures uriparser 0.8.6 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1416,7 +1416,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of uriparser 0.8.5:";; + short | recursive ) echo "Configuration of uriparser 0.8.6:";; esac cat <<\_ACEOF @@ -1548,7 +1548,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -uriparser configure 0.8.5 +uriparser configure 0.8.6 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1947,7 +1947,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by uriparser $as_me 0.8.5, which was +It was created by uriparser $as_me 0.8.6, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2810,7 +2810,7 @@ fi # Define the identity of the package. PACKAGE='uriparser' - VERSION='0.8.5' + VERSION='0.8.6' cat >>confdefs.h <<_ACEOF @@ -16883,7 +16883,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by uriparser $as_me 0.8.5, which was +This file was extended by uriparser $as_me 0.8.6, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -16949,7 +16949,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -uriparser config.status 0.8.5 +uriparser config.status 0.8.6 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 5385470..2effbe9 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ(2.61) -AC_INIT([uriparser], [0.8.5]) +AC_INIT([uriparser], [0.8.6]) AC_CONFIG_AUX_DIR([build-aux]) AM_INIT_AUTOMAKE([1.10.1 foreign dist-zip dist-bzip2 no-dist-gzip subdir-objects]) diff --git a/doc/Mainpage.txt b/doc/Mainpage.txt index 3a80e30..173511b 100644 --- a/doc/Mainpage.txt +++ b/doc/Mainpage.txt @@ -40,10 +40,10 @@ * uriFreeUriMembersA(&uri); * @endcode * - * While the URI object (::UriUriA) holds information about the recogized + * While the URI object (::UriUriA) holds information about the recognized * parts of the given URI string, the parser state object (::UriParserStateA) * keeps error code and position. This information does not belong to - * the URI itself, which is why there are two seperate objects. + * the URI itself, which is why there are two separate objects. * * You can reuse parser state objects for parsing several URIs like this: * @@ -74,7 +74,7 @@ * * @subsection recomposition Recomposing URIs (from object back to string) * According to RFC 3986 - * glueing parts of a URI together to form a string is called recomposition. + * gluing parts of a URI together to form a string is called recomposition. * Before we can recompose a URI object we have to know how much * space the resulting string will take: * @@ -141,7 +141,7 @@ * * @subsection shortening Creating References * Reference Creation is the inverse process of Reference Resolution: A common base URI - * is "substracted" from an absolute URI to make a (relative) reference. + * is "subtracted" from an absolute URI to make a (relative) reference. * If the base URI is not common the remaining URI will still be absolute, i.e. will * carry a scheme * @@ -207,7 +207,7 @@ * * * @subsection normalization Normalizing URIs - * Sometimes we come accross unnecessarily long URIs like "http://example.org/one/two/../../one". + * Sometimes we come across unnecessarily long URIs like "http://example.org/one/two/../../one". * The algorithm we can use to shorten this URI down to "http://example.org/one" is called * Syntax-Based Normalization. * Note that normalizing a URI does more than just "stripping dot segments". Please have a look at @@ -215,7 +215,7 @@ * for the full description. * * As we asked uriToStringCharsRequiredA() for the required space when converting - * a URI object back to a sring, we can ask uriNormalizeSyntaxMaskRequiredA() for + * a URI object back to a string, we can ask uriNormalizeSyntaxMaskRequiredA() for * the parts of a URI that require normalization and then pass this normalization * mask to uriNormalizeSyntaxExA(): * diff --git a/include/uriparser/Uri.h b/include/uriparser/Uri.h index a3f7914..f4600fb 100644 --- a/include/uriparser/Uri.h +++ b/include/uriparser/Uri.h @@ -1,4 +1,4 @@ -/* f9ca23a99fc1c8ff610e2bdc0bff3c4bb4d883ccbff5851fe7a1398f9b6aca57 (0.8.5+) +/* 5afca6d8abb5d1a22b4e28c912538e6729692afc98f089d9e538ca01c43ab805 (0.8.6+) * * uriparser - RFC 3986 URI parsing library * @@ -177,7 +177,7 @@ typedef struct URI_TYPE(UriStruct) { */ typedef struct URI_TYPE(ParserStateStruct) { URI_TYPE(Uri) * uri; /**< Plug in the %URI structure to be filled while parsing here */ - int errorCode; /**< Code identifying the occured error */ + int errorCode; /**< Code identifying the error which occurred */ const URI_CHAR * errorPos; /**< Pointer to position in case of a syntax error */ void * reserved; /**< Reserved to the parser */ @@ -258,8 +258,8 @@ void URI_FUNC(FreeUriMembers)(URI_TYPE(Uri) * uri); * @param inFirst IN: Pointer to first character of the input text * @param inAfterLast IN: Pointer after the last character of the input text * @param out OUT: Encoded text destination - * @param spaceToPlus IN: Wether to convert ' ' to '+' or not - * @param normalizeBreaks IN: Wether to convert CR and LF to CR-LF or not. + * @param spaceToPlus IN: Whether to convert ' ' to '+' or not + * @param normalizeBreaks IN: Whether to convert CR and LF to CR-LF or not. * @return Position of terminator in output string * * @see uriEscapeA @@ -282,8 +282,8 @@ URI_CHAR * URI_FUNC(EscapeEx)(const URI_CHAR * inFirst, * * @param in IN: Text source * @param out OUT: Encoded text destination - * @param spaceToPlus IN: Wether to convert ' ' to '+' or not - * @param normalizeBreaks IN: Wether to convert CR and LF to CR-LF or not. + * @param spaceToPlus IN: Whether to convert ' ' to '+' or not + * @param normalizeBreaks IN: Whether to convert CR and LF to CR-LF or not. * @return Position of terminator in output string * * @see uriEscapeExA @@ -381,9 +381,9 @@ int URI_FUNC(AddBaseUriEx)(URI_TYPE(Uri) * absoluteDest, /** * Tries to make a relative %URI (a reference) from an - * absolute %URI and a given base %URI. This can only work if - * the absolute %URI shares scheme and authority with - * the base %URI. If it does not the result will still be + * absolute %URI and a given base %URI. The resulting %URI is going to be + * relative if the absolute %URI and base %UI share both scheme and authority. + * If that is not the case, the result will still be * an absolute URI (with scheme part if necessary). * NOTE: On success you have to call uriFreeUriMembersA on * \p dest manually later. @@ -612,8 +612,8 @@ int URI_FUNC(ComposeQueryCharsRequired)(const URI_TYPE(QueryList) * queryList, * * @param queryList IN: Query list to measure * @param charsRequired OUT: Length of the string representation in characters excluding terminator - * @param spaceToPlus IN: Wether to convert ' ' to '+' or not - * @param normalizeBreaks IN: Wether to convert CR and LF to CR-LF or not. + * @param spaceToPlus IN: Whether to convert ' ' to '+' or not + * @param normalizeBreaks IN: Whether to convert CR and LF to CR-LF or not. * @return Error code or 0 on success * * @see uriComposeQueryCharsRequiredA @@ -656,8 +656,8 @@ int URI_FUNC(ComposeQuery)(URI_CHAR * dest, * @param queryList IN: Query list to convert * @param maxChars IN: Maximum number of characters to copy including terminator * @param charsWritten OUT: Number of characters written, can be lower than maxChars even if the query list is too long! - * @param spaceToPlus IN: Wether to convert ' ' to '+' or not - * @param normalizeBreaks IN: Wether to convert CR and LF to CR-LF or not. + * @param spaceToPlus IN: Whether to convert ' ' to '+' or not + * @param normalizeBreaks IN: Whether to convert CR and LF to CR-LF or not. * @return Error code or 0 on success * * @see uriComposeQueryA @@ -700,8 +700,8 @@ int URI_FUNC(ComposeQueryMalloc)(URI_CHAR ** dest, * * @param dest OUT: Output destination * @param queryList IN: Query list to convert - * @param spaceToPlus IN: Wether to convert ' ' to '+' or not - * @param normalizeBreaks IN: Wether to convert CR and LF to CR-LF or not. + * @param spaceToPlus IN: Whether to convert ' ' to '+' or not + * @param normalizeBreaks IN: Whether to convert CR and LF to CR-LF or not. * @return Error code or 0 on success * * @see uriComposeQueryMallocA diff --git a/include/uriparser/UriBase.h b/include/uriparser/UriBase.h index 45ba5ab..0c2a5e7 100644 --- a/include/uriparser/UriBase.h +++ b/include/uriparser/UriBase.h @@ -55,7 +55,7 @@ /* Version */ #define URI_VER_MAJOR 0 #define URI_VER_MINOR 8 -#define URI_VER_RELEASE 5 +#define URI_VER_RELEASE 6 #define URI_VER_SUFFIX_ANSI "" #define URI_VER_SUFFIX_UNICODE URI_ANSI_TO_UNICODE(URI_VER_SUFFIX_ANSI) diff --git a/src/UriFile.c b/src/UriFile.c index 332f6a9..303ee49 100644 --- a/src/UriFile.c +++ b/src/UriFile.c @@ -104,7 +104,7 @@ static URI_INLINE int URI_FUNC(FilenameToUriString)(const URI_CHAR * filename, if ((input[0] == _UT('\0')) || (fromUnix && input[0] == _UT('/')) || (!fromUnix && input[0] == _UT('\\'))) { - /* Copy text after last seperator */ + /* Copy text after last separator */ if (lastSep + 1 < input) { if (!fromUnix && absolute && (firstSegment == URI_TRUE)) { /* Quick hack to not convert "C:" to "C%3A" */ @@ -148,13 +148,17 @@ static URI_INLINE int URI_FUNC(UriStringToFilename)(const URI_CHAR * uriString, } { - const UriBool file_two_slashes = - URI_STRNCMP(uriString, _UT("file://"), URI_STRLEN(_UT("file://"))) == 0; - const UriBool file_three_slashes = file_two_slashes + const UriBool file_unknown_slashes = + URI_STRNCMP(uriString, _UT("file:"), URI_STRLEN(_UT("file:"))) == 0; + const UriBool file_one_or_more_slashes = file_unknown_slashes + && (URI_STRNCMP(uriString, _UT("file:/"), URI_STRLEN(_UT("file:/"))) == 0); + const UriBool file_two_or_more_slashes = file_one_or_more_slashes + && (URI_STRNCMP(uriString, _UT("file://"), URI_STRLEN(_UT("file://"))) == 0); + const UriBool file_three_or_more_slashes = file_two_or_more_slashes && (URI_STRNCMP(uriString, _UT("file:///"), URI_STRLEN(_UT("file:///"))) == 0); - const size_t charsToSkip = file_two_slashes - ? file_three_slashes + const size_t charsToSkip = file_two_or_more_slashes + ? file_three_or_more_slashes ? toUnix /* file:///bin/bash */ ? URI_STRLEN(_UT("file://")) @@ -162,13 +166,21 @@ static URI_INLINE int URI_FUNC(UriStringToFilename)(const URI_CHAR * uriString, : URI_STRLEN(_UT("file:///")) /* file://Server01/Letter.txt */ : URI_STRLEN(_UT("file://")) - : 0; + : ((file_one_or_more_slashes && toUnix) + /* file:/bin/bash */ + /* https://tools.ietf.org/html/rfc8089#appendix-B */ + ? URI_STRLEN(_UT("file:")) + : ((! toUnix && file_unknown_slashes && ! file_one_or_more_slashes) + /* file:c:/path/to/file */ + /* https://tools.ietf.org/html/rfc8089#appendix-E.2 */ + ? URI_STRLEN(_UT("file:")) + : 0)); const size_t charsToCopy = URI_STRLEN(uriString + charsToSkip) + 1; const UriBool is_windows_network_with_authority = (toUnix == URI_FALSE) - && file_two_slashes - && ! file_three_slashes; + && file_two_or_more_slashes + && ! file_three_or_more_slashes; URI_CHAR * const unescape_target = is_windows_network_with_authority ? (filename + 2) diff --git a/src/UriParse.c b/src/UriParse.c index 5eee16d..e087753 100644 --- a/src/UriParse.c +++ b/src/UriParse.c @@ -941,6 +941,7 @@ static const URI_CHAR * URI_FUNC(ParseMustBeSegmentNzNc)(URI_TYPE(ParserState) * */ static URI_INLINE const URI_CHAR * URI_FUNC(ParseOwnHost)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { if (first >= afterLast) { + state->uri->hostText.afterLast = afterLast; /* HOST END */ return afterLast; } diff --git a/src/UriRecompose.c b/src/UriRecompose.c index 9678aac..2705cf1 100644 --- a/src/UriRecompose.c +++ b/src/UriRecompose.c @@ -105,7 +105,7 @@ static URI_INLINE int URI_FUNC(ToStringEngine)(URI_CHAR * dest, } return URI_ERROR_TOSTRING_TOO_LONG; } - maxChars--; /* So we don't have to substract 1 for '\0' all the time */ + maxChars--; /* So we don't have to subtract 1 for '\0' all the time */ /* [01/19] result = "" */ if (dest != NULL) { diff --git a/src/UriShorten.c b/src/UriShorten.c index 0145f68..e7f6df4 100644 --- a/src/UriShorten.c +++ b/src/UriShorten.c @@ -111,22 +111,12 @@ static URI_INLINE UriBool URI_FUNC(EqualsAuthority)(const URI_TYPE(Uri) * first, /* IPvFuture */ if (first->hostData.ipFuture.first != NULL) { return ((second->hostData.ipFuture.first != NULL) - && !URI_STRNCMP(first->hostData.ipFuture.first, - second->hostData.ipFuture.first, - first->hostData.ipFuture.afterLast - - first->hostData.ipFuture.first)) - ? URI_TRUE : URI_FALSE; + && !URI_FUNC(CompareRange)(&first->hostData.ipFuture, + &second->hostData.ipFuture)) ? URI_TRUE : URI_FALSE; } - if (first->hostText.first != NULL) { - return ((second->hostText.first != NULL) - && !URI_STRNCMP(first->hostText.first, - second->hostText.first, - first->hostText.afterLast - - first->hostText.first)) ? URI_TRUE : URI_FALSE; - } - - return (second->hostText.first == NULL); + return !URI_FUNC(CompareRange)(&first->hostText, &second->hostText) + ? URI_TRUE : URI_FALSE; } @@ -155,8 +145,7 @@ static int URI_FUNC(RemoveBaseUriImpl)(URI_TYPE(Uri) * dest, } /* [01/50] if (A.scheme != Base.scheme) then */ - if (URI_STRNCMP(absSource->scheme.first, absBase->scheme.first, - absSource->scheme.afterLast - absSource->scheme.first)) { + if (URI_FUNC(CompareRange)(&absSource->scheme, &absBase->scheme)) { /* [02/50] T.scheme = A.scheme; */ dest->scheme = absSource->scheme; /* [03/50] T.authority = A.authority; */ @@ -216,8 +205,7 @@ static int URI_FUNC(RemoveBaseUriImpl)(URI_TYPE(Uri) * dest, dest->absolutePath = URI_FALSE; /* [22/50] while (first(A.path) == first(Base.path)) do */ while ((sourceSeg != NULL) && (baseSeg != NULL) - && !URI_STRNCMP(sourceSeg->text.first, baseSeg->text.first, - sourceSeg->text.afterLast - sourceSeg->text.first) + && !URI_FUNC(CompareRange)(&sourceSeg->text, &baseSeg->text) && !((sourceSeg->text.first == sourceSeg->text.afterLast) && ((sourceSeg->next == NULL) != (baseSeg->next == NULL)))) { /* [23/50] A.path++; */ diff --git a/test/test.cpp b/test/test.cpp index 0b1290c..41e3912 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "FourSuite.h" @@ -106,7 +107,9 @@ public: TEST_ADD(UriSuite::testFreeCrash_Bug20080827) TEST_ADD(UriSuite::testParseInvalid_Bug16) TEST_ADD(UriSuite::testRangeComparison) + TEST_ADD(UriSuite::testRangeComparison_RemoveBaseUri_Issue19) TEST_ADD(UriSuite::testEquals) + TEST_ADD(UriSuite::testHostTextTermination_Issue15) } private: @@ -150,7 +153,7 @@ Rule | Example | hostSet | absPath | emptySeg 1) URI = scheme ":" hier-part ... | | | | 1) "//" authority path-abempty | "s://" | true | false | false | "s:///" | true | false | true - | "s://a" | true | false | false + | "s://a" | true | false | false | "s://a/"| true | false | true 2) path-absolute | "s:/" | false | true | false 3) path-rootless | "s:a" | false | false | false @@ -1506,8 +1509,12 @@ Rule | Example | hostSet | absPath | emptySeg } void testFilenameUriConversionHelper(const wchar_t * filename, - const wchar_t * uriString, bool forUnix) { + const wchar_t * uriString, bool forUnix, + const wchar_t * expectedUriString = NULL) { const int prefixLen = forUnix ? 7 : 8; + if (! expectedUriString) { + expectedUriString = uriString; + } // Filename to URI string const size_t uriBufferLen = prefixLen + 3 * wcslen(filename) + 1; @@ -1518,9 +1525,9 @@ Rule | Example | hostSet | absPath | emptySeg uriWindowsFilenameToUriStringW(filename, uriBuffer); } #ifdef HAVE_WPRINTF - // wprintf(L"1 [%s][%s]\n", uriBuffer, uriString); + // wprintf(L"1 [%s][%s]\n", uriBuffer, expectedUriString); #endif - TEST_ASSERT(!wcscmp(uriBuffer, uriString)); + TEST_ASSERT(!wcscmp(uriBuffer, expectedUriString)); delete [] uriBuffer; // URI string to filename @@ -1542,9 +1549,12 @@ Rule | Example | hostSet | absPath | emptySeg const bool FOR_UNIX = true; const bool FOR_WINDOWS = false; testFilenameUriConversionHelper(L"/bin/bash", L"file:///bin/bash", FOR_UNIX); + testFilenameUriConversionHelper(L"/bin/bash", L"file:/bin/bash", FOR_UNIX, L"file:///bin/bash"); testFilenameUriConversionHelper(L"./configure", L"./configure", FOR_UNIX); testFilenameUriConversionHelper(L"E:\\Documents and Settings", L"file:///E:/Documents%20and%20Settings", FOR_WINDOWS); + testFilenameUriConversionHelper(L"c:\\path\\to\\file.txt", L"file:c:/path/to/file.txt", FOR_WINDOWS, L"file:///c:/path/to/file.txt"); + testFilenameUriConversionHelper(L".\\Readme.txt", L"./Readme.txt", FOR_WINDOWS); testFilenameUriConversionHelper(L"index.htm", L"index.htm", FOR_WINDOWS); @@ -1810,6 +1820,79 @@ Rule | Example | hostSet | absPath | emptySeg testEqualsHelper("//host:123"); } + void testHostTextTermination_Issue15() { + UriParserStateA state; + UriUriA uri; + state.uri = &uri; + + // Empty host and port + const char * const emptyHostWithPortUri = "//:123"; + TEST_ASSERT(URI_SUCCESS == uriParseUriA(&state, emptyHostWithPortUri)); + TEST_ASSERT(uri.hostText.first == emptyHostWithPortUri + strlen("//")); + TEST_ASSERT(uri.hostText.afterLast == uri.hostText.first + 0); + TEST_ASSERT(uri.portText.first == emptyHostWithPortUri + + strlen("//:")); + TEST_ASSERT(uri.portText.afterLast == uri.portText.first + + strlen("123")); + uriFreeUriMembersA(&uri); + + // Non-empty host and port + const char * const hostWithPortUri = "//h:123"; + TEST_ASSERT(URI_SUCCESS == uriParseUriA(&state, hostWithPortUri)); + TEST_ASSERT(uri.hostText.first == hostWithPortUri + strlen("//")); + TEST_ASSERT(uri.hostText.afterLast == uri.hostText.first + + strlen("h")); + TEST_ASSERT(uri.portText.first == hostWithPortUri + strlen("//h:")); + TEST_ASSERT(uri.portText.afterLast == uri.portText.first + + strlen("123")); + uriFreeUriMembersA(&uri); + + // Empty host, empty user info + const char * const emptyHostEmptyUserInfoUri = "//@"; + TEST_ASSERT(URI_SUCCESS == uriParseUriA(&state, + emptyHostEmptyUserInfoUri)); + TEST_ASSERT(uri.userInfo.first == emptyHostEmptyUserInfoUri + + strlen("//")); + TEST_ASSERT(uri.userInfo.afterLast == uri.userInfo.first + 0); + TEST_ASSERT(uri.hostText.first == emptyHostEmptyUserInfoUri + + strlen("//@")); + TEST_ASSERT(uri.hostText.afterLast == uri.hostText.first + 0); + uriFreeUriMembersA(&uri); + + // Non-empty host, empty user info + const char * const hostEmptyUserInfoUri = "//@h"; + TEST_ASSERT(URI_SUCCESS == uriParseUriA(&state, hostEmptyUserInfoUri)); + TEST_ASSERT(uri.userInfo.first == hostEmptyUserInfoUri + strlen("//")); + TEST_ASSERT(uri.userInfo.afterLast == uri.userInfo.first + 0); + TEST_ASSERT(uri.hostText.first == hostEmptyUserInfoUri + + strlen("//@")); + TEST_ASSERT(uri.hostText.afterLast == uri.hostText.first + + strlen("h")); + uriFreeUriMembersA(&uri); + + // Empty host, non-empty user info + const char * const emptyHostWithUserInfoUri = "//:@"; + TEST_ASSERT(URI_SUCCESS == uriParseUriA(&state, + emptyHostWithUserInfoUri)); + TEST_ASSERT(uri.userInfo.first == emptyHostWithUserInfoUri + + strlen("//")); + TEST_ASSERT(uri.userInfo.afterLast == uri.userInfo.first + 1); + TEST_ASSERT(uri.hostText.first == emptyHostWithUserInfoUri + + strlen("//:@")); + TEST_ASSERT(uri.hostText.afterLast == uri.hostText.first + 0); + uriFreeUriMembersA(&uri); + + // Exact case from issue #15 + const char * const issue15Uri = "//:%aa@"; + TEST_ASSERT(URI_SUCCESS == uriParseUriA(&state, issue15Uri)); + TEST_ASSERT(uri.userInfo.first == issue15Uri + strlen("//")); + TEST_ASSERT(uri.userInfo.afterLast == uri.userInfo.first + + strlen(":%aa")); + TEST_ASSERT(uri.hostText.first == issue15Uri + strlen("//:%aa@")); + TEST_ASSERT(uri.hostText.afterLast == uri.hostText.first + 0); + uriFreeUriMembersA(&uri); + } + void testCompareRangeHelper(const char * a, const char * b, int expected, bool avoidNullRange = true) { UriTextRangeA ra; UriTextRangeA rb; @@ -1865,6 +1948,81 @@ Rule | Example | hostSet | absPath | emptySeg testCompareRangeHelper("", NULL, 1, AVOID_NULL_RANGE); testCompareRangeHelper("", NULL, 1, KEEP_NULL_RANGE); } + + void testRemoveBaseUriHelper(const char * expected, + const char * absSourceStr, + const char * absBaseStr) { + UriParserStateA state; + UriUriA absSource; + UriUriA absBase; + UriUriA dest; + + state.uri = &absSource; + TEST_ASSERT(uriParseUriA(&state, absSourceStr) == URI_SUCCESS); + + state.uri = &absBase; + TEST_ASSERT(uriParseUriA(&state, absBaseStr) == URI_SUCCESS); + + TEST_ASSERT(uriRemoveBaseUriA(&dest, &absSource, &absBase, URI_FALSE) + == URI_SUCCESS); + + int size = 0; + TEST_ASSERT(uriToStringCharsRequiredA(&dest, &size) == URI_SUCCESS); + char * const buffer = (char *)malloc(size + 1); + TEST_ASSERT(buffer); + TEST_ASSERT(uriToStringA(buffer, &dest, size + 1, &size) + == URI_SUCCESS); + if (strcmp(buffer, expected)) { + printf("Expected \"%s\" but got \"%s\"\n", expected, buffer); + TEST_ASSERT(0); + } + free(buffer); + } + + void testRangeComparison_RemoveBaseUri_Issue19() { + // scheme + testRemoveBaseUriHelper("scheme://host/source", + "scheme://host/source", + "schemelonger://host/base"); + testRemoveBaseUriHelper("schemelonger://host/source", + "schemelonger://host/source", + "scheme://host/base"); + + // hostText + testRemoveBaseUriHelper("//host/source", + "http://host/source", + "http://hostlonger/base"); + testRemoveBaseUriHelper("//hostlonger/source", + "http://hostlonger/source", + "http://host/base"); + + // hostData.ipFuture + testRemoveBaseUriHelper("//[v7.host]/source", + "http://[v7.host]/source", + "http://[v7.hostlonger]/base"); + testRemoveBaseUriHelper("//[v7.hostlonger]/source", + "http://[v7.hostlonger]/source", + "http://host/base"); + + // path + testRemoveBaseUriHelper("path1", + "http://host/path1", + "http://host/path111"); + testRemoveBaseUriHelper("../path1/path2", + "http://host/path1/path2", + "http://host/path111/path222"); + testRemoveBaseUriHelper("path111", + "http://host/path111", + "http://host/path1"); + testRemoveBaseUriHelper("../path111/path222", + "http://host/path111/path222", + "http://host/path1/path2"); + + // Exact issue #19 + testRemoveBaseUriHelper("//example/x/abc", + "http://example/x/abc", + "http://example2/x/y/z"); + } }; -- cgit v1.2.3