diff options
author | Richard Walters <rwalters@digitalstirling.com> | 2018-07-04 19:05:06 -0700 |
---|---|---|
committer | Richard Walters <rwalters@digitalstirling.com> | 2018-07-04 19:05:06 -0700 |
commit | d95bcc094d5102cbc1b625b69bf6378e3fb730a8 (patch) | |
tree | 62c2ac08f3a8749d64fd9948db75467efb86bd3b | |
parent | 872905197e3dbcdf0041930fda67cbd371c240ac (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.hpp | 46 | ||||
-rw-r--r-- | src/Uri.cpp | 75 | ||||
-rw-r--r-- | test/src/UriTests.cpp | 46 |
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; |