From: Jason Dillaman Date: Mon, 2 Nov 2020 15:22:47 +0000 (-0500) Subject: librbd/migration: helper tool for parsing URLs into parts X-Git-Tag: v16.1.0~527^2~7 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=46c0275ddfdeebd95d4e393791db1259df87b136;p=ceph.git librbd/migration: helper tool for parsing URLs into parts The boost::beast framework doesn't include a URL parser but the HTTP client requires the host, port, and path to be specified seperately. Additionally, if https is utilized the http stream needs to be wrapped with an SSL stream. Signed-off-by: Jason Dillaman --- diff --git a/src/librbd/CMakeLists.txt b/src/librbd/CMakeLists.txt index ac4b196def1e..940a365134d9 100644 --- a/src/librbd/CMakeLists.txt +++ b/src/librbd/CMakeLists.txt @@ -131,6 +131,7 @@ set(librbd_internal_srcs migration/OpenSourceImageRequest.cc migration/RawFormat.cc migration/SourceSpecBuilder.cc + migration/Utils.cc mirror/DemoteRequest.cc mirror/DisableRequest.cc mirror/EnableRequest.cc diff --git a/src/librbd/migration/Types.h b/src/librbd/migration/Types.h new file mode 100644 index 000000000000..244dc28b7749 --- /dev/null +++ b/src/librbd/migration/Types.h @@ -0,0 +1,42 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#ifndef CEPH_LIBRBD_MIGRATION_TYPES_H +#define CEPH_LIBRBD_MIGRATION_TYPES_H + +#include +#include + +namespace librbd { +namespace migration { + +enum UrlScheme { + URL_SCHEME_HTTP, + URL_SCHEME_HTTPS, +}; + +struct UrlSpec { + UrlSpec() {} + UrlSpec(UrlScheme scheme, const std::string& host, const std::string& port, + const std::string& path) + : scheme(scheme), host(host), port(port), path(path) { + } + + UrlScheme scheme = URL_SCHEME_HTTP; + std::string host; + std::string port = "80"; + std::string path = "/"; + +}; + +inline bool operator==(const UrlSpec& lhs, const UrlSpec& rhs) { + return (lhs.scheme == rhs.scheme && + lhs.host == rhs.host && + lhs.port == rhs.port && + lhs.path == rhs.path); +} + +} // namespace migration +} // namespace librbd + +#endif // CEPH_LIBRBD_MIGRATION_TYPES_H diff --git a/src/librbd/migration/Utils.cc b/src/librbd/migration/Utils.cc new file mode 100644 index 000000000000..23b803d27627 --- /dev/null +++ b/src/librbd/migration/Utils.cc @@ -0,0 +1,65 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "librbd/migration/Utils.h" +#include "common/dout.h" +#include "common/errno.h" +#include +#include + +namespace librbd { +namespace migration { +namespace util { + +#define dout_subsys ceph_subsys_rbd +#undef dout_prefix +#define dout_prefix *_dout << "librbd::migration::util::" << __func__ << ": " + +int parse_url(CephContext* cct, const std::string& url, UrlSpec* url_spec) { + ldout(cct, 10) << "url=" << url << dendl; + *url_spec = UrlSpec{}; + + // parse the provided URL (scheme, user, password, host, port, path, + // parameters, query, and fragment) + std::regex url_regex( + R"(^(?:([^:/]*)://)?(?:(\w+)(?::(\w+))?@)?([^/;\?:#]+)(?::([^/;\?#]+))?)" + R"((?:/([^;\?#]*))?(?:;([^\?#]+))?(?:\?([^#]+))?(?:#(\w+))?$)"); + std::smatch match; + if(!std::regex_match(url, match, url_regex)) { + lderr(cct) << "invalid url: '" << url << "'" << dendl; + return -EINVAL; + } + + auto& scheme = match[1]; + if (scheme == "http" || scheme == "") { + url_spec->scheme = URL_SCHEME_HTTP; + } else if (scheme == "https") { + url_spec->scheme = URL_SCHEME_HTTPS; + url_spec->port = "443"; + } else { + lderr(cct) << "invalid url scheme: '" << url << "'" << dendl; + return -EINVAL; + } + + url_spec->host = match[4]; + auto& port = match[5]; + if (port.matched) { + try { + boost::lexical_cast(port); + } catch (boost::bad_lexical_cast&) { + lderr(cct) << "invalid url port: '" << url << "'" << dendl; + return -EINVAL; + } + url_spec->port = port; + } + + auto& path = match[6]; + if (path.matched) { + url_spec->path += path; + } + return 0; +} + +} // namespace util +} // namespace migration +} // namespace librbd diff --git a/src/librbd/migration/Utils.h b/src/librbd/migration/Utils.h new file mode 100644 index 000000000000..a3e2fe0132c6 --- /dev/null +++ b/src/librbd/migration/Utils.h @@ -0,0 +1,21 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#ifndef CEPH_LIBRBD_MIGRATION_UTILS_H +#define CEPH_LIBRBD_MIGRATION_UTILS_H + +#include "include/common_fwd.h" +#include "librbd/migration/Types.h" +#include + +namespace librbd { +namespace migration { +namespace util { + +int parse_url(CephContext* cct, const std::string& url, UrlSpec* url_spec); + +} // namespace util +} // namespace migration +} // namespace librbd + +#endif // CEPH_LIBRBD_MIGRATION_UTILS_H diff --git a/src/test/librbd/CMakeLists.txt b/src/test/librbd/CMakeLists.txt index 2c77d38b35db..5571712e23ad 100644 --- a/src/test/librbd/CMakeLists.txt +++ b/src/test/librbd/CMakeLists.txt @@ -91,6 +91,7 @@ set(unittest_librbd_srcs managed_lock/test_mock_ReleaseRequest.cc migration/test_mock_FileStream.cc migration/test_mock_RawFormat.cc + migration/test_mock_Utils.cc mirror/snapshot/test_mock_CreateNonPrimaryRequest.cc mirror/snapshot/test_mock_CreatePrimaryRequest.cc mirror/snapshot/test_mock_ImageMeta.cc diff --git a/src/test/librbd/migration/test_mock_Utils.cc b/src/test/librbd/migration/test_mock_Utils.cc new file mode 100644 index 000000000000..917c191dde6e --- /dev/null +++ b/src/test/librbd/migration/test_mock_Utils.cc @@ -0,0 +1,47 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "test/librbd/test_mock_fixture.h" +#include "test/librbd/test_support.h" +#include "librbd/migration/Utils.h" +#include "gtest/gtest.h" +#include "gmock/gmock.h" + +namespace librbd { +namespace migration { +namespace util { + +class TestMockMigrationUtils : public TestMockFixture { +public: +}; + +TEST_F(TestMockMigrationUtils, ParseUrl) { + UrlSpec url_spec; + ASSERT_EQ(-EINVAL, parse_url(g_ceph_context, "", &url_spec)); + ASSERT_EQ(-EINVAL, parse_url(g_ceph_context, "jttp://google.com/path", + &url_spec)); + ASSERT_EQ(-EINVAL, parse_url(g_ceph_context, "http://google.com:absd/path", + &url_spec)); + + ASSERT_EQ(0, parse_url(g_ceph_context, "ceph.io/path", &url_spec)); + ASSERT_EQ(UrlSpec(URL_SCHEME_HTTP, "ceph.io", "80", "/path"), url_spec); + + ASSERT_EQ(0, parse_url(g_ceph_context, "http://google.com/path", &url_spec)); + ASSERT_EQ(UrlSpec(URL_SCHEME_HTTP, "google.com", "80", "/path"), url_spec); + + ASSERT_EQ(0, parse_url(g_ceph_context, "https://ceph.io/", &url_spec)); + ASSERT_EQ(UrlSpec(URL_SCHEME_HTTPS, "ceph.io", "443", "/"), url_spec); + + ASSERT_EQ(0, parse_url(g_ceph_context, + "http://google.com:1234/some/other/path", &url_spec)); + ASSERT_EQ(UrlSpec(URL_SCHEME_HTTP, "google.com", "1234", "/some/other/path"), + url_spec); + + ASSERT_EQ(0, parse_url(g_ceph_context, + "http://1.2.3.4/", &url_spec)); + ASSERT_EQ(UrlSpec(URL_SCHEME_HTTP, "1.2.3.4", "80", "/"), url_spec); +} + +} // namespace util +} // namespace migration +} // namespace librbd