From a35689ecf4cf190c766d688053a14bcf31c6699a Mon Sep 17 00:00:00 2001 From: Matt Millett Date: Tue, 27 Aug 2024 14:02:11 -0400 Subject: [PATCH] Allow setting URI host and port by ntsa::Endpoint --- groups/nts/ntsa/ntsa_host.h | 20 +++++ groups/nts/ntsa/ntsa_uri.cpp | 89 +++++++++++++++++++--- groups/nts/ntsa/ntsa_uri.h | 24 ++++-- groups/nts/ntsa/ntsa_uri.t.cpp | 131 +++++++++++++++++++++++++++++++++ 4 files changed, 247 insertions(+), 17 deletions(-) diff --git a/groups/nts/ntsa/ntsa_host.h b/groups/nts/ntsa/ntsa_host.h index a5910eaf..1177803d 100644 --- a/groups/nts/ntsa/ntsa_host.h +++ b/groups/nts/ntsa/ntsa_host.h @@ -300,6 +300,13 @@ ntsa::IpAddress& Host::ip() return d_ip.object(); } +NTSCFG_INLINE +ntsa::LocalName& Host::localName() +{ + BSLS_ASSERT(d_type == ntsa::HostType::e_LOCAL_NAME); + return d_localName.object(); +} + NTSCFG_INLINE const ntsa::DomainName& Host::domainName() const { @@ -314,6 +321,13 @@ const ntsa::IpAddress& Host::ip() const return d_ip.object(); } +NTSCFG_INLINE +const ntsa::LocalName& Host::localName() const +{ + BSLS_ASSERT(d_type == ntsa::HostType::e_LOCAL_NAME); + return d_localName.object(); +} + NTSCFG_INLINE ntsa::HostType::Value Host::type() const { @@ -338,6 +352,12 @@ bool Host::isIp() const return (d_type == ntsa::HostType::e_IP); } +NTSCFG_INLINE +bool Host::isLocalName() const +{ + return (d_type == ntsa::HostType::e_LOCAL_NAME); +} + NTSCFG_INLINE bsl::ostream& operator<<(bsl::ostream& stream, const Host& object) { diff --git a/groups/nts/ntsa/ntsa_uri.cpp b/groups/nts/ntsa/ntsa_uri.cpp index 7424bc4d..186d2d17 100644 --- a/groups/nts/ntsa/ntsa_uri.cpp +++ b/groups/nts/ntsa/ntsa_uri.cpp @@ -435,6 +435,40 @@ ntsa::Error UriAuthority::setPort(ntsa::Port value) return ntsa::Error(); } +ntsa::Error UriAuthority::setEndpoint(const ntsa::Endpoint& endpoint) +{ + if (endpoint.isIp()) { + if (d_host.isNull()) { + d_host.makeValue().makeIp(endpoint.ip().host()); + } + else { + d_host.value().makeIp(endpoint.ip().host()); + } + + if (d_port.isNull()) { + d_port.makeValue(endpoint.ip().port()); + } + else { + d_port.value() = endpoint.ip().port(); + } + } + else if (endpoint.isLocal()) { + if (d_host.isNull()) { + d_host.makeValue().makeLocalName(endpoint.local()); + } + else { + d_host.value().makeLocalName(endpoint.local()); + } + + d_port.reset(); + } + else { + return ntsa::Error(ntsa::Error::e_INVALID); + } + + return ntsa::Error(); +} + ntsa::Error UriAuthority::setTransport(ntsa::Transport::Value value) { if (d_transport.isNull()) { @@ -1041,6 +1075,26 @@ ntsa::Error Uri::setPort(ntsa::Port value) return ntsa::Error(); } +ntsa::Error Uri::setEndpoint(const ntsa::Endpoint& value) +{ + ntsa::Error error; + + if (d_authority.isNull()) { + error = d_authority.makeValue().setEndpoint(value); + if (error) { + return error; + } + } + else { + error = d_authority.value().setEndpoint(value); + if (error) { + return error; + } + } + + return ntsa::Error(); +} + ntsa::Error Uri::setTransport(ntsa::Transport::Value value) { ntsa::Error error; @@ -1496,21 +1550,36 @@ bsl::ostream& Uri::print(bsl::ostream& stream, } if (!d_authority.value().user().isNull()) { - if (d_authority.value().user().value().empty()) { - return stream; - } + if (!d_authority.value().user().value().empty()) { + bsl::string user; + error = encodeUrl(&user, d_authority.value().user().value()); + if (error) { + return stream; + } - bsl::string user; - error = encodeUrl(&user, d_authority.value().user().value()); - if (error) { - return stream; + stream << user << '@'; } - - stream << user << '@'; } if (!d_authority.value().host().isNull()) { - stream << d_authority.value().host().value(); + if (d_authority.value().host().value().isDomainName()) { + stream << d_authority.value().host().value().domainName(); + } + else if (d_authority.value().host().value().isIp()) { + if (d_authority.value().host().value().ip().isV4()) { + stream << d_authority.value().host().value().ip().v4(); + } + else if (d_authority.value().host().value().ip().isV6()) { + stream << '[' + << d_authority.value().host().value().ip().v6() + << ']'; + } + } + else if (d_authority.value().host().value().isLocalName()) { + stream << '@' + << d_authority.value().host().value().localName() + << '@'; + } } if (!d_authority.value().port().isNull()) { diff --git a/groups/nts/ntsa/ntsa_uri.h b/groups/nts/ntsa/ntsa_uri.h index c554e462..cbf91c1f 100644 --- a/groups/nts/ntsa/ntsa_uri.h +++ b/groups/nts/ntsa/ntsa_uri.h @@ -84,29 +84,35 @@ class UriAuthority ntsa::Error setUser(const bslstl::StringRef& value); /// Set the host specified in the authority portion of the URI to the - /// // specified 'value'. Return the error. + /// specified 'value'. Return the error. ntsa::Error setHost(const ntsa::Host& value); /// Set the host specified in the authority portion of the URI to the - /// // specified 'value'. Return the error. + /// specified 'value'. Return the error. ntsa::Error setHost(const bslstl::StringRef& value); /// Set the host specified in the authority portion of the URI to the - /// // specified 'value'. Return the error. + /// specified 'value'. Return the error. ntsa::Error setHost(const ntsa::IpAddress& value); /// Set the host specified in the authority portion of the URI to the - /// // specified 'value'. Return the error. + /// specified 'value'. Return the error. ntsa::Error setHost(const ntsa::Ipv4Address& value); /// Set the host specified in the authority portion of the URI to the - /// // specified 'value'. Return the error. + /// specified 'value'. Return the error. ntsa::Error setHost(const ntsa::Ipv6Address& value); - /// Set the port specified in the authority portion of the URI. + /// 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. + /// Set the host and port in the authority portion of the URI to the + /// specified 'value'. Return the error. + ntsa::Error setEndpoint(const ntsa::Endpoint& 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); /// Return the user specified in the authority portion of the URI. @@ -490,6 +496,10 @@ class Uri /// specified 'value'. Return the error. ntsa::Error setPort(ntsa::Port value); + /// Set the host and port in the authority portion of the URI to the + /// specified 'value'. Return the error. + ntsa::Error setEndpoint(const ntsa::Endpoint& 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); diff --git a/groups/nts/ntsa/ntsa_uri.t.cpp b/groups/nts/ntsa/ntsa_uri.t.cpp index a84ea87e..258839d6 100644 --- a/groups/nts/ntsa/ntsa_uri.t.cpp +++ b/groups/nts/ntsa/ntsa_uri.t.cpp @@ -677,9 +677,140 @@ NTSCFG_TEST_CASE(2) NTSCFG_TEST_ASSERT(ta.numBlocksInUse() == 0); } +NTSCFG_TEST_CASE(3) +{ + ntscfg::TestAllocator ta; + { + ntsa::Error error; + + { + ntsa::Endpoint endpoint( + ntsa::IpEndpoint(ntsa::Ipv4Address::loopback(), 80)); + + ntsa::Uri uri(&ta); + + error = uri.setEndpoint(endpoint); + NTSCFG_TEST_OK(error); + + error = uri.setPath("path/to/resource"); + NTSCFG_TEST_OK(error); + + if (NTSCFG_TEST_VERBOSITY) { + bsl::cout << "URI: " << uri.text() + << " (endpoint: " << endpoint << ")" << bsl::endl; + } + } + + { + ntsa::Endpoint endpoint( + ntsa::IpEndpoint(ntsa::Ipv4Address::loopback(), 80)); + + ntsa::Uri uri(&ta); + + error = uri.setScheme("http"); + NTSCFG_TEST_OK(error); + + error = uri.setEndpoint(endpoint); + NTSCFG_TEST_OK(error); + + error = uri.setPath("path/to/resource"); + NTSCFG_TEST_OK(error); + + if (NTSCFG_TEST_VERBOSITY) { + bsl::cout << "URI: " << uri.text() + << " (endpoint: " << endpoint << ")" << bsl::endl; + } + } + + { + ntsa::Endpoint endpoint( + ntsa::IpEndpoint(ntsa::Ipv6Address::loopback(), 80)); + + ntsa::Uri uri(&ta); + + error = uri.setEndpoint(endpoint); + NTSCFG_TEST_OK(error); + + error = uri.setPath("path/to/resource"); + NTSCFG_TEST_OK(error); + + if (NTSCFG_TEST_VERBOSITY) { + bsl::cout << "URI: " << uri.text() + << " (endpoint: " << endpoint << ")" << bsl::endl; + } + } + + { + ntsa::Endpoint endpoint( + ntsa::IpEndpoint(ntsa::Ipv6Address::loopback(), 80)); + + ntsa::Uri uri(&ta); + + error = uri.setScheme("http"); + NTSCFG_TEST_OK(error); + + error = uri.setEndpoint(endpoint); + NTSCFG_TEST_OK(error); + + error = uri.setPath("path/to/resource"); + NTSCFG_TEST_OK(error); + + if (NTSCFG_TEST_VERBOSITY) { + bsl::cout << "URI: " << uri.text() + << " (endpoint: " << endpoint << ")" << bsl::endl; + } + } + + { + ntsa::LocalName localName; + localName.setValue("/tmp/ntf/socket"); + + ntsa::Endpoint endpoint(localName); + + ntsa::Uri uri(&ta); + + error = uri.setEndpoint(endpoint); + NTSCFG_TEST_OK(error); + + error = uri.setPath("path/to/resource"); + NTSCFG_TEST_OK(error); + + if (NTSCFG_TEST_VERBOSITY) { + bsl::cout << "URI: " << uri.text() + << " (endpoint: " << endpoint << ")" << bsl::endl; + } + } + + { + ntsa::LocalName localName; + localName.setValue("/tmp/ntf/socket"); + + ntsa::Endpoint endpoint(localName); + + ntsa::Uri uri(&ta); + + error = uri.setScheme("http"); + NTSCFG_TEST_OK(error); + + error = uri.setEndpoint(endpoint); + NTSCFG_TEST_OK(error); + + error = uri.setPath("path/to/resource"); + NTSCFG_TEST_OK(error); + + if (NTSCFG_TEST_VERBOSITY) { + bsl::cout << "URI: " << uri.text() + << " (endpoint: " << endpoint << ")" << bsl::endl; + } + } + } + NTSCFG_TEST_ASSERT(ta.numBlocksInUse() == 0); +} + NTSCFG_TEST_DRIVER { NTSCFG_TEST_REGISTER(1); NTSCFG_TEST_REGISTER(2); + NTSCFG_TEST_REGISTER(3); } NTSCFG_TEST_DRIVER_END;