From 79d0b6a784d57f3821ce3539e4280d3704cba00e Mon Sep 17 00:00:00 2001 From: Florian Kaiser Date: Fri, 12 Jul 2024 10:06:33 +0200 Subject: [PATCH 1/2] attempt parsing of port only if colon was found without this change, urls like 5.my.s3.cluster were misinterpreted and the '5' parsed as the port of the url. Bug: * the getline() function puts the entire input string into the destination string, if the delimiter was not found. This leads to the entire host string being fed to the stoi() function to parse the port. Fix: * applied suggestion by @balamurugana --- src/http.cc | 14 +++++++++----- tests/tests.cc | 31 +++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/http.cc b/src/http.cc index 8af3dfa..a96177b 100644 --- a/src/http.cc +++ b/src/http.cc @@ -140,18 +140,22 @@ Url Url::Parse(std::string value) { unsigned int port = 0; struct sockaddr_in6 dst; if (inet_pton(AF_INET6, host.c_str(), &(dst.sin6_addr)) <= 0) { - if (host.front() != '[' || host.back() != ']') { + if ((host.front() != '[' || host.back() != ']') && utils::Contains(host, ':')) { std::stringstream ss(host); std::string portstr; while (std::getline(ss, portstr, ':')) { } if (!portstr.empty()) { - try { - port = static_cast(std::stoi(portstr)); + char* str_end{}; + const long l = std::strtol(portstr.c_str(), &str_end, 10); + size_t length = std::distance(portstr.c_str(), const_cast(str_end)); + if (length == portstr.size()) { + if (l < 1 || l > 65535) { + return Url{}; + } + port = static_cast(l); host = host.substr(0, host.rfind(":" + portstr)); - } catch (const std::invalid_argument&) { - port = 0; } } } diff --git a/tests/tests.cc b/tests/tests.cc index 427dd62..f8fa3aa 100644 --- a/tests/tests.cc +++ b/tests/tests.cc @@ -699,6 +699,36 @@ class Tests { throw; } } + + void TestBaseUrl() { + std::cout << "TestBaseUrl()" << std::endl; + std::vector> tests = { + {"http://localhost:9000", "localhost", false, 9000}, + {"http://localhost", "localhost", false, 0}, + {"http://localhost:80", "localhost", false, 0}, + {"https://localhost:9443", "localhost", true, 9443}, + {"https://localhost", "localhost", true, 0}, + {"https://5.localhost.foo", "5.localhost.foo", true, 0}, + {"https://5.localhost.foo:9000", "5.localhost.foo", true, 9000}, + }; + for (auto& [url, host, https, port] : tests) { + minio::s3::BaseUrl base_url(url); + if (base_url.host != host) { + throw std::runtime_error("BaseUrl(" + url +").host: expected: " + host + + ", got: " + base_url.host); + } + if (base_url.https != https) { + throw std::runtime_error("BaseUrl("+ url +").https: expected: " + + std::to_string(https) + + ", got: " + std::to_string(base_url.https)); + } + if (base_url.port != port) { + throw std::runtime_error("BaseUrl("+ url +").port: expected: " + + std::to_string(port) + + ", got: " + std::to_string(base_url.port)); + } + } + } }; // class Tests int main(int /*argc*/, char* /*argv*/[]) { @@ -756,6 +786,7 @@ int main(int /*argc*/, char* /*argv*/[]) { tests.RemoveObjects(); tests.SelectObjectContent(); tests.ListenBucketNotification(); + tests.TestBaseUrl(); return EXIT_SUCCESS; } From 8a6591b975fda40517a6295793055ea9e5bea889 Mon Sep 17 00:00:00 2001 From: Florian Kaiser Date: Fri, 12 Jul 2024 17:01:56 +0200 Subject: [PATCH 2/2] https flag is not mirrored from Url() to BaseUrl this flag assignement was removed in: https://github.com/minio/minio-cpp/pull/111 I don't know if it was removed intentional, but without it the BaseUrl.https flag only reflects the state of how BaseUrl was constructed with. --- src/request.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/request.cc b/src/request.cc index 9b6130c..0b199d0 100644 --- a/src/request.cc +++ b/src/request.cc @@ -162,6 +162,7 @@ BaseUrl::BaseUrl(std::string host, bool https, std::string region) return; } + this->https = url.https; this->host = url.host; this->port = url.port;