diff options
-rw-r--r-- | include/Uri/Uri.hpp | 24 | ||||
-rw-r--r-- | src/Uri.cpp | 46 | ||||
-rw-r--r-- | test/src/UriTests.cpp | 49 |
3 files changed, 118 insertions, 1 deletions
diff --git a/include/Uri/Uri.hpp b/include/Uri/Uri.hpp index fb1e5c8..4907aaf 100644 --- a/include/Uri/Uri.hpp +++ b/include/Uri/Uri.hpp @@ -10,6 +10,7 @@ */ #include <memory> +#include <stdint.h> #include <string> #include <vector> @@ -84,6 +85,29 @@ namespace Uri { */ std::vector< std::string > GetPath() const; + /** + * This method returns an indication of whether or not the + * URI includes a port number. + * + * @return + * An indication of whether or not the + * URI includes a port number is returned. + */ + bool HasPort() const; + + /** + * This method returns the port number element of the URI, + * if it has one. + * + * @return + * The port number element of the URI is returned. + * + * @note + * The returned port number is only valid if the + * HasPort method returns true. + */ + uint16_t GetPort() const; + // Private properties private: /** diff --git a/src/Uri.cpp b/src/Uri.cpp index c028443..78f3b4d 100644 --- a/src/Uri.cpp +++ b/src/Uri.cpp @@ -6,6 +6,7 @@ * © 2018 by Richard Walters */ +#include <inttypes.h> #include <string> #include <Uri/Uri.hpp> #include <vector> @@ -26,6 +27,17 @@ namespace Uri { std::string host; /** + * This flag indicates whether or not the + * URI includes a port number. + */ + bool hasPort = false; + + /** + * This is the port number element of the URI. + */ + uint16_t port = 0; + + /** * This is the "path" element of the URI, * as a sequence of segments. */ @@ -46,9 +58,33 @@ namespace Uri { auto rest = uriString.substr(schemeEnd + 1); // Next parse the host. + impl_->hasPort = false; if (rest.substr(0, 2) == "//") { const auto authorityEnd = rest.find('/', 2); - impl_->host = rest.substr(2, authorityEnd - 2); + const auto portDelimiter = rest.find(':'); + if (portDelimiter == std::string::npos) { + impl_->host = rest.substr(2, authorityEnd - 2); + } else { + impl_->host = rest.substr(2, portDelimiter - 2); + uint32_t newPort = 0; + for (auto c: rest.substr(portDelimiter + 1, authorityEnd - portDelimiter - 1)) { + if ( + (c < '0') + || (c > '9') + ) { + return false; + } + newPort *= 10; + newPort += (uint16_t)(c - '0'); + if ( + (newPort & ~((1 << 16) - 1)) != 0 + ) { + return false; + } + } + impl_->port = (uint16_t)newPort; + impl_->hasPort = true; + } rest = rest.substr(authorityEnd); } else { impl_->host.clear(); @@ -90,4 +126,12 @@ namespace Uri { return impl_->path; } + bool Uri::HasPort() const { + return impl_->hasPort; + } + + uint16_t Uri::GetPort() const { + return impl_->port; + } + } diff --git a/test/src/UriTests.cpp b/test/src/UriTests.cpp index 2f8f28e..2be24b6 100644 --- a/test/src/UriTests.cpp +++ b/test/src/UriTests.cpp @@ -57,3 +57,52 @@ TEST(UriTests, ParseFromStringPathCornerCases) { ++index; } } + +TEST(UriTests, ParseFromStringHasAPortNumber) { + Uri::Uri uri; + ASSERT_TRUE(uri.ParseFromString("http://www.example.com:8080/foo/bar")); + ASSERT_EQ("www.example.com", uri.GetHost()); + ASSERT_TRUE(uri.HasPort()); + ASSERT_EQ(8080, uri.GetPort()); +} + +TEST(UriTests, ParseFromStringDoesNotHaveAPortNumber) { + Uri::Uri uri; + ASSERT_TRUE(uri.ParseFromString("http://www.example.com/foo/bar")); + ASSERT_EQ("www.example.com", uri.GetHost()); + ASSERT_FALSE(uri.HasPort()); +} + +TEST(UriTests, ParseFromStringTwiceFirstWithPortNumberThenWithout) { + Uri::Uri uri; + ASSERT_TRUE(uri.ParseFromString("http://www.example.com:8080/foo/bar")); + ASSERT_TRUE(uri.ParseFromString("http://www.example.com/foo/bar")); + ASSERT_FALSE(uri.HasPort()); +} + +TEST(UriTests, ParseFromStringBadPortNumberPurelyAlphabetic) { + Uri::Uri uri; + ASSERT_FALSE(uri.ParseFromString("http://www.example.com:spam/foo/bar")); +} + +TEST(UriTests, ParseFromStringBadPortNumberStartsNumericEndsAlphabetic) { + Uri::Uri uri; + ASSERT_FALSE(uri.ParseFromString("http://www.example.com:8080spam/foo/bar")); +} + +TEST(UriTests, ParseFromStringLargestValidPortNumber) { + Uri::Uri uri; + ASSERT_TRUE(uri.ParseFromString("http://www.example.com:65535/foo/bar")); + ASSERT_TRUE(uri.HasPort()); + ASSERT_EQ(65535, uri.GetPort()); +} + +TEST(UriTests, ParseFromStringBadPortNumberTooBig) { + Uri::Uri uri; + ASSERT_FALSE(uri.ParseFromString("http://www.example.com:65536/foo/bar")); +} + +TEST(UriTests, ParseFromStringBadPortNumberNegative) { + Uri::Uri uri; + ASSERT_FALSE(uri.ParseFromString("http://www.example.com:-1234/foo/bar")); +} |