Commit 59c7c8ea authored by Jun LI's avatar Jun LI Committed by Sara Golemon

Fix folly Uri::host() return value for IPv6 address

Summary: folly Uri::host() returns leading and trailing brackets for IPv6 host, for example, for URI "http:://[::1]:8080/index.html", host() method returns "[::1]". But square brackets are not part of host in fact, this diff is going to remove brackets for IPv6 host.

Test Plan: fbconfig -r folly/test && fbmake runtests_dbg

Reviewed By: chip@fb.com

FB internal diff: D1276513
parent 934a0b06
......@@ -64,8 +64,8 @@ Uri::Uri(StringPiece str) : port_(0) {
} else {
static const boost::regex authorityRegex(
"(?:([^@:]*)(?::([^@]*))?@)?" // username, password
"(\\[[^\\]]*\\]|[^\\[:]*)" // host (IP-literal, dotted-IPv4, or
// named host)
"(\\[[^\\]]*\\]|[^\\[:]*)" // host (IP-literal (e.g. '['+IPv6+']',
// dotted-IPv4, or named host)
"(?::(\\d*))?"); // port
auto authority = authorityAndPathMatch[1];
......@@ -121,4 +121,13 @@ fbstring Uri::authority() const {
return result;
}
fbstring Uri::hostname() const {
if (host_.size() > 0 && host_[0] == '[') {
// If it starts with '[', then it should end with ']', this is ensured by
// regex
return host_.substr(1, host_.size() - 2);
}
return host_;
}
} // namespace folly
......@@ -47,7 +47,21 @@ class Uri {
const fbstring& scheme() const { return scheme_; }
const fbstring& username() const { return username_; }
const fbstring& password() const { return password_; }
/**
* Get host part of URI. If host is an IPv6 address, square brackets will be
* returned, for example: "[::1]".
*/
const fbstring& host() const { return host_; }
/**
* Get host part of URI. If host is an IPv6 address, square brackets will not
* be returned, for exmaple "::1"; otherwise it returns the same thing as
* host().
*
* hostname() is what one needs to call if passing the host to any other tool
* or API that connects to that host/port; e.g. getaddrinfo() only understands
* IPv6 host without square brackets
*/
fbstring hostname() const;
uint16_t port() const { return port_; }
const fbstring& path() const { return path_; }
const fbstring& query() const { return query_; }
......
......@@ -79,6 +79,7 @@ TEST(Uri, Simple) {
EXPECT_EQ("", u.username());
EXPECT_EQ("", u.password());
EXPECT_EQ("[::1]", u.host());
EXPECT_EQ("::1", u.hostname());
EXPECT_EQ(8080, u.port());
EXPECT_EQ("[::1]:8080", u.authority());
EXPECT_EQ("/hello/world", u.path());
......@@ -87,6 +88,38 @@ TEST(Uri, Simple) {
EXPECT_EQ(s, u.fbstr()); // canonical
}
{
fbstring s("http://[2401:db00:20:7004:face:0:29:0]:8080/hello/world?query");
Uri u(s);
EXPECT_EQ("http", u.scheme());
EXPECT_EQ("", u.username());
EXPECT_EQ("", u.password());
EXPECT_EQ("[2401:db00:20:7004:face:0:29:0]", u.host());
EXPECT_EQ("2401:db00:20:7004:face:0:29:0", u.hostname());
EXPECT_EQ(8080, u.port());
EXPECT_EQ("[2401:db00:20:7004:face:0:29:0]:8080", u.authority());
EXPECT_EQ("/hello/world", u.path());
EXPECT_EQ("query", u.query());
EXPECT_EQ("", u.fragment());
EXPECT_EQ(s, u.fbstr()); // canonical
}
{
fbstring s("http://[2401:db00:20:7004:face:0:29:0]/hello/world?query");
Uri u(s);
EXPECT_EQ("http", u.scheme());
EXPECT_EQ("", u.username());
EXPECT_EQ("", u.password());
EXPECT_EQ("[2401:db00:20:7004:face:0:29:0]", u.host());
EXPECT_EQ("2401:db00:20:7004:face:0:29:0", u.hostname());
EXPECT_EQ(0, u.port());
EXPECT_EQ("[2401:db00:20:7004:face:0:29:0]", u.authority());
EXPECT_EQ("/hello/world", u.path());
EXPECT_EQ("query", u.query());
EXPECT_EQ("", u.fragment());
EXPECT_EQ(s, u.fbstr()); // canonical
}
{
fbstring s("http://user:pass@host.com/");
Uri u(s);
......@@ -243,4 +276,48 @@ TEST(Uri, Simple) {
EXPECT_TRUE(boost::algorithm::ends_with(ex.what(), s));
}
}
{
fbstring s("http://[::1:8080/hello/world?query#fragment");
try {
Uri u(s);
CHECK(false) << "Control should not have reached here";
} catch (const std::invalid_argument& ex) {
// success
}
}
{
fbstring s("http://::1]:8080/hello/world?query#fragment");
try {
Uri u(s);
CHECK(false) << "Control should not have reached here";
} catch (const std::invalid_argument& ex) {
// success
}
}
{
fbstring s("http://::1:8080/hello/world?query#fragment");
try {
Uri u(s);
CHECK(false) << "Control should not have reached here";
} catch (const std::invalid_argument& ex) {
// success
}
}
{
fbstring s("http://2401:db00:20:7004:face:0:29:0/hello/world?query");
try {
Uri u(s);
CHECK(false) << "Control should not have reached here";
} catch (const std::invalid_argument& ex) {
// success
}
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment