Skip to content

Commit ba27152

Browse files
charles-plantedmorissette
authored andcommitted
Add support for filters on group layers in WMS requests (fixes #5919)
* Add support for group layer with filter in WMS query * init the ows_request object in msMapLoadOWSParameters() * Added new msautotests and fixed one of the existing WMS FILTER tests
1 parent d945c8b commit ba27152

10 files changed

Lines changed: 79 additions & 40 deletions

mapobject.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -759,8 +759,7 @@ int msMapLoadOWSParameters(mapObj *map, cgiRequestObj *request,
759759
int result, i = 0;
760760
owsRequestObj ows_request;
761761

762-
ows_request.numlayers = 0;
763-
ows_request.enabled_layers = NULL;
762+
msOWSInitRequestObj(&ows_request);
764763

765764

766765
version = msOWSParseVersionString(wmtver);
@@ -778,8 +777,7 @@ int msMapLoadOWSParameters(mapObj *map, cgiRequestObj *request,
778777
request->ParamValues, request->NumParams, wms_exception_format,
779778
wms_request, &ows_request);
780779

781-
if (ows_request.numlayers > 0)
782-
msFree(ows_request.enabled_layers);
780+
msOWSClearRequestObj(&ows_request);
783781

784782
return result;
785783

mapows.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,12 @@
5050
** msOWSInitRequestObj() initializes an owsRequestObj; i.e: sets
5151
** all internal pointers to NULL.
5252
*/
53-
static void msOWSInitRequestObj(owsRequestObj *ows_request)
53+
void msOWSInitRequestObj(owsRequestObj *ows_request)
5454
{
5555
ows_request->numlayers = 0;
56+
ows_request->numwmslayerargs = 0;
5657
ows_request->enabled_layers = NULL;
58+
ows_request->layerwmsfilterindex = NULL;
5759

5860
ows_request->service = NULL;
5961
ows_request->version = NULL;
@@ -65,9 +67,10 @@ static void msOWSInitRequestObj(owsRequestObj *ows_request)
6567
** msOWSClearRequestObj() releases all resources associated with an
6668
** owsRequestObj.
6769
*/
68-
static void msOWSClearRequestObj(owsRequestObj *ows_request)
70+
void msOWSClearRequestObj(owsRequestObj *ows_request)
6971
{
7072
msFree(ows_request->enabled_layers);
73+
msFree(ows_request->layerwmsfilterindex);
7174
msFree(ows_request->service);
7275
msFree(ows_request->version);
7376
msFree(ows_request->request);

mapows.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,9 @@ typedef struct {
129129
/* owsRequestObj: Represent a OWS specific request with its enabled layers */
130130
typedef struct {
131131
int numlayers;
132+
int numwmslayerargs;
132133
int *enabled_layers;
134+
int *layerwmsfilterindex;
133135

134136
char *service;
135137
char *version;
@@ -147,6 +149,10 @@ MS_DLL_EXPORT const char * msOWSLookupMetadata2(hashTableObj *pri,
147149
hashTableObj *sec,
148150
const char *namespaces,
149151
const char *name);
152+
153+
void msOWSInitRequestObj(owsRequestObj *ows_request);
154+
void msOWSClearRequestObj(owsRequestObj *ows_request);
155+
150156
MS_DLL_EXPORT int msOWSRequestIsEnabled(mapObj *map, layerObj *layer,
151157
const char *namespaces, const char *name, int check_all_layers);
152158
MS_DLL_EXPORT void msOWSRequestLayersEnabled(mapObj *map, const char *namespaces,

mapwms.c

Lines changed: 39 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ int msWMSApplyTime(mapObj *map, int version, char *time, char *wms_exception_for
258258
}
259259
} else {
260260
/*
261-
** Check to see if there is a list of possible patterns defined. If it is the case, use
261+
** Check to see if there is a list of possible patterns defined. If it is the case, use
262262
** it to set the time pattern to use for the request.
263263
**
264264
** Last argument is set to TRUE (checkonly) to not trigger the patterns info setting, rather
@@ -310,7 +310,7 @@ int msWMSApplyTime(mapObj *map, int version, char *time, char *wms_exception_for
310310
** Apply the FILTER parameter to layers (RFC118)
311311
*/
312312
int msWMSApplyFilter(mapObj *map, int version, const char *filter,
313-
int def_srs_needs_axis_swap, char *wms_exception_format)
313+
int def_srs_needs_axis_swap, char *wms_exception_format, owsRequestObj *ows_request)
314314
{
315315
int i=0, numlayers;
316316
int numfilters=0, curfilter=0;
@@ -324,20 +324,20 @@ int msWMSApplyFilter(mapObj *map, int version, const char *filter,
324324
if (!map)
325325
return MS_FAILURE;
326326

327-
/* Count number of requested layers
327+
/* Count number of requested layers / groups / etc.
328328
* Only layers with STATUS ON were in the LAYERS request param.
329329
* Layers with STATUS DEFAULT were set in the mapfile and are
330330
* not expected to have a corresponding filter in the request
331331
*/
332-
for(i=0, numlayers=0; i<map->numlayers; i++) {
333-
layerObj *lp=NULL;
332+
for(i=0, numlayers=0; i<map->numlayers; i++) {
333+
layerObj *lp=NULL;
334334

335-
if(map->layerorder[i] != -1) {
336-
lp = (GET_LAYER(map, map->layerorder[i]));
337-
if (lp->status == MS_ON)
338-
numlayers++;
339-
}
340-
}
335+
if(map->layerorder[i] != -1) {
336+
lp = (GET_LAYER(map, map->layerorder[i]));
337+
if (lp->status == MS_ON)
338+
numlayers++;
339+
}
340+
}
341341

342342
/* -------------------------------------------------------------------- */
343343
/* Parse the Filter parameter. If there are several Filter */
@@ -347,25 +347,21 @@ int msWMSApplyFilter(mapObj *map, int version, const char *filter,
347347
if (filter[0] == '(') {
348348
paszFilters = FLTSplitFilters(filter, &numfilters);
349349

350-
if ( paszFilters && numfilters > 0 && numlayers != numfilters ) {
351-
msFreeCharArray(paszFilters, numfilters);
352-
paszFilters = NULL;
353-
}
354350
} else if (numlayers == 1) {
355351
numfilters=1;
356352
paszFilters = (char **)msSmallMalloc(sizeof(char *)*numfilters);
357353
paszFilters[0] = msStrdup(filter);
358354
}
359355

360-
if (numlayers != numfilters) {
361-
msSetError(MS_WMSERR, "Wrong number of filter elements, one filter must be specified for each requested layer.",
356+
if (numfilters != ows_request->numwmslayerargs) {
357+
msSetError(MS_WMSERR, "Wrong number of filter elements, one filter must be specified for each requested layer or groups.",
362358
"msWMSApplyFilter" );
363359
msFreeCharArray(paszFilters, numfilters);
364360
return msWMSException(map, version, "InvalidParameterValue", wms_exception_format);
365361
}
366362

367363
/* We're good to go. Apply each filter to the corresponding layer */
368-
for(i=0, curfilter=0; i<map->numlayers && curfilter<numfilters; i++) {
364+
for(i=0; i<map->numlayers; i++) {
369365
layerObj *lp=NULL;
370366

371367
if(map->layerorder[i] != -1)
@@ -375,9 +371,10 @@ int msWMSApplyFilter(mapObj *map, int version, const char *filter,
375371
if (lp == NULL || lp->status != MS_ON)
376372
continue;
377373

374+
curfilter = ows_request->layerwmsfilterindex[lp->index];
375+
378376
/* Skip empty filters */
379377
if (paszFilters[curfilter][0] == '\0') {
380-
curfilter++;
381378
continue;
382379
}
383380

@@ -959,9 +956,9 @@ int msWMSLoadGetMapParams(mapObj *map, int nVersion,
959956
outputFormatObj *format = NULL;
960957
int validlayers = 0;
961958
char *styles = NULL;
962-
int numlayers = 0;
959+
int numwmslayerargs = 0;
963960
char **layers = NULL;
964-
int layerfound =0;
961+
int layerfound = MS_FALSE;
965962
int invalidlayers = 0;
966963
char epsgbuf[100];
967964
char srsbuffer[100];
@@ -1033,11 +1030,11 @@ int msWMSLoadGetMapParams(mapObj *map, int nVersion,
10331030
layerOrder = (int*)malloc(map->numlayers * sizeof(int));
10341031
MS_CHECK_ALLOC(layerOrder, map->numlayers * sizeof(int), MS_FAILURE)
10351032

1036-
layers = msStringSplit(values[i], ',', &numlayers);
1037-
if (layers==NULL || strlen(values[i]) <=0 || numlayers < 1) {
1038-
numlayers = 0;
1033+
layers = msStringSplit(values[i], ',', &numwmslayerargs);
1034+
if (layers==NULL || strlen(values[i]) <=0 || numwmslayerargs < 1) {
1035+
numwmslayerargs = 0;
10391036
if (sld_url == NULL && sld_body == NULL) {
1040-
msFreeCharArray(layers,numlayers);
1037+
msFreeCharArray(layers,numwmslayerargs);
10411038
msFree(layerOrder);
10421039
msSetError(MS_WMSERR, "At least one layer name required in LAYERS.",
10431040
"msWMSLoadGetMapParams()");
@@ -1048,8 +1045,8 @@ int msWMSLoadGetMapParams(mapObj *map, int nVersion,
10481045
if (nVersion >= OWS_1_3_0) {
10491046
layerlimit = msOWSLookupMetadata(&(map->web.metadata), "MO", "layerlimit");
10501047
if(layerlimit) {
1051-
if (numlayers > atoi(layerlimit)) {
1052-
msFreeCharArray(layers,numlayers);
1048+
if (numwmslayerargs > atoi(layerlimit)) {
1049+
msFreeCharArray(layers,numwmslayerargs);
10531050
msFree(layerOrder);
10541051
msSetError(MS_WMSERR, "Number of layers requested exceeds LayerLimit.",
10551052
"msWMSLoadGetMapParams()");
@@ -1079,8 +1076,16 @@ int msWMSLoadGetMapParams(mapObj *map, int nVersion,
10791076
isUsedInNestedGroup = (int*)msSmallCalloc(map->numlayers, sizeof(int));
10801077
msWMSPrepareNestedGroups(map, nVersion, nestedGroups, numNestedGroups, isUsedInNestedGroup);
10811078

1082-
for (k=0; k<numlayers; k++) {
1083-
layerfound = 0;
1079+
if (ows_request->layerwmsfilterindex != NULL)
1080+
msFree(ows_request->layerwmsfilterindex);
1081+
ows_request->layerwmsfilterindex = (int*)msSmallMalloc(map->numlayers * sizeof(int));
1082+
for(j=0; j<map->numlayers; j++) {
1083+
ows_request->layerwmsfilterindex[j] = -1;
1084+
}
1085+
ows_request->numwmslayerargs = numwmslayerargs;
1086+
1087+
for (k=0; k<numwmslayerargs; k++) {
1088+
layerfound = MS_FALSE;
10841089
for (j=0; j<map->numlayers; j++) {
10851090
/* Turn on selected layers only. */
10861091
if ( ((GET_LAYER(map, j)->name &&
@@ -1096,11 +1101,12 @@ int msWMSLoadGetMapParams(mapObj *map, int nVersion,
10961101
GET_LAYER(map, j)->status = MS_ON;
10971102
}
10981103
}
1104+
ows_request->layerwmsfilterindex[j] = k; /* Assign the corresponding filter */
10991105
validlayers++;
1100-
layerfound = 1;
1106+
layerfound = MS_TRUE;
11011107
}
11021108
}
1103-
if (layerfound == 0 && numlayers>0)
1109+
if (layerfound == MS_FALSE && numwmslayerargs>0)
11041110
invalidlayers++;
11051111

11061112
}
@@ -1123,7 +1129,7 @@ int msWMSLoadGetMapParams(mapObj *map, int nVersion,
11231129
}
11241130

11251131
free(layerOrder);
1126-
msFreeCharArray(layers, numlayers);
1132+
msFreeCharArray(layers, numwmslayerargs);
11271133
} else if (strcasecmp(names[i], "STYLES") == 0) {
11281134
styles = values[i];
11291135

@@ -1887,7 +1893,7 @@ this request. Check wms/ows_enable_request settings.",
18871893
return msWMSException(map, nVersion, NULL, wms_exception_format);
18881894
}
18891895

1890-
if (msWMSApplyFilter(map, nVersion, filter, need_axis_swap, wms_exception_format) == MS_FAILURE) {
1896+
if (msWMSApplyFilter(map, nVersion, filter, need_axis_swap, wms_exception_format, ows_request) == MS_FAILURE) {
18911897
return MS_FAILURE;/* msWMSException(map, nVersion, "InvalidFilterRequest"); */
18921898
}
18931899
}
8.42 KB
Loading
25.9 KB
Loading
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version='1.0' encoding="UTF-8" standalone="no" ?>
2+
<ServiceExceptionReport version="1.3.0" xmlns="http://www.opengis.net/ogc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/ogc http://ogc.dmsolutions.ca/wms/1.3.0/exceptions_1_3_0.xsd">
3+
<ServiceException code="InvalidParameterValue">
4+
msWMSApplyFilter: WMS server error. Wrong number of filter elements, one filter must be specified for each requested layer or groups.
5+
</ServiceException>
6+
</ServiceExceptionReport>
24.1 KB
Loading
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version='1.0' encoding="UTF-8" standalone="no" ?>
2+
<ServiceExceptionReport version="1.3.0" xmlns="http://www.opengis.net/ogc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/ogc http://ogc.dmsolutions.ca/wms/1.3.0/exceptions_1_3_0.xsd">
3+
<ServiceException code="LayerNotDefined">
4+
msWMSLoadGetMapParams(): WMS server error. Invalid layer(s) given in the LAYERS parameter. A layer might be disabled for this request. Check wms/ows_enable_request settings.
5+
</ServiceException>
6+
</ServiceExceptionReport>

msautotest/wxs/wms_filter.map

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,18 @@
2222
# GetMap 1.3.0 two layers, one without and one with filter
2323
# RUN_PARMS: wms_filter_getmap130_emptyfilter.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&CRS=EPSG%3A4326&BBOX=40,-70,50,-60&WIDTH=400&HEIGHT=400&LAYERS=road,popplace&STYLES=&FORMAT=image%2Fpng&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&EXCEPTIONS=INIMAGE&FILTER=()(<Filter><PropertyIsEqualTo><PropertyName>NAME</PropertyName><Literal>Charlottetown</Literal></PropertyIsEqualTo></Filter>)" > [RESULT_DEMIME]
2424
#
25+
# GetMap 1.3.0 one group layer
26+
# RUN_PARMS: wms_filter_getmap130_one_group.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&CRS=EPSG%3A4326&BBOX=40,-70,50,-60&WIDTH=400&HEIGHT=400&LAYERS=feature_group&STYLES=&FORMAT=image%2Fpng&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&EXCEPTIONS=INIMAGE&FILTER=(<Filter><PropertyIsEqualTo><PropertyName>REG_CODE</PropertyName><Literal>12</Literal></PropertyIsEqualTo></Filter>)" > [RESULT_DEMIME]
27+
#
28+
# GetMap 1.3.0 one group layer and one layer
29+
# RUN_PARMS: wms_filter_getmap130_group_and_layer.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&CRS=EPSG%3A4326&BBOX=40,-70,50,-60&WIDTH=400&HEIGHT=400&LAYERS=feature_group,road&STYLES=&FORMAT=image%2Fpng&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&EXCEPTIONS=INIMAGE&FILTER=(<Filter><PropertyIsEqualTo><PropertyName>REG_CODE</PropertyName><Literal>12</Literal></PropertyIsEqualTo></Filter>)(<Filter><DWithin><PropertyName>Geometry</PropertyName><gml:Point><gml:coordinates>46,-63</gml:coordinates></gml:Point><Distance units='dd'>0.5</Distance></DWithin></Filter>)" > [RESULT_DEMIME]
30+
#
31+
# GetMap 1.3.0 one group one layer missing a filter
32+
# RUN_PARMS: wms_filter_getmap130_group_missingFilter.txt [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&CRS=EPSG%3A4326&BBOX=40,-70,50,-60&WIDTH=400&HEIGHT=400&LAYERS=feature_group,road&STYLES=&FORMAT=image%2Fpng&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&EXCEPTIONS=XML&FILTER=(<Filter><PropertyIsEqualTo><PropertyName>REG_CODE</PropertyName><Literal>12</Literal></PropertyIsEqualTo></Filter>)" > [RESULT_DEMIME]
33+
#
34+
# GetMap 1.3.0 filter with invalid group name
35+
# RUN_PARMS: wms_filter_getmap130_wrong_group.txt [MAPSERV] QUERY_STRING="map=[MAPFILE]&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&CRS=EPSG%3A4326&BBOX=40,-70,50,-60&WIDTH=400&HEIGHT=400&LAYERS=inval_group&STYLES=&FORMAT=image%2Fpng&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&EXCEPTIONS=XML&FILTER=(<Filter><PropertyIsEqualTo><PropertyName>REG_CODE</PropertyName><Literal>12</Literal></PropertyIsEqualTo></Filter>)" > [RESULT_DEMIME]
36+
#
2537

2638
MAP
2739

@@ -71,12 +83,13 @@ END
7183
LAYER
7284
NAME province
7385
DATA province
86+
GROUP feature_group
7487
METADATA
7588
"wms_title" "province"
7689
"wms_description" "province"
7790
"wms_result_fields" "NAME_E YEAR_EST AREA_KMSQ"
7891
END
79-
TYPE POINT
92+
TYPE POLYGON
8093
STATUS ON
8194
PROJECTION
8295
"init=epsg:3978"
@@ -96,6 +109,7 @@ END # Layer
96109
LAYER
97110
NAME popplace
98111
DATA popplace
112+
GROUP feature_group
99113
METADATA
100114
"wms_title" "popplace"
101115
"wms_description" "Cities of I.P.E."

0 commit comments

Comments
 (0)