aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Walters <rwalters@digitalstirling.com>2018-06-30 21:20:37 -0700
committerRichard Walters <rwalters@digitalstirling.com>2018-06-30 21:20:37 -0700
commita43820d0b4014878e4bbfede6acde25f5830faa7 (patch)
tree58892b88fe5927b04b060af1501741c4766b7bee
parent58e2beb7717cf724ae37e03f2e5bf3afbfc23a35 (diff)
Add support for port and hasPort elements
-rw-r--r--include/Uri/Uri.hpp24
-rw-r--r--src/Uri.cpp46
-rw-r--r--test/src/UriTests.cpp49
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"));
+}