} 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];
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
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_; }
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());
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);
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
+ }
+ }
}