Refactor EppXmlTransformer to be in the model/ package

This will allow us to perform the OT&E history verification
in the model/ package as well so that it can be used both
by both the UI and the command line tool.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=225007167
This commit is contained in:
jianglai 2018-12-11 08:25:20 -08:00
parent f58211402a
commit 0a44ef0dca
27 changed files with 257 additions and 240 deletions

View file

@ -17,8 +17,8 @@ package google.registry.flows;
import static com.google.common.base.Strings.nullToEmpty; import static com.google.common.base.Strings.nullToEmpty;
import static com.google.common.flogger.LazyArgs.lazy; import static com.google.common.flogger.LazyArgs.lazy;
import static com.google.common.io.BaseEncoding.base64; import static com.google.common.io.BaseEncoding.base64;
import static google.registry.flows.EppXmlTransformer.unmarshal;
import static google.registry.flows.FlowReporter.extractTlds; import static google.registry.flows.FlowReporter.extractTlds;
import static google.registry.flows.FlowUtils.unmarshalEpp;
import static java.nio.charset.StandardCharsets.UTF_8; import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
@ -65,7 +65,7 @@ public final class EppController {
try { try {
EppInput eppInput; EppInput eppInput;
try { try {
eppInput = unmarshal(EppInput.class, inputXmlBytes); eppInput = unmarshalEpp(EppInput.class, inputXmlBytes);
} catch (EppException e) { } catch (EppException e) {
// Log the unmarshalling error, with the raw bytes (in base64) to help with debugging. // Log the unmarshalling error, with the raw bytes (in base64) to help with debugging.
logger.atInfo().withCause(e).log( logger.atInfo().withCause(e).log(

View file

@ -14,7 +14,7 @@
package google.registry.flows; package google.registry.flows;
import static google.registry.flows.EppXmlTransformer.marshalWithLenientRetry; import static google.registry.flows.FlowUtils.marshalWithLenientRetry;
import static google.registry.model.eppoutput.Result.Code.SUCCESS_AND_CLOSE; import static google.registry.model.eppoutput.Result.Code.SUCCESS_AND_CLOSE;
import static google.registry.xml.XmlTransformer.prettyPrint; import static google.registry.xml.XmlTransformer.prettyPrint;
import static java.nio.charset.StandardCharsets.UTF_8; import static java.nio.charset.StandardCharsets.UTF_8;

View file

@ -1,179 +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.flows;
import static com.google.common.base.Preconditions.checkState;
import static google.registry.xml.ValidationMode.LENIENT;
import static google.registry.xml.ValidationMode.STRICT;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.flogger.FluentLogger;
import google.registry.flows.EppException.ParameterValueRangeErrorException;
import google.registry.flows.EppException.ParameterValueSyntaxErrorException;
import google.registry.flows.EppException.SyntaxErrorException;
import google.registry.flows.EppException.UnimplementedProtocolVersionException;
import google.registry.model.EppResourceUtils.InvalidRepoIdException;
import google.registry.model.ImmutableObject;
import google.registry.model.eppinput.EppInput;
import google.registry.model.eppinput.EppInput.WrongProtocolVersionException;
import google.registry.model.eppoutput.EppOutput;
import google.registry.model.host.InetAddressAdapter.IpVersionMismatchException;
import google.registry.model.translators.CurrencyUnitAdapter.UnknownCurrencyException;
import google.registry.xml.ValidationMode;
import google.registry.xml.XmlException;
import google.registry.xml.XmlTransformer;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.List;
/** {@link XmlTransformer} for marshalling to and from the Epp model classes. */
public class EppXmlTransformer {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
// Hardcoded XML schemas, ordered with respect to dependency.
private static final ImmutableList<String> SCHEMAS = ImmutableList.of(
"eppcom.xsd",
"epp.xsd",
"contact.xsd",
"host.xsd",
"domain.xsd",
"rgp.xsd",
"secdns.xsd",
"fee06.xsd",
"fee11.xsd",
"fee12.xsd",
"metadata.xsd",
"mark.xsd",
"dsig.xsd",
"smd.xsd",
"launch.xsd",
"allocate.xsd",
"superuser.xsd",
"allocationToken-1.0.xsd");
private static final XmlTransformer INPUT_TRANSFORMER =
new XmlTransformer(SCHEMAS, EppInput.class);
private static final XmlTransformer OUTPUT_TRANSFORMER =
new XmlTransformer(SCHEMAS, EppOutput.class);
public static void validateOutput(String xml) throws XmlException {
OUTPUT_TRANSFORMER.validate(xml);
}
/**
* Unmarshal bytes into Epp classes.
*
* @param clazz type to return, specified as a param to enforce typesafe generics
* @see <a href="https://errorprone.info/bugpattern/TypeParameterUnusedInFormals">TypeParameterUnusedInFormals</a>
*/
public static <T> T unmarshal(Class<T> clazz, byte[] bytes) throws EppException {
try {
return INPUT_TRANSFORMER.unmarshal(clazz, new ByteArrayInputStream(bytes));
} catch (XmlException e) {
// If this XmlException is wrapping a known type find it. If not, it's a syntax error.
List<Throwable> causalChain = Throwables.getCausalChain(e);
if (causalChain.stream().anyMatch(IpVersionMismatchException.class::isInstance)) {
throw new IpAddressVersionMismatchException();
}
if (causalChain.stream().anyMatch(WrongProtocolVersionException.class::isInstance)) {
throw new UnimplementedProtocolVersionException();
}
if (causalChain.stream().anyMatch(InvalidRepoIdException.class::isInstance)) {
throw new InvalidRepoIdEppException();
}
if (causalChain.stream().anyMatch(UnknownCurrencyException.class::isInstance)) {
throw new UnknownCurrencyEppException();
}
throw new GenericSyntaxErrorException(e.getMessage());
}
}
private static byte[] marshal(
XmlTransformer transformer,
ImmutableObject root,
ValidationMode validation) throws XmlException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
transformer.marshal(root, byteArrayOutputStream, UTF_8, validation);
return byteArrayOutputStream.toByteArray();
}
public static byte[] marshal(EppOutput root, ValidationMode validation) throws XmlException {
return marshal(OUTPUT_TRANSFORMER, root, validation);
}
public static byte[] marshalWithLenientRetry(EppOutput eppOutput) {
checkState(eppOutput != null);
// We need to marshal to a string instead of writing the response directly to the servlet's
// response writer, so that partial results don't get written on failure.
try {
return EppXmlTransformer.marshal(eppOutput, STRICT);
} catch (XmlException e) {
// We failed to marshal with validation. This is very bad, but we can potentially still send
// back slightly invalid xml, so try again without validation.
try {
byte[] lenient = EppXmlTransformer.marshal(eppOutput, LENIENT);
// Marshaling worked even though the results didn't validate against the schema.
logger.atSevere().withCause(e).log(
"Result marshaled but did not validate: %s", new String(lenient, UTF_8));
return lenient;
} catch (XmlException e2) {
throw new RuntimeException(e2); // Failing to marshal at all is not recoverable.
}
}
}
@VisibleForTesting
public static byte[] marshalInput(EppInput root, ValidationMode validation) throws XmlException {
return marshal(INPUT_TRANSFORMER, root, validation);
}
@VisibleForTesting
public static void validateInput(String xml) throws XmlException {
INPUT_TRANSFORMER.validate(xml);
}
/** IP address version mismatch. */
public static class IpAddressVersionMismatchException extends ParameterValueRangeErrorException {
public IpAddressVersionMismatchException() {
super("IP adddress version mismatch");
}
}
/** Invalid format for repository id. */
public static class InvalidRepoIdEppException extends ParameterValueSyntaxErrorException {
public InvalidRepoIdEppException() {
super("Invalid format for repository id");
}
}
/** Unknown currency. */
static class UnknownCurrencyEppException extends ParameterValueRangeErrorException {
public UnknownCurrencyEppException() {
super("Unknown currency.");
}
}
/** Generic syntax error that can be thrown by any flow. */
static class GenericSyntaxErrorException extends SyntaxErrorException {
public GenericSyntaxErrorException(String message) {
super(message);
}
}
}

View file

@ -14,14 +14,32 @@
package google.registry.flows; package google.registry.flows;
import static com.google.common.base.Preconditions.checkState;
import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.xml.ValidationMode.LENIENT;
import static google.registry.xml.ValidationMode.STRICT;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.base.Throwables;
import com.google.common.flogger.FluentLogger;
import google.registry.flows.EppException.CommandUseErrorException; import google.registry.flows.EppException.CommandUseErrorException;
import google.registry.flows.EppException.ParameterValueRangeErrorException;
import google.registry.flows.EppException.SyntaxErrorException;
import google.registry.flows.EppException.UnimplementedProtocolVersionException;
import google.registry.flows.custom.EntityChanges; import google.registry.flows.custom.EntityChanges;
import google.registry.model.eppcommon.EppXmlTransformer;
import google.registry.model.eppinput.EppInput.WrongProtocolVersionException;
import google.registry.model.eppoutput.EppOutput;
import google.registry.model.host.InetAddressAdapter.IpVersionMismatchException;
import google.registry.model.translators.CurrencyUnitAdapter.UnknownCurrencyException;
import google.registry.xml.XmlException;
import java.util.List;
/** Static utility functions for flows. */ /** Static utility functions for flows. */
public final class FlowUtils { public final class FlowUtils {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private FlowUtils() {} private FlowUtils() {}
/** Validate that there is a logged in client. */ /** Validate that there is a logged in client. */
@ -37,10 +55,75 @@ public final class FlowUtils {
ofy().delete().keys(entityChanges.getDeletes()); ofy().delete().keys(entityChanges.getDeletes());
} }
/**
* Unmarshal bytes into Epp classes. Does the same as {@link EppXmlTransformer#unmarshal(Class,
* byte[])} but with exception-handling logic to throw {@link EppException} instead.
*/
public static <T> T unmarshalEpp(Class<T> clazz, byte[] bytes) throws EppException {
try {
return EppXmlTransformer.unmarshal(clazz, bytes);
} catch (XmlException e) {
// If this XmlException is wrapping a known type find it. If not, it's a syntax error.
List<Throwable> causalChain = Throwables.getCausalChain(e);
if (causalChain.stream().anyMatch(IpVersionMismatchException.class::isInstance)) {
throw new IpAddressVersionMismatchException();
}
if (causalChain.stream().anyMatch(WrongProtocolVersionException.class::isInstance)) {
throw new UnimplementedProtocolVersionException();
}
if (causalChain.stream().anyMatch(UnknownCurrencyException.class::isInstance)) {
throw new UnknownCurrencyEppException();
}
throw new GenericXmlSyntaxErrorException(e.getMessage());
}
}
public static byte[] marshalWithLenientRetry(EppOutput eppOutput) {
checkState(eppOutput != null);
// We need to marshal to a string instead of writing the response directly to the servlet's
// response writer, so that partial results don't get written on failure.
try {
return EppXmlTransformer.marshal(eppOutput, STRICT);
} catch (XmlException e) {
// We failed to marshal with validation. This is very bad, but we can potentially still send
// back slightly invalid xml, so try again without validation.
try {
byte[] lenient = EppXmlTransformer.marshal(eppOutput, LENIENT);
// Marshaling worked even though the results didn't validate against the schema.
logger.atSevere().withCause(e).log(
"Result marshaled but did not validate: %s", new String(lenient, UTF_8));
return lenient;
} catch (XmlException e2) {
throw new RuntimeException(e2); // Failing to marshal at all is not recoverable.
}
}
}
/** Registrar is not logged in. */ /** Registrar is not logged in. */
public static class NotLoggedInException extends CommandUseErrorException { public static class NotLoggedInException extends CommandUseErrorException {
public NotLoggedInException() { public NotLoggedInException() {
super("Registrar is not logged in."); super("Registrar is not logged in.");
} }
} }
/** IP address version mismatch. */
public static class IpAddressVersionMismatchException extends ParameterValueRangeErrorException {
public IpAddressVersionMismatchException() {
super("IP adddress version mismatch");
}
}
/** Unknown currency. */
static class UnknownCurrencyEppException extends ParameterValueRangeErrorException {
public UnknownCurrencyEppException() {
super("Unknown currency.");
}
}
/** Generic XML syntax error that can be thrown by any flow. */
public static class GenericXmlSyntaxErrorException extends SyntaxErrorException {
public GenericXmlSyntaxErrorException(String message) {
super(message);
}
}
} }

View file

@ -15,7 +15,7 @@
package google.registry.flows.domain; package google.registry.flows.domain;
import static com.google.common.collect.Sets.union; import static com.google.common.collect.Sets.union;
import static google.registry.flows.EppXmlTransformer.unmarshal; import static google.registry.flows.FlowUtils.unmarshalEpp;
import static google.registry.flows.FlowUtils.validateClientIsLoggedIn; import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.verifyExistence; import static google.registry.flows.ResourceFlowUtils.verifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfo; import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfo;
@ -136,7 +136,7 @@ public final class DomainApplicationInfoFlow implements Flow {
if (Boolean.TRUE.equals(launchInfo.getIncludeMark())) { // Default to false. if (Boolean.TRUE.equals(launchInfo.getIncludeMark())) { // Default to false.
for (EncodedSignedMark encodedMark : application.getEncodedSignedMarks()) { for (EncodedSignedMark encodedMark : application.getEncodedSignedMarks()) {
try { try {
marksBuilder.add(unmarshal(SignedMark.class, encodedMark.getBytes()).getMark()); marksBuilder.add(unmarshalEpp(SignedMark.class, encodedMark.getBytes()).getMark());
} catch (EppException e) { } catch (EppException e) {
// This is a serious error; don't let the benign EppException propagate. // This is a serious error; don't let the benign EppException propagate.
throw new IllegalStateException("Could not decode a stored encoded signed mark", e); throw new IllegalStateException("Could not decode a stored encoded signed mark", e);

View file

@ -15,7 +15,7 @@
package google.registry.flows.domain; package google.registry.flows.domain;
import static com.google.common.collect.Iterables.concat; import static com.google.common.collect.Iterables.concat;
import static google.registry.flows.EppXmlTransformer.unmarshal; import static google.registry.flows.FlowUtils.unmarshalEpp;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import google.registry.flows.EppException; import google.registry.flows.EppException;
@ -90,7 +90,7 @@ public final class DomainFlowTmchUtils {
SignedMark signedMark; SignedMark signedMark;
try { try {
signedMark = unmarshal(SignedMark.class, signedMarkData); signedMark = unmarshalEpp(SignedMark.class, signedMarkData);
} catch (EppException e) { } catch (EppException e) {
throw new SignedMarkParsingErrorException(); throw new SignedMarkParsingErrorException();
} }

View file

@ -64,7 +64,7 @@ import org.joda.time.DateTime;
* hosts cannot have any. This flow allows creating a host name, and if necessary enqueues tasks to * hosts cannot have any. This flow allows creating a host name, and if necessary enqueues tasks to
* update DNS. * update DNS.
* *
* @error {@link google.registry.flows.EppXmlTransformer.IpAddressVersionMismatchException} * @error {@link google.registry.flows.FlowUtils.IpAddressVersionMismatchException}
* @error {@link google.registry.flows.exceptions.ResourceAlreadyExistsException} * @error {@link google.registry.flows.exceptions.ResourceAlreadyExistsException}
* @error {@link HostFlowUtils.HostNameTooLongException} * @error {@link HostFlowUtils.HostNameTooLongException}
* @error {@link HostFlowUtils.HostNameTooShallowException} * @error {@link HostFlowUtils.HostNameTooShallowException}
@ -87,8 +87,13 @@ public final class HostCreateFlow implements TransactionalFlow {
@Inject HistoryEntry.Builder historyBuilder; @Inject HistoryEntry.Builder historyBuilder;
@Inject DnsQueue dnsQueue; @Inject DnsQueue dnsQueue;
@Inject EppResponse.Builder responseBuilder; @Inject EppResponse.Builder responseBuilder;
@Inject @Config("contactAndHostRoidSuffix") String roidSuffix;
@Inject HostCreateFlow() {} @Inject
@Config("contactAndHostRoidSuffix")
String roidSuffix;
@Inject
HostCreateFlow() {}
@Override @Override
public final EppResponse run() throws EppException { public final EppResponse run() throws EppException {
@ -126,15 +131,19 @@ public final class HostCreateFlow implements TransactionalFlow {
.setType(HistoryEntry.Type.HOST_CREATE) .setType(HistoryEntry.Type.HOST_CREATE)
.setModificationTime(now) .setModificationTime(now)
.setParent(Key.create(newHost)); .setParent(Key.create(newHost));
ImmutableSet<ImmutableObject> entitiesToSave = ImmutableSet.of( ImmutableSet<ImmutableObject> entitiesToSave =
ImmutableSet.of(
newHost, newHost,
historyBuilder.build(), historyBuilder.build(),
ForeignKeyIndex.create(newHost, newHost.getDeletionTime()), ForeignKeyIndex.create(newHost, newHost.getDeletionTime()),
EppResourceIndex.create(Key.create(newHost))); EppResourceIndex.create(Key.create(newHost)));
if (superordinateDomain.isPresent()) { if (superordinateDomain.isPresent()) {
entitiesToSave = union( entitiesToSave =
union(
entitiesToSave, entitiesToSave,
superordinateDomain.get().asBuilder() superordinateDomain
.get()
.asBuilder()
.addSubordinateHost(command.getFullyQualifiedHostName()) .addSubordinateHost(command.getFullyQualifiedHostName())
.build()); .build());
// Only update DNS if this is a subordinate host. External hosts have no glue to write, so // Only update DNS if this is a subordinate host. External hosts have no glue to write, so

View file

@ -402,13 +402,5 @@ public final class EppResourceUtils {
return queryForLinkedDomains(key, now).limit(1).count() > 0; return queryForLinkedDomains(key, now).limit(1).count() > 0;
} }
/** Exception to throw when failing to parse a repo id. */
public static class InvalidRepoIdException extends Exception {
public InvalidRepoIdException(String message) {
super(message);
}
}
private EppResourceUtils() {} private EppResourceUtils() {}
} }

View file

@ -0,0 +1,95 @@
// 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.model.eppcommon;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import google.registry.model.ImmutableObject;
import google.registry.model.eppinput.EppInput;
import google.registry.model.eppoutput.EppOutput;
import google.registry.xml.ValidationMode;
import google.registry.xml.XmlException;
import google.registry.xml.XmlTransformer;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
/** {@link XmlTransformer} for marshalling to and from the Epp model classes. */
public class EppXmlTransformer {
// Hardcoded XML schemas, ordered with respect to dependency.
private static final ImmutableList<String> SCHEMAS = ImmutableList.of(
"eppcom.xsd",
"epp.xsd",
"contact.xsd",
"host.xsd",
"domain.xsd",
"rgp.xsd",
"secdns.xsd",
"fee06.xsd",
"fee11.xsd",
"fee12.xsd",
"metadata.xsd",
"mark.xsd",
"dsig.xsd",
"smd.xsd",
"launch.xsd",
"allocate.xsd",
"superuser.xsd",
"allocationToken-1.0.xsd");
private static final XmlTransformer INPUT_TRANSFORMER =
new XmlTransformer(SCHEMAS, EppInput.class);
private static final XmlTransformer OUTPUT_TRANSFORMER =
new XmlTransformer(SCHEMAS, EppOutput.class);
public static void validateOutput(String xml) throws XmlException {
OUTPUT_TRANSFORMER.validate(xml);
}
/**
* Unmarshal bytes into Epp classes.
*
* @param clazz type to return, specified as a param to enforce typesafe generics
*/
public static <T> T unmarshal(Class<T> clazz, byte[] bytes) throws XmlException {
return INPUT_TRANSFORMER.unmarshal(clazz, new ByteArrayInputStream(bytes));
}
private static byte[] marshal(
XmlTransformer transformer,
ImmutableObject root,
ValidationMode validation) throws XmlException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
transformer.marshal(root, byteArrayOutputStream, UTF_8, validation);
return byteArrayOutputStream.toByteArray();
}
public static byte[] marshal(EppOutput root, ValidationMode validation) throws XmlException {
return marshal(OUTPUT_TRANSFORMER, root, validation);
}
@VisibleForTesting
public static byte[] marshalInput(EppInput root, ValidationMode validation) throws XmlException {
return marshal(INPUT_TRANSFORMER, root, validation);
}
@VisibleForTesting
public static void validateInput(String xml) throws XmlException {
INPUT_TRANSFORMER.validate(xml);
}
}

View file

@ -21,7 +21,7 @@ import static com.google.common.base.Strings.emptyToNull;
import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.Iterables.transform; import static com.google.common.collect.Iterables.transform;
import static com.google.common.io.BaseEncoding.base16; import static com.google.common.io.BaseEncoding.base16;
import static google.registry.flows.EppXmlTransformer.unmarshal; import static google.registry.model.eppcommon.EppXmlTransformer.unmarshal;
import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.tools.CommandUtilities.addHeader; import static google.registry.tools.CommandUtilities.addHeader;
import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.joining;
@ -34,7 +34,6 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.template.soy.data.SoyMapData; import com.google.template.soy.data.SoyMapData;
import com.googlecode.objectify.Key; import com.googlecode.objectify.Key;
import google.registry.flows.EppException;
import google.registry.model.domain.DesignatedContact; import google.registry.model.domain.DesignatedContact;
import google.registry.model.domain.DomainApplication; import google.registry.model.domain.DomainApplication;
import google.registry.model.domain.DomainCommand; import google.registry.model.domain.DomainCommand;
@ -46,6 +45,7 @@ import google.registry.model.eppinput.EppInput.ResourceCommandWrapper;
import google.registry.model.reporting.HistoryEntry; import google.registry.model.reporting.HistoryEntry;
import google.registry.model.smd.SignedMark; import google.registry.model.smd.SignedMark;
import google.registry.tools.soy.DomainAllocateSoyInfo; import google.registry.tools.soy.DomainAllocateSoyInfo;
import google.registry.xml.XmlException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@ -88,7 +88,7 @@ final class AllocateDomainCommand extends MutatingEppToolCommand {
} }
/** Extract the registration period from the XML used to create the domain application. */ /** Extract the registration period from the XML used to create the domain application. */
private static Period extractPeriodFromXml(byte[] xmlBytes) throws EppException { private static Period extractPeriodFromXml(byte[] xmlBytes) throws XmlException {
EppInput eppInput = unmarshal(EppInput.class, xmlBytes); EppInput eppInput = unmarshal(EppInput.class, xmlBytes);
return ((DomainCommand.Create) return ((DomainCommand.Create)
((ResourceCommandWrapper) eppInput.getCommandWrapper().getCommand()) ((ResourceCommandWrapper) eppInput.getCommandWrapper().getCommand())
@ -182,7 +182,7 @@ final class AllocateDomainCommand extends MutatingEppToolCommand {
"dsRecords", dsRecords, "dsRecords", dsRecords,
"clTrid", clientTransactionId)); "clTrid", clientTransactionId));
applicationKeys.add(Key.create(application)); applicationKeys.add(Key.create(application));
} catch (EppException e) { } catch (XmlException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }

View file

@ -15,7 +15,7 @@
package google.registry.tools; package google.registry.tools;
import static com.google.common.base.Strings.isNullOrEmpty; import static com.google.common.base.Strings.isNullOrEmpty;
import static google.registry.flows.EppXmlTransformer.unmarshal; import static google.registry.model.eppcommon.EppXmlTransformer.unmarshal;
import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.model.registry.Registries.assertTldExists; import static google.registry.model.registry.Registries.assertTldExists;
import static google.registry.util.DateTimeUtils.isBeforeOrAt; import static google.registry.util.DateTimeUtils.isBeforeOrAt;
@ -29,7 +29,6 @@ import com.google.common.base.Joiner;
import com.google.common.net.InternetDomainName; import com.google.common.net.InternetDomainName;
import com.googlecode.objectify.cmd.LoadType; import com.googlecode.objectify.cmd.LoadType;
import com.googlecode.objectify.cmd.Query; import com.googlecode.objectify.cmd.Query;
import google.registry.flows.EppException;
import google.registry.model.domain.DomainApplication; import google.registry.model.domain.DomainApplication;
import google.registry.model.smd.EncodedSignedMark; import google.registry.model.smd.EncodedSignedMark;
import google.registry.model.smd.SignedMark; import google.registry.model.smd.SignedMark;
@ -39,6 +38,7 @@ import google.registry.tmch.TmchXmlSignature;
import google.registry.tools.params.PathParameter; import google.registry.tools.params.PathParameter;
import google.registry.util.Clock; import google.registry.util.Clock;
import google.registry.util.Idn; import google.registry.util.Idn;
import google.registry.xml.XmlException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
@ -132,7 +132,7 @@ final class GenerateApplicationsReportCommand implements CommandWithRemoteApi {
SignedMark signedMark; SignedMark signedMark;
try { try {
signedMark = unmarshal(SignedMark.class, signedMarkData); signedMark = unmarshal(SignedMark.class, signedMarkData);
} catch (EppException e) { } catch (XmlException e) {
return Optional.of(makeLine(domainApplication, "Unparseable SMD")); return Optional.of(makeLine(domainApplication, "Unparseable SMD"));
} }

View file

@ -11,7 +11,6 @@ java_library(
"//java/google/registry/config", "//java/google/registry/config",
"//java/google/registry/dns", "//java/google/registry/dns",
"//java/google/registry/export", "//java/google/registry/export",
"//java/google/registry/flows",
"//java/google/registry/gcs", "//java/google/registry/gcs",
"//java/google/registry/groups", "//java/google/registry/groups",
"//java/google/registry/mapreduce", "//java/google/registry/mapreduce",
@ -20,6 +19,7 @@ java_library(
"//java/google/registry/request", "//java/google/registry/request",
"//java/google/registry/request/auth", "//java/google/registry/request/auth",
"//java/google/registry/util", "//java/google/registry/util",
"//java/google/registry/xml",
"//third_party/objectify:objectify-v4_1", "//third_party/objectify:objectify-v4_1",
"@com_google_appengine_api_1_0_sdk", "@com_google_appengine_api_1_0_sdk",
"@com_google_appengine_tools_appengine_gcs_client", "@com_google_appengine_tools_appengine_gcs_client",

View file

@ -17,7 +17,7 @@ package google.registry.tools.server;
import static com.google.common.base.Predicates.equalTo; import static com.google.common.base.Predicates.equalTo;
import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.Maps.toMap; import static com.google.common.collect.Maps.toMap;
import static google.registry.flows.EppXmlTransformer.unmarshal; import static google.registry.model.eppcommon.EppXmlTransformer.unmarshal;
import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.util.CollectionUtils.isNullOrEmpty; import static google.registry.util.CollectionUtils.isNullOrEmpty;
import static google.registry.util.DomainNameUtils.ACE_PREFIX; import static google.registry.util.DomainNameUtils.ACE_PREFIX;
@ -30,7 +30,6 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.Multiset; import com.google.common.collect.Multiset;
import com.googlecode.objectify.Key; import com.googlecode.objectify.Key;
import com.googlecode.objectify.cmd.Query; import com.googlecode.objectify.cmd.Query;
import google.registry.flows.EppException;
import google.registry.model.domain.DomainCommand; import google.registry.model.domain.DomainCommand;
import google.registry.model.domain.fee.FeeCreateCommandExtension; import google.registry.model.domain.fee.FeeCreateCommandExtension;
import google.registry.model.domain.launch.LaunchCreateExtension; import google.registry.model.domain.launch.LaunchCreateExtension;
@ -45,6 +44,7 @@ import google.registry.request.Action;
import google.registry.request.JsonActionRunner; import google.registry.request.JsonActionRunner;
import google.registry.request.JsonActionRunner.JsonAction; import google.registry.request.JsonActionRunner.JsonAction;
import google.registry.request.auth.Auth; import google.registry.request.auth.Auth;
import google.registry.xml.XmlException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.EnumSet; import java.util.EnumSet;
@ -264,7 +264,7 @@ public class VerifyOteAction implements Runnable, JsonAction {
for (HistoryEntry historyEntry : query) { for (HistoryEntry historyEntry : query) {
try { try {
record(historyEntry); record(historyEntry);
} catch (EppException e) { } catch (XmlException e) {
throw new RuntimeException("Couldn't parse history entry " + Key.create(historyEntry), e); throw new RuntimeException("Couldn't parse history entry " + Key.create(historyEntry), e);
} }
// Break out early if all tests were passed. // Break out early if all tests were passed.
@ -276,7 +276,7 @@ public class VerifyOteAction implements Runnable, JsonAction {
} }
/** Interprets the data in the provided HistoryEntry and increments counters. */ /** Interprets the data in the provided HistoryEntry and increments counters. */
void record(final HistoryEntry historyEntry) throws EppException { void record(final HistoryEntry historyEntry) throws XmlException {
byte[] xmlBytes = historyEntry.getXmlBytes(); byte[] xmlBytes = historyEntry.getXmlBytes();
// xmlBytes can be null on contact create and update for safe-harbor compliance. // xmlBytes can be null on contact create and update for safe-harbor compliance.
final Optional<EppInput> eppInput = final Optional<EppInput> eppInput =

View file

@ -16,7 +16,7 @@ package google.registry.flows;
import static com.google.common.io.BaseEncoding.base64; import static com.google.common.io.BaseEncoding.base64;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static google.registry.flows.EppXmlTransformer.marshal; import static google.registry.model.eppcommon.EppXmlTransformer.marshal;
import static google.registry.testing.DatastoreHelper.createTld; import static google.registry.testing.DatastoreHelper.createTld;
import static google.registry.testing.LogsSubject.assertAboutLogs; import static google.registry.testing.LogsSubject.assertAboutLogs;
import static google.registry.testing.TestDataHelper.loadFile; import static google.registry.testing.TestDataHelper.loadFile;

View file

@ -35,6 +35,7 @@ import google.registry.model.billing.BillingEvent.Flag;
import google.registry.model.billing.BillingEvent.OneTime; import google.registry.model.billing.BillingEvent.OneTime;
import google.registry.model.billing.BillingEvent.Reason; import google.registry.model.billing.BillingEvent.Reason;
import google.registry.model.domain.DomainResource; import google.registry.model.domain.DomainResource;
import google.registry.model.eppcommon.EppXmlTransformer;
import google.registry.model.ofy.Ofy; import google.registry.model.ofy.Ofy;
import google.registry.model.registry.Registry; import google.registry.model.registry.Registry;
import google.registry.model.reporting.HistoryEntry; import google.registry.model.reporting.HistoryEntry;

View file

@ -19,7 +19,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.Sets.difference; import static com.google.common.collect.Sets.difference;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static google.registry.flows.EppXmlTransformer.marshal; import static google.registry.model.eppcommon.EppXmlTransformer.marshal;
import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.testing.DatastoreHelper.POLL_MESSAGE_ID_STRIPPER; import static google.registry.testing.DatastoreHelper.POLL_MESSAGE_ID_STRIPPER;
import static google.registry.testing.DatastoreHelper.getPollMessages; import static google.registry.testing.DatastoreHelper.getPollMessages;

View file

@ -35,7 +35,7 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.googlecode.objectify.Key; import com.googlecode.objectify.Key;
import google.registry.flows.EppException; import google.registry.flows.EppException;
import google.registry.flows.EppXmlTransformer.IpAddressVersionMismatchException; import google.registry.flows.FlowUtils.IpAddressVersionMismatchException;
import google.registry.flows.ResourceFlowTestCase; import google.registry.flows.ResourceFlowTestCase;
import google.registry.flows.exceptions.ResourceAlreadyExistsException; import google.registry.flows.exceptions.ResourceAlreadyExistsException;
import google.registry.flows.host.HostCreateFlow.SubordinateHostMustHaveIpException; import google.registry.flows.host.HostCreateFlow.SubordinateHostMustHaveIpException;

View file

@ -14,7 +14,7 @@
package google.registry.model; package google.registry.model;
import static google.registry.flows.EppXmlTransformer.marshalInput; import static google.registry.model.eppcommon.EppXmlTransformer.marshalInput;
import static google.registry.xml.ValidationMode.STRICT; import static google.registry.xml.ValidationMode.STRICT;
import static google.registry.xml.XmlTestUtils.assertXmlEquals; import static google.registry.xml.XmlTestUtils.assertXmlEquals;
import static java.nio.charset.StandardCharsets.UTF_8; import static java.nio.charset.StandardCharsets.UTF_8;

View file

@ -14,8 +14,8 @@
package google.registry.model.contact; package google.registry.model.contact;
import static google.registry.flows.EppXmlTransformer.marshalInput; import static google.registry.model.eppcommon.EppXmlTransformer.marshalInput;
import static google.registry.flows.EppXmlTransformer.validateInput; import static google.registry.model.eppcommon.EppXmlTransformer.validateInput;
import static google.registry.xml.ValidationMode.LENIENT; import static google.registry.xml.ValidationMode.LENIENT;
import static google.registry.xml.XmlTestUtils.assertXmlEquals; import static google.registry.xml.XmlTestUtils.assertXmlEquals;
import static java.nio.charset.StandardCharsets.UTF_8; import static java.nio.charset.StandardCharsets.UTF_8;

View file

@ -12,11 +12,10 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package google.registry.model.eppcommon;
package google.registry.flows;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static google.registry.flows.EppXmlTransformer.unmarshal; import static google.registry.model.eppcommon.EppXmlTransformer.unmarshal;
import static google.registry.testing.JUnitBackports.assertThrows; import static google.registry.testing.JUnitBackports.assertThrows;
import static google.registry.testing.TestDataHelper.loadBytes; import static google.registry.testing.TestDataHelper.loadBytes;
@ -41,8 +40,6 @@ public class EppXmlTransformerTest extends ShardableTestCase {
public void testUnmarshalingWrongClassThrows() { public void testUnmarshalingWrongClassThrows() {
assertThrows( assertThrows(
ClassCastException.class, ClassCastException.class,
() -> () -> unmarshal(EppOutput.class, loadBytes(getClass(), "contact_info.xml").read()));
EppXmlTransformer.unmarshal(
EppOutput.class, loadBytes(getClass(), "contact_info.xml").read()));
} }
} }

View file

@ -0,0 +1,14 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<info>
<contact:info
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
<contact:id>sh8013</contact:id>
<contact:authInfo>
<contact:pw>2fooBAR</contact:pw>
</contact:authInfo>
</contact:info>
</info>
<clTRID>ABC-12345</clTRID>
</command>
</epp>

View file

@ -16,15 +16,15 @@ package google.registry.model.eppinput;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.Truth8.assertThat;
import static google.registry.flows.EppXmlTransformer.unmarshal; import static google.registry.model.eppcommon.EppXmlTransformer.unmarshal;
import static google.registry.testing.JUnitBackports.assertThrows; import static google.registry.testing.JUnitBackports.assertThrows;
import static google.registry.testing.TestDataHelper.loadBytes; import static google.registry.testing.TestDataHelper.loadBytes;
import google.registry.flows.EppException.SyntaxErrorException;
import google.registry.model.contact.ContactResourceTest; import google.registry.model.contact.ContactResourceTest;
import google.registry.model.domain.DomainResourceTest; import google.registry.model.domain.DomainResourceTest;
import google.registry.model.eppinput.EppInput.InnerCommand; import google.registry.model.eppinput.EppInput.InnerCommand;
import google.registry.model.eppinput.EppInput.Login; import google.registry.model.eppinput.EppInput.Login;
import google.registry.xml.XmlException;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.JUnit4; import org.junit.runners.JUnit4;
@ -83,7 +83,7 @@ public class EppInputTest {
@Test @Test
public void testUnmarshalling_loginTagInWrongCase_throws() { public void testUnmarshalling_loginTagInWrongCase_throws() {
assertThrows( assertThrows(
SyntaxErrorException.class, XmlException.class,
() -> unmarshal(EppInput.class, loadBytes(getClass(), "login_wrong_case.xml").read())); () -> unmarshal(EppInput.class, loadBytes(getClass(), "login_wrong_case.xml").read()));
} }
} }

View file

@ -20,7 +20,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import google.registry.flows.EppXmlTransformer; import google.registry.model.eppcommon.EppXmlTransformer;
import google.registry.model.eppcommon.StatusValue; import google.registry.model.eppcommon.StatusValue;
import google.registry.model.eppinput.EppInput; import google.registry.model.eppinput.EppInput;
import google.registry.model.eppinput.EppInput.ResourceCommandWrapper; import google.registry.model.eppinput.EppInput.ResourceCommandWrapper;

View file

@ -16,7 +16,7 @@ package google.registry.testing;
import static com.google.common.truth.Truth.assertAbout; import static com.google.common.truth.Truth.assertAbout;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static google.registry.flows.EppXmlTransformer.marshal; import static google.registry.model.eppcommon.EppXmlTransformer.marshal;
import com.google.common.truth.FailureMetadata; import com.google.common.truth.FailureMetadata;
import com.google.common.truth.SimpleSubjectBuilder; import com.google.common.truth.SimpleSubjectBuilder;

View file

@ -14,7 +14,7 @@
package google.registry.testing; package google.registry.testing;
import static google.registry.flows.EppXmlTransformer.unmarshal; import static google.registry.flows.FlowUtils.unmarshalEpp;
import static google.registry.testing.TestDataHelper.loadFile; import static google.registry.testing.TestDataHelper.loadFile;
import static java.nio.charset.StandardCharsets.UTF_8; import static java.nio.charset.StandardCharsets.UTF_8;
@ -37,7 +37,12 @@ public class EppLoader {
} }
public EppInput getEpp() throws EppException { public EppInput getEpp() throws EppException {
return unmarshal(EppInput.class, eppXml.getBytes(UTF_8)); /*
* TODO(b/120837374): we shouldn't use EppException in non-Flow tests. Find a way to use {@link
* google.registry.model.eppcommon.EppXmlTransformer#unmarshal(Class, byte[])} in those tests
* instead of {@link google.registry.flows.FlowUtils#unmarshalEpp(Class, byte[])}
*/
return unmarshalEpp(EppInput.class, eppXml.getBytes(UTF_8));
} }
public String getEppXml() { public String getEppXml() {

View file

@ -16,12 +16,12 @@ package google.registry.tools;
import static com.google.common.io.BaseEncoding.base16; import static com.google.common.io.BaseEncoding.base16;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static google.registry.flows.EppXmlTransformer.unmarshal;
import static google.registry.flows.picker.FlowPicker.getFlowClass; import static google.registry.flows.picker.FlowPicker.getFlowClass;
import static google.registry.model.domain.DesignatedContact.Type.ADMIN; import static google.registry.model.domain.DesignatedContact.Type.ADMIN;
import static google.registry.model.domain.DesignatedContact.Type.BILLING; import static google.registry.model.domain.DesignatedContact.Type.BILLING;
import static google.registry.model.domain.DesignatedContact.Type.TECH; import static google.registry.model.domain.DesignatedContact.Type.TECH;
import static google.registry.model.domain.launch.ApplicationStatus.VALIDATED; import static google.registry.model.domain.launch.ApplicationStatus.VALIDATED;
import static google.registry.model.eppcommon.EppXmlTransformer.unmarshal;
import static google.registry.model.registry.Registry.TldState.QUIET_PERIOD; import static google.registry.model.registry.Registry.TldState.QUIET_PERIOD;
import static google.registry.testing.DatastoreHelper.createTld; import static google.registry.testing.DatastoreHelper.createTld;
import static google.registry.testing.DatastoreHelper.newDomainApplication; import static google.registry.testing.DatastoreHelper.newDomainApplication;