diff --git a/core/src/main/java/google/registry/rdap/RdapActionBase.java b/core/src/main/java/google/registry/rdap/RdapActionBase.java index f3cee274a..7caa079e9 100644 --- a/core/src/main/java/google/registry/rdap/RdapActionBase.java +++ b/core/src/main/java/google/registry/rdap/RdapActionBase.java @@ -32,6 +32,7 @@ import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import google.registry.cache.DomainCache; import google.registry.config.RegistryConfig.Config; import google.registry.model.EppResource; import google.registry.model.registrar.Registrar; @@ -88,6 +89,7 @@ public abstract class RdapActionBase implements Runnable { @Inject @Parameter("formatOutput") Optional formatOutputParam; @Inject @Config("rdapResultSetMaxSize") int rdapResultSetMaxSize; @Inject RdapMetrics rdapMetrics; + @Inject DomainCache domainCache; @Inject Clock clock; /** Builder for metric recording. */ @@ -117,14 +119,14 @@ public abstract class RdapActionBase implements Runnable { /** * Does the actual search and returns an RDAP JSON object. * - * RFC7480 4.1 - we have to support GET and HEAD. + *

RFC7480 4.1 - we have to support GET and HEAD. * * @param pathSearchString the search string in the URL path * @param isHeadRequest whether the returned map will actually be used. HTTP HEAD requests don't - * actually return anything. However, we usually still want to go through the process of - * building a map, to make sure that the request would return a 500 status if it were - * invoked using GET. So this field should usually be ignored, unless there's some - * expensive task required to create the map which will never result in a request failure. + * actually return anything. However, we usually still want to go through the process of + * building a map, to make sure that the request would return a 500 status if it were invoked + * using GET. So this field should usually be ignored, unless there's some expensive task + * required to create the map which will never result in a request failure. * @return A map (probably containing nested maps and lists) with the final JSON response data. */ abstract ReplyPayloadBase getJsonObjectForResource( diff --git a/core/src/main/java/google/registry/rdap/RdapDomainAction.java b/core/src/main/java/google/registry/rdap/RdapDomainAction.java index c5b6d7cb0..e47bf7c2c 100644 --- a/core/src/main/java/google/registry/rdap/RdapDomainAction.java +++ b/core/src/main/java/google/registry/rdap/RdapDomainAction.java @@ -67,10 +67,9 @@ public class RdapDomainAction extends RdapActionBase { } // The query string is not used; the RDAP syntax is /rdap/domain/mydomain.com. Optional domain = - ForeignKeyUtils.loadResourceByCache( - Domain.class, - pathSearchString, - shouldIncludeDeleted() ? START_INSTANT : getRequestTime()); + shouldIncludeDeleted() // the remote domain cache cannot handle times in the past + ? ForeignKeyUtils.loadResourceByCache(Domain.class, pathSearchString, START_INSTANT) + : domainCache.loadByDomainName(pathSearchString); if (domain.isEmpty() || !isAuthorized(domain.get())) { handlePossibleBsaBlock(domainName); // RFC7480 5.3 - if the server wishes to respond that it doesn't have data satisfying the diff --git a/core/src/main/java/google/registry/rdap/RdapDomainSearchAction.java b/core/src/main/java/google/registry/rdap/RdapDomainSearchAction.java index f79878f29..b56df0faa 100644 --- a/core/src/main/java/google/registry/rdap/RdapDomainSearchAction.java +++ b/core/src/main/java/google/registry/rdap/RdapDomainSearchAction.java @@ -181,11 +181,10 @@ public class RdapDomainSearchAction extends RdapSearchActionBase { /** Searches for domains by domain name without a wildcard or interest in deleted entries. */ private DomainSearchResponse searchByDomainNameWithoutWildcard( final RdapSearchPattern partialStringQuery) { - Optional domain = - ForeignKeyUtils.loadResourceByCache( - Domain.class, partialStringQuery.getInitialString(), getRequestTime()); return makeSearchResults( - shouldBeVisible(domain) ? ImmutableList.of(domain.get()) : ImmutableList.of()); + domainCache.loadByDomainName(partialStringQuery.getInitialString()).stream() + .filter(this::shouldBeVisible) + .toList()); } /** Searches for domains by domain name with an initial string, wildcard and possible suffix. */ @@ -359,8 +358,8 @@ public class RdapDomainSearchAction extends RdapSearchActionBase { // through the subordinate hosts. This is more efficient, and lets us permit wildcard searches // with no initial string. Domain domain = - ForeignKeyUtils.loadResourceByCache( - Domain.class, partialStringQuery.getSuffix(), timeToQuery) + domainCache + .loadByDomainName(partialStringQuery.getSuffix()) .orElseThrow( () -> new UnprocessableEntityException( diff --git a/core/src/main/java/google/registry/rdap/RdapJsonFormatter.java b/core/src/main/java/google/registry/rdap/RdapJsonFormatter.java index 2014924d0..830b221e9 100644 --- a/core/src/main/java/google/registry/rdap/RdapJsonFormatter.java +++ b/core/src/main/java/google/registry/rdap/RdapJsonFormatter.java @@ -32,6 +32,7 @@ import com.google.common.collect.Streams; import com.google.common.flogger.FluentLogger; import com.google.common.net.InetAddresses; import com.google.gson.JsonArray; +import google.registry.cache.HostCache; import google.registry.config.RegistryConfig; import google.registry.config.RegistryConfig.Config; import google.registry.model.CacheUtils; @@ -122,6 +123,7 @@ public class RdapJsonFormatter { @Inject @RequestServerName String serverName; @Inject RdapAuthorization rdapAuthorization; @Inject Clock clock; + @Inject HostCache hostCache; @Inject RdapJsonFormatter() {} @@ -393,20 +395,11 @@ public class RdapJsonFormatter { domain.getDomainName(), domain.getRepoId()); } - // We're just trying to load the hosts by cache here, but the generics and casting require - // a lot of boilerplate to make the compiler happy - Iterable> nameservers = - ImmutableSet.copyOf(domain.getNameservers()); ImmutableSet loadedHosts = - replicaTm() - .transact( - () -> { - ImmutableSet.Builder hostBuilder = new ImmutableSet.Builder<>(); - for (EppResource host : EppResource.loadByCacheIfEnabled(nameservers).values()) { - hostBuilder.add((Host) host); - } - return hostBuilder.build(); - }); + domain.getNameservers().stream() + .map(key -> hostCache.loadByRepoId((String) key.getKey())) + .flatMap(Optional::stream) + .collect(toImmutableSet()); // Add the nameservers to the data; the load was kicked off above for efficiency. // RDAP Response Profile 2.8: we MUST have the nameservers diff --git a/core/src/main/java/google/registry/rdap/RdapNameserverSearchAction.java b/core/src/main/java/google/registry/rdap/RdapNameserverSearchAction.java index 6aaed9346..5a1510776 100644 --- a/core/src/main/java/google/registry/rdap/RdapNameserverSearchAction.java +++ b/core/src/main/java/google/registry/rdap/RdapNameserverSearchAction.java @@ -175,9 +175,7 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase { /** Searches for nameservers by name using the superordinate domain as a suffix. */ private NameserverSearchResponse searchByNameUsingSuperordinateDomain( RdapSearchPattern partialStringQuery) { - Optional domain = - ForeignKeyUtils.loadResourceByCache( - Domain.class, partialStringQuery.getSuffix(), getRequestTime()); + Optional domain = domainCache.loadByDomainName(partialStringQuery.getSuffix()); if (domain.isEmpty()) { // Don't allow wildcards with suffixes which are not domains we manage. That would risk a // table scan in many easily foreseeable cases. The user might ask for ns*.zombo.com, diff --git a/core/src/test/java/google/registry/rdap/RdapActionBaseTestCase.java b/core/src/test/java/google/registry/rdap/RdapActionBaseTestCase.java index 062badbd3..9bf04675f 100644 --- a/core/src/test/java/google/registry/rdap/RdapActionBaseTestCase.java +++ b/core/src/test/java/google/registry/rdap/RdapActionBaseTestCase.java @@ -28,8 +28,10 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import google.registry.model.ForeignKeyUtils; import google.registry.model.console.User; import google.registry.model.console.UserRoles; +import google.registry.model.domain.Domain; import google.registry.persistence.transaction.JpaTestExtensions; import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension; import google.registry.request.Actions; @@ -92,6 +94,8 @@ abstract class RdapActionBaseTestCase { action.rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter(clock); action.rdapMetrics = rdapMetrics; action.requestMethod = GET; + action.domainCache = + (domainName) -> ForeignKeyUtils.loadResourceByCache(Domain.class, domainName, clock.now()); action.clock = new FakeClock(DateTime.parse("2025-01-01T00:00:00.000Z")); logout(); } diff --git a/core/src/test/java/google/registry/rdap/RdapTestHelper.java b/core/src/test/java/google/registry/rdap/RdapTestHelper.java index 1448d2e23..ec691b12b 100644 --- a/core/src/test/java/google/registry/rdap/RdapTestHelper.java +++ b/core/src/test/java/google/registry/rdap/RdapTestHelper.java @@ -27,8 +27,12 @@ import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import google.registry.model.EppResource; +import google.registry.model.host.Host; +import google.registry.persistence.VKey; import google.registry.util.Clock; import java.util.Map; +import java.util.Optional; /** Test helper methods for RDAP tests. */ class RdapTestHelper { @@ -68,6 +72,8 @@ class RdapTestHelper { + " suspect that you have failed to comply with these terms.", "We reserve the right to modify this agreement at any time."); rdapJsonFormatter.rdapTosStaticUrl = "https://www.example.tld/about/rdap/tos.html"; + rdapJsonFormatter.hostCache = + (repoId) -> Optional.ofNullable(EppResource.loadByCache(VKey.create(Host.class, repoId))); return rdapJsonFormatter; }