From f4db7fdc68461d7d30abb6ae43fa762917963ce1 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Sat, 5 Nov 2016 12:58:01 +0100 Subject: [PATCH] BUrl: allow URLs without protocol or authority again. Parsing an URL can never fail. The regexp is designed to match any input. In the worst case, everything will end up in the "path" component. WebPositive relies on this to generate file URLs from a plain path. URLs without a protocol are also possible, and can be used with an implicit protocol. A typical example is network shares sometimes noted in "//host.domain/path/file" form. Add tests for these two cases and fix the parser to behave as expected. --- src/kits/network/libnetapi/Url.cpp | 43 ++++++++++---------------- src/tests/kits/net/service/UrlTest.cpp | 12 +++++-- 2 files changed, 26 insertions(+), 29 deletions(-) diff --git a/src/kits/network/libnetapi/Url.cpp b/src/kits/network/libnetapi/Url.cpp index 9e74650816..9e40b40263 100644 --- a/src/kits/network/libnetapi/Url.cpp +++ b/src/kits/network/libnetapi/Url.cpp @@ -385,11 +385,12 @@ BUrl::UrlString() const if (HasProtocol()) { fUrlString << fProtocol << ':'; - if (HasAuthority()) - fUrlString << "//"; } - fUrlString << Authority(); + if (HasAuthority()) { + fUrlString << "//"; + fUrlString << Authority(); + } fUrlString << Path(); if (HasRequest()) @@ -922,7 +923,6 @@ enum explode_url_parse_state { EXPLODE_PATH, EXPLODE_REQUEST, // query EXPLODE_FRAGMENT, - EXPLODE_ERROR, EXPLODE_COMPLETE }; @@ -992,7 +992,7 @@ BUrl::_ExplodeUrlString(const BString& url) // The ensuing logic attempts to simulate the behaviour of extracting the groups // from the string without requiring a group-capable regex engine. - while (state != EXPLODE_ERROR && offset < length) { + while (offset < length) { switch (state) { case EXPLODE_PROTOCOL: @@ -1005,11 +1005,11 @@ BUrl::_ExplodeUrlString(const BString& url) state = EXPLODE_PROTOCOLTERMINATOR; offset = end_protocol; } else { -#if DEBUG - fprintf(stderr, - "unexpected end of url when parsing the protocol\n"); -#endif - state = EXPLODE_ERROR; + // No protocol was found, try parsing from the string + // start, beginning with authority or path + SetProtocol(""); + offset = 0; + state = EXPLODE_AUTHORITYORPATH; } break; } @@ -1017,21 +1017,21 @@ BUrl::_ExplodeUrlString(const BString& url) case EXPLODE_PROTOCOLTERMINATOR: { if (url[offset] == ':') { - state = EXPLODE_AUTHORITYORPATH; offset++; } else { -#ifdef DEBUG - fprintf(stderr, - "unexpected character '%c' terminating the protocol\n", - url_c[offset]); -#endif - state = EXPLODE_ERROR; + // No protocol was found, try parsing from the string + // start, beginning with authority or path + SetProtocol(""); + offset = 0; } + state = EXPLODE_AUTHORITYORPATH; break; } case EXPLODE_AUTHORITYORPATH: { + // The authority must start with //. If it isn't there, skip + // to parsing the path. if (strncmp(&url_c[offset], "//", 2) == 0) { state = EXPLODE_AUTHORITY; offset += 2; @@ -1085,7 +1085,6 @@ BUrl::_ExplodeUrlString(const BString& url) break; } - case EXPLODE_ERROR: case EXPLODE_COMPLETE: // should never be reached - keeps the compiler happy break; @@ -1093,14 +1092,6 @@ BUrl::_ExplodeUrlString(const BString& url) } } - if(state == EXPLODE_ERROR) { -#ifdef DEBUG - fprintf(stderr, "failure to explode url\n"); -#endif - _ResetFields(); - return B_BAD_VALUE; - } - return B_OK; } diff --git a/src/tests/kits/net/service/UrlTest.cpp b/src/tests/kits/net/service/UrlTest.cpp index 88b730fa67..90c51cce5f 100644 --- a/src/tests/kits/net/service/UrlTest.cpp +++ b/src/tests/kits/net/service/UrlTest.cpp @@ -68,7 +68,7 @@ void UrlTest::TestIsValid() !url.IsValid()); url.SetHost(""); - CPPUNIT_ASSERT_MESSAGE("Set to an invalid host.", !url.IsValid()); + CPPUNIT_ASSERT_MESSAGE("Set to an invalid host", !url.IsValid()); url.SetUrlString(""); url.SetProtocol("\t \n"); @@ -193,10 +193,16 @@ const ExplodeTest kTestExplode[] = { "urn", "", "", "", 0, "oasis:names:specification:docbook:dtd:xml:4.1.2", "", "" } }, { "http://www.goodsearch.com/login?return_path=/", { "http", "", "", "www.goodsearch.com", 0, "/login", "return_path=/", "" } }, - { "ldap://[2001:db8::7]/c=GB?objectClass?one", + { "ldap://[2001:db8::7]:389/c=GB?objectClass?one", { "ldap", "", "", "[2001:db8::7]",389,"/c=GB", "objectClass?one", "" } }, + { "ldap://[2001:db8::7]/c=GB?objectClass?one", + { "ldap", "", "", "[2001:db8::7]",0, "/c=GB", "objectClass?one", "" } }, { "HTTP://example.com.:80/%70a%74%68?a=%31#1%323", - { "HTTP", "", "", "example.com.",80, "/%70a%74%68","a=%31","1%323"} } + { "HTTP", "", "", "example.com.",80, "/%70a%74%68","a=%31","1%323"} }, + { "/boot/home/Desktop/index.html", + { "", "", "", "", 0, "/boot/home/Desktop/index.html","",""} }, + { "//remote.host/boot/home/Desktop", + { "", "", "", "remote.host", 0, "/boot/home/Desktop","",""} } }; void UrlTest::ExplodeImplodeTest()