Commit 5475a85f authored by Andrea Aime's avatar Andrea Aime
Browse files

[GEOS-5551] WFS 1.0 capabilities will NPE with misconfigured OGR and XSLT output formats

parent 2dbdef2f
......@@ -48,7 +48,7 @@ public class Ogr2OgrConfigurator implements ApplicationListener {
this(format, 1000);
}
private void loadConfiguration() {
protected void loadConfiguration() {
// start with the default configuration, override if we can load the file
OgrConfiguration configuration = OgrConfiguration.DEFAULT;
try {
......
......@@ -11,6 +11,7 @@ import java.io.IOException;
import java.io.OutputStream;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
......@@ -19,9 +20,9 @@ import java.util.zip.ZipOutputStream;
import javax.xml.namespace.QName;
import net.opengis.wfs.FeatureCollectionType;
import net.opengis.wfs.GetFeatureType;
import net.opengis.wfs.QueryType;
import net.opengis.wfs.FeatureCollectionType;
import org.geoserver.config.GeoServer;
import org.geoserver.data.util.IOUtils;
......@@ -35,7 +36,6 @@ import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureStore;
import org.geotools.data.store.EmptyFeatureCollection;
import org.geotools.feature.FeatureTypes;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.gml.producer.FeatureTransformer;
import org.opengis.feature.simple.SimpleFeatureType;
......@@ -372,5 +372,10 @@ public class Ogr2OgrOutputFormat extends WFSGetFeatureOutputFormat {
return file;
}
@Override
public List<String> getCapabilitiesElementNames() {
return getAllCapabilitiesElementNames();
}
}
\ No newline at end of file
......@@ -8,16 +8,28 @@ import junit.framework.TestResult;
import org.geoserver.data.test.MockData;
import org.geoserver.test.GeoServerTestSupport;
import static org.custommonkey.xmlunit.XMLAssert.assertXpathEvaluatesTo;
import java.util.HashMap;
import java.util.Map;
import org.custommonkey.xmlunit.SimpleNamespaceContext;
import org.custommonkey.xmlunit.XMLUnit;
import org.w3c.dom.Document;
import com.mockrunner.mock.web.MockHttpServletResponse;
public class Ogr2OgrWfsTest extends GeoServerTestSupport {
public static Test suite() {
OgrConfiguration.DEFAULT.ogr2ogrLocation = Ogr2OgrTestUtil.getOgr2Ogr();
OgrConfiguration.DEFAULT.gdalData = Ogr2OgrTestUtil.getGdalData();
Map<String, String> namespaces = new HashMap<String, String>();
namespaces.put("wfs", "http://www.opengis.net/wfs");
namespaces.put("", "http://www.opengis.net/wfs");
XMLUnit.setXpathNamespaceContext(new SimpleNamespaceContext(namespaces));
return new OneTimeTestSetup(new Ogr2OgrWfsTest());
}
......@@ -32,6 +44,41 @@ public class Ogr2OgrWfsTest extends GeoServerTestSupport {
System.out.println("Skipping ogr2ogr wfs tests, ogr2ogr could not be found, " + getName());
else
super.run(result);
// force reload of the config, some tests alter it
Ogr2OgrConfigurator configurator = getBean(Ogr2OgrConfigurator.class);
configurator.loadConfiguration();
}
<T> T getBean(Class<T> bean) {
Map beansOfType = applicationContext.getBeansOfType(bean);
if(beansOfType.size() == 0) {
return null;
} else {
return (T) beansOfType.values().iterator().next();
}
}
public void testCapabilities() throws Exception {
String request = "wfs?request=GetCapabilities&version=1.0.0";
Document dom = getAsDOM(request);
// print(dom);
// while we cannot know what formats are available, the other tests won't pass if KML is not there
assertXpathEvaluatesTo("1", "count(//wfs:GetFeature/wfs:ResultFormat/wfs:OGR-KML)", dom);
}
public void testEmptyCapabilities() throws Exception {
Ogr2OgrOutputFormat of = getBean(Ogr2OgrOutputFormat.class);
of.clearFormats();
String request = "wfs?request=GetCapabilities&version=1.0.0";
Document dom = getAsDOM(request);
// print(dom);
// this used to NPE
assertXpathEvaluatesTo("0", "count(//wfs:GetFeature/wfs:ResultFormat/wfs:OGR-KML)", dom);
assertXpathEvaluatesTo("1", "count(//wfs:GetFeature/wfs:ResultFormat/wfs:SHAPE-ZIP)", dom);
}
public void testSimpleRequest() throws Exception {
......
......@@ -427,9 +427,11 @@ public abstract class CapabilitiesTransformer extends TransformerBase {
Map dupes = new HashMap();
for (Iterator i = featureProducers.iterator(); i.hasNext();) {
WFSGetFeatureOutputFormat format = (WFSGetFeatureOutputFormat) i.next();
if (!dupes.containsKey(format.getCapabilitiesElementName())) {
element(format.getCapabilitiesElementName(), null);
dupes.put(format.getCapabilitiesElementName(), new Object());
for (String name : format.getCapabilitiesElementNames()) {
if (!dupes.containsKey(name)) {
element(name, null);
dupes.put(name, new Object());
}
}
}
}
......
......@@ -6,8 +6,13 @@ package org.geoserver.wfs;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import net.opengis.wfs.FeatureCollectionType;
import net.opengis.wfs.GetFeatureType;
......@@ -37,6 +42,17 @@ import org.geoserver.wfs.response.WFSResponse;
*
*/
public abstract class WFSGetFeatureOutputFormat extends WFSResponse {
/**
* Based on definition of valid xml element name at http://www.w3.org/TR/xml/#NT-Name
*/
static final Pattern XML_ELEMENT = Pattern.compile("[:A-Z_a-z\\u00C0\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02ff\\u0370-\\u037d"
+ "\\u037f-\\u1fff\\u200c\\u200d\\u2070-\\u218f\\u2c00-\\u2fef\\u3001-\\ud7ff"
+ "\\uf900-\\ufdcf\\ufdf0-\\ufffd\\x10000-\\xEFFFF]"
+ "[:A-Z_a-z\\u00C0\\u00D6\\u00D8-\\u00F6"
+ "\\u00F8-\\u02ff\\u0370-\\u037d\\u037f-\\u1fff\\u200c\\u200d\\u2070-\\u218f"
+ "\\u2c00-\\u2fef\\u3001-\\udfff\\uf900-\\ufdcf\\ufdf0-\\ufffd\\\\x10000-\\\\xEFFFF\\-\\.0-9"
+ "\\u00b7\\u0300-\\u036f\\u203f-\\u2040]*\\Z");
/**
* logger
......@@ -104,10 +120,13 @@ public abstract class WFSGetFeatureOutputFormat extends WFSResponse {
LOGGER.severe("ERROR IN " + this.getClass() + " IMPLEMENTATION. getCapabilitiesElementName() should return a" +
"valid XML element name string for use in the WFS 1.0.0 capabilities document.");
String of = getOutputFormat();
if(of == null) {
return null;
}
//wfs 1.1 form is not a valid xml element, do a check
if (of.matches("(\\w)+")) {
return getOutputFormat();
// wfs 1.1 form is not a valid xml element, do a check
if (XML_ELEMENT.matcher(of).matches()) {
return of;
} else {
String name = this.getClass().getName();
if ( name.indexOf('.') != -1 ) {
......@@ -117,6 +136,39 @@ public abstract class WFSGetFeatureOutputFormat extends WFSResponse {
return name;
}
}
/**
* Returns the list of output format names generated by this format, for inclusion in
* the WFS 1.0 capabilities document as XML element names
* @return
*/
public List<String> getCapabilitiesElementNames() {
String name = getCapabilitiesElementName();
if(name == null) {
return Collections.emptyList();
} else {
return Arrays.asList(name);
}
}
/**
* Subclasses can delegate to this method if they want the full list of valid
* output format element names to be returned in the WFS 1.0 capabilities
* @return
*/
protected List<String> getAllCapabilitiesElementNames() {
List<String> result = new ArrayList<String>();
for (String name : getOutputFormats()) {
if (XML_ELEMENT.matcher(name).matches()) {
result.add(name);
}
}
// have the output order be independent of the used JDK
Collections.sort(result);
return result;
}
/**
* Hook for subclasses to add addtional checks to {@link #canHandle(Operation)}.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment