Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WMTS CITE compliance fixes #1342

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,28 @@ public String toString() {
str.append(" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
str.append(
" xsi:schemaLocation=\"http://www.opengis.net/ows/1.1 http://geowebcache.org/schema/ows/1.1.0/owsExceptionReport.xsd\">\n");
str.append(" <Exception exceptionCode=\"" + exceptionCode + "\" locator=\"" + locator + "\">\n");
if (locator != null) {
str.append(" <Exception exceptionCode=\"" + exceptionCode + "\" locator=\"" + locator + "\">\n");
} else {
str.append(" <Exception exceptionCode=\"" + exceptionCode + "\">\n");
}

str.append(" <ExceptionText>" + exceptionText + "</ExceptionText>\n");
str.append(" </Exception>\n");
str.append("</ExceptionReport>\n");

return str.toString();
}

public int getHttpCode() {
return httpCode;
}

public String getExceptionCode() {
return exceptionCode;
}

public String getLocator() {
return locator;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,10 @@ private void serviceIdentification(XMLBuilder xml, ServiceInformation servInfo)
appendTag(xml, "ows:Title", servInfo.getTitle(), "Web Map Tile Service - GeoWebCache");
appendTag(xml, "ows:Abstract", servInfo.getDescription(), null);

if (servInfo != null && servInfo.getKeywords() != null) {
// a keywords element cannot be empty
if (servInfo != null
&& servInfo.getKeywords() != null
&& !servInfo.getKeywords().isEmpty()) {
xml.indentElement("ows:Keywords");
Iterator<String> keywordIter = servInfo.getKeywords().iterator();
while (keywordIter.hasNext()) {
Expand Down Expand Up @@ -453,17 +456,17 @@ private void layer(XMLBuilder xml, TileLayer layer, String baseurl, Set<GridSet>

appendTag(xml, "ows:Identifier", layer.getName(), null);

// WMTS 1.0 Layer is a ows:DatasetDescriptionSummary, which in turn can hold a ows:Metadata,
// which finally
// has the xlink:simpleAttrs attribute group, see https://www.w3.org/1999/xlink.xsd.
// Unfortunately those links do not have a format attribute, so we can't use them for
// metadata links.
if (layer.getMetadataURLs() != null) {
for (MetadataURL metadataURL : layer.getMetadataURLs()) {
xml.indentElement("MetadataURL");
xml.attribute("type", metadataURL.getType());
xml.simpleElement("Format", metadataURL.getFormat(), true);
xml.indentElement("OnlineResource")
.attribute("xmlns:xlink", "http://www.w3.org/1999/xlink")
xml.indentElement("ows:Metadata")
.attribute("xlink:type", "simple")
.attribute("xlink:href", metadataURL.getUrl().toString())
.endElement();
xml.endElement();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,12 @@ protected void writeResponse(RuntimeStats stats) throws OWSException {
TileLayer layer = convTile.getLayer();

GridSet gridSet = convTile.getGridSubset().getGridSet();
if (gridSet.getTileHeight() < j || j < 0) {
if (gridSet.getTileHeight() <= j || j < 0) {
throw new OWSException(
400, "PointIJOutOfRange", "J", "J was " + j + ", must be between 0 and " + gridSet.getTileHeight());
}

if (gridSet.getTileWidth() < i || i < 0) {
if (gridSet.getTileWidth() <= i || i < 0) {
throw new OWSException(
400, "PointIJOutOfRange", "I", "I was " + i + ", must be between 0 and " + gridSet.getTileWidth());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import org.geowebcache.util.NullURLMangler;
import org.geowebcache.util.ServletUtils;
import org.geowebcache.util.URLMangler;
import org.springframework.http.MediaType;

public class WMTSService extends Service {

Expand Down Expand Up @@ -248,6 +249,21 @@ public Conveyor getConveyor(HttpServletRequest request, HttpServletResponse resp

public Conveyor getRestConveyor(HttpServletRequest request, HttpServletResponse response)
throws GeoWebCacheException, OWSException {
// CITE compliance, if the representation is not available a 406 should be returned
// This is also the behavior mandated by the HTTP standard
String accept = request.getHeader("Accept");
if (accept != null) {
List<MediaType> mediaTypes = MediaType.parseMediaTypes(accept);
boolean representationAvailable = false;
for (MediaType mediaType : mediaTypes) {
if (mediaType.includes(MediaType.APPLICATION_XML)) {
representationAvailable = true;
break;
}
}
if (!representationAvailable) throw new HttpErrorCodeException(406, "Representation not available");
}

final String path = request.getPathInfo();

// special simpler case for GetCapabilities
Expand Down Expand Up @@ -302,14 +318,13 @@ public Conveyor getKvpConveyor(HttpServletRequest request, HttpServletResponse r
// if provided handle accepted versions parameter
if (acceptedVersions != null) {
// we only support version 1.0.0, so make sure that's one of the accepted versions
String[] versions = acceptedVersions.split("\\s*,\\s*");
int foundIndex = Arrays.binarySearch(versions, "1.0.0");
if (foundIndex < 0) {
List<String> versions = Arrays.asList(acceptedVersions.split("\\s*,\\s*"));
if (!versions.contains("1.0.0")) {
// no supported version is accepted
throw new OWSException(
400,
"VersionNegotiationFailed",
null,
"null",
"List of versions in AcceptVersions parameter value, in GetCapabilities "
+ "operation request, did not include any version supported by this server.");
}
Expand Down Expand Up @@ -409,6 +424,8 @@ private ConveyorTile getTile(
}

MimeType mimeType = null;
// the format should be present and valid also for GetFeatureInfo, while in CITE compliance
// mode
if (reqType == RequestType.TILE) {
String format = values.get("format");
if (format == null) {
Expand Down Expand Up @@ -437,6 +454,14 @@ private ConveyorTile getTile(
"INFOFORMAT",
"Unable to determine requested INFOFORMAT, " + infoFormat);
}

if (isCiteCompliant() && !isRestRequest(request)) {
String format = values.get("format");
if (format == null) {
throw new OWSException(
400, "MissingParameterValue", "FORMAT", "Unable to determine requested FORMAT, " + format);
}
}
}

final String tilematrixset = values.get("tilematrixset");
Expand Down Expand Up @@ -485,7 +510,7 @@ private ConveyorTile getTile(
throw new OWSException(
400,
"TileOutOfRange",
"TILECOLUMN",
"TILECOL",
"Column " + x + " is out of range, min: " + gridCov[0] + " max:" + gridCov[2]);
}

Expand Down Expand Up @@ -621,7 +646,7 @@ ServerConfiguration getMainConfiguration() {
*
* @return TRUE if GWC main configuration or at least one of the WMTS extensions forces CITE compliance
*/
private boolean isCiteCompliant() {
protected boolean isCiteCompliant() {
// let's see if main GWC configuration forces WMTS implementation to be CITE compliant
if (mainConfiguration != null && mainConfiguration.isWmtsCiteCompliant()) {
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
Expand Down Expand Up @@ -64,6 +65,7 @@
import org.geowebcache.layer.meta.VectorLayerMetadata;
import org.geowebcache.mime.ApplicationMime;
import org.geowebcache.mime.MimeType;
import org.geowebcache.service.HttpErrorCodeException;
import org.geowebcache.service.OWSException;
import org.geowebcache.stats.RuntimeStats;
import org.geowebcache.storage.StorageBroker;
Expand Down Expand Up @@ -142,6 +144,15 @@ public void testGetCap() throws Exception {
doc);
}

@Test
public void testGetCapInvalidFormat() throws Exception {
MockHttpServletRequest req = new MockHttpServletRequest();
req.setPathInfo("geowebcache/service/wmts/rest/WMTSCapabilities.xml");
req.addHeader("Accept", "invalid/format");
HttpErrorCodeException exception = assertThrows(HttpErrorCodeException.class, () -> dispatch(req));
assertEquals(406, exception.getErrorCode());
}

@Test
public void testGetTileWithStyle() throws Exception {
MockHttpServletRequest req = new MockHttpServletRequest();
Expand Down
Loading
Loading