From e8eabe01cf407e647b2541db459575162ba27df4 Mon Sep 17 00:00:00 2001 From: mountford Date: Tue, 6 Jun 2017 13:48:43 -0700 Subject: [PATCH] Update WHOIS output format to reflect CL&D and PDT requirements PDT testing revealed a couple ways in which our WHOIS output was non-compliant. First, the Consistent Labeling & Display policy dictates that the contact IDs must be ROIDs. See rule 11 in https://www.icann.org/resources/pages/rdds-labeling-policy-2017-02-01-en. Second, PDT tests expect that a WHOIS response will treat missing values either by omitting the line entirely, or by including the line with a blank value, but not both. So this is legal: Phone Number: 123-4567 Phone Number Ext: Fax Number: 123-4568 Fax Number Ext: and this is legal: Phone Number: 123-4567 Fax Number: 123-4568 but this is not: Phone Number: 123-4567 Phone Number Ext: Fax Number: 123-4568 In the last example, one extension line is present with a blank value, while the other extension line is omitted. We cannot do both. Therefore, we should update our code to omit lines with no value. Since we can't guarantee that we will always emit all lines that the parse might expect to see, it is safe to use the policy of omitting lines with no value. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158184150 --- .../registry/whois/DomainWhoisResponse.java | 26 +++++++++++-------- .../registry/whois/WhoisResponseImpl.java | 26 ++++++++++++++----- .../registry/whois/testdata/whois_domain.txt | 7 +++-- .../whois/testdata/whois_server_domain.txt | 12 +++------ .../testdata/whois_server_idn_punycode.txt | 12 +++------ .../whois/testdata/whois_server_idn_utf8.txt | 12 +++------ 6 files changed, 47 insertions(+), 48 deletions(-) diff --git a/java/google/registry/whois/DomainWhoisResponse.java b/java/google/registry/whois/DomainWhoisResponse.java index 08e9a6736..a18b495c3 100644 --- a/java/google/registry/whois/DomainWhoisResponse.java +++ b/java/google/registry/whois/DomainWhoisResponse.java @@ -23,6 +23,7 @@ import static google.registry.xml.UtcDateTimeAdapter.getFormattedString; import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.googlecode.objectify.Key; @@ -88,7 +89,7 @@ final class DomainWhoisResponse extends WhoisResponseImpl { .emitField("Registry Domain ID", domain.getRepoId()) .emitField("Registrar WHOIS Server", registrar.getWhoisServer()) .emitField("Registrar URL", registrar.getReferralUrl()) - .emitField("Updated Date", getFormattedString(domain.getLastEppUpdateTime())) + .emitFieldIfDefined("Updated Date", getFormattedString(domain.getLastEppUpdateTime())) .emitField("Creation Date", getFormattedString(domain.getCreationTime())) .emitField( "Registry Expiry Date", getFormattedString(domain.getRegistrationExpirationTime())) @@ -98,10 +99,10 @@ final class DomainWhoisResponse extends WhoisResponseImpl { Objects.toString(registrar.getIanaIdentifier(), "")) // Email address is a required field for registrar contacts. Therefore as long as there // is an abuse contact, we can get an email address from it. - .emitField( + .emitFieldIfDefined( "Registrar Abuse Contact Email", abuseContact.isPresent() ? abuseContact.get().getEmailAddress() : null) - .emitField( + .emitFieldIfDefined( "Registrar Abuse Contact Phone", abuseContact.isPresent() ? abuseContact.get().getPhoneNumber() : null) .emitStatusValues(domain.getStatusValues(), domain.getGracePeriods()) @@ -144,10 +145,12 @@ final class DomainWhoisResponse extends WhoisResponseImpl { class DomainEmitter extends Emitter { DomainEmitter emitPhone( String contactType, String title, @Nullable ContactPhoneNumber phoneNumber) { - return emitField( - contactType, title, phoneNumber != null ? phoneNumber.getPhoneNumber() : null) - .emitField( - contactType, title, "Ext", phoneNumber != null ? phoneNumber.getExtension() : null); + if (phoneNumber == null) { + return this; + } + return emitFieldIfDefined(ImmutableList.of(contactType, title), phoneNumber.getPhoneNumber()) + .emitFieldIfDefined( + ImmutableList.of(contactType, title, "Ext"), phoneNumber.getExtension()); } /** Emit the contact entry of the given type. */ @@ -167,19 +170,20 @@ final class DomainWhoisResponse extends WhoisResponseImpl { domain.getFullyQualifiedDomainName(), contact); return this; } - emitField("Registry", contactType, "ID", contactResource.getContactId()); + // ICANN Consistent Labeling & Display policy requires that this be the ROID. + emitField(ImmutableList.of("Registry", contactType, "ID"), contactResource.getRepoId()); PostalInfo postalInfo = chooseByUnicodePreference( preferUnicode, contactResource.getLocalizedPostalInfo(), contactResource.getInternationalizedPostalInfo()); if (postalInfo != null) { - emitField(contactType, "Name", postalInfo.getName()); - emitField(contactType, "Organization", postalInfo.getOrg()); + emitFieldIfDefined(ImmutableList.of(contactType, "Name"), postalInfo.getName()); + emitFieldIfDefined(ImmutableList.of(contactType, "Organization"), postalInfo.getOrg()); emitAddress(contactType, postalInfo.getAddress()); } return emitPhone(contactType, "Phone", contactResource.getVoiceNumber()) .emitPhone(contactType, "Fax", contactResource.getFaxNumber()) - .emitField(contactType, "Email", contactResource.getEmailAddress()); + .emitField(ImmutableList.of(contactType, "Email"), contactResource.getEmailAddress()); } /** Emits status values and grace periods as a set, in the AWIP format. */ diff --git a/java/google/registry/whois/WhoisResponseImpl.java b/java/google/registry/whois/WhoisResponseImpl.java index 917fbc6e2..153197d9c 100644 --- a/java/google/registry/whois/WhoisResponseImpl.java +++ b/java/google/registry/whois/WhoisResponseImpl.java @@ -22,12 +22,10 @@ import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.base.Optional; import com.google.common.collect.FluentIterable; -import com.google.common.collect.Iterables; import com.google.common.collect.Ordering; import google.registry.model.eppcommon.Address; import google.registry.util.Idn; import google.registry.xml.UtcDateTimeAdapter; -import java.util.Arrays; import java.util.List; import java.util.Set; import javax.annotation.Nullable; @@ -109,6 +107,16 @@ abstract class WhoisResponseImpl implements WhoisResponse { return thisCastToDerived(); } + /** Emit the field name and value followed by a newline, but only if a value exists. */ + E emitFieldIfDefined(String name, @Nullable String value) { + if (isNullOrEmpty(value)) { + return thisCastToDerived(); + } + stringBuilder.append(cleanse(name)).append(':'); + stringBuilder.append(' ').append(cleanse(value)); + return emitNewline(); + } + /** Emit the field name and value followed by a newline. */ E emitField(String name, @Nullable String value) { stringBuilder.append(cleanse(name)).append(':'); @@ -118,11 +126,17 @@ abstract class WhoisResponseImpl implements WhoisResponse { return emitNewline(); } + /** Emit a multi-part field name and value followed by a newline, but only if a value exists. */ + E emitFieldIfDefined(List nameParts, String value) { + if (isNullOrEmpty(value)) { + return thisCastToDerived(); + } + return emitField(nameParts, value); + } + /** Emit a multi-part field name and value followed by a newline. */ - E emitField(String... namePartsAndValue) { - List parts = Arrays.asList(namePartsAndValue); - return emitField( - Joiner.on(' ').join(parts.subList(0, parts.size() - 1)), Iterables.getLast(parts)); + E emitField(List nameParts, String value) { + return emitField(Joiner.on(' ').join(nameParts), value); } /** Emit a contact address. */ diff --git a/javatests/google/registry/whois/testdata/whois_domain.txt b/javatests/google/registry/whois/testdata/whois_domain.txt index e1e4109d2..c9f29be5a 100644 --- a/javatests/google/registry/whois/testdata/whois_domain.txt +++ b/javatests/google/registry/whois/testdata/whois_domain.txt @@ -15,7 +15,7 @@ Domain Status: clientRenewProhibited https://icann.org/epp#clientRenewProhibited Domain Status: clientTransferProhibited https://icann.org/epp#clientTransferProhibited Domain Status: serverUpdateProhibited https://icann.org/epp#serverUpdateProhibited Domain Status: transferPeriod https://icann.org/epp#transferPeriod -Registry Registrant ID: 5372808-ERL +Registry Registrant ID: 4-TLD Registrant Name: EXAMPLE REGISTRANT Registrant Organization: EXAMPLE ORGANIZATION Registrant Street: 123 EXAMPLE STREET @@ -28,7 +28,7 @@ Registrant Phone Ext: 1234 Registrant Fax: +1.5555551213 Registrant Fax Ext: 4321 Registrant Email: EMAIL@EXAMPLE.tld -Registry Admin ID: 5372809-ERL +Registry Admin ID: 5-TLD Admin Name: EXAMPLE REGISTRANT ADMINISTRATIVE Admin Organization: EXAMPLE REGISTRANT ORGANIZATION Admin Street: 123 EXAMPLE STREET @@ -39,9 +39,8 @@ Admin Country: EX Admin Phone: +1.5555551212 Admin Phone Ext: 1234 Admin Fax: +1.5555551213 -Admin Fax Ext: Admin Email: EMAIL@EXAMPLE.tld -Registry Tech ID: 5372811-ERL +Registry Tech ID: 6-TLD Tech Name: EXAMPLE REGISTRAR TECHNICAL Tech Organization: EXAMPLE REGISTRAR LLC Tech Street: 123 EXAMPLE STREET diff --git a/javatests/google/registry/whois/testdata/whois_server_domain.txt b/javatests/google/registry/whois/testdata/whois_server_domain.txt index 658251b47..1f8f5b9b5 100644 --- a/javatests/google/registry/whois/testdata/whois_server_domain.txt +++ b/javatests/google/registry/whois/testdata/whois_server_domain.txt @@ -13,7 +13,7 @@ Domain Status: clientDeleteProhibited https://icann.org/epp#clientDeleteProhibit Domain Status: clientRenewProhibited https://icann.org/epp#clientRenewProhibited Domain Status: clientTransferProhibited https://icann.org/epp#clientTransferProhibited Domain Status: serverUpdateProhibited https://icann.org/epp#serverUpdateProhibited -Registry Registrant ID: 5372808-ERL +Registry Registrant ID: 4-ROID Registrant Name: Goblin Market Registrant Organization: GOOGLE INCORPORATED <script> Registrant Street: 123 Example Boulevard <script> @@ -22,11 +22,9 @@ Registrant State/Province: BM Registrant Postal Code: 31337 Registrant Country: US Registrant Phone: +1.2126660420 -Registrant Phone Ext: Registrant Fax: +1.2126660420 -Registrant Fax Ext: Registrant Email: lol@cat.lol -Registry Admin ID: 5372808-IRL +Registry Admin ID: 5-ROID Admin Name: Santa Claus Admin Organization: GOOGLE INCORPORATED <script> Admin Street: 123 Example Boulevard <script> @@ -35,11 +33,9 @@ Admin State/Province: BM Admin Postal Code: 31337 Admin Country: US Admin Phone: +1.2126660420 -Admin Phone Ext: Admin Fax: +1.2126660420 -Admin Fax Ext: Admin Email: BOFH@cat.lol -Registry Tech ID: 5372808-TRL +Registry Tech ID: 6-ROID Tech Name: The Raven Tech Organization: GOOGLE INCORPORATED <script> Tech Street: 123 Example Boulevard <script> @@ -48,9 +44,7 @@ Tech State/Province: BM Tech Postal Code: 31337 Tech Country: US Tech Phone: +1.2126660420 -Tech Phone Ext: Tech Fax: +1.2126660420 -Tech Fax Ext: Tech Email: bog@cat.lol Name Server: ns1.cat.lol Name Server: ns2.cat.lol diff --git a/javatests/google/registry/whois/testdata/whois_server_idn_punycode.txt b/javatests/google/registry/whois/testdata/whois_server_idn_punycode.txt index 040024cc7..29b4cf955 100644 --- a/javatests/google/registry/whois/testdata/whois_server_idn_punycode.txt +++ b/javatests/google/registry/whois/testdata/whois_server_idn_punycode.txt @@ -13,7 +13,7 @@ Domain Status: clientDeleteProhibited https://icann.org/epp#clientDeleteProhibit Domain Status: clientRenewProhibited https://icann.org/epp#clientRenewProhibited Domain Status: clientTransferProhibited https://icann.org/epp#clientTransferProhibited Domain Status: serverUpdateProhibited https://icann.org/epp#serverUpdateProhibited -Registry Registrant ID: 5372808-ERL +Registry Registrant ID: 4-ROID Registrant Name: (◕‿◕) Registrant Organization: GOOGLE INCORPORATED <script> Registrant Street: 123 Example Boulevard <script> @@ -22,11 +22,9 @@ Registrant State/Province: BM Registrant Postal Code: 31337 Registrant Country: US Registrant Phone: +1.2126660420 -Registrant Phone Ext: Registrant Fax: +1.2126660420 -Registrant Fax Ext: Registrant Email: lol@cat.みんな -Registry Admin ID: 5372808-IRL +Registry Admin ID: 5-ROID Admin Name: Santa Claus Admin Organization: GOOGLE INCORPORATED <script> Admin Street: 123 Example Boulevard <script> @@ -35,11 +33,9 @@ Admin State/Province: BM Admin Postal Code: 31337 Admin Country: US Admin Phone: +1.2126660420 -Admin Phone Ext: Admin Fax: +1.2126660420 -Admin Fax Ext: Admin Email: BOFH@cat.みんな -Registry Tech ID: 5372808-TRL +Registry Tech ID: 6-ROID Tech Name: The Raven Tech Organization: GOOGLE INCORPORATED <script> Tech Street: 123 Example Boulevard <script> @@ -48,9 +44,7 @@ Tech State/Province: BM Tech Postal Code: 31337 Tech Country: US Tech Phone: +1.2126660420 -Tech Phone Ext: Tech Fax: +1.2126660420 -Tech Fax Ext: Tech Email: bog@cat.みんな Name Server: ns1.cat.xn--q9jyb4c Name Server: ns2.cat.xn--q9jyb4c diff --git a/javatests/google/registry/whois/testdata/whois_server_idn_utf8.txt b/javatests/google/registry/whois/testdata/whois_server_idn_utf8.txt index 79e0841ab..4107b6f72 100644 --- a/javatests/google/registry/whois/testdata/whois_server_idn_utf8.txt +++ b/javatests/google/registry/whois/testdata/whois_server_idn_utf8.txt @@ -13,7 +13,7 @@ Domain Status: clientDeleteProhibited https://icann.org/epp#clientDeleteProhibit Domain Status: clientRenewProhibited https://icann.org/epp#clientRenewProhibited Domain Status: clientTransferProhibited https://icann.org/epp#clientTransferProhibited Domain Status: serverUpdateProhibited https://icann.org/epp#serverUpdateProhibited -Registry Registrant ID: 5372808-ERL +Registry Registrant ID: 4-ROID Registrant Name: (◕‿◕) Registrant Organization: GOOGLE INCORPORATED <script> Registrant Street: 123 Example Boulevard <script> @@ -22,11 +22,9 @@ Registrant State/Province: BM Registrant Postal Code: 31337 Registrant Country: US Registrant Phone: +1.2126660420 -Registrant Phone Ext: Registrant Fax: +1.2126660420 -Registrant Fax Ext: Registrant Email: lol@cat.みんな -Registry Admin ID: 5372808-IRL +Registry Admin ID: 5-ROID Admin Name: Santa Claus Admin Organization: GOOGLE INCORPORATED <script> Admin Street: 123 Example Boulevard <script> @@ -35,11 +33,9 @@ Admin State/Province: BM Admin Postal Code: 31337 Admin Country: US Admin Phone: +1.2126660420 -Admin Phone Ext: Admin Fax: +1.2126660420 -Admin Fax Ext: Admin Email: BOFH@cat.みんな -Registry Tech ID: 5372808-TRL +Registry Tech ID: 6-ROID Tech Name: The Raven Tech Organization: GOOGLE INCORPORATED <script> Tech Street: 123 Example Boulevard <script> @@ -48,9 +44,7 @@ Tech State/Province: BM Tech Postal Code: 31337 Tech Country: US Tech Phone: +1.2126660420 -Tech Phone Ext: Tech Fax: +1.2126660420 -Tech Fax Ext: Tech Email: bog@cat.みんな Name Server: ns1.cat.みんな Name Server: ns2.cat.みんな