LCOV - code coverage report
Current view: directory - port - cpl_http.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 281 155 55.2 %
Date: 2013-03-30 Functions: 11 8 72.7 %

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

Generated by: LCOV version 1.7