/* (c) 2014 Open Source Geospatial Foundation - all rights reserved * (c) 2001 - 2013 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.vfny.geoserver.util; import static org.geoserver.ows.util.ResponseUtils.buildURL; import java.io.IOException; import java.io.Writer; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.HashMap; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.logging.Level; import java.util.logging.Logger; import javax.xml.XMLConstants; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import javax.xml.validation.Validator; import org.geoserver.catalog.DataLinkInfo; import org.geoserver.catalog.MetadataLinkInfo; import org.geoserver.ows.URLMangler.URLType; import org.geoserver.ows.util.KvpUtils; import org.geotools.util.logging.Logging; import org.w3c.dom.ls.LSInput; import org.w3c.dom.ls.LSResourceResolver; import org.xml.sax.EntityResolver; import org.xml.sax.ErrorHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.helpers.DefaultHandler; public final class ResponseUtils { static Logger LOGGER = Logging.getLogger(ResponseUtils.class); /** * @deprecated moved to {@link org.geoserver.ows.util.ResponseUtils#encodeXML(String)}. */ public static String encodeXML(String inData) { return org.geoserver.ows.util.ResponseUtils.encodeXML(inData); } /** * @deprecated moved to {@link org.geoserver.ows.util.ResponseUtils#writeEscapedString(Writer, String)} */ public static void writeEscapedString(Writer writer, String string) throws IOException { org.geoserver.ows.util.ResponseUtils.writeEscapedString(writer, string); } /* Profixies a link url interpreting a localhost url as a back reference to the server. */ private static String proxifyLink(String content, String baseURL) { try { URI uri = new URI(content); try { if (uri.getHost() == null) { //interpret no host as backreference to server Map<String, String> kvp = null; if (uri.getQuery() != null && !"".equals(uri.getQuery())) { Map<String, Object> parsed = KvpUtils.parseQueryString("?" + uri.getQuery()); kvp = new HashMap<String, String>(); for (Entry<String, Object> entry : parsed.entrySet()) { kvp.put(entry.getKey(), (String) entry.getValue()); } } content = buildURL(baseURL, uri.getPath(), kvp, URLType.RESOURCE); } } catch (Exception e) { LOGGER.log(Level.WARNING, "Unable to create proper back reference for url: " + content, e); } } catch (URISyntaxException e) { } return content; } /** * Profixies a metadata link url interpreting a localhost url as a back reference to the server. * <p> * If <tt>link</tt> is not a localhost url it is left untouched. * </p> */ public static String proxifyMetadataLink(MetadataLinkInfo link, String baseURL) { String content = link.getContent(); content = proxifyLink(content, baseURL); return content; } /** * Profixies a data link url interpreting a localhost url as a back reference to the server. * <p> * If <tt>link</tt> is not a localhost url it is left untouched. * </p> */ public static String proxifyDataLink(DataLinkInfo link, String baseURL) { String content = link.getContent(); content = proxifyLink(content, baseURL); return content; } public static List validate(InputSource xml, URL schemaURL, boolean skipTargetNamespaceException) { return validate(xml, schemaURL, skipTargetNamespaceException, null); } public static List validate(InputSource xml, URL schemaURL, boolean skipTargetNamespaceException, EntityResolver entityResolver) { StreamSource source = null; if (xml.getCharacterStream() != null) { source = new StreamSource(xml.getCharacterStream()); } else if (xml.getByteStream() != null) { source = new StreamSource(xml.getByteStream()); } else { throw new IllegalArgumentException("Could not turn input source to stream source"); } return validate(source, schemaURL, skipTargetNamespaceException, entityResolver); } public static List validate(Source xml, URL schemaURL, boolean skipTargetNamespaceException) { return validate(xml, schemaURL, skipTargetNamespaceException, null); } public static List validate(Source xml, URL schemaURL, boolean skipTargetNamespaceException, EntityResolver entityResolver) { try { Schema schema = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(schemaURL); Validator v = schema.newValidator(); if(entityResolver != null) { v.setResourceResolver(new EntityResolverToLSResourceResolver(v.getResourceResolver(), entityResolver)); } Handler handler = new Handler(skipTargetNamespaceException, entityResolver); v.setErrorHandler(handler); v.validate(xml); return handler.errors; } catch (SAXException e) { return exception(e); } catch (IOException e) { return exception(e); } } // errors in the document will be put in "errors". // if errors.size() ==0 then there were no errors. private static class Handler extends DefaultHandler { public ArrayList errors = new ArrayList(); boolean skipTargetNamespaceException; EntityResolver entityResolver; Handler (boolean skipTargetNamespaceExeption, EntityResolver entityResolver) { this.skipTargetNamespaceException = skipTargetNamespaceExeption; this.entityResolver = entityResolver; } public void error(SAXParseException exception) throws SAXException { if (skipTargetNamespaceException && exception.getMessage() .startsWith("TargetNamespace.2: Expecting no namespace, but the schema document has a target name")) { return; } errors.add(exception); } public void fatalError(SAXParseException exception) throws SAXException { errors.add(exception); } public void warning(SAXParseException exception) throws SAXException { //do nothing } @Override public InputSource resolveEntity(String publicId, String systemId) throws IOException, SAXException { if(entityResolver != null) { return this.entityResolver.resolveEntity(publicId, systemId); } else { return super.resolveEntity(publicId, systemId); } } } static List exception(Exception e) { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "Validation error", e); } return Arrays.asList(new SAXParseException(e.getLocalizedMessage(), null)); } }