migration/OpenSourceImageRequest.cc
migration/RawFormat.cc
migration/SourceSpecBuilder.cc
+ migration/Utils.cc
mirror/DemoteRequest.cc
mirror/DisableRequest.cc
mirror/EnableRequest.cc
--- /dev/null
+// -*- 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 <string>
+#include <utility>
+
+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
--- /dev/null
+// -*- 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 <boost/lexical_cast.hpp>
+#include <regex>
+
+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<uint16_t>(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
--- /dev/null
+// -*- 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 <string>
+
+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
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
--- /dev/null
+// -*- 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