mirror of
https://github.com/google/nomulus
synced 2026-05-13 03:11:49 +00:00
Use remote caches in RDAP queries (#3034)
Note that this primarily affects domain lookups. We choose to use the remote cache for hosts based on repo ID (not host name), so the remote caches are not particularly useful for host lookups. We chose this because the number of domain queries is orders of magnitude higher than the number of host queries.
This commit is contained in:
@@ -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<Boolean> 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.
|
||||
* <p>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(
|
||||
|
||||
@@ -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> 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
|
||||
|
||||
@@ -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> 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(
|
||||
|
||||
@@ -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<VKey<? extends EppResource>> nameservers =
|
||||
ImmutableSet.copyOf(domain.getNameservers());
|
||||
ImmutableSet<Host> loadedHosts =
|
||||
replicaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
ImmutableSet.Builder<Host> 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
|
||||
|
||||
@@ -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> domain =
|
||||
ForeignKeyUtils.loadResourceByCache(
|
||||
Domain.class, partialStringQuery.getSuffix(), getRequestTime());
|
||||
Optional<Domain> 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,
|
||||
|
||||
@@ -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<A extends RdapActionBase> {
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user