Index: trunk/zoo-project/zoo-kernel/caching.c
===================================================================
--- trunk/zoo-project/zoo-kernel/caching.c	(revision 642)
+++ trunk/zoo-project/zoo-kernel/caching.c	(revision 642)
@@ -0,0 +1,382 @@
+/*
+ * Author : Gérald Fenoy
+ *
+ *  Copyright 2008-2015 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "caching.h"
+#include "service.h"
+#include "service_internal.h"
+#include "response_print.h"
+#include <openssl/md5.h>
+#include <openssl/hmac.h>
+#include <openssl/evp.h>
+#include <openssl/bio.h>
+#include <openssl/buffer.h>
+
+/**
+ * Compute md5
+ * 
+ * @param url the char* 
+ * @return a char* representing the md5 of the url
+ * @warning make sure to free ressources returned by this function
+ */
+char* getMd5(char* url){
+  EVP_MD_CTX md5ctx;
+  char* fresult=(char*)malloc((EVP_MAX_MD_SIZE+1)*sizeof(char));
+  unsigned char result[EVP_MAX_MD_SIZE];
+  unsigned int len;
+  EVP_DigestInit(&md5ctx, EVP_md5());
+  EVP_DigestUpdate(&md5ctx, url, strlen(url));
+  EVP_DigestFinal_ex(&md5ctx,result,&len);
+  EVP_MD_CTX_cleanup(&md5ctx);
+  int i;
+  for(i = 0; i < len; i++){
+    if(i>0){
+      char *tmp=strdup(fresult);
+      sprintf(fresult,"%s%02x", tmp,result[i]);
+      free(tmp);
+    }
+    else
+      sprintf(fresult,"%02x",result[i]);
+  }
+  return fresult;
+}
+
+
+/**
+ * Cache a file for a given request.
+ * For each cached file, the are two files stored, a .zca and a .zcm containing
+ * the downloaded content and the mimeType respectively. 
+ *
+ * @param conf the maps containing the settings of the main.cfg file
+ * @param request the url used too fetch the content
+ * @param content the downloaded content
+ * @param mimeType the content mimeType 
+ * @param length the content size
+ * @param filepath a buffer for storing the path of the cached file; may be NULL
+ * @param max_path the size of the allocated filepath buffer  
+ */
+void addToCache(maps* conf,char* request,char* content,char* mimeType,int length, 
+                char* filepath, size_t max_path){
+  map* tmp=getMapFromMaps(conf,"main","cacheDir");
+  if(tmp!=NULL){
+    char* md5str=getMd5(request);
+    char* fname=(char*)malloc(sizeof(char)*(strlen(tmp->value)+strlen(md5str)+6));
+    sprintf(fname,"%s/%s.zca",tmp->value,md5str);
+#ifdef DEBUG
+    fprintf(stderr,"Cache list : %s\n",fname);
+    fflush(stderr);
+#endif
+    FILE* fo=fopen(fname,"w+");
+    if(fo==NULL){
+#ifdef DEBUG
+      fprintf (stderr, "Failed to open %s for writing: %s\n",fname, strerror(errno));
+#endif
+      filepath = NULL;	
+      return;
+    }
+    fwrite(content,sizeof(char),length,fo);
+    fclose(fo);
+	
+	if (filepath != NULL) {
+		strncpy(filepath, fname, max_path);
+	}	
+
+    sprintf(fname,"%s/%s.zcm",tmp->value,md5str);
+    fo=fopen(fname,"w+");
+#ifdef DEBUG
+    fprintf(stderr,"MIMETYPE: %s\n",mimeType);
+#endif
+    fwrite(mimeType,sizeof(char),strlen(mimeType),fo);
+    fclose(fo);
+
+    free(md5str);
+    free(fname);
+  }
+  else {
+	  filepath = NULL;
+  }	  
+}
+
+/**
+ * Verify if a url is available in the cache
+ *
+ * @param conf the maps containing the settings of the main.cfg file
+ * @param request the url
+ * @return the full name of the cached file if any, NULL in other case
+ * @warning make sure to free ressources returned by this function (if not NULL)
+ */
+char* isInCache(maps* conf,char* request){
+  map* tmpM=getMapFromMaps(conf,"main","cacheDir");
+  if(tmpM!=NULL){
+    char* md5str=getMd5(request);
+#ifdef DEBUG
+    fprintf(stderr,"MD5STR : (%s)\n\n",md5str);
+#endif
+    char* fname=(char*)malloc(sizeof(char)*(strlen(tmpM->value)+strlen(md5str)+6));
+    sprintf(fname,"%s/%s.zca",tmpM->value,md5str);
+    struct stat f_status;
+    int s=stat(fname, &f_status);
+    if(s==0 && f_status.st_size>0){
+      free(md5str);
+      return fname;
+    }
+    free(md5str);
+    free(fname);
+  }
+  return NULL;
+}
+
+/**
+ * Effectively run all the HTTP requests in the queue
+ *
+ * @param m the maps containing the settings of the main.cfg file
+ * @param inputs the maps containing the inputs (defined in the requests+added
+ *  per default based on the zcfg file)
+ * @param hInternet the HINTERNET pointer
+ * @return 0 on success
+ */
+int runHttpRequests(maps** m,maps** inputs,HINTERNET* hInternet){
+  if(hInternet->nb>0){
+    processDownloads(hInternet);
+    maps* content=*inputs;
+    map* tmp1;
+    int index=0;
+    char sindex[5];
+    while(content!=NULL){
+      
+      map* length=getMap(content->content,"length");
+      int shouldClean=-1;
+      if(length==NULL){
+	length=createMap("length","1");
+	shouldClean=1;
+      }
+      for(int i=0;i<atoi(length->value);i++){
+	char* fcontent;
+	char *mimeType=NULL;
+	int fsize=0;
+	char cname[15];
+	char vname[11];
+	char vname1[11];
+	char sname[9];
+	char mname[15];
+	char icname[14];
+	char xname[16];
+	char oname[12];
+	if(index>0)
+	  sprintf(vname1,"value_%d",index);
+	else
+	  sprintf(vname1,"value");
+
+	if(i>0){
+	  tmp1=getMap(content->content,cname);
+	  sprintf(cname,"cache_file_%d",i);
+	  sprintf(vname,"value_%d",i);
+	  sprintf(sname,"size_%d",i);
+	  sprintf(mname,"mimeType_%d",i);
+	  sprintf(icname,"isCached_%d",i);
+	  sprintf(xname,"Reference_%d",i);
+	  sprintf(oname,"Order_%d",i);
+	}else{
+	  sprintf(cname,"cache_file");
+	  sprintf(vname,"value");
+	  sprintf(sname,"size");
+	  sprintf(mname,"mimeType");
+	  sprintf(icname,"isCached");
+	  sprintf(xname,"Reference");
+	  sprintf(oname,"Order");
+	}
+
+	map* tmap=getMap(content->content,oname);
+	sprintf(sindex,"%d",index+1);
+	if((tmp1=getMap(content->content,xname))!=NULL && tmap!=NULL && strcasecmp(tmap->value,sindex)==0){
+
+	  if(getMap(content->content,icname)==NULL){
+	    
+	    fcontent=(char*)malloc((hInternet->ihandle[index].nDataLen+1)*sizeof(char));
+	    if(fcontent == NULL){
+	      return errorException(*m, _("Unable to allocate memory."), "InternalError",NULL);
+	    }
+	    size_t dwRead;
+	    InternetReadFile(hInternet->ihandle[index], 
+			     (LPVOID)fcontent, 
+			     hInternet->ihandle[index].nDataLen, 
+			     &dwRead);
+	    fcontent[hInternet->ihandle[index].nDataLen]=0;
+	    fsize=hInternet->ihandle[index].nDataLen;
+	    if(hInternet->ihandle[index].mimeType==NULL)
+	      mimeType=strdup("none");
+	    else
+	      mimeType=strdup(hInternet->ihandle[index].mimeType);	      
+	    
+	    map* tmpMap=getMapOrFill(&content->content,vname,"");
+	    free(tmpMap->value);
+	    tmpMap->value=(char*)malloc((fsize+1)*sizeof(char));
+	    if(tmpMap->value==NULL){
+	      return errorException(*m, _("Unable to allocate memory."), "InternalError",NULL);
+	    }
+	    memcpy(tmpMap->value,fcontent,(fsize+1)*sizeof(char));
+	    
+	    char ltmp1[256];
+	    sprintf(ltmp1,"%d",fsize);
+	    map* tmp=getMapFromMaps(*m,"main","cacheDir");
+	    if(tmp!=NULL){
+	      char* md5str=getMd5(tmp1->value);
+	      char* fname=(char*)malloc(sizeof(char)*(strlen(tmp->value)+strlen(md5str)+6));
+	      sprintf(fname,"%s/%s.zca",tmp->value,md5str);
+	      addToMap(content->content,cname,fname);
+	      free(fname);
+	    }
+	    addToMap(content->content,sname,ltmp1);
+	    addToMap(content->content,mname,mimeType);
+	    addToCache(*m,tmp1->value,fcontent,mimeType,fsize, NULL, 0);
+	    free(fcontent);
+	    free(mimeType);
+	    index++;
+
+	  }
+	}
+      }
+      if(shouldClean>0){
+	freeMap(&length);
+	free(length);
+      }
+      
+      content=content->next;
+    }
+    
+  }
+  return 0;
+}
+
+/**
+ * Add a request in the download queue
+ *
+ * @param m the maps containing the settings of the main.cfg file
+ * @param url the url to add to the queue
+ */
+void addRequestToQueue(maps** m,HINTERNET* hInternet,const char* url,bool req){
+  hInternet->waitingRequests[hInternet->nb]=strdup(url);
+  hInternet->ihandle[hInternet->nb].header=NULL;
+  if(req)
+    InternetOpenUrl(hInternet,hInternet->waitingRequests[hInternet->nb],NULL,0,INTERNET_FLAG_NO_CACHE_WRITE,0);
+  maps *oreq=getMaps(*m,"orequests");
+  if(oreq==NULL){
+    oreq=(maps*)malloc(MAPS_SIZE);
+    oreq->name=zStrdup("orequests");
+    oreq->content=createMap("value",url);
+    oreq->next=NULL;
+    addMapsToMaps(m,oreq);
+    freeMaps(&oreq);
+    free(oreq);
+  }else{
+    setMapArray(oreq->content,"value",hInternet->nb-1,url);
+  }
+}
+
+/**
+ * Try to load file from cache or download a remote file if not in cache
+ *
+ * @param m the maps containing the settings of the main.cfg file
+ * @param content the map to update
+ * @param hInternet the HINTERNET pointer
+ * @param url the url to fetch
+ * @return 0
+ */
+int loadRemoteFile(maps** m,map** content,HINTERNET* hInternet,char *url){
+  char* fcontent;
+  char* cached=isInCache(*m,url);
+  char *mimeType=NULL;
+  int fsize=0;
+
+  map* t=getMap(*content,"xlink:href");
+  if(t==NULL){
+    t=getMap((*content),"href");
+    addToMap(*content,"xlink:href",url);
+  }
+
+  if(cached!=NULL){
+
+    struct stat f_status;
+    int s=stat(cached, &f_status);
+    if(s==0){
+      fcontent=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+      FILE* f=fopen(cached,"rb");
+      fread(fcontent,f_status.st_size,1,f);
+      fsize=f_status.st_size;
+      fcontent[fsize]=0;
+      fclose(f);
+      addToMap(*content,"cache_file",cached);
+    }
+    cached[strlen(cached)-1]='m';
+    s=stat(cached, &f_status);
+    if(s==0){
+      mimeType=(char*)malloc(sizeof(char)*(f_status.st_size+1));
+      FILE* f=fopen(cached,"rb");
+      fread(mimeType,f_status.st_size,1,f);
+      mimeType[f_status.st_size]=0;
+      fclose(f);
+    }
+
+  }else{    
+    addRequestToQueue(m,hInternet,url,true);
+    return 0;
+  }
+  if(fsize==0){
+    return errorException(*m, _("Unable to download the file."), "InternalError",NULL);
+  }
+  if(mimeType!=NULL){
+    addToMap(*content,"fmimeType",mimeType);
+  }
+
+  map* tmpMap=getMapOrFill(content,"value","");
+    
+  free(tmpMap->value);
+
+  tmpMap->value=(char*)malloc((fsize+1)*sizeof(char));
+  if(tmpMap->value==NULL)
+    return errorException(*m, _("Unable to allocate memory."), "InternalError",NULL);
+  memcpy(tmpMap->value,fcontent,(fsize+1)*sizeof(char));
+
+  char ltmp1[256];
+  sprintf(ltmp1,"%d",fsize);
+  addToMap(*content,"size",ltmp1);
+  if(cached==NULL){
+    addToCache(*m,url,fcontent,mimeType,fsize, NULL, 0);
+  }
+  else{
+    addToMap(*content,"isCached","true");
+    map* tmp=getMapFromMaps(*m,"main","cacheDir");
+    if(tmp!=NULL){
+      map *c=getMap((*content),"xlink:href");
+      char* md5str=getMd5(c->value);
+      char* fname=(char*)malloc(sizeof(char)*(strlen(tmp->value)+strlen(md5str)+6));
+      sprintf(fname,"%s/%s.zca",tmp->value,md5str);
+      addToMap(*content,"cache_file",fname);
+      free(fname);
+    }
+  }
+  free(fcontent);
+  free(mimeType);
+  free(cached);
+  return 0;
+}
Index: trunk/zoo-project/zoo-kernel/caching.h
===================================================================
--- trunk/zoo-project/zoo-kernel/caching.h	(revision 642)
+++ trunk/zoo-project/zoo-kernel/caching.h	(revision 642)
@@ -0,0 +1,40 @@
+/*
+ * Author : Gérald Fenoy
+ *
+ *  Copyright 2008-2015 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "ulinet.h"
+#include "service.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  void addToCache(maps*,char*,char*,char*,int,char*,size_t);
+  char* isInCache(maps*,char*);
+  int runHttpRequests(maps**,maps**,HINTERNET*);
+  void addRequestToQueue(maps**,HINTERNET*,const char*,bool);
+  int loadRemoteFile(maps**,map**,HINTERNET*,char*);
+
+#ifdef __cplusplus
+}
+#endif
Index: trunk/zoo-project/zoo-kernel/server_internal.c
===================================================================
--- trunk/zoo-project/zoo-kernel/server_internal.c	(revision 642)
+++ trunk/zoo-project/zoo-kernel/server_internal.c	(revision 642)
@@ -0,0 +1,795 @@
+/*
+ * Author : Gérald Fenoy
+ *
+ *  Copyright 2008-2015 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "server_internal.h"
+#include "response_print.h"
+#include "mimetypes.h"
+#ifndef WIN32
+#include <dlfcn.h>
+#endif
+
+#ifdef USE_MS
+#include "service_internal_ms.h"
+#else
+#include "cpl_vsi.h"
+#endif
+
+int getVersionId(const char* version){
+  int schemaId=0;
+  for(;schemaId<2;schemaId++){
+    if(strncasecmp(version,schemas[schemaId][0],5)==0)
+      return schemaId;
+  }
+  return 0;
+}
+
+/**
+ * Extract the service identifier from the full service identifier
+ * ie: 
+ *  - Full service name: OTB.BandMath
+ *  - Service name: BandMath
+ *
+ * @param conf the maps containing the settings of the main.cfg file
+ * @param conf_dir the full path to the ZOO-Kernel directory
+ * @param identifier the full service name (potentialy including a prefix, ie:
+ *  Prefix.MyService)
+ * @param buffer the resulting service identifier (without any prefix)
+ */
+void parseIdentifier(maps* conf,char* conf_dir,char *identifier,char* buffer){
+  setMapInMaps(conf,"lenv","oIdentifier",identifier);
+  char *lid=zStrdup(identifier);
+  char *saveptr1;
+  char *tmps1=strtok_r(lid,".",&saveptr1);
+  int level=0;
+  char key[25];
+  char levels[18];
+  while(tmps1!=NULL){
+    char *test=zStrdup(tmps1);
+    char* tmps2=(char*)malloc((strlen(test)+2)*sizeof(char));
+    sprintf(key,"sprefix_%d",level);
+    sprintf(tmps2,"%s.",test);
+    sprintf(levels,"%d",level);
+    setMapInMaps(conf,"lenv","level",levels);
+    setMapInMaps(conf,"lenv",key,tmps2);
+    free(tmps2);
+    free(test);
+    level++;
+    tmps1=strtok_r(NULL,".",&saveptr1);
+  }
+  int i=0;
+  sprintf(buffer,"%s",conf_dir);
+  for(i=0;i<level;i++){
+    char *tmp0=zStrdup(buffer);
+    sprintf(key,"sprefix_%d",i);
+    map* tmp00=getMapFromMaps(conf,"lenv",key);
+    if(tmp00!=NULL)
+      sprintf(buffer,"%s/%s",tmp0,tmp00->value);
+    free(tmp0);
+    buffer[strlen(buffer)-1]=0;
+    if(i+1<level){ 
+      #ifdef IGNORE_METAPATH
+        map* tmpMap = createMap("metapath", "");
+      #else  
+        map* tmpMap=getMapFromMaps(conf,"lenv","metapath");
+      #endif	  
+      if(tmpMap==NULL || strlen(tmpMap->value)==0){
+	char *tmp01=zStrdup(tmp00->value);
+	tmp01[strlen(tmp01)-1]=0;
+	setMapInMaps(conf,"lenv","metapath",tmp01);
+	free(tmp01);
+	tmp01=NULL;
+      }
+      else{
+	if(tmp00!=NULL && tmpMap!=NULL){
+	  char *tmp00s=zStrdup(tmp00->value);
+	  tmp00s[strlen(tmp00s)-1]=0;
+	  char *value=(char*)malloc((strlen(tmp00s)+strlen(tmpMap->value)+2)*sizeof(char));
+	  sprintf(value,"%s/%s",tmpMap->value,tmp00s);
+	  setMapInMaps(conf,"lenv","metapath",value);
+	  free(value);
+	  free(tmp00s);
+	  value=NULL;
+	}
+      }
+    }else{
+      char *tmp01=zStrdup(tmp00->value);
+      tmp01[strlen(tmp01)-1]=0;
+      setMapInMaps(conf,"lenv","Identifier",tmp01);
+      free(tmp01);
+    }
+  }
+  char *tmp0=zStrdup(buffer);
+  sprintf(buffer,"%s.zcfg",tmp0);
+  free(tmp0);
+  free(lid);
+}
+
+/**
+ * Converts a hex character to its integer value 
+ *
+ * @param ch the char to convert
+ * @return the converted char 
+ */
+char from_hex(char ch) {
+  return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
+}
+
+/**
+ * Converts an integer value to its hec character 
+ *
+ * @param code the char to convert
+ * @return the converted char 
+ */
+char to_hex(char code) {
+  static char hex[] = "0123456789abcdef";
+  return hex[code & 15];
+}
+
+/**
+ * URLEncode an url
+ *
+ * @param str the url to encode
+ * @return a url-encoded version of str
+ * @warning be sure to free() the returned string after use
+ */
+char *url_encode(char *str) {
+  char *pstr = str, *buf = (char*) malloc(strlen(str) * 3 + 1), *pbuf = buf;
+  while (*pstr) {
+    if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~') 
+      *pbuf++ = *pstr;
+    else if (*pstr == ' ') 
+      *pbuf++ = '+';
+    else 
+      *pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15);
+    pstr++;
+  }
+  *pbuf = '\0';
+  return buf;
+}
+
+/**
+ * Decode an URLEncoded url
+ *
+ * @param str the URLEncoded url to decode
+ * @return a url-decoded version of str
+ * @warning be sure to free() the returned string after use
+ */
+char *url_decode(char *str) {
+  char *pstr = str, *buf = (char*) malloc(strlen(str) + 1), *pbuf = buf;
+  while (*pstr) {
+    if (*pstr == '%') {
+      if (pstr[1] && pstr[2]) {
+        *pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]);
+        pstr += 2;
+      }
+    } else if (*pstr == '+') { 
+      *pbuf++ = ' ';
+    } else {
+      *pbuf++ = *pstr;
+    }
+    pstr++;
+  }
+  *pbuf = '\0';
+  return buf;
+}
+
+/**
+ * Verify if a given language is listed in the lang list defined in the [main] 
+ * section of the main.cfg file.
+ * 
+ * @param conf the map containing the settings from the main.cfg file
+ * @param str the specific language
+ * @return 1 if the specific language is listed, -1 in other case.
+ */
+int isValidLang(maps* conf,const char *str){
+  map *tmpMap=getMapFromMaps(conf,"main","lang");
+  char *tmp=zStrdup(tmpMap->value);
+  char *pToken,*saveptr;
+  pToken=strtok_r(tmp,",",&saveptr);
+  int res=-1;
+  char *pToken1,*saveptr1;
+  pToken1=strtok_r(tmp,",",&saveptr1);
+  while(pToken1!=NULL){
+    while(pToken!=NULL){
+      if(strcasecmp(pToken1,pToken)==0){
+	res=1;
+	break;
+      }
+      pToken=strtok_r(NULL,",",&saveptr);
+    }
+    pToken1=strtok_r(NULL,",",&saveptr1);
+  }
+  free(tmp);
+  return res;
+}
+
+
+/**
+ * Access the value of the encoding key in a maps
+ *
+ * @param m the maps to search for the encoding key
+ * @return the value of the encoding key in a maps if encoding key exists,
+ *  "UTF-8" in other case.
+ */
+char* getEncoding(maps* m){
+  if(m!=NULL){
+    map* tmp=getMap(m->content,"encoding");
+    if(tmp!=NULL){
+      return tmp->value;
+    }
+    else
+      return (char*)"UTF-8";
+  }
+  else
+    return (char*)"UTF-8";  
+}
+
+/**
+ * Access the value of the version key in a maps
+ *
+ * @param m the maps to search for the version key
+ * @return the value of the version key in a maps if encoding key exists,
+ *  "1.0.0" in other case.
+ */
+char* getVersion(maps* m){
+  if(m!=NULL){
+    map* tmp=getMap(m->content,"version");
+    if(tmp!=NULL){
+      return tmp->value;
+    }
+    else
+      return (char*)"1.0.0";
+  }
+  else
+    return (char*)"1.0.0";
+}
+
+/**
+ * Read a file generated by a service.
+ * 
+ * @param m the conf maps
+ * @param content the output item
+ * @param filename the file to read
+ */
+void readGeneratedFile(maps* m,map* content,char* filename){
+  FILE * file=fopen(filename,"rb");
+  if(file==NULL){
+    fprintf(stderr,"Failed to open file %s for reading purpose.\n",filename);
+    setMapInMaps(m,"lenv","message","Unable to read produced file. Please try again later");
+    return ;
+  }
+  fseek(file, 0, SEEK_END);
+  long count = ftell(file);
+  rewind(file);
+  struct stat file_status; 
+  stat(filename, &file_status);
+  map* tmpMap1=getMap(content,"value");
+  if(tmpMap1==NULL){
+    addToMap(content,"value","");
+    tmpMap1=getMap(content,"value");
+  }
+  free(tmpMap1->value);
+  tmpMap1->value=(char*) malloc((count+1)*sizeof(char));  
+  fread(tmpMap1->value,1,count,file);
+  tmpMap1->value[count]=0;
+  fclose(file);
+  char rsize[1000];
+  sprintf(rsize,"%ld",count);
+  addToMap(content,"size",rsize);
+}
+
+
+/**
+ * Write a file from value and length
+ *
+ * @param fname the file name
+ * @param val the value
+ * @param length the value length
+ */
+int writeFile(char* fname,char* val,int length){
+  FILE* of=fopen(fname,"wb");
+  if(of==NULL){
+    return -1;
+  }
+  size_t ret=fwrite(val,sizeof(char),length,of);
+  if(ret<length){
+    fprintf(stderr,"Write error occured!\n");
+    fclose(of);
+    return -1;
+  }
+  fclose(of);
+  return 1;
+}
+
+/**
+ * Dump all values in a maps as files
+ *
+ * @param main_conf the maps containing the settings of the main.cfg file
+ * @param in the maps containing values to dump as files
+ */
+void dumpMapsValuesToFiles(maps** main_conf,maps** in){
+  map* tmpPath=getMapFromMaps(*main_conf,"main","tmpPath");
+  map* tmpSid=getMapFromMaps(*main_conf,"lenv","sid");
+  maps* inputs=*in;
+  int length=0;
+  while(inputs!=NULL){
+    if(getMap(inputs->content,"mimeType")!=NULL &&
+       getMap(inputs->content,"cache_file")==NULL){
+      map* cMap=inputs->content;
+      if(getMap(cMap,"length")!=NULL){
+	map* tmpLength=getMap(cMap,"length");
+	int len=atoi(tmpLength->value);
+	int k=0;
+	for(k=0;k<len;k++){
+	  map* cMimeType=getMapArray(cMap,"mimeType",k);
+	  map* cValue=getMapArray(cMap,"value",k);
+	  map* cSize=getMapArray(cMap,"size",k);
+	  char file_ext[32];
+	  getFileExtension(cMimeType != NULL ? cMimeType->value : NULL, file_ext, 32);
+	  char* val=(char*)malloc((strlen(tmpPath->value)+strlen(inputs->name)+strlen(tmpSid->value)+strlen(file_ext)+16)*sizeof(char));
+	  sprintf(val,"%s/Input_%s_%s_%d.%s",tmpPath->value,inputs->name,tmpSid->value,k,file_ext);
+	  length=0;
+	  if(cSize!=NULL){
+	    length=atoi(cSize->value);
+	  }
+	  writeFile(val,cValue->value,length);
+	  setMapArray(cMap,"cache_file",k,val);
+	  free(val);
+	}
+      }else{
+	int length=0;
+	map* cMimeType=getMap(cMap,"mimeType");
+	map* cValue=getMap(cMap,"value");
+	map* cSize=getMap(cMap,"size");
+	char file_ext[32];
+	getFileExtension(cMimeType != NULL ? cMimeType->value : NULL, file_ext, 32);
+	char *val=(char*)malloc((strlen(tmpPath->value)+strlen(inputs->name)+strlen(tmpSid->value)+strlen(file_ext)+16)*sizeof(char));
+	sprintf(val,"%s/Input_%s_%s_%d.%s",tmpPath->value,inputs->name,tmpSid->value,0,file_ext);
+	if(cSize!=NULL){
+	  length=atoi(cSize->value);
+	}
+	writeFile(val,cValue->value,length);
+	addToMap(cMap,"cache_file",val);
+	free(val);
+      }
+    }
+    inputs=inputs->next;
+  }
+}
+
+
+/**
+ * Base64 encoding of a char*
+ *
+ * @param input the value to encode
+ * @param length the value length
+ * @return the buffer containing the base64 value
+ * @warning make sure to free the returned value
+ */
+char *base64(const char *input, int length)
+{
+  BIO *bmem, *b64;
+  BUF_MEM *bptr;
+
+  b64 = BIO_new(BIO_f_base64());
+  BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
+  bmem = BIO_new(BIO_s_mem());
+  b64 = BIO_push(b64, bmem);
+  BIO_write(b64, input, length);
+  BIO_flush(b64);
+  BIO_get_mem_ptr(b64, &bptr);
+
+  char *buff = (char *)malloc((bptr->length+1)*sizeof(char));
+  memcpy(buff, bptr->data, bptr->length);
+  buff[bptr->length] = 0;
+
+  BIO_free_all(b64);
+
+  return buff;
+}
+
+/**
+ * Base64 decoding of a char*
+ *
+ * @param input the value to decode
+ * @param length the value length
+ * @param red the value length
+ * @return the buffer containing the base64 value 
+ * @warning make sure to free the returned value
+ */
+char *base64d(const char *input, int length,int* red)
+{
+  BIO *b64, *bmem;
+
+  char *buffer = (char *)malloc(length);
+  if(buffer){
+    memset(buffer, 0, length);
+    b64 = BIO_new(BIO_f_base64());
+    if(b64){
+      bmem = BIO_new_mem_buf((unsigned char*)input,length);
+      bmem = BIO_push(b64, bmem);
+      *red=BIO_read(bmem, buffer, length);
+      buffer[length-1]=0;
+      BIO_free_all(bmem);
+    }
+  }
+  return buffer;
+}
+
+/**
+ * Read Base64 value and split it value by lines of 64 char.
+ *
+ * @param in the map containing the value to split
+ */
+void readBase64(map **in){
+  char *res = NULL;
+  char *curs = (*in)->value;
+  int i = 0;
+  for (i = 0; i <= strlen ((*in)->value) / 64;
+       i++)
+    {
+      if (res == NULL)
+	res =
+	  (char *) malloc (65 * sizeof (char));
+      else
+	res =
+	  (char *) realloc (res,
+			    (((i + 1) * 65) +
+			     i) * sizeof (char));
+      int csize = i * 65;
+      strncpy (res + csize, curs, 64);
+      if (i == strlen ((*in)->value) / 64)
+	strcat (res, "\n\0");
+      else
+	{
+	  strncpy (res + (((i + 1) * 64) + i),
+		   "\n\0", 2);
+	  curs += 64;
+	}
+    }
+  free ((*in)->value);
+  (*in)->value = zStrdup (res);
+  free (res);
+}
+
+
+/**
+ * Add the default values defined in the zcfg to a maps.
+ *
+ * @param out the maps containing the inputs or outputs given in the initial
+ *  HTTP request
+ * @param in the description of all inputs or outputs available for a service
+ * @param m the maps containing the settings of the main.cfg file
+ * @param type 0 for inputs and 1 for outputs
+ * @param err the map to store potential missing mandatory input parameters or
+ *  wrong output names depending on the type.
+ * @return "" if no error was detected, the name of last input or output causing
+ *  an error.
+ */
+char* addDefaultValues(maps** out,elements* in,maps* m,int type,map** err){
+  map *res=*err;
+  elements* tmpInputs=in;
+  maps* out1=*out;
+  char *result=NULL;
+  int nb=0;
+  if(type==1){
+    while(out1!=NULL){
+      if(getElements(in,out1->name)==NULL){
+	if(res==NULL){
+	  res=createMap("value",out1->name);
+	}else{
+	  setMapArray(res,"value",nb,out1->name);
+	}
+	nb++;
+	result=out1->name;
+      }
+      out1=out1->next;
+    }
+    if(res!=NULL){
+      *err=res;
+      return result;
+    }
+    out1=*out;
+  }
+  while(tmpInputs!=NULL){
+    maps *tmpMaps=getMaps(out1,tmpInputs->name);
+    if(tmpMaps==NULL){
+      maps* tmpMaps2=(maps*)malloc(MAPS_SIZE);
+      tmpMaps2->name=strdup(tmpInputs->name);
+      tmpMaps2->content=NULL;
+      tmpMaps2->next=NULL;
+      
+      if(type==0){
+	map* tmpMapMinO=getMap(tmpInputs->content,"minOccurs");
+	if(tmpMapMinO!=NULL){
+	  if(atoi(tmpMapMinO->value)>=1){
+	    freeMaps(&tmpMaps2);
+	    free(tmpMaps2);
+	    if(res==NULL){
+	      res=createMap("value",tmpInputs->name);
+	    }else{
+	      setMapArray(res,"value",nb,tmpInputs->name);
+	    }
+	    nb++;
+	    result=tmpInputs->name;
+	  }
+	  else{
+	    if(tmpMaps2->content==NULL)
+	      tmpMaps2->content=createMap("minOccurs",tmpMapMinO->value);
+	    else
+	      addToMap(tmpMaps2->content,"minOccurs",tmpMapMinO->value);
+	  }
+	}
+	if(res==NULL){
+	  map* tmpMaxO=getMap(tmpInputs->content,"maxOccurs");
+	  if(tmpMaxO!=NULL){
+	    if(tmpMaps2->content==NULL)
+	      tmpMaps2->content=createMap("maxOccurs",tmpMaxO->value);
+	    else
+	      addToMap(tmpMaps2->content,"maxOccurs",tmpMaxO->value);
+	  }
+	  map* tmpMaxMB=getMap(tmpInputs->content,"maximumMegabytes");
+	  if(tmpMaxMB!=NULL){
+	    if(tmpMaps2->content==NULL)
+	      tmpMaps2->content=createMap("maximumMegabytes",tmpMaxMB->value);
+	    else
+	      addToMap(tmpMaps2->content,"maximumMegabytes",tmpMaxMB->value);
+	  }
+	}
+      }
+
+      if(res==NULL){
+	iotype* tmpIoType=tmpInputs->defaults;
+	if(tmpIoType!=NULL){
+	  map* tmpm=tmpIoType->content;
+	  while(tmpm!=NULL){
+	    if(tmpMaps2->content==NULL)
+	      tmpMaps2->content=createMap(tmpm->name,tmpm->value);
+	    else
+	      addToMap(tmpMaps2->content,tmpm->name,tmpm->value);
+	    tmpm=tmpm->next;
+	  }
+	}
+	addToMap(tmpMaps2->content,"inRequest","false");
+	if(type==0){
+	  map *tmpMap=getMap(tmpMaps2->content,"value");
+	  if(tmpMap==NULL)
+	    addToMap(tmpMaps2->content,"value","NULL");
+	}
+	if(out1==NULL){
+	  *out=dupMaps(&tmpMaps2);
+	  out1=*out;
+	}
+	else
+	  addMapsToMaps(&out1,tmpMaps2);
+	freeMap(&tmpMaps2->content);
+	free(tmpMaps2->content);
+	tmpMaps2->content=NULL;
+	freeMaps(&tmpMaps2);
+	free(tmpMaps2);
+	tmpMaps2=NULL;
+      }
+    }
+    else{
+      iotype* tmpIoType=getIoTypeFromElement(tmpInputs,tmpInputs->name,
+					     tmpMaps->content);
+      if(type==0) {
+	/**
+	 * In case of an Input maps, then add the minOccurs and maxOccurs to the
+	 * content map.
+	 */
+	map* tmpMap1=getMap(tmpInputs->content,"minOccurs");
+	if(tmpMap1!=NULL){
+	  if(tmpMaps->content==NULL)
+	    tmpMaps->content=createMap("minOccurs",tmpMap1->value);
+	  else
+	    addToMap(tmpMaps->content,"minOccurs",tmpMap1->value);
+	}
+	map* tmpMaxO=getMap(tmpInputs->content,"maxOccurs");
+	if(tmpMaxO!=NULL){
+	  if(tmpMaps->content==NULL)
+	    tmpMaps->content=createMap("maxOccurs",tmpMaxO->value);
+	  else
+	    addToMap(tmpMaps->content,"maxOccurs",tmpMaxO->value);
+	}
+	map* tmpMaxMB=getMap(tmpInputs->content,"maximumMegabytes");
+	if(tmpMaxMB!=NULL){
+	  if(tmpMaps->content==NULL)
+	    tmpMaps->content=createMap("maximumMegabytes",tmpMaxMB->value);
+	  else
+	    addToMap(tmpMaps->content,"maximumMegabytes",tmpMaxMB->value);
+	}
+	/**
+	 * Parsing BoundingBoxData, fill the following map and then add it to
+	 * the content map of the Input maps: 
+	 * lowerCorner, upperCorner, srs and dimensions
+	 * cf. parseBoundingBox
+	 */
+	if(tmpInputs->format!=NULL && strcasecmp(tmpInputs->format,"BoundingBoxData")==0){
+	  maps* tmpI=getMaps(*out,tmpInputs->name);
+	  if(tmpI!=NULL){
+	    map* tmpV=getMap(tmpI->content,"value");
+	    if(tmpV!=NULL){
+	      char *tmpVS=strdup(tmpV->value);
+	      map* tmp=parseBoundingBox(tmpVS);
+	      free(tmpVS);
+	      map* tmpC=tmp;
+	      while(tmpC!=NULL){
+		addToMap(tmpMaps->content,tmpC->name,tmpC->value);
+		tmpC=tmpC->next;
+	      }
+	      freeMap(&tmp);
+	      free(tmp);
+	    }
+	  }
+	}
+      }
+
+      if(tmpIoType!=NULL){
+	map* tmpContent=tmpIoType->content;
+	map* cval=NULL;
+	int hasPassed=-1;
+	while(tmpContent!=NULL){
+	  if((cval=getMap(tmpMaps->content,tmpContent->name))==NULL){
+#ifdef DEBUG
+	    fprintf(stderr,"addDefaultValues %s => %s\n",tmpContent->name,tmpContent->value);
+#endif
+	    if(tmpMaps->content==NULL)
+	      tmpMaps->content=createMap(tmpContent->name,tmpContent->value);
+	    else
+	      addToMap(tmpMaps->content,tmpContent->name,tmpContent->value);
+	    
+	    if(hasPassed<0 && type==0 && getMap(tmpMaps->content,"isArray")!=NULL){
+	      map* length=getMap(tmpMaps->content,"length");
+	      int i;
+	      char *tcn=strdup(tmpContent->name);
+	      for(i=1;i<atoi(length->value);i++){
+#ifdef DEBUG
+		dumpMap(tmpMaps->content);
+		fprintf(stderr,"addDefaultValues %s_%d => %s\n",tcn,i,tmpContent->value);
+#endif
+		int len=strlen((char*) tcn);
+		char *tmp1=(char *)malloc((len+10)*sizeof(char));
+		sprintf(tmp1,"%s_%d",tcn,i);
+#ifdef DEBUG
+		fprintf(stderr,"addDefaultValues %s => %s\n",tmp1,tmpContent->value);
+#endif
+		addToMap(tmpMaps->content,tmp1,tmpContent->value);
+		free(tmp1);
+		hasPassed=1;
+	      }
+	      free(tcn);
+	    }
+	  }
+	  tmpContent=tmpContent->next;
+	}
+#ifdef USE_MS
+	/**
+	 * check for useMapServer presence
+	 */
+	map* tmpCheck=getMap(tmpIoType->content,"useMapServer");
+	if(tmpCheck!=NULL){
+	  // Get the default value
+	  tmpIoType=getIoTypeFromElement(tmpInputs,tmpInputs->name,NULL);
+	  tmpCheck=getMap(tmpMaps->content,"mimeType");
+	  addToMap(tmpMaps->content,"requestedMimeType",tmpCheck->value);
+	  map* cursor=tmpIoType->content;
+	  while(cursor!=NULL){
+	    addToMap(tmpMaps->content,cursor->name,cursor->value);
+	    cursor=cursor->next;
+	  }
+	  
+	  cursor=tmpInputs->content;
+	  while(cursor!=NULL){
+	    if(strcasecmp(cursor->name,"Title")==0 ||
+	       strcasecmp(cursor->name,"Abstract")==0)
+	      addToMap(tmpMaps->content,cursor->name,cursor->value);
+           cursor=cursor->next;
+	  }
+	}
+#endif
+      }
+      if(tmpMaps->content==NULL)
+	tmpMaps->content=createMap("inRequest","true");
+      else
+	addToMap(tmpMaps->content,"inRequest","true");
+
+    }
+    tmpInputs=tmpInputs->next;
+  }
+  if(res!=NULL){
+    *err=res;
+    return result;
+  }
+  return "";
+}
+
+/**
+ * Access the last error message returned by the OS when trying to dynamically
+ * load a shared library.
+ *
+ * @return the last error message
+ * @warning The character string returned from getLastErrorMessage resides
+ * in a static buffer. The application should not write to this
+ * buffer or attempt to free() it.
+ */ 
+char* getLastErrorMessage() {                                              
+#ifdef WIN32
+  LPVOID lpMsgBuf;
+  DWORD errCode = GetLastError();
+  static char msg[ERROR_MSG_MAX_LENGTH];
+  size_t i;
+  
+  DWORD length = FormatMessage(
+			       FORMAT_MESSAGE_ALLOCATE_BUFFER | 
+			       FORMAT_MESSAGE_FROM_SYSTEM |
+			       FORMAT_MESSAGE_IGNORE_INSERTS,
+			       NULL,
+			       errCode,
+			       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+			       (LPTSTR) &lpMsgBuf,
+			       0, NULL );	
+  
+#ifdef UNICODE		
+  wcstombs_s( &i, msg, ERROR_MSG_MAX_LENGTH,
+	      (wchar_t*) lpMsgBuf, _TRUNCATE );
+#else
+  strcpy_s( msg, ERROR_MSG_MAX_LENGTH,
+	    (char *) lpMsgBuf );		
+#endif	
+  LocalFree(lpMsgBuf);
+  
+  return msg;
+#else
+  return dlerror();
+#endif
+}
+
+/**
+ * Read a file using the GDAL VSI API 
+ *
+ * @param conf the maps containing the settings of the main.cfg file
+ * @param dataSource the datasource name to read
+ * @warning make sure to free ressources returned by this function
+ */
+char *readVSIFile(maps* conf,const char* dataSource){
+    VSILFILE * fichier=VSIFOpenL(dataSource,"rb");
+    VSIStatBufL file_status;
+    VSIStatL(dataSource, &file_status);
+    if(fichier==NULL){
+      char tmp[1024];
+      sprintf(tmp,"Failed to open file %s for reading purpose. File seems empty %lld.",
+	      dataSource,file_status.st_size);
+      setMapInMaps(conf,"lenv","message",tmp);
+      return NULL;
+    }
+    char *res1=(char *)malloc(file_status.st_size*sizeof(char));
+    VSIFReadL(res1,1,file_status.st_size*sizeof(char),fichier);
+    res1[file_status.st_size-1]=0;
+    VSIFCloseL(fichier);
+    VSIUnlink(dataSource);
+    return res1;
+}
+
+
Index: trunk/zoo-project/zoo-kernel/server_internal.h
===================================================================
--- trunk/zoo-project/zoo-kernel/server_internal.h	(revision 642)
+++ trunk/zoo-project/zoo-kernel/server_internal.h	(revision 642)
@@ -0,0 +1,61 @@
+/*
+ * Author : Gérald Fenoy
+ *
+ *  Copyright 2008-2015 GeoLabs SARL. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "ulinet.h"
+#include "service.h"
+#include <openssl/sha.h>
+#include <openssl/md5.h>
+#include <openssl/hmac.h>
+#include <openssl/evp.h>
+#include <openssl/bio.h>
+#include <openssl/buffer.h>
+
+extern   int conf_read(const char*,maps*);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+  
+  char *base64(const char*,int);
+  char *base64d(const char*,int,int*);
+  void readBase64(map **);
+  char *url_decode(char *);
+  int getVersionId(const char*);
+  void readGeneratedFile(maps*,map*,char*);
+  int getServiceFromYAML(maps*,char*,service**,char *name);
+  char* addDefaultValues(maps**,elements*,maps*,int,map**);
+  char* getEncoding(maps*);
+  char *readVSIFile(maps*,const char*);
+  void parseIdentifier(maps*,char*,char*,char*);
+  void dumpMapsValuesToFiles(maps**,maps**);
+
+  int isValidLang(maps*,const char*);
+  
+  char* getLastErrorMessage();
+  
+#ifdef __cplusplus
+}
+#endif
