LCOV - code coverage report
Current view: directory - port - cpl_http.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 245 131 53.5 %
Date: 2012-12-26 Functions: 10 7 70.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: cpl_http.cpp 22588 2011-06-25 20:11:07Z rouault $
       3                 :  *
       4                 :  * Project:  libcurl based HTTP client
       5                 :  * Purpose:  libcurl based HTTP client
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2006, Frank Warmerdam
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include <map>
      31                 : #include "cpl_http.h"
      32                 : #include "cpl_multiproc.h"
      33                 : 
      34                 : #ifdef HAVE_CURL
      35                 : #  include <curl/curl.h>
      36                 : 
      37                 : 
      38                 : /* CURLINFO_RESPONSE_CODE was known as CURLINFO_HTTP_CODE in libcurl 7.10.7 and earlier */
      39                 : #if LIBCURL_VERSION_NUM < 0x070a07
      40                 : #define CURLINFO_RESPONSE_CODE CURLINFO_HTTP_CODE
      41                 : #endif
      42                 : 
      43                 : #endif
      44                 : 
      45                 : CPL_CVSID("$Id: cpl_http.cpp 22588 2011-06-25 20:11:07Z rouault $");
      46                 : 
      47                 : // list of named persistent http sessions 
      48                 : 
      49                 : #ifdef HAVE_CURL
      50             713 : static std::map<CPLString,CURL*> oSessionMap;
      51                 : static void *hSessionMapMutex = NULL;
      52                 : #endif
      53                 : 
      54                 : /************************************************************************/
      55                 : /*                            CPLWriteFct()                             */
      56                 : /*                                                                      */
      57                 : /*      Append incoming text to our collection buffer, reallocating     */
      58                 : /*      it larger as needed.                                            */
      59                 : /************************************************************************/
      60                 : 
      61                 : #ifdef HAVE_CURL
      62                 : static size_t 
      63            2732 : CPLWriteFct(void *buffer, size_t size, size_t nmemb, void *reqInfo)
      64                 : 
      65                 : {
      66            2732 :     CPLHTTPResult *psResult = (CPLHTTPResult *) reqInfo;
      67                 :     int  nNewSize;
      68                 : 
      69            2732 :     nNewSize = psResult->nDataLen + nmemb*size + 1;
      70            2732 :     if( nNewSize > psResult->nDataAlloc )
      71                 :     {
      72             491 :         psResult->nDataAlloc = (int) (nNewSize * 1.25 + 100);
      73                 :         GByte* pabyNewData = (GByte *) VSIRealloc(psResult->pabyData,
      74             491 :                                                   psResult->nDataAlloc);
      75             491 :         if( pabyNewData == NULL )
      76                 :         {
      77               0 :             VSIFree(psResult->pabyData);
      78               0 :             psResult->pabyData = NULL;
      79               0 :             psResult->pszErrBuf = CPLStrdup(CPLString().Printf("Out of memory allocating %d bytes for HTTP data buffer.", psResult->nDataAlloc));
      80               0 :             psResult->nDataAlloc = psResult->nDataLen = 0;
      81                 : 
      82               0 :             return 0;
      83                 :         }
      84             491 :         psResult->pabyData = pabyNewData;
      85                 :     }
      86                 : 
      87                 :     memcpy( psResult->pabyData + psResult->nDataLen, buffer,
      88            2732 :             nmemb * size );
      89                 : 
      90            2732 :     psResult->nDataLen += nmemb * size;
      91            2732 :     psResult->pabyData[psResult->nDataLen] = 0;
      92                 : 
      93            2732 :     return nmemb;
      94                 : }
      95                 : 
      96                 : /************************************************************************/
      97                 : /*                           CPLHdrWriteFct()                           */
      98                 : /************************************************************************/
      99            1275 : static size_t CPLHdrWriteFct(void *buffer, size_t size, size_t nmemb, void *reqInfo)
     100                 : {
     101            1275 :     CPLHTTPResult *psResult = (CPLHTTPResult *) reqInfo;
     102                 :     // copy the buffer to a char* and initialize with zeros (zero terminate as well)
     103            1275 :     char* pszHdr = (char*)CPLCalloc(nmemb + 1, size);
     104            1275 :     CPLPrintString(pszHdr, (char *)buffer, nmemb * size);
     105            1275 :     char *pszKey = NULL;
     106            1275 :     const char *pszValue = CPLParseNameValue(pszHdr, &pszKey );
     107            1275 :     psResult->papszHeaders = CSLSetNameValue(psResult->papszHeaders, pszKey, pszValue);
     108            1275 :     CPLFree(pszHdr);
     109            1275 :     CPLFree(pszKey);
     110            1275 :     return nmemb; 
     111                 : }
     112                 : 
     113                 : #endif /* def HAVE_CURL */
     114                 : 
     115                 : /************************************************************************/
     116                 : /*                           CPLHTTPFetch()                             */
     117                 : /************************************************************************/
     118                 : 
     119                 : /**
     120                 :  * \brief Fetch a document from an url and return in a string.
     121                 :  *
     122                 :  * @param pszURL valid URL recognized by underlying download library (libcurl)
     123                 :  * @param papszOptions option list as a NULL-terminated array of strings. May be NULL.
     124                 :  *                     The following options are handled :
     125                 :  * <ul>
     126                 :  * <li>TIMEOUT=val, where val is in seconds</li>
     127                 :  * <li>HEADERS=val, where val is an extra header to use when getting a web page.
     128                 :  *                  For example "Accept: application/x-ogcwkt"
     129                 :  * <li>HTTPAUTH=[BASIC/NTLM/GSSNEGOTIATE/ANY] to specify an authentication scheme to use.
     130                 :  * <li>USERPWD=userid:password to specify a user and password for authentication
     131                 :  * <li>POSTFIELDS=val, where val is a nul-terminated string to be passed to the server
     132                 :  *                     with a POST request.
     133                 :  * <li>PROXY=val, to make requests go through a proxy server, where val is of the
     134                 :  *                form proxy.server.com:port_number
     135                 :  * <li>PROXYUSERPWD=val, where val is of the form username:password
     136                 :  * <li>CUSTOMREQUEST=val, where val is GET, PUT, POST, DELETE, etc.. (GDAL >= 1.9.0)
     137                 :  * </ul>
     138                 :  *
     139                 :  * Alternatively, if not defined in the papszOptions arguments, the PROXY and 
     140                 :  * PROXYUSERPWD values are searched in the configuration options named 
     141                 :  * GDAL_HTTP_PROXY and GDAL_HTTP_PROXYUSERPWD, as proxy configuration belongs 
     142                 :  * to networking setup and makes more sense at the configuration option level 
     143                 :  * than at the connection level.
     144                 :  *
     145                 :  * @return a CPLHTTPResult* structure that must be freed by 
     146                 :  * CPLHTTPDestroyResult(), or NULL if libcurl support is disabled
     147                 :  */
     148             179 : CPLHTTPResult *CPLHTTPFetch( const char *pszURL, char **papszOptions )
     149                 : 
     150                 : {
     151                 : #ifndef HAVE_CURL
     152                 :     (void) papszOptions;
     153                 :     (void) pszURL;
     154                 : 
     155                 :     CPLError( CE_Failure, CPLE_NotSupported,
     156                 :               "GDAL/OGR not compiled with libcurl support, remote requests not supported." );
     157                 :     return NULL;
     158                 : #else
     159                 : /* -------------------------------------------------------------------- */
     160                 : /*      Are we using a persistent named session?  If so, search for     */
     161                 : /*      or create it.                                                   */
     162                 : /*                                                                      */
     163                 : /*      Currently this code does not attempt to protect against         */
     164                 : /*      multiple threads asking for the same named session.  If that    */
     165                 : /*      occurs it will be in use in multiple threads at once which      */
     166                 : /*      might have bad consequences depending on what guarantees        */
     167                 : /*      libcurl gives - which I have not investigated.                  */
     168                 : /* -------------------------------------------------------------------- */
     169             179 :     CURL *http_handle = NULL;
     170                 : 
     171             179 :     const char *pszPersistent = CSLFetchNameValue( papszOptions, "PERSISTENT" );
     172             179 :     const char *pszClosePersistent = CSLFetchNameValue( papszOptions, "CLOSE_PERSISTENT" );
     173             179 :     if (pszPersistent)
     174                 :     {
     175              66 :         CPLString osSessionName = pszPersistent;
     176              66 :         CPLMutexHolder oHolder( &hSessionMapMutex );
     177                 : 
     178              66 :         if( oSessionMap.count( osSessionName ) == 0 )
     179                 :         {
     180              18 :             oSessionMap[osSessionName] = curl_easy_init();
     181                 :             CPLDebug( "HTTP", "Establish persistent session named '%s'.",
     182              18 :                       osSessionName.c_str() );
     183                 :         }
     184                 : 
     185              66 :         http_handle = oSessionMap[osSessionName];
     186                 :     }
     187                 : /* -------------------------------------------------------------------- */
     188                 : /*      Are we requested to close a persistent named session?          */
     189                 : /* -------------------------------------------------------------------- */
     190             113 :     else if (pszClosePersistent)
     191                 :     {
     192              18 :         CPLString osSessionName = pszClosePersistent;
     193              18 :         CPLMutexHolder oHolder( &hSessionMapMutex );
     194                 : 
     195              18 :         std::map<CPLString,CURL*>::iterator oIter = oSessionMap.find( osSessionName );
     196              18 :         if( oIter != oSessionMap.end() )
     197                 :         {
     198              18 :             curl_easy_cleanup(oIter->second);
     199              18 :             oSessionMap.erase(oIter);
     200                 :             CPLDebug( "HTTP", "Ended persistent session named '%s'.",
     201              18 :                       osSessionName.c_str() );
     202                 :         }
     203                 :         else
     204                 :         {
     205                 :             CPLDebug( "HTTP", "Could not find persistent session named '%s'.",
     206               0 :                       osSessionName.c_str() );
     207                 :         }
     208                 : 
     209              18 :         return NULL;
     210                 :     }
     211                 :     else
     212              95 :         http_handle = curl_easy_init();
     213                 : 
     214                 : /* -------------------------------------------------------------------- */
     215                 : /*      Setup the request.                                              */
     216                 : /* -------------------------------------------------------------------- */
     217                 :     char szCurlErrBuf[CURL_ERROR_SIZE+1];
     218                 :     CPLHTTPResult *psResult;
     219             161 :     struct curl_slist *headers=NULL; 
     220                 : 
     221             161 :     const char* pszArobase = strchr(pszURL, '@');
     222             161 :     const char* pszSlash = strchr(pszURL, '/');
     223             161 :     const char* pszColon = (pszSlash) ? strchr(pszSlash, ':') : NULL;
     224             161 :     if (pszArobase != NULL && pszColon != NULL && pszArobase - pszColon > 0)
     225                 :     {
     226                 :         /* http://user:password@www.example.com */
     227               0 :         char* pszSanitizedURL = CPLStrdup(pszURL);
     228               0 :         pszSanitizedURL[pszColon-pszURL] = 0;
     229               0 :         CPLDebug( "HTTP", "Fetch(%s:#password#%s)", pszSanitizedURL, pszArobase );
     230               0 :         CPLFree(pszSanitizedURL);
     231                 :     }
     232                 :     else
     233                 :     {
     234             161 :         CPLDebug( "HTTP", "Fetch(%s)", pszURL );
     235                 :     }
     236                 : 
     237             161 :     psResult = (CPLHTTPResult *) CPLCalloc(1,sizeof(CPLHTTPResult));
     238                 : 
     239             161 :     curl_easy_setopt(http_handle, CURLOPT_URL, pszURL );
     240                 : 
     241             161 :     if (CSLTestBoolean(CPLGetConfigOption("CPL_CURL_VERBOSE", "NO")))
     242               0 :         curl_easy_setopt(http_handle, CURLOPT_VERBOSE, 1);
     243                 : 
     244             161 :     const char *pszHttpVersion = CSLFetchNameValue( papszOptions, "HTTP_VERSION");
     245             161 :     if( pszHttpVersion && strcmp(pszHttpVersion, "1.0") == 0 )
     246               0 :         curl_easy_setopt(http_handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0 );
     247                 : 
     248                 :     /* Support control over HTTPAUTH */
     249             161 :     const char *pszHttpAuth = CSLFetchNameValue( papszOptions, "HTTPAUTH" );
     250             161 :     if( pszHttpAuth == NULL )
     251                 :         /* do nothing */;
     252                 : 
     253                 :     /* CURLOPT_HTTPAUTH is defined in curl 7.11.0 or newer */
     254                 : #if LIBCURL_VERSION_NUM >= 0x70B00
     255               0 :     else if( EQUAL(pszHttpAuth,"BASIC") )
     256               0 :         curl_easy_setopt(http_handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC );
     257               0 :     else if( EQUAL(pszHttpAuth,"NTLM") )
     258               0 :         curl_easy_setopt(http_handle, CURLOPT_HTTPAUTH, CURLAUTH_NTLM );
     259               0 :     else if( EQUAL(pszHttpAuth,"ANY") )
     260               0 :         curl_easy_setopt(http_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY );
     261                 : #ifdef CURLAUTH_GSSNEGOTIATE
     262               0 :     else if( EQUAL(pszHttpAuth,"NEGOTIATE") )
     263               0 :         curl_easy_setopt(http_handle, CURLOPT_HTTPAUTH, CURLAUTH_GSSNEGOTIATE );
     264                 : #endif
     265                 :     else
     266                 :     {
     267                 :         CPLError( CE_Warning, CPLE_AppDefined,
     268                 :                   "Unsupported HTTPAUTH value '%s', ignored.", 
     269               0 :                   pszHttpAuth );
     270                 :     }
     271                 : #else
     272                 :     else
     273                 :     {
     274                 :         CPLError( CE_Warning, CPLE_AppDefined,
     275                 :                   "HTTPAUTH option needs curl >= 7.11.0" );
     276                 :     }
     277                 : #endif
     278                 : 
     279                 :     /* Support setting userid:password */
     280             161 :     const char *pszUserPwd = CSLFetchNameValue( papszOptions, "USERPWD" );
     281             161 :     if( pszUserPwd != NULL )
     282               0 :         curl_easy_setopt(http_handle, CURLOPT_USERPWD, pszUserPwd );
     283                 : 
     284                 :     /* Set Proxy parameters */
     285             161 :     const char* pszProxy = CSLFetchNameValue( papszOptions, "PROXY" );
     286             161 :     if (pszProxy == NULL)
     287             161 :         pszProxy = CPLGetConfigOption("GDAL_HTTP_PROXY", NULL);
     288             161 :     if (pszProxy)
     289               0 :         curl_easy_setopt(http_handle,CURLOPT_PROXY,pszProxy);
     290                 : 
     291             161 :     const char* pszProxyUserPwd = CSLFetchNameValue( papszOptions, "PROXYUSERPWD" );
     292             161 :     if (pszProxyUserPwd == NULL)
     293             161 :         pszProxyUserPwd = CPLGetConfigOption("GDAL_HTTP_PROXYUSERPWD", NULL);
     294             161 :     if (pszProxyUserPwd)
     295               0 :         curl_easy_setopt(http_handle,CURLOPT_PROXYUSERPWD,pszProxyUserPwd);
     296                 : 
     297                 :     // turn off SSL verification, accept all servers with ssl
     298             161 :     curl_easy_setopt(http_handle, CURLOPT_SSL_VERIFYPEER, FALSE);
     299                 : 
     300                 :     /* Set POST mode */
     301             161 :     const char* pszPost = CSLFetchNameValue( papszOptions, "POSTFIELDS" );
     302             161 :     if( pszPost != NULL )
     303                 :     {
     304              75 :         curl_easy_setopt(http_handle, CURLOPT_POST, 1 );
     305              75 :         curl_easy_setopt(http_handle, CURLOPT_POSTFIELDS, pszPost );
     306                 :     }
     307                 : 
     308             161 :     const char* pszCustomRequest = CSLFetchNameValue( papszOptions, "CUSTOMREQUEST" );
     309             161 :     if( pszCustomRequest != NULL )
     310                 :     {
     311              64 :         curl_easy_setopt(http_handle, CURLOPT_CUSTOMREQUEST, pszCustomRequest );
     312                 :     }
     313                 : 
     314                 :     /* Enable following redirections.  Requires libcurl 7.10.1 at least */
     315             161 :     curl_easy_setopt(http_handle, CURLOPT_FOLLOWLOCATION, 1 );
     316             161 :     curl_easy_setopt(http_handle, CURLOPT_MAXREDIRS, 10 );
     317                 :     
     318                 :     /* Set timeout.*/
     319             161 :     const char *pszTimeout = CSLFetchNameValue( papszOptions, "TIMEOUT" );
     320             161 :     if( pszTimeout != NULL )
     321                 :         curl_easy_setopt(http_handle, CURLOPT_TIMEOUT, 
     322               9 :                          atoi(pszTimeout) );
     323                 : 
     324                 :     /* Set Headers.*/
     325             161 :     const char *pszHeaders = CSLFetchNameValue( papszOptions, "HEADERS" );
     326             161 :     if( pszHeaders != NULL ) {
     327              77 :         CPLDebug ("HTTP", "These HTTP headers were set: %s", pszHeaders);
     328              77 :         headers = curl_slist_append(headers, pszHeaders);
     329              77 :         curl_easy_setopt(http_handle, CURLOPT_HTTPHEADER, headers);
     330                 :     }
     331                 : 
     332                 :     /* NOSIGNAL should be set to true for timeout to work in multithread
     333                 :      * environments on Unix, requires libcurl 7.10 or more recent.
     334                 :      * (this force avoiding the use of sgnal handlers)
     335                 :      */
     336                 : #ifdef CURLOPT_NOSIGNAL
     337                 :     curl_easy_setopt(http_handle, CURLOPT_NOSIGNAL, 1 );
     338                 : #endif
     339                 : 
     340                 :     // capture response headers
     341             161 :     curl_easy_setopt(http_handle, CURLOPT_HEADERDATA, psResult);
     342             161 :     curl_easy_setopt(http_handle, CURLOPT_HEADERFUNCTION, CPLHdrWriteFct);
     343                 :  
     344             161 :     curl_easy_setopt(http_handle, CURLOPT_WRITEDATA, psResult );
     345             161 :     curl_easy_setopt(http_handle, CURLOPT_WRITEFUNCTION, CPLWriteFct );
     346                 : 
     347             161 :     szCurlErrBuf[0] = '\0';
     348                 : 
     349             161 :     curl_easy_setopt(http_handle, CURLOPT_ERRORBUFFER, szCurlErrBuf );
     350                 : 
     351                 :     static int bHasCheckVersion = FALSE;
     352                 :     static int bSupportGZip = FALSE;
     353             161 :     if (!bHasCheckVersion)
     354                 :     {
     355               3 :         bSupportGZip = strstr(curl_version(), "zlib/") != NULL;
     356               3 :         bHasCheckVersion = TRUE;
     357                 :     }
     358             161 :     int bGZipRequested = FALSE;
     359             161 :     if (bSupportGZip && CSLTestBoolean(CPLGetConfigOption("CPL_CURL_GZIP", "YES")))
     360                 :     {
     361             161 :         bGZipRequested = TRUE;
     362             161 :         curl_easy_setopt(http_handle, CURLOPT_ENCODING, "gzip");
     363                 :     }
     364                 : 
     365                 : /* -------------------------------------------------------------------- */
     366                 : /*      Execute the request, waiting for results.                       */
     367                 : /* -------------------------------------------------------------------- */
     368             161 :     psResult->nStatus = (int) curl_easy_perform( http_handle );
     369                 : 
     370                 : /* -------------------------------------------------------------------- */
     371                 : /*      Fetch content-type if possible.                                 */
     372                 : /* -------------------------------------------------------------------- */
     373                 :     CURLcode err;
     374                 : 
     375             161 :     psResult->pszContentType = NULL;
     376                 :     err = curl_easy_getinfo( http_handle, CURLINFO_CONTENT_TYPE, 
     377             161 :                              &(psResult->pszContentType) );
     378             161 :     if( psResult->pszContentType != NULL )
     379             153 :         psResult->pszContentType = CPLStrdup(psResult->pszContentType);
     380                 : 
     381                 : /* -------------------------------------------------------------------- */
     382                 : /*      Have we encountered some sort of error?                         */
     383                 : /* -------------------------------------------------------------------- */
     384             161 :     if( strlen(szCurlErrBuf) > 0 )
     385                 :     {
     386               1 :         int bSkipError = FALSE;
     387                 : 
     388                 :         /* Some servers such as http://115.113.193.14/cgi-bin/world/qgis_mapserv.fcgi?VERSION=1.1.1&SERVICE=WMS&REQUEST=GetCapabilities */
     389                 :         /* invalidly return Content-Length as the uncompressed size, with makes curl to wait for more data */
     390                 :         /* and time-out finally. If we got the expected data size, then we don't emit an error */
     391                 :         /* but turn off GZip requests */
     392               1 :         if (bGZipRequested &&
     393                 :             strstr(szCurlErrBuf, "transfer closed with") &&
     394                 :             strstr(szCurlErrBuf, "bytes remaining to read"))
     395                 :         {
     396                 :             const char* pszContentLength =
     397               0 :                 CSLFetchNameValue(psResult->papszHeaders, "Content-Length");
     398               0 :             if (pszContentLength && psResult->nDataLen != 0 &&
     399                 :                 atoi(pszContentLength) == psResult->nDataLen)
     400                 :             {
     401               0 :                 const char* pszCurlGZIPOption = CPLGetConfigOption("CPL_CURL_GZIP", NULL);
     402               0 :                 if (pszCurlGZIPOption == NULL)
     403                 :                 {
     404               0 :                     CPLSetConfigOption("CPL_CURL_GZIP", "NO");
     405                 :                     CPLDebug("HTTP", "Disabling CPL_CURL_GZIP, because %s doesn't support it properly",
     406               0 :                              pszURL);
     407                 :                 }
     408               0 :                 psResult->nStatus = 0;
     409               0 :                 bSkipError = TRUE;
     410                 :             }
     411                 :         }
     412               1 :         if (!bSkipError)
     413                 :         {
     414               1 :             psResult->pszErrBuf = CPLStrdup(szCurlErrBuf);
     415                 :             CPLError( CE_Failure, CPLE_AppDefined,
     416               1 :                     "%s", szCurlErrBuf );
     417                 :         }
     418                 :     }
     419                 :     else
     420                 :     {
     421                 :         /* HTTP errors do not trigger curl errors. But we need to */
     422                 :         /* propagate them to the caller though */
     423             160 :         long response_code = 0;
     424             160 :         curl_easy_getinfo(http_handle, CURLINFO_RESPONSE_CODE, &response_code);
     425             160 :         if (response_code >= 400 && response_code < 600)
     426                 :         {
     427              12 :             psResult->pszErrBuf = CPLStrdup(CPLSPrintf("HTTP error code : %d", (int)response_code));
     428              12 :             CPLError( CE_Failure, CPLE_AppDefined, "%s", psResult->pszErrBuf );
     429                 :         }
     430                 :     }
     431                 : 
     432             161 :     if (!pszPersistent)
     433              95 :         curl_easy_cleanup( http_handle );
     434                 : 
     435             161 :     curl_slist_free_all(headers);
     436                 : 
     437             161 :     return psResult;
     438                 : #endif /* def HAVE_CURL */
     439                 : }
     440                 : 
     441                 : /************************************************************************/
     442                 : /*                           CPLHTTPEnabled()                           */
     443                 : /************************************************************************/
     444                 : 
     445                 : /**
     446                 :  * \brief Return if CPLHTTP services can be usefull
     447                 :  *
     448                 :  * Those services depend on GDAL being build with libcurl support.
     449                 :  *
     450                 :  * @return TRUE if libcurl support is enabled
     451                 :  */
     452               3 : int CPLHTTPEnabled()
     453                 : 
     454                 : {
     455                 : #ifdef HAVE_CURL
     456               3 :     return TRUE;
     457                 : #else
     458                 :     return FALSE;
     459                 : #endif
     460                 : }
     461                 : 
     462                 : /************************************************************************/
     463                 : /*                           CPLHTTPCleanup()                           */
     464                 : /************************************************************************/
     465                 : 
     466                 : /**
     467                 :  * \brief Cleanup function to call at application termination
     468                 :  */
     469               0 : void CPLHTTPCleanup()
     470                 : 
     471                 : {
     472                 : #ifdef HAVE_CURL
     473               0 :     if( !hSessionMapMutex )
     474               0 :         return;
     475                 : 
     476                 :     {
     477               0 :         CPLMutexHolder oHolder( &hSessionMapMutex );
     478               0 :         std::map<CPLString,CURL*>::iterator oIt;
     479                 : 
     480               0 :         for( oIt=oSessionMap.begin(); oIt != oSessionMap.end(); oIt++ )
     481               0 :             curl_easy_cleanup( oIt->second );
     482                 : 
     483               0 :         oSessionMap.clear();
     484                 :     }
     485                 : 
     486                 :     // not quite a safe sequence. 
     487               0 :     CPLDestroyMutex( hSessionMapMutex );
     488               0 :     hSessionMapMutex = NULL;
     489                 : #endif
     490                 : }
     491                 : 
     492                 : /************************************************************************/
     493                 : /*                        CPLHTTPDestroyResult()                        */
     494                 : /************************************************************************/
     495                 : 
     496                 : /**
     497                 :  * \brief Clean the memory associated with the return value of CPLHTTPFetch()
     498                 :  *
     499                 :  * @param psResult pointer to the return value of CPLHTTPFetch()
     500                 :  */
     501             161 : void CPLHTTPDestroyResult( CPLHTTPResult *psResult )
     502                 : 
     503                 : {
     504             161 :     if( psResult )
     505                 :     {
     506             161 :         CPLFree( psResult->pabyData );
     507             161 :         CPLFree( psResult->pszErrBuf );
     508             161 :         CPLFree( psResult->pszContentType );
     509             161 :         CSLDestroy( psResult->papszHeaders );
     510                 : 
     511                 :         int i;
     512             161 :         for(i=0;i<psResult->nMimePartCount;i++)
     513                 :         {
     514               0 :             CSLDestroy( psResult->pasMimePart[i].papszHeaders );
     515                 :         }
     516             161 :         CPLFree(psResult->pasMimePart);
     517                 :         
     518             161 :         CPLFree( psResult );
     519                 :     }
     520             161 : }
     521                 : 
     522                 : /************************************************************************/
     523                 : /*                     CPLHTTPParseMultipartMime()                      */
     524                 : /************************************************************************/
     525                 : 
     526                 : /**
     527                 :  * \brief Parses a a MIME multipart message
     528                 :  *
     529                 :  * This function will iterate over each part and put it in a separate
     530                 :  * element of the pasMimePart array of the provided psResult structure.
     531                 :  *
     532                 :  * @param psResult pointer to the return value of CPLHTTPFetch()
     533                 :  * @return TRUE if the message contains MIME multipart message.
     534                 :  */
     535               0 : int CPLHTTPParseMultipartMime( CPLHTTPResult *psResult )
     536                 : 
     537                 : {
     538                 : /* -------------------------------------------------------------------- */
     539                 : /*      Is it already done?                                             */
     540                 : /* -------------------------------------------------------------------- */
     541               0 :     if( psResult->nMimePartCount > 0 )
     542               0 :         return TRUE;
     543                 : 
     544                 : /* -------------------------------------------------------------------- */
     545                 : /*      Find the boundary setting in the content type.                  */
     546                 : /* -------------------------------------------------------------------- */
     547               0 :     const char *pszBound = NULL;
     548                 : 
     549               0 :     if( psResult->pszContentType != NULL )
     550               0 :         pszBound = strstr(psResult->pszContentType,"boundary=");
     551                 : 
     552               0 :     if( pszBound == NULL )
     553                 :     {
     554                 :         CPLError( CE_Failure, CPLE_AppDefined,
     555               0 :                   "Unable to parse multi-part mime, no boundary setting." );
     556               0 :         return FALSE;
     557                 :     }
     558                 : 
     559               0 :     CPLString osBoundary;
     560                 :     char **papszTokens = 
     561                 :         CSLTokenizeStringComplex( pszBound + 9, "\n ;", 
     562               0 :                                   TRUE, FALSE );
     563                 : 
     564               0 :     if( CSLCount(papszTokens) == 0 || strlen(papszTokens[0]) == 0 )
     565                 :     {
     566                 :         CPLError( CE_Failure, CPLE_AppDefined,
     567               0 :                   "Unable to parse multi-part mime, boundary not parsable." );
     568               0 :         CSLDestroy( papszTokens );
     569               0 :         return FALSE;
     570                 :     }
     571                 :     
     572               0 :     osBoundary = "--";
     573               0 :     osBoundary += papszTokens[0];
     574               0 :     CSLDestroy( papszTokens );
     575                 : 
     576                 : /* -------------------------------------------------------------------- */
     577                 : /*      Find the start of the first chunk.                              */
     578                 : /* -------------------------------------------------------------------- */
     579                 :     char *pszNext;
     580                 :     pszNext = (char *) 
     581               0 :         strstr((const char *) psResult->pabyData,osBoundary.c_str());
     582                 :     
     583               0 :     if( pszNext == NULL )
     584                 :     {
     585               0 :         CPLError( CE_Failure, CPLE_AppDefined, "No parts found." );
     586               0 :         return FALSE;
     587                 :     }
     588                 : 
     589               0 :     pszNext += strlen(osBoundary);
     590               0 :     while( *pszNext != '\n' && *pszNext != '\r' && *pszNext != '\0' )
     591               0 :         pszNext++;
     592               0 :     if( *pszNext == '\r' )
     593               0 :         pszNext++;
     594               0 :     if( *pszNext == '\n' )
     595               0 :         pszNext++;
     596                 : 
     597                 : /* -------------------------------------------------------------------- */
     598                 : /*      Loop over parts...                                              */
     599                 : /* -------------------------------------------------------------------- */
     600               0 :     while( TRUE )
     601                 :     {
     602               0 :         psResult->nMimePartCount++;
     603                 :         psResult->pasMimePart = (CPLMimePart *)
     604                 :             CPLRealloc(psResult->pasMimePart,
     605               0 :                        sizeof(CPLMimePart) * psResult->nMimePartCount );
     606                 : 
     607               0 :         CPLMimePart *psPart = psResult->pasMimePart+psResult->nMimePartCount-1;
     608                 : 
     609               0 :         memset( psPart, 0, sizeof(CPLMimePart) );
     610                 : 
     611                 : /* -------------------------------------------------------------------- */
     612                 : /*      Collect headers.                                                */
     613                 : /* -------------------------------------------------------------------- */
     614               0 :         while( *pszNext != '\n' && *pszNext != '\r' && *pszNext != '\0' )
     615                 :         {
     616               0 :             char *pszEOL = strstr(pszNext,"\n");
     617                 : 
     618               0 :             if( pszEOL == NULL )
     619                 :             {
     620                 :                 CPLError(CE_Failure, CPLE_AppDefined,
     621               0 :                          "Error while parsing multipart content (at line %d)", __LINE__);
     622               0 :                 return FALSE;
     623                 :             }
     624                 : 
     625               0 :             *pszEOL = '\0';
     626               0 :             int bRestoreAntislashR = FALSE;
     627               0 :             if (pszEOL - pszNext > 1 && pszEOL[-1] == '\r')
     628                 :             {
     629               0 :                 bRestoreAntislashR = TRUE;
     630               0 :                 pszEOL[-1] = '\0';
     631                 :             }
     632                 :             psPart->papszHeaders = 
     633               0 :                 CSLAddString( psPart->papszHeaders, pszNext );
     634               0 :             if (bRestoreAntislashR)
     635               0 :                 pszEOL[-1] = '\r';
     636               0 :             *pszEOL = '\n';
     637                 :             
     638               0 :             pszNext = pszEOL + 1;
     639                 :         }
     640                 : 
     641               0 :         if( *pszNext == '\r' )
     642               0 :             pszNext++;
     643               0 :         if( *pszNext == '\n' )
     644               0 :             pszNext++;
     645                 :             
     646                 : /* -------------------------------------------------------------------- */
     647                 : /*      Work out the data block size.                                   */
     648                 : /* -------------------------------------------------------------------- */
     649               0 :         psPart->pabyData = (GByte *) pszNext;
     650                 : 
     651                 :         int nBytesAvail = psResult->nDataLen - 
     652               0 :             (pszNext - (const char *) psResult->pabyData);
     653                 : 
     654               0 :         while( nBytesAvail > 0
     655                 :                && (*pszNext != '-' 
     656                 :                    || strncmp(pszNext,osBoundary,strlen(osBoundary)) != 0) )
     657                 :         {
     658               0 :             pszNext++;
     659               0 :             nBytesAvail--;
     660                 :         }
     661                 :         
     662               0 :         if( nBytesAvail == 0 )
     663                 :         {
     664                 :             CPLError(CE_Failure, CPLE_AppDefined,
     665               0 :                         "Error while parsing multipart content (at line %d)", __LINE__);
     666               0 :             return FALSE;
     667                 :         }
     668                 : 
     669               0 :         psPart->nDataLen = pszNext - (const char *) psPart->pabyData;
     670               0 :         pszNext += strlen(osBoundary);
     671                 : 
     672               0 :         if( strncmp(pszNext,"--",2) == 0 )
     673                 :         {
     674                 :             break;
     675                 :         }
     676                 : 
     677               0 :         if( *pszNext == '\r' )
     678               0 :             pszNext++;
     679               0 :         if( *pszNext == '\n' )
     680               0 :             pszNext++;
     681                 :         else
     682                 :         {
     683                 :             CPLError(CE_Failure, CPLE_AppDefined,
     684               0 :                         "Error while parsing multipart content (at line %d)", __LINE__);
     685               0 :             return FALSE;
     686                 :         }
     687                 :     }
     688                 : 
     689               0 :     return TRUE;
     690            2139 : }

Generated by: LCOV version 1.7