source: trunk/zoo-project/zoo-kernel/request_parser.c @ 908

Last change on this file since 908 was 889, checked in by knut, 6 years ago

Added some new logging functionality (function logMessage(), macros zooLog, zooLogMsg). Added utility functions setErrorMessage(), hasvalue(), and nonempty() in service.c. Added enum WPSException and arrays WPSExceptionText and WPSExceptionCode (see also function setErrorMessage). New conditional definition of type bool in service.c (to fix issue with bool). Null pointer check in function addToMap. Added missing return values and explicit type casts in some functions. Removed Windows-specific code in function dumpBackFinalFile (zoo_service_loader.c) that may cause error for async raw data output in formats other than XML.

  • Property svn:keywords set to Id
File size: 54.8 KB
Line 
1/*
2 * Author : Gérald FENOY
3 *
4 * Copyright (c) 2015 GeoLabs SARL
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
25#include "request_parser.h"
26#include "service_internal.h"
27#include "server_internal.h"
28#include "response_print.h"
29#include "caching.h"
30
31/**
32 * Apply XPath Expression on XML document.
33 *
34 * @param doc the XML Document
35 * @param search the XPath expression
36 * @return xmlXPathObjectPtr containing the resulting nodes set
37 */
38xmlXPathObjectPtr
39extractFromDoc (xmlDocPtr doc, const char *search)
40{
41  xmlXPathContextPtr xpathCtx;
42  xmlXPathObjectPtr xpathObj;
43  xpathCtx = xmlXPathNewContext (doc);
44  xpathObj = xmlXPathEvalExpression (BAD_CAST search, xpathCtx);
45  xmlXPathFreeContext (xpathCtx);
46  return xpathObj;
47}
48
49/**
50 * Create (or append to) an array valued maps value = "["",""]"
51 *
52 * @param m the conf maps containing the main.cfg settings
53 * @param mo the map to update
54 * @param mi the map to append
55 * @param elem the elements containing default definitions
56 * @return 0 on success, -1 on failure
57 */
58int appendMapsToMaps (maps * m, maps * mo, maps * mi, elements * elem){
59  maps *tmpMaps = getMaps (mo, mi->name);
60  map *tmap = getMapType (tmpMaps->content);
61  elements *el = getElements (elem, mi->name);
62  elements *cursor = elem;
63  while(cursor!=NULL && el==NULL){
64    if(cursor->child!=NULL)
65      el = getElements (cursor->child, mi->name);
66    cursor=cursor->next;
67  }
68  int hasEl = 1;
69  if (el == NULL)
70    hasEl = -1;
71
72  if (tmap == NULL)
73    {
74      if (hasEl > 0)
75        tmap = getMapType (el->defaults->content);
76    }
77 
78  map *testMap = NULL;
79  if (hasEl > 0)
80    {
81      testMap = getMap (el->content, "maxOccurs");
82    }
83  else
84    {
85      testMap = createMap ("maxOccurs", "unbounded");
86    }
87   
88  if (testMap != NULL)
89    {
90      if (strncasecmp (testMap->value, "unbounded", 9) != 0
91          && atoi (testMap->value) > 1)
92        {
93          addMapsArrayToMaps (&mo, mi, tmap->name);
94          map* nb=getMapFromMaps(mo,mi->name,"length");
95          if (nb!=NULL && atoi(nb->value)>atoi(testMap->value))
96            {
97              char emsg[1024];
98              sprintf (emsg,
99                       _("The maximum allowed occurrences for <%s> (%i) was exceeded."),
100                       mi->name, atoi (testMap->value));
101              errorException (m, emsg, "InternalError", NULL);
102              return -1;
103            }
104        }
105      else
106        {
107          if (strncasecmp (testMap->value, "unbounded", 9) == 0)
108            {
109              if (hasEl < 0)
110                {
111                  freeMap (&testMap);
112                  free (testMap);
113                }
114              if (addMapsArrayToMaps (&mo, mi, tmap->name) < 0)
115                {
116                  char emsg[1024];
117                  map *tmpMap = getMap (mi->content, "length");
118                  sprintf (emsg,
119                           _
120                           ("ZOO-Kernel was unable to load your data for %s position %s."),
121                           mi->name, tmpMap->value);
122                  errorException (m, emsg, "InternalError", NULL);
123                  return -1;
124                }
125            }
126          else
127            {
128              char emsg[1024];
129              sprintf (emsg,
130                       _
131                       ("The maximum allowed occurrences for <%s> is one."),
132                       mi->name);
133              errorException (m, emsg, "InternalError", NULL);
134              return -1;
135            }
136        }
137    }
138  return 0;
139}
140
141/**
142 * Make sure that each value encoded in base64 in a maps is decoded.
143 *
144 * @param in the maps containing the values
145 * @see readBase64
146 */
147void ensureDecodedBase64(maps **in){
148  maps* cursor=*in;
149  while(cursor!=NULL){
150    map *tmp=getMap(cursor->content,"encoding");
151    if(tmp!=NULL && strncasecmp(tmp->value,"base64",6)==0){
152      tmp=getMap(cursor->content,"value");
153      readBase64(&tmp);
154      addToMap(cursor->content,"base64_value",tmp->value);
155      int size=0;
156      char *s=strdup(tmp->value);
157      free(tmp->value);
158      tmp->value=base64d(s,strlen(s),&size);
159      free(s);
160      char sizes[1024];
161      sprintf(sizes,"%d",size);
162      addToMap(cursor->content,"size",sizes);
163    }
164    map* length=getMap(cursor->content,"length");
165    if(length!=NULL){
166      int len=atoi(length->value);
167      for(int i=1;i<len;i++){
168        tmp=getMapArray(cursor->content,"encoding",i);
169        if(tmp!=NULL && strncasecmp(tmp->value,"base64",6)==0){
170          char key[17];
171          sprintf(key,"base64_value_%d",i);
172          tmp=getMapArray(cursor->content,"value",i);
173          readBase64(&tmp);
174          addToMap(cursor->content,key,tmp->value);
175          int size=0;
176          char *s=strdup(tmp->value);
177          free(tmp->value);
178          tmp->value=base64d(s,strlen(s),&size);
179          free(s);
180          char sizes[1024];
181          sprintf(sizes,"%d",size);
182          sprintf(key,"size_%d",i);
183          addToMap(cursor->content,key,sizes);
184        }
185      }
186    }
187    if(cursor->child!=NULL)
188      ensureDecodedBase64(&cursor->child);
189    cursor=cursor->next;
190  }
191}
192
193/**
194 * Parse inputs provided as KVP and store them in a maps.
195 *
196 * @param main_conf the conf maps containing the main.cfg settings
197 * @param s the service
198 * @param request_inputs the map storing KVP raw value
199 * @param request_output the maps to store the KVP pairs
200 * @param hInternet the HINTERNET queue to add potential requests
201 * @return 0 on success, -1 on failure
202 */
203int kvpParseInputs(maps** main_conf,service* s,map *request_inputs,maps** request_output,HINTERNET* hInternet){
204  // Parsing inputs provided as KVP
205  maps *tmpmaps = *request_output;
206  map* r_inputs = getMap (request_inputs, "DataInputs");
207  char* cursor_input;
208  if (r_inputs != NULL){
209    //snprintf (cursor_input, 40960, "%s", r_inputs->value);
210    if(strstr(r_inputs->value,"=")==NULL)
211      cursor_input = url_decode (r_inputs->value);
212    else
213      cursor_input = zStrdup (r_inputs->value);
214    int j = 0;
215
216    // Put each DataInputs into the inputs_as_text array
217    char *pToken;
218    pToken = strtok (cursor_input, ";");
219    char **inputs_as_text = (char **) malloc (100 * sizeof (char *));
220    if (inputs_as_text == NULL)
221      {
222        free(cursor_input);
223        return errorException (*main_conf, _("Unable to allocate memory"),
224                               "InternalError", NULL);
225      }
226    int i = 0;
227    while (pToken != NULL)
228      {
229        inputs_as_text[i] =
230          (char *) malloc ((strlen (pToken) + 1) * sizeof (char));
231        if (inputs_as_text[i] == NULL)
232          {
233            free(cursor_input);
234            return errorException (*main_conf, _("Unable to allocate memory"),
235                                   "InternalError", NULL);
236          }
237        snprintf (inputs_as_text[i], strlen (pToken) + 1, "%s", pToken);
238        pToken = strtok (NULL, ";");
239        i++;
240      }
241       
242    for (j = 0; j < i; j++)
243      {
244        char *tmp = zStrdup (inputs_as_text[j]);
245        free (inputs_as_text[j]);
246        char *tmpc;
247        tmpc = strtok (tmp, "@");
248        while (tmpc != NULL)
249          {
250            char *tmpv = strstr (tmpc, "=");
251            char tmpn[256];
252            memset (tmpn, 0, 256);
253            if (tmpv != NULL)
254              {
255                strncpy (tmpn, tmpc,
256                         (strlen (tmpc) - strlen (tmpv)) * sizeof (char));
257                tmpn[strlen (tmpc) - strlen (tmpv)] = 0;
258              }
259            else
260              {
261                strncpy (tmpn, tmpc, strlen (tmpc) * sizeof (char));
262                tmpn[strlen (tmpc)] = 0;
263              }
264            if (tmpmaps == NULL)
265              {
266                tmpmaps = createMaps(tmpn);
267                if (tmpmaps == NULL)
268                  {
269                    free(cursor_input);
270                    return errorException (*main_conf,
271                                           _("Unable to allocate memory"),
272                                           "InternalError", NULL);
273                  }
274                if (tmpv != NULL)
275                  {
276                    char *tmpvf = url_decode (tmpv + 1);
277                    tmpmaps->content = createMap ("value", tmpvf);
278                    free (tmpvf);
279                  }
280                else
281                  tmpmaps->content = createMap ("value", "Reference");
282                tmpmaps->next = NULL;
283              }
284            tmpc = strtok (NULL, "@");
285            while (tmpc != NULL)
286              {
287                char *tmpv1 = strstr (tmpc, "=");
288                char tmpn1[1024];
289                memset (tmpn1, 0, 1024);
290                if (tmpv1 != NULL)
291                  {
292                    strncpy (tmpn1, tmpc, strlen (tmpc) - strlen (tmpv1));
293                    tmpn1[strlen (tmpc) - strlen (tmpv1)] = 0;
294                    addToMap (tmpmaps->content, tmpn1, tmpv1 + 1);
295                  }
296                else
297                  {
298                    strncpy (tmpn1, tmpc, strlen (tmpc));
299                    tmpn1[strlen (tmpc)] = 0;
300                    map *lmap = getLastMap (tmpmaps->content);
301                    char *tmpValue =
302                      (char *) malloc ((strlen (tmpv) + strlen (tmpc) + 1) *
303                                       sizeof (char));
304                    sprintf (tmpValue, "%s@%s", tmpv + 1, tmpc);
305                    free (lmap->value);
306                    lmap->value = zStrdup (tmpValue);
307                    free (tmpValue);
308                    tmpc = strtok (NULL, "@");
309                    continue;
310                  }
311                if (strcmp (tmpn1, "xlink:href") != 0)
312                  addToMap (tmpmaps->content, tmpn1, tmpv1 + 1);
313                else if (tmpv1 != NULL)
314                  {
315                    char *tmpx2 = url_decode (tmpv1 + 1);
316                    if (strncasecmp (tmpx2, "http://", 7) != 0 &&
317                        strncasecmp (tmpx2, "ftp://", 6) != 0 &&
318                        strncasecmp (tmpx2, "https://", 8) != 0)
319                      {
320                        char emsg[1024];
321                        sprintf (emsg,
322                                 _
323                                 ("Unable to find a valid protocol to download the remote file %s"),
324                                 tmpv1 + 1);
325                        free(cursor_input);
326                        return errorException (*main_conf, emsg, "InternalError", NULL);
327                      }
328                    addToMap (tmpmaps->content, tmpn1, tmpx2);
329                    {
330                      if (loadRemoteFile
331                          (&*main_conf, &tmpmaps->content, hInternet, tmpx2) < 0)
332                        {
333                          free(cursor_input);
334                          return errorException (*main_conf, "Unable to fetch any resource", "InternalError", NULL);
335                        }
336                      }
337                    free (tmpx2);
338                    addIntToMap (tmpmaps->content, "Order", hInternet->nb);
339                    addToMap (tmpmaps->content, "Reference", tmpv1 + 1);
340                  }
341                tmpc = strtok (NULL, "@");
342              }
343            if (*request_output == NULL)
344              *request_output = dupMaps (&tmpmaps);
345            else
346              {
347                maps *testPresence =
348                  getMaps (*request_output, tmpmaps->name);
349                if (testPresence != NULL)
350                  {
351                    elements *elem =
352                      getElements (s->inputs, tmpmaps->name);
353                    if (elem != NULL)
354                      {
355                        if (appendMapsToMaps
356                            (*main_conf, *request_output, tmpmaps,
357                             elem) < 0)
358                          {
359                            free(cursor_input);
360                            return errorException (*main_conf, "Unable to append maps", "InternalError", NULL);
361                          }
362                      }
363                  }
364                else
365                  addMapsToMaps (request_output, tmpmaps);
366              }
367            freeMaps (&tmpmaps);
368            free (tmpmaps);
369            tmpmaps = NULL;
370            free (tmp);
371          }
372      }
373    free (inputs_as_text);
374    free(cursor_input);
375  }
376  return 1;
377}
378
379/**
380 * Parse outputs provided as KVP and store them in a maps.
381 *
382 * @param main_conf the conf maps containing the main.cfg settings
383 * @param request_inputs the map storing KVP raw value
384 * @param request_output the maps to store the KVP pairs
385 * @return 0 on success, -1 on failure
386 */
387int kvpParseOutputs(maps** main_conf,map *request_inputs,maps** request_output){
388  /**
389   * Parsing outputs provided as KVP
390   */
391  map *r_inputs = NULL;
392  r_inputs = getMap (request_inputs, "ResponseDocument");
393  if (r_inputs == NULL)
394    r_inputs = getMap (request_inputs, "RawDataOutput");
395
396  if (r_inputs != NULL)
397    {
398      char *cursor_output = zStrdup (r_inputs->value);
399      int j = 0;
400
401      /**
402       * Put each Output into the outputs_as_text array
403       */
404      char *pToken;
405      maps *tmp_output = NULL;
406      pToken = strtok (cursor_output, ";");
407      char **outputs_as_text = (char **) malloc (128 * sizeof (char *));
408      if (outputs_as_text == NULL)
409        {
410          free(cursor_output);
411          return errorException (*main_conf, _("Unable to allocate memory"),
412                                 "InternalError", NULL);
413        }
414      int i = 0;
415      while (pToken != NULL)
416        {
417          outputs_as_text[i] =
418            (char *) malloc ((strlen (pToken) + 1) * sizeof (char));
419          if (outputs_as_text[i] == NULL)
420            {
421              free(cursor_output);
422              return errorException (*main_conf, _("Unable to allocate memory"),
423                                     "InternalError", NULL);
424            }
425          snprintf (outputs_as_text[i], strlen (pToken) + 1, "%s",
426                    pToken);
427          pToken = strtok (NULL, ";");
428          i++;
429        }
430      for (j = 0; j < i; j++)
431        {
432          char *tmp = zStrdup (outputs_as_text[j]);
433          free (outputs_as_text[j]);
434          char *tmpc;
435          tmpc = strtok (tmp, "@");
436          int k = 0;
437          while (tmpc != NULL)
438            {
439              if (k == 0)
440                {
441                  if (tmp_output == NULL)
442                    {
443                      tmp_output = createMaps(tmpc);
444                      if (tmp_output == NULL)
445                        {
446                          free(cursor_output);
447                          return errorException (*main_conf,
448                                                 _
449                                                 ("Unable to allocate memory"),
450                                                 "InternalError", NULL);
451                        }
452                    }
453                }
454              else
455                {
456                  char *tmpv = strstr (tmpc, "=");
457                  char tmpn[256];
458                  memset (tmpn, 0, 256);
459                  strncpy (tmpn, tmpc,
460                           (strlen (tmpc) -
461                            strlen (tmpv)) * sizeof (char));
462                  tmpn[strlen (tmpc) - strlen (tmpv)] = 0;
463                  if (tmp_output->content == NULL)
464                    {
465                      tmp_output->content = createMap (tmpn, tmpv + 1);
466                      tmp_output->content->next = NULL;
467                    }
468                  else
469                    addToMap (tmp_output->content, tmpn, tmpv + 1);
470                }
471              k++;
472              tmpc = strtok (NULL, "@");
473            }
474          if (*request_output == NULL)
475            *request_output = dupMaps (&tmp_output);
476          else
477            addMapsToMaps (request_output, tmp_output);
478          freeMaps (&tmp_output);
479          free (tmp_output);
480          tmp_output = NULL;
481          free (tmp);
482        }
483      free (outputs_as_text);
484      free(cursor_output);
485    }
486  return 1;
487}
488
489/**
490 * Create a "missingIdentifier" maps in case it is NULL.
491 *
492 * @param main_conf the conf maps containing the main.cfg settings
493 * @param mymaps the maps to update
494 * @return 0 on success, 4 on failure
495 */
496int defineMissingIdentifier(maps** main_conf,maps** mymaps){
497  if (*mymaps == NULL){
498    *mymaps = createMaps("missingIndetifier");
499    if (*mymaps == NULL){
500      return errorException (*main_conf,
501                             _("Unable to allocate memory"),
502                             "InternalError", NULL);
503    }
504  }
505  return 0;
506}
507
508/**
509 * Parse inputs from XML nodes and store them in a maps.
510 *
511 * @param main_conf the conf maps containing the main.cfg settings
512 * @param s the service
513 * @param request_output the maps to store the KVP pairs
514 * @param doc the xmlDocPtr containing the original request
515 * @param nodes the input nodes array
516 * @param hInternet the HINTERNET queue to add potential requests
517 * @return 0 on success, -1 on failure
518 */
519int xmlParseInputs(maps** main_conf,service* s,maps** request_output,xmlDocPtr doc,xmlNodeSet* nodes,HINTERNET* hInternet){
520  int k = 0;
521  int l = 0;
522  map* version=getMapFromMaps(*main_conf,"main","rversion");
523  int vid=getVersionId(version->value);
524  for (k=0; k < nodes->nodeNr; k++)
525    {
526      maps *tmpmaps = NULL;
527      xmlNodePtr cur = nodes->nodeTab[k];
528
529      if (nodes->nodeTab[k]->type == XML_ELEMENT_NODE)
530        {
531          // A specific Input node.
532          if(vid==1){
533            xmlChar *val = xmlGetProp (cur, BAD_CAST "id");
534            tmpmaps = createMaps((char *) val);
535          }
536
537          xmlNodePtr cur2 = cur->children;
538          while (cur2 != NULL)
539            {
540              while (cur2 != NULL && cur2->type != XML_ELEMENT_NODE)
541                cur2 = cur2->next;
542              if (cur2 == NULL)
543                break;
544              // Indentifier
545              if (xmlStrncasecmp
546                  (cur2->name, BAD_CAST "Identifier",
547                   xmlStrlen (cur2->name)) == 0)
548                {
549                  xmlChar *val =
550                    xmlNodeListGetString (doc, cur2->xmlChildrenNode, 1);
551                  if (tmpmaps == NULL && val!=NULL)
552                    {
553                      tmpmaps = createMaps((char*)val);
554                      if (tmpmaps == NULL)
555                        {
556                          return errorException (*main_conf,
557                                                 _
558                                                 ("Unable to allocate memory"),
559                                                 "InternalError", NULL);
560                        }
561                      xmlFree (val);
562                    }
563                }
564              // Title, Asbtract
565              if (xmlStrncasecmp
566                  (cur2->name, BAD_CAST "Title",
567                   xmlStrlen (cur2->name)) == 0
568                  || xmlStrncasecmp (cur2->name, BAD_CAST "Abstract",
569                                     xmlStrlen (cur2->name)) == 0)
570                {
571                  xmlChar *val =
572                    xmlNodeListGetString (doc, cur2->xmlChildrenNode, 1);
573                  defineMissingIdentifier(main_conf,&tmpmaps);
574                  if(val!=NULL){
575                    if (tmpmaps->content != NULL)
576                      addToMap (tmpmaps->content,
577                                (char *) cur2->name, (char *) val);
578                    else
579                      tmpmaps->content =
580                        createMap ((char *) cur2->name, (char *) val);
581                    xmlFree (val);
582                  }
583                }
584              // InputDataFormChoice (Reference or Data ?) / 2.0.0 DataInputType / Input
585              if (xmlStrcasecmp (cur2->name, BAD_CAST "Input") == 0)
586                {
587                  char *xpathExpr=(char*)malloc(61+strlen(tmpmaps->name));
588                  sprintf(xpathExpr,"/*/*[local-name()='Input' and @id='%s']/*[local-name()='Input']",tmpmaps->name);
589                  xmlXPathObjectPtr tmpsptr = extractFromDoc (doc, xpathExpr);
590                  xmlNodeSet *tmps = tmpsptr->nodesetval;
591                  if(tmps!=NULL){
592                    maps* request_output1=NULL;
593                    if(xmlParseInputs(main_conf,s,&request_output1,doc,tmps,hInternet)<0)
594                      return -1;
595                    if(tmpmaps->child==NULL)
596                      tmpmaps->child=dupMaps(&request_output1);
597                    else
598                      addMapsToMaps(&tmpmaps->child,request_output1);
599                    freeMaps(&request_output1);
600                    free(request_output1);
601                  }
602                  while(cur2->next!=NULL)
603                    cur2=cur2->next;
604                }
605              else if (xmlStrcasecmp (cur2->name, BAD_CAST "Reference") == 0)
606                {
607                  defineMissingIdentifier(main_conf,&tmpmaps);
608                  // Get every attribute from a Reference node
609                  // mimeType, encoding, schema, href, method
610                  // Header and Body gesture should be added here
611                  const char *refs[5] =
612                    { "mimeType", "encoding", "schema", "method",
613                      "href"
614                    };
615                  for (l = 0; l < 5; l++)
616                    {
617                      xmlChar *val = xmlGetProp (cur2, BAD_CAST refs[l]);
618                      if (val != NULL && xmlStrlen (val) > 0)
619                        {
620                          if (tmpmaps->content != NULL)
621                            addToMap (tmpmaps->content, refs[l],
622                                      (char *) val);
623                          else
624                            tmpmaps->content =
625                              createMap (refs[l], (char *) val);
626
627                          map *ltmp = getMap (tmpmaps->content, "method");
628                          if (l == 4 )
629                            {
630                              if ((ltmp==NULL || strncasecmp (ltmp->value, "POST",4) != 0)) //
631                              //if ((ltmp==NULL || strncmp (ltmp->value, "POST",4) != 0))
632                                {
633                                  if (loadRemoteFile
634                                      (main_conf, &tmpmaps->content, hInternet,
635                                       (char *) val) != 0)
636                                    {
637                                      return errorException (*main_conf,
638                                                             _("Unable to add a request in the queue."),
639                                                             "InternalError",
640                                                             NULL);
641                                    }
642                                  addIntToMap (tmpmaps->content, "Order", hInternet->nb);
643                                }
644                              addToMap (tmpmaps->content, "Reference", (char*) val);
645                            }
646                        }
647                      xmlFree (val);
648                    }
649                  // Parse Header and Body from Reference
650                  xmlNodePtr cur3 = cur2->children;
651                  while (cur3 != NULL)
652                    {
653                      while (cur3 != NULL
654                             && cur3->type != XML_ELEMENT_NODE)
655                        cur3 = cur3->next;
656                      if (cur3 == NULL)
657                        break;
658                      if (xmlStrcasecmp (cur3->name, BAD_CAST "Header") ==
659                          0)
660                        {
661                          const char *ha[2];
662                          ha[0] = "key";
663                          ha[1] = "value";
664                          int hai;
665                          char *has=NULL;
666                          char *key;
667                          for (hai = 0; hai < 2; hai++)
668                            {
669                              xmlChar *val =
670                                xmlGetProp (cur3, BAD_CAST ha[hai]);
671#ifdef POST_DEBUG
672                              fprintf (stderr, "%s = %s\n", ha[hai],
673                                       (char *) val);
674#endif
675                              if (hai == 0)
676                                {
677                                  key = zStrdup ((char *) val);
678                                }
679                              else
680                                {
681                                  has =
682                                    (char *)
683                                    malloc ((4 + xmlStrlen (val) +
684                                             strlen (key)) *
685                                            sizeof (char));
686                                  if (has == NULL)
687                                    {
688                                      return errorException (*main_conf,
689                                                             _
690                                                             ("Unable to allocate memory"),
691                                                             "InternalError",
692                                                             NULL);
693                                    }
694                                  snprintf (has,
695                                            (3 + xmlStrlen (val) +
696                                             strlen (key)), "%s: %s", key,
697                                            (char *) val);
698                                  free (key);
699                                }
700                              xmlFree (val);
701                            }
702                          if (has != NULL){
703                            hInternet->ihandle[hInternet->nb].header = NULL;
704                            hInternet->ihandle[hInternet->nb].header =
705                              curl_slist_append (hInternet->ihandle
706                                                 [hInternet->nb].header,
707                                                 has);
708                            free (has);
709                          }
710                        }
711                      else
712                        {
713#ifdef POST_DEBUG
714                          fprintf (stderr,
715                                   "Try to fetch the body part of the request ...\n");
716#endif
717                          if (xmlStrcasecmp (cur3->name, BAD_CAST "Body")
718                              == 0)
719                            {
720#ifdef POST_DEBUG
721                              fprintf (stderr, "Body part found (%s) !!!\n",
722                                       (char *) cur3->content);
723#endif
724                              char *tmp = NULL;
725                              xmlNodePtr cur4 = cur3->children;
726                              while (cur4 != NULL)
727                                {
728                                  while (cur4 && cur4 != NULL && cur4->type && cur4->type != XML_ELEMENT_NODE){
729                                    if(cur4->next)
730                                      cur4 = cur4->next;
731                                    else
732                                      cur4 = NULL;
733                                  }
734                                  if(cur4 != NULL) {
735                                    xmlDocPtr bdoc =
736                                      xmlNewDoc (BAD_CAST "1.0");
737                                    bdoc->encoding =
738                                      xmlCharStrdup ("UTF-8");
739                                    xmlDocSetRootElement (bdoc, cur4);
740                                    xmlChar *btmps;
741                                    int bsize;
742                                    // TODO : check for encoding defined in the input
743                                    xmlDocDumpFormatMemoryEnc(bdoc, &btmps, &bsize, "UTF-8", 0);
744                                    if (btmps != NULL){
745                                      tmp = (char *) malloc ((bsize + 1) * sizeof (char));
746
747                                      sprintf (tmp, "%s", (char*) btmps);
748
749                                      //xmlFreeDoc (bdoc);
750                                         
751                                      map *btmp =
752                                        getMap (tmpmaps->content, "Reference");
753                                      if (btmp != NULL)
754                                        {
755                                          addRequestToQueue(main_conf,hInternet,(char *) btmp->value,false);
756                                          InternetOpenUrl (hInternet,
757                                                           btmp->value,
758                                                           tmp,
759                                                           xmlStrlen(btmps),
760                                                           INTERNET_FLAG_NO_CACHE_WRITE,
761                                                           0);
762                                          addIntToMap (tmpmaps->content, "Order", hInternet->nb);
763                                        }
764                                      xmlFree (btmps);
765                                      free (tmp);
766                                      break;
767                                    }
768                                  }
769                                  cur4 = cur4->next;
770                                }
771                            }
772                          else
773                            if (xmlStrcasecmp
774                                (cur3->name,
775                                 BAD_CAST "BodyReference") == 0)
776                              {
777                                xmlChar *val =
778                                  xmlGetProp (cur3, BAD_CAST "href");
779                                HINTERNET bInternet, res1, res;
780                                bInternet = InternetOpen (
781#ifndef WIN32
782                                                          (LPCTSTR)
783#endif
784                                                          "ZooWPSClient\0",
785                                                          INTERNET_OPEN_TYPE_PRECONFIG,
786                                                          NULL, NULL, 0);
787                                if (!CHECK_INET_HANDLE (bInternet))
788                                  fprintf (stderr,
789                                           "WARNING : bInternet handle failed to initialize");
790                                bInternet.waitingRequests[0] =
791                                  strdup ((char *) val);
792                                res1 =
793                                  InternetOpenUrl (&bInternet,
794                                                   bInternet.waitingRequests
795                                                   [0], NULL, 0,
796                                                   INTERNET_FLAG_NO_CACHE_WRITE,
797                                                   0);
798                                processDownloads (&bInternet);
799                                char *tmp =
800                                  (char *)
801                                  malloc ((bInternet.ihandle[0].nDataLen +
802                                           1) * sizeof (char));
803                                if (tmp == NULL)
804                                  {
805                                    return errorException (*main_conf,
806                                                           _
807                                                           ("Unable to allocate memory"),
808                                                           "InternalError",
809                                                           NULL);
810                                  }
811                                size_t bRead;
812                                InternetReadFile (bInternet.ihandle[0],
813                                                  (LPVOID) tmp,
814                                                  bInternet.
815                                                  ihandle[0].nDataLen,
816                                                  &bRead);
817                                tmp[bInternet.ihandle[0].nDataLen] = 0;
818                                InternetCloseHandle (&bInternet);
819                                map *btmp =
820                                  getMap (tmpmaps->content, "href");
821                                if (btmp != NULL)
822                                  {
823                                    addRequestToQueue(main_conf,hInternet,(char *) btmp->value,false);
824
825                                    res =
826                                      InternetOpenUrl (hInternet,
827                                                       btmp->value,
828                                                       tmp,
829                                                       strlen(tmp),
830                                                       INTERNET_FLAG_NO_CACHE_WRITE,
831                                                       0);
832                                    addIntToMap (tmpmaps->content, "Order", hInternet->nb);
833                                  }
834                                free (tmp);
835                              }
836                        }
837                      cur3 = cur3->next;
838                    }
839                }
840              else if (xmlStrcasecmp (cur2->name, BAD_CAST "Data") == 0)
841                {
842                  defineMissingIdentifier(main_conf,&tmpmaps);
843                  xmlNodePtr cur4 = cur2->children;
844                  if(vid==1){
845                    // Get every dataEncodingAttributes from a Data node:
846                    // mimeType, encoding, schema
847                    const char *coms[3] =
848                      { "mimeType", "encoding", "schema" };
849                    for (l = 0; l < 3; l++){
850                      xmlChar *val =
851                          xmlGetProp (cur4, BAD_CAST coms[l]);
852                        if (val != NULL && strlen ((char *) val) > 0){
853                          if (tmpmaps->content != NULL)
854                            addToMap (tmpmaps->content,coms[l],(char *) val);
855                          else
856                            tmpmaps->content =
857                              createMap (coms[l],(char *) val);
858                        }
859                        xmlFree (val);
860                    }
861                    while (cur4 != NULL){
862                      while(cur4 != NULL && 
863                            cur4->type != XML_CDATA_SECTION_NODE &&
864                            cur4->type != XML_TEXT_NODE &&
865                            cur4->type != XML_ELEMENT_NODE)
866                        cur4=cur4->next;
867                      if(cur4!=NULL){
868                        if (cur4->type == XML_ELEMENT_NODE)
869                          {
870                            xmlChar *mv;
871                            int buffersize;
872                            xmlDocPtr doc1 = xmlNewDoc (BAD_CAST "1.0");
873                            xmlDocSetRootElement (doc1, cur4);
874                            xmlDocDumpFormatMemoryEnc (doc1, &mv,
875                                                       &buffersize,
876                                                       "utf-8", 0);
877                            if (tmpmaps->content != NULL)
878                              addToMap (tmpmaps->content, "value",
879                                        (char *) mv);
880                            else
881                              tmpmaps->content =
882                                createMap ("value", (char *) mv);
883                            free(mv);
884                          }
885                        else{
886                          if (tmpmaps->content != NULL)
887                            addToMap (tmpmaps->content, "value",
888                                      (char *) cur4->content);
889                          else
890                            tmpmaps->content =
891                              createMap ("value", (char *) cur4->content);
892                        }
893                        cur4=cur4->next;
894                      }
895                    }
896                  }
897
898
899                  while (cur4 != NULL)
900                    {
901                      while (cur4 != NULL
902                             && cur4->type != XML_ELEMENT_NODE)
903                        cur4 = cur4->next;
904                      if (cur4 == NULL)
905                        break;
906                      if (xmlStrcasecmp
907                          (cur4->name, BAD_CAST "LiteralData") == 0)
908                        {
909                          // Get every attribute from a LiteralData node
910                          // dataType , uom
911                          char *list[2];
912                          list[0] = zStrdup ("dataType");
913                          list[1] = zStrdup ("uom");
914                          for (l = 0; l < 2; l++)
915                            {
916                              xmlChar *val =
917                                xmlGetProp (cur4, BAD_CAST list[l]);
918                              if (val != NULL
919                                  && strlen ((char *) val) > 0)
920                                {
921                                  if (tmpmaps->content != NULL)
922                                    addToMap (tmpmaps->content, list[l],
923                                              (char *) val);
924                                  else
925                                    tmpmaps->content =
926                                      createMap (list[l], (char *) val);
927                                  xmlFree (val);
928                                }
929                              else{
930                                if(l==0){
931                                  if (tmpmaps->content != NULL)
932                                    addToMap (tmpmaps->content, list[l],
933                                              "string");
934                                  else
935                                    tmpmaps->content =
936                                      createMap (list[l],"string");
937                                }
938                              }
939                              free (list[l]);
940                            }
941                        }
942                      else
943                        if (xmlStrcasecmp
944                            (cur4->name, BAD_CAST "ComplexData") == 0)
945                          {
946                            // Get every attribute from a Reference node
947                            // mimeType, encoding, schema
948                            const char *coms[3] =
949                              { "mimeType", "encoding", "schema" };
950                            for (l = 0; l < 3; l++)
951                              {
952                                xmlChar *val =
953                                  xmlGetProp (cur4, BAD_CAST coms[l]);
954                                if (val != NULL
955                                    && strlen ((char *) val) > 0)
956                                  {
957                                    if (tmpmaps->content != NULL)
958                                      addToMap (tmpmaps->content, coms[l],
959                                                (char *) val);
960                                    else
961                                      tmpmaps->content =
962                                        createMap (coms[l], (char *) val);
963                                    xmlFree (val);
964                                  }
965                              }
966                          }
967
968                      map *test = getMap (tmpmaps->content, "encoding");
969
970                      if (test == NULL)
971                        { 
972                          if (tmpmaps->content != NULL)
973                            addToMap (tmpmaps->content, "encoding",
974                                      "utf-8");
975                          else
976                            tmpmaps->content =
977                              createMap ("encoding", "utf-8");
978                          test = getMap (tmpmaps->content, "encoding");
979                        }
980
981                      if (getMap(tmpmaps->content,"dataType")==NULL && strcasecmp (test->value, "base64") != 0)
982                        { 
983                          xmlChar *mv = xmlNodeListGetString (doc,
984                                                              cur4->xmlChildrenNode,
985                                                              1);
986                          map *ltmp =
987                            getMap (tmpmaps->content, "mimeType");
988                          if (mv == NULL
989                              ||
990                              (xmlStrcasecmp
991                               (cur4->name, BAD_CAST "ComplexData") == 0
992                               && (ltmp == NULL
993                                   || strncasecmp (ltmp->value,
994                                                   "text/xml", 8) == 0)))
995                            {
996                              xmlDocPtr doc1 = xmlNewDoc (BAD_CAST "1.0");
997                              int buffersize;
998                              xmlNodePtr cur5 = cur4->children;
999                              while (cur5 != NULL
1000                                     && cur5->type != XML_ELEMENT_NODE
1001                                     && cur5->type != XML_CDATA_SECTION_NODE)
1002                                cur5 = cur5->next;
1003                              if (cur5 != NULL
1004                                  && cur5->type != XML_CDATA_SECTION_NODE)
1005                                {
1006                                  xmlDocSetRootElement (doc1, cur5);
1007                                  xmlDocDumpFormatMemoryEnc (doc1, &mv,
1008                                                             &buffersize,
1009                                                             "utf-8", 0);
1010                                  xmlFreeDoc (doc1);
1011                                }
1012                              else
1013                                {
1014                                  if (cur5 != NULL
1015                                      && cur5->type == XML_CDATA_SECTION_NODE){
1016                                    xmlDocPtr doc2 = xmlReadMemory((const char*)cur5->content,xmlStrlen(cur5->content),
1017                                                                   "input_content.xml", NULL, XML_PARSE_RECOVER);
1018                                    xmlDocDumpFormatMemoryEnc (doc2, &mv,
1019                                                               &buffersize,
1020                                                               "utf-8", 0);
1021                                    xmlFreeDoc (doc2);
1022                                  }
1023                                }
1024                              addIntToMap (tmpmaps->content, "size",
1025                                           buffersize);
1026                            }else{
1027                            if(xmlStrcasecmp
1028                               (cur4->name, BAD_CAST "BoundingBoxData") == 0){
1029                              xmlDocPtr doc1 = xmlNewDoc(BAD_CAST "1.0");
1030                              int buffersize;
1031                              xmlDocSetRootElement(doc1,cur4);
1032                              xmlDocDumpFormatMemoryEnc(doc1,&mv,
1033                                                        &buffersize,
1034                                                        "utf-8",0);
1035                              addIntToMap (tmpmaps->content, "size",
1036                                           buffersize);
1037                              xmlParseBoundingBox(main_conf,&tmpmaps->content,doc1);
1038                            }else{
1039                              xmlNodePtr cur5 = cur4->children;
1040                              while (cur5 != NULL
1041                                     && cur5->type != XML_CDATA_SECTION_NODE)
1042                                cur5 = cur5->next;
1043                              if (cur5 != NULL
1044                                  && cur5->type == XML_CDATA_SECTION_NODE){
1045                                if(mv!=NULL)
1046                                  xmlFree(mv);
1047                                mv=xmlStrdup(cur5->content);
1048                              }
1049                            }
1050                          }
1051                          if (mv != NULL)
1052                            {
1053                              addToMap (tmpmaps->content, "value",
1054                                        (char*) mv);
1055                              xmlFree (mv);
1056                            }
1057                        }
1058                      else
1059                        {
1060                          xmlNodePtr cur5 = cur4->children;
1061                          while (cur5 != NULL
1062                                 && cur5->type != XML_CDATA_SECTION_NODE)
1063                            cur5 = cur5->next;
1064                          if (cur5 != NULL
1065                              && cur5->type == XML_CDATA_SECTION_NODE)
1066                            {
1067                              addToMap (tmpmaps->content,
1068                                        "value",
1069                                        (char *) cur5->content);
1070                            }
1071                          else{
1072                            if(cur4->xmlChildrenNode!=NULL){
1073                              xmlChar *tmp = xmlNodeListGetRawString (doc,
1074                                                                      cur4->xmlChildrenNode,
1075                                                                      0);
1076                              addToMap (tmpmaps->content, "value",
1077                                        (char *) tmp);
1078                              xmlFree (tmp);
1079                            }
1080                          }
1081                        }
1082
1083                      cur4 = cur4->next;
1084                    }
1085                }
1086              cur2 = cur2->next;
1087              while (cur2 != NULL && cur2->type != XML_ELEMENT_NODE){
1088                cur2 = cur2->next;
1089              }
1090            }
1091          {
1092            map* test=getMap(tmpmaps->content,"value");
1093            if(test==NULL && tmpmaps->child==NULL)
1094              addToMap(tmpmaps->content,"value","");
1095            maps *testPresence = getMaps (*request_output, tmpmaps->name);
1096            maps *cursor=*request_output;
1097            while(testPresence == NULL && cursor!=NULL){
1098              if(cursor->child!=NULL){
1099                testPresence = getMaps (cursor->child, tmpmaps->name);
1100              }
1101              cursor=cursor->next;
1102            }
1103            if (testPresence != NULL)
1104              {
1105                elements *elem = getElements (s->inputs, tmpmaps->name);
1106                elements *cursor=s->inputs;
1107                while(elem == NULL && cursor!=NULL){
1108                  if(cursor->child!=NULL){
1109                    elem = getElements (cursor->child, tmpmaps->name);
1110                  }
1111                  cursor=cursor->next;
1112                }
1113                if (elem != NULL)
1114                  {
1115                    if (appendMapsToMaps
1116                        (*main_conf, testPresence, tmpmaps, elem) < 0)
1117                      {
1118                        return errorException (*main_conf,
1119                                               _("Unable to append maps to maps."),
1120                                               "InternalError",
1121                                               NULL);
1122                      }
1123                  }
1124              }
1125            else
1126              addMapsToMaps (request_output, tmpmaps);
1127          }
1128          freeMaps (&tmpmaps);
1129          free (tmpmaps);
1130          tmpmaps = NULL;
1131        }
1132    }
1133  return 1;
1134}
1135
1136/**
1137 * Parse a BoundingBoxData node
1138 *
1139 * http://schemas.opengis.net/ows/1.1.0/owsCommon.xsd: BoundingBoxType
1140 *
1141 * A map to store boundingbox information will contain:
1142 *  - LowerCorner : double double (minimum within this bounding box)
1143 *  - UpperCorner : double double (maximum within this bounding box)
1144 *  - crs : URI (Reference to definition of the CRS)
1145 *  - dimensions : int
1146 *
1147 * @param main_conf the conf maps containing the main.cfg settings
1148 * @param request_inputs the map storing KVP raw value
1149 * @param doc the xmlDocPtr containing the BoudingoxData node
1150 * @return a map containing all the bounding box keys
1151 */
1152int xmlParseBoundingBox(maps** main_conf,map** current_input,xmlDocPtr doc){
1153  xmlNode *root_element = xmlDocGetRootElement(doc);
1154  for(xmlAttrPtr attr = root_element->properties; NULL != attr; attr = attr->next){
1155    xmlChar *val = xmlGetProp (root_element, BAD_CAST attr->name);
1156    addToMap(*current_input,(char*)attr->name,(char*)val);
1157    xmlFree(val);
1158    xmlNodePtr cur = root_element->children;
1159    while(cur!=NULL && cur->type != XML_ELEMENT_NODE)
1160      cur=cur->next;
1161    while(cur!=NULL && cur->type==XML_ELEMENT_NODE){
1162      xmlChar *val =
1163        xmlNodeListGetString (doc, cur->xmlChildrenNode, 1);
1164      addToMap(*current_input,(char*)cur->name,(char*)val);
1165      cur=cur->next;
1166      xmlFree(val);
1167      while(cur!=NULL && cur->type != XML_ELEMENT_NODE)
1168        cur=cur->next;
1169    }
1170  }
1171  return 0;
1172}
1173
1174/**
1175 * Parse outputs from XML nodes and store them in a maps (WPS version 2.0.0).
1176 *
1177 * @param main_conf the conf maps containing the main.cfg settings
1178 * @param request_inputs the map storing KVP raw value
1179 * @param request_output the maps to store the KVP pairs
1180 * @param doc the xmlDocPtr containing the original request
1181 * @param cur the xmlNodePtr corresponding to the ResponseDocument or RawDataOutput XML node
1182 * @param raw true if the node is RawDataOutput, false in case of ResponseDocument
1183 * @return 0 on success, -1 on failure
1184 */
1185int xmlParseOutputs2(maps** main_conf,map** request_inputs,maps** request_output,xmlDocPtr doc,xmlNodeSet* nodes){
1186  int k = 0;
1187  int l = 0;
1188  for (k=0; k < nodes->nodeNr; k++){
1189    maps *tmpmaps = NULL;
1190    xmlNodePtr cur = nodes->nodeTab[k];
1191    if (cur->type == XML_ELEMENT_NODE){
1192      maps *tmpmaps = NULL;
1193      xmlChar *val = xmlGetProp (cur, BAD_CAST "id");
1194      if(val!=NULL)
1195        tmpmaps = createMaps((char *)val);
1196      else
1197        tmpmaps = createMaps("unknownIdentifier");
1198      const char ress[4][13] =
1199        { "mimeType", "encoding", "schema", "transmission" };
1200      for (l = 0; l < 4; l++){
1201        val = xmlGetProp (cur, BAD_CAST ress[l]);
1202        if (val != NULL && strlen ((char *) val) > 0)
1203          {
1204            if (tmpmaps->content != NULL)
1205              addToMap (tmpmaps->content, ress[l],
1206                        (char *) val);
1207            else
1208              tmpmaps->content =
1209                createMap (ress[l], (char *) val);
1210            if(l==3 && strncasecmp((char*)val,"reference",xmlStrlen(val))==0)
1211              addToMap (tmpmaps->content,"asReference","true");
1212          }
1213        xmlFree (val);
1214      }
1215      if(cur->children!=NULL){
1216        xmlNodePtr ccur = cur->children;
1217        while (ccur != NULL){
1218          if(ccur->type == XML_ELEMENT_NODE){
1219            char *xpathExpr=(char*)malloc(65+strlen(tmpmaps->name));
1220            sprintf(xpathExpr,"/*/*[local-name()='Output' and @id='%s']/*[local-name()='Output']",tmpmaps->name);
1221            xmlXPathObjectPtr tmpsptr = extractFromDoc (doc, xpathExpr);
1222            xmlNodeSet* cnodes = tmpsptr->nodesetval;
1223            xmlParseOutputs2(main_conf,request_inputs,&tmpmaps->child,doc,cnodes);
1224            break;
1225          }
1226          ccur = ccur->next;
1227        }
1228      }
1229      if (*request_output == NULL){
1230        *request_output = dupMaps(&tmpmaps);
1231      }
1232      else{
1233        addMapsToMaps(request_output,tmpmaps);
1234      }
1235      freeMaps(&tmpmaps);
1236      free(tmpmaps);
1237    }
1238  }
1239  return 0;
1240}
1241
1242/**
1243 * Parse outputs from XML nodes and store them in a maps.
1244 *
1245 * @param main_conf the conf maps containing the main.cfg settings
1246 * @param request_inputs the map storing KVP raw value
1247 * @param request_output the maps to store the KVP pairs
1248 * @param doc the xmlDocPtr containing the original request
1249 * @param cur the xmlNodePtr corresponding to the ResponseDocument or RawDataOutput XML node
1250 * @param raw true if the node is RawDataOutput, false in case of ResponseDocument
1251 * @return 0 on success, -1 on failure
1252 */
1253int xmlParseOutputs(maps** main_conf,map** request_inputs,maps** request_output,xmlDocPtr doc,xmlNodePtr cur,bool raw){
1254  int l=0;
1255  if( raw == true)
1256    {
1257      addToMap (*request_inputs, "RawDataOutput", "");
1258      if (cur->type == XML_ELEMENT_NODE)
1259        {
1260
1261          maps *tmpmaps = createMaps("unknownIdentifier");
1262          if (tmpmaps == NULL)
1263            {
1264              return errorException (*main_conf, _("Unable to allocate memory"),
1265                                     "InternalError", NULL);
1266            }
1267
1268          // Get every attribute from a RawDataOutput node
1269          // mimeType, encoding, schema, uom
1270          const char *outs[4] =
1271            { "mimeType", "encoding", "schema", "uom" };
1272          for (l = 0; l < 4; l++)
1273            {
1274              xmlChar *val = xmlGetProp (cur, BAD_CAST outs[l]);
1275              if (val != NULL)
1276                {
1277                  if (strlen ((char *) val) > 0)
1278                    {
1279                      if (tmpmaps->content != NULL)
1280                        addToMap (tmpmaps->content, outs[l],
1281                                  (char *) val);
1282                      else
1283                        tmpmaps->content =
1284                          createMap (outs[l], (char *) val);
1285                    }
1286                  xmlFree (val);
1287                }
1288            }
1289          xmlNodePtr cur2 = cur->children;
1290          while (cur2 != NULL && cur2->type != XML_ELEMENT_NODE)
1291            cur2 = cur2->next;
1292          while (cur2 != NULL)
1293            {
1294              if (xmlStrncasecmp
1295                  (cur2->name, BAD_CAST "Identifier",
1296                   xmlStrlen (cur2->name)) == 0)
1297                {
1298                  xmlChar *val =
1299                    xmlNodeListGetString (NULL, cur2->xmlChildrenNode, 1);
1300                  free (tmpmaps->name);
1301                  tmpmaps->name = zStrdup ((char *) val);
1302                  xmlFree (val);
1303                }
1304              cur2 = cur2->next;
1305              while (cur2 != NULL && cur2->type != XML_ELEMENT_NODE)
1306                cur2 = cur2->next;
1307            }
1308          if (*request_output == NULL)
1309            *request_output = dupMaps (&tmpmaps);
1310          else
1311            addMapsToMaps (request_output, tmpmaps);
1312          if (tmpmaps != NULL)
1313            {
1314              freeMaps (&tmpmaps);
1315              free (tmpmaps);
1316              tmpmaps = NULL;
1317            }
1318        }
1319    }
1320  else
1321    {
1322      addToMap (*request_inputs, "ResponseDocument", "");
1323
1324      if (cur->type == XML_ELEMENT_NODE) {
1325        // Get every attribute: storeExecuteResponse, lineage, status
1326        const char *ress[3] =
1327          { "storeExecuteResponse", "lineage", "status" };
1328        xmlChar *val;
1329        for (l = 0; l < 3; l++)
1330          {
1331            val = xmlGetProp (cur, BAD_CAST ress[l]);
1332            if (val != NULL && strlen ((char *) val) > 0)
1333              {
1334                addToMap (*request_inputs, ress[l], (char *) val);
1335              }
1336            xmlFree (val);
1337          }
1338                       
1339        xmlNodePtr cur1 = cur->children;               
1340        while (cur1 != NULL) // iterate over Output nodes
1341          {
1342            if (cur1->type != XML_ELEMENT_NODE || 
1343                xmlStrncasecmp(cur1->name, BAD_CAST "Output", 
1344                               xmlStrlen (cur1->name)) != 0) {
1345              cur1 = cur1->next;
1346              continue;
1347            }
1348                               
1349            maps *tmpmaps = createMaps("unknownIdentifier"); // one per Output node
1350            if (tmpmaps == NULL) {
1351              return errorException (*main_conf,
1352                                     _
1353                                     ("Unable to allocate memory"),
1354                                     "InternalError", NULL);
1355            }
1356                               
1357            xmlNodePtr elems = cur1->children;
1358                               
1359            while (elems != NULL) {
1360
1361              // Identifier
1362              if (xmlStrncasecmp
1363                  (elems->name, BAD_CAST "Identifier",
1364                   xmlStrlen (elems->name)) == 0)
1365                {
1366                  xmlChar *val =
1367                    xmlNodeListGetString (doc, elems->xmlChildrenNode, 1);
1368               
1369                  free(tmpmaps->name);
1370                  tmpmaps->name = zStrdup ((char *) val);
1371                  if (tmpmaps->content == NULL) {
1372                    tmpmaps->content = createMap("Identifier", zStrdup ((char *) val));
1373                  }
1374                  else {
1375                    addToMap(tmpmaps->content, "Identifier", zStrdup ((char *) val));
1376                  }
1377
1378                  map* tt = getMap (*request_inputs, "ResponseDocument");
1379                  if (strlen(tt->value) == 0) {
1380                    addToMap (*request_inputs, "ResponseDocument",
1381                              (char *) val);
1382                  }
1383                  else {
1384                    char* tmp = (char*) malloc((strlen(tt->value) + 1 
1385                                                + strlen((char*) val) + 1) * sizeof(char));
1386                    sprintf (tmp, "%s;%s", tt->value, (char *) val);
1387                    free(tt->value);
1388                    tt->value = tmp;
1389                  }
1390                  xmlFree (val);
1391                }
1392             
1393              // Title, Abstract
1394              else if (xmlStrncasecmp(elems->name, BAD_CAST "Title",
1395                                      xmlStrlen (elems->name)) == 0
1396                       || xmlStrncasecmp(elems->name, BAD_CAST "Abstract",
1397                                         xmlStrlen (elems->name)) == 0)
1398                {
1399                  xmlChar *val =
1400                    xmlNodeListGetString (doc, elems->xmlChildrenNode, 1);
1401                                                       
1402                  if (tmpmaps->content == NULL) {
1403                    tmpmaps->content = createMap((char*) elems->name, zStrdup ((char *) val));
1404                  }
1405                  else {
1406                    addToMap(tmpmaps->content, (char*) elems->name, zStrdup ((char *) val));
1407                  }
1408                  xmlFree (val);
1409                }
1410              elems = elems->next;
1411            }
1412                               
1413            // Get every attribute from an Output node:
1414            // mimeType, encoding, schema, uom, asReference
1415            const char *outs[5] =
1416              { "mimeType", "encoding", "schema", "uom", "asReference" };
1417                                         
1418            for (l = 0; l < 5; l++) {
1419              xmlChar *val = xmlGetProp (cur1, BAD_CAST outs[l]);                               
1420              if (val != NULL && xmlStrlen(val) > 0) {
1421                if (tmpmaps->content != NULL) {
1422                  addToMap (tmpmaps->content, outs[l], (char *) val);
1423                }                         
1424                else {
1425                  tmpmaps->content = createMap (outs[l], (char *) val);
1426                }       
1427              }
1428              xmlFree (val);
1429            }
1430                               
1431            if (*request_output == NULL) {
1432              *request_output = tmpmaps;
1433            }   
1434            else if (getMaps(*request_output, tmpmaps->name) != NULL) {
1435              return errorException (*main_conf,
1436                                     _
1437                                     ("Duplicate <Output> elements in WPS Execute request"),
1438                                     "InternalError", NULL);
1439            }
1440            else {
1441              maps* mptr = *request_output;
1442              while (mptr->next != NULL) {
1443                mptr = mptr->next;
1444              }
1445              mptr->next = tmpmaps;     
1446            }                                   
1447            cur1 = cur1->next;
1448          }                     
1449      }
1450    }
1451  return 1;
1452}
1453
1454/**
1455 * Parse XML request and store information in maps.
1456 *
1457 * @param main_conf the conf maps containing the main.cfg settings
1458 * @param post the string containing the XML request
1459 * @param request_inputs the map storing KVP raw value
1460 * @param s the service
1461 * @param inputs the maps to store the KVP pairs
1462 * @param outputs the maps to store the KVP pairs
1463 * @param hInternet the HINTERNET queue to add potential requests
1464 * @return 0 on success, -1 on failure
1465 */
1466int xmlParseRequest(maps** main_conf,const char* post,map** request_inputs,service* s,maps** inputs,maps** outputs,HINTERNET* hInternet){
1467
1468  map* version=getMapFromMaps(*main_conf,"main","rversion");
1469  int vid=getVersionId(version->value);
1470
1471  xmlInitParser ();
1472  //xmlDocPtr doc = xmlReadMemory (post, cgiContentLength, "input_request.xml", NULL, XML_PARSE_RECOVER);
1473  xmlDocPtr doc = xmlReadMemory (post, cgiContentLength, "input_request.xml", NULL, XML_PARSE_RECOVER | XML_PARSE_HUGE); //
1474
1475  /**
1476   * Extract Input nodes from the XML Request.
1477   */
1478  xmlXPathObjectPtr tmpsptr =
1479    extractFromDoc (doc, (vid==0?"/*/*/*[local-name()='Input']":"/*/*[local-name()='Input']"));
1480  xmlNodeSet *tmps = tmpsptr->nodesetval;
1481  if(tmps==NULL || xmlParseInputs(main_conf,s,inputs,doc,tmps,hInternet)<0){
1482    xmlXPathFreeObject (tmpsptr);
1483    xmlFreeDoc (doc);
1484    xmlCleanupParser ();
1485    return -1;
1486  }
1487  xmlXPathFreeObject (tmpsptr);
1488
1489  if(vid==1){
1490    tmpsptr =
1491      extractFromDoc (doc, "/*[local-name()='Execute']");
1492    bool asRaw = false;
1493    tmps = tmpsptr->nodesetval;
1494    if(tmps->nodeNr > 0){
1495      int k = 0;
1496      for (k=0; k < tmps->nodeNr; k++){
1497        maps *tmpmaps = NULL;
1498        xmlNodePtr cur = tmps->nodeTab[k];
1499        if (cur->type == XML_ELEMENT_NODE){
1500          xmlChar *val = xmlGetProp (cur, BAD_CAST "mode");
1501          if(val!=NULL)
1502            addToMap(*request_inputs,"mode",(char*)val);
1503          else
1504            addToMap(*request_inputs,"mode","auto");
1505          val = xmlGetProp (cur, BAD_CAST "response");
1506          if(val!=NULL){
1507            addToMap(*request_inputs,"response",(char*)val);
1508            if(strncasecmp((char*)val,"raw",xmlStrlen(val))==0)
1509              addToMap(*request_inputs,"RawDataOutput","");
1510            else
1511              addToMap(*request_inputs,"ResponseDocument","");
1512          }
1513          else{
1514            addToMap(*request_inputs,"response","document");
1515            addToMap(*request_inputs,"ResponseDocument","");
1516          }
1517        }
1518      }
1519    }
1520    xmlXPathFreeObject (tmpsptr);
1521    tmpsptr =
1522      extractFromDoc (doc, "/*/*[local-name()='Output']");
1523    tmps = tmpsptr->nodesetval;
1524    if(tmps->nodeNr > 0){
1525      if(xmlParseOutputs2(main_conf,request_inputs,outputs,doc,tmps)<0){
1526        xmlXPathFreeObject (tmpsptr);
1527        xmlFreeDoc (doc);
1528        xmlCleanupParser ();
1529        return -1;
1530      }
1531    }
1532  }
1533  else{
1534    // Extract ResponseDocument / RawDataOutput from the XML Request
1535    tmpsptr =
1536      extractFromDoc (doc, "/*/*/*[local-name()='ResponseDocument']");
1537    bool asRaw = false;
1538    tmps = tmpsptr->nodesetval;
1539    if (tmps->nodeNr == 0)
1540      {
1541        xmlXPathFreeObject (tmpsptr);
1542        tmpsptr =
1543          extractFromDoc (doc, "/*/*/*[local-name()='RawDataOutput']");
1544        tmps = tmpsptr->nodesetval;
1545        asRaw = true;
1546      }
1547    if(tmps->nodeNr != 0){
1548      if(xmlParseOutputs(main_conf,request_inputs,outputs,doc,tmps->nodeTab[0],asRaw)<0){
1549        xmlXPathFreeObject (tmpsptr);
1550        xmlFreeDoc (doc);
1551        xmlCleanupParser ();
1552        return -1;
1553      }
1554    }
1555  }
1556  xmlXPathFreeObject (tmpsptr);
1557  xmlFreeDoc (doc);
1558  xmlCleanupParser ();
1559  return 1;
1560}
1561
1562/**
1563 * Parse request and store information in maps.
1564 *
1565 * @param main_conf the conf maps containing the main.cfg settings
1566 * @param post the string containing the XML request
1567 * @param request_inputs the map storing KVP raw value
1568 * @param s the service
1569 * @param inputs the maps to store the KVP pairs
1570 * @param outputs the maps to store the KVP pairs
1571 * @param hInternet the HINTERNET queue to add potential requests
1572 * @return 0 on success, -1 on failure
1573 * @see kvpParseOutputs,kvpParseInputs,xmlParseRequest
1574 */
1575int parseRequest(maps** main_conf,map** request_inputs,service* s,maps** inputs,maps** outputs,HINTERNET* hInternet){
1576  map *postRequest = NULL;
1577  postRequest = getMap (*request_inputs, "xrequest");
1578  if (postRequest == NULLMAP)
1579    {
1580      if(kvpParseOutputs(main_conf,*request_inputs,outputs)<0){
1581        return -1;
1582      }
1583      if(kvpParseInputs(main_conf,s,*request_inputs,inputs,hInternet)<0){
1584        return -1;
1585      }
1586    }
1587  else
1588    {
1589      //Parse XML request
1590      if(xmlParseRequest(main_conf,postRequest->value,request_inputs,s,inputs,outputs,hInternet)<0){
1591        return -1;
1592      }
1593    }
1594  return 1;
1595}
1596
1597/**
1598 * Ensure that each requested arguments are present in the request
1599 * DataInputs and ResponseDocument / RawDataOutput. Potentially run
1600 * http requests from the queue in parallel.
1601 * For optional inputs add default values defined in the ZCFG file.
1602 *
1603 * @param main_conf
1604 * @param s
1605 * @param original_request
1606 * @param request_inputs
1607 * @param request_outputs
1608 * @param hInternet
1609 *
1610 * @see runHttpRequests
1611 */
1612int validateRequest(maps** main_conf,service* s,map* original_request, maps** request_inputs,maps** request_outputs,HINTERNET* hInternet){
1613
1614  map* errI0=NULL;
1615  runHttpRequests (main_conf, request_inputs, hInternet,&errI0);
1616  if(errI0!=NULL){
1617    printExceptionReportResponse (*main_conf, errI0);
1618    InternetCloseHandle (hInternet);
1619    return -1;
1620  }
1621  InternetCloseHandle (hInternet);
1622
1623
1624  map* errI=NULL;
1625  char *dfv = addDefaultValues (request_inputs, s->inputs, *main_conf, 0,&errI);
1626
1627  maps *ptr = *request_inputs;
1628  while (ptr != NULL)
1629    {
1630      map *tmp0 = getMap (ptr->content, "size");
1631      map *tmp1 = getMap (ptr->content, "maximumMegabytes");
1632      if (tmp1 != NULL && tmp0 != NULL)
1633        {
1634          float i = atof (tmp0->value) / 1048576.0;
1635          if (i >= atoi (tmp1->value))
1636            {
1637              char tmps[1024];
1638              map *tmpe = createMap ("code", "FileSizeExceeded");
1639              snprintf (tmps, 1024,
1640                        _
1641                        ("The <%s> parameter has a size limit (%s MB) defined in the ZOO ServicesProvider configuration file, but the reference you provided exceeds this limit (%f MB)."),
1642                        ptr->name, tmp1->value, i);
1643              addToMap (tmpe, "locator", ptr->name);
1644              addToMap (tmpe, "text", tmps);
1645              printExceptionReportResponse (*main_conf, tmpe);
1646              freeMap (&tmpe);
1647              free (tmpe);
1648              return -1;
1649            }
1650        }
1651      ptr = ptr->next;
1652    }
1653
1654  map* errO=NULL;
1655  char *dfv1 =
1656    addDefaultValues (request_outputs, s->outputs, *main_conf, 1,&errO);
1657
1658  if (strcmp (dfv1, "") != 0 || strcmp (dfv, "") != 0)
1659    {
1660      char tmps[1024];
1661      map *tmpe = NULL;
1662      if (strcmp (dfv, "") != 0)
1663        {
1664          tmpe = createMap ("code", "MissingParameterValue");
1665          int nb=0;
1666          int length=1;
1667          map* len=getMap(errI,"length");
1668          if(len!=NULL)
1669            length=atoi(len->value);
1670          for(nb=0;nb<length;nb++){
1671            map* errp=getMapArray(errI,"value",nb);
1672            snprintf (tmps, 1024,
1673                      _
1674                      ("The <%s> argument was not specified in DataInputs but is required according to the ZOO ServicesProvider configuration file."),
1675                      errp->value);
1676            setMapArray (tmpe, "locator", nb , errp->value);
1677            setMapArray (tmpe, "text", nb , tmps);
1678            setMapArray (tmpe, "code", nb , "MissingParameterValue");
1679          }
1680        }
1681      if (strcmp (dfv1, "") != 0)
1682        {
1683          int ilength=0;
1684          if(tmpe==NULL)
1685            tmpe = createMap ("code", "InvalidParameterValue");
1686          else{
1687            map* len=getMap(tmpe,"length");
1688            if(len!=NULL)
1689              ilength=atoi(len->value);
1690          }
1691          int nb=0;
1692          int length=1;
1693          map* len=getMap(errO,"length");
1694          if(len!=NULL)
1695            length=atoi(len->value);
1696          for(nb=0;nb<length;nb++){
1697            map* errp=getMapArray(errO,"value",nb);
1698            snprintf (tmps, 1024,
1699                      _
1700                      ("The <%s> argument specified as %s identifier was not recognized (not defined in the ZOO Configuration File)."),
1701                      errp->value,
1702                      ((getMap(original_request,"RawDataOutput")!=NULL)?"RawDataOutput":"ResponseDocument"));
1703            setMapArray (tmpe, "locator", nb+ilength , errp->value);
1704            setMapArray (tmpe, "text", nb+ilength , tmps);
1705            setMapArray (tmpe, "code", nb+ilength , "InvalidParameterValue");
1706          }
1707        }
1708      printExceptionReportResponse (*main_conf, tmpe);
1709      if(errI!=NULL){
1710        freeMap(&errI);
1711        free(errI);
1712      }
1713      if(errO!=NULL){
1714        freeMap(&errO);
1715        free(errO);
1716      }
1717      freeMap (&tmpe);
1718      free (tmpe);
1719      return -1;
1720    }
1721  maps *tmpReqI = *request_inputs;
1722  while (tmpReqI != NULL)
1723    {
1724      char name[1024];
1725      if (getMap (tmpReqI->content, "isFile") != NULL)
1726        {
1727          if (cgiFormFileName (tmpReqI->name, name, sizeof (name)) ==
1728              cgiFormSuccess)
1729            {
1730              int BufferLen = 1024;
1731              cgiFilePtr file;
1732              int targetFile;
1733              char *storageNameOnServer;
1734              char *fileNameOnServer;
1735              char contentType[1024];
1736              char buffer[1024];
1737              char *tmpStr = NULL;
1738              int size;
1739              int got, t;
1740              map *path = getMapFromMaps (*main_conf, "main", "tmpPath");
1741              cgiFormFileSize (tmpReqI->name, &size);
1742              cgiFormFileContentType (tmpReqI->name, contentType,
1743                                      sizeof (contentType));
1744              if (cgiFormFileOpen (tmpReqI->name, &file) == cgiFormSuccess)
1745                {
1746                  t = -1;
1747                  while (1)
1748                    {
1749                      tmpStr = strstr (name + t + 1, "\\");
1750                      if (NULL == tmpStr)
1751                        tmpStr = strstr (name + t + 1, "/");
1752                      if (NULL != tmpStr)
1753                        t = (int) (tmpStr - name);
1754                      else
1755                        break;
1756                    }
1757                  fileNameOnServer=(char*)malloc((strlen(name) - t - 1 )*sizeof(char));
1758                  strcpy (fileNameOnServer, name + t + 1);
1759
1760                  storageNameOnServer=(char*)malloc((strlen(path->value) + strlen(fileNameOnServer) + 2)*sizeof(char));
1761                  sprintf (storageNameOnServer, "%s/%s", path->value,
1762                           fileNameOnServer);
1763#ifdef DEBUG
1764                  fprintf (stderr, "Name on server %s\n",
1765                           storageNameOnServer);
1766                  fprintf (stderr, "fileNameOnServer: %s\n",
1767                           fileNameOnServer);
1768#endif
1769                  targetFile =
1770                    open (storageNameOnServer, O_RDWR | O_CREAT | O_TRUNC,
1771                          S_IRWXU | S_IRGRP | S_IROTH);
1772                  if (targetFile < 0)
1773                    {
1774#ifdef DEBUG
1775                      fprintf (stderr, "could not create the new file,%s\n",
1776                               fileNameOnServer);
1777#endif
1778                    }
1779                  else
1780                    {
1781                      while (cgiFormFileRead (file, buffer, BufferLen, &got)
1782                             == cgiFormSuccess)
1783                        {
1784                          if (got > 0)
1785                            write (targetFile, buffer, got);
1786                        }
1787                    }
1788                  addToMap (tmpReqI->content, "lref", storageNameOnServer);
1789                  cgiFormFileClose (file);
1790                  close (targetFile);
1791                  free(fileNameOnServer);
1792                  free(storageNameOnServer);
1793#ifdef DEBUG
1794                  fprintf (stderr, "File \"%s\" has been uploaded",
1795                           fileNameOnServer);
1796#endif
1797                }
1798            }
1799        }
1800      tmpReqI = tmpReqI->next;
1801    }
1802
1803  ensureDecodedBase64 (request_inputs);
1804  return 1;
1805}
1806
1807
1808/**
1809 * Verify if a parameter value is valid.
1810 *
1811 * @param request the request map
1812 * @param res the error map potentially generated
1813 * @param toCheck the parameter to use
1814 * @param avalues the acceptable values (or null if testing only for presence)
1815 * @param mandatory verify the presence of the parameter if mandatory > 0
1816 */
1817void checkValidValue(map* request,map** res,const char* toCheck,const char** avalues,int mandatory){
1818  map* lres=*res;
1819  map* r_inputs = getMap (request,toCheck);
1820  if (r_inputs == NULL){
1821    if(mandatory>0){
1822      const char *replace=_("Mandatory parameter <%s> was not specified");
1823      char *message=(char*)malloc((strlen(replace)+strlen(toCheck)+1)*sizeof(char));
1824      sprintf(message,replace,toCheck);
1825      if(lres==NULL){
1826        lres=createMap("code","MissingParameterValue");
1827        addToMap(lres,"text",message);
1828        addToMap(lres,"locator",toCheck);       
1829      }else{
1830        int length=1;
1831        map* len=getMap(lres,"length");
1832        if(len!=NULL){
1833          length=atoi(len->value);
1834        }
1835        setMapArray(lres,"text",length,message);
1836        setMapArray(lres,"locator",length,toCheck);
1837        setMapArray(lres,"code",length,"MissingParameterValue");
1838      }
1839      free(message);
1840    }
1841  }else{
1842    if(avalues==NULL)
1843      return;
1844    int nb=0;
1845    int hasValidValue=-1;
1846    if(strncasecmp(toCheck,"Accept",6)==0){
1847      char *tmp=zStrdup(r_inputs->value);
1848      char *pToken,*saveptr;
1849      pToken=strtok_r(tmp,",",&saveptr);
1850      while(pToken!=NULL){
1851        while(avalues[nb]!=NULL){
1852          if(strcasecmp(avalues[nb],pToken)==0){
1853            hasValidValue=1;
1854            break;
1855          }
1856          nb++;
1857        }
1858        pToken=strtok_r(NULL,",",&saveptr);
1859      }
1860      free(tmp);
1861    }else{
1862      while(avalues[nb]!=NULL){
1863        if(strcasecmp(avalues[nb],r_inputs->value)==0){
1864          hasValidValue=1;
1865          break;
1866        }
1867        nb++;
1868      }
1869    }
1870    if(hasValidValue<0){
1871      const char *replace=_("The value <%s> was not recognized, %s %s the only acceptable value.");
1872      nb=0;
1873      char *vvalues=NULL;
1874      const char* num=_("is");
1875      while(avalues[nb]!=NULL){
1876        char *tvalues;
1877        if(vvalues==NULL){
1878          vvalues=(char*)malloc((strlen(avalues[nb])+3)*sizeof(char));
1879          sprintf(vvalues,"%s",avalues[nb]);
1880        }
1881        else{
1882          tvalues=zStrdup(vvalues);
1883          vvalues=(char*)realloc(vvalues,(strlen(tvalues)+strlen(avalues[nb])+3)*sizeof(char));
1884          sprintf(vvalues,"%s, %s",tvalues,avalues[nb]);
1885          free(tvalues);
1886          num=_("are");
1887        }
1888        nb++;
1889      }
1890      char *message=(char*)malloc((strlen(replace)+strlen(num)+strlen(vvalues)+strlen(toCheck)+1)*sizeof(char));
1891      sprintf(message,replace,toCheck,vvalues,num);
1892      const char *code="VersionNegotiationFailed";
1893      code="InvalidParameterValue";
1894      const char *locator=toCheck;
1895      if( strncasecmp(toCheck,"version",7)==0 ||
1896          strncasecmp(toCheck,"AcceptVersions",14)==0 )
1897        code="VersionNegotiationFailed";
1898      if( strncasecmp(toCheck,"request",7)==0){
1899        code="OperationNotSupported";
1900        locator=r_inputs->value;
1901      }
1902      if(lres==NULL){
1903        lres=createMap("code",code);
1904        addToMap(lres,"text",message);
1905        addToMap(lres,"locator",locator);       
1906      }else{
1907        int length=1;
1908        map* len=getMap(lres,"length");
1909        if(len!=NULL){
1910          length=atoi(len->value);
1911        }
1912        setMapArray(lres,"text",length,message);
1913        setMapArray(lres,"locator",length,locator);
1914        setMapArray(lres,"code",length,code);
1915      }
1916    }
1917  }
1918  if(lres!=NULL){
1919    *res=lres;
1920  }
1921}
Note: See TracBrowser for help on using the repository browser.

Search

ZOO Sponsors

http://www.zoo-project.org/trac/chrome/site/img/geolabs-logo.pnghttp://www.zoo-project.org/trac/chrome/site/img/neogeo-logo.png http://www.zoo-project.org/trac/chrome/site/img/apptech-logo.png http://www.zoo-project.org/trac/chrome/site/img/3liz-logo.png http://www.zoo-project.org/trac/chrome/site/img/gateway-logo.png

Become a sponsor !

Knowledge partners

http://www.zoo-project.org/trac/chrome/site/img/ocu-logo.png http://www.zoo-project.org/trac/chrome/site/img/gucas-logo.png http://www.zoo-project.org/trac/chrome/site/img/polimi-logo.png http://www.zoo-project.org/trac/chrome/site/img/fem-logo.png http://www.zoo-project.org/trac/chrome/site/img/supsi-logo.png http://www.zoo-project.org/trac/chrome/site/img/cumtb-logo.png

Become a knowledge partner

Related links

http://zoo-project.org/img/ogclogo.png http://zoo-project.org/img/osgeologo.png