/* (c) 2014 - 2016 Open Source Geospatial Foundation - all rights reserved * (c) 2001 - 2014 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.wms.wms_1_3; import org.geoserver.catalog.Catalog; import org.geoserver.catalog.CoverageInfo; import org.geoserver.catalog.LayerGroupInfo; import org.geoserver.catalog.StyleGenerator; import org.geoserver.catalog.StyleInfo; import org.geoserver.catalog.Styles; import org.geoserver.config.GeoServerInfo; import org.geoserver.data.test.MockData; import org.geoserver.data.test.SystemTestData; import org.geoserver.data.test.TestData; import org.geoserver.wms.GetMapOutputFormat; import org.geoserver.wms.WMS; import org.geoserver.wms.WMSInfo; import org.geoserver.wms.WMSTestSupport; import org.geoserver.wms.map.OpenLayersMapOutputFormat; import org.geoserver.wms.map.RenderedImageMapOutputFormat; import org.junit.Test; import org.springframework.mock.web.MockHttpServletResponse; import org.w3c.dom.Document; import org.w3c.dom.Element; import javax.imageio.ImageIO; import javax.xml.namespace.QName; import java.awt.Color; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.net.URL; import java.nio.charset.Charset; import java.util.Collections; import static org.geoserver.data.test.MockData.WORLD; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; public class GetMapIntegrationTest extends WMSTestSupport { String bbox = "-130,24,-66,50"; String styles = "states"; String layers = "sf:states"; public static final String STATES_SLD10 = "<StyledLayerDescriptor xmlns=\"http://www.opengis.net/sld\" version=\"1.0.0\">"+ " <NamedLayer>"+ " <Name>sf:states</Name>"+ " <UserStyle>"+ " <Name>UserSelection</Name>"+ " <FeatureTypeStyle>"+ " <Rule>"+ " <ogc:Filter xmlns:ogc=\"http://www.opengis.net/ogc\">"+ " <ogc:PropertyIsEqualTo>"+ " <ogc:PropertyName>STATE_ABBR</ogc:PropertyName>"+ " <ogc:Literal>IL</ogc:Literal>"+ " </ogc:PropertyIsEqualTo>"+ " </ogc:Filter>"+ " <PolygonSymbolizer>"+ " <Fill>"+ " <CssParameter name=\"fill\">#FF0000</CssParameter>"+ " </Fill>"+ " </PolygonSymbolizer>"+ " </Rule>"+ " <Rule>"+ " <LineSymbolizer>"+ " <Stroke/>"+ " </LineSymbolizer>"+ " </Rule>"+ " </FeatureTypeStyle>"+ " </UserStyle>"+ " </NamedLayer>"+ "</StyledLayerDescriptor>"; public static final String STATES_SLD10_INVALID = "<StyledLayerDescriptor xmlns=\"http://www.opengis.net/sld\" version=\"1.0.0\">"+ " <NamedLayer>"+ " <Name>sf:states</Name>"+ " <UserStyle>"+ " <Name>UserSelection</Name>"+ " <FeatureTypeStyle>"+ " <Rule>"+ " <ogc:Filter xmlns:ogc=\"http://www.opengis.net/ogc\">"+ " <ogc:PropertyIsEqualTo>"+ " <ogc:PropertyName>STATE_ABBR</ogc:PropertyName>"+ " <ogc:Literal>IL</ogc:Literal>"+ " </ogc:PropertyIsEqualTo>"+ " </ogc:Filter>"+ " <PolygonSymbolizer>"+ " <Font/> <!-- invalid! -->" + " <Fill>"+ " <CssParameter name=\"fill\">#FF0000</CssParameter>"+ " </Fill>"+ " </PolygonSymbolizer>"+ " </Rule>"+ " <Rule>"+ " <LineSymbolizer>"+ " <Stroke/>"+ " </LineSymbolizer>"+ " </Rule>"+ " </FeatureTypeStyle>"+ " </UserStyle>"+ " </NamedLayer>"+ "</StyledLayerDescriptor>"; public static final String STATES_SLD11 = "<StyledLayerDescriptor xmlns=\"http://www.opengis.net/sld\" " + " xmlns:se=\"http://www.opengis.net/se\" version=\"1.1.0\"> "+ " <NamedLayer> "+ " <se:Name>sf:states</se:Name> "+ " <UserStyle> "+ " <se:Name>UserSelection</se:Name> "+ " <se:FeatureTypeStyle> "+ " <se:Rule> "+ " <ogc:Filter xmlns:ogc=\"http://www.opengis.net/ogc\"> "+ " <ogc:PropertyIsEqualTo> "+ " <ogc:PropertyName>STATE_ABBR</ogc:PropertyName> "+ " <ogc:Literal>IL</ogc:Literal> "+ " </ogc:PropertyIsEqualTo> "+ " </ogc:Filter> "+ " <se:PolygonSymbolizer> "+ " <se:Fill> "+ " <se:SvgParameter name=\"fill\">#FF0000</se:SvgParameter> "+ " </se:Fill> "+ " </se:PolygonSymbolizer> "+ " </se:Rule> "+ " <se:Rule> "+ " <se:LineSymbolizer> "+ " <se:Stroke/> "+ " </se:LineSymbolizer> "+ " </se:Rule> "+ " </se:FeatureTypeStyle> "+ " </UserStyle> "+ " </NamedLayer> "+ "</StyledLayerDescriptor>"; public static final String STATES_SLD11_INVALID = "<StyledLayerDescriptor xmlns=\"http://www.opengis.net/sld\" " + " xmlns:se=\"http://www.opengis.net/se\" version=\"1.1.0\"> "+ " <NamedLayer> "+ " <se:Name>sf:states</se:Name> "+ " <UserStyle> "+ " <se:Name>UserSelection</se:Name> "+ " <se:FeatureTypeStyle> "+ " <se:Rule> "+ " <ogc:Filter xmlns:ogc=\"http://www.opengis.net/ogc\"> "+ " <ogc:PropertyIsEqualTo> "+ " <ogc:PropertyName>STATE_ABBR</ogc:PropertyName> "+ " <ogc:Literal>IL</ogc:Literal> "+ " </ogc:PropertyIsEqualTo> "+ " </ogc:Filter> "+ " <se:PolygonSymbolizer> "+ " <se:Fill> "+ " <se:SvgParameter name=\"fill\">#FF0000</se:SvgParameter> "+ " </se:Fill> "+ " <se:Font/> <!-- invalid -->" + " </se:PolygonSymbolizer> "+ " </se:Rule> "+ " <se:Rule> "+ " <se:LineSymbolizer> "+ " <se:Stroke/> "+ " </se:LineSymbolizer> "+ " </se:Rule> "+ " </se:FeatureTypeStyle> "+ " </UserStyle> "+ " </NamedLayer> "+ "</StyledLayerDescriptor>"; @Override protected void onSetUp(SystemTestData testData) throws Exception { super.onSetUp(testData); Catalog catalog = getCatalog(); testData.addStyle("Population","Population.sld", org.geoserver.wms.wms_1_1_1.GetMapIntegrationTest.class,catalog); testData.addVectorLayer(new QName(MockData.SF_URI, "states", MockData.SF_PREFIX), Collections.EMPTY_MAP,"states.properties",org.geoserver.wms.wms_1_1_1.GetMapIntegrationTest.class,catalog); } @Test public void testRepeatedValues() throws Exception { String baseRequest = "wms?service=wms&version=1.3.0&bbox=" + bbox + "&styles=&layers=" + layers + "&format=image/png" + "&request=GetMap" + "&width=550" + "&height=250" + "&srs=EPSG:4326"; // parameter repeated, but with the same value, should work MockHttpServletResponse response = getAsServletResponse(baseRequest + "&format=image/png"); checkImage(response); // parameter repeated 2 times, but with the same value, should work response = getAsServletResponse(baseRequest + "&format=image/png&format=image/png"); checkImage(response); // parameter repeated with 2 different values, should throw an exception Document dom = getAsDOM(baseRequest + "&format=image/jpeg"); assertEquals("ServiceExceptionReport", dom.getDocumentElement().getNodeName()); Element serviceException = (Element) dom.getDocumentElement().getElementsByTagName("ServiceException").item(0); assertEquals("InvalidParameterValue", serviceException.getAttribute("code")); assertEquals("FORMAT", serviceException.getAttribute("locator")); } @Test public void testSldBody10() throws Exception { MockHttpServletResponse response = getAsServletResponse("wms?bbox=" + bbox + "&styles=" + "&layers=" + layers + "&Format=image/png" + "&request=GetMap" + "&width=550" + "&height=250" + "&srs=EPSG:4326" + "&SLD_VERSION=1.0.0" + "&SLD_BODY=" + STATES_SLD10.replaceAll("=", "%3D")); checkImage(response); } @Test public void testSldBody10Validate() throws Exception { MockHttpServletResponse response = getAsServletResponse("wms?bbox=" + bbox + "&styles=" + "&layers=" + layers + "&Format=image/png" + "&request=GetMap" + "&width=550" + "&height=250" + "&srs=EPSG:4326" + "&SLD_VERSION=1.0.0" + "&SLD_BODY=" + STATES_SLD10.replaceAll("=", "%3D") + "&VALIDATESCHEMA=true"); checkImage(response); Document dom = getAsDOM("wms?bbox=" + bbox + "&styles=" + "&layers=" + layers + "&Format=image/png" + "&request=GetMap" + "&width=550" + "&height=250" + "&srs=EPSG:4326" + "&SLD_VERSION=1.0.0" + "&SLD_BODY=" + STATES_SLD10_INVALID.replaceAll("=", "%3D") + "&VALIDATESCHEMA=true", Charset.defaultCharset().displayName()); assertEquals("ServiceExceptionReport", dom.getDocumentElement().getNodeName()); dom = getAsDOM("wms?bbox=" + bbox + "&styles=" + "&layers=" + layers + "&Format=image/png" + "&request=GetMap" + "&width=550" + "&height=250" + "&srs=EPSG:4326" + "&SLD_VERSION=1.0.0" + "&SLD_BODY=" + STATES_SLD11.replaceAll("=", "%3D") + "&VALIDATESCHEMA=true", Charset.defaultCharset().displayName()); assertEquals("ServiceExceptionReport", dom.getDocumentElement().getNodeName()); } @Test public void testSldBody11() throws Exception { MockHttpServletResponse response = getAsServletResponse("wms?bbox=" + bbox + "&styles=" + "&layers=" + layers + "&Format=image/png" + "&request=GetMap" + "&width=550" + "&height=250" + "&srs=EPSG:4326" + "&SLD_VERSION=1.1.0" + "&SLD_BODY=" + STATES_SLD11.replaceAll("=", "%3D")); checkImage(response); } @Test public void testSldBody11Validate() throws Exception { MockHttpServletResponse response = getAsServletResponse("wms?bbox=" + bbox + "&styles=" + "&layers=" + layers + "&Format=image/png" + "&request=GetMap" + "&width=550" + "&height=250" + "&srs=EPSG:4326" + "&SLD_VERSION=1.1.0" + "&SLD_BODY=" + STATES_SLD11.replaceAll("=", "%3D") + "&VALIDATESCHEMA=true"); checkImage(response); Document dom = getAsDOM("wms?bbox=" + bbox + "&styles=" + "&layers=" + layers + "&Format=image/png" + "&request=GetMap" + "&width=550" + "&height=250" + "&srs=EPSG:4326" + "&SLD_VERSION=1.1.0" + "&SLD_BODY=" + STATES_SLD11_INVALID.replaceAll("=", "%3D") + "&VALIDATESCHEMA=true", Charset.defaultCharset().displayName()); assertEquals("ServiceExceptionReport", dom.getDocumentElement().getNodeName()); } @Test public void testSldBody11NoVersion() throws Exception { //will fail beacuse sld version == 1.0 Document dom = getAsDOM("wms?bbox=" + bbox + "&styles=" + "&layers=" + layers + "&Format=image/png" + "&request=GetMap" + "&width=550" + "&height=250" + "&srs=EPSG:4326" + "&SLD_VERSION=1.0.0" + "&SLD_BODY=" + STATES_SLD11.replaceAll("=", "%3D") + "&VALIDATESCHEMA=true", Charset.defaultCharset().displayName()); assertEquals("ServiceExceptionReport", dom.getDocumentElement().getNodeName()); MockHttpServletResponse response = getAsServletResponse("wms?bbox=" + bbox + "&styles=" + "&layers=" + layers + "&Format=image/png" + "&request=GetMap" + "&width=550" + "&height=250" + "&srs=EPSG:4326" + "&SLD_BODY=" + STATES_SLD11.replaceAll("=", "%3D") + "&VALIDATESCHEMA=true"); checkImage(response); } @Test public void testSldGenerateRaster() throws Exception { Catalog catalog = getCatalog(); StyleGenerator generator = new StyleGenerator(catalog); CoverageInfo coverage = catalog.getCoverageByName(WORLD.getLocalPart()); StyleInfo style = generator.createStyle(Styles.handler("SLD"), coverage); catalog.add(style); MockHttpServletResponse response = getAsServletResponse("wms?bbox=-120,35,-100,45" + "&styles=" + style.getName() + "&layers=" + coverage.getName() + "&format=image/png&request=GetMap&width=80&height=40&srs=EPSG:4326"); BufferedImage image = ImageIO.read(new ByteArrayInputStream(response.getContentAsByteArray())); Color rgb = new Color(image.getRGB(5,5)); assertEquals(rgb, new Color(170,170,170)); checkImage(response); } @Test public void testLayerGroupSingle() throws Exception { Catalog catalog = getCatalog(); LayerGroupInfo group = createLakesPlacesLayerGroup(catalog, LayerGroupInfo.Mode.SINGLE, null); try { String url = "wms?LAYERS=" + group.getName() + "&STYLES=&FORMAT=image%2Fpng&REQUEST=GetMap&SRS=EPSG%3A4326&WIDTH=256&HEIGHT=256&BBOX=0.0000,-0.0020,0.0035,0.0010"; BufferedImage image = getAsImage(url, "image/png"); assertPixel(image, 150, 160, Color.WHITE); // places assertPixel(image, 180, 16, COLOR_PLACES_GRAY); // lakes assertPixel(image, 90, 200, COLOR_LAKES_BLUE); } finally { catalog.remove(group); } } @Test public void testLayerGroupNamed() throws Exception { Catalog catalog = getCatalog(); LayerGroupInfo group = createLakesPlacesLayerGroup(catalog, LayerGroupInfo.Mode.NAMED, null); try { String url = "wms?LAYERS=" + group.getName() + "&STYLES=&FORMAT=image%2Fpng&REQUEST=GetMap&SRS=EPSG%3A4326&WIDTH=256&HEIGHT=256&BBOX=0.0000,-0.0020,0.0035,0.0010"; BufferedImage image = getAsImage(url, "image/png"); assertPixel(image, 150, 160, Color.WHITE); // places assertPixel(image, 180, 16, COLOR_PLACES_GRAY); // lakes assertPixel(image, 90, 200, COLOR_LAKES_BLUE); } finally { catalog.remove(group); } } @Test public void testLayerGroupContainer() throws Exception { Catalog catalog = getCatalog(); LayerGroupInfo group = createLakesPlacesLayerGroup(catalog, LayerGroupInfo.Mode.CONTAINER, null); try { String url = "wms?LAYERS=" + group.getName() + "&STYLES=&FORMAT=image%2Fpng&REQUEST=GetMap&SRS=EPSG%3A4326&WIDTH=256&HEIGHT=256&BBOX=0.0000,-0.0020,0.0035,0.0010"; // this group is not meant to be called directly so we should get an exception MockHttpServletResponse resp = getAsServletResponse(url); assertEquals("text/xml", resp.getContentType()); Document dom = getAsDOM(url); assertEquals("ServiceExceptionReport", dom.getDocumentElement().getNodeName()); Element serviceException = (Element) dom.getDocumentElement().getElementsByTagName("ServiceException").item(0); assertEquals("LayerNotDefined", serviceException.getAttribute("code")); assertEquals("layers", serviceException.getAttribute("locator")); assertEquals("Could not find layer " + group.getName(), serviceException.getTextContent().trim()); } finally { catalog.remove(group); } } @Test public void testLayerGroupModeEo() throws Exception { Catalog catalog = getCatalog(); LayerGroupInfo group = createLakesPlacesLayerGroup(catalog, LayerGroupInfo.Mode.EO, catalog.getLayerByName(getLayerId(MockData.LAKES))); try { String url = "wms?LAYERS=" + group.getName() + "&STYLES=&FORMAT=image%2Fpng&REQUEST=GetMap&SRS=EPSG%3A4326&WIDTH=256&HEIGHT=256&BBOX=0.0000,-0.0020,0.0035,0.0010"; BufferedImage image = getAsImage(url, "image/png"); assertPixel(image, 150, 160, Color.WHITE); // no places assertPixel(image, 180, 16, Color.WHITE); // lakes assertPixel(image, 90, 200, COLOR_LAKES_BLUE); } finally { catalog.remove(group); } } @Test public void testWorkspaceQualifiedNoLayersError() throws Exception { Document dom = getAsDOM("sf/wms?bbox=" + bbox + "&styles=" + "&layers=" + "&format=image/png" + "&request=GetMap" + "&width=550" + "&height=250" + "&srs=EPSG:4326", Charset.defaultCharset().displayName()); assertEquals("ServiceExceptionReport", dom.getDocumentElement().getNodeName()); assertTrue(dom.getDocumentElement().getTextContent().contains("No LAYERS has been requested")); } @Test public void testSldExternalEntities() throws Exception { URL sldUrl = TestData.class.getResource("externalEntities.sld"); String url = "wms?bbox=" + bbox + "&styles=" + "&layers=" + layers + "&Format=image/png" + "&request=GetMap" + "&width=550" + "&height=250" + "&srs=EPSG:4326" + "&sld=" + sldUrl.toString(); WMS wms = new WMS(getGeoServer()); GeoServerInfo geoserverInfo = wms.getGeoServer().getGlobal(); try { // enable entities in external SLD files geoserverInfo.setXmlExternalEntitiesEnabled(true); getGeoServer().save(geoserverInfo); // if entities evaluation is enabled // the parser will try to read a file on the local file system // if the file is found, its content will be used to replace the entity // if the file is not found the parser will throw a FileNotFoundException String response = getAsString(url); assertTrue(response.indexOf("Error while getting SLD.") > -1); // disable entities geoserverInfo.setXmlExternalEntitiesEnabled(false); getGeoServer().save(geoserverInfo); // if entities evaluation is disabled // the parser will throw a MalformedURLException when it finds an entity response = getAsString(url); assertTrue(response.indexOf("Entity resolution disallowed") > -1); // try default: disabled entities geoserverInfo.setXmlExternalEntitiesEnabled(null); getGeoServer().save(geoserverInfo); // if entities evaluation is disabled // the parser will throw a MalformedURLException when it finds an entity response = getAsString(url); assertTrue(response.indexOf("Entity resolution disallowed") > -1); } finally { // default geoserverInfo.setXmlExternalEntitiesEnabled(null); getGeoServer().save(geoserverInfo); } } @Test public void testAllowedMimeTypes() throws Exception { WMSInfo wms = getWMS().getServiceInfo(); GetMapOutputFormat format = new RenderedImageMapOutputFormat(getWMS()); wms.getGetMapMimeTypes().add(format.getMimeType()); wms.setGetMapMimeTypeCheckingEnabled(true); getGeoServer().save(wms); // check mime type allowed MockHttpServletResponse response = getAsServletResponse("wms?bbox=" + bbox + "&styles=&layers=" + layers + "&Format=image/png" + "&request=GetMap" + "&width=550" + "&height=250" + "&srs=EPSG:4326&version=1.3.0"); checkImage(response); // check mime type not allowed String result = getAsString("wms?bbox=" + bbox + "&styles=&layers=" + layers + "&Format="+OpenLayersMapOutputFormat.MIME_TYPE+ "&request=GetMap" + "&width=550" + "&height=250" + "&srs=EPSG:4326&version=1.3.0"); assertTrue(result.indexOf("ForbiddenFormat") > 0); wms.getGetMapMimeTypes().clear(); wms.setGetMapMimeTypeCheckingEnabled(false); getGeoServer().save(wms); result = getAsString("wms?bbox=" + bbox + "&styles=&layers=" + layers + "&Format="+OpenLayersMapOutputFormat.MIME_TYPE+ "&request=GetMap" + "&width=550" + "&height=250" + "&srs=EPSG:4326&version=1.3.0"); assertTrue(result.indexOf("OpenLayers") > 0); } }