From 666102e6829b39a9cea73dacddfe8224636373a4 Mon Sep 17 00:00:00 2001 From: Matt Millett Date: Tue, 27 Aug 2024 13:01:49 -0400 Subject: [PATCH] Allow ntsa::Host to represent a local name and include and optional transport hint in ntsa::Uri --- groups/nts/ntsa/ntsa_host.cpp | 68 ++++++++++++++++++++++++++++++- groups/nts/ntsa/ntsa_host.h | 58 ++++++++++++++++++++------ groups/nts/ntsa/ntsa_hosttype.cpp | 8 ++++ groups/nts/ntsa/ntsa_hosttype.h | 5 ++- groups/nts/ntsa/ntsa_uri.cpp | 68 +++++++++++++++++++++++++++---- groups/nts/ntsa/ntsa_uri.h | 23 ++++++++--- 6 files changed, 202 insertions(+), 28 deletions(-) diff --git a/groups/nts/ntsa/ntsa_host.cpp b/groups/nts/ntsa/ntsa_host.cpp index b57a79909..4bed773bf 100644 --- a/groups/nts/ntsa/ntsa_host.cpp +++ b/groups/nts/ntsa/ntsa_host.cpp @@ -51,10 +51,15 @@ Host::Host(const ntsa::DomainName& value) } Host::Host(const ntsa::IpAddress& value) -: d_type(ntsa::HostType::e_UNDEFINED) +: d_type(ntsa::HostType::e_IP) { new (d_ip.buffer()) ntsa::IpAddress(value); - d_type = ntsa::HostType::e_IP; +} + +Host::Host(const ntsa::LocalName& value) +: d_type(ntsa::HostType::e_LOCAL_NAME) +{ + new (d_localName.buffer()) ntsa::LocalName(value); } Host::Host(const Host& other) @@ -68,6 +73,9 @@ Host::Host(const Host& other) case ntsa::HostType::e_IP: new (d_ip.buffer()) ntsa::IpAddress(other.d_ip.object()); break; + case ntsa::HostType::e_LOCAL_NAME: + new (d_localName.buffer()) ntsa::LocalName(other.d_localName.object()); + break; default: BSLS_ASSERT(d_type == ntsa::HostType::e_UNDEFINED); } @@ -86,6 +94,9 @@ Host& Host::operator=(const Host& other) case ntsa::HostType::e_IP: this->makeIp(other.d_ip.object()); break; + case ntsa::HostType::e_LOCAL_NAME: + this->makeLocalName(other.d_localName.object()); + break; default: BSLS_ASSERT(other.d_type == ntsa::HostType::e_UNDEFINED); this->reset(); @@ -106,6 +117,12 @@ Host& Host::operator=(const ntsa::IpAddress& other) return *this; } +Host& Host::operator=(const ntsa::LocalName& other) +{ + this->makeLocalName(other); + return *this; +} + Host& Host::operator=(const bslstl::StringRef& text) { this->reset(); @@ -126,6 +143,11 @@ Host& Host::operator=(const bslstl::StringRef& text) return *this; } + if (text.size() > 0 && text[0] == '/') { + this->makeLocalName().setValue(text); + return *this; + } + this->reset(); throwAddressInvalidFormat(text); @@ -152,6 +174,11 @@ bool Host::parse(const bslstl::StringRef& text) return true; } + if (text.size() > 0 && text[0] == '/') { + this->makeLocalName().setValue(text); + return true; + } + this->reset(); return false; } @@ -212,6 +239,34 @@ ntsa::IpAddress& Host::makeIp(const ntsa::IpAddress& value) return d_ip.object(); } +ntsa::LocalName& Host::makeLocalName() +{ + if (d_type == ntsa::HostType::e_LOCAL_NAME) { + d_localName.object().reset(); + } + else { + this->reset(); + new (d_localName.buffer()) ntsa::LocalName(); + d_type = ntsa::HostType::e_LOCAL_NAME; + } + + return d_localName.object(); +} + +ntsa::LocalName& Host::makeLocalName(const ntsa::LocalName& value) +{ + if (d_type == ntsa::HostType::e_LOCAL_NAME) { + d_localName.object() = value; + } + else { + this->reset(); + new (d_localName.buffer()) ntsa::LocalName(value); + d_type = ntsa::HostType::e_LOCAL_NAME; + } + + return d_localName.object(); +} + bsl::string Host::text() const { switch (d_type) { @@ -219,6 +274,8 @@ bsl::string Host::text() const return d_domainName.object().text(); case ntsa::HostType::e_IP: return d_ip.object().text(); + case ntsa::HostType::e_LOCAL_NAME: + return d_localName.object().value(); default: return ""; } @@ -235,6 +292,8 @@ bool Host::equals(const Host& other) const return d_domainName.object() == other.d_domainName.object(); case ntsa::HostType::e_IP: return d_ip.object().equals(other.d_ip.object()); + case ntsa::HostType::e_LOCAL_NAME: + return d_localName.object().equals(other.d_localName.object()); default: return true; } @@ -251,6 +310,8 @@ bool Host::less(const Host& other) const return d_domainName.object().less(other.d_domainName.object()); case ntsa::HostType::e_IP: return d_ip.object().less(other.d_ip.object()); + case ntsa::HostType::e_LOCAL_NAME: + return d_localName.object().less(other.d_localName.object()); default: return true; } @@ -267,6 +328,9 @@ bsl::ostream& Host::print(bsl::ostream& stream, case ntsa::HostType::e_IP: d_ip.object().print(stream, level, spacesPerLevel); break; + case ntsa::HostType::e_LOCAL_NAME: + d_localName.object().print(stream, level, spacesPerLevel); + break; default: BSLS_ASSERT(d_type == ntsa::HostType::e_UNDEFINED); stream << "UNDEFINED"; diff --git a/groups/nts/ntsa/ntsa_host.h b/groups/nts/ntsa/ntsa_host.h index ab849456d..a5910eaf3 100644 --- a/groups/nts/ntsa/ntsa_host.h +++ b/groups/nts/ntsa/ntsa_host.h @@ -21,6 +21,7 @@ BSLS_IDENT("$Id: $") #include #include +#include #include #include #include @@ -78,22 +79,27 @@ class Host union { bsls::ObjectBuffer d_domainName; bsls::ObjectBuffer d_ip; + bsls::ObjectBuffer d_localName; }; ntsa::HostType::Value d_type; public: - /// Create a new address having an undefined type. + /// Create a new host having an undefined type. Host(); - /// Create a new address having a "domain name" representation having - /// the specified 'value'. + /// Create a new host having a "domain name" representation having the + /// specified 'value'. explicit Host(const ntsa::DomainName& value); - /// Create a new address having a "ip" representation having the - /// specified 'value'. + /// Create a new host having a "ip" representation having the specified + /// 'value'. explicit Host(const ntsa::IpAddress& value); + /// Create a new host having a "local name" representation having the + /// specified 'value'. + explicit Host(const ntsa::LocalName& value); + /// Create a new address parsed from the specified 'text' /// representation. explicit Host(const bslstl::StringRef& text); @@ -117,6 +123,10 @@ class Host /// Return a reference to this modifiable object. Host& operator=(const ntsa::IpAddress& other); + /// Assign the value of the specified 'other' object to this object. Return + /// a reference to this modifiable object. + Host& operator=(const ntsa::LocalName& other); + /// Set the value of the object from the specified 'text'. Host& operator=(const bslstl::StringRef& text); @@ -147,27 +157,45 @@ class Host /// representation. ntsa::IpAddress& makeIp(const ntsa::IpAddress& value); + /// Select the "local name" address representation. Return a reference to + /// the modifiable representation. + ntsa::LocalName& makeLocalName(); + + /// Select the "local name" address representation initially having the + /// specified 'value'. Return a reference to the modifiable representation. + ntsa::LocalName& makeLocalName(const ntsa::LocalName& value); + /// Return a reference to the modifiable "domain name" address - /// representation. The behavior is undefined unless 'isDomainName()' - /// is true. + /// representation. The behavior is undefined unless 'isDomainName()' is + /// true. ntsa::DomainName& domainName(); - /// Return a reference to the modifiable "ip" address representation. - /// The behavior is undefined unless 'isIp()' is true. + /// Return a reference to the modifiable "ip" address representation. The + /// behavior is undefined unless 'isIp()' is true. ntsa::IpAddress& ip(); + /// Return a reference to the modifiable "local name" address + /// representation. The behavior is undefined unless 'isLocalName()' is + /// true. + ntsa::LocalName& localName(); + /// Return the textual representation of this object. bsl::string text() const; /// Return a reference to the non-modifiable "domain name" address - /// representation. The behavior is undefined unless 'isDomainName()' - /// is true. + /// representation. The behavior is undefined unless 'isDomainName()' is + /// true. const ntsa::DomainName& domainName() const; - /// Return a reference to the non-modifiable "ip" address - /// representation. The behavior is undefined unless 'isIp()' is true. + /// Return a reference to the non-modifiable "ip" address representation. + /// The behavior is undefined unless 'isIp()' is true. const ntsa::IpAddress& ip() const; + /// Return a reference to the non-modifiable "local name" address + /// representation. The behavior is undefined unless 'isLocalName()' is + /// true. + const ntsa::LocalName& localName() const; + /// Return the type of the address representation. ntsa::HostType::Value type() const; @@ -183,6 +211,10 @@ class Host /// selected, otherwise return false. bool isIp() const; + /// Return true if the "local name" address representation is currently + /// selected, otherwise return false. + bool isLocalName() const; + /// Return true if this object has the same value as the specified /// 'other' object, otherwise return false. bool equals(const Host& other) const; diff --git a/groups/nts/ntsa/ntsa_hosttype.cpp b/groups/nts/ntsa/ntsa_hosttype.cpp index 093787cb9..b56c8fa52 100644 --- a/groups/nts/ntsa/ntsa_hosttype.cpp +++ b/groups/nts/ntsa/ntsa_hosttype.cpp @@ -29,6 +29,7 @@ int HostType::fromInt(HostType::Value* result, int number) case HostType::e_UNDEFINED: case HostType::e_DOMAIN_NAME: case HostType::e_IP: + case HostType::e_LOCAL_NAME: *result = static_cast(number); return 0; default: @@ -51,6 +52,10 @@ int HostType::fromString(HostType::Value* result, *result = e_IP; return 0; } + if (bdlb::String::areEqualCaseless(string, "LOCAL_NAME")) { + *result = e_LOCAL_NAME; + return 0; + } return -1; } @@ -67,6 +72,9 @@ const char* HostType::toString(HostType::Value value) case e_IP: { return "IP"; } break; + case e_LOCAL_NAME: { + return "LOCAL_NAME"; + } break; } BSLS_ASSERT(!"invalid enumerator"); diff --git a/groups/nts/ntsa/ntsa_hosttype.h b/groups/nts/ntsa/ntsa_hosttype.h index 8bc380d95..e42273140 100644 --- a/groups/nts/ntsa/ntsa_hosttype.h +++ b/groups/nts/ntsa/ntsa_hosttype.h @@ -42,7 +42,10 @@ struct HostType { e_DOMAIN_NAME = 1, /// The host type is an IP address - e_IP = 2 + e_IP = 2, + + /// The host type is a local name. + e_LOCAL_NAME = 3 }; /// Return the string representation exactly matching the enumerator diff --git a/groups/nts/ntsa/ntsa_uri.cpp b/groups/nts/ntsa/ntsa_uri.cpp index f0f7de3bd..7424bc4d3 100644 --- a/groups/nts/ntsa/ntsa_uri.cpp +++ b/groups/nts/ntsa/ntsa_uri.cpp @@ -311,6 +311,7 @@ UriAuthority::UriAuthority(bslma::Allocator* basicAllocator) : d_user(basicAllocator) , d_host() , d_port() +, d_transport() { } @@ -319,6 +320,7 @@ UriAuthority::UriAuthority(const UriAuthority& other, : d_user(other.d_user, basicAllocator) , d_host(other.d_host) , d_port(other.d_port) +, d_transport(other.d_transport) { } @@ -329,9 +331,10 @@ UriAuthority::~UriAuthority() UriAuthority& UriAuthority::operator=(const UriAuthority& other) { if (this != &other) { - d_user = other.d_user; - d_host = other.d_host; - d_port = other.d_port; + d_user = other.d_user; + d_host = other.d_host; + d_port = other.d_port; + d_transport = other.d_transport; } return *this; @@ -342,6 +345,7 @@ void UriAuthority::reset() d_user.reset(); d_host.reset(); d_port.reset(); + d_transport.reset(); } ntsa::Error UriAuthority::setUser(const bslstl::StringRef& value) @@ -431,6 +435,18 @@ ntsa::Error UriAuthority::setPort(ntsa::Port value) return ntsa::Error(); } +ntsa::Error UriAuthority::setTransport(ntsa::Transport::Value value) +{ + if (d_transport.isNull()) { + d_transport.makeValue(value); + } + else { + d_transport.value() = value; + } + + return ntsa::Error(); +} + const bdlb::NullableValue& UriAuthority::user() const { return d_user; @@ -446,10 +462,16 @@ const bdlb::NullableValue& UriAuthority::port() const return d_port; } +const bdlb::NullableValue& +UriAuthority::transport() const +{ + return d_transport; +} + bool UriAuthority::equals(const UriAuthority& other) const { return d_user == other.d_user && d_host == other.d_host && - d_port == other.d_port; + d_port == other.d_port && d_transport == other.d_transport; } bool UriAuthority::less(const UriAuthority& other) const @@ -458,7 +480,7 @@ bool UriAuthority::less(const UriAuthority& other) const return true; } - if (other.d_user < other.d_user) { + if (other.d_user < d_user) { return false; } @@ -466,11 +488,19 @@ bool UriAuthority::less(const UriAuthority& other) const return true; } - if (other.d_host < other.d_host) { + if (other.d_host < d_host) { return false; } - return d_port < other.d_port; + if (d_port < other.d_port) { + return true; + } + + if (other.d_port < d_port) { + return false; + } + + return d_transport < other.d_transport; } bsl::ostream& UriAuthority::print(bsl::ostream& stream, @@ -492,6 +522,10 @@ bsl::ostream& UriAuthority::print(bsl::ostream& stream, printer.printAttribute("port", d_port); } + if (!d_transport.isNull()) { + printer.printAttribute("transport", d_transport); + } + printer.end(); return stream; } @@ -1007,6 +1041,26 @@ ntsa::Error Uri::setPort(ntsa::Port value) return ntsa::Error(); } +ntsa::Error Uri::setTransport(ntsa::Transport::Value value) +{ + ntsa::Error error; + + if (d_authority.isNull()) { + error = d_authority.makeValue().setTransport(value); + if (error) { + return error; + } + } + else { + error = d_authority.value().setTransport(value); + if (error) { + return error; + } + } + + return ntsa::Error(); +} + ntsa::Error Uri::setPath(const bslstl::StringRef& value) { if (value.empty()) { diff --git a/groups/nts/ntsa/ntsa_uri.h b/groups/nts/ntsa/ntsa_uri.h index 24f22f2ef..c554e462b 100644 --- a/groups/nts/ntsa/ntsa_uri.h +++ b/groups/nts/ntsa/ntsa_uri.h @@ -25,6 +25,7 @@ BSLS_IDENT("$Id: $") #include #include #include +#include #include #include #include @@ -49,9 +50,10 @@ namespace ntsa { /// @ingroup module_ntsa_identity class UriAuthority { - bdlb::NullableValue d_user; - bdlb::NullableValue d_host; - bdlb::NullableValue d_port; + bdlb::NullableValue d_user; + bdlb::NullableValue d_host; + bdlb::NullableValue d_port; + bdlb::NullableValue d_transport; public: /// Create a new URI authority. Optionally specify an 'basicAllocator' @@ -104,6 +106,9 @@ class UriAuthority /// Set the port specified in the authority portion of the URI. ntsa::Error setPort(ntsa::Port value); + /// Set the transport specified in the authority portion of the URI. + ntsa::Error setTransport(ntsa::Transport::Value value); + /// Return the user specified in the authority portion of the URI. const bdlb::NullableValue& user() const; @@ -113,6 +118,9 @@ class UriAuthority /// Return the port specified in the authority portion of the URI. const bdlb::NullableValue& port() const; + /// Return the transport specified in the authority portion of the URI. + const bdlb::NullableValue& transport() const; + /// Return true if this object has the same value as the specified /// 'other' object, otherwise return false. bool equals(const UriAuthority& other) const; @@ -478,10 +486,14 @@ class Uri /// specified 'value'. Return the error. ntsa::Error setHost(const ntsa::Ipv6Address& value); - /// Set the port specified in the authority portion of the URI. Return - /// the error. + /// Set the port specified in the authority portion of the URI to the + /// specified 'value'. Return the error. ntsa::Error setPort(ntsa::Port value); + /// Set the transport specified in the authority portion of the URI to the + /// specified 'value'. Return the error. + ntsa::Error setTransport(ntsa::Transport::Value value); + /// Set the path to the resource to the specified 'value'. Return the /// error. ntsa::Error setPath(const bslstl::StringRef& value); @@ -606,6 +618,7 @@ void hashAppend(HASH_ALGORITHM& algorithm, const UriAuthority& value) hashAppend(algorithm, value.user()); hashAppend(algorithm, value.host()); hashAppend(algorithm, value.port()); + hashAppend(algorithm, value.transport()); } template