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.
This commit is contained in:
Adrien Destugues
2016-11-05 13:01:36 +01:00
parent a9af524dbb
commit f4db7fdc68
2 changed files with 26 additions and 29 deletions
+17 -26
View File
@@ -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;
}
+9 -3
View File
@@ -68,7 +68,7 @@ void UrlTest::TestIsValid()
!url.IsValid());
url.SetHost("<invalid>");
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()