mirror of
https://github.com/google/nomulus.git
synced 2025-04-30 20:17:51 +02:00
Java's stock regex implementation doesn't guarantee linear time complexity which makes it a security liability. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=121159875
89 lines
3.2 KiB
Java
89 lines
3.2 KiB
Java
// Copyright 2016 The Domain Registry 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.xml;
|
|
|
|
import static com.google.common.base.Throwables.propagateIfInstanceOf;
|
|
import static com.google.common.base.Verify.verify;
|
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
|
|
|
import com.google.re2j.Pattern;
|
|
|
|
import java.io.ByteArrayOutputStream;
|
|
|
|
import javax.annotation.concurrent.NotThreadSafe;
|
|
import javax.xml.bind.JAXBContext;
|
|
import javax.xml.bind.JAXBElement;
|
|
import javax.xml.bind.JAXBException;
|
|
import javax.xml.bind.MarshalException;
|
|
import javax.xml.bind.Marshaller;
|
|
import javax.xml.validation.Schema;
|
|
|
|
/** JAXB marshaller for building pieces of XML documents in a single thread. */
|
|
@NotThreadSafe
|
|
public final class XmlFragmentMarshaller {
|
|
|
|
private static final Pattern XMLNS_PATTERN = Pattern.compile(" xmlns:\\w+=\"[^\"]+\"");
|
|
|
|
private final ByteArrayOutputStream os = new ByteArrayOutputStream();
|
|
private final Marshaller marshaller;
|
|
private final Schema schema;
|
|
|
|
XmlFragmentMarshaller(JAXBContext jaxbContext, Schema schema) {
|
|
try {
|
|
marshaller = jaxbContext.createMarshaller();
|
|
marshaller.setProperty(Marshaller.JAXB_ENCODING, UTF_8.toString());
|
|
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
|
|
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
|
|
} catch (JAXBException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
this.schema = schema;
|
|
}
|
|
|
|
/**
|
|
* Turns an individual JAXB element into an XML fragment string.
|
|
*
|
|
* @throws MarshalException if schema validation failed
|
|
*/
|
|
public String marshal(JAXBElement<?> element) throws MarshalException {
|
|
return internalMarshal(element, true);
|
|
}
|
|
|
|
/** Turns an individual JAXB element into an XML fragment string. */
|
|
public String marshalLenient(JAXBElement<?> element) {
|
|
try {
|
|
return internalMarshal(element, false);
|
|
} catch (MarshalException e) {
|
|
throw new RuntimeException("MarshalException shouldn't be thrown in lenient mode", e);
|
|
}
|
|
}
|
|
|
|
private String internalMarshal(JAXBElement<?> element, boolean strict) throws MarshalException {
|
|
os.reset();
|
|
marshaller.setSchema(strict ? schema : null);
|
|
try {
|
|
marshaller.marshal(element, os);
|
|
} catch (JAXBException e) {
|
|
propagateIfInstanceOf(e, MarshalException.class);
|
|
throw new RuntimeException("Mysterious XML exception", e);
|
|
}
|
|
String fragment = new String(os.toByteArray(), UTF_8);
|
|
int endOfFirstLine = fragment.indexOf(">\n");
|
|
verify(endOfFirstLine > 0, "Bad XML fragment:\n%s", fragment);
|
|
String firstLine = fragment.substring(0, endOfFirstLine + 2);
|
|
String rest = fragment.substring(firstLine.length());
|
|
return XMLNS_PATTERN.matcher(firstLine).replaceAll("") + rest;
|
|
}
|
|
}
|