mirror of
https://github.com/google/nomulus.git
synced 2025-05-14 00:17:20 +02:00
Save the RDAP request time globally instead of passing it around
Also removed the rdapWhoisServer value, as it's just null and will likely stay that way (it isn't mentioned in the RDAP response profile) If it'll ever become required, we can add it back. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=247643981
This commit is contained in:
parent
b10f880b7f
commit
a0040c5eda
15 changed files with 197 additions and 320 deletions
|
@ -969,20 +969,6 @@ public final class RegistryConfig {
|
||||||
return 100;
|
return 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* WHOIS server displayed in RDAP query responses. As per Gustavo Lozano of ICANN, this should
|
|
||||||
* be omitted, but the ICANN operational profile doesn't actually say that, so it's good to have
|
|
||||||
* the ability to reinstate this field if necessary.
|
|
||||||
*
|
|
||||||
* @see google.registry.rdap.RdapActionBase
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
@Provides
|
|
||||||
@Config("rdapWhoisServer")
|
|
||||||
public static String provideRdapWhoisServer() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Redaction text for email address in WHOIS
|
* Redaction text for email address in WHOIS
|
||||||
*
|
*
|
||||||
|
|
|
@ -49,13 +49,11 @@ import google.registry.request.Parameter;
|
||||||
import google.registry.request.RequestMethod;
|
import google.registry.request.RequestMethod;
|
||||||
import google.registry.request.RequestPath;
|
import google.registry.request.RequestPath;
|
||||||
import google.registry.request.Response;
|
import google.registry.request.Response;
|
||||||
import google.registry.util.Clock;
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
|
|
||||||
|
@ -86,7 +84,6 @@ public abstract class RdapActionBase implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject Response response;
|
@Inject Response response;
|
||||||
@Inject Clock clock;
|
|
||||||
@Inject @RequestMethod Action.Method requestMethod;
|
@Inject @RequestMethod Action.Method requestMethod;
|
||||||
@Inject @RequestPath String requestPath;
|
@Inject @RequestPath String requestPath;
|
||||||
@Inject RdapAuthorization rdapAuthorization;
|
@Inject RdapAuthorization rdapAuthorization;
|
||||||
|
@ -94,7 +91,6 @@ public abstract class RdapActionBase implements Runnable {
|
||||||
@Inject @Parameter("registrar") Optional<String> registrarParam;
|
@Inject @Parameter("registrar") Optional<String> registrarParam;
|
||||||
@Inject @Parameter("includeDeleted") Optional<Boolean> includeDeletedParam;
|
@Inject @Parameter("includeDeleted") Optional<Boolean> includeDeletedParam;
|
||||||
@Inject @Parameter("formatOutput") Optional<Boolean> formatOutputParam;
|
@Inject @Parameter("formatOutput") Optional<Boolean> formatOutputParam;
|
||||||
@Inject @Config("rdapWhoisServer") @Nullable String rdapWhoisServer;
|
|
||||||
@Inject @Config("rdapResultSetMaxSize") int rdapResultSetMaxSize;
|
@Inject @Config("rdapResultSetMaxSize") int rdapResultSetMaxSize;
|
||||||
@Inject RdapMetrics rdapMetrics;
|
@Inject RdapMetrics rdapMetrics;
|
||||||
|
|
||||||
|
@ -242,8 +238,8 @@ public abstract class RdapActionBase implements Runnable {
|
||||||
* <p>This is true if the resource is not deleted, or the request wants to see deleted items, and
|
* <p>This is true if the resource is not deleted, or the request wants to see deleted items, and
|
||||||
* is authorized to do so.
|
* is authorized to do so.
|
||||||
*/
|
*/
|
||||||
boolean isAuthorized(EppResource eppResource, DateTime now) {
|
boolean isAuthorized(EppResource eppResource) {
|
||||||
return now.isBefore(eppResource.getDeletionTime())
|
return getRequestTime().isBefore(eppResource.getDeletionTime())
|
||||||
|| (shouldIncludeDeleted()
|
|| (shouldIncludeDeleted()
|
||||||
&& rdapAuthorization
|
&& rdapAuthorization
|
||||||
.isAuthorizedForClientId(eppResource.getPersistedCurrentSponsorClientId()));
|
.isAuthorizedForClientId(eppResource.getPersistedCurrentSponsorClientId()));
|
||||||
|
@ -257,8 +253,8 @@ public abstract class RdapActionBase implements Runnable {
|
||||||
* do so, and:
|
* do so, and:
|
||||||
* 2. The request did not specify a registrar to filter on, or the registrar matches.
|
* 2. The request did not specify a registrar to filter on, or the registrar matches.
|
||||||
*/
|
*/
|
||||||
boolean shouldBeVisible(EppResource eppResource, DateTime now) {
|
boolean shouldBeVisible(EppResource eppResource) {
|
||||||
return isAuthorized(eppResource, now)
|
return isAuthorized(eppResource)
|
||||||
&& (!registrarParam.isPresent()
|
&& (!registrarParam.isPresent()
|
||||||
|| registrarParam.get().equals(eppResource.getPersistedCurrentSponsorClientId()));
|
|| registrarParam.get().equals(eppResource.getPersistedCurrentSponsorClientId()));
|
||||||
}
|
}
|
||||||
|
@ -271,8 +267,8 @@ public abstract class RdapActionBase implements Runnable {
|
||||||
* forward in time to empty),
|
* forward in time to empty),
|
||||||
* 2. The request did not specify a registrar to filter on, or the registrar matches.
|
* 2. The request did not specify a registrar to filter on, or the registrar matches.
|
||||||
*/
|
*/
|
||||||
boolean shouldBeVisible(Optional<? extends EppResource> eppResource, DateTime now) {
|
boolean shouldBeVisible(Optional<? extends EppResource> eppResource) {
|
||||||
return eppResource.isPresent() && shouldBeVisible(eppResource.get(), now);
|
return eppResource.isPresent() && shouldBeVisible(eppResource.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -468,7 +464,6 @@ public abstract class RdapActionBase implements Runnable {
|
||||||
*
|
*
|
||||||
* @param query an already-defined query to be run; a filter on currentSponsorClientId will be
|
* @param query an already-defined query to be run; a filter on currentSponsorClientId will be
|
||||||
* added if appropriate
|
* added if appropriate
|
||||||
* @param now the time as of which to evaluate the query
|
|
||||||
* @param checkForVisibility true if the results should be checked to make sure they are visible;
|
* @param checkForVisibility true if the results should be checked to make sure they are visible;
|
||||||
* normally this should be equal to the shouldIncludeDeleted setting, but in cases where
|
* normally this should be equal to the shouldIncludeDeleted setting, but in cases where
|
||||||
* the query could not check deletion status (due to Datastore limitations such as the
|
* the query could not check deletion status (due to Datastore limitations such as the
|
||||||
|
@ -483,7 +478,7 @@ public abstract class RdapActionBase implements Runnable {
|
||||||
* query is greater than or equal to the maximum number we might have expected
|
* query is greater than or equal to the maximum number we might have expected
|
||||||
*/
|
*/
|
||||||
<T extends EppResource> RdapResultSet<T> getMatchingResources(
|
<T extends EppResource> RdapResultSet<T> getMatchingResources(
|
||||||
Query<T> query, boolean checkForVisibility, DateTime now, int querySizeLimit) {
|
Query<T> query, boolean checkForVisibility, int querySizeLimit) {
|
||||||
Optional<String> desiredRegistrar = getDesiredRegistrar();
|
Optional<String> desiredRegistrar = getDesiredRegistrar();
|
||||||
if (desiredRegistrar.isPresent()) {
|
if (desiredRegistrar.isPresent()) {
|
||||||
query = query.filter("currentSponsorClientId", desiredRegistrar.get());
|
query = query.filter("currentSponsorClientId", desiredRegistrar.get());
|
||||||
|
@ -496,7 +491,7 @@ public abstract class RdapActionBase implements Runnable {
|
||||||
int numResourcesQueried = 0;
|
int numResourcesQueried = 0;
|
||||||
boolean someExcluded = false;
|
boolean someExcluded = false;
|
||||||
for (T resource : query) {
|
for (T resource : query) {
|
||||||
if (shouldBeVisible(resource, now)) {
|
if (shouldBeVisible(resource)) {
|
||||||
resources.add(resource);
|
resources.add(resource);
|
||||||
} else {
|
} else {
|
||||||
someExcluded = true;
|
someExcluded = true;
|
||||||
|
@ -542,4 +537,9 @@ public abstract class RdapActionBase implements Runnable {
|
||||||
metricInformationBuilder.setPrefixLength(partialStringQuery.getInitialString().length());
|
metricInformationBuilder.setPrefixLength(partialStringQuery.getInitialString().length());
|
||||||
return partialStringQuery;
|
return partialStringQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns the DateTime this request took place. */
|
||||||
|
DateTime getRequestTime() {
|
||||||
|
return rdapJsonFormatter.getRequestTime();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,6 @@ import google.registry.request.HttpException.NotFoundException;
|
||||||
import google.registry.request.auth.Auth;
|
import google.registry.request.auth.Auth;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import org.joda.time.DateTime;
|
|
||||||
|
|
||||||
/** RDAP (new WHOIS) action for domain requests. */
|
/** RDAP (new WHOIS) action for domain requests. */
|
||||||
@Action(
|
@Action(
|
||||||
|
@ -48,7 +47,6 @@ public class RdapDomainAction extends RdapActionBase {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RdapDomain getJsonObjectForResource(String pathSearchString, boolean isHeadRequest) {
|
public RdapDomain getJsonObjectForResource(String pathSearchString, boolean isHeadRequest) {
|
||||||
DateTime now = clock.nowUtc();
|
|
||||||
pathSearchString = canonicalizeName(pathSearchString);
|
pathSearchString = canonicalizeName(pathSearchString);
|
||||||
try {
|
try {
|
||||||
validateDomainName(pathSearchString);
|
validateDomainName(pathSearchString);
|
||||||
|
@ -61,14 +59,14 @@ public class RdapDomainAction extends RdapActionBase {
|
||||||
// The query string is not used; the RDAP syntax is /rdap/domain/mydomain.com.
|
// The query string is not used; the RDAP syntax is /rdap/domain/mydomain.com.
|
||||||
Optional<DomainBase> domainBase =
|
Optional<DomainBase> domainBase =
|
||||||
loadByForeignKey(
|
loadByForeignKey(
|
||||||
DomainBase.class, pathSearchString, shouldIncludeDeleted() ? START_OF_TIME : now);
|
DomainBase.class,
|
||||||
if (!shouldBeVisible(domainBase, now)) {
|
pathSearchString,
|
||||||
|
shouldIncludeDeleted() ? START_OF_TIME : rdapJsonFormatter.getRequestTime());
|
||||||
|
if (!shouldBeVisible(domainBase)) {
|
||||||
throw new NotFoundException(pathSearchString + " not found");
|
throw new NotFoundException(pathSearchString + " not found");
|
||||||
}
|
}
|
||||||
return rdapJsonFormatter.makeRdapJsonForDomain(
|
return rdapJsonFormatter.makeRdapJsonForDomain(
|
||||||
domainBase.get(),
|
domainBase.get(),
|
||||||
rdapWhoisServer,
|
|
||||||
now,
|
|
||||||
OutputDataType.FULL);
|
OutputDataType.FULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,6 @@ import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import org.joda.time.DateTime;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RDAP (new WHOIS) action for domain search requests.
|
* RDAP (new WHOIS) action for domain search requests.
|
||||||
|
@ -93,7 +92,6 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
||||||
@Override
|
@Override
|
||||||
public DomainSearchResponse getJsonObjectForResource(
|
public DomainSearchResponse getJsonObjectForResource(
|
||||||
String pathSearchString, boolean isHeadRequest) {
|
String pathSearchString, boolean isHeadRequest) {
|
||||||
DateTime now = clock.nowUtc();
|
|
||||||
// RDAP syntax example: /rdap/domains?name=exam*.com.
|
// RDAP syntax example: /rdap/domains?name=exam*.com.
|
||||||
// The pathSearchString is not used by search commands.
|
// The pathSearchString is not used by search commands.
|
||||||
if (pathSearchString.length() > 0) {
|
if (pathSearchString.length() > 0) {
|
||||||
|
@ -115,8 +113,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new BadRequestException("Invalid value of nsLdhName parameter");
|
throw new BadRequestException("Invalid value of nsLdhName parameter");
|
||||||
}
|
}
|
||||||
results = searchByDomainName(
|
results = searchByDomainName(recordWildcardType(RdapSearchPattern.create(asciiName, true)));
|
||||||
recordWildcardType(RdapSearchPattern.create(asciiName, true)), now);
|
|
||||||
} else if (nsLdhNameParam.isPresent()) {
|
} else if (nsLdhNameParam.isPresent()) {
|
||||||
metricInformationBuilder.setSearchType(SearchType.BY_NAMESERVER_NAME);
|
metricInformationBuilder.setSearchType(SearchType.BY_NAMESERVER_NAME);
|
||||||
// syntax: /rdap/domains?nsLdhName=ns1.exam*.com
|
// syntax: /rdap/domains?nsLdhName=ns1.exam*.com
|
||||||
|
@ -126,7 +123,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
||||||
throw new BadRequestException("Invalid value of nsLdhName parameter");
|
throw new BadRequestException("Invalid value of nsLdhName parameter");
|
||||||
}
|
}
|
||||||
results = searchByNameserverLdhName(
|
results = searchByNameserverLdhName(
|
||||||
recordWildcardType(RdapSearchPattern.create(nsLdhNameParam.get(), true)), now);
|
recordWildcardType(RdapSearchPattern.create(nsLdhNameParam.get(), true)));
|
||||||
} else {
|
} else {
|
||||||
metricInformationBuilder.setSearchType(SearchType.BY_NAMESERVER_ADDRESS);
|
metricInformationBuilder.setSearchType(SearchType.BY_NAMESERVER_ADDRESS);
|
||||||
metricInformationBuilder.setWildcardType(WildcardType.NO_WILDCARD);
|
metricInformationBuilder.setWildcardType(WildcardType.NO_WILDCARD);
|
||||||
|
@ -138,7 +135,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
throw new BadRequestException("Invalid value of nsIp parameter");
|
throw new BadRequestException("Invalid value of nsIp parameter");
|
||||||
}
|
}
|
||||||
results = searchByNameserverIp(inetAddress, now);
|
results = searchByNameserverIp(inetAddress);
|
||||||
}
|
}
|
||||||
if (results.domainSearchResults().isEmpty()) {
|
if (results.domainSearchResults().isEmpty()) {
|
||||||
throw new NotFoundException("No domains found");
|
throw new NotFoundException("No domains found");
|
||||||
|
@ -158,12 +155,11 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
||||||
* <p>Searches which include deleted entries are effectively treated as if they have a wildcard,
|
* <p>Searches which include deleted entries are effectively treated as if they have a wildcard,
|
||||||
* since the same name can return multiple results.
|
* since the same name can return multiple results.
|
||||||
*/
|
*/
|
||||||
private DomainSearchResponse searchByDomainName(
|
private DomainSearchResponse searchByDomainName(final RdapSearchPattern partialStringQuery) {
|
||||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
|
||||||
// Handle queries without a wildcard -- just load by foreign key. We can't do this if deleted
|
// Handle queries without a wildcard -- just load by foreign key. We can't do this if deleted
|
||||||
// entries are included, because there may be multiple nameservers with the same name.
|
// entries are included, because there may be multiple nameservers with the same name.
|
||||||
if (!partialStringQuery.getHasWildcard() && !shouldIncludeDeleted()) {
|
if (!partialStringQuery.getHasWildcard() && !shouldIncludeDeleted()) {
|
||||||
return searchByDomainNameWithoutWildcard(partialStringQuery, now);
|
return searchByDomainNameWithoutWildcard(partialStringQuery);
|
||||||
}
|
}
|
||||||
// Handle queries with a wildcard and initial search string. We require either a TLD or an
|
// Handle queries with a wildcard and initial search string. We require either a TLD or an
|
||||||
// initial string at least MIN_INITIAL_STRING_LENGTH long.
|
// initial string at least MIN_INITIAL_STRING_LENGTH long.
|
||||||
|
@ -177,32 +173,29 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
||||||
+ " without a TLD suffix",
|
+ " without a TLD suffix",
|
||||||
RdapSearchPattern.MIN_INITIAL_STRING_LENGTH));
|
RdapSearchPattern.MIN_INITIAL_STRING_LENGTH));
|
||||||
}
|
}
|
||||||
return searchByDomainNameWithInitialString(partialStringQuery, now);
|
return searchByDomainNameWithInitialString(partialStringQuery);
|
||||||
}
|
}
|
||||||
if (partialStringQuery.getSuffix() == null) {
|
if (partialStringQuery.getSuffix() == null) {
|
||||||
throw new UnprocessableEntityException(
|
throw new UnprocessableEntityException(
|
||||||
"Initial search string is required for wildcard domain searches without a TLD suffix");
|
"Initial search string is required for wildcard domain searches without a TLD suffix");
|
||||||
}
|
}
|
||||||
return searchByDomainNameByTld(partialStringQuery.getSuffix(), now);
|
return searchByDomainNameByTld(partialStringQuery.getSuffix());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Searches for domains by domain name without a wildcard or interest in deleted entries.
|
* Searches for domains by domain name without a wildcard or interest in deleted entries.
|
||||||
*/
|
*/
|
||||||
private DomainSearchResponse searchByDomainNameWithoutWildcard(
|
private DomainSearchResponse searchByDomainNameWithoutWildcard(
|
||||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
final RdapSearchPattern partialStringQuery) {
|
||||||
Optional<DomainBase> domainBase =
|
Optional<DomainBase> domainBase =
|
||||||
loadByForeignKey(DomainBase.class, partialStringQuery.getInitialString(), now);
|
loadByForeignKey(DomainBase.class, partialStringQuery.getInitialString(), getRequestTime());
|
||||||
return makeSearchResults(
|
return makeSearchResults(
|
||||||
shouldBeVisible(domainBase, now)
|
shouldBeVisible(domainBase) ? ImmutableList.of(domainBase.get()) : ImmutableList.of());
|
||||||
? ImmutableList.of(domainBase.get())
|
|
||||||
: ImmutableList.of(),
|
|
||||||
now);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Searches for domains by domain name with an initial string, wildcard and possible suffix. */
|
/** Searches for domains by domain name with an initial string, wildcard and possible suffix. */
|
||||||
private DomainSearchResponse searchByDomainNameWithInitialString(
|
private DomainSearchResponse searchByDomainNameWithInitialString(
|
||||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
final RdapSearchPattern partialStringQuery) {
|
||||||
// We can't query for undeleted domains as part of the query itself; that would require an
|
// We can't query for undeleted domains as part of the query itself; that would require an
|
||||||
// inequality query on deletion time, and we are already using inequality queries on
|
// inequality query on deletion time, and we are already using inequality queries on
|
||||||
// fullyQualifiedDomainName. So we instead pick an arbitrary limit of
|
// fullyQualifiedDomainName. So we instead pick an arbitrary limit of
|
||||||
|
@ -227,11 +220,11 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
||||||
}
|
}
|
||||||
query = query.limit(querySizeLimit);
|
query = query.limit(querySizeLimit);
|
||||||
// Always check for visibility, because we couldn't look at the deletionTime in the query.
|
// Always check for visibility, because we couldn't look at the deletionTime in the query.
|
||||||
return makeSearchResults(getMatchingResources(query, true, now, querySizeLimit), now);
|
return makeSearchResults(getMatchingResources(query, true, querySizeLimit));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Searches for domains by domain name with a TLD suffix. */
|
/** Searches for domains by domain name with a TLD suffix. */
|
||||||
private DomainSearchResponse searchByDomainNameByTld(String tld, DateTime now) {
|
private DomainSearchResponse searchByDomainNameByTld(String tld) {
|
||||||
// Even though we are not searching on fullyQualifiedDomainName, we want the results to come
|
// Even though we are not searching on fullyQualifiedDomainName, we want the results to come
|
||||||
// back ordered by name, so we are still in the same boat as
|
// back ordered by name, so we are still in the same boat as
|
||||||
// searchByDomainNameWithInitialString, unable to perform an inequality query on deletion time.
|
// searchByDomainNameWithInitialString, unable to perform an inequality query on deletion time.
|
||||||
|
@ -246,7 +239,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
||||||
query = query.filter("fullyQualifiedDomainName >", cursorString.get());
|
query = query.filter("fullyQualifiedDomainName >", cursorString.get());
|
||||||
}
|
}
|
||||||
query = query.order("fullyQualifiedDomainName").limit(querySizeLimit);
|
query = query.order("fullyQualifiedDomainName").limit(querySizeLimit);
|
||||||
return makeSearchResults(getMatchingResources(query, true, now, querySizeLimit), now);
|
return makeSearchResults(getMatchingResources(query, true, querySizeLimit));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -259,13 +252,13 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
||||||
* domains which used to be connected to an undeleted nameserver.
|
* domains which used to be connected to an undeleted nameserver.
|
||||||
*/
|
*/
|
||||||
private DomainSearchResponse searchByNameserverLdhName(
|
private DomainSearchResponse searchByNameserverLdhName(
|
||||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
final RdapSearchPattern partialStringQuery) {
|
||||||
Iterable<Key<HostResource>> hostKeys = getNameserverRefsByLdhName(partialStringQuery, now);
|
Iterable<Key<HostResource>> hostKeys = getNameserverRefsByLdhName(partialStringQuery);
|
||||||
if (Iterables.isEmpty(hostKeys)) {
|
if (Iterables.isEmpty(hostKeys)) {
|
||||||
metricInformationBuilder.setNumHostsRetrieved(0);
|
metricInformationBuilder.setNumHostsRetrieved(0);
|
||||||
throw new NotFoundException("No matching nameservers found");
|
throw new NotFoundException("No matching nameservers found");
|
||||||
}
|
}
|
||||||
return searchByNameserverRefs(hostKeys, now);
|
return searchByNameserverRefs(hostKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -279,14 +272,14 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
||||||
* domain and just list all of its subordinate hosts.
|
* domain and just list all of its subordinate hosts.
|
||||||
*/
|
*/
|
||||||
private Iterable<Key<HostResource>> getNameserverRefsByLdhName(
|
private Iterable<Key<HostResource>> getNameserverRefsByLdhName(
|
||||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
final RdapSearchPattern partialStringQuery) {
|
||||||
// Handle queries without a wildcard.
|
// Handle queries without a wildcard.
|
||||||
if (!partialStringQuery.getHasWildcard()) {
|
if (!partialStringQuery.getHasWildcard()) {
|
||||||
return getNameserverRefsByLdhNameWithoutWildcard(partialStringQuery, now);
|
return getNameserverRefsByLdhNameWithoutWildcard(partialStringQuery);
|
||||||
}
|
}
|
||||||
// Handle queries with a wildcard and suffix (specifying a suprerordinate domain).
|
// Handle queries with a wildcard and suffix (specifying a suprerordinate domain).
|
||||||
if (partialStringQuery.getSuffix() != null) {
|
if (partialStringQuery.getSuffix() != null) {
|
||||||
return getNameserverRefsByLdhNameWithSuffix(partialStringQuery, now);
|
return getNameserverRefsByLdhNameWithSuffix(partialStringQuery);
|
||||||
}
|
}
|
||||||
// If there's no suffix, query the host resources. Query the resources themselves, rather than
|
// If there's no suffix, query the host resources. Query the resources themselves, rather than
|
||||||
// the foreign key indexes, because then we have an index on fully qualified host name and
|
// the foreign key indexes, because then we have an index on fully qualified host name and
|
||||||
|
@ -313,7 +306,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
||||||
|
|
||||||
/** Assembles a list of {@link HostResource} keys by name when the pattern has no wildcard. */
|
/** Assembles a list of {@link HostResource} keys by name when the pattern has no wildcard. */
|
||||||
private Iterable<Key<HostResource>> getNameserverRefsByLdhNameWithoutWildcard(
|
private Iterable<Key<HostResource>> getNameserverRefsByLdhNameWithoutWildcard(
|
||||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
final RdapSearchPattern partialStringQuery) {
|
||||||
// If we need to check the sponsoring registrar, we need to load the resource rather than just
|
// If we need to check the sponsoring registrar, we need to load the resource rather than just
|
||||||
// the key.
|
// the key.
|
||||||
Optional<String> desiredRegistrar = getDesiredRegistrar();
|
Optional<String> desiredRegistrar = getDesiredRegistrar();
|
||||||
|
@ -322,7 +315,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
||||||
loadByForeignKey(
|
loadByForeignKey(
|
||||||
HostResource.class,
|
HostResource.class,
|
||||||
partialStringQuery.getInitialString(),
|
partialStringQuery.getInitialString(),
|
||||||
shouldIncludeDeleted() ? START_OF_TIME : now);
|
shouldIncludeDeleted() ? START_OF_TIME : getRequestTime());
|
||||||
return (!host.isPresent()
|
return (!host.isPresent()
|
||||||
|| !desiredRegistrar.get().equals(host.get().getPersistedCurrentSponsorClientId()))
|
|| !desiredRegistrar.get().equals(host.get().getPersistedCurrentSponsorClientId()))
|
||||||
? ImmutableList.of()
|
? ImmutableList.of()
|
||||||
|
@ -332,14 +325,14 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
||||||
loadAndGetKey(
|
loadAndGetKey(
|
||||||
HostResource.class,
|
HostResource.class,
|
||||||
partialStringQuery.getInitialString(),
|
partialStringQuery.getInitialString(),
|
||||||
shouldIncludeDeleted() ? START_OF_TIME : now);
|
shouldIncludeDeleted() ? START_OF_TIME : getRequestTime());
|
||||||
return (hostKey == null) ? ImmutableList.of() : ImmutableList.of(hostKey);
|
return (hostKey == null) ? ImmutableList.of() : ImmutableList.of(hostKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Assembles a list of {@link HostResource} keys by name using a superordinate domain suffix. */
|
/** Assembles a list of {@link HostResource} keys by name using a superordinate domain suffix. */
|
||||||
private Iterable<Key<HostResource>> getNameserverRefsByLdhNameWithSuffix(
|
private Iterable<Key<HostResource>> getNameserverRefsByLdhNameWithSuffix(
|
||||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
final RdapSearchPattern partialStringQuery) {
|
||||||
// The suffix must be a domain that we manage. That way, we can look up the domain and search
|
// The suffix must be a domain that we manage. That way, we can look up the domain and search
|
||||||
// through the subordinate hosts. This is more efficient, and lets us permit wildcard searches
|
// through the subordinate hosts. This is more efficient, and lets us permit wildcard searches
|
||||||
// with no initial string.
|
// with no initial string.
|
||||||
|
@ -347,7 +340,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
||||||
loadByForeignKey(
|
loadByForeignKey(
|
||||||
DomainBase.class,
|
DomainBase.class,
|
||||||
partialStringQuery.getSuffix(),
|
partialStringQuery.getSuffix(),
|
||||||
shouldIncludeDeleted() ? START_OF_TIME : now)
|
shouldIncludeDeleted() ? START_OF_TIME : getRequestTime())
|
||||||
.orElseThrow(
|
.orElseThrow(
|
||||||
() ->
|
() ->
|
||||||
new UnprocessableEntityException(
|
new UnprocessableEntityException(
|
||||||
|
@ -362,14 +355,19 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
||||||
if (desiredRegistrar.isPresent()) {
|
if (desiredRegistrar.isPresent()) {
|
||||||
Optional<HostResource> host =
|
Optional<HostResource> host =
|
||||||
loadByForeignKey(
|
loadByForeignKey(
|
||||||
HostResource.class, fqhn, shouldIncludeDeleted() ? START_OF_TIME : now);
|
HostResource.class,
|
||||||
|
fqhn,
|
||||||
|
shouldIncludeDeleted() ? START_OF_TIME : getRequestTime());
|
||||||
if (host.isPresent()
|
if (host.isPresent()
|
||||||
&& desiredRegistrar.get().equals(host.get().getPersistedCurrentSponsorClientId())) {
|
&& desiredRegistrar.get().equals(host.get().getPersistedCurrentSponsorClientId())) {
|
||||||
builder.add(Key.create(host.get()));
|
builder.add(Key.create(host.get()));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Key<HostResource> hostKey =
|
Key<HostResource> hostKey =
|
||||||
loadAndGetKey(HostResource.class, fqhn, shouldIncludeDeleted() ? START_OF_TIME : now);
|
loadAndGetKey(
|
||||||
|
HostResource.class,
|
||||||
|
fqhn,
|
||||||
|
shouldIncludeDeleted() ? START_OF_TIME : getRequestTime());
|
||||||
if (hostKey != null) {
|
if (hostKey != null) {
|
||||||
builder.add(hostKey);
|
builder.add(hostKey);
|
||||||
} else {
|
} else {
|
||||||
|
@ -398,7 +396,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
||||||
* domains which used to be connected to an undeleted nameserver.
|
* domains which used to be connected to an undeleted nameserver.
|
||||||
*/
|
*/
|
||||||
private DomainSearchResponse searchByNameserverIp(
|
private DomainSearchResponse searchByNameserverIp(
|
||||||
final InetAddress inetAddress, final DateTime now) {
|
final InetAddress inetAddress) {
|
||||||
Query<HostResource> query =
|
Query<HostResource> query =
|
||||||
queryItems(
|
queryItems(
|
||||||
HostResource.class,
|
HostResource.class,
|
||||||
|
@ -412,7 +410,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
||||||
if (desiredRegistrar.isPresent()) {
|
if (desiredRegistrar.isPresent()) {
|
||||||
query = query.filter("currentSponsorClientId", desiredRegistrar.get());
|
query = query.filter("currentSponsorClientId", desiredRegistrar.get());
|
||||||
}
|
}
|
||||||
return searchByNameserverRefs(query.keys(), now);
|
return searchByNameserverRefs(query.keys());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -422,7 +420,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
||||||
* #searchByNameserverIp} after they assemble the relevant host keys.
|
* #searchByNameserverIp} after they assemble the relevant host keys.
|
||||||
*/
|
*/
|
||||||
private DomainSearchResponse searchByNameserverRefs(
|
private DomainSearchResponse searchByNameserverRefs(
|
||||||
final Iterable<Key<HostResource>> hostKeys, final DateTime now) {
|
final Iterable<Key<HostResource>> hostKeys) {
|
||||||
// We must break the query up into chunks, because the in operator is limited to 30 subqueries.
|
// We must break the query up into chunks, because the in operator is limited to 30 subqueries.
|
||||||
// Since it is possible for the same domain to show up more than once in our result list (if
|
// Since it is possible for the same domain to show up more than once in our result list (if
|
||||||
// we do a wildcard nameserver search that returns multiple nameservers used by the same
|
// we do a wildcard nameserver search that returns multiple nameservers used by the same
|
||||||
|
@ -439,14 +437,13 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
||||||
.type(DomainBase.class)
|
.type(DomainBase.class)
|
||||||
.filter("nsHosts in", chunk);
|
.filter("nsHosts in", chunk);
|
||||||
if (!shouldIncludeDeleted()) {
|
if (!shouldIncludeDeleted()) {
|
||||||
query = query.filter("deletionTime >", now);
|
query = query.filter("deletionTime >", getRequestTime());
|
||||||
// If we are not performing an inequality query, we can filter on the cursor in the query.
|
// If we are not performing an inequality query, we can filter on the cursor in the query.
|
||||||
// Otherwise, we will need to filter the results afterward.
|
// Otherwise, we will need to filter the results afterward.
|
||||||
} else if (cursorString.isPresent()) {
|
} else if (cursorString.isPresent()) {
|
||||||
query = query.filter("fullyQualifiedDomainName >", cursorString.get());
|
query = query.filter("fullyQualifiedDomainName >", cursorString.get());
|
||||||
}
|
}
|
||||||
Stream<DomainBase> stream =
|
Stream<DomainBase> stream = Streams.stream(query).filter(domain -> isAuthorized(domain));
|
||||||
Streams.stream(query).filter(domain -> isAuthorized(domain, now));
|
|
||||||
if (cursorString.isPresent()) {
|
if (cursorString.isPresent()) {
|
||||||
stream =
|
stream =
|
||||||
stream.filter(
|
stream.filter(
|
||||||
|
@ -464,24 +461,22 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
||||||
(numHostKeysSearched >= maxNameserversInFirstStage)
|
(numHostKeysSearched >= maxNameserversInFirstStage)
|
||||||
? IncompletenessWarningType.MIGHT_BE_INCOMPLETE
|
? IncompletenessWarningType.MIGHT_BE_INCOMPLETE
|
||||||
: IncompletenessWarningType.COMPLETE,
|
: IncompletenessWarningType.COMPLETE,
|
||||||
(numHostKeysSearched > 0) ? Optional.of((long) domains.size()) : Optional.empty(),
|
(numHostKeysSearched > 0) ? Optional.of((long) domains.size()) : Optional.empty());
|
||||||
now);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Output JSON for a list of domains, with no incompleteness warnings. */
|
/** Output JSON for a list of domains, with no incompleteness warnings. */
|
||||||
private DomainSearchResponse makeSearchResults(List<DomainBase> domains, DateTime now) {
|
private DomainSearchResponse makeSearchResults(List<DomainBase> domains) {
|
||||||
return makeSearchResults(
|
return makeSearchResults(
|
||||||
domains, IncompletenessWarningType.COMPLETE, Optional.of((long) domains.size()), now);
|
domains, IncompletenessWarningType.COMPLETE, Optional.of((long) domains.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Output JSON from data in an {@link RdapResultSet} object. */
|
/** Output JSON from data in an {@link RdapResultSet} object. */
|
||||||
private DomainSearchResponse makeSearchResults(
|
private DomainSearchResponse makeSearchResults(
|
||||||
RdapResultSet<DomainBase> resultSet, DateTime now) {
|
RdapResultSet<DomainBase> resultSet) {
|
||||||
return makeSearchResults(
|
return makeSearchResults(
|
||||||
resultSet.resources(),
|
resultSet.resources(),
|
||||||
resultSet.incompletenessWarningType(),
|
resultSet.incompletenessWarningType(),
|
||||||
Optional.of((long) resultSet.numResourcesRetrieved()),
|
Optional.of((long) resultSet.numResourcesRetrieved()));
|
||||||
now);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -494,8 +489,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
||||||
private DomainSearchResponse makeSearchResults(
|
private DomainSearchResponse makeSearchResults(
|
||||||
List<DomainBase> domains,
|
List<DomainBase> domains,
|
||||||
IncompletenessWarningType incompletenessWarningType,
|
IncompletenessWarningType incompletenessWarningType,
|
||||||
Optional<Long> numDomainsRetrieved,
|
Optional<Long> numDomainsRetrieved) {
|
||||||
DateTime now) {
|
|
||||||
numDomainsRetrieved.ifPresent(metricInformationBuilder::setNumDomainsRetrieved);
|
numDomainsRetrieved.ifPresent(metricInformationBuilder::setNumDomainsRetrieved);
|
||||||
OutputDataType outputDataType =
|
OutputDataType outputDataType =
|
||||||
(domains.size() > 1) ? OutputDataType.SUMMARY : OutputDataType.FULL;
|
(domains.size() > 1) ? OutputDataType.SUMMARY : OutputDataType.FULL;
|
||||||
|
@ -505,8 +499,9 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
||||||
Optional<String> newCursor = Optional.empty();
|
Optional<String> newCursor = Optional.empty();
|
||||||
for (DomainBase domain : Iterables.limit(domains, rdapResultSetMaxSize)) {
|
for (DomainBase domain : Iterables.limit(domains, rdapResultSetMaxSize)) {
|
||||||
newCursor = Optional.of(domain.getFullyQualifiedDomainName());
|
newCursor = Optional.of(domain.getFullyQualifiedDomainName());
|
||||||
builder.domainSearchResultsBuilder().add(
|
builder
|
||||||
rdapJsonFormatter.makeRdapJsonForDomain(domain, rdapWhoisServer, now, outputDataType));
|
.domainSearchResultsBuilder()
|
||||||
|
.add(rdapJsonFormatter.makeRdapJsonForDomain(domain, outputDataType));
|
||||||
}
|
}
|
||||||
if (rdapResultSetMaxSize < domains.size()) {
|
if (rdapResultSetMaxSize < domains.size()) {
|
||||||
builder.setNextPageUri(createNavigationUri(newCursor.get()));
|
builder.setNextPageUri(createNavigationUri(newCursor.get()));
|
||||||
|
|
|
@ -33,7 +33,6 @@ import google.registry.request.HttpException.NotFoundException;
|
||||||
import google.registry.request.auth.Auth;
|
import google.registry.request.auth.Auth;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import org.joda.time.DateTime;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RDAP (new WHOIS) action for entity (contact and registrar) requests. the ICANN operational
|
* RDAP (new WHOIS) action for entity (contact and registrar) requests. the ICANN operational
|
||||||
|
@ -62,7 +61,6 @@ public class RdapEntityAction extends RdapActionBase {
|
||||||
@Override
|
@Override
|
||||||
public RdapEntity getJsonObjectForResource(
|
public RdapEntity getJsonObjectForResource(
|
||||||
String pathSearchString, boolean isHeadRequest) {
|
String pathSearchString, boolean isHeadRequest) {
|
||||||
DateTime now = clock.nowUtc();
|
|
||||||
// The query string is not used; the RDAP syntax is /rdap/entity/handle (the handle is the roid
|
// The query string is not used; the RDAP syntax is /rdap/entity/handle (the handle is the roid
|
||||||
// for contacts and the client identifier for registrars). Since RDAP's concept of an entity
|
// for contacts and the client identifier for registrars). Since RDAP's concept of an entity
|
||||||
// includes both contacts and registrars, search for one first, then the other.
|
// includes both contacts and registrars, search for one first, then the other.
|
||||||
|
@ -73,12 +71,10 @@ public class RdapEntityAction extends RdapActionBase {
|
||||||
ContactResource contactResource = ofy().load().key(contactKey).now();
|
ContactResource contactResource = ofy().load().key(contactKey).now();
|
||||||
// As per Andy Newton on the regext mailing list, contacts by themselves have no role, since
|
// As per Andy Newton on the regext mailing list, contacts by themselves have no role, since
|
||||||
// they are global, and might have different roles for different domains.
|
// they are global, and might have different roles for different domains.
|
||||||
if ((contactResource != null) && shouldBeVisible(contactResource, now)) {
|
if ((contactResource != null) && shouldBeVisible(contactResource)) {
|
||||||
return rdapJsonFormatter.makeRdapJsonForContact(
|
return rdapJsonFormatter.makeRdapJsonForContact(
|
||||||
contactResource,
|
contactResource,
|
||||||
Optional.empty(),
|
Optional.empty(),
|
||||||
rdapWhoisServer,
|
|
||||||
now,
|
|
||||||
OutputDataType.FULL);
|
OutputDataType.FULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,7 +84,7 @@ public class RdapEntityAction extends RdapActionBase {
|
||||||
Optional<Registrar> registrar = getRegistrarByIanaIdentifier(ianaIdentifier);
|
Optional<Registrar> registrar = getRegistrarByIanaIdentifier(ianaIdentifier);
|
||||||
if (registrar.isPresent() && shouldBeVisible(registrar.get())) {
|
if (registrar.isPresent() && shouldBeVisible(registrar.get())) {
|
||||||
return rdapJsonFormatter.makeRdapJsonForRegistrar(
|
return rdapJsonFormatter.makeRdapJsonForRegistrar(
|
||||||
registrar.get(), rdapWhoisServer, now, OutputDataType.FULL);
|
registrar.get(), OutputDataType.FULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// At this point, we have failed to find either a contact or a registrar.
|
// At this point, we have failed to find either a contact or a registrar.
|
||||||
|
|
|
@ -43,7 +43,6 @@ import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import org.joda.time.DateTime;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RDAP (new WHOIS) action for entity (contact and registrar) search requests.
|
* RDAP (new WHOIS) action for entity (contact and registrar) search requests.
|
||||||
|
@ -111,7 +110,6 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
||||||
@Override
|
@Override
|
||||||
public EntitySearchResponse getJsonObjectForResource(
|
public EntitySearchResponse getJsonObjectForResource(
|
||||||
String pathSearchString, boolean isHeadRequest) {
|
String pathSearchString, boolean isHeadRequest) {
|
||||||
DateTime now = clock.nowUtc();
|
|
||||||
|
|
||||||
// RDAP syntax example: /rdap/entities?fn=Bobby%20Joe*.
|
// RDAP syntax example: /rdap/entities?fn=Bobby%20Joe*.
|
||||||
// The pathSearchString is not used by search commands.
|
// The pathSearchString is not used by search commands.
|
||||||
|
@ -166,8 +164,7 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
||||||
recordWildcardType(RdapSearchPattern.create(fnParam.get(), false)),
|
recordWildcardType(RdapSearchPattern.create(fnParam.get(), false)),
|
||||||
cursorType,
|
cursorType,
|
||||||
cursorQueryString,
|
cursorQueryString,
|
||||||
subtype,
|
subtype);
|
||||||
now);
|
|
||||||
|
|
||||||
// Search by handle.
|
// Search by handle.
|
||||||
} else {
|
} else {
|
||||||
|
@ -179,8 +176,7 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
||||||
recordWildcardType(RdapSearchPattern.create(handleParam.get(), false)),
|
recordWildcardType(RdapSearchPattern.create(handleParam.get(), false)),
|
||||||
cursorType,
|
cursorType,
|
||||||
cursorQueryString,
|
cursorQueryString,
|
||||||
subtype,
|
subtype);
|
||||||
now);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the result object and return it.
|
// Build the result object and return it.
|
||||||
|
@ -218,8 +214,7 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
||||||
final RdapSearchPattern partialStringQuery,
|
final RdapSearchPattern partialStringQuery,
|
||||||
CursorType cursorType,
|
CursorType cursorType,
|
||||||
Optional<String> cursorQueryString,
|
Optional<String> cursorQueryString,
|
||||||
Subtype subtype,
|
Subtype subtype) {
|
||||||
DateTime now) {
|
|
||||||
// Don't allow wildcard suffixes when searching for entities.
|
// Don't allow wildcard suffixes when searching for entities.
|
||||||
if (partialStringQuery.getHasWildcard() && (partialStringQuery.getSuffix() != null)) {
|
if (partialStringQuery.getHasWildcard() && (partialStringQuery.getSuffix() != null)) {
|
||||||
throw new UnprocessableEntityException(
|
throw new UnprocessableEntityException(
|
||||||
|
@ -282,10 +277,10 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
||||||
if (rdapAuthorization.role() != RdapAuthorization.Role.ADMINISTRATOR) {
|
if (rdapAuthorization.role() != RdapAuthorization.Role.ADMINISTRATOR) {
|
||||||
query = query.filter("currentSponsorClientId in", rdapAuthorization.clientIds());
|
query = query.filter("currentSponsorClientId in", rdapAuthorization.clientIds());
|
||||||
}
|
}
|
||||||
resultSet = getMatchingResources(query, false, now, rdapResultSetMaxSize + 1);
|
resultSet = getMatchingResources(query, false, rdapResultSetMaxSize + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return makeSearchResults(resultSet, registrars, QueryType.FULL_NAME, now);
|
return makeSearchResults(resultSet, registrars, QueryType.FULL_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -302,8 +297,7 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
||||||
final RdapSearchPattern partialStringQuery,
|
final RdapSearchPattern partialStringQuery,
|
||||||
CursorType cursorType,
|
CursorType cursorType,
|
||||||
Optional<String> cursorQueryString,
|
Optional<String> cursorQueryString,
|
||||||
Subtype subtype,
|
Subtype subtype) {
|
||||||
DateTime now) {
|
|
||||||
if (partialStringQuery.getSuffix() != null) {
|
if (partialStringQuery.getSuffix() != null) {
|
||||||
throw new UnprocessableEntityException("Suffixes not allowed in entity handle searches");
|
throw new UnprocessableEntityException("Suffixes not allowed in entity handle searches");
|
||||||
}
|
}
|
||||||
|
@ -320,7 +314,7 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
||||||
.id(partialStringQuery.getInitialString())
|
.id(partialStringQuery.getInitialString())
|
||||||
.now();
|
.now();
|
||||||
contactResourceList =
|
contactResourceList =
|
||||||
((contactResource != null) && shouldBeVisible(contactResource, now))
|
((contactResource != null) && shouldBeVisible(contactResource))
|
||||||
? ImmutableList.of(contactResource)
|
? ImmutableList.of(contactResource)
|
||||||
: ImmutableList.of();
|
: ImmutableList.of();
|
||||||
}
|
}
|
||||||
|
@ -335,8 +329,7 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
||||||
IncompletenessWarningType.COMPLETE,
|
IncompletenessWarningType.COMPLETE,
|
||||||
contactResourceList.size(),
|
contactResourceList.size(),
|
||||||
registrarList,
|
registrarList,
|
||||||
QueryType.HANDLE,
|
QueryType.HANDLE);
|
||||||
now);
|
|
||||||
// Handle queries with a wildcard (or including deleted), but no suffix. Because the handle
|
// Handle queries with a wildcard (or including deleted), but no suffix. Because the handle
|
||||||
// for registrars is the IANA identifier number, don't allow wildcard searches for registrars,
|
// for registrars is the IANA identifier number, don't allow wildcard searches for registrars,
|
||||||
// by simply not searching for registrars if a wildcard is present (unless the request is for
|
// by simply not searching for registrars if a wildcard is present (unless the request is for
|
||||||
|
@ -385,14 +378,12 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
||||||
getDeletedItemHandling(),
|
getDeletedItemHandling(),
|
||||||
querySizeLimit),
|
querySizeLimit),
|
||||||
shouldIncludeDeleted(),
|
shouldIncludeDeleted(),
|
||||||
now,
|
|
||||||
querySizeLimit);
|
querySizeLimit);
|
||||||
}
|
}
|
||||||
return makeSearchResults(
|
return makeSearchResults(
|
||||||
contactResultSet,
|
contactResultSet,
|
||||||
registrars,
|
registrars,
|
||||||
QueryType.HANDLE,
|
QueryType.HANDLE);
|
||||||
now);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,15 +408,13 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
||||||
private EntitySearchResponse makeSearchResults(
|
private EntitySearchResponse makeSearchResults(
|
||||||
RdapResultSet<ContactResource> resultSet,
|
RdapResultSet<ContactResource> resultSet,
|
||||||
List<Registrar> registrars,
|
List<Registrar> registrars,
|
||||||
QueryType queryType,
|
QueryType queryType) {
|
||||||
DateTime now) {
|
|
||||||
return makeSearchResults(
|
return makeSearchResults(
|
||||||
resultSet.resources(),
|
resultSet.resources(),
|
||||||
resultSet.incompletenessWarningType(),
|
resultSet.incompletenessWarningType(),
|
||||||
resultSet.numResourcesRetrieved(),
|
resultSet.numResourcesRetrieved(),
|
||||||
registrars,
|
registrars,
|
||||||
queryType,
|
queryType);
|
||||||
now);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -441,7 +430,6 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
||||||
* results
|
* results
|
||||||
* @param registrars the list of registrars which can be returned
|
* @param registrars the list of registrars which can be returned
|
||||||
* @param queryType whether the query was by full name or by handle
|
* @param queryType whether the query was by full name or by handle
|
||||||
* @param now the current date and time
|
|
||||||
* @return an {@link RdapSearchResults} object
|
* @return an {@link RdapSearchResults} object
|
||||||
*/
|
*/
|
||||||
private EntitySearchResponse makeSearchResults(
|
private EntitySearchResponse makeSearchResults(
|
||||||
|
@ -449,8 +437,7 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
||||||
IncompletenessWarningType incompletenessWarningType,
|
IncompletenessWarningType incompletenessWarningType,
|
||||||
int numContactsRetrieved,
|
int numContactsRetrieved,
|
||||||
List<Registrar> registrars,
|
List<Registrar> registrars,
|
||||||
QueryType queryType,
|
QueryType queryType) {
|
||||||
DateTime now) {
|
|
||||||
|
|
||||||
metricInformationBuilder.setNumContactsRetrieved(numContactsRetrieved);
|
metricInformationBuilder.setNumContactsRetrieved(numContactsRetrieved);
|
||||||
|
|
||||||
|
@ -476,8 +463,6 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
||||||
builder.entitySearchResultsBuilder().add(rdapJsonFormatter.makeRdapJsonForContact(
|
builder.entitySearchResultsBuilder().add(rdapJsonFormatter.makeRdapJsonForContact(
|
||||||
contact,
|
contact,
|
||||||
Optional.empty(),
|
Optional.empty(),
|
||||||
rdapWhoisServer,
|
|
||||||
now,
|
|
||||||
outputDataType));
|
outputDataType));
|
||||||
newCursor =
|
newCursor =
|
||||||
Optional.of(
|
Optional.of(
|
||||||
|
@ -493,7 +478,7 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
||||||
.entitySearchResultsBuilder()
|
.entitySearchResultsBuilder()
|
||||||
.add(
|
.add(
|
||||||
rdapJsonFormatter.makeRdapJsonForRegistrar(
|
rdapJsonFormatter.makeRdapJsonForRegistrar(
|
||||||
registrar, rdapWhoisServer, now, outputDataType));
|
registrar, outputDataType));
|
||||||
newCursor = Optional.of(REGISTRAR_CURSOR_PREFIX + registrar.getRegistrarName());
|
newCursor = Optional.of(REGISTRAR_CURSOR_PREFIX + registrar.getRegistrarName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,6 @@ import google.registry.rdap.RdapDataStructures.Event;
|
||||||
import google.registry.rdap.RdapDataStructures.EventAction;
|
import google.registry.rdap.RdapDataStructures.EventAction;
|
||||||
import google.registry.rdap.RdapDataStructures.Link;
|
import google.registry.rdap.RdapDataStructures.Link;
|
||||||
import google.registry.rdap.RdapDataStructures.Notice;
|
import google.registry.rdap.RdapDataStructures.Notice;
|
||||||
import google.registry.rdap.RdapDataStructures.Port43WhoisServer;
|
|
||||||
import google.registry.rdap.RdapDataStructures.PublicId;
|
import google.registry.rdap.RdapDataStructures.PublicId;
|
||||||
import google.registry.rdap.RdapDataStructures.RdapStatus;
|
import google.registry.rdap.RdapDataStructures.RdapStatus;
|
||||||
import google.registry.rdap.RdapObjectClasses.RdapDomain;
|
import google.registry.rdap.RdapObjectClasses.RdapDomain;
|
||||||
|
@ -59,6 +58,7 @@ import google.registry.rdap.RdapObjectClasses.Vcard;
|
||||||
import google.registry.rdap.RdapObjectClasses.VcardArray;
|
import google.registry.rdap.RdapObjectClasses.VcardArray;
|
||||||
import google.registry.request.FullServletPath;
|
import google.registry.request.FullServletPath;
|
||||||
import google.registry.request.HttpException.InternalServerErrorException;
|
import google.registry.request.HttpException.InternalServerErrorException;
|
||||||
|
import google.registry.util.Clock;
|
||||||
import java.net.Inet4Address;
|
import java.net.Inet4Address;
|
||||||
import java.net.Inet6Address;
|
import java.net.Inet6Address;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
|
@ -87,11 +87,13 @@ import org.joda.time.DateTimeComparator;
|
||||||
*/
|
*/
|
||||||
public class RdapJsonFormatter {
|
public class RdapJsonFormatter {
|
||||||
|
|
||||||
|
private DateTime requestTime = null;
|
||||||
|
|
||||||
@Inject @Config("rdapTos") ImmutableList<String> rdapTos;
|
@Inject @Config("rdapTos") ImmutableList<String> rdapTos;
|
||||||
@Inject @Config("rdapTosStaticUrl") @Nullable String rdapTosStaticUrl;
|
@Inject @Config("rdapTosStaticUrl") @Nullable String rdapTosStaticUrl;
|
||||||
@Inject @FullServletPath String fullServletPath;
|
@Inject @FullServletPath String fullServletPath;
|
||||||
@Inject RdapAuthorization rdapAuthorization;
|
@Inject RdapAuthorization rdapAuthorization;
|
||||||
|
@Inject Clock clock;
|
||||||
@Inject RdapJsonFormatter() {}
|
@Inject RdapJsonFormatter() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -213,15 +215,10 @@ public class RdapJsonFormatter {
|
||||||
* Creates a JSON object for a {@link DomainBase}.
|
* Creates a JSON object for a {@link DomainBase}.
|
||||||
*
|
*
|
||||||
* @param domainBase the domain resource object from which the JSON object should be created
|
* @param domainBase the domain resource object from which the JSON object should be created
|
||||||
* @param whoisServer the fully-qualified domain name of the WHOIS server to be listed in the
|
|
||||||
* port43 field; if null, port43 is not added to the object
|
|
||||||
* @param now the as-date
|
|
||||||
* @param outputDataType whether to generate full or summary data
|
* @param outputDataType whether to generate full or summary data
|
||||||
*/
|
*/
|
||||||
RdapDomain makeRdapJsonForDomain(
|
RdapDomain makeRdapJsonForDomain(
|
||||||
DomainBase domainBase,
|
DomainBase domainBase,
|
||||||
@Nullable String whoisServer,
|
|
||||||
DateTime now,
|
|
||||||
OutputDataType outputDataType) {
|
OutputDataType outputDataType) {
|
||||||
RdapDomain.Builder builder = RdapDomain.builder();
|
RdapDomain.Builder builder = RdapDomain.builder();
|
||||||
// RDAP Response Profile 15feb19 section 2.2:
|
// RDAP Response Profile 15feb19 section 2.2:
|
||||||
|
@ -232,7 +229,7 @@ public class RdapJsonFormatter {
|
||||||
makeStatusValueList(
|
makeStatusValueList(
|
||||||
domainBase.getStatusValues(),
|
domainBase.getStatusValues(),
|
||||||
false, // isRedacted
|
false, // isRedacted
|
||||||
domainBase.getDeletionTime().isBefore(now)));
|
domainBase.getDeletionTime().isBefore(getRequestTime())));
|
||||||
builder.linksBuilder().add(
|
builder.linksBuilder().add(
|
||||||
makeSelfLink("domain", domainBase.getFullyQualifiedDomainName()));
|
makeSelfLink("domain", domainBase.getFullyQualifiedDomainName()));
|
||||||
boolean displayContacts =
|
boolean displayContacts =
|
||||||
|
@ -243,7 +240,7 @@ public class RdapJsonFormatter {
|
||||||
if (outputDataType == OutputDataType.SUMMARY) {
|
if (outputDataType == OutputDataType.SUMMARY) {
|
||||||
builder.remarksBuilder().add(RdapIcannStandardInformation.SUMMARY_DATA_REMARK);
|
builder.remarksBuilder().add(RdapIcannStandardInformation.SUMMARY_DATA_REMARK);
|
||||||
} else {
|
} else {
|
||||||
ImmutableList<Event> events = makeEvents(domainBase, now);
|
ImmutableList<Event> events = makeEvents(domainBase);
|
||||||
builder.eventsBuilder().addAll(events);
|
builder.eventsBuilder().addAll(events);
|
||||||
// Kick off the database loads of the nameservers that we will need, so it can load
|
// Kick off the database loads of the nameservers that we will need, so it can load
|
||||||
// asynchronously while we load and process the contacts.
|
// asynchronously while we load and process the contacts.
|
||||||
|
@ -267,26 +264,18 @@ public class RdapJsonFormatter {
|
||||||
makeRdapJsonForContact(
|
makeRdapJsonForContact(
|
||||||
loadedContacts.get(designatedContact.getContactKey()),
|
loadedContacts.get(designatedContact.getContactKey()),
|
||||||
Optional.of(designatedContact.getType()),
|
Optional.of(designatedContact.getType()),
|
||||||
null,
|
|
||||||
now,
|
|
||||||
outputDataType))
|
outputDataType))
|
||||||
.forEach(builder.entitiesBuilder()::add);
|
.forEach(builder.entitiesBuilder()::add);
|
||||||
}
|
}
|
||||||
builder
|
builder
|
||||||
.entitiesBuilder()
|
.entitiesBuilder()
|
||||||
.add(
|
.add(createInternalRegistrarEntity(domainBase.getCurrentSponsorClientId()));
|
||||||
createInternalRegistrarEntity(
|
|
||||||
domainBase.getCurrentSponsorClientId(), whoisServer, now));
|
|
||||||
// Add the nameservers to the data; the load was kicked off above for efficiency.
|
// Add the nameservers to the data; the load was kicked off above for efficiency.
|
||||||
for (HostResource hostResource
|
for (HostResource hostResource
|
||||||
: HOST_RESOURCE_ORDERING.immutableSortedCopy(loadedHosts.values())) {
|
: HOST_RESOURCE_ORDERING.immutableSortedCopy(loadedHosts.values())) {
|
||||||
builder.nameserversBuilder().add(makeRdapJsonForHost(
|
builder.nameserversBuilder().add(makeRdapJsonForHost(hostResource, outputDataType));
|
||||||
hostResource, null, now, outputDataType));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (whoisServer != null) {
|
|
||||||
builder.setPort43(Port43WhoisServer.create(whoisServer));
|
|
||||||
}
|
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,14 +283,8 @@ public class RdapJsonFormatter {
|
||||||
* Creates a JSON object for the desired registrar to an existing list of JSON objects.
|
* Creates a JSON object for the desired registrar to an existing list of JSON objects.
|
||||||
*
|
*
|
||||||
* @param clientId the registrar client ID
|
* @param clientId the registrar client ID
|
||||||
* @param whoisServer the fully-qualified domain name of the WHOIS server to be listed in the
|
|
||||||
* port43 field; if null, port43 is not added to the object
|
|
||||||
* @param now the as-date
|
|
||||||
*/
|
*/
|
||||||
RdapEntity createInternalRegistrarEntity(
|
RdapEntity createInternalRegistrarEntity(String clientId) {
|
||||||
String clientId,
|
|
||||||
@Nullable String whoisServer,
|
|
||||||
DateTime now) {
|
|
||||||
Optional<Registrar> registrar = Registrar.loadByClientIdCached(clientId);
|
Optional<Registrar> registrar = Registrar.loadByClientIdCached(clientId);
|
||||||
if (!registrar.isPresent()) {
|
if (!registrar.isPresent()) {
|
||||||
throw new InternalServerErrorException(
|
throw new InternalServerErrorException(
|
||||||
|
@ -309,26 +292,17 @@ public class RdapJsonFormatter {
|
||||||
}
|
}
|
||||||
// TODO(b/130150723): we need to display the ABUSE contact for registrar object inside of Domain
|
// TODO(b/130150723): we need to display the ABUSE contact for registrar object inside of Domain
|
||||||
// responses. Currently, we use summary for any "internal" registrar.
|
// responses. Currently, we use summary for any "internal" registrar.
|
||||||
return makeRdapJsonForRegistrar(
|
return makeRdapJsonForRegistrar(registrar.get(), OutputDataType.SUMMARY);
|
||||||
registrar.get(),
|
|
||||||
whoisServer,
|
|
||||||
now,
|
|
||||||
OutputDataType.SUMMARY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a JSON object for a {@link HostResource}.
|
* Creates a JSON object for a {@link HostResource}.
|
||||||
*
|
*
|
||||||
* @param hostResource the host resource object from which the JSON object should be created
|
* @param hostResource the host resource object from which the JSON object should be created
|
||||||
* @param whoisServer the fully-qualified domain name of the WHOIS server to be listed in the
|
|
||||||
* port43 field; if null, port43 is not added to the object
|
|
||||||
* @param now the as-date
|
|
||||||
* @param outputDataType whether to generate full or summary data
|
* @param outputDataType whether to generate full or summary data
|
||||||
*/
|
*/
|
||||||
RdapNameserver makeRdapJsonForHost(
|
RdapNameserver makeRdapJsonForHost(
|
||||||
HostResource hostResource,
|
HostResource hostResource,
|
||||||
@Nullable String whoisServer,
|
|
||||||
DateTime now,
|
|
||||||
OutputDataType outputDataType) {
|
OutputDataType outputDataType) {
|
||||||
RdapNameserver.Builder builder = RdapNameserver.builder()
|
RdapNameserver.Builder builder = RdapNameserver.builder()
|
||||||
.setHandle(hostResource.getRepoId())
|
.setHandle(hostResource.getRepoId())
|
||||||
|
@ -336,11 +310,15 @@ public class RdapJsonFormatter {
|
||||||
|
|
||||||
ImmutableSet.Builder<StatusValue> statuses = new ImmutableSet.Builder<>();
|
ImmutableSet.Builder<StatusValue> statuses = new ImmutableSet.Builder<>();
|
||||||
statuses.addAll(hostResource.getStatusValues());
|
statuses.addAll(hostResource.getStatusValues());
|
||||||
if (isLinked(Key.create(hostResource), now)) {
|
if (isLinked(Key.create(hostResource), getRequestTime())) {
|
||||||
statuses.add(StatusValue.LINKED);
|
statuses.add(StatusValue.LINKED);
|
||||||
}
|
}
|
||||||
if (hostResource.isSubordinate()
|
if (hostResource.isSubordinate()
|
||||||
&& ofy().load().key(hostResource.getSuperordinateDomain()).now().cloneProjectedAtTime(now)
|
&& ofy()
|
||||||
|
.load()
|
||||||
|
.key(hostResource.getSuperordinateDomain())
|
||||||
|
.now()
|
||||||
|
.cloneProjectedAtTime(getRequestTime())
|
||||||
.getStatusValues()
|
.getStatusValues()
|
||||||
.contains(StatusValue.PENDING_TRANSFER)) {
|
.contains(StatusValue.PENDING_TRANSFER)) {
|
||||||
statuses.add(StatusValue.PENDING_TRANSFER);
|
statuses.add(StatusValue.PENDING_TRANSFER);
|
||||||
|
@ -351,7 +329,7 @@ public class RdapJsonFormatter {
|
||||||
makeStatusValueList(
|
makeStatusValueList(
|
||||||
statuses.build(),
|
statuses.build(),
|
||||||
false, // isRedacted
|
false, // isRedacted
|
||||||
hostResource.getDeletionTime().isBefore(now)));
|
hostResource.getDeletionTime().isBefore(getRequestTime())));
|
||||||
builder
|
builder
|
||||||
.linksBuilder()
|
.linksBuilder()
|
||||||
.add(makeSelfLink("nameserver", hostResource.getFullyQualifiedHostName()));
|
.add(makeSelfLink("nameserver", hostResource.getFullyQualifiedHostName()));
|
||||||
|
@ -361,7 +339,7 @@ public class RdapJsonFormatter {
|
||||||
if (outputDataType == OutputDataType.SUMMARY) {
|
if (outputDataType == OutputDataType.SUMMARY) {
|
||||||
builder.remarksBuilder().add(RdapIcannStandardInformation.SUMMARY_DATA_REMARK);
|
builder.remarksBuilder().add(RdapIcannStandardInformation.SUMMARY_DATA_REMARK);
|
||||||
} else {
|
} else {
|
||||||
builder.eventsBuilder().addAll(makeEvents(hostResource, now));
|
builder.eventsBuilder().addAll(makeEvents(hostResource));
|
||||||
}
|
}
|
||||||
|
|
||||||
// We MUST have the ip addresses: RDAP Response Profile 4.2.
|
// We MUST have the ip addresses: RDAP Response Profile 4.2.
|
||||||
|
@ -372,13 +350,9 @@ public class RdapJsonFormatter {
|
||||||
builder.ipv6Builder().add(InetAddresses.toAddrString(inetAddress));
|
builder.ipv6Builder().add(InetAddresses.toAddrString(inetAddress));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
builder.entitiesBuilder().add(createInternalRegistrarEntity(
|
builder
|
||||||
hostResource.getPersistedCurrentSponsorClientId(),
|
.entitiesBuilder()
|
||||||
whoisServer,
|
.add(createInternalRegistrarEntity(hostResource.getPersistedCurrentSponsorClientId()));
|
||||||
now));
|
|
||||||
if (whoisServer != null) {
|
|
||||||
builder.setPort43(Port43WhoisServer.create(whoisServer));
|
|
||||||
}
|
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,16 +361,11 @@ public class RdapJsonFormatter {
|
||||||
*
|
*
|
||||||
* @param contactResource the contact resource object from which the JSON object should be created
|
* @param contactResource the contact resource object from which the JSON object should be created
|
||||||
* @param contactType the contact type to map to an RDAP role; if absent, no role is listed
|
* @param contactType the contact type to map to an RDAP role; if absent, no role is listed
|
||||||
* @param whoisServer the fully-qualified domain name of the WHOIS server to be listed in the
|
|
||||||
* port43 field; if null, port43 is not added to the object
|
|
||||||
* @param now the as-date
|
|
||||||
* @param outputDataType whether to generate full or summary data
|
* @param outputDataType whether to generate full or summary data
|
||||||
*/
|
*/
|
||||||
RdapEntity makeRdapJsonForContact(
|
RdapEntity makeRdapJsonForContact(
|
||||||
ContactResource contactResource,
|
ContactResource contactResource,
|
||||||
Optional<DesignatedContact.Type> contactType,
|
Optional<DesignatedContact.Type> contactType,
|
||||||
@Nullable String whoisServer,
|
|
||||||
DateTime now,
|
|
||||||
OutputDataType outputDataType) {
|
OutputDataType outputDataType) {
|
||||||
boolean isAuthorized =
|
boolean isAuthorized =
|
||||||
rdapAuthorization.isAuthorizedForClientId(contactResource.getCurrentSponsorClientId());
|
rdapAuthorization.isAuthorizedForClientId(contactResource.getCurrentSponsorClientId());
|
||||||
|
@ -408,11 +377,11 @@ public class RdapJsonFormatter {
|
||||||
.statusBuilder()
|
.statusBuilder()
|
||||||
.addAll(
|
.addAll(
|
||||||
makeStatusValueList(
|
makeStatusValueList(
|
||||||
isLinked(Key.create(contactResource), now)
|
isLinked(Key.create(contactResource), getRequestTime())
|
||||||
? union(contactResource.getStatusValues(), StatusValue.LINKED)
|
? union(contactResource.getStatusValues(), StatusValue.LINKED)
|
||||||
: contactResource.getStatusValues(),
|
: contactResource.getStatusValues(),
|
||||||
!isAuthorized,
|
!isAuthorized,
|
||||||
contactResource.getDeletionTime().isBefore(now)));
|
contactResource.getDeletionTime().isBefore(getRequestTime())));
|
||||||
|
|
||||||
contactType.ifPresent(
|
contactType.ifPresent(
|
||||||
type -> entityBuilder.rolesBuilder().add(convertContactTypeToRdapRole(type)));
|
type -> entityBuilder.rolesBuilder().add(convertContactTypeToRdapRole(type)));
|
||||||
|
@ -456,10 +425,7 @@ public class RdapJsonFormatter {
|
||||||
if (outputDataType == OutputDataType.SUMMARY) {
|
if (outputDataType == OutputDataType.SUMMARY) {
|
||||||
entityBuilder.remarksBuilder().add(RdapIcannStandardInformation.SUMMARY_DATA_REMARK);
|
entityBuilder.remarksBuilder().add(RdapIcannStandardInformation.SUMMARY_DATA_REMARK);
|
||||||
} else {
|
} else {
|
||||||
entityBuilder.eventsBuilder().addAll(makeEvents(contactResource, now));
|
entityBuilder.eventsBuilder().addAll(makeEvents(contactResource));
|
||||||
}
|
|
||||||
if (whoisServer != null) {
|
|
||||||
entityBuilder.setPort43(Port43WhoisServer.create(whoisServer));
|
|
||||||
}
|
}
|
||||||
return entityBuilder.build();
|
return entityBuilder.build();
|
||||||
}
|
}
|
||||||
|
@ -468,15 +434,10 @@ public class RdapJsonFormatter {
|
||||||
* Creates a JSON object for a {@link Registrar}.
|
* Creates a JSON object for a {@link Registrar}.
|
||||||
*
|
*
|
||||||
* @param registrar the registrar object from which the JSON object should be created
|
* @param registrar the registrar object from which the JSON object should be created
|
||||||
* @param whoisServer the fully-qualified domain name of the WHOIS server to be listed in the
|
|
||||||
* port43 field; if null, port43 is not added to the object
|
|
||||||
* @param now the as-date
|
|
||||||
* @param outputDataType whether to generate full or summary data
|
* @param outputDataType whether to generate full or summary data
|
||||||
*/
|
*/
|
||||||
RdapEntity makeRdapJsonForRegistrar(
|
RdapEntity makeRdapJsonForRegistrar(
|
||||||
Registrar registrar,
|
Registrar registrar,
|
||||||
@Nullable String whoisServer,
|
|
||||||
DateTime now,
|
|
||||||
OutputDataType outputDataType) {
|
OutputDataType outputDataType) {
|
||||||
RdapEntity.Builder builder = RdapEntity.builder();
|
RdapEntity.Builder builder = RdapEntity.builder();
|
||||||
Long ianaIdentifier = registrar.getIanaIdentifier();
|
Long ianaIdentifier = registrar.getIanaIdentifier();
|
||||||
|
@ -521,11 +482,11 @@ public class RdapJsonFormatter {
|
||||||
if (outputDataType == OutputDataType.SUMMARY) {
|
if (outputDataType == OutputDataType.SUMMARY) {
|
||||||
builder.remarksBuilder().add(RdapIcannStandardInformation.SUMMARY_DATA_REMARK);
|
builder.remarksBuilder().add(RdapIcannStandardInformation.SUMMARY_DATA_REMARK);
|
||||||
} else {
|
} else {
|
||||||
builder.eventsBuilder().addAll(makeEvents(registrar, now));
|
builder.eventsBuilder().addAll(makeEvents(registrar));
|
||||||
// include the registrar contacts as subentities
|
// include the registrar contacts as subentities
|
||||||
ImmutableList<RdapEntity> registrarContacts =
|
ImmutableList<RdapEntity> registrarContacts =
|
||||||
registrar.getContacts().stream()
|
registrar.getContacts().stream()
|
||||||
.map(registrarContact -> makeRdapJsonForRegistrarContact(registrarContact, null))
|
.map(registrarContact -> makeRdapJsonForRegistrarContact(registrarContact))
|
||||||
.filter(optional -> optional.isPresent())
|
.filter(optional -> optional.isPresent())
|
||||||
.map(optional -> optional.get())
|
.map(optional -> optional.get())
|
||||||
.collect(toImmutableList());
|
.collect(toImmutableList());
|
||||||
|
@ -533,9 +494,6 @@ public class RdapJsonFormatter {
|
||||||
// one is required by the RDAP response profile
|
// one is required by the RDAP response profile
|
||||||
builder.entitiesBuilder().addAll(registrarContacts);
|
builder.entitiesBuilder().addAll(registrarContacts);
|
||||||
}
|
}
|
||||||
if (whoisServer != null) {
|
|
||||||
builder.setPort43(Port43WhoisServer.create(whoisServer));
|
|
||||||
}
|
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -545,11 +503,9 @@ public class RdapJsonFormatter {
|
||||||
* <p>Returns empty if this contact shouldn't be visible (doesn't have a role).
|
* <p>Returns empty if this contact shouldn't be visible (doesn't have a role).
|
||||||
*
|
*
|
||||||
* @param registrarContact the registrar contact for which the JSON object should be created
|
* @param registrarContact the registrar contact for which the JSON object should be created
|
||||||
* @param whoisServer the fully-qualified domain name of the WHOIS server to be listed in the
|
|
||||||
* port43 field; if null, port43 is not added to the object
|
|
||||||
*/
|
*/
|
||||||
static Optional<RdapEntity> makeRdapJsonForRegistrarContact(
|
static Optional<RdapEntity> makeRdapJsonForRegistrarContact(
|
||||||
RegistrarContact registrarContact, @Nullable String whoisServer) {
|
RegistrarContact registrarContact) {
|
||||||
ImmutableList<RdapEntity.Role> roles = makeRdapRoleList(registrarContact);
|
ImmutableList<RdapEntity.Role> roles = makeRdapRoleList(registrarContact);
|
||||||
if (roles.isEmpty()) {
|
if (roles.isEmpty()) {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
|
@ -576,9 +532,6 @@ public class RdapJsonFormatter {
|
||||||
vcardBuilder.add(Vcard.create("email", "text", emailAddress));
|
vcardBuilder.add(Vcard.create("email", "text", emailAddress));
|
||||||
}
|
}
|
||||||
builder.setVcardArray(vcardBuilder.build());
|
builder.setVcardArray(vcardBuilder.build());
|
||||||
if (whoisServer != null) {
|
|
||||||
builder.setPort43(Port43WhoisServer.create(whoisServer));
|
|
||||||
}
|
|
||||||
return Optional.of(builder.build());
|
return Optional.of(builder.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -627,7 +580,7 @@ public class RdapJsonFormatter {
|
||||||
/**
|
/**
|
||||||
* Creates an event list for a domain, host or contact resource.
|
* Creates an event list for a domain, host or contact resource.
|
||||||
*/
|
*/
|
||||||
private static ImmutableList<Event> makeEvents(EppResource resource, DateTime now) {
|
private ImmutableList<Event> makeEvents(EppResource resource) {
|
||||||
HashMap<EventAction, HistoryEntry> lastEntryOfType = Maps.newHashMap();
|
HashMap<EventAction, HistoryEntry> lastEntryOfType = Maps.newHashMap();
|
||||||
// Events (such as transfer, but also create) can appear multiple times. We only want the last
|
// Events (such as transfer, but also create) can appear multiple times. We only want the last
|
||||||
// time they appeared.
|
// time they appeared.
|
||||||
|
@ -707,13 +660,13 @@ public class RdapJsonFormatter {
|
||||||
// any EPP update (for example, by the passage of time).
|
// any EPP update (for example, by the passage of time).
|
||||||
DateTime lastChangeTime =
|
DateTime lastChangeTime =
|
||||||
changeTimesBuilder.build().stream()
|
changeTimesBuilder.build().stream()
|
||||||
.filter(changeTime -> changeTime.isBefore(now))
|
.filter(changeTime -> changeTime.isBefore(getRequestTime()))
|
||||||
.max(DateTimeComparator.getInstance())
|
.max(DateTimeComparator.getInstance())
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
if (lastChangeTime != null && lastChangeTime.isAfter(creationTime)) {
|
if (lastChangeTime != null && lastChangeTime.isAfter(creationTime)) {
|
||||||
eventsBuilder.add(makeEvent(EventAction.LAST_CHANGED, null, lastChangeTime));
|
eventsBuilder.add(makeEvent(EventAction.LAST_CHANGED, null, lastChangeTime));
|
||||||
}
|
}
|
||||||
eventsBuilder.add(makeEvent(EventAction.LAST_UPDATE_OF_RDAP_DATABASE, null, now));
|
eventsBuilder.add(makeEvent(EventAction.LAST_UPDATE_OF_RDAP_DATABASE, null, getRequestTime()));
|
||||||
// TODO(b/129849684): sort events by their time once we return a list of Events instead of JSON
|
// TODO(b/129849684): sort events by their time once we return a list of Events instead of JSON
|
||||||
// objects.
|
// objects.
|
||||||
return eventsBuilder.build();
|
return eventsBuilder.build();
|
||||||
|
@ -722,7 +675,7 @@ public class RdapJsonFormatter {
|
||||||
/**
|
/**
|
||||||
* Creates an event list for a {@link Registrar}.
|
* Creates an event list for a {@link Registrar}.
|
||||||
*/
|
*/
|
||||||
private static ImmutableList<Event> makeEvents(Registrar registrar, DateTime now) {
|
private ImmutableList<Event> makeEvents(Registrar registrar) {
|
||||||
ImmutableList.Builder<Event> eventsBuilder = new ImmutableList.Builder<>();
|
ImmutableList.Builder<Event> eventsBuilder = new ImmutableList.Builder<>();
|
||||||
Long ianaIdentifier = registrar.getIanaIdentifier();
|
Long ianaIdentifier = registrar.getIanaIdentifier();
|
||||||
eventsBuilder.add(makeEvent(
|
eventsBuilder.add(makeEvent(
|
||||||
|
@ -734,7 +687,7 @@ public class RdapJsonFormatter {
|
||||||
eventsBuilder.add(makeEvent(
|
eventsBuilder.add(makeEvent(
|
||||||
EventAction.LAST_CHANGED, null, registrar.getLastUpdateTime()));
|
EventAction.LAST_CHANGED, null, registrar.getLastUpdateTime()));
|
||||||
}
|
}
|
||||||
eventsBuilder.add(makeEvent(EventAction.LAST_UPDATE_OF_RDAP_DATABASE, null, now));
|
eventsBuilder.add(makeEvent(EventAction.LAST_UPDATE_OF_RDAP_DATABASE, null, getRequestTime()));
|
||||||
return eventsBuilder.build();
|
return eventsBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -884,4 +837,26 @@ public class RdapJsonFormatter {
|
||||||
.setType("application/rdap+json")
|
.setType("application/rdap+json")
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the DateTime this request took place.
|
||||||
|
*
|
||||||
|
* <p>The RDAP reply is large with a lot of different object in them. We want to make sure that
|
||||||
|
* all these objects are projected to the same "now".
|
||||||
|
*
|
||||||
|
* <p>This "now" will also be considered the time of the "last update of RDAP database" event that
|
||||||
|
* RDAP sepc requires.
|
||||||
|
*
|
||||||
|
* <p>We would have set this during the constructor, but the clock is injected after construction.
|
||||||
|
* So instead we set the time during the first call to this function.
|
||||||
|
*
|
||||||
|
* <p>We would like even more to just inject it in RequestModule and use it in many places in our
|
||||||
|
* codebase that just need a general "now" of the request, but that's a lot of work.
|
||||||
|
*/
|
||||||
|
DateTime getRequestTime() {
|
||||||
|
if (requestTime == null) {
|
||||||
|
requestTime = clock.nowUtc();
|
||||||
|
}
|
||||||
|
return requestTime;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,6 @@ import google.registry.request.HttpException.NotFoundException;
|
||||||
import google.registry.request.auth.Auth;
|
import google.registry.request.auth.Auth;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import org.joda.time.DateTime;
|
|
||||||
|
|
||||||
/** RDAP (new WHOIS) action for nameserver requests. */
|
/** RDAP (new WHOIS) action for nameserver requests. */
|
||||||
@Action(
|
@Action(
|
||||||
|
@ -48,7 +47,6 @@ public class RdapNameserverAction extends RdapActionBase {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RdapNameserver getJsonObjectForResource(String pathSearchString, boolean isHeadRequest) {
|
public RdapNameserver getJsonObjectForResource(String pathSearchString, boolean isHeadRequest) {
|
||||||
DateTime now = clock.nowUtc();
|
|
||||||
pathSearchString = canonicalizeName(pathSearchString);
|
pathSearchString = canonicalizeName(pathSearchString);
|
||||||
// The RDAP syntax is /rdap/nameserver/ns1.mydomain.com.
|
// The RDAP syntax is /rdap/nameserver/ns1.mydomain.com.
|
||||||
try {
|
try {
|
||||||
|
@ -63,11 +61,12 @@ public class RdapNameserverAction extends RdapActionBase {
|
||||||
// the most recently deleted one.
|
// the most recently deleted one.
|
||||||
Optional<HostResource> hostResource =
|
Optional<HostResource> hostResource =
|
||||||
loadByForeignKey(
|
loadByForeignKey(
|
||||||
HostResource.class, pathSearchString, shouldIncludeDeleted() ? START_OF_TIME : now);
|
HostResource.class,
|
||||||
if (!shouldBeVisible(hostResource, now)) {
|
pathSearchString,
|
||||||
|
shouldIncludeDeleted() ? START_OF_TIME : getRequestTime());
|
||||||
|
if (!shouldBeVisible(hostResource)) {
|
||||||
throw new NotFoundException(pathSearchString + " not found");
|
throw new NotFoundException(pathSearchString + " not found");
|
||||||
}
|
}
|
||||||
return rdapJsonFormatter.makeRdapJsonForHost(
|
return rdapJsonFormatter.makeRdapJsonForHost(hostResource.get(), OutputDataType.FULL);
|
||||||
hostResource.get(), rdapWhoisServer, now, OutputDataType.FULL);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,6 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import org.joda.time.DateTime;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RDAP (new WHOIS) action for nameserver search requests.
|
* RDAP (new WHOIS) action for nameserver search requests.
|
||||||
|
@ -82,7 +81,6 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
||||||
@Override
|
@Override
|
||||||
public NameserverSearchResponse getJsonObjectForResource(
|
public NameserverSearchResponse getJsonObjectForResource(
|
||||||
String pathSearchString, boolean isHeadRequest) {
|
String pathSearchString, boolean isHeadRequest) {
|
||||||
DateTime now = clock.nowUtc();
|
|
||||||
// RDAP syntax example: /rdap/nameservers?name=ns*.example.com.
|
// RDAP syntax example: /rdap/nameservers?name=ns*.example.com.
|
||||||
// The pathSearchString is not used by search commands.
|
// The pathSearchString is not used by search commands.
|
||||||
if (pathSearchString.length() > 0) {
|
if (pathSearchString.length() > 0) {
|
||||||
|
@ -103,8 +101,7 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
||||||
}
|
}
|
||||||
results =
|
results =
|
||||||
searchByName(
|
searchByName(
|
||||||
recordWildcardType(RdapSearchPattern.create(Idn.toASCII(nameParam.get()), true)),
|
recordWildcardType(RdapSearchPattern.create(Idn.toASCII(nameParam.get()), true)));
|
||||||
now);
|
|
||||||
} else {
|
} else {
|
||||||
// syntax: /rdap/nameservers?ip=1.2.3.4
|
// syntax: /rdap/nameservers?ip=1.2.3.4
|
||||||
metricInformationBuilder.setSearchType(SearchType.BY_NAMESERVER_ADDRESS);
|
metricInformationBuilder.setSearchType(SearchType.BY_NAMESERVER_ADDRESS);
|
||||||
|
@ -114,7 +111,7 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
throw new BadRequestException("Invalid value of ip parameter");
|
throw new BadRequestException("Invalid value of ip parameter");
|
||||||
}
|
}
|
||||||
results = searchByIp(inetAddress, now);
|
results = searchByIp(inetAddress);
|
||||||
}
|
}
|
||||||
if (results.nameserverSearchResults().isEmpty()) {
|
if (results.nameserverSearchResults().isEmpty()) {
|
||||||
throw new NotFoundException("No nameservers found");
|
throw new NotFoundException("No nameservers found");
|
||||||
|
@ -128,12 +125,11 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
||||||
* <p>When deleted nameservers are included in the search, the search is treated as if it has a
|
* <p>When deleted nameservers are included in the search, the search is treated as if it has a
|
||||||
* wildcard, because multiple results can be returned.
|
* wildcard, because multiple results can be returned.
|
||||||
*/
|
*/
|
||||||
private NameserverSearchResponse searchByName(
|
private NameserverSearchResponse searchByName(final RdapSearchPattern partialStringQuery) {
|
||||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
|
||||||
// Handle queries without a wildcard -- just load by foreign key. We can't do this if deleted
|
// Handle queries without a wildcard -- just load by foreign key. We can't do this if deleted
|
||||||
// nameservers are desired, because there may be multiple nameservers with the same name.
|
// nameservers are desired, because there may be multiple nameservers with the same name.
|
||||||
if (!partialStringQuery.getHasWildcard() && !shouldIncludeDeleted()) {
|
if (!partialStringQuery.getHasWildcard() && !shouldIncludeDeleted()) {
|
||||||
return searchByNameUsingForeignKey(partialStringQuery, now);
|
return searchByNameUsingForeignKey(partialStringQuery);
|
||||||
// Handle queries with a wildcard (or including deleted entries). If there is a suffix, it
|
// Handle queries with a wildcard (or including deleted entries). If there is a suffix, it
|
||||||
// should be a domain that we manage, so we can look up the domain and search through the
|
// should be a domain that we manage, so we can look up the domain and search through the
|
||||||
// subordinate hosts. This is more efficient, and lets us permit wildcard searches with no
|
// subordinate hosts. This is more efficient, and lets us permit wildcard searches with no
|
||||||
|
@ -145,10 +141,10 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
||||||
throw new UnprocessableEntityException(
|
throw new UnprocessableEntityException(
|
||||||
"A suffix after a wildcard is not allowed when searching for deleted nameservers");
|
"A suffix after a wildcard is not allowed when searching for deleted nameservers");
|
||||||
}
|
}
|
||||||
return searchByNameUsingSuperordinateDomain(partialStringQuery, now);
|
return searchByNameUsingSuperordinateDomain(partialStringQuery);
|
||||||
// Handle queries with a wildcard (or deleted entries included), but no suffix.
|
// Handle queries with a wildcard (or deleted entries included), but no suffix.
|
||||||
} else {
|
} else {
|
||||||
return searchByNameUsingPrefix(partialStringQuery, now);
|
return searchByNameUsingPrefix(partialStringQuery);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,10 +154,11 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
||||||
* <p>In this case, we can load by foreign key.
|
* <p>In this case, we can load by foreign key.
|
||||||
*/
|
*/
|
||||||
private NameserverSearchResponse searchByNameUsingForeignKey(
|
private NameserverSearchResponse searchByNameUsingForeignKey(
|
||||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
RdapSearchPattern partialStringQuery) {
|
||||||
Optional<HostResource> hostResource =
|
Optional<HostResource> hostResource =
|
||||||
loadByForeignKey(HostResource.class, partialStringQuery.getInitialString(), now);
|
loadByForeignKey(
|
||||||
if (!shouldBeVisible(hostResource, now)) {
|
HostResource.class, partialStringQuery.getInitialString(), getRequestTime());
|
||||||
|
if (!shouldBeVisible(hostResource)) {
|
||||||
metricInformationBuilder.setNumHostsRetrieved(0);
|
metricInformationBuilder.setNumHostsRetrieved(0);
|
||||||
throw new NotFoundException("No nameservers found");
|
throw new NotFoundException("No nameservers found");
|
||||||
}
|
}
|
||||||
|
@ -173,17 +170,15 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
||||||
builder.nameserverSearchResultsBuilder().add(
|
builder.nameserverSearchResultsBuilder().add(
|
||||||
rdapJsonFormatter.makeRdapJsonForHost(
|
rdapJsonFormatter.makeRdapJsonForHost(
|
||||||
hostResource.get(),
|
hostResource.get(),
|
||||||
rdapWhoisServer,
|
|
||||||
now,
|
|
||||||
OutputDataType.FULL));
|
OutputDataType.FULL));
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Searches for nameservers by name using the superordinate domain as a suffix. */
|
/** Searches for nameservers by name using the superordinate domain as a suffix. */
|
||||||
private NameserverSearchResponse searchByNameUsingSuperordinateDomain(
|
private NameserverSearchResponse searchByNameUsingSuperordinateDomain(
|
||||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
RdapSearchPattern partialStringQuery) {
|
||||||
Optional<DomainBase> domainBase =
|
Optional<DomainBase> domainBase =
|
||||||
loadByForeignKey(DomainBase.class, partialStringQuery.getSuffix(), now);
|
loadByForeignKey(DomainBase.class, partialStringQuery.getSuffix(), getRequestTime());
|
||||||
if (!domainBase.isPresent()) {
|
if (!domainBase.isPresent()) {
|
||||||
// Don't allow wildcards with suffixes which are not domains we manage. That would risk a
|
// 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,
|
// table scan in many easily foreseeable cases. The user might ask for ns*.zombo.com,
|
||||||
|
@ -201,8 +196,9 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
||||||
// We can't just check that the host name starts with the initial query string, because
|
// We can't just check that the host name starts with the initial query string, because
|
||||||
// then the query ns.exam*.example.com would match against nameserver ns.example.com.
|
// then the query ns.exam*.example.com would match against nameserver ns.example.com.
|
||||||
if (partialStringQuery.matches(fqhn)) {
|
if (partialStringQuery.matches(fqhn)) {
|
||||||
Optional<HostResource> hostResource = loadByForeignKey(HostResource.class, fqhn, now);
|
Optional<HostResource> hostResource =
|
||||||
if (shouldBeVisible(hostResource, now)) {
|
loadByForeignKey(HostResource.class, fqhn, getRequestTime());
|
||||||
|
if (shouldBeVisible(hostResource)) {
|
||||||
hostList.add(hostResource.get());
|
hostList.add(hostResource.get());
|
||||||
if (hostList.size() > rdapResultSetMaxSize) {
|
if (hostList.size() > rdapResultSetMaxSize) {
|
||||||
break;
|
break;
|
||||||
|
@ -214,8 +210,7 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
||||||
hostList,
|
hostList,
|
||||||
IncompletenessWarningType.COMPLETE,
|
IncompletenessWarningType.COMPLETE,
|
||||||
domainBase.get().getSubordinateHosts().size(),
|
domainBase.get().getSubordinateHosts().size(),
|
||||||
CursorType.NAME,
|
CursorType.NAME);
|
||||||
now);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -223,8 +218,7 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
||||||
*
|
*
|
||||||
* <p>There are no pending deletes for hosts, so we can call {@link RdapActionBase#queryItems}.
|
* <p>There are no pending deletes for hosts, so we can call {@link RdapActionBase#queryItems}.
|
||||||
*/
|
*/
|
||||||
private NameserverSearchResponse searchByNameUsingPrefix(
|
private NameserverSearchResponse searchByNameUsingPrefix(RdapSearchPattern partialStringQuery) {
|
||||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
|
||||||
// Add 1 so we can detect truncation.
|
// Add 1 so we can detect truncation.
|
||||||
int querySizeLimit = getStandardQuerySizeLimit();
|
int querySizeLimit = getStandardQuerySizeLimit();
|
||||||
Query<HostResource> query =
|
Query<HostResource> query =
|
||||||
|
@ -236,13 +230,12 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
||||||
getDeletedItemHandling(),
|
getDeletedItemHandling(),
|
||||||
querySizeLimit);
|
querySizeLimit);
|
||||||
return makeSearchResults(
|
return makeSearchResults(
|
||||||
getMatchingResources(query, shouldIncludeDeleted(), now, querySizeLimit),
|
getMatchingResources(query, shouldIncludeDeleted(), querySizeLimit),
|
||||||
CursorType.NAME,
|
CursorType.NAME);
|
||||||
now);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Searches for nameservers by IP address, returning a JSON array of nameserver info maps. */
|
/** Searches for nameservers by IP address, returning a JSON array of nameserver info maps. */
|
||||||
private NameserverSearchResponse searchByIp(final InetAddress inetAddress, DateTime now) {
|
private NameserverSearchResponse searchByIp(InetAddress inetAddress) {
|
||||||
// Add 1 so we can detect truncation.
|
// Add 1 so we can detect truncation.
|
||||||
int querySizeLimit = getStandardQuerySizeLimit();
|
int querySizeLimit = getStandardQuerySizeLimit();
|
||||||
Query<HostResource> query =
|
Query<HostResource> query =
|
||||||
|
@ -255,20 +248,18 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
||||||
getDeletedItemHandling(),
|
getDeletedItemHandling(),
|
||||||
querySizeLimit);
|
querySizeLimit);
|
||||||
return makeSearchResults(
|
return makeSearchResults(
|
||||||
getMatchingResources(query, shouldIncludeDeleted(), now, querySizeLimit),
|
getMatchingResources(query, shouldIncludeDeleted(), querySizeLimit),
|
||||||
CursorType.ADDRESS,
|
CursorType.ADDRESS);
|
||||||
now);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Output JSON for a lists of hosts contained in an {@link RdapResultSet}. */
|
/** Output JSON for a lists of hosts contained in an {@link RdapResultSet}. */
|
||||||
private NameserverSearchResponse makeSearchResults(
|
private NameserverSearchResponse makeSearchResults(
|
||||||
RdapResultSet<HostResource> resultSet, CursorType cursorType, DateTime now) {
|
RdapResultSet<HostResource> resultSet, CursorType cursorType) {
|
||||||
return makeSearchResults(
|
return makeSearchResults(
|
||||||
resultSet.resources(),
|
resultSet.resources(),
|
||||||
resultSet.incompletenessWarningType(),
|
resultSet.incompletenessWarningType(),
|
||||||
resultSet.numResourcesRetrieved(),
|
resultSet.numResourcesRetrieved(),
|
||||||
cursorType,
|
cursorType);
|
||||||
now);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Output JSON for a list of hosts. */
|
/** Output JSON for a list of hosts. */
|
||||||
|
@ -276,8 +267,7 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
||||||
List<HostResource> hosts,
|
List<HostResource> hosts,
|
||||||
IncompletenessWarningType incompletenessWarningType,
|
IncompletenessWarningType incompletenessWarningType,
|
||||||
int numHostsRetrieved,
|
int numHostsRetrieved,
|
||||||
CursorType cursorType,
|
CursorType cursorType) {
|
||||||
DateTime now) {
|
|
||||||
metricInformationBuilder.setNumHostsRetrieved(numHostsRetrieved);
|
metricInformationBuilder.setNumHostsRetrieved(numHostsRetrieved);
|
||||||
OutputDataType outputDataType =
|
OutputDataType outputDataType =
|
||||||
(hosts.size() > 1) ? OutputDataType.SUMMARY : OutputDataType.FULL;
|
(hosts.size() > 1) ? OutputDataType.SUMMARY : OutputDataType.FULL;
|
||||||
|
@ -290,9 +280,9 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
||||||
(cursorType == CursorType.NAME)
|
(cursorType == CursorType.NAME)
|
||||||
? host.getFullyQualifiedHostName()
|
? host.getFullyQualifiedHostName()
|
||||||
: host.getRepoId());
|
: host.getRepoId());
|
||||||
builder.nameserverSearchResultsBuilder().add(
|
builder
|
||||||
rdapJsonFormatter.makeRdapJsonForHost(
|
.nameserverSearchResultsBuilder()
|
||||||
host, rdapWhoisServer, now, outputDataType));
|
.add(rdapJsonFormatter.makeRdapJsonForHost(host, outputDataType));
|
||||||
}
|
}
|
||||||
if (rdapResultSetMaxSize < hosts.size()) {
|
if (rdapResultSetMaxSize < hosts.size()) {
|
||||||
builder.setNextPageUri(createNavigationUri(newCursor.get()));
|
builder.setNextPageUri(createNavigationUri(newCursor.get()));
|
||||||
|
|
|
@ -205,9 +205,18 @@ final class RdapObjectClasses {
|
||||||
@JsonableElement abstract ImmutableList<RdapStatus> status();
|
@JsonableElement abstract ImmutableList<RdapStatus> status();
|
||||||
@JsonableElement abstract ImmutableList<Remark> remarks();
|
@JsonableElement abstract ImmutableList<Remark> remarks();
|
||||||
@JsonableElement abstract ImmutableList<Link> links();
|
@JsonableElement abstract ImmutableList<Link> links();
|
||||||
@JsonableElement abstract Optional<Port43WhoisServer> port43();
|
|
||||||
@JsonableElement abstract ImmutableList<Event> events();
|
@JsonableElement abstract ImmutableList<Event> events();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WHOIS server displayed in RDAP query responses.
|
||||||
|
*
|
||||||
|
* <p>As per Gustavo Lozano of ICANN, this should be omitted, but the ICANN operational profile
|
||||||
|
* doesn't actually say that, so it's good to have the ability to reinstate this field if
|
||||||
|
* necessary.
|
||||||
|
*/
|
||||||
|
@JsonableElement
|
||||||
|
abstract Optional<Port43WhoisServer> port43();
|
||||||
|
|
||||||
RdapObjectBase(BoilerplateType boilerplateType, ObjectClassName objectClassName) {
|
RdapObjectBase(BoilerplateType boilerplateType, ObjectClassName objectClassName) {
|
||||||
super(boilerplateType);
|
super(boilerplateType);
|
||||||
this.objectClassName = objectClassName;
|
this.objectClassName = objectClassName;
|
||||||
|
|
|
@ -17,6 +17,7 @@ package google.registry.request;
|
||||||
import static com.google.common.net.MediaType.JSON_UTF_8;
|
import static com.google.common.net.MediaType.JSON_UTF_8;
|
||||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||||
|
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.base.VerifyException;
|
import com.google.common.base.VerifyException;
|
||||||
import com.google.common.collect.ImmutableListMultimap;
|
import com.google.common.collect.ImmutableListMultimap;
|
||||||
import com.google.common.io.ByteStreams;
|
import com.google.common.io.ByteStreams;
|
||||||
|
@ -47,6 +48,7 @@ public final class RequestModule {
|
||||||
private final HttpServletResponse rsp;
|
private final HttpServletResponse rsp;
|
||||||
private final AuthResult authResult;
|
private final AuthResult authResult;
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
public RequestModule(
|
public RequestModule(
|
||||||
HttpServletRequest req, HttpServletResponse rsp) {
|
HttpServletRequest req, HttpServletResponse rsp) {
|
||||||
this(req, rsp, AuthResult.NOT_AUTHENTICATED);
|
this(req, rsp, AuthResult.NOT_AUTHENTICATED);
|
||||||
|
|
|
@ -73,7 +73,6 @@ public class RdapActionBaseTest extends RdapActionBaseTestCase<RdapActionBaseTes
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
createTld("thing");
|
createTld("thing");
|
||||||
action.rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -89,15 +89,13 @@ public class RdapActionBaseTestCase<A extends RdapActionBase> {
|
||||||
public void baseSetUp() {
|
public void baseSetUp() {
|
||||||
inject.setStaticField(Ofy.class, "clock", clock);
|
inject.setStaticField(Ofy.class, "clock", clock);
|
||||||
action = TypeUtils.instantiate(rdapActionClass);
|
action = TypeUtils.instantiate(rdapActionClass);
|
||||||
action.clock = clock;
|
|
||||||
action.includeDeletedParam = Optional.empty();
|
action.includeDeletedParam = Optional.empty();
|
||||||
action.registrarParam = Optional.empty();
|
action.registrarParam = Optional.empty();
|
||||||
action.formatOutputParam = Optional.empty();
|
action.formatOutputParam = Optional.empty();
|
||||||
action.response = response;
|
action.response = response;
|
||||||
action.rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter();
|
action.rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter(clock);
|
||||||
action.rdapMetrics = rdapMetrics;
|
action.rdapMetrics = rdapMetrics;
|
||||||
action.requestMethod = Action.Method.GET;
|
action.requestMethod = Action.Method.GET;
|
||||||
action.rdapWhoisServer = null;
|
|
||||||
logout();
|
logout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,14 +86,12 @@ public class RdapJsonFormatterTest {
|
||||||
private ContactResource contactResourceTech;
|
private ContactResource contactResourceTech;
|
||||||
private ContactResource contactResourceNotLinked;
|
private ContactResource contactResourceNotLinked;
|
||||||
|
|
||||||
// Do not set a port43 whois server, as per Gustavo Lozano.
|
|
||||||
private static final String WHOIS_SERVER = null;
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
inject.setStaticField(Ofy.class, "clock", clock);
|
inject.setStaticField(Ofy.class, "clock", clock);
|
||||||
|
|
||||||
rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter();
|
rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter(clock);
|
||||||
rdapJsonFormatter.rdapAuthorization =
|
rdapJsonFormatter.rdapAuthorization =
|
||||||
RdapAuthorization.create(RdapAuthorization.Role.REGISTRAR, "unicoderegistrar");
|
RdapAuthorization.create(RdapAuthorization.Role.REGISTRAR, "unicoderegistrar");
|
||||||
|
|
||||||
|
@ -315,51 +313,35 @@ public class RdapJsonFormatterTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRegistrar() {
|
public void testRegistrar() {
|
||||||
assertThat(
|
assertThat(rdapJsonFormatter.makeRdapJsonForRegistrar(registrar, OutputDataType.FULL).toJson())
|
||||||
rdapJsonFormatter
|
|
||||||
.makeRdapJsonForRegistrar(
|
|
||||||
registrar, WHOIS_SERVER, clock.nowUtc(), OutputDataType.FULL)
|
|
||||||
.toJson())
|
|
||||||
.isEqualTo(loadJson("rdapjson_registrar.json"));
|
.isEqualTo(loadJson("rdapjson_registrar.json"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRegistrar_summary() {
|
public void testRegistrar_summary() {
|
||||||
assertThat(
|
assertThat(
|
||||||
rdapJsonFormatter
|
rdapJsonFormatter.makeRdapJsonForRegistrar(registrar, OutputDataType.SUMMARY).toJson())
|
||||||
.makeRdapJsonForRegistrar(
|
|
||||||
registrar, WHOIS_SERVER, clock.nowUtc(), OutputDataType.SUMMARY)
|
|
||||||
.toJson())
|
|
||||||
.isEqualTo(loadJson("rdapjson_registrar_summary.json"));
|
.isEqualTo(loadJson("rdapjson_registrar_summary.json"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHost_ipv4() {
|
public void testHost_ipv4() {
|
||||||
assertThat(
|
assertThat(
|
||||||
rdapJsonFormatter
|
rdapJsonFormatter.makeRdapJsonForHost(hostResourceIpv4, OutputDataType.FULL).toJson())
|
||||||
.makeRdapJsonForHost(
|
|
||||||
hostResourceIpv4, WHOIS_SERVER, clock.nowUtc(), OutputDataType.FULL)
|
|
||||||
.toJson())
|
|
||||||
.isEqualTo(loadJson("rdapjson_host_ipv4.json"));
|
.isEqualTo(loadJson("rdapjson_host_ipv4.json"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHost_ipv6() {
|
public void testHost_ipv6() {
|
||||||
assertThat(
|
assertThat(
|
||||||
rdapJsonFormatter
|
rdapJsonFormatter.makeRdapJsonForHost(hostResourceIpv6, OutputDataType.FULL).toJson())
|
||||||
.makeRdapJsonForHost(
|
|
||||||
hostResourceIpv6, WHOIS_SERVER, clock.nowUtc(), OutputDataType.FULL)
|
|
||||||
.toJson())
|
|
||||||
.isEqualTo(loadJson("rdapjson_host_ipv6.json"));
|
.isEqualTo(loadJson("rdapjson_host_ipv6.json"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHost_both() {
|
public void testHost_both() {
|
||||||
assertThat(
|
assertThat(
|
||||||
rdapJsonFormatter
|
rdapJsonFormatter.makeRdapJsonForHost(hostResourceBoth, OutputDataType.FULL).toJson())
|
||||||
.makeRdapJsonForHost(
|
|
||||||
hostResourceBoth, WHOIS_SERVER, clock.nowUtc(), OutputDataType.FULL)
|
|
||||||
.toJson())
|
|
||||||
.isEqualTo(loadJson("rdapjson_host_both.json"));
|
.isEqualTo(loadJson("rdapjson_host_both.json"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,8 +349,7 @@ public class RdapJsonFormatterTest {
|
||||||
public void testHost_both_summary() {
|
public void testHost_both_summary() {
|
||||||
assertThat(
|
assertThat(
|
||||||
rdapJsonFormatter
|
rdapJsonFormatter
|
||||||
.makeRdapJsonForHost(
|
.makeRdapJsonForHost(hostResourceBoth, OutputDataType.SUMMARY)
|
||||||
hostResourceBoth, WHOIS_SERVER, clock.nowUtc(), OutputDataType.SUMMARY)
|
|
||||||
.toJson())
|
.toJson())
|
||||||
.isEqualTo(loadJson("rdapjson_host_both_summary.json"));
|
.isEqualTo(loadJson("rdapjson_host_both_summary.json"));
|
||||||
}
|
}
|
||||||
|
@ -377,8 +358,7 @@ public class RdapJsonFormatterTest {
|
||||||
public void testHost_noAddresses() {
|
public void testHost_noAddresses() {
|
||||||
assertThat(
|
assertThat(
|
||||||
rdapJsonFormatter
|
rdapJsonFormatter
|
||||||
.makeRdapJsonForHost(
|
.makeRdapJsonForHost(hostResourceNoAddresses, OutputDataType.FULL)
|
||||||
hostResourceNoAddresses, WHOIS_SERVER, clock.nowUtc(), OutputDataType.FULL)
|
|
||||||
.toJson())
|
.toJson())
|
||||||
.isEqualTo(loadJson("rdapjson_host_no_addresses.json"));
|
.isEqualTo(loadJson("rdapjson_host_no_addresses.json"));
|
||||||
}
|
}
|
||||||
|
@ -387,8 +367,7 @@ public class RdapJsonFormatterTest {
|
||||||
public void testHost_notLinked() {
|
public void testHost_notLinked() {
|
||||||
assertThat(
|
assertThat(
|
||||||
rdapJsonFormatter
|
rdapJsonFormatter
|
||||||
.makeRdapJsonForHost(
|
.makeRdapJsonForHost(hostResourceNotLinked, OutputDataType.FULL)
|
||||||
hostResourceNotLinked, WHOIS_SERVER, clock.nowUtc(), OutputDataType.FULL)
|
|
||||||
.toJson())
|
.toJson())
|
||||||
.isEqualTo(loadJson("rdapjson_host_not_linked.json"));
|
.isEqualTo(loadJson("rdapjson_host_not_linked.json"));
|
||||||
}
|
}
|
||||||
|
@ -397,11 +376,7 @@ public class RdapJsonFormatterTest {
|
||||||
public void testHost_superordinateHasPendingTransfer() {
|
public void testHost_superordinateHasPendingTransfer() {
|
||||||
assertThat(
|
assertThat(
|
||||||
rdapJsonFormatter
|
rdapJsonFormatter
|
||||||
.makeRdapJsonForHost(
|
.makeRdapJsonForHost(hostResourceSuperordinatePendingTransfer, OutputDataType.FULL)
|
||||||
hostResourceSuperordinatePendingTransfer,
|
|
||||||
WHOIS_SERVER,
|
|
||||||
clock.nowUtc(),
|
|
||||||
OutputDataType.FULL)
|
|
||||||
.toJson())
|
.toJson())
|
||||||
.isEqualTo(loadJson("rdapjson_host_pending_transfer.json"));
|
.isEqualTo(loadJson("rdapjson_host_pending_transfer.json"));
|
||||||
}
|
}
|
||||||
|
@ -413,8 +388,6 @@ public class RdapJsonFormatterTest {
|
||||||
.makeRdapJsonForContact(
|
.makeRdapJsonForContact(
|
||||||
contactResourceRegistrant,
|
contactResourceRegistrant,
|
||||||
Optional.of(DesignatedContact.Type.REGISTRANT),
|
Optional.of(DesignatedContact.Type.REGISTRANT),
|
||||||
WHOIS_SERVER,
|
|
||||||
clock.nowUtc(),
|
|
||||||
OutputDataType.FULL)
|
OutputDataType.FULL)
|
||||||
.toJson())
|
.toJson())
|
||||||
.isEqualTo(loadJson("rdapjson_registrant.json"));
|
.isEqualTo(loadJson("rdapjson_registrant.json"));
|
||||||
|
@ -427,8 +400,6 @@ public class RdapJsonFormatterTest {
|
||||||
.makeRdapJsonForContact(
|
.makeRdapJsonForContact(
|
||||||
contactResourceRegistrant,
|
contactResourceRegistrant,
|
||||||
Optional.of(DesignatedContact.Type.REGISTRANT),
|
Optional.of(DesignatedContact.Type.REGISTRANT),
|
||||||
WHOIS_SERVER,
|
|
||||||
clock.nowUtc(),
|
|
||||||
OutputDataType.SUMMARY)
|
OutputDataType.SUMMARY)
|
||||||
.toJson())
|
.toJson())
|
||||||
.isEqualTo(loadJson("rdapjson_registrant_summary.json"));
|
.isEqualTo(loadJson("rdapjson_registrant_summary.json"));
|
||||||
|
@ -442,8 +413,6 @@ public class RdapJsonFormatterTest {
|
||||||
.makeRdapJsonForContact(
|
.makeRdapJsonForContact(
|
||||||
contactResourceRegistrant,
|
contactResourceRegistrant,
|
||||||
Optional.of(DesignatedContact.Type.REGISTRANT),
|
Optional.of(DesignatedContact.Type.REGISTRANT),
|
||||||
WHOIS_SERVER,
|
|
||||||
clock.nowUtc(),
|
|
||||||
OutputDataType.FULL)
|
OutputDataType.FULL)
|
||||||
.toJson())
|
.toJson())
|
||||||
.isEqualTo(loadJson("rdapjson_registrant_logged_out.json"));
|
.isEqualTo(loadJson("rdapjson_registrant_logged_out.json"));
|
||||||
|
@ -463,8 +432,6 @@ public class RdapJsonFormatterTest {
|
||||||
.makeRdapJsonForContact(
|
.makeRdapJsonForContact(
|
||||||
contactResourceRegistrant,
|
contactResourceRegistrant,
|
||||||
Optional.of(DesignatedContact.Type.REGISTRANT),
|
Optional.of(DesignatedContact.Type.REGISTRANT),
|
||||||
WHOIS_SERVER,
|
|
||||||
clock.nowUtc(),
|
|
||||||
OutputDataType.FULL)
|
OutputDataType.FULL)
|
||||||
.toJson())
|
.toJson())
|
||||||
.isEqualTo(loadJson("rdapjson_registrant.json"));
|
.isEqualTo(loadJson("rdapjson_registrant.json"));
|
||||||
|
@ -477,8 +444,6 @@ public class RdapJsonFormatterTest {
|
||||||
.makeRdapJsonForContact(
|
.makeRdapJsonForContact(
|
||||||
contactResourceAdmin,
|
contactResourceAdmin,
|
||||||
Optional.of(DesignatedContact.Type.ADMIN),
|
Optional.of(DesignatedContact.Type.ADMIN),
|
||||||
WHOIS_SERVER,
|
|
||||||
clock.nowUtc(),
|
|
||||||
OutputDataType.FULL)
|
OutputDataType.FULL)
|
||||||
.toJson())
|
.toJson())
|
||||||
.isEqualTo(loadJson("rdapjson_admincontact.json"));
|
.isEqualTo(loadJson("rdapjson_admincontact.json"));
|
||||||
|
@ -491,8 +456,6 @@ public class RdapJsonFormatterTest {
|
||||||
.makeRdapJsonForContact(
|
.makeRdapJsonForContact(
|
||||||
contactResourceTech,
|
contactResourceTech,
|
||||||
Optional.of(DesignatedContact.Type.TECH),
|
Optional.of(DesignatedContact.Type.TECH),
|
||||||
WHOIS_SERVER,
|
|
||||||
clock.nowUtc(),
|
|
||||||
OutputDataType.FULL)
|
OutputDataType.FULL)
|
||||||
.toJson())
|
.toJson())
|
||||||
.isEqualTo(loadJson("rdapjson_techcontact.json"));
|
.isEqualTo(loadJson("rdapjson_techcontact.json"));
|
||||||
|
@ -505,8 +468,6 @@ public class RdapJsonFormatterTest {
|
||||||
.makeRdapJsonForContact(
|
.makeRdapJsonForContact(
|
||||||
contactResourceTech,
|
contactResourceTech,
|
||||||
Optional.empty(),
|
Optional.empty(),
|
||||||
WHOIS_SERVER,
|
|
||||||
clock.nowUtc(),
|
|
||||||
OutputDataType.FULL)
|
OutputDataType.FULL)
|
||||||
.toJson())
|
.toJson())
|
||||||
.isEqualTo(loadJson("rdapjson_rolelesscontact.json"));
|
.isEqualTo(loadJson("rdapjson_rolelesscontact.json"));
|
||||||
|
@ -519,8 +480,6 @@ public class RdapJsonFormatterTest {
|
||||||
.makeRdapJsonForContact(
|
.makeRdapJsonForContact(
|
||||||
contactResourceNotLinked,
|
contactResourceNotLinked,
|
||||||
Optional.empty(),
|
Optional.empty(),
|
||||||
WHOIS_SERVER,
|
|
||||||
clock.nowUtc(),
|
|
||||||
OutputDataType.FULL)
|
OutputDataType.FULL)
|
||||||
.toJson())
|
.toJson())
|
||||||
.isEqualTo(loadJson("rdapjson_unlinkedcontact.json"));
|
.isEqualTo(loadJson("rdapjson_unlinkedcontact.json"));
|
||||||
|
@ -532,8 +491,6 @@ public class RdapJsonFormatterTest {
|
||||||
rdapJsonFormatter
|
rdapJsonFormatter
|
||||||
.makeRdapJsonForDomain(
|
.makeRdapJsonForDomain(
|
||||||
domainBaseFull,
|
domainBaseFull,
|
||||||
WHOIS_SERVER,
|
|
||||||
clock.nowUtc(),
|
|
||||||
OutputDataType.FULL)
|
OutputDataType.FULL)
|
||||||
.toJson())
|
.toJson())
|
||||||
.isEqualTo(loadJson("rdapjson_domain_full.json"));
|
.isEqualTo(loadJson("rdapjson_domain_full.json"));
|
||||||
|
@ -543,11 +500,7 @@ public class RdapJsonFormatterTest {
|
||||||
public void testDomain_summary() {
|
public void testDomain_summary() {
|
||||||
assertThat(
|
assertThat(
|
||||||
rdapJsonFormatter
|
rdapJsonFormatter
|
||||||
.makeRdapJsonForDomain(
|
.makeRdapJsonForDomain(domainBaseFull, OutputDataType.SUMMARY)
|
||||||
domainBaseFull,
|
|
||||||
WHOIS_SERVER,
|
|
||||||
clock.nowUtc(),
|
|
||||||
OutputDataType.SUMMARY)
|
|
||||||
.toJson())
|
.toJson())
|
||||||
.isEqualTo(loadJson("rdapjson_domain_summary.json"));
|
.isEqualTo(loadJson("rdapjson_domain_summary.json"));
|
||||||
}
|
}
|
||||||
|
@ -556,13 +509,7 @@ public class RdapJsonFormatterTest {
|
||||||
public void testDomain_logged_out() {
|
public void testDomain_logged_out() {
|
||||||
rdapJsonFormatter.rdapAuthorization = RdapAuthorization.PUBLIC_AUTHORIZATION;
|
rdapJsonFormatter.rdapAuthorization = RdapAuthorization.PUBLIC_AUTHORIZATION;
|
||||||
assertThat(
|
assertThat(
|
||||||
rdapJsonFormatter
|
rdapJsonFormatter.makeRdapJsonForDomain(domainBaseFull, OutputDataType.FULL).toJson())
|
||||||
.makeRdapJsonForDomain(
|
|
||||||
domainBaseFull,
|
|
||||||
WHOIS_SERVER,
|
|
||||||
clock.nowUtc(),
|
|
||||||
OutputDataType.FULL)
|
|
||||||
.toJson())
|
|
||||||
.isEqualTo(loadJson("rdapjson_domain_logged_out.json"));
|
.isEqualTo(loadJson("rdapjson_domain_logged_out.json"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -570,11 +517,7 @@ public class RdapJsonFormatterTest {
|
||||||
public void testDomain_noNameserversNoTransfers() {
|
public void testDomain_noNameserversNoTransfers() {
|
||||||
assertThat(
|
assertThat(
|
||||||
rdapJsonFormatter
|
rdapJsonFormatter
|
||||||
.makeRdapJsonForDomain(
|
.makeRdapJsonForDomain(domainBaseNoNameserversNoTransfers, OutputDataType.FULL)
|
||||||
domainBaseNoNameserversNoTransfers,
|
|
||||||
WHOIS_SERVER,
|
|
||||||
clock.nowUtc(),
|
|
||||||
OutputDataType.FULL)
|
|
||||||
.toJson())
|
.toJson())
|
||||||
.isEqualTo(loadJson("rdapjson_domain_no_nameservers.json"));
|
.isEqualTo(loadJson("rdapjson_domain_no_nameservers.json"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ import com.google.gson.GsonBuilder;
|
||||||
import com.google.gson.JsonArray;
|
import com.google.gson.JsonArray;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
import google.registry.util.Clock;
|
||||||
|
|
||||||
public class RdapTestHelper {
|
public class RdapTestHelper {
|
||||||
|
|
||||||
|
@ -142,10 +143,11 @@ public class RdapTestHelper {
|
||||||
"type", "text/html")))));
|
"type", "text/html")))));
|
||||||
}
|
}
|
||||||
|
|
||||||
static RdapJsonFormatter getTestRdapJsonFormatter() {
|
static RdapJsonFormatter getTestRdapJsonFormatter(Clock clock) {
|
||||||
RdapJsonFormatter rdapJsonFormatter = new RdapJsonFormatter();
|
RdapJsonFormatter rdapJsonFormatter = new RdapJsonFormatter();
|
||||||
rdapJsonFormatter.rdapAuthorization = RdapAuthorization.PUBLIC_AUTHORIZATION;
|
rdapJsonFormatter.rdapAuthorization = RdapAuthorization.PUBLIC_AUTHORIZATION;
|
||||||
rdapJsonFormatter.fullServletPath = "https://example.tld/rdap/";
|
rdapJsonFormatter.fullServletPath = "https://example.tld/rdap/";
|
||||||
|
rdapJsonFormatter.clock = clock;
|
||||||
rdapJsonFormatter.rdapTos =
|
rdapJsonFormatter.rdapTos =
|
||||||
ImmutableList.of(
|
ImmutableList.of(
|
||||||
"By querying our Domain Database, you are agreeing to comply with these"
|
"By querying our Domain Database, you are agreeing to comply with these"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue