mirror of
https://github.com/google/nomulus.git
synced 2025-05-13 07:57:13 +02:00
Reimplement the RDAP Json creation using Jsonables
Currently we try to reimplemnet the same behavior of the existing code as much as possible. We only fix issues that go against the RFC7483, but we don't yet update the code to follow the latest (15feb19) RDAP Response Profile. That will require a much bigger change especially for the test files, so it'll wait for a followup CL. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=246948018
This commit is contained in:
parent
e382299212
commit
bdc41edd34
85 changed files with 2589 additions and 2367 deletions
|
@ -1,52 +0,0 @@
|
|||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.config;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* AutoValue class describing an RDAP Notice object.
|
||||
*
|
||||
* <p>This is used for injecting RDAP help pages.
|
||||
*/
|
||||
@AutoValue
|
||||
public abstract class RdapNoticeDescriptor {
|
||||
|
||||
public static Builder builder() {
|
||||
return new AutoValue_RdapNoticeDescriptor.Builder();
|
||||
}
|
||||
|
||||
@Nullable public abstract String getTitle();
|
||||
public abstract ImmutableList<String> getDescription();
|
||||
@Nullable public abstract String getTypeString();
|
||||
@Nullable public abstract String getLinkValueSuffix();
|
||||
@Nullable public abstract String getLinkHrefUrlString();
|
||||
|
||||
/** Builder class for {@link RdapNoticeDescriptor}. */
|
||||
@AutoValue.Builder
|
||||
public abstract static class Builder {
|
||||
|
||||
public abstract Builder setTitle(@Nullable String title);
|
||||
public abstract Builder setDescription(Iterable<String> description);
|
||||
public abstract Builder setTypeString(@Nullable String typeString);
|
||||
public abstract Builder setLinkValueSuffix(@Nullable String linkValueSuffix);
|
||||
public abstract Builder setLinkHrefUrlString(@Nullable String linkHrefUrlString);
|
||||
|
||||
public abstract RdapNoticeDescriptor build();
|
||||
}
|
||||
}
|
||||
|
|
@ -26,7 +26,6 @@ import com.google.common.base.Splitter;
|
|||
import com.google.common.base.Strings;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
|
@ -1267,19 +1266,6 @@ public final class RegistryConfig {
|
|||
return ImmutableList.copyOf(config.credentialOAuth.localCredentialOauthScopes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the help path for the RDAP terms of service.
|
||||
*
|
||||
* <p>Make sure that this path is equal to the key of the entry in the RDAP help map containing
|
||||
* the terms of service. The ICANN operational profile requires that the TOS be included in all
|
||||
* responses, and this string is used to find the TOS in the help map.
|
||||
*/
|
||||
@Provides
|
||||
@Config("rdapTosPath")
|
||||
public static String provideRdapTosPath() {
|
||||
return "/tos";
|
||||
}
|
||||
|
||||
/** OAuth client ID used by the nomulus tool. */
|
||||
@Provides
|
||||
@Config("toolsClientId")
|
||||
|
@ -1311,51 +1297,6 @@ public final class RegistryConfig {
|
|||
public static String provideRdapTosStaticUrl(RegistryConfigSettings config) {
|
||||
return config.registryPolicy.rdapTosStaticUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the help text to be used by RDAP.
|
||||
*
|
||||
* <p>Make sure that the map entry for the terms of service use the same key as specified in
|
||||
* rdapTosPath above.
|
||||
*/
|
||||
@Singleton
|
||||
@Provides
|
||||
@Config("rdapHelpMap")
|
||||
public static ImmutableMap<String, RdapNoticeDescriptor> provideRdapHelpMap(
|
||||
@Config("rdapTos") ImmutableList<String> rdapTos,
|
||||
@Config("rdapTosStaticUrl") @Nullable String rdapTosStaticUrl) {
|
||||
return new ImmutableMap.Builder<String, RdapNoticeDescriptor>()
|
||||
.put(
|
||||
"/",
|
||||
RdapNoticeDescriptor.builder()
|
||||
.setTitle("RDAP Help")
|
||||
.setDescription(
|
||||
ImmutableList.of(
|
||||
"domain/XXXX",
|
||||
"nameserver/XXXX",
|
||||
"entity/XXXX",
|
||||
"domains?name=XXXX",
|
||||
"domains?nsLdhName=XXXX",
|
||||
"domains?nsIp=XXXX",
|
||||
"nameservers?name=XXXX",
|
||||
"nameservers?ip=XXXX",
|
||||
"entities?fn=XXXX",
|
||||
"entities?handle=XXXX",
|
||||
"help/XXXX"))
|
||||
.setLinkValueSuffix("help/")
|
||||
.setLinkHrefUrlString(
|
||||
"https://github.com/google/nomulus/blob/master/docs/rdap.md")
|
||||
.build())
|
||||
.put(
|
||||
"/tos",
|
||||
RdapNoticeDescriptor.builder()
|
||||
.setTitle("RDAP Terms of Service")
|
||||
.setDescription(rdapTos)
|
||||
.setLinkValueSuffix("help/tos")
|
||||
.setLinkHrefUrlString(rdapTosStaticUrl)
|
||||
.build())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -360,8 +360,6 @@ abstract class AbstractJsonableObject implements Jsonable {
|
|||
*
|
||||
* <p>If not empty - the resulting list is the allowed names. If the name ends with [], it means
|
||||
* the class is an element in a array with this name.
|
||||
*
|
||||
* <p>A name of "*" means this is allowed to merge.
|
||||
*/
|
||||
static Optional<ImmutableSet<String>> getNameRestriction(Class<?> clazz) {
|
||||
// Find the first superclass that has an RestrictJsonNames annotation.
|
||||
|
|
|
@ -25,11 +25,11 @@ import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
|
|||
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||
|
||||
import com.google.api.client.json.jackson2.JacksonFactory;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.common.net.MediaType;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.re2j.Pattern;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.cmd.Query;
|
||||
|
@ -38,9 +38,12 @@ import google.registry.model.EppResource;
|
|||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.rdap.RdapMetrics.EndpointType;
|
||||
import google.registry.rdap.RdapMetrics.WildcardType;
|
||||
import google.registry.rdap.RdapObjectClasses.ErrorResponse;
|
||||
import google.registry.rdap.RdapObjectClasses.ReplyPayloadBase;
|
||||
import google.registry.rdap.RdapObjectClasses.TopLevelReplyObject;
|
||||
import google.registry.rdap.RdapSearchResults.BaseSearchResponse;
|
||||
import google.registry.rdap.RdapSearchResults.IncompletenessWarningType;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.FullServletPath;
|
||||
import google.registry.request.HttpException;
|
||||
import google.registry.request.HttpException.UnprocessableEntityException;
|
||||
import google.registry.request.Parameter;
|
||||
|
@ -51,7 +54,6 @@ import google.registry.request.auth.AuthResult;
|
|||
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
|
||||
import google.registry.request.auth.UserAuthInfo;
|
||||
import google.registry.util.Clock;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
|
@ -60,7 +62,6 @@ import java.util.Optional;
|
|||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.time.DateTime;
|
||||
import org.json.simple.JSONValue;
|
||||
|
||||
/**
|
||||
* Base RDAP (new WHOIS) action for all requests.
|
||||
|
@ -92,7 +93,6 @@ public abstract class RdapActionBase implements Runnable {
|
|||
@Inject Clock clock;
|
||||
@Inject @RequestMethod Action.Method requestMethod;
|
||||
@Inject @RequestPath String requestPath;
|
||||
@Inject @FullServletPath String fullServletPath;
|
||||
@Inject AuthResult authResult;
|
||||
@Inject AuthenticatedRegistrarAccessor registrarAccessor;
|
||||
@Inject RdapJsonFormatter rdapJsonFormatter;
|
||||
|
@ -138,7 +138,7 @@ public abstract class RdapActionBase implements Runnable {
|
|||
* expensive task required to create the map which will never result in a request failure.
|
||||
* @return A map (probably containing nested maps and lists) with the final JSON response data.
|
||||
*/
|
||||
abstract ImmutableMap<String, Object> getJsonObjectForResource(
|
||||
abstract ReplyPayloadBase getJsonObjectForResource(
|
||||
String pathSearchString, boolean isHeadRequest);
|
||||
|
||||
@Override
|
||||
|
@ -159,12 +159,16 @@ public abstract class RdapActionBase implements Runnable {
|
|||
checkArgument(
|
||||
pathProper.startsWith(getActionPath()),
|
||||
"%s doesn't start with %s", pathProper, getActionPath());
|
||||
ImmutableMap<String, Object> rdapJson =
|
||||
ReplyPayloadBase replyObject =
|
||||
getJsonObjectForResource(
|
||||
pathProper.substring(getActionPath().length()), requestMethod == Action.Method.HEAD);
|
||||
if (replyObject instanceof BaseSearchResponse) {
|
||||
metricInformationBuilder.setIncompletenessWarningType(
|
||||
((BaseSearchResponse) replyObject).incompletenessWarningType());
|
||||
}
|
||||
response.setStatus(SC_OK);
|
||||
response.setContentType(RESPONSE_MEDIA_TYPE);
|
||||
setPayload(rdapJson);
|
||||
setPayload(replyObject);
|
||||
metricInformationBuilder.setStatusCode(SC_OK);
|
||||
} catch (HttpException e) {
|
||||
setError(e.getResponseCode(), e.getResponseCodeString(), e.getMessage());
|
||||
|
@ -182,26 +186,29 @@ public abstract class RdapActionBase implements Runnable {
|
|||
response.setStatus(status);
|
||||
response.setContentType(RESPONSE_MEDIA_TYPE);
|
||||
try {
|
||||
setPayload(rdapJsonFormatter.makeError(status, title, description));
|
||||
setPayload(ErrorResponse.create(status, title, description));
|
||||
} catch (Exception ex) {
|
||||
logger.atSevere().withCause(ex).log("Failed to create an error response.");
|
||||
response.setPayload("");
|
||||
}
|
||||
}
|
||||
|
||||
void setPayload(ImmutableMap<String, Object> rdapJson) {
|
||||
void setPayload(ReplyPayloadBase replyObject) {
|
||||
if (requestMethod == Action.Method.HEAD) {
|
||||
return;
|
||||
}
|
||||
|
||||
GsonBuilder gsonBuilder = new GsonBuilder();
|
||||
gsonBuilder.disableHtmlEscaping();
|
||||
if (formatOutputParam.orElse(false)) {
|
||||
try {
|
||||
response.setPayload(new JacksonFactory().toPrettyString(rdapJson));
|
||||
return;
|
||||
} catch (IOException e) {
|
||||
logger.atWarning().withCause(e).log(
|
||||
"Unable to pretty-print RDAP JSON response; falling back to unformatted output.");
|
||||
gsonBuilder.setPrettyPrinting();
|
||||
}
|
||||
}
|
||||
response.setPayload(JSONValue.toJSONString(rdapJson));
|
||||
Gson gson = gsonBuilder.create();
|
||||
|
||||
TopLevelReplyObject topLevelObject =
|
||||
TopLevelReplyObject.create(replyObject, rdapJsonFormatter.createTosNotice());
|
||||
|
||||
response.setPayload(gson.toJson(topLevelObject.toJson()));
|
||||
}
|
||||
|
||||
RdapAuthorization getAuthorization() {
|
||||
|
|
|
@ -17,8 +17,8 @@ package google.registry.rdap;
|
|||
import static google.registry.request.Action.Method.GET;
|
||||
import static google.registry.request.Action.Method.HEAD;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.rdap.RdapMetrics.EndpointType;
|
||||
import google.registry.rdap.RdapObjectClasses.ReplyPayloadBase;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.HttpException.NotImplementedException;
|
||||
import google.registry.request.auth.Auth;
|
||||
|
@ -43,8 +43,7 @@ public class RdapAutnumAction extends RdapActionBase {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ImmutableMap<String, Object> getJsonObjectForResource(
|
||||
String pathSearchString, boolean isHeadRequest) {
|
||||
public ReplyPayloadBase getJsonObjectForResource(String pathSearchString, boolean isHeadRequest) {
|
||||
throw new NotImplementedException("Domain Name Registry information only");
|
||||
}
|
||||
}
|
||||
|
|
487
java/google/registry/rdap/RdapDataStructures.java
Normal file
487
java/google/registry/rdap/RdapDataStructures.java
Normal file
|
@ -0,0 +1,487 @@
|
|||
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.rdap;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import google.registry.rdap.AbstractJsonableObject.RestrictJsonNames;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* Data Structures defined in RFC7483 section 4.
|
||||
*/
|
||||
final class RdapDataStructures {
|
||||
|
||||
private RdapDataStructures() {}
|
||||
|
||||
/**
|
||||
* RDAP conformance defined in 4.1 of RFC7483.
|
||||
*/
|
||||
@RestrictJsonNames("rdapConformance")
|
||||
static final class RdapConformance implements Jsonable {
|
||||
|
||||
static final RdapConformance INSTANCE = new RdapConformance();
|
||||
|
||||
private RdapConformance() {}
|
||||
|
||||
@Override
|
||||
public JsonArray toJson() {
|
||||
JsonArray jsonArray = new JsonArray();
|
||||
// Conformance to RFC7483
|
||||
// TODO(b/127490882) check if we need to Add back the rdap_level_0 string, as I think that
|
||||
// just means we conform to the RFC, which we do
|
||||
// jsonArray.add("rdap_level_0");
|
||||
|
||||
// Conformance to the RDAP Response Profile V2.1
|
||||
// (see section 1.3)
|
||||
jsonArray.add("icann_rdap_response_profile_0");
|
||||
return jsonArray;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Links defined in 4.2 of RFC7483.
|
||||
*/
|
||||
@RestrictJsonNames("links[]")
|
||||
@AutoValue
|
||||
abstract static class Link extends AbstractJsonableObject {
|
||||
@JsonableElement abstract String href();
|
||||
|
||||
@JsonableElement abstract Optional<String> rel();
|
||||
@JsonableElement abstract Optional<String> hreflang();
|
||||
@JsonableElement abstract Optional<String> title();
|
||||
@JsonableElement abstract Optional<String> media();
|
||||
@JsonableElement abstract Optional<String> type();
|
||||
@JsonableElement abstract Optional<String> value();
|
||||
|
||||
static Builder builder() {
|
||||
return new AutoValue_RdapDataStructures_Link.Builder();
|
||||
}
|
||||
|
||||
@AutoValue.Builder
|
||||
abstract static class Builder {
|
||||
abstract Builder setHref(String href);
|
||||
abstract Builder setRel(String rel);
|
||||
abstract Builder setHreflang(String hrefLang);
|
||||
abstract Builder setTitle(String title);
|
||||
abstract Builder setMedia(String media);
|
||||
abstract Builder setType(String type);
|
||||
abstract Builder setValue(String value);
|
||||
|
||||
abstract Link build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notices and Remarks defined in 4.3 of RFC7483.
|
||||
*
|
||||
* <p>Each has an optional "type" denoting a registered type string defined in 10.2.1. The type is
|
||||
* defined as common to both Notices and Remarks, but each item is only appropriate to one of
|
||||
* them. So we will divide all the "types" from the RFC to two enums - one for Notices and one for
|
||||
* Remarks.
|
||||
*/
|
||||
private abstract static class NoticeOrRemark extends AbstractJsonableObject {
|
||||
@JsonableElement abstract Optional<String> title();
|
||||
@JsonableElement abstract ImmutableList<String> description();
|
||||
@JsonableElement abstract ImmutableList<Link> links();
|
||||
|
||||
abstract static class Builder<B extends Builder<?>> {
|
||||
abstract B setTitle(String title);
|
||||
abstract B setDescription(ImmutableList<String> description);
|
||||
abstract B setDescription(String... description);
|
||||
abstract ImmutableList.Builder<Link> linksBuilder();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
B addLink(Link link) {
|
||||
linksBuilder().add(link);
|
||||
return (B) this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notices defined in 4.3 of RFC7483.
|
||||
*
|
||||
* <p>A notice denotes information about the service itself or the entire response, and hence will
|
||||
* only be in the top-most object.
|
||||
*/
|
||||
@AutoValue
|
||||
@RestrictJsonNames("notices[]")
|
||||
abstract static class Notice extends NoticeOrRemark {
|
||||
|
||||
/**
|
||||
* Notice and Remark Type are defined in 10.2.1 of RFC7483.
|
||||
*
|
||||
* <p>We only keep the "service or entire response" values for Notice.Type.
|
||||
*/
|
||||
@RestrictJsonNames("type")
|
||||
enum Type implements Jsonable {
|
||||
RESULT_TRUNCATED_AUTHORIZATION("result set truncated due to authorization"),
|
||||
RESULT_TRUNCATED_LOAD("result set truncated due to excessive load"),
|
||||
RESULT_TRUNCATED_UNEXPLAINABLE("result set truncated due to unexplainable reasons");
|
||||
|
||||
|
||||
private final String rfc7483String;
|
||||
|
||||
Type(String rfc7483String) {
|
||||
this.rfc7483String = rfc7483String;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonPrimitive toJson() {
|
||||
return new JsonPrimitive(rfc7483String);
|
||||
}
|
||||
}
|
||||
|
||||
@JsonableElement
|
||||
abstract Optional<Notice.Type> type();
|
||||
|
||||
static Builder builder() {
|
||||
return new AutoValue_RdapDataStructures_Notice.Builder();
|
||||
}
|
||||
|
||||
@AutoValue.Builder
|
||||
abstract static class Builder extends NoticeOrRemark.Builder<Builder> {
|
||||
abstract Builder setType(Notice.Type type);
|
||||
|
||||
abstract Notice build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remarks defined in 4.3 of RFC7483.
|
||||
*
|
||||
* <p>A remark denotes information about the specific object, and hence each object has its own
|
||||
* "remarks" array.
|
||||
*/
|
||||
@AutoValue
|
||||
@RestrictJsonNames("remarks[]")
|
||||
abstract static class Remark extends NoticeOrRemark {
|
||||
|
||||
/**
|
||||
* Notice and Remark Type are defined in 10.2.1 of RFC7483.
|
||||
*
|
||||
* <p>We only keep the "specific object" values for Remark.Type.
|
||||
*/
|
||||
@RestrictJsonNames("type")
|
||||
enum Type implements Jsonable {
|
||||
OBJECT_TRUNCATED_AUTHORIZATION("object truncated due to authorization"),
|
||||
OBJECT_TRUNCATED_LOAD("object truncated due to excessive load"),
|
||||
OBJECT_TRUNCATED_UNEXPLAINABLE("object truncated due to unexplainable reasons"),
|
||||
// This one isn't in the "RDAP JSON Values registry", but it's in the RDAP Response Profile,
|
||||
// so I'm adding it here, but we have to ask them about it...
|
||||
OBJECT_REDACTED_AUTHORIZATION("object redacted due to authorization");
|
||||
|
||||
private final String rfc7483String;
|
||||
|
||||
Type(String rfc7483String) {
|
||||
this.rfc7483String = rfc7483String;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonPrimitive toJson() {
|
||||
return new JsonPrimitive(rfc7483String);
|
||||
}
|
||||
}
|
||||
|
||||
@JsonableElement
|
||||
abstract Optional<Remark.Type> type();
|
||||
|
||||
static Builder builder() {
|
||||
return new AutoValue_RdapDataStructures_Remark.Builder();
|
||||
}
|
||||
|
||||
@AutoValue.Builder
|
||||
abstract static class Builder extends NoticeOrRemark.Builder<Builder> {
|
||||
abstract Builder setType(Remark.Type type);
|
||||
|
||||
abstract Remark build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Language Identifier defined in 4.4 of RFC7483.
|
||||
*
|
||||
* The allowed values are described in RFC5646.
|
||||
*/
|
||||
@RestrictJsonNames("lang")
|
||||
enum LanguageIdentifier implements Jsonable {
|
||||
EN("en");
|
||||
|
||||
private final String languageIdentifier;
|
||||
|
||||
LanguageIdentifier(String languageIdentifier) {
|
||||
this.languageIdentifier = languageIdentifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonPrimitive toJson() {
|
||||
return new JsonPrimitive(languageIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Events defined in 4.5 of RFC7483.
|
||||
*
|
||||
* <p>There's a type of Event that must not have the "eventActor" (see 5.1), so we create 2
|
||||
* versions - one with and one without.
|
||||
*/
|
||||
private abstract static class EventBase extends AbstractJsonableObject {
|
||||
@JsonableElement abstract EventAction eventAction();
|
||||
@JsonableElement abstract DateTime eventDate();
|
||||
@JsonableElement abstract ImmutableList<Link> links();
|
||||
|
||||
|
||||
abstract static class Builder<B extends Builder<?>> {
|
||||
abstract B setEventAction(EventAction eventAction);
|
||||
abstract B setEventDate(DateTime eventDate);
|
||||
abstract ImmutableList.Builder<Link> linksBuilder();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
B addLink(Link link) {
|
||||
linksBuilder().add(link);
|
||||
return (B) this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Status values for events specified in RFC 7483 § 10.2.3. */
|
||||
enum EventAction implements Jsonable {
|
||||
REGISTRATION("registration"),
|
||||
REREGISTRATION("reregistration"),
|
||||
LAST_CHANGED("last changed"),
|
||||
EXPIRATION("expiration"),
|
||||
DELETION("deletion"),
|
||||
REINSTANTIATION("reinstantiation"),
|
||||
TRANSFER("transfer"),
|
||||
LOCKED("locked"),
|
||||
UNLOCKED("unlocked"),
|
||||
LAST_UPDATE_OF_RDAP_DATABASE("last update of RDAP database");
|
||||
|
||||
/** Value as it appears in RDAP messages. */
|
||||
private final String rfc7483String;
|
||||
|
||||
EventAction(String rfc7483String) {
|
||||
this.rfc7483String = rfc7483String;
|
||||
}
|
||||
|
||||
String getDisplayName() {
|
||||
return rfc7483String;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonPrimitive toJson() {
|
||||
return new JsonPrimitive(rfc7483String);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Events defined in 4.5 of RFC7483.
|
||||
*
|
||||
* <p>There's a type of Event that MUST NOT have the "eventActor" (see 5.1), so we have this
|
||||
* object to enforce that.
|
||||
*/
|
||||
@RestrictJsonNames("asEventActor[]")
|
||||
@AutoValue
|
||||
abstract static class EventWithoutActor extends EventBase {
|
||||
|
||||
static Builder builder() {
|
||||
return new AutoValue_RdapDataStructures_EventWithoutActor.Builder();
|
||||
}
|
||||
|
||||
|
||||
@AutoValue.Builder
|
||||
abstract static class Builder extends EventBase.Builder<Builder> {
|
||||
abstract EventWithoutActor build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Events defined in 4.5 of RFC7483.
|
||||
*/
|
||||
@RestrictJsonNames("events[]")
|
||||
@AutoValue
|
||||
abstract static class Event extends EventBase {
|
||||
@JsonableElement abstract Optional<String> eventActor();
|
||||
|
||||
static Builder builder() {
|
||||
return new AutoValue_RdapDataStructures_Event.Builder();
|
||||
}
|
||||
|
||||
|
||||
@AutoValue.Builder
|
||||
abstract static class Builder extends EventBase.Builder<Builder> {
|
||||
abstract Builder setEventActor(String eventActor);
|
||||
abstract Event build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Status defined in 4.6 of RFC7483.
|
||||
*
|
||||
* <p>This indicates the state of the registered object.
|
||||
*
|
||||
* <p>The allowed values are in section 10.2.2.
|
||||
*/
|
||||
@RestrictJsonNames("status[]")
|
||||
enum RdapStatus implements Jsonable {
|
||||
|
||||
// Status values specified in RFC 7483 § 10.2.2.
|
||||
VALIDATED("validated"),
|
||||
RENEW_PROHIBITED("renew prohibited"),
|
||||
UPDATE_PROHIBITED("update prohibited"),
|
||||
TRANSFER_PROHIBITED("transfer prohibited"),
|
||||
DELETE_PROHIBITED("delete prohibited"),
|
||||
PROXY("proxy"),
|
||||
PRIVATE("private"),
|
||||
REMOVED("removed"),
|
||||
OBSCURED("obscured"),
|
||||
ASSOCIATED("associated"),
|
||||
ACTIVE("active"),
|
||||
INACTIVE("inactive"),
|
||||
LOCKED("locked"),
|
||||
PENDING_CREATE("pending create"),
|
||||
PENDING_RENEW("pending renew"),
|
||||
PENDING_TRANSFER("pending transfer"),
|
||||
PENDING_UPDATE("pending update"),
|
||||
PENDING_DELETE("pending delete"),
|
||||
|
||||
// Additional status values defined in
|
||||
// https://tools.ietf.org/html/draft-ietf-regext-epp-rdap-status-mapping-01.
|
||||
ADD_PERIOD("add period"),
|
||||
AUTO_RENEW_PERIOD("auto renew period"),
|
||||
CLIENT_DELETE_PROHIBITED("client delete prohibited"),
|
||||
CLIENT_HOLD("client hold"),
|
||||
CLIENT_RENEW_PROHIBITED("client renew prohibited"),
|
||||
CLIENT_TRANSFER_PROHIBITED("client transfer prohibited"),
|
||||
CLIENT_UPDATE_PROHIBITED("client update prohibited"),
|
||||
PENDING_RESTORE("pending restore"),
|
||||
REDEMPTION_PERIOD("redemption period"),
|
||||
RENEW_PERIOD("renew period"),
|
||||
SERVER_DELETE_PROHIBITED("server deleted prohibited"),
|
||||
SERVER_RENEW_PROHIBITED("server renew prohibited"),
|
||||
SERVER_TRANSFER_PROHIBITED("server transfer prohibited"),
|
||||
SERVER_UPDATE_PROHIBITED("server update prohibited"),
|
||||
SERVER_HOLD("server hold"),
|
||||
TRANSFER_PERIOD("transfer period");
|
||||
|
||||
/** Value as it appears in RDAP messages. */
|
||||
private final String rfc7483String;
|
||||
|
||||
RdapStatus(String rfc7483String) {
|
||||
this.rfc7483String = rfc7483String;
|
||||
}
|
||||
|
||||
String getDisplayName() {
|
||||
return rfc7483String;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonPrimitive toJson() {
|
||||
return new JsonPrimitive(rfc7483String);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Port 43 WHOIS Server defined in 4.7 of RFC7483.
|
||||
*
|
||||
* <p>This contains the fully qualifies host name of IP address of the WHOIS RFC3912 server where
|
||||
* the containing object instance may be found.
|
||||
*/
|
||||
@RestrictJsonNames("port43")
|
||||
@AutoValue
|
||||
abstract static class Port43WhoisServer implements Jsonable {
|
||||
abstract String port43();
|
||||
|
||||
@Override
|
||||
public JsonPrimitive toJson() {
|
||||
return new JsonPrimitive(port43());
|
||||
}
|
||||
|
||||
static Port43WhoisServer create(String port43) {
|
||||
return new AutoValue_RdapDataStructures_Port43WhoisServer(port43);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Public IDs defined in 4.8 of RFC7483.
|
||||
*
|
||||
* <p>Maps a public identifier to an object class.
|
||||
*/
|
||||
@RestrictJsonNames("publicIds[]")
|
||||
@AutoValue
|
||||
abstract static class PublicId extends AbstractJsonableObject {
|
||||
@RestrictJsonNames("type")
|
||||
enum Type implements Jsonable {
|
||||
IANA_REGISTRAR_ID("IANA Registrar ID");
|
||||
|
||||
private final String rfc7483String;
|
||||
|
||||
Type(String rfc7483String) {
|
||||
this.rfc7483String = rfc7483String;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonPrimitive toJson() {
|
||||
return new JsonPrimitive(rfc7483String);
|
||||
}
|
||||
}
|
||||
|
||||
@JsonableElement
|
||||
abstract PublicId.Type type();
|
||||
|
||||
@JsonableElement abstract String identifier();
|
||||
|
||||
static PublicId create(PublicId.Type type, String identifier) {
|
||||
return new AutoValue_RdapDataStructures_PublicId(type, identifier);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Object Class Name defined in 4.7 of RFC7483.
|
||||
*
|
||||
* <p>Identifies the type of the object being processed. Is REQUIRED in all RDAP response objects,
|
||||
* but not so for internal objects whose type can be inferred by their key name in the enclosing
|
||||
* object.
|
||||
*/
|
||||
@RestrictJsonNames("objectClassName")
|
||||
enum ObjectClassName implements Jsonable {
|
||||
/** Defined in 5.1 of RFC7483. */
|
||||
ENTITY("entity"),
|
||||
/** Defined in 5.2 of RFC7483. */
|
||||
NAMESERVER("nameserver"),
|
||||
/** Defined in 5.3 of RFC7483. */
|
||||
DOMAIN("domain"),
|
||||
/** Defined in 5.4 of RFC7483. Only relevant for Registrars, so isn't implemented here. */
|
||||
IP_NETWORK("ip network"),
|
||||
/** Defined in 5.5 of RFC7483. Only relevant for Registrars, so isn't implemented here. */
|
||||
AUTONOMUS_SYSTEM("autnum");
|
||||
|
||||
private final String className;
|
||||
|
||||
ObjectClassName(String className) {
|
||||
this.className = className;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonPrimitive toJson() {
|
||||
return new JsonPrimitive(className);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -20,11 +20,11 @@ import static google.registry.request.Action.Method.GET;
|
|||
import static google.registry.request.Action.Method.HEAD;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
import google.registry.rdap.RdapJsonFormatter.OutputDataType;
|
||||
import google.registry.rdap.RdapMetrics.EndpointType;
|
||||
import google.registry.rdap.RdapObjectClasses.RdapDomain;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.HttpException.BadRequestException;
|
||||
import google.registry.request.HttpException.NotFoundException;
|
||||
|
@ -47,8 +47,7 @@ public class RdapDomainAction extends RdapActionBase {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ImmutableMap<String, Object> getJsonObjectForResource(
|
||||
String pathSearchString, boolean isHeadRequest) {
|
||||
public RdapDomain getJsonObjectForResource(String pathSearchString, boolean isHeadRequest) {
|
||||
DateTime now = clock.nowUtc();
|
||||
pathSearchString = canonicalizeName(pathSearchString);
|
||||
try {
|
||||
|
@ -68,8 +67,6 @@ public class RdapDomainAction extends RdapActionBase {
|
|||
}
|
||||
return rdapJsonFormatter.makeRdapJsonForDomain(
|
||||
domainBase.get(),
|
||||
true,
|
||||
fullServletPath,
|
||||
rdapWhoisServer,
|
||||
now,
|
||||
OutputDataType.FULL,
|
||||
|
|
|
@ -22,7 +22,6 @@ import static google.registry.request.Action.Method.HEAD;
|
|||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Streams;
|
||||
|
@ -33,11 +32,11 @@ import com.googlecode.objectify.Key;
|
|||
import com.googlecode.objectify.cmd.Query;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
import google.registry.model.host.HostResource;
|
||||
import google.registry.rdap.RdapJsonFormatter.BoilerplateType;
|
||||
import google.registry.rdap.RdapJsonFormatter.OutputDataType;
|
||||
import google.registry.rdap.RdapMetrics.EndpointType;
|
||||
import google.registry.rdap.RdapMetrics.SearchType;
|
||||
import google.registry.rdap.RdapMetrics.WildcardType;
|
||||
import google.registry.rdap.RdapSearchResults.DomainSearchResponse;
|
||||
import google.registry.rdap.RdapSearchResults.IncompletenessWarningType;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.HttpException.BadRequestException;
|
||||
|
@ -48,7 +47,6 @@ import google.registry.request.auth.Auth;
|
|||
import google.registry.util.Idn;
|
||||
import google.registry.util.NonFinalForTesting;
|
||||
import java.net.InetAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
@ -93,7 +91,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
* <p>The RDAP spec allows for domain search by domain name, nameserver name or nameserver IP.
|
||||
*/
|
||||
@Override
|
||||
public ImmutableMap<String, Object> getJsonObjectForResource(
|
||||
public DomainSearchResponse getJsonObjectForResource(
|
||||
String pathSearchString, boolean isHeadRequest) {
|
||||
DateTime now = clock.nowUtc();
|
||||
// RDAP syntax example: /rdap/domains?name=exam*.com.
|
||||
|
@ -107,7 +105,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
"You must specify either name=XXXX, nsLdhName=YYYY or nsIp=ZZZZ");
|
||||
}
|
||||
decodeCursorToken();
|
||||
RdapSearchResults results;
|
||||
DomainSearchResponse results;
|
||||
if (nameParam.isPresent()) {
|
||||
metricInformationBuilder.setSearchType(SearchType.BY_DOMAIN_NAME);
|
||||
// syntax: /rdap/domains?name=exam*.com
|
||||
|
@ -142,18 +140,10 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
}
|
||||
results = searchByNameserverIp(inetAddress, now);
|
||||
}
|
||||
if (results.jsonList().isEmpty()) {
|
||||
if (results.domainSearchResults().isEmpty()) {
|
||||
throw new NotFoundException("No domains found");
|
||||
}
|
||||
ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
|
||||
builder.put("domainSearchResults", results.jsonList());
|
||||
rdapJsonFormatter.addTopLevelEntries(
|
||||
builder,
|
||||
BoilerplateType.DOMAIN,
|
||||
getNotices(results),
|
||||
ImmutableList.of(),
|
||||
fullServletPath);
|
||||
return builder.build();
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -168,7 +158,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
* <p>Searches which include deleted entries are effectively treated as if they have a wildcard,
|
||||
* since the same name can return multiple results.
|
||||
*/
|
||||
private RdapSearchResults searchByDomainName(
|
||||
private DomainSearchResponse searchByDomainName(
|
||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
||||
// 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.
|
||||
|
@ -199,7 +189,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
/**
|
||||
* Searches for domains by domain name without a wildcard or interest in deleted entries.
|
||||
*/
|
||||
private RdapSearchResults searchByDomainNameWithoutWildcard(
|
||||
private DomainSearchResponse searchByDomainNameWithoutWildcard(
|
||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
||||
Optional<DomainBase> domainBase =
|
||||
loadByForeignKey(DomainBase.class, partialStringQuery.getInitialString(), now);
|
||||
|
@ -211,7 +201,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
}
|
||||
|
||||
/** Searches for domains by domain name with an initial string, wildcard and possible suffix. */
|
||||
private RdapSearchResults searchByDomainNameWithInitialString(
|
||||
private DomainSearchResponse searchByDomainNameWithInitialString(
|
||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
||||
// 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
|
||||
|
@ -241,7 +231,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
}
|
||||
|
||||
/** Searches for domains by domain name with a TLD suffix. */
|
||||
private RdapSearchResults searchByDomainNameByTld(String tld, DateTime now) {
|
||||
private DomainSearchResponse searchByDomainNameByTld(String tld, DateTime now) {
|
||||
// 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
|
||||
// searchByDomainNameWithInitialString, unable to perform an inequality query on deletion time.
|
||||
|
@ -268,7 +258,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
* <p>The includeDeleted parameter does NOT cause deleted nameservers to be searched, only deleted
|
||||
* domains which used to be connected to an undeleted nameserver.
|
||||
*/
|
||||
private RdapSearchResults searchByNameserverLdhName(
|
||||
private DomainSearchResponse searchByNameserverLdhName(
|
||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
||||
Iterable<Key<HostResource>> hostKeys = getNameserverRefsByLdhName(partialStringQuery, now);
|
||||
if (Iterables.isEmpty(hostKeys)) {
|
||||
|
@ -407,7 +397,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
* <p>The includeDeleted parameter does NOT cause deleted nameservers to be searched, only deleted
|
||||
* domains which used to be connected to an undeleted nameserver.
|
||||
*/
|
||||
private RdapSearchResults searchByNameserverIp(
|
||||
private DomainSearchResponse searchByNameserverIp(
|
||||
final InetAddress inetAddress, final DateTime now) {
|
||||
Query<HostResource> query =
|
||||
queryItems(
|
||||
|
@ -431,7 +421,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
* <p>This method is called by {@link #searchByNameserverLdhName} and {@link
|
||||
* #searchByNameserverIp} after they assemble the relevant host keys.
|
||||
*/
|
||||
private RdapSearchResults searchByNameserverRefs(
|
||||
private DomainSearchResponse searchByNameserverRefs(
|
||||
final Iterable<Key<HostResource>> hostKeys, final DateTime now) {
|
||||
// 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
|
||||
|
@ -466,13 +456,6 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
}
|
||||
List<DomainBase> domains = domainSetBuilder.build().asList();
|
||||
metricInformationBuilder.setNumHostsRetrieved(numHostKeysSearched);
|
||||
if (domains.size() > rdapResultSetMaxSize) {
|
||||
return makeSearchResults(
|
||||
domains.subList(0, rdapResultSetMaxSize),
|
||||
IncompletenessWarningType.TRUNCATED,
|
||||
Optional.of((long) domains.size()),
|
||||
now);
|
||||
} else {
|
||||
// If everything that we found will fit in the result, check whether there might have been
|
||||
// more results that got dropped because the first stage limit on number of nameservers. If
|
||||
// so, indicate the result might be incomplete.
|
||||
|
@ -484,16 +467,15 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
(numHostKeysSearched > 0) ? Optional.of((long) domains.size()) : Optional.empty(),
|
||||
now);
|
||||
}
|
||||
}
|
||||
|
||||
/** Output JSON for a list of domains, with no incompleteness warnings. */
|
||||
private RdapSearchResults makeSearchResults(List<DomainBase> domains, DateTime now) {
|
||||
private DomainSearchResponse makeSearchResults(List<DomainBase> domains, DateTime now) {
|
||||
return makeSearchResults(
|
||||
domains, IncompletenessWarningType.COMPLETE, Optional.of((long) domains.size()), now);
|
||||
}
|
||||
|
||||
/** Output JSON from data in an {@link RdapResultSet} object. */
|
||||
private RdapSearchResults makeSearchResults(
|
||||
private DomainSearchResponse makeSearchResults(
|
||||
RdapResultSet<DomainBase> resultSet, DateTime now) {
|
||||
return makeSearchResults(
|
||||
resultSet.resources(),
|
||||
|
@ -509,7 +491,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
* than are in the list, or MIGHT_BE_INCOMPLETE if a search for domains by nameserver returned the
|
||||
* maximum number of nameservers in the first stage query.
|
||||
*/
|
||||
private RdapSearchResults makeSearchResults(
|
||||
private DomainSearchResponse makeSearchResults(
|
||||
List<DomainBase> domains,
|
||||
IncompletenessWarningType incompletenessWarningType,
|
||||
Optional<Long> numDomainsRetrieved,
|
||||
|
@ -517,28 +499,21 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
|
|||
numDomainsRetrieved.ifPresent(metricInformationBuilder::setNumDomainsRetrieved);
|
||||
OutputDataType outputDataType =
|
||||
(domains.size() > 1) ? OutputDataType.SUMMARY : OutputDataType.FULL;
|
||||
DomainSearchResponse.Builder builder =
|
||||
DomainSearchResponse.builder()
|
||||
.setIncompletenessWarningType(incompletenessWarningType);
|
||||
RdapAuthorization authorization = getAuthorization();
|
||||
List<ImmutableMap<String, Object>> jsonList = new ArrayList<>();
|
||||
Optional<String> newCursor = Optional.empty();
|
||||
for (DomainBase domain : domains) {
|
||||
for (DomainBase domain : Iterables.limit(domains, rdapResultSetMaxSize)) {
|
||||
newCursor = Optional.of(domain.getFullyQualifiedDomainName());
|
||||
jsonList.add(
|
||||
builder.domainSearchResultsBuilder().add(
|
||||
rdapJsonFormatter.makeRdapJsonForDomain(
|
||||
domain, false, fullServletPath, rdapWhoisServer, now, outputDataType, authorization));
|
||||
if (jsonList.size() >= rdapResultSetMaxSize) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
IncompletenessWarningType finalIncompletenessWarningType =
|
||||
(jsonList.size() < domains.size())
|
||||
? IncompletenessWarningType.TRUNCATED
|
||||
: incompletenessWarningType;
|
||||
metricInformationBuilder.setIncompletenessWarningType(finalIncompletenessWarningType);
|
||||
return RdapSearchResults.create(
|
||||
ImmutableList.copyOf(jsonList),
|
||||
finalIncompletenessWarningType,
|
||||
(finalIncompletenessWarningType == IncompletenessWarningType.TRUNCATED)
|
||||
? newCursor
|
||||
: Optional.empty());
|
||||
domain, rdapWhoisServer, now, outputDataType, authorization));
|
||||
}
|
||||
if (rdapResultSetMaxSize < domains.size()) {
|
||||
builder.setNextPageUri(createNavigationUri(newCursor.get()));
|
||||
builder.setIncompletenessWarningType(IncompletenessWarningType.TRUNCATED);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ import static google.registry.rdap.RdapUtils.getRegistrarByIanaIdentifier;
|
|||
import static google.registry.request.Action.Method.GET;
|
||||
import static google.registry.request.Action.Method.HEAD;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.primitives.Longs;
|
||||
import com.google.re2j.Pattern;
|
||||
import com.googlecode.objectify.Key;
|
||||
|
@ -27,6 +26,7 @@ import google.registry.model.contact.ContactResource;
|
|||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.rdap.RdapJsonFormatter.OutputDataType;
|
||||
import google.registry.rdap.RdapMetrics.EndpointType;
|
||||
import google.registry.rdap.RdapObjectClasses.RdapEntity;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.HttpException.BadRequestException;
|
||||
import google.registry.request.HttpException.NotFoundException;
|
||||
|
@ -60,7 +60,7 @@ public class RdapEntityAction extends RdapActionBase {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ImmutableMap<String, Object> getJsonObjectForResource(
|
||||
public RdapEntity getJsonObjectForResource(
|
||||
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
|
||||
|
@ -76,9 +76,7 @@ public class RdapEntityAction extends RdapActionBase {
|
|||
if ((contactResource != null) && shouldBeVisible(contactResource, now)) {
|
||||
return rdapJsonFormatter.makeRdapJsonForContact(
|
||||
contactResource,
|
||||
true,
|
||||
Optional.empty(),
|
||||
fullServletPath,
|
||||
rdapWhoisServer,
|
||||
now,
|
||||
OutputDataType.FULL,
|
||||
|
@ -91,7 +89,7 @@ public class RdapEntityAction extends RdapActionBase {
|
|||
Optional<Registrar> registrar = getRegistrarByIanaIdentifier(ianaIdentifier);
|
||||
if (registrar.isPresent() && shouldBeVisible(registrar.get())) {
|
||||
return rdapJsonFormatter.makeRdapJsonForRegistrar(
|
||||
registrar.get(), true, fullServletPath, rdapWhoisServer, now, OutputDataType.FULL);
|
||||
registrar.get(), rdapWhoisServer, now, OutputDataType.FULL);
|
||||
}
|
||||
}
|
||||
// At this point, we have failed to find either a contact or a registrar.
|
||||
|
|
|
@ -21,17 +21,17 @@ import static google.registry.request.Action.Method.GET;
|
|||
import static google.registry.request.Action.Method.HEAD;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.google.common.primitives.Booleans;
|
||||
import com.google.common.primitives.Longs;
|
||||
import com.googlecode.objectify.cmd.Query;
|
||||
import google.registry.model.contact.ContactResource;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.rdap.RdapJsonFormatter.BoilerplateType;
|
||||
import google.registry.rdap.RdapJsonFormatter.OutputDataType;
|
||||
import google.registry.rdap.RdapMetrics.EndpointType;
|
||||
import google.registry.rdap.RdapMetrics.SearchType;
|
||||
import google.registry.rdap.RdapSearchResults.EntitySearchResponse;
|
||||
import google.registry.rdap.RdapSearchResults.IncompletenessWarningType;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.HttpException.BadRequestException;
|
||||
|
@ -39,7 +39,6 @@ import google.registry.request.HttpException.NotFoundException;
|
|||
import google.registry.request.HttpException.UnprocessableEntityException;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.auth.Auth;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
@ -110,7 +109,7 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
|||
|
||||
/** Parses the parameters and calls the appropriate search function. */
|
||||
@Override
|
||||
public ImmutableMap<String, Object> getJsonObjectForResource(
|
||||
public EntitySearchResponse getJsonObjectForResource(
|
||||
String pathSearchString, boolean isHeadRequest) {
|
||||
DateTime now = clock.nowUtc();
|
||||
|
||||
|
@ -157,7 +156,7 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
|||
}
|
||||
|
||||
// Search by name.
|
||||
RdapSearchResults results;
|
||||
EntitySearchResponse results;
|
||||
if (fnParam.isPresent()) {
|
||||
metricInformationBuilder.setSearchType(SearchType.BY_FULL_NAME);
|
||||
// syntax: /rdap/entities?fn=Bobby%20Joe*
|
||||
|
@ -185,18 +184,10 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
|||
}
|
||||
|
||||
// Build the result object and return it.
|
||||
if (results.jsonList().isEmpty()) {
|
||||
if (results.entitySearchResults().isEmpty()) {
|
||||
throw new NotFoundException("No entities found");
|
||||
}
|
||||
ImmutableMap.Builder<String, Object> jsonBuilder = new ImmutableMap.Builder<>();
|
||||
jsonBuilder.put("entitySearchResults", results.jsonList());
|
||||
rdapJsonFormatter.addTopLevelEntries(
|
||||
jsonBuilder,
|
||||
BoilerplateType.ENTITY,
|
||||
getNotices(results),
|
||||
ImmutableList.of(),
|
||||
fullServletPath);
|
||||
return jsonBuilder.build();
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -223,7 +214,7 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
|||
* href="https://newgtlds.icann.org/sites/default/files/agreements/agreement-approved-09jan14-en.htm">1.6
|
||||
* of Section 4 of the Base Registry Agreement</a>
|
||||
*/
|
||||
private RdapSearchResults searchByName(
|
||||
private EntitySearchResponse searchByName(
|
||||
final RdapSearchPattern partialStringQuery,
|
||||
CursorType cursorType,
|
||||
Optional<String> cursorQueryString,
|
||||
|
@ -308,7 +299,7 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
|||
* In both cases, the suffix can be turned into an additional query filter field. For contacts,
|
||||
* there is no equivalent string suffix that can be used as a query filter, so we disallow use.
|
||||
*/
|
||||
private RdapSearchResults searchByHandle(
|
||||
private EntitySearchResponse searchByHandle(
|
||||
final RdapSearchPattern partialStringQuery,
|
||||
CursorType cursorType,
|
||||
Optional<String> cursorQueryString,
|
||||
|
@ -424,7 +415,7 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
|||
* <p>This is a convenience wrapper for the four-argument makeSearchResults; it unpacks the
|
||||
* properties of the {@link RdapResultSet} structure and passes them as separate arguments.
|
||||
*/
|
||||
private RdapSearchResults makeSearchResults(
|
||||
private EntitySearchResponse makeSearchResults(
|
||||
RdapResultSet<ContactResource> resultSet,
|
||||
List<Registrar> registrars,
|
||||
QueryType queryType,
|
||||
|
@ -454,7 +445,7 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
|||
* @param now the current date and time
|
||||
* @return an {@link RdapSearchResults} object
|
||||
*/
|
||||
private RdapSearchResults makeSearchResults(
|
||||
private EntitySearchResponse makeSearchResults(
|
||||
List<ContactResource> contacts,
|
||||
IncompletenessWarningType incompletenessWarningType,
|
||||
int numContactsRetrieved,
|
||||
|
@ -473,25 +464,19 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
|||
// (contacts and registrars), and partially because we try to fetch one more than the max size,
|
||||
// so we can tell whether to display the truncation notification.
|
||||
RdapAuthorization authorization = getAuthorization();
|
||||
List<ImmutableMap<String, Object>> jsonOutputList = new ArrayList<>();
|
||||
// Each time we add a contact or registrar to the output data set, remember what the appropriate
|
||||
// cursor would be if it were the last item returned. When we stop adding items, the last cursor
|
||||
// value we remembered will be the right one to pass back.
|
||||
EntitySearchResponse.Builder builder =
|
||||
EntitySearchResponse.builder()
|
||||
.setIncompletenessWarningType(incompletenessWarningType);
|
||||
Optional<String> newCursor = Optional.empty();
|
||||
for (ContactResource contact : contacts) {
|
||||
if (jsonOutputList.size() >= rdapResultSetMaxSize) {
|
||||
return RdapSearchResults.create(
|
||||
ImmutableList.copyOf(jsonOutputList),
|
||||
IncompletenessWarningType.TRUNCATED,
|
||||
newCursor);
|
||||
}
|
||||
for (ContactResource contact : Iterables.limit(contacts, rdapResultSetMaxSize)) {
|
||||
// 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.
|
||||
jsonOutputList.add(rdapJsonFormatter.makeRdapJsonForContact(
|
||||
builder.entitySearchResultsBuilder().add(rdapJsonFormatter.makeRdapJsonForContact(
|
||||
contact,
|
||||
false,
|
||||
Optional.empty(),
|
||||
fullServletPath,
|
||||
rdapWhoisServer,
|
||||
now,
|
||||
outputDataType,
|
||||
|
@ -503,22 +488,22 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
|
|||
? contact.getSearchName()
|
||||
: contact.getRepoId()));
|
||||
}
|
||||
for (Registrar registrar : registrars) {
|
||||
if (jsonOutputList.size() >= rdapResultSetMaxSize) {
|
||||
return RdapSearchResults.create(
|
||||
ImmutableList.copyOf(jsonOutputList),
|
||||
IncompletenessWarningType.TRUNCATED,
|
||||
newCursor);
|
||||
}
|
||||
jsonOutputList.add(rdapJsonFormatter.makeRdapJsonForRegistrar(
|
||||
registrar, false, fullServletPath, rdapWhoisServer, now, outputDataType));
|
||||
if (rdapResultSetMaxSize > contacts.size()) {
|
||||
for (Registrar registrar :
|
||||
Iterables.limit(registrars, rdapResultSetMaxSize - contacts.size())) {
|
||||
builder
|
||||
.entitySearchResultsBuilder()
|
||||
.add(
|
||||
rdapJsonFormatter.makeRdapJsonForRegistrar(
|
||||
registrar, rdapWhoisServer, now, outputDataType));
|
||||
newCursor = Optional.of(REGISTRAR_CURSOR_PREFIX + registrar.getRegistrarName());
|
||||
}
|
||||
return RdapSearchResults.create(
|
||||
ImmutableList.copyOf(jsonOutputList),
|
||||
(jsonOutputList.size() < rdapResultSetMaxSize)
|
||||
? incompletenessWarningType
|
||||
: IncompletenessWarningType.COMPLETE,
|
||||
Optional.empty());
|
||||
}
|
||||
if (rdapResultSetMaxSize < contacts.size() + registrars.size()) {
|
||||
builder.setNextPageUri(createNavigationUri(newCursor.get()));
|
||||
builder.setIncompletenessWarningType(IncompletenessWarningType.TRUNCATED);
|
||||
return builder.build();
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,12 +17,14 @@ package google.registry.rdap;
|
|||
import static google.registry.request.Action.Method.GET;
|
||||
import static google.registry.request.Action.Method.HEAD;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.rdap.RdapJsonFormatter.BoilerplateType;
|
||||
import google.registry.rdap.RdapDataStructures.Link;
|
||||
import google.registry.rdap.RdapDataStructures.Notice;
|
||||
import google.registry.rdap.RdapMetrics.EndpointType;
|
||||
import google.registry.rdap.RdapObjectClasses.HelpResponse;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.HttpException.NotFoundException;
|
||||
import google.registry.request.auth.Auth;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
|
||||
/** RDAP (new WHOIS) action for help requests. */
|
||||
|
@ -34,22 +36,53 @@ import javax.inject.Inject;
|
|||
auth = Auth.AUTH_PUBLIC_ANONYMOUS)
|
||||
public class RdapHelpAction extends RdapActionBase {
|
||||
|
||||
/** The help path for the RDAP terms of service. */
|
||||
public static final String TOS_PATH = "/tos";
|
||||
|
||||
private static final String RDAP_HELP_LINK =
|
||||
"https://github.com/google/nomulus/blob/master/docs/rdap.md";
|
||||
|
||||
@Inject public RdapHelpAction() {
|
||||
super("help", EndpointType.HELP);
|
||||
}
|
||||
|
||||
private Notice createHelpNotice() {
|
||||
String linkValue = rdapJsonFormatter.makeRdapServletRelativeUrl("help");
|
||||
Link.Builder linkBuilder =
|
||||
Link.builder()
|
||||
.setValue(linkValue)
|
||||
.setRel("alternate")
|
||||
.setHref(RDAP_HELP_LINK)
|
||||
.setType("text/html");
|
||||
return Notice.builder()
|
||||
.setTitle("RDAP Help")
|
||||
.setDescription(
|
||||
"domain/XXXX",
|
||||
"nameserver/XXXX",
|
||||
"entity/XXXX",
|
||||
"domains?name=XXXX",
|
||||
"domains?nsLdhName=XXXX",
|
||||
"domains?nsIp=XXXX",
|
||||
"nameservers?name=XXXX",
|
||||
"nameservers?ip=XXXX",
|
||||
"entities?fn=XXXX",
|
||||
"entities?handle=XXXX",
|
||||
"help/XXXX")
|
||||
.addLink(linkBuilder.build())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableMap<String, Object> getJsonObjectForResource(
|
||||
public HelpResponse getJsonObjectForResource(
|
||||
String pathSearchString, boolean isHeadRequest) {
|
||||
// We rely on addTopLevelEntries to notice if we are sending the TOS notice, and not add a
|
||||
// duplicate boilerplate entry.
|
||||
ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
|
||||
rdapJsonFormatter.addTopLevelEntries(
|
||||
builder,
|
||||
BoilerplateType.OTHER,
|
||||
ImmutableList.of(rdapJsonFormatter.getJsonHelpNotice(pathSearchString, fullServletPath)),
|
||||
ImmutableList.of(),
|
||||
fullServletPath);
|
||||
return builder.build();
|
||||
if (pathSearchString.isEmpty() || pathSearchString.equals("/")) {
|
||||
return HelpResponse.create(Optional.of(createHelpNotice()));
|
||||
}
|
||||
if (pathSearchString.equals(TOS_PATH)) {
|
||||
// A TOS notice is added to every reply automatically, so we don't want to add another one
|
||||
// here
|
||||
return HelpResponse.create(Optional.empty());
|
||||
}
|
||||
throw new NotFoundException("no help found for " + pathSearchString);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,145 +15,143 @@
|
|||
package google.registry.rdap;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.rdap.RdapDataStructures.Link;
|
||||
import google.registry.rdap.RdapDataStructures.Notice;
|
||||
import google.registry.rdap.RdapDataStructures.Remark;
|
||||
|
||||
/**
|
||||
* This file contains boilerplate required by the ICANN RDAP Profile.
|
||||
*
|
||||
* @see <a href="https://www.icann.org/resources/pages/rdap-operational-profile-2016-07-26-en">RDAP Operational Profile for gTLD Registries and Registrars</a>
|
||||
* @see <a href="https://www.icann.org/resources/pages/rdap-operational-profile-2016-07-26-en">RDAP
|
||||
* Operational Profile for gTLD Registries and Registrars</a>
|
||||
*/
|
||||
|
||||
public class RdapIcannStandardInformation {
|
||||
|
||||
/** Required by ICANN RDAP Profile section 1.4.10. */
|
||||
private static final ImmutableMap<String, Object> CONFORMANCE_NOTICE =
|
||||
ImmutableMap.of(
|
||||
"description",
|
||||
ImmutableList.of(
|
||||
private static final Notice CONFORMANCE_NOTICE =
|
||||
Notice.builder()
|
||||
.setDescription(
|
||||
"This response conforms to the RDAP Operational Profile for gTLD Registries and"
|
||||
+ " Registrars version 1.0"));
|
||||
+ " Registrars version 1.0")
|
||||
.build();
|
||||
|
||||
/** Required by ICANN RDAP Profile section 1.5.18. */
|
||||
private static final ImmutableMap<String, Object> DOMAIN_STATUS_CODES_NOTICE =
|
||||
ImmutableMap.of(
|
||||
"title",
|
||||
"Status Codes",
|
||||
"description",
|
||||
ImmutableList.of(
|
||||
"For more information on domain status codes, please visit https://icann.org/epp"),
|
||||
"links",
|
||||
ImmutableList.of(
|
||||
ImmutableMap.of(
|
||||
"value", "https://icann.org/epp",
|
||||
"rel", "alternate",
|
||||
"href", "https://icann.org/epp",
|
||||
"type", "text/html")));
|
||||
private static final Notice DOMAIN_STATUS_CODES_NOTICE =
|
||||
Notice.builder()
|
||||
.setTitle("Status Codes")
|
||||
.setDescription(
|
||||
"For more information on domain status codes, please visit"
|
||||
+ " https://icann.org/epp")
|
||||
.addLink(
|
||||
Link.builder()
|
||||
.setValue("https://icann.org/epp")
|
||||
.setRel("alternate")
|
||||
.setHref("https://icann.org/epp")
|
||||
.setType("text/html")
|
||||
.build())
|
||||
.build();
|
||||
|
||||
/** Required by ICANN RDAP Profile section 1.5.20. */
|
||||
private static final ImmutableMap<String, Object> INACCURACY_COMPLAINT_FORM_NOTICE =
|
||||
ImmutableMap.of(
|
||||
"description",
|
||||
ImmutableList.of(
|
||||
"URL of the ICANN Whois Inaccuracy Complaint Form: https://www.icann.org/wicf"),
|
||||
"links",
|
||||
ImmutableList.of(
|
||||
ImmutableMap.of(
|
||||
"value", "https://www.icann.org/wicf",
|
||||
"rel", "alternate",
|
||||
"href", "https://www.icann.org/wicf",
|
||||
"type", "text/html")));
|
||||
private static final Notice INACCURACY_COMPLAINT_FORM_NOTICE =
|
||||
Notice.builder()
|
||||
.setDescription(
|
||||
"URL of the ICANN Whois Inaccuracy Complaint Form: https://www.icann.org/wicf")
|
||||
.addLink(
|
||||
Link.builder()
|
||||
.setValue("https://www.icann.org/wicf")
|
||||
.setRel("alternate")
|
||||
.setHref("https://www.icann.org/wicf")
|
||||
.setType("text/html")
|
||||
.build())
|
||||
.build();
|
||||
|
||||
/** Boilerplate notices required by domain responses. */
|
||||
static final ImmutableList<ImmutableMap<String, Object>> domainBoilerplateNotices =
|
||||
static final ImmutableList<Notice> domainBoilerplateNotices =
|
||||
ImmutableList.of(
|
||||
CONFORMANCE_NOTICE, DOMAIN_STATUS_CODES_NOTICE, INACCURACY_COMPLAINT_FORM_NOTICE);
|
||||
CONFORMANCE_NOTICE,
|
||||
// RDAP Response Profile 2.6.3
|
||||
DOMAIN_STATUS_CODES_NOTICE,
|
||||
INACCURACY_COMPLAINT_FORM_NOTICE);
|
||||
|
||||
/** Boilerplate remarks required by nameserver and entity responses. */
|
||||
static final ImmutableList<ImmutableMap<String, Object>> nameserverAndEntityBoilerplateNotices =
|
||||
static final ImmutableList<Notice> nameserverAndEntityBoilerplateNotices =
|
||||
ImmutableList.of(CONFORMANCE_NOTICE);
|
||||
|
||||
/**
|
||||
* Required by ICANN RDAP Profile section 1.4.9, as corrected by Gustavo Lozano of ICANN.
|
||||
*
|
||||
* @see <a href="http://mm.icann.org/pipermail/gtld-tech/2016-October/000822.html">Questions about the ICANN RDAP Profile</a>
|
||||
* @see <a href="http://mm.icann.org/pipermail/gtld-tech/2016-October/000822.html">Questions about
|
||||
* the ICANN RDAP Profile</a>
|
||||
*/
|
||||
static final ImmutableMap<String, Object> SUMMARY_DATA_REMARK =
|
||||
ImmutableMap.of(
|
||||
"title",
|
||||
"Incomplete Data",
|
||||
"description",
|
||||
ImmutableList.of(
|
||||
"Summary data only. For complete data, send a specific query for the object."),
|
||||
"type",
|
||||
"object truncated due to unexplainable reasons");
|
||||
static final Remark SUMMARY_DATA_REMARK =
|
||||
Remark.builder()
|
||||
.setTitle("Incomplete Data")
|
||||
.setDescription(
|
||||
"Summary data only. For complete data, send a specific query for the object.")
|
||||
.setType(Remark.Type.OBJECT_TRUNCATED_UNEXPLAINABLE)
|
||||
.build();
|
||||
|
||||
/**
|
||||
* Required by ICANN RDAP Profile section 1.4.8, as corrected by Gustavo Lozano of ICANN.
|
||||
*
|
||||
* @see <a href="http://mm.icann.org/pipermail/gtld-tech/2016-October/000822.html">Questions about the ICANN RDAP Profile</a>
|
||||
* @see <a href="http://mm.icann.org/pipermail/gtld-tech/2016-October/000822.html">Questions about
|
||||
* the ICANN RDAP Profile</a>
|
||||
*/
|
||||
static final ImmutableMap<String, Object> TRUNCATED_RESULT_SET_NOTICE =
|
||||
ImmutableMap.of(
|
||||
"title",
|
||||
"Search Policy",
|
||||
"description",
|
||||
ImmutableList.of("Search results per query are limited."),
|
||||
"type",
|
||||
"result set truncated due to unexplainable reasons");
|
||||
static final Notice TRUNCATED_RESULT_SET_NOTICE =
|
||||
Notice.builder()
|
||||
.setTitle("Search Policy")
|
||||
.setDescription("Search results per query are limited.")
|
||||
.setType(Notice.Type.RESULT_TRUNCATED_UNEXPLAINABLE)
|
||||
.build();
|
||||
|
||||
/** Truncation notice as a singleton list, for easy use. */
|
||||
static final ImmutableList<ImmutableMap<String, Object>> TRUNCATION_NOTICES =
|
||||
static final ImmutableList<Notice> TRUNCATION_NOTICES =
|
||||
ImmutableList.of(TRUNCATED_RESULT_SET_NOTICE);
|
||||
|
||||
/**
|
||||
* Used when a search for domains by nameserver may have returned incomplete information because
|
||||
* there were too many nameservers in the first stage results.
|
||||
*/
|
||||
static final ImmutableMap<String, Object> POSSIBLY_INCOMPLETE_RESULT_SET_NOTICE =
|
||||
ImmutableMap.of(
|
||||
"title",
|
||||
"Search Policy",
|
||||
"description",
|
||||
ImmutableList.of(
|
||||
"Search results may contain incomplete information due to first-stage query limits."),
|
||||
"type",
|
||||
"result set truncated due to unexplainable reasons");
|
||||
static final Notice POSSIBLY_INCOMPLETE_RESULT_SET_NOTICE =
|
||||
Notice.builder()
|
||||
.setTitle("Search Policy")
|
||||
.setDescription(
|
||||
"Search results may contain incomplete information due to first-stage query"
|
||||
+ " limits.")
|
||||
.setType(Notice.Type.RESULT_TRUNCATED_UNEXPLAINABLE)
|
||||
.build();
|
||||
|
||||
/** Possibly incomplete notice as a singleton list, for easy use. */
|
||||
static final ImmutableList<ImmutableMap<String, Object>> POSSIBLY_INCOMPLETE_NOTICES =
|
||||
static final ImmutableList<Notice> POSSIBLY_INCOMPLETE_NOTICES =
|
||||
ImmutableList.of(POSSIBLY_INCOMPLETE_RESULT_SET_NOTICE);
|
||||
|
||||
/** Included when the requester is not logged in as the owner of the domain being returned. */
|
||||
static final ImmutableMap<String, Object> DOMAIN_CONTACTS_HIDDEN_DATA_REMARK =
|
||||
ImmutableMap.of(
|
||||
"title",
|
||||
"Contacts Hidden",
|
||||
"description",
|
||||
ImmutableList.of("Domain contacts are visible only to the owning registrar."),
|
||||
"type",
|
||||
"object truncated due to unexplainable reasons");
|
||||
static final Remark DOMAIN_CONTACTS_HIDDEN_DATA_REMARK =
|
||||
Remark.builder()
|
||||
.setTitle("Contacts Hidden")
|
||||
.setDescription("Domain contacts are visible only to the owning registrar.")
|
||||
.setType(Remark.Type.OBJECT_TRUNCATED_UNEXPLAINABLE)
|
||||
.build();
|
||||
|
||||
/**
|
||||
* Included when requester is not logged in as the owner of the contact being returned. Format
|
||||
* required by ICANN RDAP Pilot Profile draft section 1.4.11.
|
||||
* required by ICANN RDAP Response Profile 15feb19 section 2.7.4.3.
|
||||
*/
|
||||
static final ImmutableMap<String, Object> CONTACT_PERSONAL_DATA_HIDDEN_DATA_REMARK =
|
||||
ImmutableMap.of(
|
||||
"title",
|
||||
"Data Policy",
|
||||
"description",
|
||||
ImmutableList.of(
|
||||
static final Remark CONTACT_PERSONAL_DATA_HIDDEN_DATA_REMARK =
|
||||
Remark.builder()
|
||||
.setTitle("Redacted for Privacy")
|
||||
.setDescription(
|
||||
"Some of the data in this object has been removed.",
|
||||
"Contact personal data is visible only to the owning registrar."),
|
||||
"type",
|
||||
"object truncated due to authorization",
|
||||
"links",
|
||||
ImmutableList.of(
|
||||
ImmutableMap.of(
|
||||
"value",
|
||||
"https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
|
||||
"rel", "alternate",
|
||||
"href",
|
||||
"https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
|
||||
"type", "text/html")));
|
||||
"Contact personal data is visible only to the owning registrar.")
|
||||
.setType(Remark.Type.OBJECT_REDACTED_AUTHORIZATION)
|
||||
.addLink(
|
||||
Link.builder()
|
||||
.setValue(
|
||||
"https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication")
|
||||
.setRel("alternate")
|
||||
.setHref(
|
||||
"https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication")
|
||||
.setType("text/html")
|
||||
.build())
|
||||
.build();
|
||||
}
|
||||
|
|
|
@ -17,8 +17,8 @@ package google.registry.rdap;
|
|||
import static google.registry.request.Action.Method.GET;
|
||||
import static google.registry.request.Action.Method.HEAD;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.rdap.RdapMetrics.EndpointType;
|
||||
import google.registry.rdap.RdapObjectClasses.ReplyPayloadBase;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.HttpException.NotImplementedException;
|
||||
import google.registry.request.auth.Auth;
|
||||
|
@ -43,8 +43,7 @@ public class RdapIpAction extends RdapActionBase {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ImmutableMap<String, Object> getJsonObjectForResource(
|
||||
String pathSearchString, boolean isHeadRequest) {
|
||||
public ReplyPayloadBase getJsonObjectForResource(String pathSearchString, boolean isHeadRequest) {
|
||||
throw new NotImplementedException("Domain Name Registry information only");
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -20,11 +20,11 @@ import static google.registry.request.Action.Method.GET;
|
|||
import static google.registry.request.Action.Method.HEAD;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.model.host.HostResource;
|
||||
import google.registry.rdap.RdapJsonFormatter.OutputDataType;
|
||||
import google.registry.rdap.RdapMetrics.EndpointType;
|
||||
import google.registry.rdap.RdapObjectClasses.RdapNameserver;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.HttpException.BadRequestException;
|
||||
import google.registry.request.HttpException.NotFoundException;
|
||||
|
@ -47,8 +47,7 @@ public class RdapNameserverAction extends RdapActionBase {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ImmutableMap<String, Object> getJsonObjectForResource(
|
||||
String pathSearchString, boolean isHeadRequest) {
|
||||
public RdapNameserver getJsonObjectForResource(String pathSearchString, boolean isHeadRequest) {
|
||||
DateTime now = clock.nowUtc();
|
||||
pathSearchString = canonicalizeName(pathSearchString);
|
||||
// The RDAP syntax is /rdap/nameserver/ns1.mydomain.com.
|
||||
|
@ -69,6 +68,6 @@ public class RdapNameserverAction extends RdapActionBase {
|
|||
throw new NotFoundException(pathSearchString + " not found");
|
||||
}
|
||||
return rdapJsonFormatter.makeRdapJsonForHost(
|
||||
hostResource.get(), true, fullServletPath, rdapWhoisServer, now, OutputDataType.FULL);
|
||||
hostResource.get(), rdapWhoisServer, now, OutputDataType.FULL);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,6 @@ import static google.registry.model.EppResourceUtils.loadByForeignKey;
|
|||
import static google.registry.request.Action.Method.GET;
|
||||
import static google.registry.request.Action.Method.HEAD;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.net.InetAddresses;
|
||||
|
@ -27,11 +25,11 @@ import com.google.common.primitives.Booleans;
|
|||
import com.googlecode.objectify.cmd.Query;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
import google.registry.model.host.HostResource;
|
||||
import google.registry.rdap.RdapJsonFormatter.BoilerplateType;
|
||||
import google.registry.rdap.RdapJsonFormatter.OutputDataType;
|
||||
import google.registry.rdap.RdapMetrics.EndpointType;
|
||||
import google.registry.rdap.RdapMetrics.SearchType;
|
||||
import google.registry.rdap.RdapSearchResults.IncompletenessWarningType;
|
||||
import google.registry.rdap.RdapSearchResults.NameserverSearchResponse;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.HttpException.BadRequestException;
|
||||
import google.registry.request.HttpException.NotFoundException;
|
||||
|
@ -82,7 +80,7 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
|||
* <p>The RDAP spec allows nameserver search by either name or IP address.
|
||||
*/
|
||||
@Override
|
||||
public ImmutableMap<String, Object> getJsonObjectForResource(
|
||||
public NameserverSearchResponse getJsonObjectForResource(
|
||||
String pathSearchString, boolean isHeadRequest) {
|
||||
DateTime now = clock.nowUtc();
|
||||
// RDAP syntax example: /rdap/nameservers?name=ns*.example.com.
|
||||
|
@ -94,7 +92,7 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
|||
throw new BadRequestException("You must specify either name=XXXX or ip=YYYY");
|
||||
}
|
||||
decodeCursorToken();
|
||||
RdapSearchResults results;
|
||||
NameserverSearchResponse results;
|
||||
if (nameParam.isPresent()) {
|
||||
// syntax: /rdap/nameservers?name=exam*.com
|
||||
metricInformationBuilder.setSearchType(SearchType.BY_NAMESERVER_NAME);
|
||||
|
@ -118,19 +116,10 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
|||
}
|
||||
results = searchByIp(inetAddress, now);
|
||||
}
|
||||
if (results.jsonList().isEmpty()) {
|
||||
if (results.nameserverSearchResults().isEmpty()) {
|
||||
throw new NotFoundException("No nameservers found");
|
||||
}
|
||||
ImmutableMap.Builder<String, Object> jsonBuilder = new ImmutableMap.Builder<>();
|
||||
jsonBuilder.put("nameserverSearchResults", results.jsonList());
|
||||
|
||||
rdapJsonFormatter.addTopLevelEntries(
|
||||
jsonBuilder,
|
||||
BoilerplateType.NAMESERVER,
|
||||
getNotices(results),
|
||||
ImmutableList.of(),
|
||||
fullServletPath);
|
||||
return jsonBuilder.build();
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -139,7 +128,7 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
|||
* <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.
|
||||
*/
|
||||
private RdapSearchResults searchByName(
|
||||
private NameserverSearchResponse searchByName(
|
||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
||||
// 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.
|
||||
|
@ -168,7 +157,7 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
|||
*
|
||||
* <p>In this case, we can load by foreign key.
|
||||
*/
|
||||
private RdapSearchResults searchByNameUsingForeignKey(
|
||||
private NameserverSearchResponse searchByNameUsingForeignKey(
|
||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
||||
Optional<HostResource> hostResource =
|
||||
loadByForeignKey(HostResource.class, partialStringQuery.getInitialString(), now);
|
||||
|
@ -177,19 +166,21 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
|||
throw new NotFoundException("No nameservers found");
|
||||
}
|
||||
metricInformationBuilder.setNumHostsRetrieved(1);
|
||||
return RdapSearchResults.create(
|
||||
ImmutableList.of(
|
||||
|
||||
NameserverSearchResponse.Builder builder =
|
||||
NameserverSearchResponse.builder()
|
||||
.setIncompletenessWarningType(IncompletenessWarningType.COMPLETE);
|
||||
builder.nameserverSearchResultsBuilder().add(
|
||||
rdapJsonFormatter.makeRdapJsonForHost(
|
||||
hostResource.get(),
|
||||
false,
|
||||
fullServletPath,
|
||||
rdapWhoisServer,
|
||||
now,
|
||||
OutputDataType.FULL)));
|
||||
OutputDataType.FULL));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/** Searches for nameservers by name using the superordinate domain as a suffix. */
|
||||
private RdapSearchResults searchByNameUsingSuperordinateDomain(
|
||||
private NameserverSearchResponse searchByNameUsingSuperordinateDomain(
|
||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
||||
Optional<DomainBase> domainBase =
|
||||
loadByForeignKey(DomainBase.class, partialStringQuery.getSuffix(), now);
|
||||
|
@ -232,7 +223,7 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
|||
*
|
||||
* <p>There are no pending deletes for hosts, so we can call {@link RdapActionBase#queryItems}.
|
||||
*/
|
||||
private RdapSearchResults searchByNameUsingPrefix(
|
||||
private NameserverSearchResponse searchByNameUsingPrefix(
|
||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
||||
// Add 1 so we can detect truncation.
|
||||
int querySizeLimit = getStandardQuerySizeLimit();
|
||||
|
@ -251,7 +242,7 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
|||
}
|
||||
|
||||
/** Searches for nameservers by IP address, returning a JSON array of nameserver info maps. */
|
||||
private RdapSearchResults searchByIp(final InetAddress inetAddress, DateTime now) {
|
||||
private NameserverSearchResponse searchByIp(final InetAddress inetAddress, DateTime now) {
|
||||
// Add 1 so we can detect truncation.
|
||||
int querySizeLimit = getStandardQuerySizeLimit();
|
||||
Query<HostResource> query =
|
||||
|
@ -270,7 +261,7 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
|||
}
|
||||
|
||||
/** Output JSON for a lists of hosts contained in an {@link RdapResultSet}. */
|
||||
private RdapSearchResults makeSearchResults(
|
||||
private NameserverSearchResponse makeSearchResults(
|
||||
RdapResultSet<HostResource> resultSet, CursorType cursorType, DateTime now) {
|
||||
return makeSearchResults(
|
||||
resultSet.resources(),
|
||||
|
@ -281,7 +272,7 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
|||
}
|
||||
|
||||
/** Output JSON for a list of hosts. */
|
||||
private RdapSearchResults makeSearchResults(
|
||||
private NameserverSearchResponse makeSearchResults(
|
||||
List<HostResource> hosts,
|
||||
IncompletenessWarningType incompletenessWarningType,
|
||||
int numHostsRetrieved,
|
||||
|
@ -290,8 +281,8 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
|||
metricInformationBuilder.setNumHostsRetrieved(numHostsRetrieved);
|
||||
OutputDataType outputDataType =
|
||||
(hosts.size() > 1) ? OutputDataType.SUMMARY : OutputDataType.FULL;
|
||||
ImmutableList.Builder<ImmutableMap<String, Object>> jsonListBuilder =
|
||||
new ImmutableList.Builder<>();
|
||||
NameserverSearchResponse.Builder builder =
|
||||
NameserverSearchResponse.builder().setIncompletenessWarningType(incompletenessWarningType);
|
||||
Optional<String> newCursor = Optional.empty();
|
||||
for (HostResource host : Iterables.limit(hosts, rdapResultSetMaxSize)) {
|
||||
newCursor =
|
||||
|
@ -299,15 +290,14 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
|
|||
(cursorType == CursorType.NAME)
|
||||
? host.getFullyQualifiedHostName()
|
||||
: host.getRepoId());
|
||||
jsonListBuilder.add(
|
||||
builder.nameserverSearchResultsBuilder().add(
|
||||
rdapJsonFormatter.makeRdapJsonForHost(
|
||||
host, false, fullServletPath, rdapWhoisServer, now, outputDataType));
|
||||
}
|
||||
ImmutableList<ImmutableMap<String, Object>> jsonList = jsonListBuilder.build();
|
||||
if (jsonList.size() < hosts.size()) {
|
||||
return RdapSearchResults.create(jsonList, IncompletenessWarningType.TRUNCATED, newCursor);
|
||||
} else {
|
||||
return RdapSearchResults.create(jsonList, incompletenessWarningType, Optional.empty());
|
||||
host, rdapWhoisServer, now, outputDataType));
|
||||
}
|
||||
if (rdapResultSetMaxSize < hosts.size()) {
|
||||
builder.setNextPageUri(createNavigationUri(newCursor.get()));
|
||||
builder.setIncompletenessWarningType(IncompletenessWarningType.TRUNCATED);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
|
|
442
java/google/registry/rdap/RdapObjectClasses.java
Normal file
442
java/google/registry/rdap/RdapObjectClasses.java
Normal file
|
@ -0,0 +1,442 @@
|
|||
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.rdap;
|
||||
|
||||
import static google.registry.util.DomainNameUtils.ACE_PREFIX;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Ordering;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import google.registry.rdap.AbstractJsonableObject.RestrictJsonNames;
|
||||
import google.registry.rdap.RdapDataStructures.Event;
|
||||
import google.registry.rdap.RdapDataStructures.EventWithoutActor;
|
||||
import google.registry.rdap.RdapDataStructures.LanguageIdentifier;
|
||||
import google.registry.rdap.RdapDataStructures.Link;
|
||||
import google.registry.rdap.RdapDataStructures.Notice;
|
||||
import google.registry.rdap.RdapDataStructures.ObjectClassName;
|
||||
import google.registry.rdap.RdapDataStructures.Port43WhoisServer;
|
||||
import google.registry.rdap.RdapDataStructures.PublicId;
|
||||
import google.registry.rdap.RdapDataStructures.RdapConformance;
|
||||
import google.registry.rdap.RdapDataStructures.RdapStatus;
|
||||
import google.registry.rdap.RdapDataStructures.Remark;
|
||||
import google.registry.util.Idn;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Object Classes defined in RFC7483 section 5.
|
||||
*/
|
||||
final class RdapObjectClasses {
|
||||
|
||||
/**
|
||||
* Temporary implementation of VCards.
|
||||
*
|
||||
* Will create a better implementation soon.
|
||||
*/
|
||||
@RestrictJsonNames({})
|
||||
@AutoValue
|
||||
abstract static class Vcard implements Jsonable {
|
||||
abstract String property();
|
||||
abstract ImmutableMap<String, ImmutableList<String>> parameters();
|
||||
abstract String valueType();
|
||||
abstract JsonElement value();
|
||||
|
||||
static Vcard create(
|
||||
String property,
|
||||
ImmutableMap<String, ImmutableList<String>> parameters,
|
||||
String valueType,
|
||||
JsonElement value) {
|
||||
return new AutoValue_RdapObjectClasses_Vcard(property, parameters, valueType, value);
|
||||
}
|
||||
|
||||
static Vcard create(
|
||||
String property,
|
||||
ImmutableMap<String, ImmutableList<String>> parameters,
|
||||
String valueType,
|
||||
String value) {
|
||||
return create(property, parameters, valueType, new JsonPrimitive(value));
|
||||
}
|
||||
|
||||
static Vcard create(String property, String valueType, JsonElement value) {
|
||||
return create(property, ImmutableMap.of(), valueType, value);
|
||||
}
|
||||
|
||||
static Vcard create(String property, String valueType, String value) {
|
||||
return create(property, valueType, new JsonPrimitive(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonArray toJson() {
|
||||
JsonArray jsonArray = new JsonArray();
|
||||
jsonArray.add(property());
|
||||
jsonArray.add(new Gson().toJsonTree(parameters()));
|
||||
jsonArray.add(valueType());
|
||||
jsonArray.add(value());
|
||||
return jsonArray;
|
||||
}
|
||||
}
|
||||
|
||||
@RestrictJsonNames("vcardArray")
|
||||
@AutoValue
|
||||
abstract static class VcardArray implements Jsonable {
|
||||
|
||||
private static final String VCARD_VERSION_NUMBER = "4.0";
|
||||
private static final Vcard VCARD_ENTRY_VERSION =
|
||||
Vcard.create("version", "text", VCARD_VERSION_NUMBER);
|
||||
|
||||
abstract ImmutableList<Vcard> vcards();
|
||||
|
||||
@Override
|
||||
public JsonArray toJson() {
|
||||
JsonArray jsonArray = new JsonArray();
|
||||
jsonArray.add("vcard");
|
||||
JsonArray jsonVcardsArray = new JsonArray();
|
||||
jsonVcardsArray.add(VCARD_ENTRY_VERSION.toJson());
|
||||
vcards().forEach(vcard -> jsonVcardsArray.add(vcard.toJson()));
|
||||
jsonArray.add(jsonVcardsArray);
|
||||
return jsonArray;
|
||||
}
|
||||
|
||||
static Builder builder() {
|
||||
return new AutoValue_RdapObjectClasses_VcardArray.Builder();
|
||||
}
|
||||
|
||||
@AutoValue.Builder
|
||||
abstract static class Builder {
|
||||
abstract ImmutableList.Builder<Vcard> vcardsBuilder();
|
||||
Builder add(Vcard vcard) {
|
||||
vcardsBuilder().add(vcard);
|
||||
return this;
|
||||
}
|
||||
|
||||
abstract VcardArray build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indication of what type of boilerplate notices are required for the RDAP JSON messages. The
|
||||
* ICANN RDAP Profile specifies that, for instance, domain name responses should include a remark
|
||||
* about domain status codes. So we need to know when to include such boilerplate. On the other
|
||||
* hand, remarks are not allowed except in domain, nameserver and entity objects, so we need to
|
||||
* suppress them for other types of responses (e.g. help).
|
||||
*/
|
||||
public enum BoilerplateType {
|
||||
DOMAIN,
|
||||
NAMESERVER,
|
||||
ENTITY,
|
||||
OTHER
|
||||
}
|
||||
|
||||
/**
|
||||
* An object that can be used to create a TopLevelReply.
|
||||
*
|
||||
* All Actions need to return an object of this type.
|
||||
*/
|
||||
@RestrictJsonNames("*")
|
||||
abstract static class ReplyPayloadBase extends AbstractJsonableObject {
|
||||
final BoilerplateType boilerplateType;
|
||||
|
||||
ReplyPayloadBase(BoilerplateType boilerplateType) {
|
||||
this.boilerplateType = boilerplateType;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The Top Level JSON reply, Adds the required top-level boilerplate to a ReplyPayloadBase.
|
||||
*
|
||||
* <p>RFC 7483 specifies that the top-level object should include an entry indicating the
|
||||
* conformance level. ICANN RDAP spec for 15feb19 mandates several additional entries, in sections
|
||||
* 2.6.3, 2.11 of the Response Profile and 3.3.2, 3.5, of the Technical Implementation Guide.
|
||||
*/
|
||||
@AutoValue
|
||||
@RestrictJsonNames({})
|
||||
abstract static class TopLevelReplyObject extends AbstractJsonableObject {
|
||||
@JsonableElement("rdapConformance")
|
||||
static final RdapConformance RDAP_CONFORMANCE = RdapConformance.INSTANCE;
|
||||
|
||||
@JsonableElement("*") abstract ReplyPayloadBase aAreplyObject();
|
||||
@JsonableElement("notices[]") abstract Notice aTosNotice();
|
||||
|
||||
@JsonableElement("notices") ImmutableList<Notice> boilerplateNotices() {
|
||||
switch (aAreplyObject().boilerplateType) {
|
||||
case DOMAIN:
|
||||
return RdapIcannStandardInformation.domainBoilerplateNotices;
|
||||
case NAMESERVER:
|
||||
case ENTITY:
|
||||
return RdapIcannStandardInformation.nameserverAndEntityBoilerplateNotices;
|
||||
default: // things other than domains, nameservers and entities do not yet have boilerplate
|
||||
return ImmutableList.of();
|
||||
}
|
||||
}
|
||||
|
||||
static TopLevelReplyObject create(ReplyPayloadBase replyObject, Notice tosNotice) {
|
||||
return new AutoValue_RdapObjectClasses_TopLevelReplyObject(replyObject, tosNotice);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A base object shared by Entity, Nameserver, and Domain.
|
||||
*
|
||||
* <p>Not part of the spec, but seems convenient.
|
||||
*/
|
||||
private abstract static class RdapObjectBase extends ReplyPayloadBase {
|
||||
@JsonableElement final ObjectClassName objectClassName;
|
||||
|
||||
@JsonableElement abstract Optional<String> handle();
|
||||
@JsonableElement abstract ImmutableList<PublicId> publicIds();
|
||||
@JsonableElement abstract ImmutableList<RdapEntity> entities();
|
||||
@JsonableElement abstract ImmutableList<RdapStatus> status();
|
||||
@JsonableElement abstract ImmutableList<Remark> remarks();
|
||||
@JsonableElement abstract ImmutableList<Link> links();
|
||||
@JsonableElement abstract Optional<Port43WhoisServer> port43();
|
||||
@JsonableElement abstract ImmutableList<Event> events();
|
||||
|
||||
RdapObjectBase(BoilerplateType boilerplateType, ObjectClassName objectClassName) {
|
||||
super(boilerplateType);
|
||||
this.objectClassName = objectClassName;
|
||||
}
|
||||
|
||||
|
||||
abstract static class Builder<B extends Builder<?>> {
|
||||
abstract B setHandle(String handle);
|
||||
abstract ImmutableList.Builder<PublicId> publicIdsBuilder();
|
||||
abstract ImmutableList.Builder<RdapEntity> entitiesBuilder();
|
||||
abstract ImmutableList.Builder<RdapStatus> statusBuilder();
|
||||
abstract ImmutableList.Builder<Remark> remarksBuilder();
|
||||
abstract ImmutableList.Builder<Link> linksBuilder();
|
||||
abstract B setPort43(Port43WhoisServer port43);
|
||||
abstract ImmutableList.Builder<Event> eventsBuilder();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The Entity Object Class defined in 5.1 of RFC7483.
|
||||
*
|
||||
* <p>We're missing the "autnums" and "networks" fields
|
||||
*/
|
||||
@RestrictJsonNames({"entities[]", "entitySearchResults[]"})
|
||||
@AutoValue
|
||||
abstract static class RdapEntity extends RdapObjectBase {
|
||||
|
||||
/** Role values specified in RFC 7483 § 10.2.4. */
|
||||
@RestrictJsonNames("roles[]")
|
||||
enum Role implements Jsonable {
|
||||
REGISTRANT("registrant"),
|
||||
TECH("technical"),
|
||||
ADMIN("administrative"),
|
||||
ABUSE("abuse"),
|
||||
BILLING("billing"),
|
||||
REGISTRAR("registrar"),
|
||||
RESELLER("reseller"),
|
||||
SPONSOR("sponsor"),
|
||||
PROXY("proxy"),
|
||||
NOTIFICATIONS("notifications"),
|
||||
NOC("noc");
|
||||
|
||||
/** Value as it appears in RDAP messages. */
|
||||
final String rfc7483String;
|
||||
|
||||
Role(String rfc7483String) {
|
||||
this.rfc7483String = rfc7483String;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonPrimitive toJson() {
|
||||
return new JsonPrimitive(rfc7483String);
|
||||
}
|
||||
}
|
||||
|
||||
RdapEntity() {
|
||||
super(BoilerplateType.ENTITY, ObjectClassName.ENTITY);
|
||||
}
|
||||
|
||||
@JsonableElement abstract Optional<VcardArray> vcardArray();
|
||||
@JsonableElement abstract ImmutableSet<Role> roles();
|
||||
@JsonableElement abstract ImmutableList<EventWithoutActor> asEventActor();
|
||||
|
||||
static Builder builder() {
|
||||
return new AutoValue_RdapObjectClasses_RdapEntity.Builder();
|
||||
}
|
||||
|
||||
@AutoValue.Builder
|
||||
abstract static class Builder extends RdapObjectBase.Builder<Builder> {
|
||||
abstract Builder setVcardArray(VcardArray vcardArray);
|
||||
abstract ImmutableSet.Builder<Role> rolesBuilder();
|
||||
abstract ImmutableList.Builder<EventWithoutActor> asEventActorBuilder();
|
||||
|
||||
abstract RdapEntity build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A base object shared by Nameserver, and Domain.
|
||||
*
|
||||
* <p>Takes care of the name and unicode field.
|
||||
*
|
||||
* <p>See RDAP Response Profile 15feb19 sections 2.1 and 4.1.
|
||||
*
|
||||
* <p>Not part of the spec, but seems convenient.
|
||||
*/
|
||||
private abstract static class RdapNamedObjectBase extends RdapObjectBase {
|
||||
|
||||
@JsonableElement abstract String ldhName();
|
||||
|
||||
@JsonableElement final Optional<String> unicodeName() {
|
||||
// Only include the unicodeName field if there are unicode characters.
|
||||
//
|
||||
// TODO(b/127490882) Consider removing the condition (i.e. always having the unicodeName
|
||||
// field)
|
||||
if (!hasUnicodeComponents(ldhName())) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.of(Idn.toUnicode(ldhName()));
|
||||
}
|
||||
|
||||
private static boolean hasUnicodeComponents(String fullyQualifiedName) {
|
||||
return fullyQualifiedName.startsWith(ACE_PREFIX)
|
||||
|| fullyQualifiedName.contains("." + ACE_PREFIX);
|
||||
}
|
||||
|
||||
abstract static class Builder<B extends Builder<?>> extends RdapObjectBase.Builder<B> {
|
||||
abstract B setLdhName(String ldhName);
|
||||
}
|
||||
|
||||
RdapNamedObjectBase(BoilerplateType boilerplateType, ObjectClassName objectClassName) {
|
||||
super(boilerplateType, objectClassName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The Nameserver Object Class defined in 5.2 of RFC7483.
|
||||
*/
|
||||
@RestrictJsonNames({"nameservers[]", "nameserverSearchResults[]"})
|
||||
@AutoValue
|
||||
abstract static class RdapNameserver extends RdapNamedObjectBase {
|
||||
|
||||
@JsonableElement Optional<IpAddresses> ipAddresses() {
|
||||
if (ipv6().isEmpty() && ipv4().isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.of(new IpAddresses());
|
||||
}
|
||||
|
||||
abstract ImmutableList<String> ipv6();
|
||||
abstract ImmutableList<String> ipv4();
|
||||
|
||||
class IpAddresses extends AbstractJsonableObject {
|
||||
@JsonableElement ImmutableList<String> v6() {
|
||||
return Ordering.natural().immutableSortedCopy(ipv6());
|
||||
}
|
||||
|
||||
@JsonableElement ImmutableList<String> v4() {
|
||||
return Ordering.natural().immutableSortedCopy(ipv4());
|
||||
}
|
||||
}
|
||||
|
||||
RdapNameserver() {
|
||||
super(BoilerplateType.NAMESERVER, ObjectClassName.NAMESERVER);
|
||||
}
|
||||
|
||||
static Builder builder() {
|
||||
return new AutoValue_RdapObjectClasses_RdapNameserver.Builder();
|
||||
}
|
||||
|
||||
@AutoValue.Builder
|
||||
abstract static class Builder extends RdapNamedObjectBase.Builder<Builder> {
|
||||
abstract ImmutableList.Builder<String> ipv6Builder();
|
||||
abstract ImmutableList.Builder<String> ipv4Builder();
|
||||
|
||||
abstract RdapNameserver build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The Domain Object Class defined in 5.3 of RFC7483.
|
||||
*
|
||||
* We're missing the "variants", "secureDNS", "network" fields
|
||||
*/
|
||||
@RestrictJsonNames("domainSearchResults[]")
|
||||
@AutoValue
|
||||
abstract static class RdapDomain extends RdapNamedObjectBase {
|
||||
|
||||
@JsonableElement abstract ImmutableList<RdapNameserver> nameservers();
|
||||
|
||||
RdapDomain() {
|
||||
super(BoilerplateType.DOMAIN, ObjectClassName.DOMAIN);
|
||||
}
|
||||
|
||||
static Builder builder() {
|
||||
return new AutoValue_RdapObjectClasses_RdapDomain.Builder();
|
||||
}
|
||||
|
||||
@AutoValue.Builder
|
||||
abstract static class Builder extends RdapNamedObjectBase.Builder<Builder> {
|
||||
abstract ImmutableList.Builder<RdapNameserver> nameserversBuilder();
|
||||
|
||||
abstract RdapDomain build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error Response Body defined in 6 of RFC7483.
|
||||
*/
|
||||
@RestrictJsonNames({})
|
||||
@AutoValue
|
||||
abstract static class ErrorResponse extends ReplyPayloadBase {
|
||||
|
||||
@JsonableElement final LanguageIdentifier lang = LanguageIdentifier.EN;
|
||||
|
||||
@JsonableElement abstract int errorCode();
|
||||
@JsonableElement abstract String title();
|
||||
@JsonableElement abstract ImmutableList<String> description();
|
||||
|
||||
ErrorResponse() {
|
||||
super(BoilerplateType.OTHER);
|
||||
}
|
||||
|
||||
static ErrorResponse create(int status, String title, String description) {
|
||||
return new AutoValue_RdapObjectClasses_ErrorResponse(
|
||||
status, title, ImmutableList.of(description));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Help Response defined in 7 of RFC7483.
|
||||
*
|
||||
* <p>The helpNotice field is optional, because if the user requests the TOS - that's already
|
||||
* given by the boilerplate of TopLevelReplyObject so we don't want to give it again.
|
||||
*/
|
||||
@RestrictJsonNames({})
|
||||
@AutoValue
|
||||
abstract static class HelpResponse extends ReplyPayloadBase {
|
||||
@JsonableElement("notices[]") abstract Optional<Notice> helpNotice();
|
||||
|
||||
HelpResponse() {
|
||||
super(BoilerplateType.OTHER);
|
||||
}
|
||||
|
||||
static HelpResponse create(Optional<Notice> helpNotice) {
|
||||
return new AutoValue_RdapObjectClasses_HelpResponse(helpNotice);
|
||||
}
|
||||
}
|
||||
|
||||
private RdapObjectClasses() {}
|
||||
}
|
|
@ -18,12 +18,12 @@ import static java.nio.charset.StandardCharsets.UTF_8;
|
|||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableListMultimap;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.rdap.RdapMetrics.EndpointType;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.ParameterMap;
|
||||
import google.registry.request.RequestUrl;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
|
@ -119,19 +119,8 @@ public abstract class RdapSearchActionBase extends RdapActionBase {
|
|||
}
|
||||
}
|
||||
|
||||
ImmutableList<ImmutableMap<String, Object>> getNotices(RdapSearchResults results) {
|
||||
ImmutableList<ImmutableMap<String, Object>> notices = results.getIncompletenessWarnings();
|
||||
if (results.nextCursor().isPresent()) {
|
||||
ImmutableList.Builder<ImmutableMap<String, Object>> noticesBuilder =
|
||||
new ImmutableList.Builder<>();
|
||||
noticesBuilder.addAll(notices);
|
||||
noticesBuilder.add(
|
||||
RdapJsonFormatter.makeRdapJsonNavigationLinkNotice(
|
||||
Optional.of(
|
||||
getRequestUrlWithExtraParameter(
|
||||
"cursor", encodeCursorToken(results.nextCursor().get())))));
|
||||
notices = noticesBuilder.build();
|
||||
}
|
||||
return notices;
|
||||
/** Creates the URL for this same search with a different starting point cursor. */
|
||||
URI createNavigationUri(String cursor) {
|
||||
return URI.create(getRequestUrlWithExtraParameter("cursor", encodeCursorToken(cursor)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,14 @@ import static google.registry.rdap.RdapIcannStandardInformation.TRUNCATION_NOTIC
|
|||
import com.google.auto.value.AutoValue;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.rdap.RdapDataStructures.Link;
|
||||
import google.registry.rdap.RdapDataStructures.Notice;
|
||||
import google.registry.rdap.RdapObjectClasses.BoilerplateType;
|
||||
import google.registry.rdap.RdapObjectClasses.RdapDomain;
|
||||
import google.registry.rdap.RdapObjectClasses.RdapEntity;
|
||||
import google.registry.rdap.RdapObjectClasses.RdapNameserver;
|
||||
import google.registry.rdap.RdapObjectClasses.ReplyPayloadBase;
|
||||
import java.net.URI;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
|
@ -31,6 +39,130 @@ import java.util.Optional;
|
|||
@AutoValue
|
||||
abstract class RdapSearchResults {
|
||||
|
||||
/**
|
||||
* Responding To Searches defined in 8 of RFC7483.
|
||||
*/
|
||||
abstract static class BaseSearchResponse extends ReplyPayloadBase {
|
||||
abstract IncompletenessWarningType incompletenessWarningType();
|
||||
abstract ImmutableMap<String, URI> navigationLinks();
|
||||
|
||||
@JsonableElement("notices") ImmutableList<Notice> getIncompletenessWarnings() {
|
||||
switch (incompletenessWarningType()) {
|
||||
case TRUNCATED:
|
||||
return TRUNCATION_NOTICES;
|
||||
case MIGHT_BE_INCOMPLETE:
|
||||
return POSSIBLY_INCOMPLETE_NOTICES;
|
||||
case COMPLETE:
|
||||
break;
|
||||
}
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JSON object containing a notice with page navigation links.
|
||||
*
|
||||
* <p>At the moment, only a next page link is supported. Other types of links (e.g. previous
|
||||
* page) could be added in the future, but it's not clear how to generate such links, given the
|
||||
* way we are querying the database.
|
||||
*
|
||||
* <p>This isn't part of the spec.
|
||||
*/
|
||||
@JsonableElement("notices[]")
|
||||
Optional<Notice> getNavigationNotice() {
|
||||
if (navigationLinks().isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
Notice.Builder builder =
|
||||
Notice.builder().setTitle("Navigation Links").setDescription("Links to related pages.");
|
||||
navigationLinks().forEach((name, uri) ->
|
||||
builder.linksBuilder()
|
||||
.add(Link.builder()
|
||||
.setRel(name)
|
||||
.setHref(uri.toString())
|
||||
.setType("application/rdap+json")
|
||||
.build()));
|
||||
return Optional.of(builder.build());
|
||||
}
|
||||
|
||||
BaseSearchResponse(BoilerplateType boilerplateType) {
|
||||
super(boilerplateType);
|
||||
}
|
||||
|
||||
abstract static class Builder<B extends Builder<?>> {
|
||||
abstract ImmutableMap.Builder<String, URI> navigationLinksBuilder();
|
||||
abstract B setIncompletenessWarningType(IncompletenessWarningType type);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
B setNextPageUri(URI uri) {
|
||||
navigationLinksBuilder().put("next", uri);
|
||||
return (B) this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AutoValue
|
||||
abstract static class DomainSearchResponse extends BaseSearchResponse {
|
||||
|
||||
@JsonableElement abstract ImmutableList<RdapDomain> domainSearchResults();
|
||||
|
||||
DomainSearchResponse() {
|
||||
super(BoilerplateType.DOMAIN);
|
||||
}
|
||||
|
||||
static Builder builder() {
|
||||
return new AutoValue_RdapSearchResults_DomainSearchResponse.Builder();
|
||||
}
|
||||
|
||||
@AutoValue.Builder
|
||||
abstract static class Builder extends BaseSearchResponse.Builder<Builder> {
|
||||
abstract ImmutableList.Builder<RdapDomain> domainSearchResultsBuilder();
|
||||
|
||||
abstract DomainSearchResponse build();
|
||||
}
|
||||
}
|
||||
|
||||
@AutoValue
|
||||
abstract static class EntitySearchResponse extends BaseSearchResponse {
|
||||
|
||||
@JsonableElement public abstract ImmutableList<RdapEntity> entitySearchResults();
|
||||
|
||||
EntitySearchResponse() {
|
||||
super(BoilerplateType.ENTITY);
|
||||
}
|
||||
|
||||
static Builder builder() {
|
||||
return new AutoValue_RdapSearchResults_EntitySearchResponse.Builder();
|
||||
}
|
||||
|
||||
@AutoValue.Builder
|
||||
abstract static class Builder extends BaseSearchResponse.Builder<Builder> {
|
||||
abstract ImmutableList.Builder<RdapEntity> entitySearchResultsBuilder();
|
||||
|
||||
abstract EntitySearchResponse build();
|
||||
}
|
||||
}
|
||||
|
||||
@AutoValue
|
||||
abstract static class NameserverSearchResponse extends BaseSearchResponse {
|
||||
|
||||
@JsonableElement public abstract ImmutableList<RdapNameserver> nameserverSearchResults();
|
||||
|
||||
NameserverSearchResponse() {
|
||||
super(BoilerplateType.NAMESERVER);
|
||||
}
|
||||
|
||||
static Builder builder() {
|
||||
return new AutoValue_RdapSearchResults_NameserverSearchResponse.Builder();
|
||||
}
|
||||
|
||||
@AutoValue.Builder
|
||||
abstract static class Builder extends BaseSearchResponse.Builder<Builder> {
|
||||
abstract ImmutableList.Builder<RdapNameserver> nameserverSearchResultsBuilder();
|
||||
|
||||
abstract NameserverSearchResponse build();
|
||||
}
|
||||
}
|
||||
|
||||
enum IncompletenessWarningType {
|
||||
|
||||
/** Result set is complete. */
|
||||
|
@ -45,35 +177,4 @@ abstract class RdapSearchResults {
|
|||
*/
|
||||
MIGHT_BE_INCOMPLETE
|
||||
}
|
||||
|
||||
static RdapSearchResults create(ImmutableList<ImmutableMap<String, Object>> jsonList) {
|
||||
return create(jsonList, IncompletenessWarningType.COMPLETE, Optional.empty());
|
||||
}
|
||||
|
||||
static RdapSearchResults create(
|
||||
ImmutableList<ImmutableMap<String, Object>> jsonList,
|
||||
IncompletenessWarningType incompletenessWarningType,
|
||||
Optional<String> nextCursor) {
|
||||
return new AutoValue_RdapSearchResults(jsonList, incompletenessWarningType, nextCursor);
|
||||
}
|
||||
|
||||
/** List of JSON result object representations. */
|
||||
abstract ImmutableList<ImmutableMap<String, Object>> jsonList();
|
||||
|
||||
/** Type of warning to display regarding possible incomplete data. */
|
||||
abstract IncompletenessWarningType incompletenessWarningType();
|
||||
|
||||
/** Cursor for fetching the next page of results, or empty() if there are no more. */
|
||||
abstract Optional<String> nextCursor();
|
||||
|
||||
/** Convenience method to get the appropriate warnings for the incompleteness warning type. */
|
||||
ImmutableList<ImmutableMap<String, Object>> getIncompletenessWarnings() {
|
||||
if (incompletenessWarningType() == IncompletenessWarningType.TRUNCATED) {
|
||||
return TRUNCATION_NOTICES;
|
||||
}
|
||||
if (incompletenessWarningType() == IncompletenessWarningType.MIGHT_BE_INCOMPLETE) {
|
||||
return POSSIBLY_INCOMPLETE_NOTICES;
|
||||
}
|
||||
return ImmutableList.of();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,6 +96,12 @@ public final class RequestModule {
|
|||
return req.getRequestURI();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the part of this request's URL that calls the servlet.
|
||||
*
|
||||
* <p>This includes the path to the servlet, but does not include any extra path information or a
|
||||
* query string.
|
||||
*/
|
||||
@Provides
|
||||
@FullServletPath
|
||||
static String provideFullServletPath(HttpServletRequest req) {
|
||||
|
|
|
@ -19,15 +19,13 @@ import static com.google.common.truth.Truth.assertThat;
|
|||
import static google.registry.request.Action.Method.GET;
|
||||
import static google.registry.request.Action.Method.HEAD;
|
||||
import static google.registry.testing.DatastoreHelper.createTld;
|
||||
import static google.registry.testing.TestDataHelper.loadFile;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.rdap.RdapJsonFormatter.BoilerplateType;
|
||||
import google.registry.rdap.RdapMetrics.EndpointType;
|
||||
import google.registry.rdap.RdapMetrics.SearchType;
|
||||
import google.registry.rdap.RdapMetrics.WildcardType;
|
||||
import google.registry.rdap.RdapObjectClasses.BoilerplateType;
|
||||
import google.registry.rdap.RdapObjectClasses.ReplyPayloadBase;
|
||||
import google.registry.rdap.RdapSearchResults.IncompletenessWarningType;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.auth.Auth;
|
||||
|
@ -59,7 +57,7 @@ public class RdapActionBaseTest extends RdapActionBaseTestCase<RdapActionBaseTes
|
|||
}
|
||||
|
||||
@Override
|
||||
public ImmutableMap<String, Object> getJsonObjectForResource(
|
||||
public ReplyPayloadBase getJsonObjectForResource(
|
||||
String pathSearchString, boolean isHeadRequest) {
|
||||
if (pathSearchString.equals("IllegalArgumentException")) {
|
||||
throw new IllegalArgumentException();
|
||||
|
@ -67,46 +65,36 @@ public class RdapActionBaseTest extends RdapActionBaseTestCase<RdapActionBaseTes
|
|||
if (pathSearchString.equals("RuntimeException")) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
|
||||
builder.put("key", "value");
|
||||
rdapJsonFormatter.addTopLevelEntries(
|
||||
builder,
|
||||
BoilerplateType.OTHER,
|
||||
ImmutableList.of(),
|
||||
ImmutableList.of(),
|
||||
"http://myserver.example.com/");
|
||||
return builder.build();
|
||||
return new ReplyPayloadBase(BoilerplateType.OTHER) {
|
||||
@JsonableElement public String key = "value";
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
createTld("thing");
|
||||
action.fullServletPath = "http://myserver.example.com" + actionPath;
|
||||
action.rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIllegalValue_showsReadableTypeName() {
|
||||
assertThat(generateActualJson("IllegalArgumentException")).isEqualTo(JSONValue.parse(
|
||||
"{\"lang\":\"en\", \"errorCode\":400, \"title\":\"Bad Request\","
|
||||
+ "\"rdapConformance\":[\"icann_rdap_response_profile_0\"],"
|
||||
+ "\"description\":[\"Not a valid human-readable string\"]}"));
|
||||
assertThat(generateActualJson("IllegalArgumentException")).isEqualTo(generateExpectedJsonError(
|
||||
"Not a valid human-readable string",
|
||||
400));
|
||||
assertThat(response.getStatus()).isEqualTo(400);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRuntimeException_returns500Error() {
|
||||
assertThat(generateActualJson("RuntimeException")).isEqualTo(JSONValue.parse(
|
||||
"{\"lang\":\"en\", \"errorCode\":500, \"title\":\"Internal Server Error\","
|
||||
+ "\"rdapConformance\":[\"icann_rdap_response_profile_0\"],"
|
||||
+ "\"description\":[\"An error was encountered\"]}"));
|
||||
assertThat(generateActualJson("RuntimeException"))
|
||||
.isEqualTo(generateExpectedJsonError("An error was encountered", 500));
|
||||
assertThat(response.getStatus()).isEqualTo(500);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidName_works() {
|
||||
assertThat(generateActualJson("no.thing")).isEqualTo(JSONValue.parse(
|
||||
loadFile(this.getClass(), "rdapjson_toplevel.json")));
|
||||
assertThat(generateActualJson("no.thing")).isEqualTo(loadJsonFile("rdapjson_toplevel.json"));
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
}
|
||||
|
||||
|
@ -173,18 +161,14 @@ public class RdapActionBaseTest extends RdapActionBaseTestCase<RdapActionBaseTes
|
|||
.build());
|
||||
}
|
||||
|
||||
private String loadFileWithoutTrailingNewline(String fileName) {
|
||||
String contents = loadFile(this.getClass(), fileName);
|
||||
return contents.endsWith("\n") ? contents.substring(0, contents.length() - 1) : contents;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnformatted() {
|
||||
action.requestPath = actionPath + "no.thing";
|
||||
action.requestMethod = GET;
|
||||
action.run();
|
||||
assertThat(response.getPayload())
|
||||
.isEqualTo(loadFileWithoutTrailingNewline("rdap_unformatted_output.json"));
|
||||
String payload = response.getPayload();
|
||||
assertThat(payload).doesNotContain("\n");
|
||||
assertThat(JSONValue.parse(payload)).isEqualTo(loadJsonFile("rdapjson_toplevel.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -193,7 +177,8 @@ public class RdapActionBaseTest extends RdapActionBaseTestCase<RdapActionBaseTes
|
|||
action.requestMethod = GET;
|
||||
action.formatOutputParam = Optional.of(true);
|
||||
action.run();
|
||||
assertThat(response.getPayload())
|
||||
.isEqualTo(loadFileWithoutTrailingNewline("rdap_formatted_output.json"));
|
||||
String payload = response.getPayload();
|
||||
assertThat(payload).contains("\n");
|
||||
assertThat(JSONValue.parse(payload)).isEqualTo(loadJsonFile("rdapjson_toplevel.json"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,16 +14,19 @@
|
|||
|
||||
package google.registry.rdap;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.rdap.RdapAuthorization.Role.ADMINISTRATOR;
|
||||
import static google.registry.rdap.RdapAuthorization.Role.PUBLIC;
|
||||
import static google.registry.rdap.RdapAuthorization.Role.REGISTRAR;
|
||||
import static google.registry.request.Action.Method.GET;
|
||||
import static google.registry.request.Action.Method.HEAD;
|
||||
import static google.registry.request.auth.AuthenticatedRegistrarAccessor.Role.OWNER;
|
||||
import static google.registry.testing.TestDataHelper.loadFile;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.appengine.api.users.User;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSetMultimap;
|
||||
import google.registry.model.ofy.Ofy;
|
||||
import google.registry.request.Action;
|
||||
|
@ -37,8 +40,10 @@ import google.registry.testing.FakeClock;
|
|||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.testing.InjectRule;
|
||||
import google.registry.util.TypeUtils;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.JSONValue;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
|
@ -99,7 +104,6 @@ public class RdapActionBaseTestCase<A extends RdapActionBase> {
|
|||
action.rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter();
|
||||
action.rdapMetrics = rdapMetrics;
|
||||
action.requestMethod = Action.Method.GET;
|
||||
action.fullServletPath = "https://example.tld/rdap";
|
||||
action.rdapWhoisServer = null;
|
||||
logout();
|
||||
}
|
||||
|
@ -126,18 +130,80 @@ public class RdapActionBaseTestCase<A extends RdapActionBase> {
|
|||
metricRole = ADMINISTRATOR;
|
||||
}
|
||||
|
||||
protected Object generateActualJson(String domainName) {
|
||||
protected JSONObject generateActualJson(String domainName) {
|
||||
action.requestPath = actionPath + domainName;
|
||||
action.requestMethod = GET;
|
||||
action.run();
|
||||
return JSONValue.parse(response.getPayload());
|
||||
return (JSONObject) JSONValue.parse(response.getPayload());
|
||||
}
|
||||
|
||||
protected String generateHeadPayload(String domainName) {
|
||||
action.requestPath = actionPath + domainName;
|
||||
action.fullServletPath = "http://myserver.example.com" + actionPath;
|
||||
action.requestMethod = HEAD;
|
||||
action.run();
|
||||
return response.getPayload();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a resource testdata JSON file, and applies substitutions.
|
||||
*
|
||||
* <p>{@code loadJsonFile("filename.json", "NANE", "something", "ID", "other")} is the same as
|
||||
* {@code loadJsonFile("filename.json", ImmutableMap.of("NANE", "something", "ID", "other"))}.
|
||||
*
|
||||
* @param filename the name of the file from the testdata directory
|
||||
* @param keysAndValues alternating substitution key and value. The substitutions are applied to
|
||||
* the file before parsing it to JSON.
|
||||
*/
|
||||
protected JSONObject loadJsonFile(String filename, String... keysAndValues) {
|
||||
checkArgument(keysAndValues.length % 2 == 0);
|
||||
ImmutableMap.Builder<String, String> builder = new ImmutableMap.Builder<>();
|
||||
for (int i = 0; i < keysAndValues.length; i += 2) {
|
||||
if (keysAndValues[i + 1] != null) {
|
||||
builder.put(keysAndValues[i], keysAndValues[i + 1]);
|
||||
}
|
||||
}
|
||||
return loadJsonFile(filename, builder.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a resource testdata JSON file, and applies substitutions.
|
||||
*
|
||||
* @param filename the name of the file from the testdata directory
|
||||
* @param substitutions map of substitutions to apply to the file. The substitutions are applied
|
||||
* to the file before parsing it to JSON.
|
||||
*/
|
||||
protected JSONObject loadJsonFile(String filename, Map<String, String> substitutions) {
|
||||
return (JSONObject) JSONValue.parse(loadFile(this.getClass(), filename, substitutions));
|
||||
}
|
||||
|
||||
protected JSONObject generateExpectedJsonError(
|
||||
String description,
|
||||
int code) {
|
||||
String title;
|
||||
switch (code) {
|
||||
case 404:
|
||||
title = "Not Found";
|
||||
break;
|
||||
case 500:
|
||||
title = "Internal Server Error";
|
||||
break;
|
||||
case 501:
|
||||
title = "Not Implemented";
|
||||
break;
|
||||
case 400:
|
||||
title = "Bad Request";
|
||||
break;
|
||||
case 422:
|
||||
title = "Unprocessable Entity";
|
||||
break;
|
||||
default:
|
||||
title = "ERR";
|
||||
break;
|
||||
}
|
||||
return loadJsonFile(
|
||||
"rdap_error.json",
|
||||
"DESCRIPTION", description,
|
||||
"TITLE", title,
|
||||
"CODE", String.valueOf(code));
|
||||
}
|
||||
}
|
||||
|
|
177
javatests/google/registry/rdap/RdapDataStructuresTest.java
Normal file
177
javatests/google/registry/rdap/RdapDataStructuresTest.java
Normal file
|
@ -0,0 +1,177 @@
|
|||
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.rdap;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.rdap.RdapTestHelper.createJson;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.rdap.RdapDataStructures.Event;
|
||||
import google.registry.rdap.RdapDataStructures.EventAction;
|
||||
import google.registry.rdap.RdapDataStructures.EventWithoutActor;
|
||||
import google.registry.rdap.RdapDataStructures.LanguageIdentifier;
|
||||
import google.registry.rdap.RdapDataStructures.Link;
|
||||
import google.registry.rdap.RdapDataStructures.Notice;
|
||||
import google.registry.rdap.RdapDataStructures.ObjectClassName;
|
||||
import google.registry.rdap.RdapDataStructures.Port43WhoisServer;
|
||||
import google.registry.rdap.RdapDataStructures.PublicId;
|
||||
import google.registry.rdap.RdapDataStructures.RdapConformance;
|
||||
import google.registry.rdap.RdapDataStructures.RdapStatus;
|
||||
import google.registry.rdap.RdapDataStructures.Remark;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
@RunWith(JUnit4.class)
|
||||
public final class RdapDataStructuresTest {
|
||||
|
||||
private void assertRestrictedNames(Object object, String... names) {
|
||||
assertThat(AbstractJsonableObject.getNameRestriction(object.getClass()).get())
|
||||
.containsExactlyElementsIn(ImmutableSet.copyOf(names));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRdapConformance() {
|
||||
assertThat(RdapConformance.INSTANCE.toJson())
|
||||
.isEqualTo(createJson("['icann_rdap_response_profile_0']"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLink() {
|
||||
Link link =
|
||||
Link.builder()
|
||||
.setHref("myHref")
|
||||
.setRel("myRel")
|
||||
.setTitle("myTitle")
|
||||
.setType("myType")
|
||||
.build();
|
||||
assertThat(link.toJson())
|
||||
.isEqualTo(createJson("{'href':'myHref','rel':'myRel','title':'myTitle','type':'myType'}"));
|
||||
assertRestrictedNames(link, "links[]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotice() {
|
||||
Notice notice = Notice.builder()
|
||||
.setDescription("AAA", "BBB")
|
||||
.setTitle("myTitle")
|
||||
.addLink(Link.builder().setHref("myHref").setTitle("myLink").build())
|
||||
.setType(Notice.Type.RESULT_TRUNCATED_AUTHORIZATION)
|
||||
.build();
|
||||
assertThat(notice.toJson())
|
||||
.isEqualTo(
|
||||
createJson(
|
||||
"{",
|
||||
" 'title':'myTitle',",
|
||||
" 'type':'result set truncated due to authorization',",
|
||||
" 'description':['AAA','BBB'],",
|
||||
" 'links':[{'href':'myHref','title':'myLink'}]",
|
||||
"}"));
|
||||
assertRestrictedNames(notice, "notices[]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemark() {
|
||||
Remark remark = Remark.builder()
|
||||
.setDescription("AAA", "BBB")
|
||||
.setTitle("myTitle")
|
||||
.addLink(Link.builder().setHref("myHref").setTitle("myLink").build())
|
||||
.setType(Remark.Type.OBJECT_TRUNCATED_AUTHORIZATION)
|
||||
.build();
|
||||
assertThat(remark.toJson())
|
||||
.isEqualTo(
|
||||
createJson(
|
||||
"{",
|
||||
" 'title':'myTitle',",
|
||||
" 'type':'object truncated due to authorization',",
|
||||
" 'description':['AAA','BBB'],",
|
||||
" 'links':[{'href':'myHref','title':'myLink'}]",
|
||||
"}"));
|
||||
assertRestrictedNames(remark, "remarks[]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLanguage() {
|
||||
assertThat(LanguageIdentifier.EN.toJson()).isEqualTo(createJson("'en'"));
|
||||
assertRestrictedNames(LanguageIdentifier.EN, "lang");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvent() {
|
||||
Event event =
|
||||
Event.builder()
|
||||
.setEventAction(EventAction.REGISTRATION)
|
||||
.setEventActor("Event Actor")
|
||||
.setEventDate(DateTime.parse("2012-04-03T14:54Z"))
|
||||
.addLink(Link.builder().setHref("myHref").build())
|
||||
.build();
|
||||
assertThat(event.toJson())
|
||||
.isEqualTo(
|
||||
createJson(
|
||||
"{",
|
||||
" 'eventAction':'registration',",
|
||||
" 'eventActor':'Event Actor',",
|
||||
" 'eventDate':'2012-04-03T14:54:00.000Z',",
|
||||
" 'links':[{'href':'myHref'}]",
|
||||
"}"));
|
||||
assertRestrictedNames(event, "events[]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventWithoutActor() {
|
||||
EventWithoutActor event =
|
||||
EventWithoutActor.builder()
|
||||
.setEventAction(EventAction.REGISTRATION)
|
||||
.setEventDate(DateTime.parse("2012-04-03T14:54Z"))
|
||||
.addLink(Link.builder().setHref("myHref").build())
|
||||
.build();
|
||||
assertThat(event.toJson())
|
||||
.isEqualTo(
|
||||
createJson(
|
||||
"{",
|
||||
" 'eventAction':'registration',",
|
||||
" 'eventDate':'2012-04-03T14:54:00.000Z',",
|
||||
" 'links':[{'href':'myHref'}]",
|
||||
"}"));
|
||||
assertRestrictedNames(event, "asEventActor[]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRdapStatus() {
|
||||
assertThat(RdapStatus.ACTIVE.toJson()).isEqualTo(createJson("'active'"));
|
||||
assertRestrictedNames(RdapStatus.ACTIVE, "status[]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPort43() {
|
||||
Port43WhoisServer port43 = Port43WhoisServer.create("myServer");
|
||||
assertThat(port43.toJson()).isEqualTo(createJson("'myServer'"));
|
||||
assertRestrictedNames(port43, "port43");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPublicId() {
|
||||
PublicId publicId = PublicId.create(PublicId.Type.IANA_REGISTRAR_ID, "myId");
|
||||
assertThat(publicId.toJson())
|
||||
.isEqualTo(createJson("{'identifier':'myId','type':'IANA Registrar ID'}"));
|
||||
assertRestrictedNames(publicId, "publicIds[]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testObjectClassName() {
|
||||
assertThat(ObjectClassName.DOMAIN.toJson()).isEqualTo(createJson("'domain'"));
|
||||
assertRestrictedNames(ObjectClassName.DOMAIN, "objectClassName");
|
||||
}
|
||||
}
|
|
@ -24,7 +24,6 @@ import static google.registry.testing.FullFieldsTestEntityHelper.makeDomainBase;
|
|||
import static google.registry.testing.FullFieldsTestEntityHelper.makeHistoryEntry;
|
||||
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrar;
|
||||
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrarContacts;
|
||||
import static google.registry.testing.TestDataHelper.loadFile;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
@ -47,7 +46,6 @@ import java.util.Map;
|
|||
import java.util.Optional;
|
||||
import javax.annotation.Nullable;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.JSONValue;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
@ -230,24 +228,15 @@ public class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainActio
|
|||
clock.nowUtc().minusMonths(6)));
|
||||
}
|
||||
|
||||
private Object generateExpectedJson(
|
||||
String name,
|
||||
String punycodeName,
|
||||
String handle,
|
||||
String expectedOutputFile) {
|
||||
return generateExpectedJson(
|
||||
name, punycodeName, handle, null, null, null, null, expectedOutputFile);
|
||||
}
|
||||
|
||||
private Object generateExpectedJson(
|
||||
private JSONObject generateExpectedJson(
|
||||
String expectedOutputFile,
|
||||
String name,
|
||||
String punycodeName,
|
||||
String handle,
|
||||
@Nullable List<String> contactRoids,
|
||||
@Nullable List<String> nameserverRoids,
|
||||
@Nullable List<String> nameserverNames,
|
||||
@Nullable String registrarName,
|
||||
String expectedOutputFile) {
|
||||
@Nullable String registrarName) {
|
||||
ImmutableMap.Builder<String, String> substitutionsBuilder = new ImmutableMap.Builder<>();
|
||||
substitutionsBuilder.put("NAME", name);
|
||||
substitutionsBuilder.put("PUNYCODENAME", (punycodeName == null) ? name : punycodeName);
|
||||
|
@ -282,11 +271,10 @@ public class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainActio
|
|||
substitutionsBuilder.put("NAMESERVER2NAME", "ns2.cat.lol");
|
||||
substitutionsBuilder.put("NAMESERVER2PUNYCODENAME", "ns2.cat.lol");
|
||||
}
|
||||
return JSONValue.parse(
|
||||
loadFile(this.getClass(), expectedOutputFile, substitutionsBuilder.build()));
|
||||
return loadJsonFile(expectedOutputFile, substitutionsBuilder.build());
|
||||
}
|
||||
|
||||
private Object generateExpectedJsonWithTopLevelEntries(
|
||||
private JSONObject generateExpectedJsonWithTopLevelEntries(
|
||||
String name,
|
||||
String punycodeName,
|
||||
String handle,
|
||||
|
@ -304,7 +292,7 @@ public class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainActio
|
|||
registrarName,
|
||||
expectedOutputFile);
|
||||
}
|
||||
private Object generateExpectedJsonWithTopLevelEntries(
|
||||
private JSONObject generateExpectedJsonWithTopLevelEntries(
|
||||
String name,
|
||||
String punycodeName,
|
||||
String handle,
|
||||
|
@ -313,34 +301,23 @@ public class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainActio
|
|||
@Nullable List<String> nameserverNames,
|
||||
@Nullable String registrarName,
|
||||
String expectedOutputFile) {
|
||||
Object obj =
|
||||
JSONObject obj =
|
||||
generateExpectedJson(
|
||||
expectedOutputFile,
|
||||
name,
|
||||
punycodeName,
|
||||
handle,
|
||||
contactRoids,
|
||||
nameserverRoids,
|
||||
nameserverNames,
|
||||
registrarName,
|
||||
expectedOutputFile);
|
||||
if (obj instanceof Map) {
|
||||
registrarName);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> map = (Map<String, Object>) obj;
|
||||
ImmutableMap.Builder<String, Object> builder =
|
||||
RdapTestHelper.getBuilderExcluding(
|
||||
map, ImmutableSet.of("rdapConformance", "notices", "remarks"));
|
||||
builder.put("rdapConformance", ImmutableList.of("icann_rdap_response_profile_0"));
|
||||
RdapTestHelper.getBuilderExcluding(map, ImmutableSet.of("notices"));
|
||||
RdapTestHelper.addDomainBoilerplateNotices(
|
||||
builder,
|
||||
false,
|
||||
RdapTestHelper.createNotices(
|
||||
"https://example.tld/rdap/",
|
||||
(contactRoids == null)
|
||||
? RdapTestHelper.ContactNoticeType.DOMAIN
|
||||
: RdapTestHelper.ContactNoticeType.NONE,
|
||||
map.get("notices")));
|
||||
builder, RdapTestHelper.createNotices("https://example.tld/rdap/", map.get("notices")));
|
||||
obj = new JSONObject(builder.build());
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -361,9 +338,7 @@ public class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainActio
|
|||
"cat.lol",
|
||||
null,
|
||||
"C-LOL",
|
||||
expectedOutputFile.equals("rdap_domain.json")
|
||||
? ImmutableList.of("4-ROID", "6-ROID", "2-ROID")
|
||||
: null,
|
||||
ImmutableList.of("4-ROID", "6-ROID", "2-ROID"),
|
||||
ImmutableList.of("8-ROID", "A-ROID"),
|
||||
"Yes Virginia <script>",
|
||||
expectedOutputFile));
|
||||
|
@ -374,12 +349,10 @@ public class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainActio
|
|||
public void testInvalidDomain_returns400() {
|
||||
assertJsonEqual(
|
||||
generateActualJson("invalid/domain/name"),
|
||||
generateExpectedJson(
|
||||
generateExpectedJsonError(
|
||||
"invalid/domain/name is not a valid domain name: Domain names can only contain a-z,"
|
||||
+ " 0-9, '.' and '-'",
|
||||
null,
|
||||
"1",
|
||||
"rdap_error_400.json"));
|
||||
400));
|
||||
assertThat(response.getStatus()).isEqualTo(400);
|
||||
}
|
||||
|
||||
|
@ -387,12 +360,10 @@ public class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainActio
|
|||
public void testUnknownDomain_returns400() {
|
||||
assertJsonEqual(
|
||||
generateActualJson("missingdomain.com"),
|
||||
generateExpectedJson(
|
||||
generateExpectedJsonError(
|
||||
"missingdomain.com is not a valid domain name: Domain name is under tld com which"
|
||||
+ " doesn't exist",
|
||||
null,
|
||||
"1",
|
||||
"rdap_error_400.json"));
|
||||
400));
|
||||
assertThat(response.getStatus()).isEqualTo(400);
|
||||
}
|
||||
|
||||
|
@ -424,28 +395,28 @@ public class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainActio
|
|||
|
||||
@Test
|
||||
public void testValidDomain_notLoggedIn_noContacts() {
|
||||
assertProperResponseForCatLol("cat.lol", "rdap_domain_no_contacts.json");
|
||||
assertProperResponseForCatLol("cat.lol", "rdap_domain_no_contacts_with_remark.json");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidDomain_loggedInAsOtherRegistrar_noContacts() {
|
||||
login("idnregistrar");
|
||||
assertProperResponseForCatLol("cat.lol", "rdap_domain_no_contacts.json");
|
||||
assertProperResponseForCatLol("cat.lol", "rdap_domain_no_contacts_with_remark.json");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpperCase_ignored() {
|
||||
assertProperResponseForCatLol("CaT.lOl", "rdap_domain_no_contacts.json");
|
||||
assertProperResponseForCatLol("CaT.lOl", "rdap_domain_no_contacts_with_remark.json");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTrailingDot_ignored() {
|
||||
assertProperResponseForCatLol("cat.lol.", "rdap_domain_no_contacts.json");
|
||||
assertProperResponseForCatLol("cat.lol.", "rdap_domain_no_contacts_with_remark.json");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryParameter_ignored() {
|
||||
assertProperResponseForCatLol("cat.lol?key=value", "rdap_domain_no_contacts.json");
|
||||
assertProperResponseForCatLol("cat.lol?key=value", "rdap_domain_no_contacts_with_remark.json");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -525,7 +496,7 @@ public class RdapDomainActionTest extends RdapActionBaseTestCase<RdapDomainActio
|
|||
public void testDeletedDomain_notFound() {
|
||||
assertJsonEqual(
|
||||
generateActualJson("dodo.lol"),
|
||||
generateExpectedJson("dodo.lol not found", null, "1", "rdap_error_404.json"));
|
||||
generateExpectedJsonError("dodo.lol not found", 404));
|
||||
assertThat(response.getStatus()).isEqualTo(404);
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@ import static google.registry.testing.FullFieldsTestEntityHelper.makeDomainBase;
|
|||
import static google.registry.testing.FullFieldsTestEntityHelper.makeHistoryEntry;
|
||||
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrar;
|
||||
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrarContacts;
|
||||
import static google.registry.testing.TestDataHelper.loadFile;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableListMultimap;
|
||||
|
@ -90,11 +89,11 @@ public class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDom
|
|||
|
||||
enum RequestType { NONE, NAME, NS_LDH_NAME, NS_IP }
|
||||
|
||||
private Object generateActualJson(RequestType requestType, String paramValue) {
|
||||
private JSONObject generateActualJson(RequestType requestType, String paramValue) {
|
||||
return generateActualJson(requestType, paramValue, null);
|
||||
}
|
||||
|
||||
private Object generateActualJson(
|
||||
private JSONObject generateActualJson(
|
||||
RequestType requestType, String paramValue, String cursor) {
|
||||
action.requestPath = actionPath;
|
||||
action.requestMethod = POST;
|
||||
|
@ -136,7 +135,7 @@ public class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDom
|
|||
}
|
||||
}
|
||||
action.run();
|
||||
return JSONValue.parse(response.getPayload());
|
||||
return (JSONObject) JSONValue.parse(response.getPayload());
|
||||
}
|
||||
|
||||
private HostResource addHostToMap(HostResource host) {
|
||||
|
@ -363,27 +362,25 @@ public class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDom
|
|||
action.requestMethod = POST;
|
||||
}
|
||||
|
||||
private Object generateExpectedJsonForTwoDomains() {
|
||||
private JSONObject generateExpectedJsonForTwoDomains() {
|
||||
return generateExpectedJsonForTwoDomains("cat.example", "21-EXAMPLE", "cat.lol", "C-LOL");
|
||||
}
|
||||
|
||||
private Object generateExpectedJsonForTwoDomains(
|
||||
private JSONObject generateExpectedJsonForTwoDomains(
|
||||
String domain1Name,
|
||||
String domain1Handle,
|
||||
String domain2Name,
|
||||
String domain2Handle) {
|
||||
return JSONValue.parse(loadFile(
|
||||
this.getClass(),
|
||||
return loadJsonFile(
|
||||
"rdap_domains_two.json",
|
||||
ImmutableMap.of(
|
||||
"TYPE", "domain name",
|
||||
"DOMAINNAME1", domain1Name,
|
||||
"DOMAINHANDLE1", domain1Handle,
|
||||
"DOMAINNAME2", domain2Name,
|
||||
"DOMAINHANDLE2", domain2Handle)));
|
||||
"DOMAINHANDLE2", domain2Handle);
|
||||
}
|
||||
|
||||
private Object generateExpectedJsonForFourDomains(
|
||||
private JSONObject generateExpectedJsonForFourDomains(
|
||||
String domain1Name,
|
||||
String domain1Handle,
|
||||
String domain2Name,
|
||||
|
@ -406,7 +403,7 @@ public class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDom
|
|||
expectedOutputFile);
|
||||
}
|
||||
|
||||
private Object generateExpectedJsonForFourDomains(
|
||||
private JSONObject generateExpectedJsonForFourDomains(
|
||||
String domain1Name,
|
||||
String domain1Handle,
|
||||
String domain2Name,
|
||||
|
@ -417,33 +414,25 @@ public class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDom
|
|||
String domain4Handle,
|
||||
String nextQuery,
|
||||
String expectedOutputFile) {
|
||||
return JSONValue.parse(
|
||||
loadFile(
|
||||
this.getClass(),
|
||||
return loadJsonFile(
|
||||
expectedOutputFile,
|
||||
new ImmutableMap.Builder<String, String>()
|
||||
.put("TYPE", "domain name")
|
||||
.put("DOMAINPUNYCODENAME1", domain1Name)
|
||||
.put("DOMAINNAME1", IDN.toUnicode(domain1Name))
|
||||
.put("DOMAINHANDLE1", domain1Handle)
|
||||
.put("DOMAINPUNYCODENAME2", domain2Name)
|
||||
.put("DOMAINNAME2", IDN.toUnicode(domain2Name))
|
||||
.put("DOMAINHANDLE2", domain2Handle)
|
||||
.put("DOMAINPUNYCODENAME3", domain3Name)
|
||||
.put("DOMAINNAME3", IDN.toUnicode(domain3Name))
|
||||
.put("DOMAINHANDLE3", domain3Handle)
|
||||
.put("DOMAINPUNYCODENAME4", domain4Name)
|
||||
.put("DOMAINNAME4", IDN.toUnicode(domain4Name))
|
||||
.put("DOMAINHANDLE4", domain4Handle)
|
||||
.put("NEXT_QUERY", nextQuery)
|
||||
.build()));
|
||||
"TYPE", "domain name",
|
||||
"DOMAINPUNYCODENAME1", domain1Name,
|
||||
"DOMAINNAME1", IDN.toUnicode(domain1Name),
|
||||
"DOMAINHANDLE1", domain1Handle,
|
||||
"DOMAINPUNYCODENAME2", domain2Name,
|
||||
"DOMAINNAME2", IDN.toUnicode(domain2Name),
|
||||
"DOMAINHANDLE2", domain2Handle,
|
||||
"DOMAINPUNYCODENAME3", domain3Name,
|
||||
"DOMAINNAME3", IDN.toUnicode(domain3Name),
|
||||
"DOMAINHANDLE3", domain3Handle,
|
||||
"DOMAINPUNYCODENAME4", domain4Name,
|
||||
"DOMAINNAME4", IDN.toUnicode(domain4Name),
|
||||
"DOMAINHANDLE4", domain4Handle,
|
||||
"NEXT_QUERY", nextQuery);
|
||||
}
|
||||
|
||||
private Object generateExpectedJson(String name, String expectedOutputFile) {
|
||||
return generateExpectedJson(name, null, null, null, null, null, expectedOutputFile);
|
||||
}
|
||||
|
||||
private Object generateExpectedJson(
|
||||
private JSONObject generateExpectedJson(
|
||||
String name,
|
||||
String punycodeName,
|
||||
String handle,
|
||||
|
@ -476,11 +465,10 @@ public class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDom
|
|||
if (registrarName != null) {
|
||||
substitutionsBuilder.put("REGISTRARNAME", registrarName);
|
||||
}
|
||||
return JSONValue.parse(
|
||||
loadFile(this.getClass(), expectedOutputFile, substitutionsBuilder.build()));
|
||||
return loadJsonFile(expectedOutputFile, substitutionsBuilder.build());
|
||||
}
|
||||
|
||||
private Object generateExpectedJsonForDomain(
|
||||
private JSONObject generateExpectedJsonForDomain(
|
||||
String name,
|
||||
String punycodeName,
|
||||
String handle,
|
||||
|
@ -488,7 +476,7 @@ public class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDom
|
|||
@Nullable List<String> nameservers,
|
||||
@Nullable String registrarName,
|
||||
String expectedOutputFile) {
|
||||
Object obj =
|
||||
JSONObject obj =
|
||||
generateExpectedJson(
|
||||
name,
|
||||
punycodeName,
|
||||
|
@ -497,6 +485,7 @@ public class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDom
|
|||
nameservers,
|
||||
registrarName,
|
||||
expectedOutputFile);
|
||||
obj.remove("rdapConformance");
|
||||
ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
|
||||
builder.put("domainSearchResults", ImmutableList.of(obj));
|
||||
builder.put("rdapConformance", ImmutableList.of("icann_rdap_response_profile_0"));
|
||||
|
@ -560,7 +549,7 @@ public class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDom
|
|||
persistResources(domainsBuilder.build());
|
||||
}
|
||||
|
||||
private Object readMultiDomainFile(
|
||||
private JSONObject readMultiDomainFile(
|
||||
String fileName,
|
||||
String domainName1,
|
||||
String domainHandle1,
|
||||
|
@ -583,7 +572,7 @@ public class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDom
|
|||
"none");
|
||||
}
|
||||
|
||||
private Object readMultiDomainFile(
|
||||
private JSONObject readMultiDomainFile(
|
||||
String fileName,
|
||||
String domainName1,
|
||||
String domainHandle1,
|
||||
|
@ -594,30 +583,24 @@ public class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDom
|
|||
String domainName4,
|
||||
String domainHandle4,
|
||||
String nextQuery) {
|
||||
return JSONValue.parse(loadFile(
|
||||
this.getClass(),
|
||||
return loadJsonFile(
|
||||
fileName,
|
||||
new ImmutableMap.Builder<String, String>()
|
||||
.put("DOMAINNAME1", domainName1)
|
||||
.put("DOMAINHANDLE1", domainHandle1)
|
||||
.put("DOMAINNAME2", domainName2)
|
||||
.put("DOMAINHANDLE2", domainHandle2)
|
||||
.put("DOMAINNAME3", domainName3)
|
||||
.put("DOMAINHANDLE3", domainHandle3)
|
||||
.put("DOMAINNAME4", domainName4)
|
||||
.put("DOMAINHANDLE4", domainHandle4)
|
||||
.put("NEXT_QUERY", nextQuery)
|
||||
.build()));
|
||||
"DOMAINNAME1", domainName1,
|
||||
"DOMAINHANDLE1", domainHandle1,
|
||||
"DOMAINNAME2", domainName2,
|
||||
"DOMAINHANDLE2", domainHandle2,
|
||||
"DOMAINNAME3", domainName3,
|
||||
"DOMAINHANDLE3", domainHandle3,
|
||||
"DOMAINNAME4", domainName4,
|
||||
"DOMAINHANDLE4", domainHandle4,
|
||||
"NEXT_QUERY", nextQuery);
|
||||
}
|
||||
|
||||
private void checkNumberOfDomainsInResult(Object obj, int expected) {
|
||||
private void checkNumberOfDomainsInResult(JSONObject obj, int expected) {
|
||||
assertThat(obj).isInstanceOf(Map.class);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> map = (Map<String, Object>) obj;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Object> domains = (List<Object>) map.get("domainSearchResults");
|
||||
List<Object> domains = (List<Object>) obj.get("domainSearchResults");
|
||||
|
||||
assertThat(domains).hasSize(expected);
|
||||
}
|
||||
|
@ -717,7 +700,7 @@ public class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDom
|
|||
RequestType requestType, String queryString, String errorMessage) {
|
||||
rememberWildcardType(queryString);
|
||||
assertThat(generateActualJson(requestType, queryString))
|
||||
.isEqualTo(generateExpectedJson(errorMessage, "rdap_error_404.json"));
|
||||
.isEqualTo(generateExpectedJsonError(errorMessage, 404));
|
||||
assertThat(response.getStatus()).isEqualTo(404);
|
||||
}
|
||||
|
||||
|
@ -801,7 +784,7 @@ public class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDom
|
|||
int expectedPageCount =
|
||||
(expectedNames.size() + action.rdapResultSetMaxSize - 1) / action.rdapResultSetMaxSize;
|
||||
for (int pageNum = 0; pageNum < expectedPageCount; pageNum++) {
|
||||
Object results = generateActualJson(requestType, paramValue, cursor);
|
||||
JSONObject results = generateActualJson(requestType, paramValue, cursor);
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
String linkToNext = RdapTestHelper.getLinkToNext(results);
|
||||
if (pageNum == expectedPageCount - 1) {
|
||||
|
@ -811,7 +794,7 @@ public class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDom
|
|||
int pos = linkToNext.indexOf("cursor=");
|
||||
assertThat(pos).isAtLeast(0);
|
||||
cursor = URLDecoder.decode(linkToNext.substring(pos + 7), "UTF-8");
|
||||
Object searchResults = ((JSONObject) results).get("domainSearchResults");
|
||||
Object searchResults = results.get("domainSearchResults");
|
||||
assertThat(searchResults).isInstanceOf(JSONArray.class);
|
||||
assertThat(((JSONArray) searchResults)).hasSize(action.rdapResultSetMaxSize);
|
||||
for (Object item : ((JSONArray) searchResults)) {
|
||||
|
@ -838,9 +821,9 @@ public class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDom
|
|||
@Test
|
||||
public void testInvalidRequest_rejected() {
|
||||
assertThat(generateActualJson(RequestType.NONE, null))
|
||||
.isEqualTo(generateExpectedJson(
|
||||
.isEqualTo(generateExpectedJsonError(
|
||||
"You must specify either name=XXXX, nsLdhName=YYYY or nsIp=ZZZZ",
|
||||
"rdap_error_400.json"));
|
||||
400));
|
||||
assertThat(response.getStatus()).isEqualTo(400);
|
||||
verifyErrorMetrics(SearchType.NONE, Optional.empty(), 400);
|
||||
}
|
||||
|
@ -848,10 +831,10 @@ public class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDom
|
|||
@Test
|
||||
public void testInvalidWildcard_rejected() {
|
||||
assertThat(generateActualJson(RequestType.NAME, "exam*ple"))
|
||||
.isEqualTo(generateExpectedJson(
|
||||
.isEqualTo(generateExpectedJsonError(
|
||||
"Suffix after wildcard must be one or more domain"
|
||||
+ " name labels, e.g. exam*.tld, ns*.example.tld",
|
||||
"rdap_error_422.json"));
|
||||
422));
|
||||
assertThat(response.getStatus()).isEqualTo(422);
|
||||
verifyErrorMetrics(SearchType.BY_DOMAIN_NAME, Optional.empty(), 422);
|
||||
}
|
||||
|
@ -859,7 +842,7 @@ public class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDom
|
|||
@Test
|
||||
public void testMultipleWildcards_rejected() {
|
||||
assertThat(generateActualJson(RequestType.NAME, "*.*"))
|
||||
.isEqualTo(generateExpectedJson("Only one wildcard allowed", "rdap_error_422.json"));
|
||||
.isEqualTo(generateExpectedJsonError("Only one wildcard allowed", 422));
|
||||
assertThat(response.getStatus()).isEqualTo(422);
|
||||
verifyErrorMetrics(SearchType.BY_DOMAIN_NAME, Optional.empty(), 422);
|
||||
}
|
||||
|
@ -869,10 +852,10 @@ public class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDom
|
|||
rememberWildcardType("*");
|
||||
assertThat(generateActualJson(RequestType.NAME, "*"))
|
||||
.isEqualTo(
|
||||
generateExpectedJson(
|
||||
generateExpectedJsonError(
|
||||
"Initial search string is required for wildcard domain searches without a TLD"
|
||||
+ " suffix",
|
||||
"rdap_error_422.json"));
|
||||
422));
|
||||
assertThat(response.getStatus()).isEqualTo(422);
|
||||
verifyErrorMetrics(SearchType.BY_DOMAIN_NAME, Optional.empty(), 422);
|
||||
}
|
||||
|
@ -882,10 +865,10 @@ public class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDom
|
|||
rememberWildcardType("a*");
|
||||
assertThat(generateActualJson(RequestType.NAME, "a*"))
|
||||
.isEqualTo(
|
||||
generateExpectedJson(
|
||||
generateExpectedJsonError(
|
||||
"Initial search string must be at least 2 characters for wildcard domain searches"
|
||||
+ " without a TLD suffix",
|
||||
"rdap_error_422.json"));
|
||||
422));
|
||||
assertThat(response.getStatus()).isEqualTo(422);
|
||||
verifyErrorMetrics(SearchType.BY_DOMAIN_NAME, Optional.empty(), 422);
|
||||
}
|
||||
|
@ -1226,7 +1209,7 @@ public class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDom
|
|||
// There are enough domains to fill a full result set; deleted domains are ignored.
|
||||
createManyDomainsAndHosts(4, 4, 2);
|
||||
rememberWildcardType("domain*.lol");
|
||||
Object obj = generateActualJson(RequestType.NAME, "domain*.lol");
|
||||
JSONObject obj = generateActualJson(RequestType.NAME, "domain*.lol");
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
checkNumberOfDomainsInResult(obj, 4);
|
||||
verifyMetrics(SearchType.BY_DOMAIN_NAME, Optional.of(16L));
|
||||
|
@ -1237,7 +1220,7 @@ public class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDom
|
|||
// There are not enough domains to fill a full result set.
|
||||
createManyDomainsAndHosts(3, 20, 2);
|
||||
rememberWildcardType("domain*.lol");
|
||||
Object obj = generateActualJson(RequestType.NAME, "domain*.lol");
|
||||
JSONObject obj = generateActualJson(RequestType.NAME, "domain*.lol");
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
checkNumberOfDomainsInResult(obj, 3);
|
||||
verifyMetrics(SearchType.BY_DOMAIN_NAME, Optional.of(60L));
|
||||
|
@ -1682,7 +1665,7 @@ public class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDom
|
|||
// each one references the nameserver.
|
||||
createManyDomainsAndHosts(3, 1, 40);
|
||||
rememberWildcardType("ns1.domain1.lol");
|
||||
Object obj = generateActualJson(RequestType.NS_LDH_NAME, "ns1.domain1.lol");
|
||||
JSONObject obj = generateActualJson(RequestType.NS_LDH_NAME, "ns1.domain1.lol");
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
checkNumberOfDomainsInResult(obj, 3);
|
||||
verifyMetrics(SearchType.BY_NAMESERVER_NAME, Optional.of(3L), Optional.of(1L));
|
||||
|
@ -1693,7 +1676,7 @@ public class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDom
|
|||
// Same as above, except with a wildcard (that still only finds one nameserver).
|
||||
createManyDomainsAndHosts(3, 1, 40);
|
||||
rememberWildcardType("ns1.domain1.l*");
|
||||
Object obj = generateActualJson(RequestType.NS_LDH_NAME, "ns1.domain1.l*");
|
||||
JSONObject obj = generateActualJson(RequestType.NS_LDH_NAME, "ns1.domain1.l*");
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
checkNumberOfDomainsInResult(obj, 3);
|
||||
verifyMetrics(SearchType.BY_NAMESERVER_NAME, Optional.of(3L), Optional.of(1L));
|
||||
|
@ -1707,7 +1690,7 @@ public class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDom
|
|||
// have more than that number of nameservers for an effective test.
|
||||
createManyDomainsAndHosts(3, 1, 39);
|
||||
rememberWildcardType("ns*.domain1.lol");
|
||||
Object obj = generateActualJson(RequestType.NS_LDH_NAME, "ns*.domain1.lol");
|
||||
JSONObject obj = generateActualJson(RequestType.NS_LDH_NAME, "ns*.domain1.lol");
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
checkNumberOfDomainsInResult(obj, 3);
|
||||
verifyMetrics(SearchType.BY_NAMESERVER_NAME, Optional.of(3L), Optional.of(39L));
|
||||
|
|
|
@ -24,7 +24,6 @@ import static google.registry.testing.FullFieldsTestEntityHelper.makeDomainBase;
|
|||
import static google.registry.testing.FullFieldsTestEntityHelper.makeHostResource;
|
||||
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrar;
|
||||
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrarContacts;
|
||||
import static google.registry.testing.TestDataHelper.loadFile;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
@ -41,7 +40,7 @@ import google.registry.request.Action;
|
|||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nullable;
|
||||
import org.json.simple.JSONValue;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
@ -132,51 +131,27 @@ public class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityActio
|
|||
clock.nowUtc().minusMonths(6));
|
||||
}
|
||||
|
||||
private Object generateExpectedJson(String handle, String expectedOutputFile) {
|
||||
return generateExpectedJson(handle, "(◕‿◕)", "", expectedOutputFile);
|
||||
}
|
||||
|
||||
private Object generateExpectedJson(
|
||||
String handle,
|
||||
String status,
|
||||
String expectedOutputFile) {
|
||||
return generateExpectedJson(handle, "(◕‿◕)", status, expectedOutputFile);
|
||||
}
|
||||
|
||||
private Object generateExpectedJson(
|
||||
String handle,
|
||||
String fullName,
|
||||
String status,
|
||||
String expectedOutputFile) {
|
||||
return generateExpectedJson(
|
||||
handle, fullName, status, null, expectedOutputFile);
|
||||
}
|
||||
|
||||
private Object generateExpectedJson(
|
||||
String handle,
|
||||
String fullName,
|
||||
String status,
|
||||
@Nullable String address,
|
||||
String expectedOutputFile) {
|
||||
return JSONValue.parse(
|
||||
loadFile(
|
||||
this.getClass(),
|
||||
return loadJsonFile(
|
||||
expectedOutputFile,
|
||||
new ImmutableMap.Builder<String, String>()
|
||||
.put("NAME", handle)
|
||||
.put("FULLNAME", fullName)
|
||||
.put("ADDRESS", (address == null) ? "\"1 Smiley Row\", \"Suite みんな\"" : address)
|
||||
.put("EMAIL", "lol@cat.みんな")
|
||||
.put("TYPE", "entity")
|
||||
.put("STATUS", status)
|
||||
.build()));
|
||||
"NAME", handle,
|
||||
"FULLNAME", fullName,
|
||||
"ADDRESS", (address == null) ? "\"1 Smiley Row\", \"Suite みんな\"" : address,
|
||||
"EMAIL", "lol@cat.みんな",
|
||||
"TYPE", "entity",
|
||||
"STATUS", status);
|
||||
}
|
||||
|
||||
private Object generateExpectedJsonWithTopLevelEntries(
|
||||
String handle,
|
||||
String expectedOutputFile) {
|
||||
return generateExpectedJsonWithTopLevelEntries(
|
||||
handle, "(◕‿◕)", "active", null, false, expectedOutputFile);
|
||||
handle, "(◕‿◕)", "active", null, expectedOutputFile);
|
||||
}
|
||||
|
||||
private Object generateExpectedJsonWithTopLevelEntries(
|
||||
|
@ -184,35 +159,26 @@ public class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityActio
|
|||
String fullName,
|
||||
String status,
|
||||
String address,
|
||||
boolean addNoPersonalDataRemark,
|
||||
String expectedOutputFile) {
|
||||
Object obj = generateExpectedJson(handle, fullName, status, address, expectedOutputFile);
|
||||
if (obj instanceof Map) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> map = (Map<String, Object>) obj;
|
||||
ImmutableMap.Builder<String, Object> builder =
|
||||
RdapTestHelper.getBuilderExcluding(
|
||||
map, ImmutableSet.of("rdapConformance", "notices", "remarks"));
|
||||
builder.put("rdapConformance", ImmutableList.of("icann_rdap_response_profile_0"));
|
||||
RdapTestHelper.getBuilderExcluding(map, ImmutableSet.of("notices"));
|
||||
RdapTestHelper.addNonDomainBoilerplateNotices(
|
||||
builder,
|
||||
RdapTestHelper.createNotices(
|
||||
"https://example.tld/rdap/",
|
||||
addNoPersonalDataRemark
|
||||
? RdapTestHelper.ContactNoticeType.CONTACT
|
||||
: RdapTestHelper.ContactNoticeType.NONE,
|
||||
map.get("notices")));
|
||||
obj = builder.build();
|
||||
builder, RdapTestHelper.createNotices("https://example.tld/rdap/", map.get("notices")));
|
||||
obj = new JSONObject(builder.build());
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
private void runSuccessfulTest(String queryString, String fileName) {
|
||||
runSuccessfulTest(queryString, "(◕‿◕)", "active", null, false, fileName);
|
||||
runSuccessfulTest(queryString, "(◕‿◕)", "active", null, fileName);
|
||||
}
|
||||
|
||||
private void runSuccessfulTest(String queryString, String fullName, String fileName) {
|
||||
runSuccessfulTest(queryString, fullName, "active", null, false, fileName);
|
||||
runSuccessfulTest(queryString, fullName, "active", null, fileName);
|
||||
}
|
||||
|
||||
private void runSuccessfulTest(
|
||||
|
@ -220,27 +186,26 @@ public class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityActio
|
|||
String fullName,
|
||||
String rdapStatus,
|
||||
String address,
|
||||
boolean addNoPersonalDataRemark,
|
||||
String fileName) {
|
||||
assertThat(generateActualJson(queryString))
|
||||
.isEqualTo(
|
||||
generateExpectedJsonWithTopLevelEntries(
|
||||
queryString, fullName, rdapStatus, address, addNoPersonalDataRemark, fileName));
|
||||
queryString, fullName, rdapStatus, address, fileName));
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
}
|
||||
|
||||
private void runNotFoundTest(String queryString) {
|
||||
assertThat(generateActualJson(queryString))
|
||||
.isEqualTo(generateExpectedJson(queryString + " not found", "", "rdap_error_404.json"));
|
||||
.isEqualTo(generateExpectedJsonError(queryString + " not found", 404));
|
||||
assertThat(response.getStatus()).isEqualTo(404);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidEntity_returns400() {
|
||||
assertThat(generateActualJson("invalid/entity/handle")).isEqualTo(
|
||||
generateExpectedJson(
|
||||
generateExpectedJsonError(
|
||||
"invalid/entity/handle is not a valid entity handle",
|
||||
"rdap_error_400.json"));
|
||||
400));
|
||||
assertThat(response.getStatus()).isEqualTo(400);
|
||||
}
|
||||
|
||||
|
@ -282,7 +247,6 @@ public class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityActio
|
|||
"(◕‿◕)",
|
||||
"active",
|
||||
null,
|
||||
true,
|
||||
"rdap_associated_contact_no_personal_data.json");
|
||||
}
|
||||
|
||||
|
@ -294,7 +258,6 @@ public class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityActio
|
|||
"(◕‿◕)",
|
||||
"active",
|
||||
null,
|
||||
true,
|
||||
"rdap_associated_contact_no_personal_data.json");
|
||||
}
|
||||
|
||||
|
@ -349,7 +312,6 @@ public class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityActio
|
|||
"",
|
||||
"inactive",
|
||||
"",
|
||||
false,
|
||||
"rdap_contact_deleted.json");
|
||||
}
|
||||
|
||||
|
@ -362,7 +324,6 @@ public class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityActio
|
|||
"",
|
||||
"inactive",
|
||||
"",
|
||||
false,
|
||||
"rdap_contact_deleted.json");
|
||||
}
|
||||
|
||||
|
@ -409,7 +370,7 @@ public class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityActio
|
|||
login("deletedregistrar");
|
||||
action.includeDeletedParam = Optional.of(true);
|
||||
runSuccessfulTest(
|
||||
"104", "Yes Virginia <script>", "inactive", null, false, "rdap_registrar.json");
|
||||
"104", "Yes Virginia <script>", "inactive", null, "rdap_registrar.json");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -424,7 +385,7 @@ public class RdapEntityActionTest extends RdapActionBaseTestCase<RdapEntityActio
|
|||
loginAsAdmin();
|
||||
action.includeDeletedParam = Optional.of(true);
|
||||
runSuccessfulTest(
|
||||
"104", "Yes Virginia <script>", "inactive", null, false, "rdap_registrar.json");
|
||||
"104", "Yes Virginia <script>", "inactive", null, "rdap_registrar.json");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
package google.registry.rdap;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.request.Action.Method.GET;
|
||||
import static google.registry.testing.DatastoreHelper.createTld;
|
||||
|
@ -27,7 +26,6 @@ import static google.registry.testing.FullFieldsTestEntityHelper.makeContactReso
|
|||
import static google.registry.testing.FullFieldsTestEntityHelper.makeHistoryEntry;
|
||||
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrar;
|
||||
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrarContacts;
|
||||
import static google.registry.testing.TestDataHelper.loadFile;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableListMultimap;
|
||||
|
@ -70,11 +68,11 @@ public class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEnt
|
|||
private Registrar registrarInactive;
|
||||
private Registrar registrarTest;
|
||||
|
||||
private Object generateActualJsonWithFullName(String fn) {
|
||||
private JSONObject generateActualJsonWithFullName(String fn) {
|
||||
return generateActualJsonWithFullName(fn, null);
|
||||
}
|
||||
|
||||
private Object generateActualJsonWithFullName(String fn, String cursor) {
|
||||
private JSONObject generateActualJsonWithFullName(String fn, String cursor) {
|
||||
metricSearchType = SearchType.BY_FULL_NAME;
|
||||
action.fnParam = Optional.of(fn);
|
||||
if (cursor == null) {
|
||||
|
@ -85,14 +83,14 @@ public class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEnt
|
|||
action.cursorTokenParam = Optional.of(cursor);
|
||||
}
|
||||
action.run();
|
||||
return JSONValue.parse(response.getPayload());
|
||||
return (JSONObject) JSONValue.parse(response.getPayload());
|
||||
}
|
||||
|
||||
private Object generateActualJsonWithHandle(String handle) {
|
||||
private JSONObject generateActualJsonWithHandle(String handle) {
|
||||
return generateActualJsonWithHandle(handle, null);
|
||||
}
|
||||
|
||||
private Object generateActualJsonWithHandle(String handle, String cursor) {
|
||||
private JSONObject generateActualJsonWithHandle(String handle, String cursor) {
|
||||
metricSearchType = SearchType.BY_HANDLE;
|
||||
action.handleParam = Optional.of(handle);
|
||||
if (cursor == null) {
|
||||
|
@ -103,7 +101,7 @@ public class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEnt
|
|||
action.cursorTokenParam = Optional.of(cursor);
|
||||
}
|
||||
action.run();
|
||||
return JSONValue.parse(response.getPayload());
|
||||
return (JSONObject) JSONValue.parse(response.getPayload());
|
||||
}
|
||||
|
||||
@Before
|
||||
|
@ -158,18 +156,17 @@ public class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEnt
|
|||
action.subtypeParam = Optional.empty();
|
||||
}
|
||||
|
||||
private Object generateExpectedJson(String expectedOutputFile) {
|
||||
return JSONValue.parse(
|
||||
loadFile(this.getClass(), expectedOutputFile, ImmutableMap.of("TYPE", "entity")));
|
||||
private JSONObject generateExpectedJson(String expectedOutputFile) {
|
||||
return loadJsonFile(expectedOutputFile, "TYPE", "entity");
|
||||
}
|
||||
|
||||
private Object generateExpectedJson(
|
||||
private JSONObject generateExpectedJson(
|
||||
String handle,
|
||||
String expectedOutputFile) {
|
||||
return generateExpectedJson(handle, null, "active", null, null, expectedOutputFile);
|
||||
}
|
||||
|
||||
private Object generateExpectedJson(
|
||||
private JSONObject generateExpectedJson(
|
||||
String handle,
|
||||
@Nullable String fullName,
|
||||
String status,
|
||||
|
@ -189,20 +186,19 @@ public class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEnt
|
|||
}
|
||||
builder.put("TYPE", "entity");
|
||||
builder.put("STATUS", status);
|
||||
String substitutedFile = loadFile(this.getClass(), expectedOutputFile, builder.build());
|
||||
Object jsonObject = JSONValue.parse(substitutedFile);
|
||||
checkNotNull(jsonObject, "substituted file is not valid JSON: %s", substitutedFile);
|
||||
return jsonObject;
|
||||
return loadJsonFile(expectedOutputFile, builder.build());
|
||||
}
|
||||
|
||||
private Object generateExpectedJsonForEntity(
|
||||
private JSONObject generateExpectedJsonForEntity(
|
||||
String handle,
|
||||
String fullName,
|
||||
String status,
|
||||
@Nullable String email,
|
||||
@Nullable String address,
|
||||
String expectedOutputFile) {
|
||||
Object obj = generateExpectedJson(handle, fullName, status, email, address, expectedOutputFile);
|
||||
JSONObject obj =
|
||||
generateExpectedJson(handle, fullName, status, email, address, expectedOutputFile);
|
||||
obj.remove("rdapConformance");
|
||||
ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
|
||||
builder.put("entitySearchResults", ImmutableList.of(obj));
|
||||
builder.put("rdapConformance", ImmutableList.of("icann_rdap_response_profile_0"));
|
||||
|
@ -244,10 +240,20 @@ public class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEnt
|
|||
}
|
||||
|
||||
private void verifyMetrics(long numContactsRetrieved) {
|
||||
verifyMetrics(Optional.of(numContactsRetrieved));
|
||||
verifyMetrics(numContactsRetrieved, IncompletenessWarningType.COMPLETE);
|
||||
}
|
||||
|
||||
private void verifyMetrics(
|
||||
long numContactsRetrieved, IncompletenessWarningType incompletenessWarningType) {
|
||||
verifyMetrics(Optional.of(numContactsRetrieved), incompletenessWarningType);
|
||||
}
|
||||
|
||||
private void verifyMetrics(Optional<Long> numContactsRetrieved) {
|
||||
verifyMetrics(numContactsRetrieved, IncompletenessWarningType.COMPLETE);
|
||||
}
|
||||
|
||||
private void verifyMetrics(
|
||||
Optional<Long> numContactsRetrieved, IncompletenessWarningType incompletenessWarningType) {
|
||||
verifyMetrics(
|
||||
EndpointType.ENTITIES,
|
||||
GET,
|
||||
|
@ -256,7 +262,7 @@ public class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEnt
|
|||
Optional.empty(),
|
||||
Optional.empty(),
|
||||
numContactsRetrieved,
|
||||
IncompletenessWarningType.COMPLETE);
|
||||
incompletenessWarningType);
|
||||
}
|
||||
|
||||
private void verifyErrorMetrics(long numContactsRetrieved) {
|
||||
|
@ -269,14 +275,11 @@ public class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEnt
|
|||
verifyMetrics(numContactsRetrieved);
|
||||
}
|
||||
|
||||
private void checkNumberOfEntitiesInResult(Object obj, int expected) {
|
||||
private void checkNumberOfEntitiesInResult(JSONObject obj, int expected) {
|
||||
assertThat(obj).isInstanceOf(Map.class);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> map = (Map<String, Object>) obj;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Object> entities = (List<Object>) map.get("entitySearchResults");
|
||||
List<Object> entities = (List<Object>) obj.get("entitySearchResults");
|
||||
|
||||
assertThat(entities).hasSize(expected);
|
||||
}
|
||||
|
@ -318,7 +321,7 @@ public class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEnt
|
|||
private void runNotFoundNameTest(String queryString) {
|
||||
rememberWildcardType(queryString);
|
||||
assertThat(generateActualJsonWithFullName(queryString))
|
||||
.isEqualTo(generateExpectedJson("No entities found", "rdap_error_404.json"));
|
||||
.isEqualTo(generateExpectedJsonError("No entities found", 404));
|
||||
assertThat(response.getStatus()).isEqualTo(404);
|
||||
}
|
||||
|
||||
|
@ -359,7 +362,7 @@ public class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEnt
|
|||
private void runNotFoundHandleTest(String queryString) {
|
||||
rememberWildcardType(queryString);
|
||||
assertThat(generateActualJsonWithHandle(queryString))
|
||||
.isEqualTo(generateExpectedJson("No entities found", "rdap_error_404.json"));
|
||||
.isEqualTo(generateExpectedJsonError("No entities found", 404));
|
||||
assertThat(response.getStatus()).isEqualTo(404);
|
||||
}
|
||||
|
||||
|
@ -381,7 +384,7 @@ public class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEnt
|
|||
int expectedPageCount =
|
||||
(expectedNames.size() + action.rdapResultSetMaxSize - 1) / action.rdapResultSetMaxSize;
|
||||
for (int pageNum = 0; pageNum < expectedPageCount; pageNum++) {
|
||||
Object results =
|
||||
JSONObject results =
|
||||
(queryType == QueryType.FULL_NAME)
|
||||
? generateActualJsonWithFullName(paramValue, cursor)
|
||||
: generateActualJsonWithHandle(paramValue, cursor);
|
||||
|
@ -394,7 +397,7 @@ public class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEnt
|
|||
int pos = linkToNext.indexOf("cursor=");
|
||||
assertThat(pos).isAtLeast(0);
|
||||
cursor = URLDecoder.decode(linkToNext.substring(pos + 7), "UTF-8");
|
||||
Object searchResults = ((JSONObject) results).get("entitySearchResults");
|
||||
Object searchResults = results.get("entitySearchResults");
|
||||
assertThat(searchResults).isInstanceOf(JSONArray.class);
|
||||
assertThat(((JSONArray) searchResults)).hasSize(action.rdapResultSetMaxSize);
|
||||
for (Object item : ((JSONArray) searchResults)) {
|
||||
|
@ -429,8 +432,8 @@ public class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEnt
|
|||
action.run();
|
||||
assertThat(JSONValue.parse(response.getPayload()))
|
||||
.isEqualTo(
|
||||
generateExpectedJson(
|
||||
"You must specify either fn=XXXX or handle=YYYY", "rdap_error_400.json"));
|
||||
generateExpectedJsonError(
|
||||
"You must specify either fn=XXXX or handle=YYYY", 400));
|
||||
assertThat(response.getStatus()).isEqualTo(400);
|
||||
verifyErrorMetrics(Optional.empty(), 400);
|
||||
}
|
||||
|
@ -439,7 +442,7 @@ public class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEnt
|
|||
public void testNameMatch_suffixRejected() {
|
||||
assertThat(generateActualJsonWithFullName("exam*ple"))
|
||||
.isEqualTo(
|
||||
generateExpectedJson("Suffix not allowed after wildcard", "rdap_error_422.json"));
|
||||
generateExpectedJsonError("Suffix not allowed after wildcard", 422));
|
||||
assertThat(response.getStatus()).isEqualTo(422);
|
||||
verifyErrorMetrics(Optional.empty(), 422);
|
||||
}
|
||||
|
@ -448,7 +451,7 @@ public class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEnt
|
|||
public void testHandleMatch_suffixRejected() {
|
||||
assertThat(generateActualJsonWithHandle("exam*ple"))
|
||||
.isEqualTo(
|
||||
generateExpectedJson("Suffix not allowed after wildcard", "rdap_error_422.json"));
|
||||
generateExpectedJsonError("Suffix not allowed after wildcard", 422));
|
||||
assertThat(response.getStatus()).isEqualTo(422);
|
||||
verifyErrorMetrics(Optional.empty(), 422);
|
||||
}
|
||||
|
@ -456,7 +459,7 @@ public class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEnt
|
|||
@Test
|
||||
public void testMultipleWildcards_rejected() {
|
||||
assertThat(generateActualJsonWithHandle("*.*"))
|
||||
.isEqualTo(generateExpectedJson("Only one wildcard allowed", "rdap_error_422.json"));
|
||||
.isEqualTo(generateExpectedJsonError("Only one wildcard allowed", 422));
|
||||
assertThat(response.getStatus()).isEqualTo(422);
|
||||
verifyErrorMetrics(Optional.empty(), 422);
|
||||
}
|
||||
|
@ -466,9 +469,9 @@ public class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEnt
|
|||
rememberWildcardType("*");
|
||||
assertThat(generateActualJsonWithHandle("*"))
|
||||
.isEqualTo(
|
||||
generateExpectedJson(
|
||||
generateExpectedJsonError(
|
||||
"Initial search string must be at least 2 characters",
|
||||
"rdap_error_422.json"));
|
||||
422));
|
||||
assertThat(response.getStatus()).isEqualTo(422);
|
||||
verifyErrorMetrics(Optional.empty(), 422);
|
||||
}
|
||||
|
@ -478,9 +481,9 @@ public class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEnt
|
|||
rememberWildcardType("a*");
|
||||
assertThat(generateActualJsonWithHandle("a*"))
|
||||
.isEqualTo(
|
||||
generateExpectedJson(
|
||||
generateExpectedJsonError(
|
||||
"Initial search string must be at least 2 characters",
|
||||
"rdap_error_422.json"));
|
||||
422));
|
||||
assertThat(response.getStatus()).isEqualTo(422);
|
||||
verifyErrorMetrics(Optional.empty(), 422);
|
||||
}
|
||||
|
@ -490,9 +493,9 @@ public class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEnt
|
|||
action.subtypeParam = Optional.of("Space Aliens");
|
||||
assertThat(generateActualJsonWithFullName("Blinky (赤ベイ)"))
|
||||
.isEqualTo(
|
||||
generateExpectedJson(
|
||||
generateExpectedJsonError(
|
||||
"Subtype parameter must specify contacts, registrars or all",
|
||||
"rdap_error_400.json"));
|
||||
400));
|
||||
assertThat(response.getStatus()).isEqualTo(400);
|
||||
metricSearchType = SearchType.NONE; // Error occurs before search type is set.
|
||||
verifyErrorMetrics(Optional.empty(), 400);
|
||||
|
@ -700,7 +703,7 @@ public class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEnt
|
|||
generateExpectedJson(
|
||||
"fn=Entity+*&cursor=YzpFbnRpdHkgNA%3D%3D", "rdap_truncated_contacts.json"));
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
verifyMetrics(5);
|
||||
verifyMetrics(5, IncompletenessWarningType.TRUNCATED);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -714,7 +717,7 @@ public class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEnt
|
|||
"fn=Entity+*&cursor=YzpFbnRpdHkgNA%3D%3D", "rdap_truncated_contacts.json"));
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
// For contacts, we only need to fetch one result set's worth (plus one).
|
||||
verifyMetrics(5);
|
||||
verifyMetrics(5, IncompletenessWarningType.TRUNCATED);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -755,7 +758,7 @@ public class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEnt
|
|||
generateExpectedJson(
|
||||
"fn=Entity+*&cursor=cjpFbnRpdHkgNA%3D%3D", "rdap_truncated_registrars.json"));
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
verifyMetrics(0);
|
||||
verifyMetrics(0, IncompletenessWarningType.TRUNCATED);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -767,7 +770,7 @@ public class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEnt
|
|||
generateExpectedJson(
|
||||
"fn=Entity+*&cursor=cjpFbnRpdHkgNA%3D%3D", "rdap_truncated_registrars.json"));
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
verifyMetrics(0);
|
||||
verifyMetrics(0, IncompletenessWarningType.TRUNCATED);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -828,7 +831,7 @@ public class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEnt
|
|||
generateExpectedJson(
|
||||
"fn=Entity+*&cursor=cjpFbnRpdHkgNA%3D%3D", "rdap_truncated_mixed_entities.json"));
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
verifyMetrics(3);
|
||||
verifyMetrics(3, IncompletenessWarningType.TRUNCATED);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1234,10 +1237,10 @@ public class RdapEntitySearchActionTest extends RdapSearchActionTestCase<RdapEnt
|
|||
public void testHandleMatchMix_found_truncated() {
|
||||
createManyContactsAndRegistrars(30, 0, registrarTest);
|
||||
rememberWildcardType("00*");
|
||||
Object obj = generateActualJsonWithHandle("00*");
|
||||
JSONObject obj = generateActualJsonWithHandle("00*");
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
checkNumberOfEntitiesInResult(obj, 4);
|
||||
verifyMetrics(5);
|
||||
verifyMetrics(5, IncompletenessWarningType.TRUNCATED);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -15,16 +15,13 @@
|
|||
package google.registry.rdap;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.testing.TestDataHelper.loadFile;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.rdap.RdapMetrics.EndpointType;
|
||||
import google.registry.rdap.RdapMetrics.SearchType;
|
||||
import google.registry.rdap.RdapMetrics.WildcardType;
|
||||
import google.registry.rdap.RdapSearchResults.IncompletenessWarningType;
|
||||
import google.registry.request.Action;
|
||||
import org.json.simple.JSONValue;
|
||||
import org.junit.Test;
|
||||
|
||||
/** Unit tests for {@link RdapHelpAction}. */
|
||||
|
@ -34,44 +31,38 @@ public class RdapHelpActionTest extends RdapActionBaseTestCase<RdapHelpAction> {
|
|||
super(RdapHelpAction.class);
|
||||
}
|
||||
|
||||
private Object generateExpectedJson(String name, String expectedOutputFile) {
|
||||
return JSONValue.parse(
|
||||
loadFile(this.getClass(), expectedOutputFile, ImmutableMap.of("NAME", name)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHelpActionMaliciousPath_notFound() {
|
||||
assertThat(generateActualJson("../passwd")).isEqualTo(
|
||||
generateExpectedJson(
|
||||
"no help found for ../passwd", "rdap_error_404.json"));
|
||||
assertThat(generateActualJson("../passwd"))
|
||||
.isEqualTo(generateExpectedJsonError("no help found for ../passwd", 404));
|
||||
assertThat(response.getStatus()).isEqualTo(404);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHelpActionUnknownPath_notFound() {
|
||||
assertThat(generateActualJson("hlarg")).isEqualTo(
|
||||
generateExpectedJson("no help found for hlarg", "rdap_error_404.json"));
|
||||
generateExpectedJsonError("no help found for hlarg", 404));
|
||||
assertThat(response.getStatus()).isEqualTo(404);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHelpActionDefault_getsIndex() {
|
||||
assertThat(generateActualJson(""))
|
||||
.isEqualTo(generateExpectedJson("", "rdap_help_index.json"));
|
||||
.isEqualTo(loadJsonFile("rdap_help_index.json"));
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHelpActionSlash_getsIndex() {
|
||||
assertThat(generateActualJson("/"))
|
||||
.isEqualTo(generateExpectedJson("", "rdap_help_index.json"));
|
||||
.isEqualTo(loadJsonFile("rdap_help_index.json"));
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHelpActionTos_works() {
|
||||
assertThat(generateActualJson("/tos"))
|
||||
.isEqualTo(generateExpectedJson("", "rdap_help_tos.json"));
|
||||
.isEqualTo(loadJsonFile("rdap_help_tos.json"));
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,10 +27,10 @@ import static google.registry.testing.TestDataHelper.loadFile;
|
|||
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.config.RdapNoticeDescriptor;
|
||||
import google.registry.model.contact.ContactResource;
|
||||
import google.registry.model.domain.DesignatedContact;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
|
@ -44,12 +44,14 @@ import google.registry.model.reporting.HistoryEntry;
|
|||
import google.registry.model.transfer.TransferData;
|
||||
import google.registry.model.transfer.TransferStatus;
|
||||
import google.registry.rdap.RdapJsonFormatter.OutputDataType;
|
||||
import google.registry.rdap.RdapObjectClasses.BoilerplateType;
|
||||
import google.registry.rdap.RdapObjectClasses.ReplyPayloadBase;
|
||||
import google.registry.rdap.RdapObjectClasses.TopLevelReplyObject;
|
||||
import google.registry.testing.AppEngineRule;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.InjectRule;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
import org.json.simple.JSONValue;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
@ -84,8 +86,6 @@ public class RdapJsonFormatterTest {
|
|||
private ContactResource contactResourceTech;
|
||||
private ContactResource contactResourceNotLinked;
|
||||
|
||||
private static final String LINK_BASE = "http://myserver.example.com/";
|
||||
private static final String LINK_BASE_NO_TRAILING_SLASH = "http://myserver.example.com";
|
||||
// Do not set a port43 whois server, as per Gustavo Lozano.
|
||||
private static final String WHOIS_SERVER = null;
|
||||
|
||||
|
@ -307,415 +307,316 @@ public class RdapJsonFormatterTest {
|
|||
.build());
|
||||
}
|
||||
|
||||
private Object loadJson(String expectedFileName) {
|
||||
return JSONValue.parse(loadFile(this.getClass(), expectedFileName));
|
||||
private JsonElement loadJson(String expectedFileName) {
|
||||
return new Gson().fromJson(loadFile(this.getClass(), expectedFileName), JsonElement.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegistrar() {
|
||||
assertThat(rdapJsonFormatter.makeRdapJsonForRegistrar(
|
||||
registrar, false, LINK_BASE, WHOIS_SERVER, clock.nowUtc(), OutputDataType.FULL))
|
||||
assertThat(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForRegistrar(
|
||||
registrar, WHOIS_SERVER, clock.nowUtc(), OutputDataType.FULL)
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_registrar.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegistrar_summary() {
|
||||
assertThat(rdapJsonFormatter.makeRdapJsonForRegistrar(
|
||||
registrar, false, LINK_BASE, WHOIS_SERVER, clock.nowUtc(), OutputDataType.SUMMARY))
|
||||
assertThat(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForRegistrar(
|
||||
registrar, WHOIS_SERVER, clock.nowUtc(), OutputDataType.SUMMARY)
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_registrar_summary.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHost_ipv4() {
|
||||
assertThat(rdapJsonFormatter.makeRdapJsonForHost(
|
||||
hostResourceIpv4,
|
||||
false,
|
||||
LINK_BASE,
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.FULL))
|
||||
assertThat(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForHost(
|
||||
hostResourceIpv4, WHOIS_SERVER, clock.nowUtc(), OutputDataType.FULL)
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_host_ipv4.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHost_ipv6() {
|
||||
assertThat(rdapJsonFormatter.makeRdapJsonForHost(
|
||||
hostResourceIpv6,
|
||||
false,
|
||||
LINK_BASE,
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.FULL))
|
||||
assertThat(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForHost(
|
||||
hostResourceIpv6, WHOIS_SERVER, clock.nowUtc(), OutputDataType.FULL)
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_host_ipv6.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHost_both() {
|
||||
assertThat(rdapJsonFormatter.makeRdapJsonForHost(
|
||||
hostResourceBoth,
|
||||
false,
|
||||
LINK_BASE,
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.FULL))
|
||||
assertThat(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForHost(
|
||||
hostResourceBoth, WHOIS_SERVER, clock.nowUtc(), OutputDataType.FULL)
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_host_both.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHost_both_summary() {
|
||||
assertThat(rdapJsonFormatter.makeRdapJsonForHost(
|
||||
hostResourceBoth,
|
||||
false,
|
||||
LINK_BASE,
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.SUMMARY))
|
||||
assertThat(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForHost(
|
||||
hostResourceBoth, WHOIS_SERVER, clock.nowUtc(), OutputDataType.SUMMARY)
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_host_both_summary.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHost_noAddresses() {
|
||||
assertThat(rdapJsonFormatter.makeRdapJsonForHost(
|
||||
hostResourceNoAddresses,
|
||||
false,
|
||||
LINK_BASE,
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.FULL))
|
||||
assertThat(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForHost(
|
||||
hostResourceNoAddresses, WHOIS_SERVER, clock.nowUtc(), OutputDataType.FULL)
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_host_no_addresses.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHost_notLinked() {
|
||||
assertThat(rdapJsonFormatter.makeRdapJsonForHost(
|
||||
hostResourceNotLinked,
|
||||
false,
|
||||
LINK_BASE,
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.FULL))
|
||||
assertThat(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForHost(
|
||||
hostResourceNotLinked, WHOIS_SERVER, clock.nowUtc(), OutputDataType.FULL)
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_host_not_linked.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHost_superordinateHasPendingTransfer() {
|
||||
assertThat(rdapJsonFormatter.makeRdapJsonForHost(
|
||||
assertThat(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForHost(
|
||||
hostResourceSuperordinatePendingTransfer,
|
||||
false,
|
||||
LINK_BASE,
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.FULL))
|
||||
OutputDataType.FULL)
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_host_pending_transfer.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegistrant() {
|
||||
assertThat(
|
||||
rdapJsonFormatter.makeRdapJsonForContact(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForContact(
|
||||
contactResourceRegistrant,
|
||||
false,
|
||||
Optional.of(DesignatedContact.Type.REGISTRANT),
|
||||
LINK_BASE,
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.FULL,
|
||||
RdapAuthorization.create(RdapAuthorization.Role.REGISTRAR, "unicoderegistrar")))
|
||||
RdapAuthorization.create(RdapAuthorization.Role.REGISTRAR, "unicoderegistrar"))
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_registrant.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegistrant_summary() {
|
||||
assertThat(
|
||||
rdapJsonFormatter.makeRdapJsonForContact(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForContact(
|
||||
contactResourceRegistrant,
|
||||
false,
|
||||
Optional.of(DesignatedContact.Type.REGISTRANT),
|
||||
LINK_BASE,
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.SUMMARY,
|
||||
RdapAuthorization.create(RdapAuthorization.Role.REGISTRAR, "unicoderegistrar")))
|
||||
RdapAuthorization.create(RdapAuthorization.Role.REGISTRAR, "unicoderegistrar"))
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_registrant_summary.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegistrant_loggedOut() {
|
||||
assertThat(
|
||||
rdapJsonFormatter.makeRdapJsonForContact(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForContact(
|
||||
contactResourceRegistrant,
|
||||
false,
|
||||
Optional.of(DesignatedContact.Type.REGISTRANT),
|
||||
LINK_BASE,
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.FULL,
|
||||
RdapAuthorization.PUBLIC_AUTHORIZATION))
|
||||
RdapAuthorization.PUBLIC_AUTHORIZATION)
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_registrant_logged_out.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegistrant_baseHasNoTrailingSlash() {
|
||||
// First, make sure we have a trailing slash at the end by default!
|
||||
// This test tries to change the default state, if the default doesn't have a /, then this test
|
||||
// doesn't help.
|
||||
assertThat(rdapJsonFormatter.fullServletPath).endsWith("/");
|
||||
rdapJsonFormatter.fullServletPath =
|
||||
rdapJsonFormatter.fullServletPath.substring(
|
||||
0, rdapJsonFormatter.fullServletPath.length() - 1);
|
||||
assertThat(
|
||||
rdapJsonFormatter.makeRdapJsonForContact(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForContact(
|
||||
contactResourceRegistrant,
|
||||
false,
|
||||
Optional.of(DesignatedContact.Type.REGISTRANT),
|
||||
LINK_BASE_NO_TRAILING_SLASH,
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.FULL,
|
||||
RdapAuthorization.create(RdapAuthorization.Role.REGISTRAR, "unicoderegistrar")))
|
||||
RdapAuthorization.create(RdapAuthorization.Role.REGISTRAR, "unicoderegistrar"))
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_registrant.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegistrant_noBase() {
|
||||
assertThat(
|
||||
rdapJsonFormatter.makeRdapJsonForContact(
|
||||
contactResourceRegistrant,
|
||||
false,
|
||||
Optional.of(DesignatedContact.Type.REGISTRANT),
|
||||
null,
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.FULL,
|
||||
RdapAuthorization.create(RdapAuthorization.Role.REGISTRAR, "unicoderegistrar")))
|
||||
.isEqualTo(loadJson("rdapjson_registrant_nobase.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAdmin() {
|
||||
assertThat(
|
||||
rdapJsonFormatter.makeRdapJsonForContact(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForContact(
|
||||
contactResourceAdmin,
|
||||
false,
|
||||
Optional.of(DesignatedContact.Type.ADMIN),
|
||||
LINK_BASE,
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.FULL,
|
||||
RdapAuthorization.create(RdapAuthorization.Role.REGISTRAR, "unicoderegistrar")))
|
||||
RdapAuthorization.create(RdapAuthorization.Role.REGISTRAR, "unicoderegistrar"))
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_admincontact.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTech() {
|
||||
assertThat(
|
||||
rdapJsonFormatter.makeRdapJsonForContact(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForContact(
|
||||
contactResourceTech,
|
||||
false,
|
||||
Optional.of(DesignatedContact.Type.TECH),
|
||||
LINK_BASE,
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.FULL,
|
||||
RdapAuthorization.create(RdapAuthorization.Role.REGISTRAR, "unicoderegistrar")))
|
||||
RdapAuthorization.create(RdapAuthorization.Role.REGISTRAR, "unicoderegistrar"))
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_techcontact.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRolelessContact() {
|
||||
assertThat(
|
||||
rdapJsonFormatter.makeRdapJsonForContact(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForContact(
|
||||
contactResourceTech,
|
||||
false,
|
||||
Optional.empty(),
|
||||
LINK_BASE,
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.FULL,
|
||||
RdapAuthorization.create(RdapAuthorization.Role.REGISTRAR, "unicoderegistrar")))
|
||||
RdapAuthorization.create(RdapAuthorization.Role.REGISTRAR, "unicoderegistrar"))
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_rolelesscontact.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnlinkedContact() {
|
||||
assertThat(
|
||||
rdapJsonFormatter.makeRdapJsonForContact(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForContact(
|
||||
contactResourceNotLinked,
|
||||
false,
|
||||
Optional.empty(),
|
||||
LINK_BASE,
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.FULL,
|
||||
RdapAuthorization.create(RdapAuthorization.Role.REGISTRAR, "unicoderegistrar")))
|
||||
RdapAuthorization.create(RdapAuthorization.Role.REGISTRAR, "unicoderegistrar"))
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_unlinkedcontact.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDomain_full() {
|
||||
assertThat(rdapJsonFormatter.makeRdapJsonForDomain(
|
||||
assertThat(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForDomain(
|
||||
domainBaseFull,
|
||||
false,
|
||||
LINK_BASE,
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.FULL,
|
||||
RdapAuthorization.create(RdapAuthorization.Role.REGISTRAR, "unicoderegistrar")))
|
||||
RdapAuthorization.create(RdapAuthorization.Role.REGISTRAR, "unicoderegistrar"))
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_domain_full.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDomain_summary() {
|
||||
assertThat(rdapJsonFormatter.makeRdapJsonForDomain(
|
||||
assertThat(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForDomain(
|
||||
domainBaseFull,
|
||||
false,
|
||||
LINK_BASE,
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.SUMMARY,
|
||||
RdapAuthorization.create(RdapAuthorization.Role.REGISTRAR, "unicoderegistrar")))
|
||||
RdapAuthorization.create(RdapAuthorization.Role.REGISTRAR, "unicoderegistrar"))
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_domain_summary.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDomain_logged_out() {
|
||||
assertThat(rdapJsonFormatter.makeRdapJsonForDomain(
|
||||
assertThat(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForDomain(
|
||||
domainBaseFull,
|
||||
false,
|
||||
LINK_BASE,
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.FULL,
|
||||
RdapAuthorization.PUBLIC_AUTHORIZATION))
|
||||
RdapAuthorization.PUBLIC_AUTHORIZATION)
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_domain_logged_out.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDomain_noNameserversNoTransfers() {
|
||||
assertThat(rdapJsonFormatter.makeRdapJsonForDomain(
|
||||
assertThat(
|
||||
rdapJsonFormatter
|
||||
.makeRdapJsonForDomain(
|
||||
domainBaseNoNameserversNoTransfers,
|
||||
false,
|
||||
LINK_BASE,
|
||||
WHOIS_SERVER,
|
||||
clock.nowUtc(),
|
||||
OutputDataType.FULL,
|
||||
RdapAuthorization.create(RdapAuthorization.Role.REGISTRAR, "unicoderegistrar")))
|
||||
RdapAuthorization.create(RdapAuthorization.Role.REGISTRAR, "unicoderegistrar"))
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_domain_no_nameservers.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testError() {
|
||||
assertThat(
|
||||
rdapJsonFormatter
|
||||
.makeError(SC_BAD_REQUEST, "Invalid Domain Name", "Not a valid domain name"))
|
||||
RdapObjectClasses.ErrorResponse.create(
|
||||
SC_BAD_REQUEST, "Invalid Domain Name", "Not a valid domain name")
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_error.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHelp_absoluteHtmlUrl() {
|
||||
assertThat(RdapJsonFormatter.makeRdapJsonNotice(
|
||||
RdapNoticeDescriptor.builder()
|
||||
.setTitle("RDAP Help")
|
||||
.setDescription(ImmutableList.of(
|
||||
"RDAP Help Topics (use /help/topic for information)",
|
||||
"syntax",
|
||||
"tos (Terms of Service)"))
|
||||
.setLinkValueSuffix("help/index")
|
||||
.setLinkHrefUrlString(LINK_BASE + "about/rdap/index.html")
|
||||
.build(),
|
||||
LINK_BASE))
|
||||
.isEqualTo(loadJson("rdapjson_notice_alternate_link.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHelp_relativeHtmlUrlWithStartingSlash() {
|
||||
assertThat(RdapJsonFormatter.makeRdapJsonNotice(
|
||||
RdapNoticeDescriptor.builder()
|
||||
.setTitle("RDAP Help")
|
||||
.setDescription(ImmutableList.of(
|
||||
"RDAP Help Topics (use /help/topic for information)",
|
||||
"syntax",
|
||||
"tos (Terms of Service)"))
|
||||
.setLinkValueSuffix("help/index")
|
||||
.setLinkHrefUrlString("/about/rdap/index.html")
|
||||
.build(),
|
||||
LINK_BASE))
|
||||
.isEqualTo(loadJson("rdapjson_notice_alternate_link.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHelp_relativeHtmlUrlWithoutStartingSlash() {
|
||||
assertThat(RdapJsonFormatter.makeRdapJsonNotice(
|
||||
RdapNoticeDescriptor.builder()
|
||||
.setTitle("RDAP Help")
|
||||
.setDescription(ImmutableList.of(
|
||||
"RDAP Help Topics (use /help/topic for information)",
|
||||
"syntax",
|
||||
"tos (Terms of Service)"))
|
||||
.setLinkValueSuffix("help/index")
|
||||
.setLinkHrefUrlString("about/rdap/index.html")
|
||||
.build(),
|
||||
LINK_BASE))
|
||||
.isEqualTo(loadJson("rdapjson_notice_alternate_link.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHelp_noHtmlUrl() {
|
||||
assertThat(RdapJsonFormatter.makeRdapJsonNotice(
|
||||
RdapNoticeDescriptor.builder()
|
||||
.setTitle("RDAP Help")
|
||||
.setDescription(ImmutableList.of(
|
||||
"RDAP Help Topics (use /help/topic for information)",
|
||||
"syntax",
|
||||
"tos (Terms of Service)"))
|
||||
.setLinkValueSuffix("help/index")
|
||||
.build(),
|
||||
LINK_BASE))
|
||||
.isEqualTo(loadJson("rdapjson_notice_self_link.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTopLevel() {
|
||||
ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
|
||||
builder.put("key", "value");
|
||||
rdapJsonFormatter.addTopLevelEntries(
|
||||
builder,
|
||||
RdapJsonFormatter.BoilerplateType.OTHER,
|
||||
ImmutableList.of(),
|
||||
ImmutableList.of(),
|
||||
LINK_BASE);
|
||||
assertThat(builder.build()).isEqualTo(loadJson("rdapjson_toplevel.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTopLevel_withTermsOfService() {
|
||||
ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
|
||||
builder.put("key", "value");
|
||||
rdapJsonFormatter.addTopLevelEntries(
|
||||
builder,
|
||||
RdapJsonFormatter.BoilerplateType.OTHER,
|
||||
ImmutableList.of(rdapJsonFormatter.getJsonHelpNotice("/tos", LINK_BASE)),
|
||||
ImmutableList.of(),
|
||||
LINK_BASE);
|
||||
assertThat(builder.build()).isEqualTo(loadJson("rdapjson_toplevel.json"));
|
||||
assertThat(
|
||||
TopLevelReplyObject.create(
|
||||
new ReplyPayloadBase(BoilerplateType.OTHER) {
|
||||
@JsonableElement public String key = "value";
|
||||
},
|
||||
rdapJsonFormatter.createTosNotice())
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_toplevel.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTopLevel_domain() {
|
||||
ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
|
||||
builder.put("key", "value");
|
||||
rdapJsonFormatter.addTopLevelEntries(
|
||||
builder,
|
||||
RdapJsonFormatter.BoilerplateType.DOMAIN,
|
||||
ImmutableList.of(),
|
||||
ImmutableList.of(),
|
||||
LINK_BASE);
|
||||
assertThat(builder.build()).isEqualTo(loadJson("rdapjson_toplevel_domain.json"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTopLevel_domainWithTermsOfService() {
|
||||
ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
|
||||
builder.put("key", "value");
|
||||
rdapJsonFormatter.addTopLevelEntries(
|
||||
builder,
|
||||
RdapJsonFormatter.BoilerplateType.DOMAIN,
|
||||
ImmutableList.of(rdapJsonFormatter.getJsonHelpNotice("/tos", LINK_BASE)),
|
||||
ImmutableList.of(),
|
||||
LINK_BASE);
|
||||
assertThat(builder.build()).isEqualTo(loadJson("rdapjson_toplevel_domain.json"));
|
||||
assertThat(
|
||||
TopLevelReplyObject.create(
|
||||
new ReplyPayloadBase(BoilerplateType.DOMAIN) {
|
||||
@JsonableElement public String key = "value";
|
||||
},
|
||||
rdapJsonFormatter.createTosNotice())
|
||||
.toJson())
|
||||
.isEqualTo(loadJson("rdapjson_toplevel_domain.json"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ import static google.registry.testing.DatastoreHelper.createTld;
|
|||
import static google.registry.testing.DatastoreHelper.persistResource;
|
||||
import static google.registry.testing.FullFieldsTestEntityHelper.makeAndPersistHostResource;
|
||||
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrar;
|
||||
import static google.registry.testing.TestDataHelper.loadFile;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
@ -34,7 +33,7 @@ import google.registry.request.Action;
|
|||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nullable;
|
||||
import org.json.simple.JSONValue;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
@ -92,10 +91,9 @@ public class RdapNameserverActionTest extends RdapActionBaseTestCase<RdapNameser
|
|||
if (!punycodeSet) {
|
||||
builder.put("PUNYCODENAME", name);
|
||||
}
|
||||
return JSONValue.parse(loadFile(
|
||||
this.getClass(),
|
||||
return loadJsonFile(
|
||||
expectedOutputFile,
|
||||
builder.build()));
|
||||
builder.build());
|
||||
}
|
||||
|
||||
private Object generateExpectedJsonWithTopLevelEntries(
|
||||
|
@ -114,9 +112,8 @@ public class RdapNameserverActionTest extends RdapActionBaseTestCase<RdapNameser
|
|||
builder,
|
||||
RdapTestHelper.createNotices(
|
||||
"https://example.tld/rdap/",
|
||||
RdapTestHelper.ContactNoticeType.NONE,
|
||||
map.get("notices")));
|
||||
obj = builder.build();
|
||||
obj = new JSONObject(builder.build());
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
@ -125,17 +122,16 @@ public class RdapNameserverActionTest extends RdapActionBaseTestCase<RdapNameser
|
|||
public void testInvalidNameserver_returns400() {
|
||||
assertThat(generateActualJson("invalid/host/name"))
|
||||
.isEqualTo(
|
||||
generateExpectedJson(
|
||||
generateExpectedJsonError(
|
||||
"invalid/host/name is not a valid nameserver: Invalid host name",
|
||||
null,
|
||||
"rdap_error_400.json"));
|
||||
400));
|
||||
assertThat(response.getStatus()).isEqualTo(400);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnknownNameserver_returns404() {
|
||||
assertThat(generateActualJson("ns1.missing.com")).isEqualTo(
|
||||
generateExpectedJson("ns1.missing.com not found", null, "rdap_error_404.json"));
|
||||
generateExpectedJsonError("ns1.missing.com not found", 404));
|
||||
assertThat(response.getStatus()).isEqualTo(404);
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ import static google.registry.testing.FullFieldsTestEntityHelper.makeDomainBase;
|
|||
import static google.registry.testing.FullFieldsTestEntityHelper.makeHostResource;
|
||||
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrar;
|
||||
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrarContacts;
|
||||
import static google.registry.testing.TestDataHelper.loadFile;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableListMultimap;
|
||||
|
@ -43,7 +42,6 @@ import google.registry.rdap.RdapSearchResults.IncompletenessWarningType;
|
|||
import google.registry.testing.FakeResponse;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nullable;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.JSONValue;
|
||||
|
@ -65,11 +63,11 @@ public class RdapNameserverSearchActionTest
|
|||
private HostResource hostNs1CatLol;
|
||||
private HostResource hostNs2CatLol;
|
||||
|
||||
private Object generateActualJsonWithName(String name) {
|
||||
private JSONObject generateActualJsonWithName(String name) {
|
||||
return generateActualJsonWithName(name, null);
|
||||
}
|
||||
|
||||
private Object generateActualJsonWithName(String name, String cursor) {
|
||||
private JSONObject generateActualJsonWithName(String name, String cursor) {
|
||||
metricSearchType = SearchType.BY_NAMESERVER_NAME;
|
||||
rememberWildcardType(name);
|
||||
action.nameParam = Optional.of(name);
|
||||
|
@ -81,14 +79,14 @@ public class RdapNameserverSearchActionTest
|
|||
action.cursorTokenParam = Optional.of(cursor);
|
||||
}
|
||||
action.run();
|
||||
return JSONValue.parse(response.getPayload());
|
||||
return (JSONObject) JSONValue.parse(response.getPayload());
|
||||
}
|
||||
|
||||
private Object generateActualJsonWithIp(String ipString) {
|
||||
private JSONObject generateActualJsonWithIp(String ipString) {
|
||||
return generateActualJsonWithIp(ipString, null);
|
||||
}
|
||||
|
||||
private Object generateActualJsonWithIp(String ipString, String cursor) {
|
||||
private JSONObject generateActualJsonWithIp(String ipString, String cursor) {
|
||||
metricSearchType = SearchType.BY_NAMESERVER_ADDRESS;
|
||||
action.parameterMap = ImmutableListMultimap.of("ip", ipString);
|
||||
action.ipParam = Optional.of(ipString);
|
||||
|
@ -100,7 +98,7 @@ public class RdapNameserverSearchActionTest
|
|||
action.cursorTokenParam = Optional.of(cursor);
|
||||
}
|
||||
action.run();
|
||||
return JSONValue.parse(response.getPayload());
|
||||
return (JSONObject) JSONValue.parse(response.getPayload());
|
||||
}
|
||||
|
||||
@Before
|
||||
|
@ -156,59 +154,30 @@ public class RdapNameserverSearchActionTest
|
|||
action.nameParam = Optional.empty();
|
||||
}
|
||||
|
||||
private Object generateExpectedJson(String expectedOutputFile) {
|
||||
return generateExpectedJson(null, null, null, null, null, expectedOutputFile);
|
||||
}
|
||||
|
||||
private Object generateExpectedJson(String name, String expectedOutputFile) {
|
||||
return generateExpectedJson(name, null, null, null, null, expectedOutputFile);
|
||||
}
|
||||
|
||||
private Object generateExpectedJson(
|
||||
@Nullable String name,
|
||||
@Nullable String punycodeName,
|
||||
@Nullable String handle,
|
||||
@Nullable String ipAddressType,
|
||||
@Nullable String ipAddress,
|
||||
String expectedOutputFile) {
|
||||
ImmutableMap.Builder<String, String> builder = new ImmutableMap.Builder<>();
|
||||
if (name != null) {
|
||||
builder.put("NAME", name);
|
||||
}
|
||||
if ((name != null) || (punycodeName != null)) {
|
||||
builder.put("PUNYCODENAME", (punycodeName == null) ? name : punycodeName);
|
||||
}
|
||||
if (handle != null) {
|
||||
builder.put("HANDLE", handle);
|
||||
}
|
||||
if (ipAddressType != null) {
|
||||
builder.put("ADDRESSTYPE", ipAddressType);
|
||||
}
|
||||
if (ipAddress != null) {
|
||||
builder.put("ADDRESS", ipAddress);
|
||||
}
|
||||
builder.put("STATUS", "active");
|
||||
builder.put("TYPE", "nameserver");
|
||||
return JSONValue.parse(
|
||||
loadFile(this.getClass(), expectedOutputFile, builder.build()));
|
||||
}
|
||||
|
||||
private Object generateExpectedJsonForNameserver(
|
||||
private JSONObject generateExpectedJsonForNameserver(
|
||||
String name,
|
||||
String punycodeName,
|
||||
String handle,
|
||||
String ipAddressType,
|
||||
String ipAddress,
|
||||
String expectedOutputFile) {
|
||||
Object obj =
|
||||
generateExpectedJson(
|
||||
name, punycodeName, handle, ipAddressType, ipAddress, expectedOutputFile);
|
||||
JSONObject obj =
|
||||
loadJsonFile(
|
||||
expectedOutputFile,
|
||||
"NAME", name,
|
||||
"PUNYCODENAME", punycodeName,
|
||||
"HANDLE", handle,
|
||||
"ADDRESSTYPE", ipAddressType,
|
||||
"ADDRESS", ipAddress,
|
||||
"STATUS", "active",
|
||||
"TYPE", "nameserver");
|
||||
obj.remove("rdapConformance");
|
||||
ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
|
||||
builder.put("nameserverSearchResults", ImmutableList.of(obj));
|
||||
builder.put("rdapConformance", ImmutableList.of("icann_rdap_response_profile_0"));
|
||||
RdapTestHelper.addNonDomainBoilerplateNotices(
|
||||
builder, RdapTestHelper.createNotices("https://example.tld/rdap/"));
|
||||
return builder.build();
|
||||
return new JSONObject(builder.build());
|
||||
}
|
||||
|
||||
private void createManyHosts(int numHosts) {
|
||||
|
@ -234,6 +203,11 @@ public class RdapNameserverSearchActionTest
|
|||
.build());
|
||||
}
|
||||
|
||||
private void verifyMetrics(
|
||||
long numHostsRetrieved, IncompletenessWarningType incompletenessWarningType) {
|
||||
verifyMetrics(Optional.of(numHostsRetrieved), incompletenessWarningType);
|
||||
}
|
||||
|
||||
private void verifyMetrics(long numHostsRetrieved) {
|
||||
verifyMetrics(Optional.of(numHostsRetrieved), IncompletenessWarningType.COMPLETE);
|
||||
}
|
||||
|
@ -274,8 +248,9 @@ public class RdapNameserverSearchActionTest
|
|||
action.run();
|
||||
assertThat(JSONValue.parse(response.getPayload()))
|
||||
.isEqualTo(
|
||||
generateExpectedJson(
|
||||
"You must specify either name=XXXX or ip=YYYY", "rdap_error_400.json"));
|
||||
generateExpectedJsonError(
|
||||
"You must specify either name=XXXX or ip=YYYY",
|
||||
400));
|
||||
assertThat(response.getStatus()).isEqualTo(400);
|
||||
verifyErrorMetrics(Optional.empty(), 400);
|
||||
}
|
||||
|
@ -284,10 +259,10 @@ public class RdapNameserverSearchActionTest
|
|||
public void testInvalidSuffix_rejected() {
|
||||
assertThat(generateActualJsonWithName("exam*ple"))
|
||||
.isEqualTo(
|
||||
generateExpectedJson(
|
||||
generateExpectedJsonError(
|
||||
"Suffix after wildcard must be one or more domain"
|
||||
+ " name labels, e.g. exam*.tld, ns*.example.tld",
|
||||
"rdap_error_422.json"));
|
||||
422));
|
||||
assertThat(response.getStatus()).isEqualTo(422);
|
||||
verifyErrorMetrics(Optional.empty(), 422);
|
||||
}
|
||||
|
@ -296,9 +271,9 @@ public class RdapNameserverSearchActionTest
|
|||
public void testNonexistentDomainSuffix_unprocessable() {
|
||||
assertThat(generateActualJsonWithName("exam*.foo.bar"))
|
||||
.isEqualTo(
|
||||
generateExpectedJson(
|
||||
generateExpectedJsonError(
|
||||
"A suffix after a wildcard in a nameserver lookup must be an in-bailiwick domain",
|
||||
"rdap_error_422.json"));
|
||||
422));
|
||||
assertThat(response.getStatus()).isEqualTo(422);
|
||||
verifyErrorMetrics(Optional.empty(), 422);
|
||||
}
|
||||
|
@ -306,7 +281,7 @@ public class RdapNameserverSearchActionTest
|
|||
@Test
|
||||
public void testMultipleWildcards_rejected() {
|
||||
assertThat(generateActualJsonWithName("*.*"))
|
||||
.isEqualTo(generateExpectedJson("Only one wildcard allowed", "rdap_error_422.json"));
|
||||
.isEqualTo(generateExpectedJsonError("Only one wildcard allowed", 422));
|
||||
assertThat(response.getStatus()).isEqualTo(422);
|
||||
verifyErrorMetrics(Optional.empty(), 422);
|
||||
}
|
||||
|
@ -315,8 +290,8 @@ public class RdapNameserverSearchActionTest
|
|||
public void testNoCharactersToMatch_rejected() {
|
||||
assertThat(generateActualJsonWithName("*"))
|
||||
.isEqualTo(
|
||||
generateExpectedJson(
|
||||
"Initial search string must be at least 2 characters", "rdap_error_422.json"));
|
||||
generateExpectedJsonError(
|
||||
"Initial search string must be at least 2 characters", 422));
|
||||
assertThat(response.getStatus()).isEqualTo(422);
|
||||
verifyErrorMetrics(Optional.empty(), 422);
|
||||
}
|
||||
|
@ -325,8 +300,8 @@ public class RdapNameserverSearchActionTest
|
|||
public void testFewerThanTwoCharactersToMatch_rejected() {
|
||||
assertThat(generateActualJsonWithName("a*"))
|
||||
.isEqualTo(
|
||||
generateExpectedJson(
|
||||
"Initial search string must be at least 2 characters", "rdap_error_422.json"));
|
||||
generateExpectedJsonError(
|
||||
"Initial search string must be at least 2 characters", 422));
|
||||
assertThat(response.getStatus()).isEqualTo(422);
|
||||
verifyErrorMetrics(Optional.empty(), 422);
|
||||
}
|
||||
|
@ -491,7 +466,7 @@ public class RdapNameserverSearchActionTest
|
|||
public void testNameMatch_nsstar_found() {
|
||||
generateActualJsonWithName("ns*");
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
verifyMetrics(5);
|
||||
verifyMetrics(5, IncompletenessWarningType.TRUNCATED);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -505,7 +480,7 @@ public class RdapNameserverSearchActionTest
|
|||
public void testNameMatch_ns1_castar_found() {
|
||||
generateActualJsonWithName("ns1.ca*");
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
verifyMetrics(5);
|
||||
verifyMetrics(5, IncompletenessWarningType.TRUNCATED);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -519,7 +494,7 @@ public class RdapNameserverSearchActionTest
|
|||
public void testNameMatch_nontruncatedResultSet() {
|
||||
createManyHosts(4);
|
||||
assertThat(generateActualJsonWithName("nsx*.cat.lol"))
|
||||
.isEqualTo(generateExpectedJson("rdap_nontruncated_hosts.json"));
|
||||
.isEqualTo(loadJsonFile("rdap_nontruncated_hosts.json"));
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
verifyMetrics(4);
|
||||
}
|
||||
|
@ -529,10 +504,10 @@ public class RdapNameserverSearchActionTest
|
|||
createManyHosts(5);
|
||||
assertThat(generateActualJsonWithName("nsx*.cat.lol"))
|
||||
.isEqualTo(
|
||||
generateExpectedJson(
|
||||
"name=nsx*.cat.lol&cursor=bnN4NC5jYXQubG9s", "rdap_truncated_hosts.json"));
|
||||
loadJsonFile(
|
||||
"rdap_truncated_hosts.json", "QUERY", "name=nsx*.cat.lol&cursor=bnN4NC5jYXQubG9s"));
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
verifyMetrics(5);
|
||||
verifyMetrics(5, IncompletenessWarningType.TRUNCATED);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -540,11 +515,11 @@ public class RdapNameserverSearchActionTest
|
|||
createManyHosts(9);
|
||||
assertThat(generateActualJsonWithName("nsx*.cat.lol"))
|
||||
.isEqualTo(
|
||||
generateExpectedJson(
|
||||
"name=nsx*.cat.lol&cursor=bnN4NC5jYXQubG9s", "rdap_truncated_hosts.json"));
|
||||
loadJsonFile(
|
||||
"rdap_truncated_hosts.json", "QUERY", "name=nsx*.cat.lol&cursor=bnN4NC5jYXQubG9s"));
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
// When searching names, we look for additional matches, in case some are not visible.
|
||||
verifyMetrics(9);
|
||||
verifyMetrics(9, IncompletenessWarningType.TRUNCATED);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -568,7 +543,7 @@ public class RdapNameserverSearchActionTest
|
|||
public void testNameMatchDeletedHost_notFound() {
|
||||
persistResource(hostNs1CatLol.asBuilder().setDeletionTime(clock.nowUtc().minusDays(1)).build());
|
||||
assertThat(generateActualJsonWithName("ns1.cat.lol"))
|
||||
.isEqualTo(generateExpectedJson("No nameservers found", "rdap_error_404.json"));
|
||||
.isEqualTo(generateExpectedJsonError("No nameservers found", 404));
|
||||
assertThat(response.getStatus()).isEqualTo(404);
|
||||
verifyErrorMetrics();
|
||||
}
|
||||
|
@ -577,7 +552,7 @@ public class RdapNameserverSearchActionTest
|
|||
public void testNameMatchDeletedHostWithWildcard_notFound() {
|
||||
persistResource(hostNs1CatLol.asBuilder().setDeletionTime(clock.nowUtc().minusDays(1)).build());
|
||||
assertThat(generateActualJsonWithName("cat.lo*"))
|
||||
.isEqualTo(generateExpectedJson("No nameservers found", "rdap_error_404.json"));
|
||||
.isEqualTo(generateExpectedJsonError("No nameservers found", 404));
|
||||
assertThat(response.getStatus()).isEqualTo(404);
|
||||
verifyErrorMetrics();
|
||||
}
|
||||
|
@ -669,7 +644,7 @@ public class RdapNameserverSearchActionTest
|
|||
int expectedPageCount =
|
||||
(expectedNames.size() + action.rdapResultSetMaxSize - 1) / action.rdapResultSetMaxSize;
|
||||
for (int pageNum = 0; pageNum < expectedPageCount; pageNum++) {
|
||||
Object results =
|
||||
JSONObject results =
|
||||
byName
|
||||
? generateActualJsonWithName(paramValue, cursor)
|
||||
: generateActualJsonWithIp(paramValue, cursor);
|
||||
|
@ -682,7 +657,7 @@ public class RdapNameserverSearchActionTest
|
|||
int pos = linkToNext.indexOf("cursor=");
|
||||
assertThat(pos).isAtLeast(0);
|
||||
cursor = URLDecoder.decode(linkToNext.substring(pos + 7), "UTF-8");
|
||||
Object searchResults = ((JSONObject) results).get("nameserverSearchResults");
|
||||
Object searchResults = results.get("nameserverSearchResults");
|
||||
assertThat(searchResults).isInstanceOf(JSONArray.class);
|
||||
assertThat(((JSONArray) searchResults)).hasSize(action.rdapResultSetMaxSize);
|
||||
for (Object item : ((JSONArray) searchResults)) {
|
||||
|
@ -776,7 +751,7 @@ public class RdapNameserverSearchActionTest
|
|||
@Test
|
||||
public void testAddressMatchV6Address_foundMultiple() {
|
||||
assertThat(generateActualJsonWithIp("bad:f00d:cafe::15:beef"))
|
||||
.isEqualTo(generateExpectedJson("rdap_multiple_hosts.json"));
|
||||
.isEqualTo(loadJsonFile("rdap_multiple_hosts.json"));
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
verifyMetrics(2);
|
||||
}
|
||||
|
@ -792,7 +767,7 @@ public class RdapNameserverSearchActionTest
|
|||
public void testAddressMatchDeletedHost_notFound() {
|
||||
persistResource(hostNs1CatLol.asBuilder().setDeletionTime(clock.nowUtc().minusDays(1)).build());
|
||||
assertThat(generateActualJsonWithIp("1.2.3.4"))
|
||||
.isEqualTo(generateExpectedJson("No nameservers found", "rdap_error_404.json"));
|
||||
.isEqualTo(generateExpectedJsonError("No nameservers found", 404));
|
||||
assertThat(response.getStatus()).isEqualTo(404);
|
||||
verifyErrorMetrics();
|
||||
}
|
||||
|
@ -801,7 +776,7 @@ public class RdapNameserverSearchActionTest
|
|||
public void testAddressMatch_nontruncatedResultSet() {
|
||||
createManyHosts(4);
|
||||
assertThat(generateActualJsonWithIp("5.5.5.1"))
|
||||
.isEqualTo(generateExpectedJson("rdap_nontruncated_hosts.json"));
|
||||
.isEqualTo(loadJsonFile("rdap_nontruncated_hosts.json"));
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
verifyMetrics(4);
|
||||
}
|
||||
|
@ -811,10 +786,10 @@ public class RdapNameserverSearchActionTest
|
|||
createManyHosts(5);
|
||||
assertThat(generateActualJsonWithIp("5.5.5.1"))
|
||||
.isEqualTo(
|
||||
generateExpectedJson(
|
||||
"ip=5.5.5.1&cursor=MTctUk9JRA%3D%3D", "rdap_truncated_hosts.json"));
|
||||
loadJsonFile(
|
||||
"rdap_truncated_hosts.json", "QUERY", "ip=5.5.5.1&cursor=MTctUk9JRA%3D%3D"));
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
verifyMetrics(5);
|
||||
verifyMetrics(5, IncompletenessWarningType.TRUNCATED);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -822,12 +797,12 @@ public class RdapNameserverSearchActionTest
|
|||
createManyHosts(9);
|
||||
assertThat(generateActualJsonWithIp("5.5.5.1"))
|
||||
.isEqualTo(
|
||||
generateExpectedJson(
|
||||
"ip=5.5.5.1&cursor=MTctUk9JRA%3D%3D", "rdap_truncated_hosts.json"));
|
||||
loadJsonFile(
|
||||
"rdap_truncated_hosts.json", "QUERY", "ip=5.5.5.1&cursor=MTctUk9JRA%3D%3D"));
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
// When searching by address and not including deleted, we don't need to search for extra
|
||||
// matches.
|
||||
verifyMetrics(5);
|
||||
verifyMetrics(5, IncompletenessWarningType.TRUNCATED);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -16,9 +16,12 @@ package google.registry.rdap;
|
|||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.config.RdapNoticeDescriptor;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonElement;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
@ -28,6 +31,12 @@ import org.json.simple.JSONObject;
|
|||
|
||||
public class RdapTestHelper {
|
||||
|
||||
private static final Gson GSON = new GsonBuilder().create();
|
||||
|
||||
static JsonElement createJson(String... lines) {
|
||||
return GSON.fromJson(Joiner.on("\n").join(lines), JsonElement.class);
|
||||
}
|
||||
|
||||
enum ContactNoticeType {
|
||||
NONE,
|
||||
DOMAIN,
|
||||
|
@ -46,48 +55,13 @@ public class RdapTestHelper {
|
|||
}
|
||||
|
||||
static ImmutableList<ImmutableMap<String, Object>> createNotices(String linkBase) {
|
||||
return createNotices(linkBase, ContactNoticeType.NONE, null);
|
||||
return createNotices(linkBase, null);
|
||||
}
|
||||
|
||||
static ImmutableList<ImmutableMap<String, Object>> createNotices(
|
||||
String linkBase, ContactNoticeType contactNoticeType, @Nullable Object otherNotices) {
|
||||
String linkBase, @Nullable Object otherNotices) {
|
||||
ImmutableList.Builder<ImmutableMap<String, Object>> noticesBuilder =
|
||||
getBuilderWithOthersAdded(otherNotices);
|
||||
switch (contactNoticeType) {
|
||||
case DOMAIN:
|
||||
noticesBuilder.add(
|
||||
ImmutableMap.of(
|
||||
"title", "Contacts Hidden",
|
||||
"description",
|
||||
ImmutableList.of("Domain contacts are visible only to the owning registrar."),
|
||||
"type", "object truncated due to unexplainable reasons"));
|
||||
break;
|
||||
case CONTACT:
|
||||
noticesBuilder.add(
|
||||
ImmutableMap.of(
|
||||
"title",
|
||||
"Data Policy",
|
||||
"description",
|
||||
ImmutableList.of(
|
||||
"Some of the data in this object has been removed.",
|
||||
"Contact personal data is visible only to the owning registrar."),
|
||||
"type",
|
||||
"object truncated due to authorization",
|
||||
"links",
|
||||
ImmutableList.of(
|
||||
ImmutableMap.of(
|
||||
"value",
|
||||
"https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
|
||||
"rel",
|
||||
"alternate",
|
||||
"href",
|
||||
"https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication",
|
||||
"type",
|
||||
"text/html"))));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
noticesBuilder.add(
|
||||
ImmutableMap.of(
|
||||
"title", "RDAP Terms of Service",
|
||||
|
@ -142,28 +116,13 @@ public class RdapTestHelper {
|
|||
}
|
||||
|
||||
static void addDomainBoilerplateNotices(ImmutableMap.Builder<String, Object> builder) {
|
||||
addDomainBoilerplateNotices(builder, false, null);
|
||||
addDomainBoilerplateNotices(builder, null);
|
||||
}
|
||||
|
||||
static void addDomainBoilerplateNotices(
|
||||
ImmutableMap.Builder<String, Object> builder, @Nullable Object otherNotices) {
|
||||
addDomainBoilerplateNotices(builder, false, otherNotices);
|
||||
}
|
||||
|
||||
static void addDomainBoilerplateNotices(
|
||||
ImmutableMap.Builder<String, Object> builder,
|
||||
boolean addNoContactRemark,
|
||||
@Nullable Object otherNotices) {
|
||||
ImmutableList.Builder<ImmutableMap<String, Object>> noticesBuilder =
|
||||
getBuilderWithOthersAdded(otherNotices);
|
||||
if (addNoContactRemark) {
|
||||
noticesBuilder.add(
|
||||
ImmutableMap.of(
|
||||
"title", "Contacts Hidden",
|
||||
"description",
|
||||
ImmutableList.of("Domain contacts are visible only to the owning registrar."),
|
||||
"type", "object truncated due to unexplainable reasons"));
|
||||
}
|
||||
noticesBuilder.add(
|
||||
ImmutableMap.of(
|
||||
"description",
|
||||
|
@ -214,32 +173,8 @@ public class RdapTestHelper {
|
|||
|
||||
static RdapJsonFormatter getTestRdapJsonFormatter() {
|
||||
RdapJsonFormatter rdapJsonFormatter = new RdapJsonFormatter();
|
||||
rdapJsonFormatter.rdapTosPath = "/tos";
|
||||
rdapJsonFormatter.rdapHelpMap =
|
||||
ImmutableMap.of(
|
||||
"/",
|
||||
RdapNoticeDescriptor.builder()
|
||||
.setTitle("RDAP Help")
|
||||
.setDescription(
|
||||
ImmutableList.of(
|
||||
"domain/XXXX",
|
||||
"nameserver/XXXX",
|
||||
"entity/XXXX",
|
||||
"domains?name=XXXX",
|
||||
"domains?nsLdhName=XXXX",
|
||||
"domains?nsIp=XXXX",
|
||||
"nameservers?name=XXXX",
|
||||
"nameservers?ip=XXXX",
|
||||
"entities?fn=XXXX",
|
||||
"entities?handle=XXXX",
|
||||
"help/XXXX"))
|
||||
.setLinkValueSuffix("help/")
|
||||
.setLinkHrefUrlString("https://github.com/google/nomulus/blob/master/docs/rdap.md")
|
||||
.build(),
|
||||
"/tos",
|
||||
RdapNoticeDescriptor.builder()
|
||||
.setTitle("RDAP Terms of Service")
|
||||
.setDescription(
|
||||
rdapJsonFormatter.fullServletPath = "https://example.tld/rdap/";
|
||||
rdapJsonFormatter.rdapTos =
|
||||
ImmutableList.of(
|
||||
"By querying our Domain Database, you are agreeing to comply with these"
|
||||
+ " terms so please read them carefully.",
|
||||
|
@ -261,10 +196,8 @@ public class RdapTestHelper {
|
|||
+ " purposes of detecting and preventing misuse.",
|
||||
"We reserve the right to restrict or deny your access to the database if we"
|
||||
+ " suspect that you have failed to comply with these terms.",
|
||||
"We reserve the right to modify this agreement at any time."))
|
||||
.setLinkValueSuffix("help/tos")
|
||||
.setLinkHrefUrlString("https://www.registry.tld/about/rdap/tos.html")
|
||||
.build());
|
||||
"We reserve the right to modify this agreement at any time.");
|
||||
rdapJsonFormatter.rdapTosStaticUrl = "https://www.registry.tld/about/rdap/tos.html";
|
||||
return rdapJsonFormatter;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
{
|
||||
"rdapConformance": [
|
||||
"icann_rdap_response_profile_0"
|
||||
],
|
||||
"objectClassName" : "entity",
|
||||
"handle" : "%NAME%",
|
||||
"status" : ["active", "associated"],
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
{
|
||||
"rdapConformance": [
|
||||
"icann_rdap_response_profile_0"
|
||||
],
|
||||
"objectClassName" : "entity",
|
||||
"handle" : "%NAME%",
|
||||
"status" : ["active", "associated", "removed"],
|
||||
|
@ -21,5 +24,23 @@
|
|||
"eventAction": "last update of RDAP database",
|
||||
"eventDate": "2000-01-01T00:00:00.000Z"
|
||||
}
|
||||
],
|
||||
"remarks": [
|
||||
{
|
||||
"title": "Redacted for Privacy",
|
||||
"type": "object redacted due to authorization",
|
||||
"links": [
|
||||
{
|
||||
"type":"text\/html",
|
||||
"value": "https:\/\/github.com\/google\/nomulus\/blob\/master\/docs\/rdap.md#authentication",
|
||||
"href": "https:\/\/github.com\/google\/nomulus\/blob\/master\/docs\/rdap.md#authentication",
|
||||
"rel": "alternate"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
"Some of the data in this object has been removed.",
|
||||
"Contact personal data is visible only to the owning registrar."
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
{
|
||||
"rdapConformance": [
|
||||
"icann_rdap_response_profile_0"
|
||||
],
|
||||
"objectClassName" : "entity",
|
||||
"handle" : "%NAME%",
|
||||
"status" : ["%STATUS%"],
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
{
|
||||
"rdapConformance": [
|
||||
"icann_rdap_response_profile_0"
|
||||
],
|
||||
"objectClassName" : "entity",
|
||||
"handle" : "%NAME%",
|
||||
"status" : ["inactive"],
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
{
|
||||
"rdapConformance": [
|
||||
"icann_rdap_response_profile_0"
|
||||
],
|
||||
"objectClassName" : "entity",
|
||||
"handle" : "%NAME%",
|
||||
"status" : ["active", "removed"],
|
||||
|
@ -24,12 +27,12 @@
|
|||
],
|
||||
"remarks": [
|
||||
{
|
||||
"title": "Data Policy",
|
||||
"title": "Redacted for Privacy",
|
||||
"description": [
|
||||
"Some of the data in this object has been removed.",
|
||||
"Contact personal data is visible only to the owning registrar."
|
||||
],
|
||||
"type": "object truncated due to authorization",
|
||||
"type": "object redacted due to authorization",
|
||||
"links" :
|
||||
[
|
||||
{
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
{
|
||||
"rdapConformance": [
|
||||
"icann_rdap_response_profile_0"
|
||||
],
|
||||
"status": [
|
||||
"client delete prohibited",
|
||||
"client renew prohibited",
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
{
|
||||
"rdapConformance": [
|
||||
"icann_rdap_response_profile_0"
|
||||
],
|
||||
"status": [
|
||||
"client delete prohibited",
|
||||
"client renew prohibited",
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
{
|
||||
"rdapConformance": [
|
||||
"icann_rdap_response_profile_0"
|
||||
],
|
||||
"status": [
|
||||
"client delete prohibited",
|
||||
"client renew prohibited",
|
||||
|
|
|
@ -1,262 +0,0 @@
|
|||
{
|
||||
"objectClassName": "domain",
|
||||
"handle": "%HANDLE%",
|
||||
"ldhName": "%NAME%",
|
||||
"status": [
|
||||
"client delete prohibited",
|
||||
"client renew prohibited",
|
||||
"client transfer prohibited",
|
||||
"server update prohibited"
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"href": "https://example.tld/rdap/domain/%NAME%",
|
||||
"type": "application/rdap+json",
|
||||
"rel": "self",
|
||||
"value": "https://example.tld/rdap/domain/%NAME%"
|
||||
}
|
||||
],
|
||||
"events": [
|
||||
{
|
||||
"eventAction": "registration",
|
||||
"eventActor": "foo",
|
||||
"eventDate": "2000-01-01T00:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"eventAction": "expiration",
|
||||
"eventDate": "2110-10-08T00:44:59.000Z"
|
||||
},
|
||||
{
|
||||
"eventAction": "last update of RDAP database",
|
||||
"eventDate": "2000-01-01T00:00:00.000Z"
|
||||
}
|
||||
],
|
||||
"nameservers": [
|
||||
{
|
||||
"status": [
|
||||
"active",
|
||||
"associated"
|
||||
],
|
||||
"handle": "%NAMESERVER1ROID%",
|
||||
"links": [
|
||||
{
|
||||
"href": "https://example.tld/rdap/nameserver/%NAMESERVER1NAME%",
|
||||
"type": "application/rdap+json",
|
||||
"rel": "self",
|
||||
"value": "https://example.tld/rdap/nameserver/%NAMESERVER1NAME%"
|
||||
}
|
||||
],
|
||||
"ldhName": "%NAMESERVER1NAME%",
|
||||
"ipAddresses": {
|
||||
"v4": [
|
||||
"%NAMESERVER1ADDRESS%"
|
||||
]
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"eventAction": "registration",
|
||||
"eventActor": "foo",
|
||||
"eventDate": "1999-01-01T00:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"eventAction": "last update of RDAP database",
|
||||
"eventDate": "2000-01-01T00:00:00.000Z"
|
||||
}
|
||||
],
|
||||
"objectClassName": "nameserver",
|
||||
"entities": [
|
||||
{
|
||||
"objectClassName": "entity",
|
||||
"status": [ "active" ],
|
||||
"handle": "1",
|
||||
"roles": [ "registrar" ],
|
||||
"links": [
|
||||
{
|
||||
"href": "https://example.tld/rdap/entity/1",
|
||||
"type": "application/rdap+json",
|
||||
"rel": "self",
|
||||
"value": "https://example.tld/rdap/entity/1"
|
||||
}
|
||||
],
|
||||
"vcardArray" : [
|
||||
"vcard",
|
||||
[
|
||||
["version", {}, "text", "4.0"],
|
||||
["fn", {}, "text", "The Registrar"],
|
||||
[
|
||||
"adr",
|
||||
{},
|
||||
"text",
|
||||
[
|
||||
"",
|
||||
"",
|
||||
"123 Example Boulevard",
|
||||
"Williamsburg",
|
||||
"NY",
|
||||
"11211",
|
||||
"United States"
|
||||
]
|
||||
],
|
||||
["tel", {"type":["voice"]}, "uri", "tel:+1.2223334444"],
|
||||
["email", {}, "text", "the.registrar@example.com"]
|
||||
]
|
||||
],
|
||||
"publicIds" : [
|
||||
{
|
||||
"type": "IANA Registrar ID",
|
||||
"identifier":"1"
|
||||
}
|
||||
],
|
||||
"remarks": [
|
||||
{
|
||||
"title": "Incomplete Data",
|
||||
"description": [
|
||||
"Summary data only. For complete data, send a specific query for the object."
|
||||
],
|
||||
"type": "object truncated due to unexplainable reasons"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"status": [
|
||||
"active",
|
||||
"associated"
|
||||
],
|
||||
"handle": "%NAMESERVER2ROID%",
|
||||
"links": [
|
||||
{
|
||||
"href": "https://example.tld/rdap/nameserver/%NAMESERVER2NAME%",
|
||||
"type": "application/rdap+json",
|
||||
"rel": "self",
|
||||
"value": "https://example.tld/rdap/nameserver/%NAMESERVER2NAME%"
|
||||
}
|
||||
],
|
||||
"ldhName": "%NAMESERVER2NAME%",
|
||||
"ipAddresses": {
|
||||
"v6": [
|
||||
"%NAMESERVER2ADDRESS%"
|
||||
]
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"eventAction": "registration",
|
||||
"eventActor": "foo",
|
||||
"eventDate": "1998-01-01T00:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"eventAction": "last update of RDAP database",
|
||||
"eventDate": "2000-01-01T00:00:00.000Z"
|
||||
}
|
||||
],
|
||||
"objectClassName": "nameserver",
|
||||
"entities": [
|
||||
{
|
||||
"objectClassName": "entity",
|
||||
"status": [ "active" ],
|
||||
"handle": "1",
|
||||
"roles": [ "registrar" ],
|
||||
"links": [
|
||||
{
|
||||
"href": "https://example.tld/rdap/entity/1",
|
||||
"type": "application/rdap+json",
|
||||
"rel": "self",
|
||||
"value": "https://example.tld/rdap/entity/1"
|
||||
}
|
||||
],
|
||||
"vcardArray" : [
|
||||
"vcard",
|
||||
[
|
||||
["version", {}, "text", "4.0"],
|
||||
["fn", {}, "text", "The Registrar"],
|
||||
[
|
||||
"adr",
|
||||
{},
|
||||
"text",
|
||||
[
|
||||
"",
|
||||
"",
|
||||
"123 Example Boulevard",
|
||||
"Williamsburg",
|
||||
"NY",
|
||||
"11211",
|
||||
"United States"
|
||||
]
|
||||
],
|
||||
["tel", {"type":["voice"]}, "uri", "tel:+1.2223334444"],
|
||||
["email", {}, "text", "the.registrar@example.com"]
|
||||
]
|
||||
],
|
||||
"publicIds" : [
|
||||
{
|
||||
"type": "IANA Registrar ID",
|
||||
"identifier":"1"
|
||||
}
|
||||
],
|
||||
"remarks": [
|
||||
{
|
||||
"title": "Incomplete Data",
|
||||
"description": [
|
||||
"Summary data only. For complete data, send a specific query for the object."
|
||||
],
|
||||
"type": "object truncated due to unexplainable reasons"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"entities": [
|
||||
{
|
||||
"objectClassName" : "entity",
|
||||
"handle" : "1",
|
||||
"status" : ["active"],
|
||||
"roles" : ["registrar"],
|
||||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "https://example.tld/rdap/entity/1",
|
||||
"rel" : "self",
|
||||
"href" : "https://example.tld/rdap/entity/1",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
"publicIds" :
|
||||
[
|
||||
{
|
||||
"type" : "IANA Registrar ID",
|
||||
"identifier" : "1"
|
||||
}
|
||||
],
|
||||
"vcardArray" :
|
||||
[
|
||||
"vcard",
|
||||
[
|
||||
["version", {}, "text", "4.0"],
|
||||
["fn", {}, "text", "%REGISTRARNAME%"],
|
||||
["adr", {}, "text", [
|
||||
"",
|
||||
"",
|
||||
"123 Example Boulevard <script>",
|
||||
"Williamsburg <script>",
|
||||
"NY",
|
||||
"11211",
|
||||
"United States"]],
|
||||
["tel", {"type" : ["voice"]}, "uri", "tel:+1.2125551212"],
|
||||
["tel", {"type" : ["fax"]}, "uri", "tel:+1.2125551213"],
|
||||
["email", {}, "text", "contact-us@example.com"]
|
||||
]
|
||||
],
|
||||
"remarks": [
|
||||
{
|
||||
"title": "Incomplete Data",
|
||||
"description": [
|
||||
"Summary data only. For complete data, send a specific query for the object."
|
||||
],
|
||||
"type": "object truncated due to unexplainable reasons"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -2,6 +2,9 @@
|
|||
"objectClassName": "domain",
|
||||
"handle": "%HANDLE%",
|
||||
"ldhName": "%NAME%",
|
||||
"rdapConformance": [
|
||||
"icann_rdap_response_profile_0"
|
||||
],
|
||||
"status": [
|
||||
"client delete prohibited",
|
||||
"client renew prohibited",
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
{
|
||||
"rdapConformance": [
|
||||
"icann_rdap_response_profile_0"
|
||||
],
|
||||
"status": [
|
||||
"client delete prohibited",
|
||||
"client renew prohibited",
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
{
|
||||
"rdapConformance": [
|
||||
"icann_rdap_response_profile_0"
|
||||
],
|
||||
"objectClassName": "domain",
|
||||
"handle": "%HANDLE%",
|
||||
"ldhName": "%PUNYCODENAME%",
|
||||
|
|
36
javatests/google/registry/rdap/testdata/rdap_error.json
vendored
Normal file
36
javatests/google/registry/rdap/testdata/rdap_error.json
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"lang": "en",
|
||||
"errorCode": %CODE%,
|
||||
"title": "%TITLE%",
|
||||
"description": [
|
||||
"%DESCRIPTION%"
|
||||
],
|
||||
"rdapConformance": [
|
||||
"icann_rdap_response_profile_0"
|
||||
],
|
||||
"notices": [
|
||||
{
|
||||
"description": [
|
||||
"By querying our Domain Database, you are agreeing to comply with these terms so please read them carefully.",
|
||||
"Any information provided is 'as is' without any guarantee of accuracy.",
|
||||
"Please do not misuse the Domain Database. It is intended solely for query-based access.",
|
||||
"Don't use the Domain Database to allow, enable, or otherwise support the transmission of mass unsolicited, commercial advertising or solicitations.",
|
||||
"Don't access our Domain Database through the use of high volume, automated electronic processes that send queries or data to the systems of any ICANN-accredited registrar.",
|
||||
"You may only use the information contained in the Domain Database for lawful purposes.",
|
||||
"Do not compile, repackage, disseminate, or otherwise use the information contained in the Domain Database in its entirety, or in any substantial portion, without our prior written permission.",
|
||||
"We may retain certain details about queries to our Domain Database for the purposes of detecting and preventing misuse.",
|
||||
"We reserve the right to restrict or deny your access to the database if we suspect that you have failed to comply with these terms.",
|
||||
"We reserve the right to modify this agreement at any time."
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"href": "https://www.registry.tld/about/rdap/tos.html",
|
||||
"rel": "alternate",
|
||||
"type": "text/html",
|
||||
"value": "https://example.tld/rdap/help/tos"
|
||||
}
|
||||
],
|
||||
"title": "RDAP Terms of Service"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"lang": "en",
|
||||
"errorCode": 400,
|
||||
"title": "Bad Request",
|
||||
"description": [
|
||||
"%NAME%"
|
||||
],
|
||||
"rdapConformance": [
|
||||
"icann_rdap_response_profile_0"
|
||||
]
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"lang": "en",
|
||||
"errorCode": 404,
|
||||
"title": "Not Found",
|
||||
"description": [
|
||||
"%NAME%"
|
||||
],
|
||||
"rdapConformance": [
|
||||
"icann_rdap_response_profile_0"
|
||||
]
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"lang": "en",
|
||||
"errorCode": 422,
|
||||
"title": "Unprocessable Entity",
|
||||
"description": [
|
||||
"%NAME%"
|
||||
],
|
||||
"rdapConformance": [
|
||||
"icann_rdap_response_profile_0"
|
||||
]
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"lang": "en",
|
||||
"errorCode": 501,
|
||||
"title": "Not Implemented",
|
||||
"description": [
|
||||
"%NAME%"
|
||||
],
|
||||
"rdapConformance": [
|
||||
"icann_rdap_response_profile_0"
|
||||
]
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
{
|
||||
"key" : "value",
|
||||
"rdapConformance" : [ "icann_rdap_response_profile_0" ],
|
||||
"notices" : [ {
|
||||
"title" : "RDAP Terms of Service",
|
||||
"description" : [ "By querying our Domain Database, you are agreeing to comply with these terms so please read them carefully.", "Any information provided is 'as is' without any guarantee of accuracy.", "Please do not misuse the Domain Database. It is intended solely for query-based access.", "Don't use the Domain Database to allow, enable, or otherwise support the transmission of mass unsolicited, commercial advertising or solicitations.", "Don't access our Domain Database through the use of high volume, automated electronic processes that send queries or data to the systems of any ICANN-accredited registrar.", "You may only use the information contained in the Domain Database for lawful purposes.", "Do not compile, repackage, disseminate, or otherwise use the information contained in the Domain Database in its entirety, or in any substantial portion, without our prior written permission.", "We may retain certain details about queries to our Domain Database for the purposes of detecting and preventing misuse.", "We reserve the right to restrict or deny your access to the database if we suspect that you have failed to comply with these terms.", "We reserve the right to modify this agreement at any time." ],
|
||||
"links" : [ {
|
||||
"value" : "http://myserver.example.com/help/tos",
|
||||
"rel" : "alternate",
|
||||
"href" : "https://www.registry.tld/about/rdap/tos.html",
|
||||
"type" : "text/html"
|
||||
} ]
|
||||
} ]
|
||||
}
|
|
@ -21,7 +21,7 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "https://example.tld/rdap/help/%NAME%",
|
||||
"value" : "https://example.tld/rdap/help",
|
||||
"rel" : "alternate",
|
||||
"type" : "text/html",
|
||||
"href" : "https://github.com/google/nomulus/blob/master/docs/rdap.md"
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
{
|
||||
"rdapConformance": [
|
||||
"icann_rdap_response_profile_0"
|
||||
],
|
||||
"status": [
|
||||
"%STATUS%"
|
||||
],
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
{
|
||||
"rdapConformance": [
|
||||
"icann_rdap_response_profile_0"
|
||||
],
|
||||
"status": [
|
||||
"active"
|
||||
],
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
{
|
||||
"rdapConformance": [
|
||||
"icann_rdap_response_profile_0"
|
||||
],
|
||||
"status": [
|
||||
"active",
|
||||
"associated"
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
{
|
||||
"rdapConformance": [
|
||||
"icann_rdap_response_profile_0"
|
||||
],
|
||||
"status": [
|
||||
"active"
|
||||
],
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
{
|
||||
"rdapConformance": [
|
||||
"icann_rdap_response_profile_0"
|
||||
],
|
||||
"objectClassName" : "entity",
|
||||
"handle" : "%NAME%",
|
||||
"status" : ["%STATUS%"],
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
{
|
||||
"rdapConformance": [
|
||||
"icann_rdap_response_profile_0"
|
||||
],
|
||||
"objectClassName" : "entity",
|
||||
"handle" : "%NAME%",
|
||||
"status" : ["%STATUS%"],
|
||||
|
|
|
@ -337,7 +337,7 @@
|
|||
{
|
||||
"type" : "application/rdap+json",
|
||||
"rel" : "next",
|
||||
"href" : "https://example.tld/rdap/nameservers?%NAME%"
|
||||
"href" : "https://example.tld/rdap/nameservers?%QUERY%"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"key":"value","rdapConformance":["icann_rdap_response_profile_0"],"notices":[{"title":"RDAP Terms of Service","description":["By querying our Domain Database, you are agreeing to comply with these terms so please read them carefully.","Any information provided is 'as is' without any guarantee of accuracy.","Please do not misuse the Domain Database. It is intended solely for query-based access.","Don't use the Domain Database to allow, enable, or otherwise support the transmission of mass unsolicited, commercial advertising or solicitations.","Don't access our Domain Database through the use of high volume, automated electronic processes that send queries or data to the systems of any ICANN-accredited registrar.","You may only use the information contained in the Domain Database for lawful purposes.","Do not compile, repackage, disseminate, or otherwise use the information contained in the Domain Database in its entirety, or in any substantial portion, without our prior written permission.","We may retain certain details about queries to our Domain Database for the purposes of detecting and preventing misuse.","We reserve the right to restrict or deny your access to the database if we suspect that you have failed to comply with these terms.","We reserve the right to modify this agreement at any time."],"links":[{"value":"http:\/\/myserver.example.com\/help\/tos","rel":"alternate","href":"https:\/\/www.registry.tld\/about\/rdap\/tos.html","type":"text\/html"}]}]}
|
||||
{"key":"value","rdapConformance":["icann_rdap_response_profile_0"],"notices":[{"title":"RDAP Terms of Service","links":[{"href":"https:\/\/www.registry.tld\/about\/rdap\/tos.html","rel":"alternate","type":"text\/html","value":"http:\/\/myserver.example.com\/help\/tos"}],"description":["By querying our Domain Database, you are agreeing to comply with these terms so please read them carefully.","Any information provided is 'as is' without any guarantee of accuracy.","Please do not misuse the Domain Database. It is intended solely for query-based access.","Don't use the Domain Database to allow, enable, or otherwise support the transmission of mass unsolicited, commercial advertising or solicitations.","Don't access our Domain Database through the use of high volume, automated electronic processes that send queries or data to the systems of any ICANN-accredited registrar.","You may only use the information contained in the Domain Database for lawful purposes.","Do not compile, repackage, disseminate, or otherwise use the information contained in the Domain Database in its entirety, or in any substantial portion, without our prior written permission.","We may retain certain details about queries to our Domain Database for the purposes of detecting and preventing misuse.","We reserve the right to restrict or deny your access to the database if we suspect that you have failed to comply with these terms.","We reserve the right to modify this agreement at any time."]}]}
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/entity/4-ROID",
|
||||
"value" : "https://example.tld/rdap/entity/4-ROID",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/entity/4-ROID",
|
||||
"href" : "https://example.tld/rdap/entity/4-ROID",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/domain/cat.xn--q9jyb4c",
|
||||
"value" : "https://example.tld/rdap/domain/cat.xn--q9jyb4c",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/domain/cat.xn--q9jyb4c",
|
||||
"href" : "https://example.tld/rdap/domain/cat.xn--q9jyb4c",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
@ -54,9 +54,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/nameserver/ns1.cat.xn--q9jyb4c",
|
||||
"value" : "https://example.tld/rdap/nameserver/ns1.cat.xn--q9jyb4c",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/nameserver/ns1.cat.xn--q9jyb4c",
|
||||
"href" : "https://example.tld/rdap/nameserver/ns1.cat.xn--q9jyb4c",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
@ -84,9 +84,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/entity/1",
|
||||
"value" : "https://example.tld/rdap/entity/1",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/entity/1",
|
||||
"href" : "https://example.tld/rdap/entity/1",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
@ -137,9 +137,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/nameserver/ns2.cat.xn--q9jyb4c",
|
||||
"value" : "https://example.tld/rdap/nameserver/ns2.cat.xn--q9jyb4c",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/nameserver/ns2.cat.xn--q9jyb4c",
|
||||
"href" : "https://example.tld/rdap/nameserver/ns2.cat.xn--q9jyb4c",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
@ -167,9 +167,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/entity/1",
|
||||
"value" : "https://example.tld/rdap/entity/1",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/entity/1",
|
||||
"href" : "https://example.tld/rdap/entity/1",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
@ -222,9 +222,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/entity/4-ROID",
|
||||
"value" : "https://example.tld/rdap/entity/4-ROID",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/entity/4-ROID",
|
||||
"href" : "https://example.tld/rdap/entity/4-ROID",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
@ -271,9 +271,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/entity/6-ROID",
|
||||
"value" : "https://example.tld/rdap/entity/6-ROID",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/entity/6-ROID",
|
||||
"href" : "https://example.tld/rdap/entity/6-ROID",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
@ -320,9 +320,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/entity/2-ROID",
|
||||
"value" : "https://example.tld/rdap/entity/2-ROID",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/entity/2-ROID",
|
||||
"href" : "https://example.tld/rdap/entity/2-ROID",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
@ -345,7 +345,7 @@
|
|||
["fn", {}, "text", "(◕‿◕)"],
|
||||
["org", {}, "text", "GOOGLE INCORPORATED <script>"],
|
||||
["tel", {"type" : ["voice"]}, "uri", "tel:+1.2126660420"],
|
||||
["tel", {"type" : ["fax"]}, "uri", "tel:+1.2126660420"]
|
||||
["tel", {"type" : ["fax"]}, "uri", "tel:+1.2126660420"],
|
||||
["email", {}, "text", "lol@cat.みんな"]
|
||||
]
|
||||
]
|
||||
|
@ -358,9 +358,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/entity/1",
|
||||
"value" : "https://example.tld/rdap/entity/1",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/entity/1",
|
||||
"href" : "https://example.tld/rdap/entity/1",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/domain/cat.xn--q9jyb4c",
|
||||
"value" : "https://example.tld/rdap/domain/cat.xn--q9jyb4c",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/domain/cat.xn--q9jyb4c",
|
||||
"href" : "https://example.tld/rdap/domain/cat.xn--q9jyb4c",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
@ -54,9 +54,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/nameserver/ns1.cat.xn--q9jyb4c",
|
||||
"value" : "https://example.tld/rdap/nameserver/ns1.cat.xn--q9jyb4c",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/nameserver/ns1.cat.xn--q9jyb4c",
|
||||
"href" : "https://example.tld/rdap/nameserver/ns1.cat.xn--q9jyb4c",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
@ -84,9 +84,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/entity/1",
|
||||
"value" : "https://example.tld/rdap/entity/1",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/entity/1",
|
||||
"href" : "https://example.tld/rdap/entity/1",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
@ -137,9 +137,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/nameserver/ns2.cat.xn--q9jyb4c",
|
||||
"value" : "https://example.tld/rdap/nameserver/ns2.cat.xn--q9jyb4c",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/nameserver/ns2.cat.xn--q9jyb4c",
|
||||
"href" : "https://example.tld/rdap/nameserver/ns2.cat.xn--q9jyb4c",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
@ -167,9 +167,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/entity/1",
|
||||
"value" : "https://example.tld/rdap/entity/1",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/entity/1",
|
||||
"href" : "https://example.tld/rdap/entity/1",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
@ -221,9 +221,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/entity/1",
|
||||
"value" : "https://example.tld/rdap/entity/1",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/entity/1",
|
||||
"href" : "https://example.tld/rdap/entity/1",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/domain/fish.xn--q9jyb4c",
|
||||
"value" : "https://example.tld/rdap/domain/fish.xn--q9jyb4c",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/domain/fish.xn--q9jyb4c",
|
||||
"href" : "https://example.tld/rdap/domain/fish.xn--q9jyb4c",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
@ -45,9 +45,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/entity/4-ROID",
|
||||
"value" : "https://example.tld/rdap/entity/4-ROID",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/entity/4-ROID",
|
||||
"href" : "https://example.tld/rdap/entity/4-ROID",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
@ -94,9 +94,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/entity/6-ROID",
|
||||
"value" : "https://example.tld/rdap/entity/6-ROID",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/entity/6-ROID",
|
||||
"href" : "https://example.tld/rdap/entity/6-ROID",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
@ -143,9 +143,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/entity/2-ROID",
|
||||
"value" : "https://example.tld/rdap/entity/2-ROID",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/entity/2-ROID",
|
||||
"href" : "https://example.tld/rdap/entity/2-ROID",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
@ -181,9 +181,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/entity/1",
|
||||
"value" : "https://example.tld/rdap/entity/1",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/entity/1",
|
||||
"href" : "https://example.tld/rdap/entity/1",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/domain/cat.xn--q9jyb4c",
|
||||
"value" : "https://example.tld/rdap/domain/cat.xn--q9jyb4c",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/domain/cat.xn--q9jyb4c",
|
||||
"href" : "https://example.tld/rdap/domain/cat.xn--q9jyb4c",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
{
|
||||
"rdapConformance" :
|
||||
[
|
||||
"icann_rdap_response_profile_0"
|
||||
],
|
||||
"lang" : "en"
|
||||
"lang" : "en",
|
||||
"errorCode" : 400,
|
||||
"title" : "Invalid Domain Name",
|
||||
"description" :
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/nameserver/ns3.cat.xn--q9jyb4c",
|
||||
"value" : "https://example.tld/rdap/nameserver/ns3.cat.xn--q9jyb4c",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/nameserver/ns3.cat.xn--q9jyb4c",
|
||||
"href" : "https://example.tld/rdap/nameserver/ns3.cat.xn--q9jyb4c",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
@ -38,9 +38,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/entity/1",
|
||||
"value" : "https://example.tld/rdap/entity/1",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/entity/1",
|
||||
"href" : "https://example.tld/rdap/entity/1",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/nameserver/ns3.cat.xn--q9jyb4c",
|
||||
"value" : "https://example.tld/rdap/nameserver/ns3.cat.xn--q9jyb4c",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/nameserver/ns3.cat.xn--q9jyb4c",
|
||||
"href" : "https://example.tld/rdap/nameserver/ns3.cat.xn--q9jyb4c",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
@ -36,9 +36,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/entity/1",
|
||||
"value" : "https://example.tld/rdap/entity/1",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/entity/1",
|
||||
"href" : "https://example.tld/rdap/entity/1",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/nameserver/ns1.cat.xn--q9jyb4c",
|
||||
"value" : "https://example.tld/rdap/nameserver/ns1.cat.xn--q9jyb4c",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/nameserver/ns1.cat.xn--q9jyb4c",
|
||||
"href" : "https://example.tld/rdap/nameserver/ns1.cat.xn--q9jyb4c",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
@ -37,9 +37,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/entity/1",
|
||||
"value" : "https://example.tld/rdap/entity/1",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/entity/1",
|
||||
"href" : "https://example.tld/rdap/entity/1",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/nameserver/ns2.cat.xn--q9jyb4c",
|
||||
"value" : "https://example.tld/rdap/nameserver/ns2.cat.xn--q9jyb4c",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/nameserver/ns2.cat.xn--q9jyb4c",
|
||||
"href" : "https://example.tld/rdap/nameserver/ns2.cat.xn--q9jyb4c",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
@ -37,9 +37,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/entity/1",
|
||||
"value" : "https://example.tld/rdap/entity/1",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/entity/1",
|
||||
"href" : "https://example.tld/rdap/entity/1",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/nameserver/ns4.cat.xn--q9jyb4c",
|
||||
"value" : "https://example.tld/rdap/nameserver/ns4.cat.xn--q9jyb4c",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/nameserver/ns4.cat.xn--q9jyb4c",
|
||||
"href" : "https://example.tld/rdap/nameserver/ns4.cat.xn--q9jyb4c",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
@ -33,9 +33,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/entity/1",
|
||||
"value" : "https://example.tld/rdap/entity/1",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/entity/1",
|
||||
"href" : "https://example.tld/rdap/entity/1",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/nameserver/ns5.cat.xn--q9jyb4c",
|
||||
"value" : "https://example.tld/rdap/nameserver/ns5.cat.xn--q9jyb4c",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/nameserver/ns5.cat.xn--q9jyb4c",
|
||||
"href" : "https://example.tld/rdap/nameserver/ns5.cat.xn--q9jyb4c",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
@ -33,9 +33,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/entity/1",
|
||||
"value" : "https://example.tld/rdap/entity/1",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/entity/1",
|
||||
"href" : "https://example.tld/rdap/entity/1",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/nameserver/ns1.dog.xn--q9jyb4c",
|
||||
"value" : "https://example.tld/rdap/nameserver/ns1.dog.xn--q9jyb4c",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/nameserver/ns1.dog.xn--q9jyb4c",
|
||||
"href" : "https://example.tld/rdap/nameserver/ns1.dog.xn--q9jyb4c",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
@ -33,9 +33,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/entity/1",
|
||||
"value" : "https://example.tld/rdap/entity/1",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/entity/1",
|
||||
"href" : "https://example.tld/rdap/entity/1",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
|
|
@ -9,10 +9,10 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/help/index",
|
||||
"value" : "https://example.tld/rdap/help/index",
|
||||
"rel" : "alternate",
|
||||
"type" : "text/html",
|
||||
"href" : "http://myserver.example.com/about/rdap/index.html"
|
||||
"href" : "https://example.tld/rdap/about/rdap/index.html"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -9,10 +9,10 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/help/index",
|
||||
"value" : "https://example.tld/rdap/help/index",
|
||||
"rel" : "self",
|
||||
"type" : "application/rdap+json",
|
||||
"href" : "http://myserver.example.com/help/index",
|
||||
"href" : "https://example.tld/rdap/help/index"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/entity/2-ROID",
|
||||
"value" : "https://example.tld/rdap/entity/2-ROID",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/entity/2-ROID",
|
||||
"href" : "https://example.tld/rdap/entity/2-ROID",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/entity/2-ROID",
|
||||
"value" : "https://example.tld/rdap/entity/2-ROID",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/entity/2-ROID",
|
||||
"href" : "https://example.tld/rdap/entity/2-ROID",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
@ -25,12 +25,12 @@
|
|||
],
|
||||
"remarks": [
|
||||
{
|
||||
"title": "Data Policy",
|
||||
"title": "Redacted for Privacy",
|
||||
"description": [
|
||||
"Some of the data in this object has been removed.",
|
||||
"Contact personal data is visible only to the owning registrar."
|
||||
],
|
||||
"type": "object truncated due to authorization",
|
||||
"type": "object redacted due to authorization",
|
||||
"links" :
|
||||
[
|
||||
{
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/entity/2-ROID",
|
||||
"value" : "https://example.tld/rdap/entity/2-ROID",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/entity/2-ROID",
|
||||
"href" : "https://example.tld/rdap/entity/2-ROID",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/entity/2-ROID",
|
||||
"value" : "https://example.tld/rdap/entity/2-ROID",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/entity/2-ROID",
|
||||
"href" : "https://example.tld/rdap/entity/2-ROID",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
@ -33,12 +33,12 @@
|
|||
"type": "object truncated due to unexplainable reasons"
|
||||
},
|
||||
{
|
||||
"title": "Data Policy",
|
||||
"title": "Redacted for Privacy",
|
||||
"description": [
|
||||
"Some of the data in this object has been removed.",
|
||||
"Contact personal data is visible only to the owning registrar."
|
||||
],
|
||||
"type": "object truncated due to authorization",
|
||||
"type": "object redacted due to authorization",
|
||||
"links" :
|
||||
[
|
||||
{
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/entity/1",
|
||||
"value" : "https://example.tld/rdap/entity/1",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/entity/1",
|
||||
"href" : "https://example.tld/rdap/entity/1",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
@ -68,7 +68,7 @@
|
|||
["tel", {"type" : ["voice"]}, "uri", "tel:+1.2125551215"],
|
||||
["email", {}, "text", "janedoe@example.com"]
|
||||
]
|
||||
],
|
||||
]
|
||||
},
|
||||
{
|
||||
"objectClassName" : "entity",
|
||||
|
@ -83,7 +83,7 @@
|
|||
["tel", {"type" : ["fax"]}, "uri", "tel:+1.2125551213"],
|
||||
["email", {}, "text", "johndoe@example.com"]
|
||||
]
|
||||
],
|
||||
]
|
||||
},
|
||||
{
|
||||
"objectClassName" : "entity",
|
||||
|
@ -99,7 +99,7 @@
|
|||
["tel", {"type" : ["fax"]}, "uri", "tel:+1.2125551218"],
|
||||
["email", {}, "text", "playdoe@example.com"]
|
||||
]
|
||||
],
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/entity/1",
|
||||
"value" : "https://example.tld/rdap/entity/1",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/entity/1",
|
||||
"href" : "https://example.tld/rdap/entity/1",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/entity/6-ROID",
|
||||
"value" : "https://example.tld/rdap/entity/6-ROID",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/entity/6-ROID",
|
||||
"href" : "https://example.tld/rdap/entity/6-ROID",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/entity/6-ROID",
|
||||
"value" : "https://example.tld/rdap/entity/6-ROID",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/entity/6-ROID",
|
||||
"href" : "https://example.tld/rdap/entity/6-ROID",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/help/tos",
|
||||
"value" : "https://example.tld/rdap/help/tos",
|
||||
"rel" : "alternate",
|
||||
"href" : "https://www.registry.tld/about/rdap/tos.html",
|
||||
"type" : "text/html"
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/help/tos",
|
||||
"value" : "https://example.tld/rdap/help/tos",
|
||||
"rel" : "alternate",
|
||||
"href" : "https://www.registry.tld/about/rdap/tos.html",
|
||||
"type" : "text/html"
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
"links" :
|
||||
[
|
||||
{
|
||||
"value" : "http://myserver.example.com/entity/8-ROID",
|
||||
"value" : "https://example.tld/rdap/entity/8-ROID",
|
||||
"rel" : "self",
|
||||
"href" : "http://myserver.example.com/entity/8-ROID",
|
||||
"href" : "https://example.tld/rdap/entity/8-ROID",
|
||||
"type" : "application/rdap+json"
|
||||
}
|
||||
],
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue