1 /******************************************************************************
2 * $Id$
3 *
4 * Project: MapServer
5 * Purpose: OGC Web Services (WMS, WFS) support functions
6 * Author: Daniel Morissette, DM Solutions Group (morissette@dmsolutions.ca)
7 *
8 ******************************************************************************
9 * Copyright (c) 1996-2005 Regents of the University of Minnesota.
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included in
19 * all copies of this Software or works derived from this Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 * DEALINGS IN THE SOFTWARE.
28 ****************************************************************************/
29
30 #include "mapserver.h"
31 #include "maptime.h"
32 #include "maptemplate.h"
33 #include "mapows.h"
34
35 #if defined(USE_LIBXML2)
36 #include "maplibxml2.h"
37 #else
38 #include "cpl_minixml.h"
39 #include "cpl_error.h"
40 #endif
41 #include "mapowscommon.h"
42
43 #include <ctype.h> /* isalnum() */
44 #include <stdarg.h>
45 #include <assert.h>
46
47
48
49 /*
50 ** msOWSInitRequestObj() initializes an owsRequestObj; i.e: sets
51 ** all internal pointers to NULL.
52 */
msOWSInitRequestObj(owsRequestObj * ows_request)53 void msOWSInitRequestObj(owsRequestObj *ows_request)
54 {
55 ows_request->numlayers = 0;
56 ows_request->numwmslayerargs = 0;
57 ows_request->enabled_layers = NULL;
58 ows_request->layerwmsfilterindex = NULL;
59
60 ows_request->service = NULL;
61 ows_request->version = NULL;
62 ows_request->request = NULL;
63 ows_request->document = NULL;
64 }
65
66 /*
67 ** msOWSClearRequestObj() releases all resources associated with an
68 ** owsRequestObj.
69 */
msOWSClearRequestObj(owsRequestObj * ows_request)70 void msOWSClearRequestObj(owsRequestObj *ows_request)
71 {
72 msFree(ows_request->enabled_layers);
73 msFree(ows_request->layerwmsfilterindex);
74 msFree(ows_request->service);
75 msFree(ows_request->version);
76 msFree(ows_request->request);
77 if(ows_request->document) {
78 #if defined(USE_LIBXML2)
79 xmlFreeDoc(ows_request->document);
80 xmlCleanupParser();
81 #else
82 CPLDestroyXMLNode(ows_request->document);
83 #endif
84 }
85 }
86
87 #if defined(USE_LIBXML2) && LIBXML_VERSION < 20900
88 static int bExternalEntityAsked = MS_FALSE;
dummyEntityLoader(const char * URL,const char * ID,xmlParserCtxtPtr context)89 static xmlParserInputPtr dummyEntityLoader(const char * URL,
90 const char * ID,
91 xmlParserCtxtPtr context )
92 {
93 bExternalEntityAsked = MS_TRUE;
94 return NULL;
95 }
96 #endif
97
98 /*
99 ** msOWSPreParseRequest() parses a cgiRequestObj either with GET/KVP
100 ** or with POST/XML. Only SERVICE, VERSION (or WMTVER) and REQUEST are
101 ** being determined, all WxS (or SOS) specific parameters are parsed
102 ** within the according handler.
103 ** The results are saved within an owsRequestObj. If the request was
104 ** transmitted with POST/XML, either the document (if compiled with
105 ** libxml2) or the root CPLXMLNode is saved to the ows_request->document
106 ** field.
107 ** Returns MS_SUCCESS upon success, MS_FAILURE if severe errors occurred
108 ** or MS_DONE, if the service could not be determined.
109 */
msOWSPreParseRequest(cgiRequestObj * request,owsRequestObj * ows_request)110 static int msOWSPreParseRequest(cgiRequestObj *request,
111 owsRequestObj *ows_request)
112 {
113 /* decide if KVP or XML */
114 if (request->type == MS_GET_REQUEST || (request->type == MS_POST_REQUEST
115 && request->contenttype && strncmp(request->contenttype, "application/x-www-form-urlencoded", strlen("application/x-www-form-urlencoded")) == 0)) {
116 int i;
117 /* parse KVP parameters service, version and request */
118 for (i = 0; i < request->NumParams; ++i) {
119 if (ows_request->service == NULL &&
120 EQUAL(request->ParamNames[i], "SERVICE")) {
121 ows_request->service = msStrdup(request->ParamValues[i]);
122 } else if (ows_request->version == NULL &&
123 (EQUAL(request->ParamNames[i], "VERSION")
124 || EQUAL(request->ParamNames[i], "WMTVER"))) { /* for WMS */
125 ows_request->version = msStrdup(request->ParamValues[i]);
126 } else if (ows_request->request == NULL &&
127 EQUAL(request->ParamNames[i], "REQUEST")) {
128 ows_request->request = msStrdup(request->ParamValues[i]);
129 }
130
131 /* stop if we have all necessary parameters */
132 if(ows_request->service && ows_request->version && ows_request->request) {
133 break;
134 }
135 }
136 } else if (request->type == MS_POST_REQUEST) {
137 #if defined(USE_LIBXML2)
138 xmlNodePtr root = NULL;
139 #if LIBXML_VERSION < 20900
140 xmlExternalEntityLoader oldExternalEntityLoader;
141 #endif
142 #else
143 CPLXMLNode *temp;
144 #endif
145 if (!request->postrequest || !strlen(request->postrequest)) {
146 msSetError(MS_OWSERR, "POST request is empty.",
147 "msOWSPreParseRequest()");
148 return MS_FAILURE;
149 }
150 #if defined(USE_LIBXML2)
151 #if LIBXML_VERSION < 20900
152 oldExternalEntityLoader = xmlGetExternalEntityLoader();
153 /* to avoid XML External Entity vulnerability with libxml2 < 2.9 */
154 xmlSetExternalEntityLoader (dummyEntityLoader);
155 bExternalEntityAsked = MS_FALSE;
156 #endif
157 /* parse to DOM-Structure with libxml2 and get the root element */
158 ows_request->document = xmlParseMemory(request->postrequest,
159 strlen(request->postrequest));
160 #if LIBXML_VERSION < 20900
161 xmlSetExternalEntityLoader (oldExternalEntityLoader);
162 if( bExternalEntityAsked )
163 {
164 msSetError(MS_OWSERR, "XML parsing error: %s",
165 "msOWSPreParseRequest()", "External entity fetch");
166 return MS_FAILURE;
167 }
168 #endif
169 if (ows_request->document == NULL
170 || (root = xmlDocGetRootElement(ows_request->document)) == NULL) {
171 xmlErrorPtr error = xmlGetLastError();
172 msSetError(MS_OWSERR, "XML parsing error: %s",
173 "msOWSPreParseRequest()", error->message);
174 return MS_FAILURE;
175 }
176
177 /* Get service, version and request from root */
178 ows_request->service = (char *) xmlGetProp(root, BAD_CAST "service");
179 ows_request->version = (char *) xmlGetProp(root, BAD_CAST "version");
180 ows_request->request = msStrdup((char *) root->name);
181
182 #else
183 /* parse with CPLXML */
184 ows_request->document = CPLParseXMLString(request->postrequest);
185 if (ows_request->document == NULL) {
186 msSetError(MS_OWSERR, "XML parsing error: %s",
187 "msOWSPreParseRequest()", CPLGetLastErrorMsg());
188 return MS_FAILURE;
189 }
190
191 /* remove all namespaces */
192 CPLStripXMLNamespace(ows_request->document, NULL, 1);
193 for (temp = ows_request->document;
194 temp != NULL;
195 temp = temp->psNext) {
196
197 if (temp->eType == CXT_Element) {
198 const char *service, *version;
199 ows_request->request = msStrdup(temp->pszValue);
200
201 if ((service = CPLGetXMLValue(temp, "service", NULL)) != NULL) {
202 ows_request->service = msStrdup(service);
203 }
204 if ((version = CPLGetXMLValue(temp, "version", NULL)) != NULL) {
205 ows_request->version = msStrdup(version);
206 }
207 continue;
208 }
209 }
210 #endif /* defined(USE_LIBXML2) */
211 } else {
212 msSetError(MS_OWSERR, "Unknown request method. Use either GET or POST.",
213 "msOWSPreParseRequest()");
214 return MS_FAILURE;
215 }
216
217 /* certain WMS requests do not require the service parameter */
218 /* see: http://trac.osgeo.org/mapserver/ticket/2531 */
219 if (ows_request->service == NULL
220 && ows_request->request != NULL) {
221 if (EQUAL(ows_request->request, "GetMap")
222 || EQUAL(ows_request->request, "GetFeatureInfo")) {
223 ows_request->service = msStrdup("WMS");
224 } else { /* service could not be determined */
225 return MS_DONE;
226 }
227 }
228
229 return MS_SUCCESS;
230 }
231
232 /*
233 ** msOWSDispatch() is the entry point for any OWS request (WMS, WFS, ...)
234 ** - If this is a valid request then it is processed and MS_SUCCESS is returned
235 ** on success, or MS_FAILURE on failure.
236 ** - If force_ows_mode is true then an exception will be produced if the
237 ** request is not recognized as a valid request.
238 ** - If force_ows_mode is false and this does not appear to be a valid OWS
239 ** request then MS_DONE is returned and MapServer is expected to process
240 ** this as a regular MapServer (traditional CGI) request.
241 */
msOWSDispatch(mapObj * map,cgiRequestObj * request,int ows_mode)242 int msOWSDispatch(mapObj *map, cgiRequestObj *request, int ows_mode)
243 {
244 int status = MS_DONE, force_ows_mode = 0;
245 owsRequestObj ows_request;
246
247 if (!request) {
248 return status;
249 }
250
251 force_ows_mode = (ows_mode == OWS || ows_mode == WFS);
252
253 msOWSInitRequestObj(&ows_request);
254 switch(msOWSPreParseRequest(request, &ows_request)) {
255 case MS_FAILURE: /* a severe error occurred */
256 return MS_FAILURE;
257 case MS_DONE:
258 /* OWS Service could not be determined */
259 /* continue for now */
260 status = MS_DONE;
261 }
262
263 if (ows_request.service == NULL) {
264 #ifdef USE_LIBXML2
265 if (ows_request.request && EQUAL(ows_request.request, "GetMetadata")) {
266 status = msMetadataDispatch(map, request, &ows_request);
267 msOWSClearRequestObj(&ows_request);
268 return status;
269 }
270 #endif
271 #ifdef USE_WFS_SVR
272 if( msOWSLookupMetadata(&(map->web.metadata), "FO", "cite_wfs2") != NULL ) {
273 status = msWFSException(map, "service", MS_OWS_ERROR_MISSING_PARAMETER_VALUE, NULL );
274 }
275 else
276 #endif
277
278 /* exit if service is not set */
279 if(force_ows_mode) {
280 msSetError( MS_MISCERR,
281 "OWS Common exception: exceptionCode=MissingParameterValue, locator=SERVICE, ExceptionText=SERVICE parameter missing.",
282 "msOWSDispatch()");
283 status = MS_FAILURE;
284 } else {
285 status = MS_DONE;
286 }
287 } else if (EQUAL(ows_request.service, "WMS")) {
288 #ifdef USE_WMS_SVR
289 status = msWMSDispatch(map, request, &ows_request, MS_FALSE);
290 #else
291 msSetError( MS_WMSERR,
292 "SERVICE=WMS requested, but WMS support not configured in MapServer.",
293 "msOWSDispatch()" );
294 #endif
295 } else if (EQUAL(ows_request.service, "WFS")) {
296 #ifdef USE_WFS_SVR
297 status = msWFSDispatch(map, request, &ows_request, (ows_mode == WFS));
298 #else
299 msSetError( MS_WFSERR,
300 "SERVICE=WFS requested, but WFS support not configured in MapServer.",
301 "msOWSDispatch()" );
302 #endif
303 } else if (EQUAL(ows_request.service, "WCS")) {
304 #ifdef USE_WCS_SVR
305 status = msWCSDispatch(map, request, &ows_request);
306 #else
307 msSetError( MS_WCSERR,
308 "SERVICE=WCS requested, but WCS support not configured in MapServer.",
309 "msOWSDispatch()" );
310 #endif
311 } else if (EQUAL(ows_request.service, "SOS")) {
312 #ifdef USE_SOS_SVR
313 status = msSOSDispatch(map, request, &ows_request);
314 #else
315 msSetError( MS_SOSERR,
316 "SERVICE=SOS requested, but SOS support not configured in MapServer.",
317 "msOWSDispatch()" );
318 #endif
319 } else if(force_ows_mode) {
320 msSetError( MS_MISCERR,
321 "OWS Common exception: exceptionCode=InvalidParameterValue, locator=SERVICE, ExceptionText=SERVICE parameter value invalid.",
322 "msOWSDispatch()");
323 status = MS_FAILURE;
324 }
325
326 msOWSClearRequestObj(&ows_request);
327 return status;
328 }
329
330 /*
331 ** msOWSIpParse()
332 **
333 ** Parse the IP address or range into a binary array.
334 ** Supports ipv4 and ipv6 addresses
335 ** Ranges can be specified using the CIDR notation (ie: 192.100.100.0/24)
336 **
337 ** Returns the parsed of the IP (4 or 16).
338 */
msOWSIpParse(const char * ip,unsigned char * ip1,unsigned char * mask)339 int msOWSIpParse(const char* ip, unsigned char* ip1, unsigned char* mask)
340 {
341 int len = 0, masklen, seps;
342
343 if (msCountChars((char*)ip, '.') == 3) {
344 /* ipv4 */
345 unsigned char* val = ip1;
346 len = 1;
347 masklen = 32;
348 *val = 0;
349 while (*ip) {
350 if (*ip >= '0' && *ip <= '9')
351 (*val) = 10 * (*val) + (*ip - '0');
352 else if (*ip == '.') {
353 ++val;
354 *val = 0;
355 ++len;
356 }
357 else if (*ip == '/')
358 {
359 masklen = atoi(ip+1);
360 if (masklen > 32)
361 masklen = 32;
362 break;
363 }
364 else
365 break;
366 ++ip;
367 }
368 if (len != 4)
369 return 0;
370 /* write mask */
371 if (mask) {
372 memset(mask, 0, len);
373 val = mask;
374 while (masklen) {
375 if (masklen >= 8) {
376 *val = 0xff;
377 masklen -= 8;
378 }
379 else {
380 *val = - ((unsigned char)pow(2, 8 - masklen));
381 break;
382 }
383 ++val;
384 }
385 }
386 }
387 else if ((seps = msCountChars((char*)ip, ':')) > 1 && seps < 8) {
388 /* ipv6 */
389 unsigned short* val = (unsigned short*)ip1;
390 len = 2;
391 masklen = 128;
392 *val = 0;
393 while (*ip) {
394 if (*ip >= '0' && *ip <= '9')
395 (*val) = 16 * (*val) + (*ip - '0');
396 else if (*ip >= 'a' && *ip <= 'f')
397 (*val) = 16 * (*val) + (*ip - 'a' + 10);
398 else if (*ip >= 'A' && *ip <= 'F')
399 (*val) = 16 * (*val) + (*ip - 'A' + 10);
400 else if (*ip == ':') {
401 ++ip;
402 ++val;
403 len += 2;
404 *val = 0;
405 if (*ip == ':') {
406 /* insert 0 values */
407 while (seps <= 7) {
408 ++val;
409 len += 2;
410 *val = 0;
411 ++seps;
412 }
413 }
414 else
415 continue;
416 }
417 else if (*ip == '/')
418 {
419 masklen = atoi(ip+1);
420 if (masklen > 128)
421 masklen = 128;
422 break;
423 }
424 else
425 break;
426 ++ip;
427 }
428 if (len != 16)
429 return 0;
430 /* write mask */
431 if (mask) {
432 memset(mask, 0, len);
433 val = (unsigned short*)mask;
434 while (masklen) {
435 if (masklen >= 16) {
436 *val = 0xffff;
437 masklen -= 16;
438 }
439 else {
440 *val = - ((unsigned short)pow(2, 16 - masklen));
441 break;
442 }
443 ++val;
444 }
445 }
446 }
447
448 return len;
449 }
450
451 /*
452 ** msOWSIpInList()
453 **
454 ** Check if an ip is in a space separated list of IP addresses/ranges.
455 ** Supports ipv4 and ipv6 addresses
456 ** Ranges can be specified using the CIDR notation (ie: 192.100.100.0/24)
457 **
458 ** Returns MS_TRUE if the IP is found.
459 */
msOWSIpInList(const char * ip_list,const char * ip)460 int msOWSIpInList(const char *ip_list, const char* ip)
461 {
462 int i, j, numips, iplen;
463 unsigned char ip1[16];
464 unsigned char ip2[16];
465 unsigned char mask[16];
466 char** ips;
467
468 /* Parse input IP */
469 iplen = msOWSIpParse(ip, (unsigned char*)&ip1, NULL);
470 if (iplen != 4 && iplen != 16) /* ipv4 or ipv6 */
471 return MS_FALSE;
472
473 ips = msStringSplit(ip_list, ' ', &numips);
474 if (ips) {
475 for (i = 0; i < numips; i++) {
476 if (msOWSIpParse(ips[i], (unsigned char*)&ip2, (unsigned char*)&mask) == iplen)
477 {
478 for (j = 0; j < iplen; j++) {
479 if ((ip1[j] & mask[j]) != (ip2[j] & mask[j]))
480 break;
481 }
482 if (j == iplen) {
483 msFreeCharArray(ips, numips);
484 return MS_TRUE; /* match found */
485 }
486 }
487 }
488 msFreeCharArray(ips, numips);
489 }
490
491 return MS_FALSE;
492 }
493
494 /*
495 ** msOWSIpDisabled()
496 **
497 ** Check if an ip is in a list specified in the metadata section.
498 **
499 ** Returns MS_TRUE if the IP is found.
500 */
msOWSIpInMetadata(const char * ip_list,const char * ip)501 int msOWSIpInMetadata(const char *ip_list, const char* ip)
502 {
503 FILE *stream;
504 char buffer[MS_BUFFER_LENGTH];
505 int found = MS_FALSE;
506
507 if (strncasecmp(ip_list, "file:", 5) == 0) {
508 stream = fopen(ip_list + 5, "r");
509 if(stream) {
510 found = MS_FALSE;
511 while(fgets(buffer, MS_BUFFER_LENGTH, stream)) {
512 if(msOWSIpInList(buffer, ip)) {
513 found = MS_TRUE;
514 break;
515 }
516 }
517 fclose(stream);
518 }
519 }
520 else {
521 if(msOWSIpInList(ip_list, ip))
522 found = MS_TRUE;
523 }
524 return found;
525 }
526
527 /*
528 ** msOWSIpDisabled()
529 **
530 ** Check if the layers are enabled or disabled by IP list.
531 **
532 ** 'namespaces' is a string with a letter for each namespace to lookup
533 ** in the order they should be looked up. e.g. "MO" to lookup wms_ and ows_
534 ** If namespaces is NULL then this function just does a regular metadata
535 ** lookup.
536 **
537 ** Returns the disabled flag.
538 */
msOWSIpDisabled(hashTableObj * metadata,const char * namespaces,const char * ip)539 int msOWSIpDisabled(hashTableObj *metadata, const char *namespaces, const char* ip)
540 {
541 const char *ip_list;
542 int disabled = MS_FALSE;
543
544 if (!ip)
545 return MS_FALSE; /* no endpoint ip */
546
547 ip_list = msOWSLookupMetadata(metadata, namespaces, "allowed_ip_list");
548 if (!ip_list)
549 ip_list = msOWSLookupMetadata(metadata, "O", "allowed_ip_list");
550
551 if (ip_list) {
552 disabled = MS_TRUE;
553 if (msOWSIpInMetadata(ip_list, ip))
554 disabled = MS_FALSE;
555 }
556
557 ip_list = msOWSLookupMetadata(metadata, namespaces, "denied_ip_list");
558 if (!ip_list)
559 ip_list = msOWSLookupMetadata(metadata, "O", "denied_ip_list");
560
561 if (ip_list && msOWSIpInMetadata(ip_list, ip))
562 disabled = MS_TRUE;
563
564 return disabled;
565 }
566
567 /*
568 ** msOWSRequestIsEnabled()
569 **
570 ** Check if a layer is visible for a specific OWS request.
571 **
572 ** 'namespaces' is a string with a letter for each namespace to lookup in
573 ** the order they should be looked up. e.g. "MO" to lookup wms_ and ows_ If
574 ** namespaces is NULL then this function just does a regular metadata
575 ** lookup. If check_all_layers is set to MS_TRUE, the function will check
576 ** all layers to see if the request is enable. (returns as soon as one is found) */
msOWSRequestIsEnabled(mapObj * map,layerObj * layer,const char * namespaces,const char * request,int check_all_layers)577 int msOWSRequestIsEnabled(mapObj *map, layerObj *layer,
578 const char *namespaces, const char *request, int check_all_layers)
579 {
580 int disabled = MS_FALSE; /* explicitly disabled flag */
581 const char *enable_request;
582 const char *remote_ip;
583
584 if (request == NULL)
585 return MS_FALSE;
586
587 remote_ip = getenv("REMOTE_ADDR");
588
589 /* First, we check in the layer metadata */
590 if (layer && check_all_layers == MS_FALSE) {
591 enable_request = msOWSLookupMetadata(&layer->metadata, namespaces, "enable_request");
592 if (msOWSParseRequestMetadata(enable_request, request, &disabled))
593 return MS_TRUE;
594 if (disabled) return MS_FALSE;
595
596 enable_request = msOWSLookupMetadata(&layer->metadata, "O", "enable_request");
597 if (msOWSParseRequestMetadata(enable_request, request, &disabled))
598 return MS_TRUE;
599 if (disabled) return MS_FALSE;
600
601 if (msOWSIpDisabled(&layer->metadata, namespaces, remote_ip))
602 return MS_FALSE;
603 }
604
605 if (map && (check_all_layers == MS_FALSE || map->numlayers == 0)) {
606 /* then we check in the map metadata */
607 enable_request = msOWSLookupMetadata(&map->web.metadata, namespaces, "enable_request");
608 if (msOWSParseRequestMetadata(enable_request, request, &disabled))
609 return MS_TRUE;
610 if (disabled) return MS_FALSE;
611
612 enable_request = msOWSLookupMetadata(&map->web.metadata, "O", "enable_request");
613 if (msOWSParseRequestMetadata(enable_request, request, &disabled))
614 return MS_TRUE;
615 if (disabled) return MS_FALSE;
616
617 if (msOWSIpDisabled(&map->web.metadata, namespaces, remote_ip))
618 return MS_FALSE;
619 }
620
621 if (map && check_all_layers == MS_TRUE) {
622 int i, globally_enabled = MS_FALSE;
623 enable_request = msOWSLookupMetadata(&map->web.metadata, namespaces, "enable_request");
624 globally_enabled = msOWSParseRequestMetadata(enable_request, request, &disabled);
625
626 if (!globally_enabled && !disabled) {
627 enable_request = msOWSLookupMetadata(&map->web.metadata, "O", "enable_request");
628 globally_enabled = msOWSParseRequestMetadata(enable_request, request, &disabled);
629 }
630
631 if (globally_enabled && msOWSIpDisabled(&map->web.metadata, namespaces, remote_ip))
632 globally_enabled = MS_FALSE;
633
634 /* Check all layers */
635 for(i=0; i<map->numlayers; i++) {
636 int result = MS_FALSE;
637 layerObj *lp;
638 lp = (GET_LAYER(map, i));
639
640 enable_request = msOWSLookupMetadata(&lp->metadata, namespaces, "enable_request");
641 result = msOWSParseRequestMetadata(enable_request, request, &disabled);
642 if (!result && disabled) continue; /* if the request has been explicitly set to disabled, continue */
643
644 if (!result && !disabled) { /* if the request has not been found in the wms metadata, */
645 /* check the ows namespace */
646
647 enable_request = msOWSLookupMetadata(&lp->metadata, "O", "enable_request");
648 result = msOWSParseRequestMetadata(enable_request, request, &disabled);
649 if (!result && disabled) continue;
650 }
651
652 if (msOWSIpDisabled(&lp->metadata, namespaces, remote_ip))
653 continue;
654
655 if (result || (!disabled && globally_enabled))
656 return MS_TRUE;
657 }
658
659 if (!disabled && globally_enabled)
660 return MS_TRUE;
661 }
662
663 return MS_FALSE;
664 }
665
666 /*
667 ** msOWSRequestLayersEnabled()
668 **
669 ** Check if the layers are visible for a specific OWS request.
670 **
671 ** 'namespaces' is a string with a letter for each namespace to lookup
672 ** in the order they should be looked up. e.g. "MO" to lookup wms_ and ows_
673 ** If namespaces is NULL then this function just does a regular metadata
674 ** lookup.
675 **
676 ** Generates an array of the layer ids enabled.
677 */
msOWSRequestLayersEnabled(mapObj * map,const char * namespaces,const char * request,owsRequestObj * ows_request)678 void msOWSRequestLayersEnabled(mapObj *map, const char *namespaces,
679 const char *request, owsRequestObj *ows_request)
680 {
681 int disabled = MS_FALSE; /* explicitly disabled flag */
682 int globally_enabled = MS_FALSE;
683 const char *enable_request;
684 const char *remote_ip;
685
686 if (ows_request->numlayers > 0)
687 msFree(ows_request->enabled_layers);
688
689 ows_request->numlayers = 0;
690 ows_request->enabled_layers = NULL;
691
692 if (request == NULL || (map == NULL) || (map->numlayers <= 0))
693 return;
694
695 remote_ip = getenv("REMOTE_ADDR");
696
697 enable_request = msOWSLookupMetadata(&map->web.metadata, namespaces, "enable_request");
698 globally_enabled = msOWSParseRequestMetadata(enable_request, request, &disabled);
699
700 if (!globally_enabled && !disabled) {
701 enable_request = msOWSLookupMetadata(&map->web.metadata, "O", "enable_request");
702 globally_enabled = msOWSParseRequestMetadata(enable_request, request, &disabled);
703 }
704
705 if (globally_enabled && msOWSIpDisabled(&map->web.metadata, namespaces, remote_ip))
706 globally_enabled = MS_FALSE;
707
708 if (map->numlayers) {
709 int i, layers_size = map->numlayers; /* for most of cases, this will be relatively small */
710
711 ows_request->enabled_layers = (int*)msSmallMalloc(sizeof(int)*layers_size);
712
713 for(i=0; i<map->numlayers; i++) {
714 int result = MS_FALSE;
715 layerObj *lp;
716 lp = (GET_LAYER(map, i));
717
718 enable_request = msOWSLookupMetadata(&lp->metadata, namespaces, "enable_request");
719 result = msOWSParseRequestMetadata(enable_request, request, &disabled);
720 if (!result && disabled) continue; /* if the request has been explicitly set to disabled, continue */
721
722 if (!result && !disabled) { /* if the request has not been found in the wms metadata, */
723 /* check the ows namespace */
724
725 enable_request = msOWSLookupMetadata(&lp->metadata, "O", "enable_request");
726 result = msOWSParseRequestMetadata(enable_request, request, &disabled);
727 if (!result && disabled) continue;
728 }
729
730 if (msOWSIpDisabled(&lp->metadata, namespaces, remote_ip))
731 continue;
732
733 if (result || (!disabled && globally_enabled)) {
734 ows_request->enabled_layers[ows_request->numlayers] = lp->index;
735 ows_request->numlayers++;
736 }
737 }
738
739 if (ows_request->numlayers == 0) {
740 msFree(ows_request->enabled_layers);
741 ows_request->enabled_layers = NULL;
742 }
743 }
744 }
745
746 /* msOWSParseRequestMetadata
747 *
748 * This function parse a enable_request metadata string and check if the
749 * given request is present and enabled.
750 */
msOWSParseRequestMetadata(const char * metadata,const char * request,int * disabled)751 int msOWSParseRequestMetadata(const char *metadata, const char *request, int *disabled)
752 {
753 char requestBuffer[32];
754 int wordFlag = MS_FALSE;
755 int disableFlag = MS_FALSE;
756 int allFlag = MS_FALSE;
757 char *bufferPtr, *ptr = NULL;
758 int i;
759 size_t len = 0;
760
761 *disabled = MS_FALSE;
762
763 if (metadata == NULL)
764 return MS_FALSE;
765
766 ptr = (char*)metadata;
767 len = strlen(ptr);
768 requestBuffer[0] = '\0';
769 bufferPtr = requestBuffer;
770
771 for (i=0; i<=len; ++i,++ptr) {
772
773 if (!wordFlag && isspace(*ptr))
774 continue;
775
776 wordFlag = MS_TRUE;
777
778 if (*ptr == '!') {
779 disableFlag = MS_TRUE;
780 continue;
781 } else if ( (*ptr == ' ') || (*ptr != '\0' && ptr[1] == '\0')) { /* end of word */
782 if (ptr[1] == '\0' && *ptr != ' ') {
783 *bufferPtr = *ptr;
784 ++bufferPtr;
785 }
786
787 *bufferPtr = '\0';
788 if (strcasecmp(request, requestBuffer) == 0) {
789 *disabled = MS_TRUE; /* explicitly found, will stop the process in msOWSRequestIsEnabled() */
790 return (disableFlag ? MS_FALSE:MS_TRUE);
791 } else {
792 if (strcmp("*", requestBuffer) == 0) { /* check if we read the all flag */
793 if (disableFlag)
794 *disabled = MS_TRUE;
795 allFlag = disableFlag ? MS_FALSE:MS_TRUE;
796 }
797 /* reset flags */
798 wordFlag = MS_FALSE;
799 disableFlag = MS_FALSE;
800 bufferPtr = requestBuffer;
801 }
802 } else {
803 *bufferPtr = *ptr;
804 ++bufferPtr;
805 }
806 }
807
808 return allFlag;
809 }
810
811 /*
812 ** msOWSLookupMetadata()
813 **
814 ** Attempts to lookup a given metadata name in multiple OWS namespaces.
815 **
816 ** 'namespaces' is a string with a letter for each namespace to lookup
817 ** in the order they should be looked up. e.g. "MO" to lookup wms_ and ows_
818 ** If namespaces is NULL then this function just does a regular metadata
819 ** lookup.
820 */
msOWSLookupMetadata(hashTableObj * metadata,const char * namespaces,const char * name)821 const char *msOWSLookupMetadata(hashTableObj *metadata,
822 const char *namespaces, const char *name)
823 {
824 const char *value = NULL;
825
826 if (namespaces == NULL) {
827 value = msLookupHashTable(metadata, (char*)name);
828 } else {
829 char buf[100] = "ows_";
830
831 strlcpy(buf+4, name, 96);
832
833 while (value == NULL && *namespaces != '\0') {
834 switch (*namespaces) {
835 case 'O': /* ows_... */
836 buf[0] = 'o';
837 buf[1] = 'w';
838 buf[2] = 's';
839 break;
840 case 'M': /* wms_... */
841 buf[0] = 'w';
842 buf[1] = 'm';
843 buf[2] = 's';
844 break;
845 case 'F': /* wfs_... */
846 buf[0] = 'w';
847 buf[1] = 'f';
848 buf[2] = 's';
849 break;
850 case 'C': /* wcs_... */
851 buf[0] = 'w';
852 buf[1] = 'c';
853 buf[2] = 's';
854 break;
855 case 'G': /* gml_... */
856 buf[0] = 'g';
857 buf[1] = 'm';
858 buf[2] = 'l';
859 break;
860 case 'S': /* sos_... */
861 buf[0] = 's';
862 buf[1] = 'o';
863 buf[2] = 's';
864 break;
865 default:
866 /* We should never get here unless an invalid code (typo) is */
867 /* present in the code, but since this happened before... */
868 msSetError(MS_WMSERR,
869 "Unsupported metadata namespace code (%c).",
870 "msOWSLookupMetadata()", *namespaces );
871 assert(MS_FALSE);
872 return NULL;
873 }
874
875 value = msLookupHashTable(metadata, buf);
876 namespaces++;
877 }
878 }
879
880 return value;
881 }
882
883
884 /*
885 ** msOWSLookupMetadataWithLanguage()
886 **
887 ** Attempts to lookup a given metadata name in multiple OWS namespaces
888 ** for a specific language.
889 */
msOWSLookupMetadataWithLanguage(hashTableObj * metadata,const char * namespaces,const char * name,const char * validated_language)890 const char *msOWSLookupMetadataWithLanguage(hashTableObj *metadata,
891 const char *namespaces, const char *name, const char* validated_language)
892 {
893 const char *value = NULL;
894
895 if ( name && validated_language ) {
896 size_t bufferSize = strlen(name)+strlen(validated_language)+2;
897 char *name2 = (char *) msSmallMalloc( bufferSize );
898 snprintf(name2, bufferSize, "%s.%s", name, validated_language);
899 value = msOWSLookupMetadata(metadata, namespaces, name2);
900 free(name2);
901 }
902
903 if ( name && !value ) {
904 value = msOWSLookupMetadata(metadata, namespaces, name);
905 }
906
907
908 return value;
909 }
910
911 /*
912 ** msOWSLookupMetadata2()
913 **
914 ** Attempts to lookup a given metadata name in multiple hashTables, and
915 ** in multiple OWS namespaces within each. First searches the primary
916 ** table and if no result is found, attempts the search using the
917 ** secondary (fallback) table.
918 **
919 ** 'namespaces' is a string with a letter for each namespace to lookup
920 ** in the order they should be looked up. e.g. "MO" to lookup wms_ and ows_
921 ** If namespaces is NULL then this function just does a regular metadata
922 ** lookup.
923 */
msOWSLookupMetadata2(hashTableObj * pri,hashTableObj * sec,const char * namespaces,const char * name)924 const char *msOWSLookupMetadata2(hashTableObj *pri,
925 hashTableObj *sec,
926 const char *namespaces,
927 const char *name)
928 {
929 const char *result;
930
931 if ((result = msOWSLookupMetadata(pri, namespaces, name)) == NULL) {
932 /* Try the secondary table */
933 result = msOWSLookupMetadata(sec, namespaces, name);
934 }
935
936 return result;
937 }
938
939
940 /* msOWSParseVersionString()
941 **
942 ** Parse a version string in the format "a.b.c" or "a.b" and return an
943 ** integer in the format 0x0a0b0c suitable for regular integer comparisons.
944 **
945 ** Returns one of OWS_VERSION_NOTSET or OWS_VERSION_BADFORMAT if version
946 ** could not be parsed.
947 */
msOWSParseVersionString(const char * pszVersion)948 int msOWSParseVersionString(const char *pszVersion)
949 {
950 char **digits = NULL;
951 int numDigits = 0;
952
953 if (pszVersion) {
954 int nVersion = 0;
955 digits = msStringSplit(pszVersion, '.', &numDigits);
956 if (digits == NULL || numDigits < 2 || numDigits > 3) {
957 msSetError(MS_OWSERR,
958 "Invalid version (%s). Version must be in the "
959 "format 'x.y' or 'x.y.z'",
960 "msOWSParseVersionString()", pszVersion);
961 if (digits)
962 msFreeCharArray(digits, numDigits);
963 return OWS_VERSION_BADFORMAT;
964 }
965
966 nVersion = atoi(digits[0])*0x010000;
967 nVersion += atoi(digits[1])*0x0100;
968 if (numDigits > 2)
969 nVersion += atoi(digits[2]);
970
971 msFreeCharArray(digits, numDigits);
972
973 return nVersion;
974 }
975
976 return OWS_VERSION_NOTSET;
977 }
978
979 /* msOWSGetVersionString()
980 **
981 ** Returns a OWS version string in the format a.b.c from the integer
982 ** version value passed as argument (0x0a0b0c)
983 **
984 ** Fills in the pszBuffer and returns a reference to it. Recommended buffer
985 ** size is OWS_VERSION_MAXLEN chars.
986 */
msOWSGetVersionString(int nVersion,char * pszBuffer)987 const char *msOWSGetVersionString(int nVersion, char *pszBuffer)
988 {
989
990 if (pszBuffer)
991 snprintf(pszBuffer, OWS_VERSION_MAXLEN-1, "%d.%d.%d",
992 (nVersion/0x10000)%0x100, (nVersion/0x100)%0x100, nVersion%0x100);
993
994 return pszBuffer;
995 }
996
997
998 #if defined(USE_WMS_SVR) || defined (USE_WFS_SVR) || defined (USE_WCS_SVR) || defined(USE_SOS_SVR) || defined(USE_WMS_LYR) || defined(USE_WFS_LYR)
999
1000 /*
1001 ** msRenameLayer()
1002 */
msRenameLayer(layerObj * lp,int count)1003 static int msRenameLayer(layerObj *lp, int count)
1004 {
1005 char *newname;
1006 newname = (char*)malloc((strlen(lp->name)+5)*sizeof(char));
1007 if (!newname) {
1008 msSetError(MS_MEMERR, NULL, "msRenameLayer()");
1009 return MS_FAILURE;
1010 }
1011 sprintf(newname, "%s_%2.2d", lp->name, count);
1012 free(lp->name);
1013 lp->name = newname;
1014
1015 return MS_SUCCESS;
1016 }
1017
1018 /*
1019 ** msOWSMakeAllLayersUnique()
1020 */
msOWSMakeAllLayersUnique(mapObj * map)1021 int msOWSMakeAllLayersUnique(mapObj *map)
1022 {
1023 int i, j;
1024
1025 /* Make sure all layers in the map file have valid and unique names */
1026 for(i=0; i<map->numlayers; i++) {
1027 int count=1;
1028 for(j=i+1; j<map->numlayers; j++) {
1029 if (GET_LAYER(map, i)->name == NULL || GET_LAYER(map, j)->name == NULL) {
1030 continue;
1031 }
1032 if (strcasecmp(GET_LAYER(map, i)->name, GET_LAYER(map, j)->name) == 0 &&
1033 msRenameLayer((GET_LAYER(map, j)), ++count) != MS_SUCCESS) {
1034 return MS_FAILURE;
1035 }
1036 }
1037
1038 /* Don't forget to rename the first layer if duplicates were found */
1039 if (count > 1 && msRenameLayer((GET_LAYER(map, i)), 1) != MS_SUCCESS) {
1040 return MS_FAILURE;
1041 }
1042 }
1043 return MS_SUCCESS;
1044 }
1045
1046 /*
1047 ** msOWSNegotiateVersion()
1048 **
1049 ** returns the most suitable version an OWS is to support given a client
1050 ** version parameter.
1051 **
1052 ** supported_versions must be ordered from highest to lowest
1053 **
1054 ** Returns a version integer of the supported version
1055 **
1056 */
1057
msOWSNegotiateVersion(int requested_version,const int supported_versions[],int num_supported_versions)1058 int msOWSNegotiateVersion(int requested_version, const int supported_versions[], int num_supported_versions)
1059 {
1060 int i;
1061
1062 /* if version is not set return highest version */
1063 if (! requested_version)
1064 return supported_versions[0];
1065
1066 /* if the requested version is lower than the lowest version return the lowest version */
1067 if (requested_version < supported_versions[num_supported_versions-1])
1068 return supported_versions[num_supported_versions-1];
1069
1070 /* return the first entry that's lower than or equal to the requested version */
1071 for (i = 0; i < num_supported_versions; i++) {
1072 if (supported_versions[i] <= requested_version)
1073 return supported_versions[i];
1074 }
1075
1076 return requested_version;
1077 }
1078
1079 /*
1080 ** msOWSTerminateOnlineResource()
1081 **
1082 ** Append trailing "?" or "&" to an onlineresource URL if it doesn't have
1083 ** one already. The returned string is then ready to append GET parameters
1084 ** to it.
1085 **
1086 ** Returns a newly allocated string that should be freed by the caller or
1087 ** NULL in case of error.
1088 */
msOWSTerminateOnlineResource(const char * src_url)1089 char * msOWSTerminateOnlineResource(const char *src_url)
1090 {
1091 char *online_resource = NULL;
1092 size_t buffer_size = 0;
1093
1094 if (src_url == NULL)
1095 return NULL;
1096
1097 buffer_size = strlen(src_url)+2;
1098 online_resource = (char*) malloc(buffer_size);
1099
1100 if (online_resource == NULL) {
1101 msSetError(MS_MEMERR, NULL, "msOWSTerminateOnlineResource()");
1102 return NULL;
1103 }
1104
1105 strlcpy(online_resource, src_url, buffer_size);
1106
1107 /* Append trailing '?' or '&' if missing. */
1108 if (strchr(online_resource, '?') == NULL)
1109 strlcat(online_resource, "?", buffer_size);
1110 else {
1111 char *c;
1112 c = online_resource+strlen(online_resource)-1;
1113 if (*c != '?' && *c != '&')
1114 strlcpy(c+1, "&", buffer_size-strlen(online_resource));
1115 }
1116
1117 return online_resource;
1118 }
1119
1120 /*
1121 ** msOWSGetOnlineResource()
1122 **
1123 ** Return the online resource for this service. First try to lookup
1124 ** specified metadata, and if not found then try to build the URL ourselves.
1125 **
1126 ** Returns a newly allocated string that should be freed by the caller or
1127 ** NULL in case of error.
1128 */
msOWSGetOnlineResource(mapObj * map,const char * namespaces,const char * metadata_name,cgiRequestObj * req)1129 char * msOWSGetOnlineResource(mapObj *map, const char *namespaces, const char *metadata_name,
1130 cgiRequestObj *req)
1131 {
1132 const char *value;
1133 char *online_resource = NULL;
1134
1135 /* We need this script's URL, including hostname. */
1136 /* Default to use the value of the "onlineresource" metadata, and if not */
1137 /* set then build it: "http://$(SERVER_NAME):$(SERVER_PORT)$(SCRIPT_NAME)?" */
1138 /* (+append the map=... param if it was explicitly passed in QUERY_STRING) */
1139 /* */
1140 if ((value = msOWSLookupMetadata(&(map->web.metadata), namespaces, metadata_name))) {
1141 online_resource = msOWSTerminateOnlineResource(value);
1142 } else {
1143 if ((online_resource = msBuildOnlineResource(map, req)) == NULL) {
1144 msSetError(MS_CGIERR, "Impossible to establish server URL. Please set \"%s\" metadata.", "msOWSGetOnlineResource()", metadata_name);
1145 return NULL;
1146 }
1147 }
1148
1149 return online_resource;
1150 }
1151
1152
1153 /*
1154 ** msOWSGetOnlineResource()
1155 **
1156 ** Return the online resource for this service and add language parameter.
1157 **
1158 ** Returns a newly allocated string that should be freed by the caller or
1159 ** NULL in case of error.
1160 */
msOWSGetOnlineResource2(mapObj * map,const char * namespaces,const char * metadata_name,cgiRequestObj * req,const char * validated_language)1161 char * msOWSGetOnlineResource2(mapObj *map, const char *namespaces, const char *metadata_name,
1162 cgiRequestObj *req, const char* validated_language)
1163 {
1164 char *online_resource = msOWSGetOnlineResource(map, namespaces, metadata_name, req);
1165
1166 if ( online_resource && validated_language ) {
1167 /* online_resource is already terminated, so we can simply add language=...& */
1168 /* but first we need to make sure that online_resource has enough capacity */
1169 online_resource = (char *)msSmallRealloc(online_resource, strlen(online_resource) + strlen(validated_language) + 11);
1170 strcat(online_resource, "language=");
1171 strcat(online_resource, validated_language);
1172 strcat(online_resource, "&");
1173 }
1174
1175 return online_resource;
1176 }
1177
1178 /* msOWSGetSchemasLocation()
1179 **
1180 ** schemas location is the root of the web tree where all WFS-related
1181 ** schemas can be found on this server. These URLs must exist in order
1182 ** to validate xml.
1183 **
1184 ** Use value of "ows_schemas_location" metadata, if not set then
1185 ** return ".." as a default
1186 */
msOWSGetSchemasLocation(mapObj * map)1187 const char *msOWSGetSchemasLocation(mapObj *map)
1188 {
1189 const char *schemas_location;
1190
1191 schemas_location = msLookupHashTable(&(map->web.metadata),
1192 "ows_schemas_location");
1193 if (schemas_location == NULL)
1194 schemas_location = OWS_DEFAULT_SCHEMAS_LOCATION;
1195
1196 return schemas_location;
1197 }
1198
1199 /* msOWSGetInspireSchemasLocation()
1200 **
1201 ** schemas location is the root of the web tree where all Inspire-related
1202 ** schemas can be found on this server. These URLs must exist in order
1203 ** to validate xml.
1204 **
1205 ** Use value of "inspire_schemas_location" metadata
1206 */
msOWSGetInspireSchemasLocation(mapObj * map)1207 const char *msOWSGetInspireSchemasLocation(mapObj *map)
1208 {
1209 const char *schemas_location;
1210
1211 schemas_location = msLookupHashTable(&(map->web.metadata),
1212 "inspire_schemas_location");
1213 if (schemas_location == NULL)
1214 schemas_location = "http://inspire.ec.europa.eu/schemas";
1215
1216 return schemas_location;
1217 }
1218
1219 /* msOWSGetLanguage()
1220 **
1221 ** returns the language via MAP/WEB/METADATA/ows_language
1222 **
1223 ** Use value of "ows_language" metadata, if not set then
1224 ** return "undefined" as a default
1225 */
msOWSGetLanguage(mapObj * map,const char * context)1226 const char *msOWSGetLanguage(mapObj *map, const char *context)
1227 {
1228 const char *language;
1229
1230 /* if this is an exception, MapServer always returns Exception
1231 messages in en-US
1232 */
1233 if (strcmp(context,"exception") == 0) {
1234 language = MS_ERROR_LANGUAGE;
1235 }
1236 /* if not, fetch language from mapfile metadata */
1237 else {
1238 language = msLookupHashTable(&(map->web.metadata), "ows_language");
1239
1240 if (language == NULL) {
1241 language = "undefined";
1242 }
1243 }
1244 return language;
1245 }
1246
1247 /* msOWSGetLanguageList
1248 **
1249 ** Returns the list of languages that this service supports
1250 **
1251 ** Use value of "languages" metadata (comma-separated list), or NULL if not set
1252 **
1253 ** Returns a malloced char** of length numitems which must be freed
1254 ** by the caller, or NULL (with numitems = 0)
1255 */
msOWSGetLanguageList(mapObj * map,const char * namespaces,int * numitems)1256 char **msOWSGetLanguageList(mapObj *map, const char *namespaces, int *numitems)
1257 {
1258
1259 const char *languages = NULL;
1260
1261 languages = msOWSLookupMetadata(&(map->web.metadata), namespaces, "languages");
1262 if (languages && strlen(languages) > 0) {
1263 return msStringSplit(languages, ',', numitems);
1264 } else {
1265 *numitems = 0;
1266 return NULL;
1267 }
1268 }
1269
1270 /* msOWSGetLanguageFromList
1271 **
1272 ** Returns a language according to the language requested by the client
1273 **
1274 ** If the requested language is in the languages metadata then use it,
1275 ** otherwise ignore it and use the defaul language, which is the first entry in
1276 ** the languages metadata list. Calling with a NULL requested_langauge
1277 ** therefore returns this default language. If the language metadata list is
1278 ** not defined then the language is set to NULL.
1279 **
1280 ** Returns a malloced char* which must be freed by the caller, or NULL
1281 */
msOWSGetLanguageFromList(mapObj * map,const char * namespaces,const char * requested_language)1282 char *msOWSGetLanguageFromList(mapObj *map, const char *namespaces, const char *requested_language)
1283 {
1284 int num_items = 0;
1285 char **languages = msOWSGetLanguageList(map, namespaces, &num_items);
1286 char *language = NULL;
1287
1288 if( languages && num_items > 0 ) {
1289 if ( !requested_language || !msStringInArray( requested_language, languages, num_items) ) {
1290 language = msStrdup(languages[0]);
1291 } else {
1292 language = msStrdup(requested_language);
1293 }
1294 }
1295 msFreeCharArray(languages, num_items);
1296
1297 return language;
1298 }
1299
1300
1301 /* msOWSLanguageNegotiation
1302 **
1303 ** Returns a language according to the accepted languages requested by the client
1304 **
1305 ** Returns a malloced char* which must be freed by the caller, or NULL
1306 */
msOWSLanguageNegotiation(mapObj * map,const char * namespaces,char ** accept_languages,int num_accept_languages)1307 char *msOWSLanguageNegotiation(mapObj *map, const char *namespaces, char **accept_languages, int num_accept_languages)
1308 {
1309 int num_languages = 0;
1310 char **languages = NULL;
1311 char *result_language = NULL;
1312
1313 languages = msOWSGetLanguageList(map, namespaces, &num_languages);
1314
1315 if (languages && num_languages > 0) {
1316 int i;
1317 for (i = 0; i < num_accept_languages; ++i) {
1318 const char *accept_language = accept_languages[i];
1319
1320 /* '*' means any language */
1321 if (EQUAL(accept_language, "*")) {
1322 result_language = msStrdup(languages[0]);
1323 break;
1324 } else if (msStringInArray(accept_language, languages, num_languages)) {
1325 result_language = msStrdup(accept_language);
1326 break;
1327 }
1328 }
1329
1330 if (result_language == NULL) {
1331 result_language = msStrdup(languages[0]);
1332 }
1333 }
1334
1335 msFreeCharArray(languages, num_languages);
1336 return result_language;
1337 }
1338
1339
1340 /* msOWSPrintInspireCommonExtendedCapabilities
1341 **
1342 ** Output INSPIRE common extended capabilities items to stream
1343 ** The currently supported items are metadata and languages
1344 **
1345 ** tag_name is the name (including ns prefix) of the tag to include the whole
1346 ** extended capabilities block in
1347 **
1348 ** service is currently included for future compatibility when differing
1349 ** extended capabilities elements are included for different service types
1350 **
1351 ** Returns a status code; MS_NOERR if all ok, action_if_not_found otherwise
1352 */
msOWSPrintInspireCommonExtendedCapabilities(FILE * stream,mapObj * map,const char * namespaces,int action_if_not_found,const char * tag_name,const char * tag_ns,const char * validated_language,const OWSServiceType service)1353 int msOWSPrintInspireCommonExtendedCapabilities(FILE *stream, mapObj *map, const char *namespaces,
1354 int action_if_not_found, const char *tag_name, const char* tag_ns,
1355 const char *validated_language, const OWSServiceType service)
1356 {
1357
1358 int metadataStatus = 0;
1359 int languageStatus = 0;
1360
1361 if( tag_ns )
1362 msIO_fprintf(stream, " <%s %s>\n", tag_name, tag_ns);
1363 else
1364 msIO_fprintf(stream, " <%s>\n", tag_name);
1365
1366 metadataStatus = msOWSPrintInspireCommonMetadata(stream, map, namespaces, action_if_not_found, service);
1367 languageStatus = msOWSPrintInspireCommonLanguages(stream, map, namespaces, action_if_not_found, validated_language);
1368
1369 msIO_fprintf(stream, " </%s>\n", tag_name);
1370
1371 return (metadataStatus != MS_NOERR) ? metadataStatus : languageStatus;
1372 }
1373
1374 /* msOWSPrintInspireCommonMetadata
1375 **
1376 ** Output INSPIRE common metadata items to a stream
1377 **
1378 ** Returns a status code; MS_NOERR if all OK, action_if_not_found otherwise
1379 */
msOWSPrintInspireCommonMetadata(FILE * stream,mapObj * map,const char * namespaces,int action_if_not_found,const OWSServiceType service)1380 int msOWSPrintInspireCommonMetadata(FILE *stream, mapObj *map, const char *namespaces,
1381 int action_if_not_found, const OWSServiceType service)
1382 {
1383
1384 int status = MS_NOERR;
1385 const char *inspire_capabilities = NULL;
1386
1387 inspire_capabilities = msOWSLookupMetadata(&(map->web.metadata), namespaces, "inspire_capabilities");
1388
1389 if(!inspire_capabilities) {
1390 if (OWS_WARN == action_if_not_found) {
1391 msIO_fprintf(stream, "<!-- WARNING: missing metadata entry for 'inspire_capabilities', one of 'embed' and 'url' must be supplied. -->\n");
1392 }
1393 return action_if_not_found;
1394 }
1395 if (strcasecmp("url",inspire_capabilities) == 0) {
1396 if ( msOWSLookupMetadata(&(map->web.metadata), namespaces, "inspire_metadataurl_href") != NULL ) {
1397 msIO_fprintf(stream, " <inspire_common:MetadataUrl xsi:type=\"inspire_common:resourceLocatorType\">\n");
1398 msOWSPrintEncodeMetadata(stream, &(map->web.metadata), namespaces, "inspire_metadataurl_href", OWS_WARN, " <inspire_common:URL>%s</inspire_common:URL>\n", "");
1399 msOWSPrintEncodeMetadata(stream, &(map->web.metadata), namespaces, "inspire_metadataurl_format", OWS_WARN, " <inspire_common:MediaType>%s</inspire_common:MediaType>\n", "");
1400 msIO_fprintf(stream, " </inspire_common:MetadataUrl>\n");
1401 } else {
1402 status = action_if_not_found;
1403 if (OWS_WARN == action_if_not_found) {
1404 msIO_fprintf(stream, "<!-- WARNING: Mandatory metadata '%s%s' was missing in this context. -->\n", (namespaces?"..._":""), "inspire_metadataurl_href");
1405 }
1406 }
1407 } else if (strcasecmp("embed",inspire_capabilities) == 0) {
1408 msOWSPrintEncodeMetadata(stream, &(map->web.metadata), namespaces, "inspire_resourcelocator", OWS_WARN, " <inspire_common:ResourceLocator>\n <inspire_common:URL>%s</inspire_common:URL>\n </inspire_common:ResourceLocator>\n", NULL);
1409 msIO_fprintf(stream," <inspire_common:ResourceType>service</inspire_common:ResourceType>\n");
1410 msOWSPrintEncodeMetadata(stream, &(map->web.metadata), namespaces, "inspire_temporal_reference", OWS_WARN, " <inspire_common:TemporalReference>\n <inspire_common:DateOfLastRevision>%s</inspire_common:DateOfLastRevision>\n </inspire_common:TemporalReference>\n", "");
1411 msIO_fprintf(stream, " <inspire_common:Conformity>\n");
1412 msIO_fprintf(stream, " <inspire_common:Specification>\n");
1413 msIO_fprintf(stream, " <inspire_common:Title>-</inspire_common:Title>\n");
1414 msOWSPrintEncodeMetadata(stream, &(map->web.metadata), namespaces, "inspire_temporal_reference", OWS_NOERR, " <inspire_common:DateOfLastRevision>%s</inspire_common:DateOfLastRevision>\n", "");
1415 msIO_fprintf(stream, " </inspire_common:Specification>\n");
1416 msIO_fprintf(stream, " <inspire_common:Degree>notEvaluated</inspire_common:Degree>\n");
1417 msIO_fprintf(stream, " </inspire_common:Conformity>\n");
1418 msIO_fprintf(stream, " <inspire_common:MetadataPointOfContact>\n");
1419 msOWSPrintEncodeMetadata(stream, &(map->web.metadata), namespaces, "inspire_mpoc_name", OWS_WARN, " <inspire_common:OrganisationName>%s</inspire_common:OrganisationName>\n", "");
1420 msOWSPrintEncodeMetadata(stream, &(map->web.metadata), namespaces, "inspire_mpoc_email", OWS_WARN, " <inspire_common:EmailAddress>%s</inspire_common:EmailAddress>\n", "");
1421 msIO_fprintf(stream, " </inspire_common:MetadataPointOfContact>\n");
1422 msOWSPrintEncodeMetadata(stream, &(map->web.metadata), namespaces, "inspire_metadatadate", OWS_WARN, " <inspire_common:MetadataDate>%s</inspire_common:MetadataDate>\n", "");
1423 if( service == OWS_WFS || service == OWS_WCS )
1424 msIO_fprintf(stream," <inspire_common:SpatialDataServiceType>download</inspire_common:SpatialDataServiceType>\n");
1425 else
1426 msIO_fprintf(stream," <inspire_common:SpatialDataServiceType>view</inspire_common:SpatialDataServiceType>\n");
1427 msOWSPrintEncodeMetadata(stream, &(map->web.metadata), namespaces, "inspire_keyword", OWS_WARN, " <inspire_common:MandatoryKeyword>\n <inspire_common:KeywordValue>%s</inspire_common:KeywordValue>\n </inspire_common:MandatoryKeyword>\n", "");
1428 } else {
1429 status = action_if_not_found;
1430 if (OWS_WARN == action_if_not_found) {
1431 msIO_fprintf(stream, "<!-- WARNING: invalid value '%s' for 'inspire_capabilities', only 'embed' and 'url' are supported. -->\n", inspire_capabilities);
1432 }
1433 }
1434
1435 return status;
1436 }
1437
1438 /* msOWSPrintInspireCommonLanguages
1439 **
1440 ** Output INSPIRE supported languages block to stream
1441 **
1442 ** Returns a status code; MS_NOERR if all OK; action_if_not_found otherwise
1443 */
msOWSPrintInspireCommonLanguages(FILE * stream,mapObj * map,const char * namespaces,int action_if_not_found,const char * validated_language)1444 int msOWSPrintInspireCommonLanguages(FILE *stream, mapObj *map, const char *namespaces,
1445 int action_if_not_found, const char *validated_language)
1446 {
1447 char *buffer = NULL; /* temp variable for malloced strings that will need freeing */
1448 int status = MS_NOERR;
1449
1450 char *default_language = msOWSGetLanguageFromList(map, namespaces, NULL);
1451
1452 if(validated_language && default_language) {
1453 msIO_fprintf(stream, " <inspire_common:SupportedLanguages>\n");
1454 msIO_fprintf(stream, " <inspire_common:DefaultLanguage><inspire_common:Language>%s"
1455 "</inspire_common:Language></inspire_common:DefaultLanguage>\n",
1456 buffer = msEncodeHTMLEntities(default_language));
1457 msFree(buffer);
1458
1459 /* append _exclude to our default_language*/
1460 default_language = msSmallRealloc(default_language,strlen(default_language)+strlen("_exclude")+1);
1461 strcat(default_language,"_exclude");
1462
1463 msOWSPrintEncodeMetadataList(stream, &(map->web.metadata), namespaces, "languages", NULL, NULL,
1464 " <inspire_common:SupportedLanguage><inspire_common:Language>%s"
1465 "</inspire_common:Language></inspire_common:SupportedLanguage>\n", default_language);
1466 msIO_fprintf(stream, " </inspire_common:SupportedLanguages>\n");
1467 msIO_fprintf(stream, " <inspire_common:ResponseLanguage><inspire_common:Language>%s"
1468 "</inspire_common:Language></inspire_common:ResponseLanguage>\n", validated_language);
1469 } else {
1470 status = action_if_not_found;
1471 if (OWS_WARN == action_if_not_found) {
1472 msIO_fprintf(stream, "<!-- WARNING: Mandatory metadata '%s%s' was missing in this context. -->\n", (namespaces?"..._":""), "languages");
1473 }
1474 }
1475
1476 msFree(default_language);
1477
1478 return status;
1479 }
1480
1481 /*
1482 ** msOWSPrintMetadata()
1483 **
1484 ** Attempt to output a capability item. If corresponding metadata is not
1485 ** found then one of a number of predefined actions will be taken.
1486 ** If a default value is provided and metadata is absent then the
1487 ** default will be used.
1488 */
1489
msOWSPrintMetadata(FILE * stream,hashTableObj * metadata,const char * namespaces,const char * name,int action_if_not_found,const char * format,const char * default_value)1490 int msOWSPrintMetadata(FILE *stream, hashTableObj *metadata,
1491 const char *namespaces, const char *name,
1492 int action_if_not_found, const char *format,
1493 const char *default_value)
1494 {
1495 const char *value = NULL;
1496 int status = MS_NOERR;
1497
1498 if((value = msOWSLookupMetadata(metadata, namespaces, name)) != NULL) {
1499 msIO_fprintf(stream, format, value);
1500 } else {
1501 if (action_if_not_found == OWS_WARN) {
1502 msIO_fprintf(stream, "<!-- WARNING: Mandatory metadata '%s%s' was missing in this context. -->\n", (namespaces?"..._":""), name);
1503 status = action_if_not_found;
1504 }
1505
1506 if (default_value)
1507 msIO_fprintf(stream, format, default_value);
1508 }
1509
1510 return status;
1511 }
1512
1513
1514 /*
1515 ** msOWSPrintEncodeMetadata()
1516 **
1517 ** Attempt to output a capability item. If corresponding metadata is not
1518 ** found then one of a number of predefined actions will be taken.
1519 ** If a default value is provided and metadata is absent then the
1520 ** default will be used.
1521 ** Also encode the value with msEncodeHTMLEntities.
1522 */
1523
msOWSPrintEncodeMetadata(FILE * stream,hashTableObj * metadata,const char * namespaces,const char * name,int action_if_not_found,const char * format,const char * default_value)1524 int msOWSPrintEncodeMetadata(FILE *stream, hashTableObj *metadata,
1525 const char *namespaces, const char *name,
1526 int action_if_not_found,
1527 const char *format, const char *default_value)
1528 {
1529 return msOWSPrintEncodeMetadata2(stream, metadata, namespaces, name, action_if_not_found, format, default_value, NULL);
1530 }
1531
1532
1533 /*
1534 ** msOWSPrintEncodeMetadata2()
1535 **
1536 ** Attempt to output a capability item in the requested language.
1537 ** Fallback using no language parameter.
1538 */
msOWSPrintEncodeMetadata2(FILE * stream,hashTableObj * metadata,const char * namespaces,const char * name,int action_if_not_found,const char * format,const char * default_value,const char * validated_language)1539 int msOWSPrintEncodeMetadata2(FILE *stream, hashTableObj *metadata,
1540 const char *namespaces, const char *name,
1541 int action_if_not_found,
1542 const char *format, const char *default_value,
1543 const char *validated_language)
1544 {
1545 const char *value;
1546 char * pszEncodedValue=NULL;
1547 int status = MS_NOERR;
1548
1549 if((value = msOWSLookupMetadataWithLanguage(metadata, namespaces, name, validated_language))) {
1550 pszEncodedValue = msEncodeHTMLEntities(value);
1551 msIO_fprintf(stream, format, pszEncodedValue);
1552 free(pszEncodedValue);
1553 } else {
1554 if (action_if_not_found == OWS_WARN) {
1555 msIO_fprintf(stream, "<!-- WARNING: Mandatory metadata '%s%s%s%s' was missing in this context. -->\n", (namespaces?"..._":""), name, (validated_language?".":""), (validated_language?validated_language:""));
1556 status = action_if_not_found;
1557 }
1558
1559 if (default_value) {
1560 pszEncodedValue = msEncodeHTMLEntities(default_value);
1561 msIO_fprintf(stream, format, default_value);
1562 free(pszEncodedValue);
1563 }
1564 }
1565
1566 return status;
1567 }
1568
1569
1570 /*
1571 ** msOWSGetEncodeMetadata()
1572 **
1573 ** Equivalent to msOWSPrintEncodeMetadata. Returns en encoded value of the
1574 ** metadata or the default value.
1575 ** Caller should free the returned string.
1576 */
msOWSGetEncodeMetadata(hashTableObj * metadata,const char * namespaces,const char * name,const char * default_value)1577 char *msOWSGetEncodeMetadata(hashTableObj *metadata,
1578 const char *namespaces, const char *name,
1579 const char *default_value)
1580 {
1581 const char *value;
1582 char * pszEncodedValue=NULL;
1583 if((value = msOWSLookupMetadata(metadata, namespaces, name)))
1584 pszEncodedValue = msEncodeHTMLEntities(value);
1585 else if (default_value)
1586 pszEncodedValue = msEncodeHTMLEntities(default_value);
1587
1588 return pszEncodedValue;
1589 }
1590
1591
1592 /*
1593 ** msOWSPrintValidateMetadata()
1594 **
1595 ** Attempt to output a capability item. If corresponding metadata is not
1596 ** found then one of a number of predefined actions will be taken.
1597 ** If a default value is provided and metadata is absent then the
1598 ** default will be used.
1599 ** Also validate the value with msIsXMLTagValid.
1600 */
1601
msOWSPrintValidateMetadata(FILE * stream,hashTableObj * metadata,const char * namespaces,const char * name,int action_if_not_found,const char * format,const char * default_value)1602 int msOWSPrintValidateMetadata(FILE *stream, hashTableObj *metadata,
1603 const char *namespaces, const char *name,
1604 int action_if_not_found,
1605 const char *format, const char *default_value)
1606 {
1607 const char *value;
1608 int status = MS_NOERR;
1609
1610 if((value = msOWSLookupMetadata(metadata, namespaces, name))) {
1611 if(msIsXMLTagValid(value) == MS_FALSE)
1612 msIO_fprintf(stream, "<!-- WARNING: The value '%s' is not valid in a "
1613 "XML tag context. -->\n", value);
1614 msIO_fprintf(stream, format, value);
1615 } else {
1616 if (action_if_not_found == OWS_WARN) {
1617 msIO_fprintf(stream, "<!-- WARNING: Mandatory metadata '%s%s' was missing in this context. -->\n", (namespaces?"..._":""), name);
1618 status = action_if_not_found;
1619 }
1620
1621 if (default_value) {
1622 if(msIsXMLTagValid(default_value) == MS_FALSE)
1623 msIO_fprintf(stream, "<!-- WARNING: The value '%s' is not valid "
1624 "in a XML tag context. -->\n", default_value);
1625 msIO_fprintf(stream, format, default_value);
1626 }
1627 }
1628
1629 return status;
1630 }
1631
1632 /*
1633 ** msOWSPrintGroupMetadata()
1634 **
1635 ** Attempt to output a capability item. If corresponding metadata is not
1636 ** found then one of a number of predefined actions will be taken.
1637 ** If a default value is provided and metadata is absent then the
1638 ** default will be used.
1639 */
msOWSPrintGroupMetadata(FILE * stream,mapObj * map,char * pszGroupName,const char * namespaces,const char * name,int action_if_not_found,const char * format,const char * default_value)1640 int msOWSPrintGroupMetadata(FILE *stream, mapObj *map, char* pszGroupName,
1641 const char *namespaces, const char *name,
1642 int action_if_not_found,
1643 const char *format, const char *default_value)
1644 {
1645 return msOWSPrintGroupMetadata2(stream, map, pszGroupName, namespaces, name, action_if_not_found, format, default_value, NULL);
1646 }
1647
1648 /*
1649 ** msOWSPrintGroupMetadata2()
1650 **
1651 ** Attempt to output a capability item in the requested language.
1652 ** Fallback using no language parameter.
1653 */
msOWSPrintGroupMetadata2(FILE * stream,mapObj * map,char * pszGroupName,const char * namespaces,const char * name,int action_if_not_found,const char * format,const char * default_value,const char * validated_language)1654 int msOWSPrintGroupMetadata2(FILE *stream, mapObj *map, char* pszGroupName,
1655 const char *namespaces, const char *name,
1656 int action_if_not_found,
1657 const char *format, const char *default_value,
1658 const char *validated_language)
1659 {
1660 const char *value;
1661 char *encoded;
1662 int status = MS_NOERR;
1663 int i;
1664
1665 for (i=0; i<map->numlayers; i++) {
1666 if (GET_LAYER(map, i)->group && (strcmp(GET_LAYER(map, i)->group, pszGroupName) == 0) && &(GET_LAYER(map, i)->metadata)) {
1667 if((value = msOWSLookupMetadataWithLanguage(&(GET_LAYER(map, i)->metadata), namespaces, name, validated_language))) {
1668 encoded = msEncodeHTMLEntities(value);
1669 msIO_fprintf(stream, format, encoded);
1670 msFree(encoded);
1671 return status;
1672 }
1673 }
1674 }
1675
1676 if (action_if_not_found == OWS_WARN) {
1677 msIO_fprintf(stream, "<!-- WARNING: Mandatory metadata '%s%s' was missing in this context. -->\n", (namespaces?"..._":""), name);
1678 status = action_if_not_found;
1679 }
1680
1681 if (default_value) {
1682 encoded = msEncodeHTMLEntities(default_value);
1683 msIO_fprintf(stream, format, encoded);
1684 msFree(encoded);
1685 }
1686
1687 return status;
1688 }
1689
1690 /* msOWSPrintURLType()
1691 **
1692 ** Attempt to output a URL item in capabilties. If corresponding metadata
1693 ** is not found then one of a number of predefined actions will be taken.
1694 ** Since it's a capability item, five metadata will be used to populate the
1695 ** XML elements.
1696 **
1697 ** The 'name' argument is the basename of the metadata items relating to this
1698 ** URL type and the suffixes _type, _width, _height, _format and _href will
1699 ** be appended to the name in the metadata search.
1700 ** e.g. passing name=metadataurl will result in the following medata entries
1701 ** being used:
1702 ** ows_metadataurl_type
1703 ** ows_metadataurl_format
1704 ** ows_metadataurl_href
1705 ** ... (width and height are unused for metadata)
1706 **
1707 ** As for all the msOWSPrint*() functions, the namespace argument specifies
1708 ** which prefix (ows_, wms_, wcs_, etc.) is used for the metadata names above.
1709 **
1710 ** Then the final string will be built from
1711 ** the tag_name and the five metadata. The template is:
1712 ** <tag_name%type%width%height%format>%href</tag_name>
1713 **
1714 ** For example the width format will usually be " width=\"%s\"".
1715 ** An extern format will be "> <Format>%s</Format"
1716 **
1717 ** Another template template may be used, but it needs to contains 5 %s,
1718 ** otherwise leave it to NULL. If tag_format is used then you don't need the
1719 ** tag_name and the tabspace.
1720 **
1721 ** Note that all values will be HTML-encoded.
1722 **/
msOWSPrintURLType(FILE * stream,hashTableObj * metadata,const char * namespaces,const char * name,int action_if_not_found,const char * tag_format,const char * tag_name,const char * type_format,const char * width_format,const char * height_format,const char * urlfrmt_format,const char * href_format,int type_is_mandatory,int width_is_mandatory,int height_is_mandatory,int format_is_mandatory,int href_is_mandatory,const char * default_type,const char * default_width,const char * default_height,const char * default_urlfrmt,const char * default_href,const char * tabspace)1723 int msOWSPrintURLType(FILE *stream, hashTableObj *metadata,
1724 const char *namespaces, const char *name,
1725 int action_if_not_found, const char *tag_format,
1726 const char *tag_name, const char *type_format,
1727 const char *width_format, const char *height_format,
1728 const char *urlfrmt_format, const char *href_format,
1729 int type_is_mandatory, int width_is_mandatory,
1730 int height_is_mandatory, int format_is_mandatory,
1731 int href_is_mandatory, const char *default_type,
1732 const char *default_width, const char *default_height,
1733 const char *default_urlfrmt, const char *default_href,
1734 const char *tabspace)
1735 {
1736 const char *value;
1737 char *metadata_name;
1738 size_t buffer_size = 0, buffer_size_tmp = 0;
1739 char *encoded;
1740 int status = MS_NOERR;
1741 char *type=NULL, *width=NULL, *height=NULL, *urlfrmt=NULL, *href=NULL;
1742
1743 buffer_size = strlen(name)+10;
1744 metadata_name = (char*)malloc(buffer_size);
1745
1746 /* Get type */
1747 if(type_format != NULL) {
1748 snprintf(metadata_name, buffer_size, "%s_type", name);
1749 value = msOWSLookupMetadata(metadata, namespaces, metadata_name);
1750 if(value != NULL) {
1751 encoded = msEncodeHTMLEntities(value);
1752 buffer_size_tmp = strlen(type_format)+strlen(encoded)+1;
1753 type = (char*)malloc(buffer_size_tmp);
1754 snprintf(type, buffer_size_tmp, type_format, encoded);
1755 msFree(encoded);
1756 }
1757 }
1758
1759 /* Get width */
1760 if(width_format != NULL) {
1761 snprintf(metadata_name, buffer_size, "%s_width", name);
1762 value = msOWSLookupMetadata(metadata, namespaces, metadata_name);
1763 if(value != NULL) {
1764 encoded = msEncodeHTMLEntities(value);
1765 buffer_size_tmp = strlen(width_format)+strlen(encoded)+1;
1766 width = (char*)malloc(buffer_size_tmp);
1767 snprintf(width, buffer_size_tmp, width_format, encoded);
1768 msFree(encoded);
1769 }
1770 }
1771
1772 /* Get height */
1773 if(height_format != NULL) {
1774 snprintf(metadata_name, buffer_size, "%s_height", name);
1775 value = msOWSLookupMetadata(metadata, namespaces, metadata_name);
1776 if(value != NULL) {
1777 encoded = msEncodeHTMLEntities(value);
1778 buffer_size_tmp = strlen(height_format)+strlen(encoded)+1;
1779 height = (char*)malloc(buffer_size_tmp);
1780 snprintf(height, buffer_size_tmp, height_format, encoded);
1781 msFree(encoded);
1782 }
1783 }
1784
1785 /* Get format */
1786 if(urlfrmt_format != NULL) {
1787 snprintf(metadata_name, buffer_size, "%s_format", name);
1788 value = msOWSLookupMetadata(metadata, namespaces, metadata_name);
1789 if(value != NULL) {
1790 encoded = msEncodeHTMLEntities(value);
1791 buffer_size_tmp = strlen(urlfrmt_format)+strlen(encoded)+1;
1792 urlfrmt = (char*)malloc(buffer_size_tmp);
1793 snprintf(urlfrmt, buffer_size_tmp, urlfrmt_format, encoded);
1794 msFree(encoded);
1795 }
1796 }
1797
1798 /* Get href */
1799 if(href_format != NULL) {
1800 snprintf(metadata_name, buffer_size, "%s_href", name);
1801 value = msOWSLookupMetadata(metadata, namespaces, metadata_name);
1802 if(value != NULL) {
1803 encoded = msEncodeHTMLEntities(value);
1804 buffer_size_tmp = strlen(href_format)+strlen(encoded)+1;
1805 href = (char*)malloc(buffer_size_tmp);
1806 snprintf(href, buffer_size_tmp, href_format, encoded);
1807 msFree(encoded);
1808 }
1809 }
1810
1811 msFree(metadata_name);
1812
1813 if(type || width || height || urlfrmt || href ||
1814 (!metadata && (default_type || default_width || default_height ||
1815 default_urlfrmt || default_href))) {
1816 if((!type && type_is_mandatory) || (!width && width_is_mandatory) ||
1817 (!height && height_is_mandatory) ||
1818 (!urlfrmt && format_is_mandatory) || (!href && href_is_mandatory)) {
1819 msIO_fprintf(stream, "<!-- WARNING: Some mandatory elements for '%s' are missing in this context. -->\n", tag_name);
1820 if (action_if_not_found == OWS_WARN) {
1821 msIO_fprintf(stream, "<!-- WARNING: Mandatory metadata '%s%s' was missing in this context. -->\n", (namespaces?"..._":""), name);
1822 status = action_if_not_found;
1823 }
1824 } else {
1825 if(!type && type_format && default_type) {
1826 buffer_size_tmp = strlen(type_format) + strlen(default_type) + 2;
1827 type = (char*) malloc(buffer_size_tmp);
1828 snprintf(type, buffer_size_tmp, type_format, default_type);
1829 } else if(!type)
1830 type = msStrdup("");
1831 if(!width && width_format && default_width) {
1832 buffer_size_tmp = strlen(width_format) + strlen(default_width) + 2;
1833 width = (char*) malloc(buffer_size_tmp);
1834 snprintf(width, buffer_size_tmp, width_format, default_width);
1835 } else if(!width)
1836 width = msStrdup("");
1837 if(!height && height_format && default_height) {
1838 buffer_size_tmp = strlen(height_format) + strlen(default_height) + 2;
1839 height = (char*) malloc(buffer_size_tmp);
1840 snprintf(height, buffer_size_tmp, height_format, default_height);
1841 } else if(!height)
1842 height = msStrdup("");
1843 if(!urlfrmt && urlfrmt_format && default_urlfrmt) {
1844 buffer_size_tmp = strlen(urlfrmt_format) + strlen(default_urlfrmt) + 2;
1845 urlfrmt = (char*) malloc(buffer_size_tmp);
1846 snprintf(urlfrmt, buffer_size_tmp, urlfrmt_format, default_urlfrmt);
1847 } else if(!urlfrmt)
1848 urlfrmt = msStrdup("");
1849 if(!href && href_format && default_href) {
1850 buffer_size_tmp = strlen(href_format) + strlen(default_href) + 2;
1851 href = (char*) malloc(buffer_size_tmp);
1852 snprintf(href, buffer_size_tmp, href_format, default_href);
1853 } else if(!href)
1854 href = msStrdup("");
1855
1856 if(tag_format == NULL)
1857 msIO_fprintf(stream, "%s<%s%s%s%s%s>%s</%s>\n", tabspace,
1858 tag_name, type, width, height, urlfrmt, href,
1859 tag_name);
1860 else
1861 msIO_fprintf(stream, tag_format,
1862 type, width, height, urlfrmt, href);
1863 }
1864
1865 msFree(type);
1866 msFree(width);
1867 msFree(height);
1868 msFree(urlfrmt);
1869 msFree(href);
1870 } else {
1871 if (action_if_not_found == OWS_WARN) {
1872 msIO_fprintf(stream, "<!-- WARNING: Mandatory metadata '%s%s' was missing in this context. -->\n", (namespaces?"..._":""), name);
1873 status = action_if_not_found;
1874 }
1875 }
1876
1877 return status;
1878 }
1879
1880 /* msOWSPrintParam()
1881 **
1882 ** Same as printMetadata() but applied to mapfile parameters.
1883 **/
msOWSPrintParam(FILE * stream,const char * name,const char * value,int action_if_not_found,const char * format,const char * default_value)1884 int msOWSPrintParam(FILE *stream, const char *name, const char *value,
1885 int action_if_not_found, const char *format,
1886 const char *default_value)
1887 {
1888 int status = MS_NOERR;
1889
1890 if(value && strlen(value) > 0) {
1891 msIO_fprintf(stream, format, value);
1892 } else {
1893 if (action_if_not_found == OWS_WARN) {
1894 msIO_fprintf(stream, "<!-- WARNING: Mandatory mapfile parameter '%s' was missing in this context. -->\n", name);
1895 status = action_if_not_found;
1896 }
1897
1898 if (default_value)
1899 msIO_fprintf(stream, format, default_value);
1900 }
1901
1902 return status;
1903 }
1904
1905 /* msOWSPrintEncodeParam()
1906 **
1907 ** Same as printEncodeMetadata() but applied to mapfile parameters.
1908 **/
msOWSPrintEncodeParam(FILE * stream,const char * name,const char * value,int action_if_not_found,const char * format,const char * default_value)1909 int msOWSPrintEncodeParam(FILE *stream, const char *name, const char *value,
1910 int action_if_not_found, const char *format,
1911 const char *default_value)
1912 {
1913 int status = MS_NOERR;
1914 char *encode;
1915
1916 if(value && strlen(value) > 0) {
1917 encode = msEncodeHTMLEntities(value);
1918 msIO_fprintf(stream, format, encode);
1919 msFree(encode);
1920 } else {
1921 if (action_if_not_found == OWS_WARN) {
1922 msIO_fprintf(stream, "<!-- WARNING: Mandatory mapfile parameter '%s' was missing in this context. -->\n", name);
1923 status = action_if_not_found;
1924 }
1925
1926 if (default_value) {
1927 encode = msEncodeHTMLEntities(default_value);
1928 msIO_fprintf(stream, format, encode);
1929 msFree(encode);
1930 }
1931 }
1932
1933 return status;
1934 }
1935
1936 /* msOWSPrintMetadataList()
1937 **
1938 ** Prints comma-separated lists metadata. (e.g. keywordList)
1939 ** default_value serves 2 purposes if specified:
1940 ** - won't be printed if part of MetadataList (default_value == key"_exclude")
1941 ** (exclusion)
1942 ** - will be printed if MetadataList is empty (fallback)
1943 **/
msOWSPrintMetadataList(FILE * stream,hashTableObj * metadata,const char * namespaces,const char * name,const char * startTag,const char * endTag,const char * itemFormat,const char * default_value)1944 int msOWSPrintMetadataList(FILE *stream, hashTableObj *metadata,
1945 const char *namespaces, const char *name,
1946 const char *startTag,
1947 const char *endTag, const char *itemFormat,
1948 const char *default_value)
1949 {
1950 const char *value;
1951
1952 value = msOWSLookupMetadata(metadata, namespaces, name);
1953
1954 if(value == NULL) {
1955 value = default_value;
1956 default_value = NULL;
1957 }
1958
1959 if(value != NULL) {
1960 char **keywords;
1961 int numkeywords;
1962
1963 keywords = msStringSplit(value, ',', &numkeywords);
1964 if(keywords && numkeywords > 0) {
1965 int kw;
1966 if(startTag) msIO_fprintf(stream, "%s", startTag);
1967 for(kw=0; kw<numkeywords; kw++) {
1968 if (default_value != NULL
1969 && strncasecmp(keywords[kw],default_value,strlen(keywords[kw])) == 0
1970 && strncasecmp("_exclude",default_value+strlen(default_value)-8,8) == 0)
1971 continue;
1972
1973 msIO_fprintf(stream, itemFormat, keywords[kw]);
1974 }
1975 if(endTag) msIO_fprintf(stream, "%s", endTag);
1976 }
1977 msFreeCharArray(keywords, numkeywords);
1978 return MS_TRUE;
1979 }
1980 return MS_FALSE;
1981 }
1982
1983 /* msOWSPrintEncodeMetadataList()
1984 **
1985 ** Prints comma-separated lists metadata. (e.g. keywordList)
1986 ** This will print HTML encoded values.
1987 ** default_value serves 2 purposes if specified:
1988 ** - won't be printed if part of MetadataList (default_value == key"_exclude")
1989 ** (exclusion)
1990 ** - will be printed if MetadataList is empty (fallback)
1991 **/
msOWSPrintEncodeMetadataList(FILE * stream,hashTableObj * metadata,const char * namespaces,const char * name,const char * startTag,const char * endTag,const char * itemFormat,const char * default_value)1992 int msOWSPrintEncodeMetadataList(FILE *stream, hashTableObj *metadata,
1993 const char *namespaces, const char *name,
1994 const char *startTag,
1995 const char *endTag, const char *itemFormat,
1996 const char *default_value)
1997 {
1998 const char *value;
1999 char *encoded;
2000 size_t default_value_len = 0;
2001
2002 value = msOWSLookupMetadata(metadata, namespaces, name);
2003
2004 if(value == NULL) {
2005 value = default_value;
2006 default_value = NULL;
2007 }
2008 if( default_value )
2009 default_value_len = strlen(default_value);
2010
2011 if(value != NULL) {
2012 char **keywords;
2013 int numkeywords;
2014
2015 keywords = msStringSplit(value, ',', &numkeywords);
2016 if(keywords && numkeywords > 0) {
2017 int kw;
2018 if(startTag) msIO_fprintf(stream, "%s", startTag);
2019 for(kw=0; kw<numkeywords; kw++) {
2020 if (default_value != NULL
2021 && default_value_len > 8
2022 && strncasecmp(keywords[kw],default_value,strlen(keywords[kw])) == 0
2023 && strncasecmp("_exclude",default_value+default_value_len-8,8) == 0)
2024 continue;
2025
2026 encoded = msEncodeHTMLEntities(keywords[kw]);
2027 msIO_fprintf(stream, itemFormat, encoded);
2028 msFree(encoded);
2029 }
2030 if(endTag) msIO_fprintf(stream, "%s", endTag);
2031 }
2032 msFreeCharArray(keywords, numkeywords);
2033 return MS_TRUE;
2034 }
2035 return MS_FALSE;
2036 }
2037
2038 /* msOWSPrintEncodeParamList()
2039 **
2040 ** Same as msOWSPrintEncodeMetadataList() but applied to mapfile parameters.
2041 **/
msOWSPrintEncodeParamList(FILE * stream,const char * name,const char * value,int action_if_not_found,char delimiter,const char * startTag,const char * endTag,const char * format,const char * default_value)2042 int msOWSPrintEncodeParamList(FILE *stream, const char *name,
2043 const char *value, int action_if_not_found,
2044 char delimiter, const char *startTag,
2045 const char *endTag, const char *format,
2046 const char *default_value)
2047 {
2048 int status = MS_NOERR;
2049 char *encoded;
2050 char **items = NULL;
2051 int numitems = 0, i;
2052
2053 if(value && strlen(value) > 0)
2054 items = msStringSplit(value, delimiter, &numitems);
2055 else {
2056 if (action_if_not_found == OWS_WARN) {
2057 msIO_fprintf(stream, "<!-- WARNING: Mandatory mapfile parameter '%s' was missing in this context. -->\n", name);
2058 status = action_if_not_found;
2059 }
2060
2061 if (default_value)
2062 items = msStringSplit(default_value, delimiter, &numitems);
2063 }
2064
2065 if(items && numitems > 0) {
2066 if(startTag) msIO_fprintf(stream, "%s", startTag);
2067 for(i=0; i<numitems; i++) {
2068 encoded = msEncodeHTMLEntities(items[i]);
2069 msIO_fprintf(stream, format, encoded);
2070 msFree(encoded);
2071 }
2072 if(endTag) msIO_fprintf(stream, "%s", endTag);
2073 }
2074 msFreeCharArray(items, numitems);
2075
2076 return status;
2077 }
2078
2079
2080 /*
2081 ** msOWSProjectToWGS84()
2082 **
2083 ** Reprojects the extent to WGS84.
2084 **
2085 */
msOWSProjectToWGS84(projectionObj * srcproj,rectObj * ext)2086 void msOWSProjectToWGS84(projectionObj *srcproj, rectObj *ext)
2087 {
2088 if (srcproj->proj && !msProjIsGeographicCRS(srcproj)) {
2089 projectionObj wgs84;
2090 msInitProjection(&wgs84);
2091 msProjectionInheritContextFrom(&wgs84, srcproj);
2092 msLoadProjectionString(&wgs84, "+proj=longlat +ellps=WGS84 +datum=WGS84");
2093 msProjectRect(srcproj, &wgs84, ext);
2094 msFreeProjection(&wgs84);
2095 }
2096 }
2097
2098 /*
2099 ** msOWSPrintEX_GeographicBoundingBox()
2100 **
2101 ** Print a EX_GeographicBoundingBox tag for WMS1.3.0
2102 **
2103 */
msOWSPrintEX_GeographicBoundingBox(FILE * stream,const char * tabspace,rectObj * extent,projectionObj * srcproj)2104 void msOWSPrintEX_GeographicBoundingBox(FILE *stream, const char *tabspace,
2105 rectObj *extent, projectionObj *srcproj)
2106
2107 {
2108 const char *pszTag = "EX_GeographicBoundingBox"; /* The default for WMS */
2109 rectObj ext;
2110
2111 ext = *extent;
2112
2113 /* always project to lat long */
2114 msOWSProjectToWGS84(srcproj, &ext);
2115
2116 msIO_fprintf(stream, "%s<%s>\n", tabspace, pszTag);
2117 msIO_fprintf(stream, "%s <westBoundLongitude>%g</westBoundLongitude>\n", tabspace, ext.minx);
2118 msIO_fprintf(stream, "%s <eastBoundLongitude>%g</eastBoundLongitude>\n", tabspace, ext.maxx);
2119 msIO_fprintf(stream, "%s <southBoundLatitude>%g</southBoundLatitude>\n", tabspace, ext.miny);
2120 msIO_fprintf(stream, "%s <northBoundLatitude>%g</northBoundLatitude>\n", tabspace, ext.maxy);
2121 msIO_fprintf(stream, "%s</%s>\n", tabspace, pszTag);
2122
2123 /* msIO_fprintf(stream, "%s<%s minx=\"%g\" miny=\"%g\" maxx=\"%g\" maxy=\"%g\" />\n",
2124 tabspace, pszTag, ext.minx, ext.miny, ext.maxx, ext.maxy); */
2125 }
2126
2127 /*
2128 ** msOWSPrintLatLonBoundingBox()
2129 **
2130 ** Print a LatLonBoundingBox tag for WMS, or LatLongBoundingBox for WFS
2131 ** ... yes, the tag name differs between WMS and WFS, yuck!
2132 **
2133 */
msOWSPrintLatLonBoundingBox(FILE * stream,const char * tabspace,rectObj * extent,projectionObj * srcproj,projectionObj * wfsproj,OWSServiceType nService)2134 void msOWSPrintLatLonBoundingBox(FILE *stream, const char *tabspace,
2135 rectObj *extent, projectionObj *srcproj,
2136 projectionObj *wfsproj, OWSServiceType nService)
2137 {
2138 const char *pszTag = "LatLonBoundingBox"; /* The default for WMS */
2139 rectObj ext;
2140
2141 ext = *extent;
2142
2143 if (nService == OWS_WMS) { /* always project to lat long */
2144 msOWSProjectToWGS84(srcproj, &ext);
2145 } else if (nService == OWS_WFS) { /* called from wfs 1.0.0 only: project to map srs, if set */
2146 pszTag = "LatLongBoundingBox";
2147 if (wfsproj) {
2148 if (msProjectionsDiffer(srcproj, wfsproj) == MS_TRUE)
2149 msProjectRect(srcproj, wfsproj, &ext);
2150 }
2151 }
2152
2153 msIO_fprintf(stream, "%s<%s minx=\"%g\" miny=\"%g\" maxx=\"%g\" maxy=\"%g\" />\n",
2154 tabspace, pszTag, ext.minx, ext.miny, ext.maxx, ext.maxy);
2155 }
2156
2157 /*
2158 ** Emit a bounding box if we can find projection information.
2159 ** If <namespaces>_bbox_extended is not set, emit a single bounding box
2160 ** using the layer's native SRS (ignoring any <namespaces>_srs metadata).
2161 **
2162 ** If <namespaces>_bbox_extended is set to true, emit a bounding box
2163 ** for every projection listed in the <namespaces>_srs list.
2164 ** Check the map level metadata for both _bbox_extended and _srs,
2165 ** if there is no such metadata at the layer level.
2166 ** (These settings make more sense at the global/map level anyways)
2167 */
msOWSPrintBoundingBox(FILE * stream,const char * tabspace,rectObj * extent,projectionObj * srcproj,hashTableObj * layer_meta,hashTableObj * map_meta,const char * namespaces,int wms_version)2168 void msOWSPrintBoundingBox(FILE *stream, const char *tabspace,
2169 rectObj *extent,
2170 projectionObj *srcproj,
2171 hashTableObj *layer_meta,
2172 hashTableObj *map_meta,
2173 const char *namespaces,
2174 int wms_version)
2175 {
2176 const char *value, *resx, *resy, *wms_bbox_extended;
2177 char *encoded, *encoded_resx, *encoded_resy, *epsg_str;
2178 char **epsgs;
2179 int i, num_epsgs;
2180 projectionObj proj;
2181 rectObj ext;
2182
2183 wms_bbox_extended = msOWSLookupMetadata2(layer_meta, map_meta, namespaces, "bbox_extended");
2184 if( wms_bbox_extended && strncasecmp(wms_bbox_extended, "true", 5) == 0 ) {
2185 /* get a list of all projections from the metadata
2186 try the layer metadata first, otherwise use the map's */
2187 if( msOWSLookupMetadata(layer_meta, namespaces, "srs") ) {
2188 msOWSGetEPSGProj(srcproj, layer_meta, namespaces, MS_FALSE, &epsg_str);
2189 } else {
2190 msOWSGetEPSGProj(srcproj, map_meta, namespaces, MS_FALSE, &epsg_str);
2191 }
2192 epsgs = msStringSplit(epsg_str, ' ', &num_epsgs);
2193 msFree(epsg_str);
2194 } else {
2195 /* Look for EPSG code in PROJECTION block only. "wms_srs" metadata cannot be
2196 * used to establish the native projection of a layer for BoundingBox purposes.
2197 */
2198 epsgs = (char **) msSmallMalloc(sizeof(char *));
2199 num_epsgs = 1;
2200 msOWSGetEPSGProj(srcproj, layer_meta, namespaces, MS_TRUE, &(epsgs[0]));
2201 }
2202
2203 for( i = 0; i < num_epsgs; i++) {
2204 value = epsgs[i];
2205 if( value && *value) {
2206 memcpy(&ext, extent, sizeof(rectObj));
2207
2208 /* reproject the extents for each SRS's bounding box */
2209 msInitProjection(&proj);
2210 msProjectionInheritContextFrom(&proj, srcproj);
2211 if (msLoadProjectionStringEPSG(&proj, (char *)value) == 0) {
2212 if (msProjectionsDiffer(srcproj, &proj) == MS_TRUE) {
2213 msProjectRect(srcproj, &proj, &ext);
2214 }
2215 /*for wms 1.3.0 we need to make sure that we present the BBOX with
2216 a reversed axes for some espg codes*/
2217 if (wms_version >= OWS_1_3_0 && value && strncasecmp(value, "EPSG:", 5) == 0) {
2218 msAxisNormalizePoints( &proj, 1, &(ext.minx), &(ext.miny) );
2219 msAxisNormalizePoints( &proj, 1, &(ext.maxx), &(ext.maxy) );
2220 }
2221 }
2222 msFreeProjection( &proj );
2223
2224 encoded = msEncodeHTMLEntities(value);
2225 if (wms_version >= OWS_1_3_0)
2226 msIO_fprintf(stream, "%s<BoundingBox CRS=\"%s\"\n"
2227 "%s minx=\"%g\" miny=\"%g\" maxx=\"%g\" maxy=\"%g\"",
2228 tabspace, encoded,
2229 tabspace, ext.minx, ext.miny,
2230 ext.maxx, ext.maxy);
2231 else
2232 msIO_fprintf(stream, "%s<BoundingBox SRS=\"%s\"\n"
2233 "%s minx=\"%g\" miny=\"%g\" maxx=\"%g\" maxy=\"%g\"",
2234 tabspace, encoded,
2235 tabspace, ext.minx, ext.miny,
2236 ext.maxx, ext.maxy);
2237
2238 msFree(encoded);
2239
2240 if( (resx = msOWSLookupMetadata2( layer_meta, map_meta, "MFO", "resx" )) != NULL &&
2241 (resy = msOWSLookupMetadata2( layer_meta, map_meta, "MFO", "resy" )) != NULL ) {
2242 encoded_resx = msEncodeHTMLEntities(resx);
2243 encoded_resy = msEncodeHTMLEntities(resy);
2244 msIO_fprintf( stream, "\n%s resx=\"%s\" resy=\"%s\"",
2245 tabspace, encoded_resx, encoded_resy );
2246 msFree(encoded_resx);
2247 msFree(encoded_resy);
2248 }
2249
2250 msIO_fprintf( stream, " />\n" );
2251 }
2252 }
2253 msFreeCharArray(epsgs, num_epsgs);
2254 }
2255
2256
2257 /*
2258 ** Print the contact information
2259 */
msOWSPrintContactInfo(FILE * stream,const char * tabspace,int nVersion,hashTableObj * metadata,const char * namespaces)2260 void msOWSPrintContactInfo( FILE *stream, const char *tabspace,
2261 int nVersion, hashTableObj *metadata,
2262 const char *namespaces )
2263 {
2264 /* contact information is a required element in 1.0.7 but the */
2265 /* sub-elements such as ContactPersonPrimary, etc. are not! */
2266 /* In 1.1.0, ContactInformation becomes optional. */
2267 if (nVersion > OWS_1_0_0) {
2268 msIO_fprintf(stream, "%s<ContactInformation>\n", tabspace);
2269
2270 /* ContactPersonPrimary is optional, but when present then all its */
2271 /* sub-elements are mandatory */
2272
2273 if(msOWSLookupMetadata(metadata, namespaces, "contactperson") ||
2274 msOWSLookupMetadata(metadata, namespaces, "contactorganization")) {
2275 msIO_fprintf(stream, "%s <ContactPersonPrimary>\n", tabspace);
2276
2277 msOWSPrintEncodeMetadata(stream, metadata, namespaces, "contactperson",
2278 OWS_WARN, " <ContactPerson>%s</ContactPerson>\n", NULL);
2279 msOWSPrintEncodeMetadata(stream, metadata, namespaces, "contactorganization",
2280 OWS_WARN, " <ContactOrganization>%s</ContactOrganization>\n",
2281 NULL);
2282 msIO_fprintf(stream, "%s </ContactPersonPrimary>\n", tabspace);
2283 }
2284
2285 if(msOWSLookupMetadata(metadata, namespaces, "contactposition")) {
2286 msOWSPrintEncodeMetadata(stream, metadata, namespaces, "contactposition",
2287 OWS_NOERR, " <ContactPosition>%s</ContactPosition>\n",
2288 NULL);
2289 }
2290
2291 /* ContactAdress is optional, but when present then all its */
2292 /* sub-elements are mandatory */
2293 if(msOWSLookupMetadata( metadata, namespaces, "addresstype" ) ||
2294 msOWSLookupMetadata( metadata, namespaces, "address" ) ||
2295 msOWSLookupMetadata( metadata, namespaces, "city" ) ||
2296 msOWSLookupMetadata( metadata, namespaces, "stateorprovince" ) ||
2297 msOWSLookupMetadata( metadata, namespaces, "postcode" ) ||
2298 msOWSLookupMetadata( metadata, namespaces, "country" )) {
2299 msIO_fprintf(stream, "%s <ContactAddress>\n", tabspace);
2300
2301 msOWSPrintEncodeMetadata(stream, metadata, namespaces,"addresstype", OWS_WARN,
2302 " <AddressType>%s</AddressType>\n", NULL);
2303 msOWSPrintEncodeMetadata(stream, metadata, namespaces, "address", OWS_WARN,
2304 " <Address>%s</Address>\n", NULL);
2305 msOWSPrintEncodeMetadata(stream, metadata, namespaces, "city", OWS_WARN,
2306 " <City>%s</City>\n", NULL);
2307 msOWSPrintEncodeMetadata(stream, metadata, namespaces, "stateorprovince",
2308 OWS_WARN," <StateOrProvince>%s</StateOrProvince>\n", NULL);
2309 msOWSPrintEncodeMetadata(stream, metadata, namespaces, "postcode", OWS_WARN,
2310 " <PostCode>%s</PostCode>\n", NULL);
2311 msOWSPrintEncodeMetadata(stream, metadata, namespaces, "country", OWS_WARN,
2312 " <Country>%s</Country>\n", NULL);
2313 msIO_fprintf(stream, "%s </ContactAddress>\n", tabspace);
2314 }
2315
2316 if(msOWSLookupMetadata(metadata, namespaces, "contactvoicetelephone")) {
2317 msOWSPrintEncodeMetadata(stream, metadata, namespaces,
2318 "contactvoicetelephone", OWS_NOERR,
2319 " <ContactVoiceTelephone>%s</ContactVoiceTelephone>\n",
2320 NULL);
2321 }
2322
2323 if(msOWSLookupMetadata(metadata, namespaces, "contactfacsimiletelephone")) {
2324 msOWSPrintEncodeMetadata(stream, metadata,
2325 namespaces, "contactfacsimiletelephone", OWS_NOERR,
2326 " <ContactFacsimileTelephone>%s</ContactFacsimileTelephone>\n",
2327 NULL);
2328 }
2329
2330 if(msOWSLookupMetadata(metadata, namespaces, "contactelectronicmailaddress")) {
2331 msOWSPrintEncodeMetadata(stream, metadata,
2332 namespaces, "contactelectronicmailaddress", OWS_NOERR,
2333 " <ContactElectronicMailAddress>%s</ContactElectronicMailAddress>\n",
2334 NULL);
2335 }
2336 msIO_fprintf(stream, "%s</ContactInformation>\n", tabspace);
2337 }
2338 }
2339
2340 /*
2341 ** msOWSGetLayerExtent()
2342 **
2343 ** Try to establish layer extent, first looking for "ows_extent" metadata, and
2344 ** if not found then call msLayerGetExtent() which will lookup the
2345 ** layer->extent member, and if not found will open layer to read extent.
2346 **
2347 */
msOWSGetLayerExtent(mapObj * map,layerObj * lp,const char * namespaces,rectObj * ext)2348 int msOWSGetLayerExtent(mapObj *map, layerObj *lp, const char *namespaces, rectObj *ext)
2349 {
2350 const char *value;
2351
2352 if ((value = msOWSLookupMetadata(&(lp->metadata), namespaces, "extent")) != NULL) {
2353 char **tokens;
2354 int n;
2355
2356 tokens = msStringSplit(value, ' ', &n);
2357 if (tokens==NULL || n != 4) {
2358 msSetError(MS_WMSERR, "Wrong number of arguments for EXTENT metadata.",
2359 "msOWSGetLayerExtent()");
2360 return MS_FAILURE;
2361 }
2362 ext->minx = atof(tokens[0]);
2363 ext->miny = atof(tokens[1]);
2364 ext->maxx = atof(tokens[2]);
2365 ext->maxy = atof(tokens[3]);
2366
2367 msFreeCharArray(tokens, n);
2368 return MS_SUCCESS;
2369 } else {
2370 return msLayerGetExtent(lp, ext);
2371 }
2372
2373 return MS_FAILURE;
2374 }
2375
2376
2377 /**********************************************************************
2378 * msOWSExecuteRequests()
2379 *
2380 * Execute a number of WFS/WMS HTTP requests in parallel, and then
2381 * update layerObj information with the result of the requests.
2382 **********************************************************************/
msOWSExecuteRequests(httpRequestObj * pasReqInfo,int numRequests,mapObj * map,int bCheckLocalCache)2383 int msOWSExecuteRequests(httpRequestObj *pasReqInfo, int numRequests,
2384 mapObj *map, int bCheckLocalCache)
2385 {
2386 int nStatus, iReq;
2387
2388 /* Execute requests */
2389 #if defined(USE_CURL)
2390 nStatus = msHTTPExecuteRequests(pasReqInfo, numRequests, bCheckLocalCache);
2391 #else
2392 msSetError(MS_WMSERR, "msOWSExecuteRequests() called apparently without libcurl configured, msHTTPExecuteRequests() not available.",
2393 "msOWSExecuteRequests()");
2394 return MS_FAILURE;
2395 #endif
2396
2397 /* Scan list of layers and call the handler for each layer type to */
2398 /* pass them the request results. */
2399 for(iReq=0; iReq<numRequests; iReq++) {
2400 if (pasReqInfo[iReq].nLayerId >= 0 &&
2401 pasReqInfo[iReq].nLayerId < map->numlayers) {
2402 layerObj *lp;
2403
2404 lp = GET_LAYER(map, pasReqInfo[iReq].nLayerId);
2405
2406 if (lp->connectiontype == MS_WFS)
2407 msWFSUpdateRequestInfo(lp, &(pasReqInfo[iReq]));
2408 }
2409 }
2410
2411 return nStatus;
2412 }
2413
2414 /**********************************************************************
2415 * msOWSProcessException()
2416 *
2417 **********************************************************************/
msOWSProcessException(layerObj * lp,const char * pszFname,int nErrorCode,const char * pszFuncName)2418 void msOWSProcessException(layerObj *lp, const char *pszFname,
2419 int nErrorCode, const char *pszFuncName)
2420 {
2421 FILE *fp;
2422
2423 if ((fp = fopen(pszFname, "r")) != NULL) {
2424 char *pszBuf=NULL;
2425 int nBufSize=0;
2426 char *pszStart, *pszEnd;
2427
2428 fseek(fp, 0, SEEK_END);
2429 nBufSize = ftell(fp);
2430 if(nBufSize < 0) {
2431 msSetError(MS_IOERR, NULL, "msOWSProcessException()");
2432 fclose(fp);
2433 return;
2434 }
2435 rewind(fp);
2436 pszBuf = (char*)malloc((nBufSize+1)*sizeof(char));
2437 if (pszBuf == NULL) {
2438 msSetError(MS_MEMERR, NULL, "msOWSProcessException()");
2439 fclose(fp);
2440 return;
2441 }
2442
2443 if ((int) fread(pszBuf, 1, nBufSize, fp) != nBufSize) {
2444 msSetError(MS_IOERR, NULL, "msOWSProcessException()");
2445 free(pszBuf);
2446 fclose(fp);
2447 return;
2448 }
2449
2450 pszBuf[nBufSize] = '\0';
2451
2452
2453 /* OK, got the data in the buffer. Look for the <Message> tags */
2454 if ((strstr(pszBuf, "<WFS_Exception>") && /* WFS style */
2455 (pszStart = strstr(pszBuf, "<Message>")) &&
2456 (pszEnd = strstr(pszStart, "</Message>")) ) ||
2457 (strstr(pszBuf, "<ServiceExceptionReport>") && /* WMS style */
2458 (pszStart = strstr(pszBuf, "<ServiceException>")) &&
2459 (pszEnd = strstr(pszStart, "</ServiceException>")) )) {
2460 pszStart = strchr(pszStart, '>')+1;
2461 *pszEnd = '\0';
2462 msSetError(nErrorCode, "Got Remote Server Exception for layer %s: %s",
2463 pszFuncName, lp->name?lp->name:"(null)", pszStart);
2464 } else {
2465 msSetError(MS_WFSCONNERR, "Unable to parse Remote Server Exception Message for layer %s.",
2466 pszFuncName, lp->name?lp->name:"(null)");
2467 }
2468
2469 free(pszBuf);
2470 fclose(fp);
2471 }
2472 }
2473
2474 /**********************************************************************
2475 * msOWSBuildURLFilename()
2476 *
2477 * Build a unique filename for this URL to use in caching remote server
2478 * requests. Slashes and illegal characters will be turned into '_'
2479 *
2480 * Returns a newly allocated buffer that should be freed by the caller or
2481 * NULL in case of error.
2482 **********************************************************************/
msOWSBuildURLFilename(const char * pszPath,const char * pszURL,const char * pszExt)2483 char *msOWSBuildURLFilename(const char *pszPath, const char *pszURL,
2484 const char *pszExt)
2485 {
2486 char *pszBuf, *pszPtr;
2487 int i;
2488 size_t nBufLen = 0;
2489
2490
2491 nBufLen = strlen(pszURL) + strlen(pszExt) +2;
2492 if (pszPath)
2493 nBufLen += (strlen(pszPath)+1);
2494
2495 pszBuf = (char*)malloc(nBufLen);
2496 if (pszBuf == NULL) {
2497 msSetError(MS_MEMERR, NULL, "msOWSBuildURLFilename()");
2498 return NULL;
2499 }
2500 pszBuf[0] = '\0';
2501
2502 if (pszPath) {
2503 #ifdef _WIN32
2504 if (pszPath[strlen(pszPath) -1] != '/' &&
2505 pszPath[strlen(pszPath) -1] != '\\')
2506 snprintf(pszBuf, nBufLen, "%s\\", pszPath);
2507 else
2508 snprintf(pszBuf, nBufLen, "%s", pszPath);
2509 #else
2510 if (pszPath[strlen(pszPath) -1] != '/')
2511 snprintf(pszBuf, nBufLen, "%s/", pszPath);
2512 else
2513 snprintf(pszBuf, nBufLen, "%s", pszPath);
2514 #endif
2515 }
2516
2517 pszPtr = pszBuf + strlen(pszBuf);
2518
2519 for(i=0; pszURL[i] != '\0'; i++) {
2520 if (isalnum(pszURL[i]))
2521 *pszPtr = pszURL[i];
2522 else
2523 *pszPtr = '_';
2524 pszPtr++;
2525 }
2526
2527 strlcpy(pszPtr, pszExt, nBufLen);
2528
2529 return pszBuf;
2530 }
2531
2532 /*
2533 ** msOWSGetEPSGProj()
2534 **
2535 ** Extract projection code for this layer/map.
2536 **
2537 ** First look for a xxx_srs metadata. If not found then look for an EPSG
2538 ** code in projectionObj, and if not found then return NULL.
2539 **
2540 ** If bReturnOnlyFirstOne=TRUE and metadata contains multiple EPSG codes
2541 ** then only the first one (which is assumed to be the layer's default
2542 ** projection) is returned.
2543 */
msOWSGetEPSGProj(projectionObj * proj,hashTableObj * metadata,const char * namespaces,int bReturnOnlyFirstOne,char ** epsgCode)2544 void msOWSGetEPSGProj(projectionObj *proj, hashTableObj *metadata, const char *namespaces, int bReturnOnlyFirstOne, char **epsgCode)
2545 {
2546 const char *value;
2547 *epsgCode = NULL;
2548
2549 /* metadata value should already be in format "EPSG:n" or "AUTO:..." */
2550 if (metadata && ((value = msOWSLookupMetadata(metadata, namespaces, "srs")) != NULL)) {
2551 const char *space_ptr;
2552 if (!bReturnOnlyFirstOne || (space_ptr = strchr(value,' ')) == NULL) {
2553 *epsgCode = msStrdup(value);
2554 return;
2555 }
2556
2557
2558 *epsgCode = msSmallMalloc((space_ptr - value + 1)*sizeof(char));
2559 /* caller requested only first projection code, copy up to the first space character*/
2560 strlcpy(*epsgCode, value, space_ptr - value + 1) ;
2561 return;
2562 } else if (proj && proj->numargs > 0 && (value = strstr(proj->args[0], "init=epsg:")) != NULL) {
2563 *epsgCode = msSmallMalloc((strlen("EPSG:")+strlen(value+10)+1)*sizeof(char));
2564 sprintf(*epsgCode, "EPSG:%s", value+10);
2565 return;
2566 } else if (proj && proj->numargs > 0 && (value = strstr(proj->args[0], "init=crs:")) != NULL) {
2567 *epsgCode = msSmallMalloc((strlen("CRS:")+strlen(value+9)+1)*sizeof(char));
2568 sprintf(*epsgCode, "CRS:%s", value+9);
2569 return;
2570 } else if (proj && proj->numargs > 0 && (strncasecmp(proj->args[0], "AUTO:", 5) == 0 ||
2571 strncasecmp(proj->args[0], "AUTO2:", 6) == 0)) {
2572 *epsgCode = msStrdup(proj->args[0]);
2573 return;
2574 }
2575 }
2576 /*
2577 ** msOWSGetProjURN()
2578 **
2579 ** Fetch an OGC URN for this layer or map. Similar to msOWSGetEPSGProj()
2580 ** but returns the result in the form "urn:ogc:def:crs:EPSG::27700".
2581 ** The returned buffer is dynamically allocated, and must be freed by the
2582 ** caller.
2583 */
msOWSGetProjURN(projectionObj * proj,hashTableObj * metadata,const char * namespaces,int bReturnOnlyFirstOne)2584 char *msOWSGetProjURN(projectionObj *proj, hashTableObj *metadata, const char *namespaces, int bReturnOnlyFirstOne)
2585 {
2586 char *result;
2587 char **tokens;
2588 int numtokens, i;
2589 size_t bufferSize = 0;
2590 char *oldStyle = NULL;
2591
2592 msOWSGetEPSGProj( proj, metadata, namespaces, bReturnOnlyFirstOne, &oldStyle );
2593
2594 if( oldStyle == NULL || strncmp(oldStyle,"EPSG:",5) != 0 ) {
2595 msFree(oldStyle);
2596 return NULL;
2597 }
2598
2599 result = msStrdup("");
2600
2601 tokens = msStringSplit(oldStyle, ' ', &numtokens);
2602 msFree(oldStyle);
2603 for(i=0; tokens != NULL && i<numtokens; i++) {
2604 char urn[100];
2605
2606 if( strncmp(tokens[i],"EPSG:",5) == 0 )
2607 snprintf( urn, sizeof(urn), "urn:ogc:def:crs:EPSG::%s", tokens[i]+5 );
2608 else if( strcasecmp(tokens[i],"imageCRS") == 0 )
2609 snprintf( urn, sizeof(urn), "urn:ogc:def:crs:OGC::imageCRS" );
2610 else if( strncmp(tokens[i],"urn:ogc:def:crs:",16) == 0 ) {
2611 strlcpy( urn, tokens[i], sizeof(urn));
2612 } else {
2613 strlcpy( urn, "", sizeof(urn));
2614 }
2615
2616 if( strlen(urn) > 0 ) {
2617 bufferSize = strlen(result)+strlen(urn)+2;
2618 result = (char *) realloc(result, bufferSize);
2619
2620 if( strlen(result) > 0 )
2621 strlcat( result, " ", bufferSize);
2622 strlcat( result, urn , bufferSize);
2623 } else {
2624 msDebug( "msOWSGetProjURN(): Failed to process SRS '%s', ignored.",
2625 tokens[i] );
2626 }
2627 }
2628
2629 msFreeCharArray(tokens, numtokens);
2630
2631 if( strlen(result) == 0 ) {
2632 msFree( result );
2633 return NULL;
2634 } else
2635 return result;
2636 }
2637
2638 /*
2639 ** msOWSGetProjURI()
2640 **
2641 ** Fetch an OGC URI for this layer or map. Similar to msOWSGetEPSGProj()
2642 ** but returns the result in the form "http://www.opengis.net/def/crs/EPSG/0/27700".
2643 ** The returned buffer is dynamically allocated, and must be freed by the
2644 ** caller.
2645 */
msOWSGetProjURI(projectionObj * proj,hashTableObj * metadata,const char * namespaces,int bReturnOnlyFirstOne)2646 char *msOWSGetProjURI(projectionObj *proj, hashTableObj *metadata, const char *namespaces, int bReturnOnlyFirstOne)
2647 {
2648 char *result;
2649 char **tokens;
2650 int numtokens, i;
2651 char *oldStyle = NULL;
2652
2653 msOWSGetEPSGProj( proj, metadata, namespaces, bReturnOnlyFirstOne, &oldStyle);
2654
2655 if( oldStyle == NULL || !EQUALN(oldStyle,"EPSG:",5) ) {
2656 msFree(oldStyle); // avoid leak
2657 return NULL;
2658 }
2659
2660 result = msStrdup("");
2661
2662 tokens = msStringSplit(oldStyle, ' ', &numtokens);
2663 msFree(oldStyle);
2664 for(i=0; tokens != NULL && i<numtokens; i++) {
2665 char urn[100];
2666
2667 if( strncmp(tokens[i],"EPSG:",5) == 0 )
2668 snprintf( urn, sizeof(urn), "http://www.opengis.net/def/crs/EPSG/0/%s", tokens[i]+5 );
2669 else if( strcasecmp(tokens[i],"imageCRS") == 0 )
2670 snprintf( urn, sizeof(urn), "http://www.opengis.net/def/crs/OGC/0/imageCRS" );
2671 else if( strncmp(tokens[i],"http://www.opengis.net/def/crs/",16) == 0 )
2672 snprintf( urn, sizeof(urn), "%s", tokens[i] );
2673 else
2674 strlcpy( urn, "", sizeof(urn) );
2675
2676 if( strlen(urn) > 0 ) {
2677 result = (char *) realloc(result,strlen(result)+strlen(urn)+2);
2678
2679 if( strlen(result) > 0 )
2680 strcat( result, " " );
2681 strcat( result, urn );
2682 } else {
2683 msDebug( "msOWSGetProjURI(): Failed to process SRS '%s', ignored.",
2684 tokens[i] );
2685 }
2686 }
2687
2688 msFreeCharArray(tokens, numtokens);
2689
2690 if( strlen(result) == 0 ) {
2691 msFree( result );
2692 return NULL;
2693 } else
2694 return result;
2695 }
2696
2697
2698 /*
2699 ** msOWSGetDimensionInfo()
2700 **
2701 ** Extract dimension information from a layer's metadata
2702 **
2703 ** Before 4.9, only the time dimension was support. With the addition of
2704 ** Web Map Context 1.1.0, we need to support every dimension types.
2705 ** This function get the dimension information from special metadata in
2706 ** the layer, but can also return default values for the time dimension.
2707 **
2708 */
msOWSGetDimensionInfo(layerObj * layer,const char * pszDimension,const char ** papszDimUserValue,const char ** papszDimUnits,const char ** papszDimDefault,const char ** papszDimNearValue,const char ** papszDimUnitSymbol,const char ** papszDimMultiValue)2709 void msOWSGetDimensionInfo(layerObj *layer, const char *pszDimension,
2710 const char **papszDimUserValue,
2711 const char **papszDimUnits,
2712 const char **papszDimDefault,
2713 const char **papszDimNearValue,
2714 const char **papszDimUnitSymbol,
2715 const char **papszDimMultiValue)
2716 {
2717 char *pszDimensionItem;
2718 size_t bufferSize = 0;
2719
2720 if(pszDimension == NULL || layer == NULL)
2721 return;
2722
2723 bufferSize = strlen(pszDimension)+50;
2724 pszDimensionItem = (char*)malloc(bufferSize);
2725
2726 /* units (mandatory in map context) */
2727 if(papszDimUnits != NULL) {
2728 snprintf(pszDimensionItem, bufferSize, "dimension_%s_units", pszDimension);
2729 *papszDimUnits = msOWSLookupMetadata(&(layer->metadata), "MO",
2730 pszDimensionItem);
2731 }
2732 /* unitSymbol (mandatory in map context) */
2733 if(papszDimUnitSymbol != NULL) {
2734 snprintf(pszDimensionItem, bufferSize, "dimension_%s_unitsymbol", pszDimension);
2735 *papszDimUnitSymbol = msOWSLookupMetadata(&(layer->metadata), "MO",
2736 pszDimensionItem);
2737 }
2738 /* userValue (mandatory in map context) */
2739 if(papszDimUserValue != NULL) {
2740 snprintf(pszDimensionItem, bufferSize, "dimension_%s_uservalue", pszDimension);
2741 *papszDimUserValue = msOWSLookupMetadata(&(layer->metadata), "MO",
2742 pszDimensionItem);
2743 }
2744 /* default */
2745 if(papszDimDefault != NULL) {
2746 snprintf(pszDimensionItem, bufferSize, "dimension_%s_default", pszDimension);
2747 *papszDimDefault = msOWSLookupMetadata(&(layer->metadata), "MO",
2748 pszDimensionItem);
2749 }
2750 /* multipleValues */
2751 if(papszDimMultiValue != NULL) {
2752 snprintf(pszDimensionItem, bufferSize, "dimension_%s_multiplevalues", pszDimension);
2753 *papszDimMultiValue = msOWSLookupMetadata(&(layer->metadata), "MO",
2754 pszDimensionItem);
2755 }
2756 /* nearestValue */
2757 if(papszDimNearValue != NULL) {
2758 snprintf(pszDimensionItem, bufferSize, "dimension_%s_nearestvalue", pszDimension);
2759 *papszDimNearValue = msOWSLookupMetadata(&(layer->metadata), "MO",
2760 pszDimensionItem);
2761 }
2762
2763 /* Use default time value if necessary */
2764 if(strcasecmp(pszDimension, "time") == 0) {
2765 if(papszDimUserValue != NULL && *papszDimUserValue == NULL)
2766 *papszDimUserValue = msOWSLookupMetadata(&(layer->metadata),
2767 "MO", "time");
2768 if(papszDimDefault != NULL && *papszDimDefault == NULL)
2769 *papszDimDefault = msOWSLookupMetadata(&(layer->metadata),
2770 "MO", "timedefault");
2771 if(papszDimUnits != NULL && *papszDimUnits == NULL)
2772 *papszDimUnits = "ISO8601";
2773 if(papszDimUnitSymbol != NULL && *papszDimUnitSymbol == NULL)
2774 *papszDimUnitSymbol = "t";
2775 if(papszDimNearValue != NULL && *papszDimNearValue == NULL)
2776 *papszDimNearValue = "0";
2777 }
2778
2779 free(pszDimensionItem);
2780
2781 return;
2782 }
2783
2784 /**
2785 * msOWSNegotiateUpdateSequence()
2786 *
2787 * returns the updateSequence value for an OWS
2788 *
2789 * @param requested_updatesequence the updatesequence passed by the client
2790 * @param updatesequence the updatesequence set by the server
2791 *
2792 * @return result of comparison (-1, 0, 1)
2793 * -1: lower / higher OR values not set by client or server
2794 * 1: higher / lower
2795 * 0: equal
2796 */
2797
msOWSNegotiateUpdateSequence(const char * requested_updatesequence,const char * updatesequence)2798 int msOWSNegotiateUpdateSequence(const char *requested_updatesequence, const char *updatesequence)
2799 {
2800 int i;
2801 int valtype1 = 1; /* default datatype for updatesequence passed by client */
2802 int valtype2 = 1; /* default datatype for updatesequence set by server */
2803 struct tm tm_requested_updatesequence, tm_updatesequence;
2804
2805 /* if not specified by client, or set by server,
2806 server responds with latest Capabilities XML */
2807 if (! requested_updatesequence || ! updatesequence)
2808 return -1;
2809
2810 /* test to see if server value is an integer (1), string (2) or timestamp (3) */
2811 if (msStringIsInteger(updatesequence) == MS_FAILURE)
2812 valtype1 = 2;
2813
2814 if (valtype1 == 2) { /* test if timestamp */
2815 msTimeInit(&tm_updatesequence);
2816 if (msParseTime(updatesequence, &tm_updatesequence) == MS_TRUE)
2817 valtype1 = 3;
2818 msResetErrorList();
2819 }
2820
2821 /* test to see if client value is an integer (1), string (2) or timestamp (3) */
2822 if (msStringIsInteger(requested_updatesequence) == MS_FAILURE)
2823 valtype2 = 2;
2824
2825 if (valtype2 == 2) { /* test if timestamp */
2826 msTimeInit(&tm_requested_updatesequence);
2827 if (msParseTime(requested_updatesequence, &tm_requested_updatesequence) == MS_TRUE)
2828 valtype2 = 3;
2829 msResetErrorList();
2830 }
2831
2832 /* if the datatypes do not match, do not compare, */
2833 if (valtype1 != valtype2)
2834 return -1;
2835
2836 if (valtype1 == 1) { /* integer */
2837 if (atoi(requested_updatesequence) < atoi(updatesequence))
2838 return -1;
2839
2840 if (atoi(requested_updatesequence) > atoi(updatesequence))
2841 return 1;
2842
2843 if (atoi(requested_updatesequence) == atoi(updatesequence))
2844 return 0;
2845 }
2846
2847 if (valtype1 == 2) /* string */
2848 return strcasecmp(requested_updatesequence, updatesequence);
2849
2850 if (valtype1 == 3) { /* timestamp */
2851 /* compare timestamps */
2852 i = msDateCompare(&tm_requested_updatesequence, &tm_updatesequence) +
2853 msTimeCompare(&tm_requested_updatesequence, &tm_updatesequence);
2854 return i;
2855 }
2856
2857 /* return default -1 */
2858 return -1;
2859 }
2860
2861
2862 /************************************************************************/
2863 /* msOwsIsOutputFormatValid */
2864 /* */
2865 /* Utlity function to parse a comma separated list in a */
2866 /* metedata object and select and outputformat. */
2867 /************************************************************************/
msOwsIsOutputFormatValid(mapObj * map,const char * format,hashTableObj * metadata,const char * namespaces,const char * name)2868 outputFormatObj* msOwsIsOutputFormatValid(mapObj *map, const char *format,
2869 hashTableObj *metadata,
2870 const char *namespaces, const char *name)
2871 {
2872 char **tokens=NULL;
2873 int i,n;
2874 outputFormatObj *psFormat = NULL;
2875 const char * format_list=NULL;
2876
2877 if (map && format && metadata && namespaces && name) {
2878 msApplyDefaultOutputFormats(map);
2879 format_list = msOWSLookupMetadata(metadata, namespaces, name);
2880 n = 0;
2881 if ( format_list)
2882 tokens = msStringSplit(format_list, ',', &n);
2883
2884 if (tokens && n > 0) {
2885 for (i=0; i<n; i++) {
2886 int iFormat = msGetOutputFormatIndex( map, tokens[i]);
2887 const char *mimetype;
2888 if( iFormat == -1 )
2889 continue;
2890
2891 mimetype = map->outputformatlist[iFormat]->mimetype;
2892
2893 msStringTrim(tokens[i]);
2894 if (strcasecmp(tokens[i], format) == 0)
2895 break;
2896 if (mimetype && strcasecmp(mimetype, format) == 0)
2897 break;
2898 }
2899 if (i < n)
2900 psFormat = msSelectOutputFormat( map, format);
2901 }
2902 if(tokens)
2903 msFreeCharArray(tokens, n);
2904 }
2905
2906 return psFormat;
2907 }
2908
2909 #endif /* USE_WMS_SVR || USE_WFS_SVR || USE_WCS_SVR */
2910
2911
2912
2913