mirror of
https://github.com/google/nomulus.git
synced 2025-05-13 07:57:13 +02:00
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:
parent
f58211402a
commit
0a44ef0dca
27 changed files with 257 additions and 240 deletions
|
@ -17,8 +17,8 @@ package google.registry.flows;
|
|||
import static com.google.common.base.Strings.nullToEmpty;
|
||||
import static com.google.common.flogger.LazyArgs.lazy;
|
||||
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.FlowUtils.unmarshalEpp;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
@ -65,7 +65,7 @@ public final class EppController {
|
|||
try {
|
||||
EppInput eppInput;
|
||||
try {
|
||||
eppInput = unmarshal(EppInput.class, inputXmlBytes);
|
||||
eppInput = unmarshalEpp(EppInput.class, inputXmlBytes);
|
||||
} catch (EppException e) {
|
||||
// Log the unmarshalling error, with the raw bytes (in base64) to help with debugging.
|
||||
logger.atInfo().withCause(e).log(
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
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.xml.XmlTransformer.prettyPrint;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,14 +14,32 @@
|
|||
|
||||
package google.registry.flows;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
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.ParameterValueRangeErrorException;
|
||||
import google.registry.flows.EppException.SyntaxErrorException;
|
||||
import google.registry.flows.EppException.UnimplementedProtocolVersionException;
|
||||
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. */
|
||||
public final class FlowUtils {
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
private FlowUtils() {}
|
||||
|
||||
/** Validate that there is a logged in client. */
|
||||
|
@ -37,10 +55,75 @@ public final class FlowUtils {
|
|||
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. */
|
||||
public static class NotLoggedInException extends CommandUseErrorException {
|
||||
public NotLoggedInException() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
package google.registry.flows.domain;
|
||||
|
||||
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.ResourceFlowUtils.verifyExistence;
|
||||
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.
|
||||
for (EncodedSignedMark encodedMark : application.getEncodedSignedMarks()) {
|
||||
try {
|
||||
marksBuilder.add(unmarshal(SignedMark.class, encodedMark.getBytes()).getMark());
|
||||
marksBuilder.add(unmarshalEpp(SignedMark.class, encodedMark.getBytes()).getMark());
|
||||
} catch (EppException e) {
|
||||
// This is a serious error; don't let the benign EppException propagate.
|
||||
throw new IllegalStateException("Could not decode a stored encoded signed mark", e);
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
package google.registry.flows.domain;
|
||||
|
||||
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 google.registry.flows.EppException;
|
||||
|
@ -90,7 +90,7 @@ public final class DomainFlowTmchUtils {
|
|||
|
||||
SignedMark signedMark;
|
||||
try {
|
||||
signedMark = unmarshal(SignedMark.class, signedMarkData);
|
||||
signedMark = unmarshalEpp(SignedMark.class, signedMarkData);
|
||||
} catch (EppException e) {
|
||||
throw new SignedMarkParsingErrorException();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
* 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 HostFlowUtils.HostNameTooLongException}
|
||||
* @error {@link HostFlowUtils.HostNameTooShallowException}
|
||||
|
@ -87,8 +87,13 @@ public final class HostCreateFlow implements TransactionalFlow {
|
|||
@Inject HistoryEntry.Builder historyBuilder;
|
||||
@Inject DnsQueue dnsQueue;
|
||||
@Inject EppResponse.Builder responseBuilder;
|
||||
@Inject @Config("contactAndHostRoidSuffix") String roidSuffix;
|
||||
@Inject HostCreateFlow() {}
|
||||
|
||||
@Inject
|
||||
@Config("contactAndHostRoidSuffix")
|
||||
String roidSuffix;
|
||||
|
||||
@Inject
|
||||
HostCreateFlow() {}
|
||||
|
||||
@Override
|
||||
public final EppResponse run() throws EppException {
|
||||
|
@ -126,17 +131,21 @@ public final class HostCreateFlow implements TransactionalFlow {
|
|||
.setType(HistoryEntry.Type.HOST_CREATE)
|
||||
.setModificationTime(now)
|
||||
.setParent(Key.create(newHost));
|
||||
ImmutableSet<ImmutableObject> entitiesToSave = ImmutableSet.of(
|
||||
newHost,
|
||||
historyBuilder.build(),
|
||||
ForeignKeyIndex.create(newHost, newHost.getDeletionTime()),
|
||||
EppResourceIndex.create(Key.create(newHost)));
|
||||
ImmutableSet<ImmutableObject> entitiesToSave =
|
||||
ImmutableSet.of(
|
||||
newHost,
|
||||
historyBuilder.build(),
|
||||
ForeignKeyIndex.create(newHost, newHost.getDeletionTime()),
|
||||
EppResourceIndex.create(Key.create(newHost)));
|
||||
if (superordinateDomain.isPresent()) {
|
||||
entitiesToSave = union(
|
||||
entitiesToSave,
|
||||
superordinateDomain.get().asBuilder()
|
||||
.addSubordinateHost(command.getFullyQualifiedHostName())
|
||||
.build());
|
||||
entitiesToSave =
|
||||
union(
|
||||
entitiesToSave,
|
||||
superordinateDomain
|
||||
.get()
|
||||
.asBuilder()
|
||||
.addSubordinateHost(command.getFullyQualifiedHostName())
|
||||
.build());
|
||||
// Only update DNS if this is a subordinate host. External hosts have no glue to write, so
|
||||
// they are only written as NS records from the referencing domain.
|
||||
dnsQueue.addHostRefreshTask(targetId);
|
||||
|
|
|
@ -402,13 +402,5 @@ public final class EppResourceUtils {
|
|||
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() {}
|
||||
}
|
||||
|
|
95
java/google/registry/model/eppcommon/EppXmlTransformer.java
Normal file
95
java/google/registry/model/eppcommon/EppXmlTransformer.java
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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.Iterables.transform;
|
||||
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.tools.CommandUtilities.addHeader;
|
||||
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.template.soy.data.SoyMapData;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.model.domain.DesignatedContact;
|
||||
import google.registry.model.domain.DomainApplication;
|
||||
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.smd.SignedMark;
|
||||
import google.registry.tools.soy.DomainAllocateSoyInfo;
|
||||
import google.registry.xml.XmlException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
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. */
|
||||
private static Period extractPeriodFromXml(byte[] xmlBytes) throws EppException {
|
||||
private static Period extractPeriodFromXml(byte[] xmlBytes) throws XmlException {
|
||||
EppInput eppInput = unmarshal(EppInput.class, xmlBytes);
|
||||
return ((DomainCommand.Create)
|
||||
((ResourceCommandWrapper) eppInput.getCommandWrapper().getCommand())
|
||||
|
@ -182,7 +182,7 @@ final class AllocateDomainCommand extends MutatingEppToolCommand {
|
|||
"dsRecords", dsRecords,
|
||||
"clTrid", clientTransactionId));
|
||||
applicationKeys.add(Key.create(application));
|
||||
} catch (EppException e) {
|
||||
} catch (XmlException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
package google.registry.tools;
|
||||
|
||||
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.registry.Registries.assertTldExists;
|
||||
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.googlecode.objectify.cmd.LoadType;
|
||||
import com.googlecode.objectify.cmd.Query;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.model.domain.DomainApplication;
|
||||
import google.registry.model.smd.EncodedSignedMark;
|
||||
import google.registry.model.smd.SignedMark;
|
||||
|
@ -39,6 +38,7 @@ import google.registry.tmch.TmchXmlSignature;
|
|||
import google.registry.tools.params.PathParameter;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.Idn;
|
||||
import google.registry.xml.XmlException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
@ -132,7 +132,7 @@ final class GenerateApplicationsReportCommand implements CommandWithRemoteApi {
|
|||
SignedMark signedMark;
|
||||
try {
|
||||
signedMark = unmarshal(SignedMark.class, signedMarkData);
|
||||
} catch (EppException e) {
|
||||
} catch (XmlException e) {
|
||||
return Optional.of(makeLine(domainApplication, "Unparseable SMD"));
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ java_library(
|
|||
"//java/google/registry/config",
|
||||
"//java/google/registry/dns",
|
||||
"//java/google/registry/export",
|
||||
"//java/google/registry/flows",
|
||||
"//java/google/registry/gcs",
|
||||
"//java/google/registry/groups",
|
||||
"//java/google/registry/mapreduce",
|
||||
|
@ -20,6 +19,7 @@ java_library(
|
|||
"//java/google/registry/request",
|
||||
"//java/google/registry/request/auth",
|
||||
"//java/google/registry/util",
|
||||
"//java/google/registry/xml",
|
||||
"//third_party/objectify:objectify-v4_1",
|
||||
"@com_google_appengine_api_1_0_sdk",
|
||||
"@com_google_appengine_tools_appengine_gcs_client",
|
||||
|
|
|
@ -17,7 +17,7 @@ package google.registry.tools.server;
|
|||
import static com.google.common.base.Predicates.equalTo;
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
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.util.CollectionUtils.isNullOrEmpty;
|
||||
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.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.cmd.Query;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.model.domain.DomainCommand;
|
||||
import google.registry.model.domain.fee.FeeCreateCommandExtension;
|
||||
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.JsonAction;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.xml.XmlException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
|
@ -264,7 +264,7 @@ public class VerifyOteAction implements Runnable, JsonAction {
|
|||
for (HistoryEntry historyEntry : query) {
|
||||
try {
|
||||
record(historyEntry);
|
||||
} catch (EppException e) {
|
||||
} catch (XmlException e) {
|
||||
throw new RuntimeException("Couldn't parse history entry " + Key.create(historyEntry), e);
|
||||
}
|
||||
// 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. */
|
||||
void record(final HistoryEntry historyEntry) throws EppException {
|
||||
void record(final HistoryEntry historyEntry) throws XmlException {
|
||||
byte[] xmlBytes = historyEntry.getXmlBytes();
|
||||
// xmlBytes can be null on contact create and update for safe-harbor compliance.
|
||||
final Optional<EppInput> eppInput =
|
||||
|
|
|
@ -16,7 +16,7 @@ package google.registry.flows;
|
|||
|
||||
import static com.google.common.io.BaseEncoding.base64;
|
||||
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.LogsSubject.assertAboutLogs;
|
||||
import static google.registry.testing.TestDataHelper.loadFile;
|
||||
|
|
|
@ -35,6 +35,7 @@ import google.registry.model.billing.BillingEvent.Flag;
|
|||
import google.registry.model.billing.BillingEvent.OneTime;
|
||||
import google.registry.model.billing.BillingEvent.Reason;
|
||||
import google.registry.model.domain.DomainResource;
|
||||
import google.registry.model.eppcommon.EppXmlTransformer;
|
||||
import google.registry.model.ofy.Ofy;
|
||||
import google.registry.model.registry.Registry;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
|
|
|
@ -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.Sets.difference;
|
||||
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.testing.DatastoreHelper.POLL_MESSAGE_ID_STRIPPER;
|
||||
import static google.registry.testing.DatastoreHelper.getPollMessages;
|
||||
|
|
|
@ -35,7 +35,7 @@ import com.google.common.collect.ImmutableMap;
|
|||
import com.google.common.collect.ImmutableSet;
|
||||
import com.googlecode.objectify.Key;
|
||||
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.exceptions.ResourceAlreadyExistsException;
|
||||
import google.registry.flows.host.HostCreateFlow.SubordinateHostMustHaveIpException;
|
||||
|
|
|
@ -45,7 +45,7 @@ public abstract class LoginFlowTestCase extends FlowTestCase<LoginFlow> {
|
|||
|
||||
@Before
|
||||
public void initRegistrar() {
|
||||
sessionMetadata.setClientId(null); // Don't implicitly log in (all other flows need to).
|
||||
sessionMetadata.setClientId(null); // Don't implicitly log in (all other flows need to).
|
||||
registrar = loadRegistrar("NewRegistrar");
|
||||
registrarBuilder = registrar.asBuilder();
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
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.XmlTestUtils.assertXmlEquals;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
|
||||
package google.registry.model.contact;
|
||||
|
||||
import static google.registry.flows.EppXmlTransformer.marshalInput;
|
||||
import static google.registry.flows.EppXmlTransformer.validateInput;
|
||||
import static google.registry.model.eppcommon.EppXmlTransformer.marshalInput;
|
||||
import static google.registry.model.eppcommon.EppXmlTransformer.validateInput;
|
||||
import static google.registry.xml.ValidationMode.LENIENT;
|
||||
import static google.registry.xml.XmlTestUtils.assertXmlEquals;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
|
|
@ -12,11 +12,10 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
|
||||
package google.registry.flows;
|
||||
package google.registry.model.eppcommon;
|
||||
|
||||
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.TestDataHelper.loadBytes;
|
||||
|
||||
|
@ -41,8 +40,6 @@ public class EppXmlTransformerTest extends ShardableTestCase {
|
|||
public void testUnmarshalingWrongClassThrows() {
|
||||
assertThrows(
|
||||
ClassCastException.class,
|
||||
() ->
|
||||
EppXmlTransformer.unmarshal(
|
||||
EppOutput.class, loadBytes(getClass(), "contact_info.xml").read()));
|
||||
() -> unmarshal(EppOutput.class, loadBytes(getClass(), "contact_info.xml").read()));
|
||||
}
|
||||
}
|
14
javatests/google/registry/model/eppcommon/testdata/contact_info.xml
vendored
Normal file
14
javatests/google/registry/model/eppcommon/testdata/contact_info.xml
vendored
Normal 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>
|
|
@ -16,15 +16,15 @@ package google.registry.model.eppinput;
|
|||
|
||||
import static com.google.common.truth.Truth.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.TestDataHelper.loadBytes;
|
||||
|
||||
import google.registry.flows.EppException.SyntaxErrorException;
|
||||
import google.registry.model.contact.ContactResourceTest;
|
||||
import google.registry.model.domain.DomainResourceTest;
|
||||
import google.registry.model.eppinput.EppInput.InnerCommand;
|
||||
import google.registry.model.eppinput.EppInput.Login;
|
||||
import google.registry.xml.XmlException;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
@ -83,7 +83,7 @@ public class EppInputTest {
|
|||
@Test
|
||||
public void testUnmarshalling_loginTagInWrongCase_throws() {
|
||||
assertThrows(
|
||||
SyntaxErrorException.class,
|
||||
XmlException.class,
|
||||
() -> unmarshal(EppInput.class, loadBytes(getClass(), "login_wrong_case.xml").read()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
|
|||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
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.eppinput.EppInput;
|
||||
import google.registry.model.eppinput.EppInput.ResourceCommandWrapper;
|
||||
|
|
|
@ -16,7 +16,7 @@ package google.registry.testing;
|
|||
|
||||
import static com.google.common.truth.Truth.assertAbout;
|
||||
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.SimpleSubjectBuilder;
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
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 java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
|
@ -37,7 +37,12 @@ public class EppLoader {
|
|||
}
|
||||
|
||||
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() {
|
||||
|
|
|
@ -16,12 +16,12 @@ package google.registry.tools;
|
|||
|
||||
import static com.google.common.io.BaseEncoding.base16;
|
||||
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.model.domain.DesignatedContact.Type.ADMIN;
|
||||
import static google.registry.model.domain.DesignatedContact.Type.BILLING;
|
||||
import static google.registry.model.domain.DesignatedContact.Type.TECH;
|
||||
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.testing.DatastoreHelper.createTld;
|
||||
import static google.registry.testing.DatastoreHelper.newDomainApplication;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue