aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Walters <rwalters@digitalstirling.com>2018-07-04 19:05:06 -0700
committerRichard Walters <rwalters@digitalstirling.com>2018-07-04 19:05:06 -0700
commitd95bcc094d5102cbc1b625b69bf6378e3fb730a8 (patch)
tree62c2ac08f3a8749d64fd9948db75467efb86bd3b
parent872905197e3dbcdf0041930fda67cbd371c240ac (diff)
Add capability of setting other elements
* userinfo * port (hasPort) * path * fragment Also include these element when generating string from URI.
-rw-r--r--include/Uri/Uri.hpp46
-rw-r--r--src/Uri.cpp75
-rw-r--r--test/src/UriTests.cpp46
3 files changed, 152 insertions, 15 deletions
diff --git a/include/Uri/Uri.hpp b/include/Uri/Uri.hpp
index 0b4a22c..7074990 100644
--- a/include/Uri/Uri.hpp
+++ b/include/Uri/Uri.hpp
@@ -221,6 +221,14 @@ namespace Uri {
void SetScheme(const std::string& scheme);
/**
+ * This method sets the userinfo element of the URI.
+ *
+ * @param[in] userinfo
+ * This is the userinfo to set for the URI.
+ */
+ void SetUserInfo(const std::string& userinfo);
+
+ /**
* This method sets the host element of the URI.
*
* @param[in] host
@@ -229,6 +237,36 @@ namespace Uri {
void SetHost(const std::string& host);
/**
+ * This method sets the port element of the URI.
+ *
+ * @param[in] port
+ * This is the port to set for the URI.
+ */
+ void SetPort(uint16_t port);
+
+ /**
+ * This method removes the port element from the URI.
+ */
+ void ClearPort();
+
+ /**
+ * This method sets the path element of the URI.
+ *
+ * @param[in] path
+ * This is the sequence of segments to use to form the path
+ * to set for the URI.
+ *
+ * An empty string segment can be used at the front to
+ * indicate an absolute path (as opposed to a relative one).
+ *
+ * An empty string segment can be used at the back to
+ * make sure the path ends in a delimiter (forward slash)
+ * when printed out or when combined with another URI
+ * via the Resolve() method.
+ */
+ void SetPath(const std::vector< std::string >& path);
+
+ /**
* This method sets the query element of the URI.
*
* @param[in] query
@@ -237,6 +275,14 @@ namespace Uri {
void SetQuery(const std::string& query);
/**
+ * This method sets the fragment element of the URI.
+ *
+ * @param[in] fragment
+ * This is the fragment to set for the URI.
+ */
+ void SetFragment(const std::string& fragment);
+
+ /**
* This method constructs and returns the string
* rendering of the URI, according to the rules
* in RFC 3986 (https://tools.ietf.org/html/rfc3986).
diff --git a/src/Uri.cpp b/src/Uri.cpp
index 5d36a9d..eee40ad 100644
--- a/src/Uri.cpp
+++ b/src/Uri.cpp
@@ -556,6 +556,24 @@ namespace Uri {
// Methods
/**
+ * This method returns an indication of whether or not
+ * the URI includes any element that is part of the
+ * authority of the URI.
+ *
+ * @return
+ * An indication of whether or not the URI includes
+ * any element that is part of the authority of the
+ * URI is returned.
+ */
+ bool HasAuthority() const {
+ return (
+ !host.empty()
+ || !userInfo.empty()
+ || hasPort
+ );
+ }
+
+ /**
* This method builds the internal path element sequence
* by parsing it from the given path string.
*
@@ -1249,30 +1267,77 @@ namespace Uri {
impl_->scheme = scheme;
}
+ void Uri::SetUserInfo(const std::string& userinfo) {
+ impl_->userInfo = userinfo;
+ }
+
void Uri::SetHost(const std::string& host) {
impl_->host = host;
}
+ void Uri::SetPort(uint16_t port) {
+ impl_->port = port;
+ impl_->hasPort = true;
+ }
+
+ void Uri::ClearPort() {
+ impl_->hasPort = false;
+ }
+
+ void Uri::SetPath(const std::vector< std::string >& path) {
+ impl_->path = path;
+ }
+
void Uri::SetQuery(const std::string& query) {
impl_->query = query;
}
+ void Uri::SetFragment(const std::string& fragment) {
+ impl_->fragment = fragment;
+ }
+
std::string Uri::GenerateString() const {
std::ostringstream buffer;
if (!impl_->scheme.empty()) {
buffer << impl_->scheme << ':';
}
- if (!impl_->host.empty()) {
+ if (impl_->HasAuthority()) {
buffer << "//";
- if (ValidateIpv6Address(impl_->host)) {
- buffer << '[' << impl_->host << ']';
- } else {
- buffer << impl_->host;
+ if (!impl_->userInfo.empty()) {
+ buffer << impl_->userInfo << '@';
+ }
+ if (!impl_->host.empty()) {
+ if (ValidateIpv6Address(impl_->host)) {
+ buffer << '[' << impl_->host << ']';
+ } else {
+ buffer << impl_->host;
+ }
}
+ if (impl_->hasPort) {
+ buffer << ':' << impl_->port;
+ }
+ }
+ // Special case: absolute but otherwise empty path.
+ if (
+ impl_->IsPathAbsolute()
+ && (impl_->path.size() == 1)
+ ) {
+ buffer << '/';
+ }
+ size_t i = 0;
+ for (const auto& segment: impl_->path) {
+ buffer << segment;
+ if (i + 1 < impl_->path.size()) {
+ buffer << '/';
+ }
+ ++i;
}
if (!impl_->query.empty()) {
buffer << '?' << impl_->query;
}
+ if (!impl_->fragment.empty()) {
+ buffer << '#' << impl_->fragment;
+ }
return buffer.str();
}
}
diff --git a/test/src/UriTests.cpp b/test/src/UriTests.cpp
index e2ad7bd..9dbff55 100644
--- a/test/src/UriTests.cpp
+++ b/test/src/UriTests.cpp
@@ -759,28 +759,54 @@ TEST(UriTests, IPv6Address) {
TEST(UriTests, GenerateString) {
struct TestVector {
std::string scheme;
+ std::string userinfo;
std::string host;
+ bool hasPort;
+ uint16_t port;
+ std::vector< std::string > path;
std::string query;
+ std::string fragment;
std::string expectedUriString;
};
const std::vector< TestVector > testVectors{
- {"http", "www.example.com", "foobar", "http://www.example.com?foobar"},
- {"", "example.com", "bar", "//example.com?bar"},
- {"", "example.com", "", "//example.com"},
- {"", "", "bar", "?bar"},
- {"http", "", "bar", "http:?bar"},
- {"http", "", "", "http:"},
- {"http", "::1", "", "http://[::1]"},
- {"http", "::1.2.3.4", "", "http://[::1.2.3.4]"},
- {"http", "1.2.3.4", "", "http://1.2.3.4"},
- {"", "", "", ""},
+ {"http", "bob", "www.example.com", true, 8080, {"", "abc", "def"}, "foobar", "ch2", "http://bob@www.example.com:8080/abc/def?foobar#ch2"},
+ {"http", "bob", "www.example.com", true, 0, {}, "foobar", "ch2", "http://bob@www.example.com:0?foobar#ch2"},
+ {"", "", "example.com", false, 0, {}, "bar", "", "//example.com?bar"},
+ {"", "", "example.com", false, 0, {}, "", "", "//example.com"},
+ {"", "", "example.com", false, 0, {""}, "", "", "//example.com/"},
+ {"", "", "example.com", false, 0, {"", "xyz"}, "", "", "//example.com/xyz"},
+ {"", "", "example.com", false, 0, {"", "xyz", ""}, "", "", "//example.com/xyz/"},
+ {"", "", "", false, 0, {""}, "", "", "/"},
+ {"", "", "", false, 0, {"", "xyz"}, "", "", "/xyz"},
+ {"", "", "", false, 0, {"", "xyz", ""}, "", "", "/xyz/"},
+ {"", "", "", false, 0, {}, "", "", ""},
+ {"", "", "", false, 0, {"xyz"}, "", "", "xyz"},
+ {"", "", "", false, 0, {"xyz", ""}, "", "", "xyz/"},
+ {"", "", "", false, 0, {}, "bar", "", "?bar"},
+ {"http", "", "", false, 0, {}, "bar", "", "http:?bar"},
+ {"http", "", "", false, 0, {}, "", "", "http:"},
+ {"http", "", "::1", false, 0, {}, "", "", "http://[::1]"},
+ {"http", "", "::1.2.3.4", false, 0, {}, "", "", "http://[::1.2.3.4]"},
+ {"http", "", "1.2.3.4", false, 0, {}, "", "", "http://1.2.3.4"},
+ {"", "", "", false, 0, {}, "", "", ""},
+ {"http", "bob", "", false, 0, {}, "foobar", "", "http://bob@?foobar"},
+ {"", "bob", "", false, 0, {}, "foobar", "", "//bob@?foobar"},
+ {"", "bob", "", false, 0, {}, "", "", "//bob@"},
};
size_t index = 0;
for (const auto& testVector : testVectors) {
Uri::Uri uri;
uri.SetScheme(testVector.scheme);
+ uri.SetUserInfo(testVector.userinfo);
uri.SetHost(testVector.host);
+ if (testVector.hasPort) {
+ uri.SetPort(testVector.port);
+ } else {
+ uri.ClearPort();
+ }
+ uri.SetPath(testVector.path);
uri.SetQuery(testVector.query);
+ uri.SetFragment(testVector.fragment);
const auto actualUriString = uri.GenerateString();
ASSERT_EQ(testVector.expectedUriString, actualUriString) << index;
++index;