LCOV - code coverage report
Current view: directory - port - cpl_http.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 127 52 40.9 %
Date: 2010-01-09 Functions: 6 3 50.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: cpl_http.cpp 17927 2009-10-30 18:37:12Z rouault $
       3                 :  *
       4                 :  * Project:  WCS Client Driver
       5                 :  * Purpose:  Implementation of Dataset and RasterBand classes for WCS.
       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 "cpl_conv.h"
      31                 : #include "cpl_http.h"
      32                 : 
      33                 : #ifdef HAVE_CURL
      34                 : #  include <curl/curl.h>
      35                 : #endif
      36                 : 
      37                 : CPL_CVSID("$Id: cpl_http.cpp 17927 2009-10-30 18:37:12Z rouault $");
      38                 : 
      39                 : /************************************************************************/
      40                 : /*                            CPLWriteFct()                             */
      41                 : /*                                                                      */
      42                 : /*      Append incoming text to our collection buffer, reallocating     */
      43                 : /*      it larger as needed.                                            */
      44                 : /************************************************************************/
      45                 : 
      46                 : #ifdef HAVE_CURL
      47                 : static size_t 
      48              13 : CPLWriteFct(void *buffer, size_t size, size_t nmemb, void *reqInfo)
      49                 : 
      50                 : {
      51              13 :     CPLHTTPResult *psResult = (CPLHTTPResult *) reqInfo;
      52                 :     int  nNewSize;
      53                 : 
      54              13 :     nNewSize = psResult->nDataLen + nmemb*size + 1;
      55              13 :     if( nNewSize > psResult->nDataAlloc )
      56                 :     {
      57               9 :         psResult->nDataAlloc = (int) (nNewSize * 1.25 + 100);
      58                 :         GByte* pabyNewData = (GByte *) VSIRealloc(psResult->pabyData,
      59               9 :                                                   psResult->nDataAlloc);
      60               9 :         if( pabyNewData == NULL )
      61                 :         {
      62               0 :             VSIFree(psResult->pabyData);
      63               0 :             psResult->pabyData = NULL;
      64               0 :             psResult->pszErrBuf = CPLStrdup(CPLString().Printf("Out of memory allocating %d bytes for HTTP data buffer.", psResult->nDataAlloc));
      65               0 :             psResult->nDataAlloc = psResult->nDataLen = 0;
      66                 : 
      67               0 :             return 0;
      68                 :         }
      69               9 :         psResult->pabyData = pabyNewData;
      70                 :     }
      71                 : 
      72                 :     memcpy( psResult->pabyData + psResult->nDataLen, buffer,
      73              13 :             nmemb * size );
      74                 : 
      75              13 :     psResult->nDataLen += nmemb * size;
      76              13 :     psResult->pabyData[psResult->nDataLen] = 0;
      77                 : 
      78              13 :     return nmemb;
      79                 : }
      80                 : #endif /* def HAVE_CURL */
      81                 : 
      82                 : /************************************************************************/
      83                 : /*                           CPLHTTPFetch()                             */
      84                 : /************************************************************************/
      85                 : 
      86                 : /**
      87                 :  * \brief Fetch a document from an url and return in a string.
      88                 :  *
      89                 :  * @param pszURL valid URL recognized by underlying download library (libcurl)
      90                 :  * @param papszOptions option list as a NULL-terminated array of strings. May be NULL.
      91                 :  *                     The following options are handled :
      92                 :  * <ul>
      93                 :  * <li>TIMEOUT=val, where val is in seconds</li>
      94                 :  * <li>HEADERS=val, where val is an extra header to use when getting a web page.
      95                 :  *                  For example "Accept: application/x-ogcwkt"
      96                 :  * <li>HTTPAUTH=[BASIC/NTLM/ANY] to specify an authentication scheme to use.
      97                 :  * <li>USERPWD=userid:password to specify a user and password for authentication
      98                 :  * </ul>
      99                 :  *
     100                 :  * @return a CPLHTTPResult* structure that must be freed by CPLHTTPDestroyResult(),
     101                 :  *         or NULL if libcurl support is diabled
     102                 :  */
     103               3 : CPLHTTPResult *CPLHTTPFetch( const char *pszURL, char **papszOptions )
     104                 : 
     105                 : {
     106                 : #ifndef HAVE_CURL
     107                 :     CPLError( CE_Failure, CPLE_NotSupported,
     108                 :               "GDAL/OGR not compiled with libcurl support, remote requests not supported." );
     109                 :     return NULL;
     110                 : #else
     111                 :     CURL *http_handle;
     112                 :     char szCurlErrBuf[CURL_ERROR_SIZE+1];
     113                 :     CPLHTTPResult *psResult;
     114               3 :     struct curl_slist *headers=NULL; 
     115                 : 
     116                 : 
     117               3 :     CPLDebug( "HTTP", "Fetch(%s)", pszURL );
     118                 : 
     119               3 :     psResult = (CPLHTTPResult *) CPLCalloc(1,sizeof(CPLHTTPResult));
     120                 : 
     121               3 :     http_handle = curl_easy_init();
     122                 : 
     123               3 :     curl_easy_setopt(http_handle, CURLOPT_URL, pszURL );
     124                 : 
     125                 :     /* Support control over HTTPAUTH */
     126               3 :     const char *pszHttpAuth = CSLFetchNameValue( papszOptions, "HTTPAUTH" );
     127               3 :     if( pszHttpAuth == NULL )
     128                 :         /* do nothing */;
     129                 : 
     130                 :     /* CURLOPT_HTTPAUTH is defined in curl 7.11.0 or newer */
     131                 : #if LIBCURL_VERSION_NUM >= 0x70B00
     132               0 :     else if( EQUAL(pszHttpAuth,"BASIC") )
     133               0 :         curl_easy_setopt(http_handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC );
     134               0 :     else if( EQUAL(pszHttpAuth,"NTLM") )
     135               0 :         curl_easy_setopt(http_handle, CURLOPT_HTTPAUTH, CURLAUTH_NTLM );
     136               0 :     else if( EQUAL(pszHttpAuth,"ANY") )
     137               0 :         curl_easy_setopt(http_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY );
     138                 :     else
     139                 :     {
     140                 :         CPLError( CE_Warning, CPLE_AppDefined,
     141                 :                   "Unsupported HTTPAUTH value '%s', ignored.", 
     142               0 :                   pszHttpAuth );
     143                 :     }
     144                 : #else
     145                 :     else
     146                 :     {
     147                 :         CPLError( CE_Warning, CPLE_AppDefined,
     148                 :                   "HTTPAUTH option needs curl >= 7.11.0" );
     149                 :     }
     150                 : #endif
     151                 : 
     152                 :     /* Support setting userid:password */
     153               3 :     const char *pszUserPwd = CSLFetchNameValue( papszOptions, "USERPWD" );
     154               3 :     if( pszUserPwd != NULL )
     155               0 :         curl_easy_setopt(http_handle, CURLOPT_USERPWD, pszUserPwd );
     156                 : 
     157                 :     /* Enable following redirections.  Requires libcurl 7.10.1 at least */
     158               3 :     curl_easy_setopt(http_handle, CURLOPT_FOLLOWLOCATION, 1 );
     159               3 :     curl_easy_setopt(http_handle, CURLOPT_MAXREDIRS, 10 );
     160                 :     
     161                 :     /* Set timeout.*/
     162               3 :     const char *pszTimeout = CSLFetchNameValue( papszOptions, "TIMEOUT" );
     163               3 :     if( pszTimeout != NULL )
     164                 :         curl_easy_setopt(http_handle, CURLOPT_TIMEOUT, 
     165               2 :                          atoi(pszTimeout) );
     166                 : 
     167                 :     /* Set Headers.*/
     168               3 :     const char *pszHeaders = CSLFetchNameValue( papszOptions, "HEADERS" );
     169               3 :     if( pszHeaders != NULL ) {
     170               2 :         CPLDebug ("HTTP", "These HTTP headers were set: %s", pszHeaders);
     171               2 :         headers = curl_slist_append(headers, pszHeaders);
     172               2 :         curl_easy_setopt(http_handle, CURLOPT_HTTPHEADER, headers);
     173                 :     }
     174                 :                          
     175                 :     /* NOSIGNAL should be set to true for timeout to work in multithread
     176                 :      * environments on Unix, requires libcurl 7.10 or more recent.
     177                 :      * (this force avoiding the use of sgnal handlers)
     178                 :      */
     179                 : #ifdef CURLOPT_NOSIGNAL
     180                 :     curl_easy_setopt(http_handle, CURLOPT_NOSIGNAL, 1 );
     181                 : #endif
     182                 : 
     183               3 :     curl_easy_setopt(http_handle, CURLOPT_WRITEDATA, psResult );
     184               3 :     curl_easy_setopt(http_handle, CURLOPT_WRITEFUNCTION, CPLWriteFct );
     185                 : 
     186               3 :     szCurlErrBuf[0] = '\0';
     187                 : 
     188               3 :     curl_easy_setopt(http_handle, CURLOPT_ERRORBUFFER, szCurlErrBuf );
     189                 : 
     190               3 :     psResult->nStatus = (int) curl_easy_perform( http_handle );
     191                 : 
     192                 : /* -------------------------------------------------------------------- */
     193                 : /*      Fetch content-type if possible.                                 */
     194                 : /* -------------------------------------------------------------------- */
     195                 :     CURLcode err;
     196                 : 
     197               3 :     psResult->pszContentType = NULL;
     198                 :     err = curl_easy_getinfo( http_handle, CURLINFO_CONTENT_TYPE, 
     199               3 :                              &(psResult->pszContentType) );
     200               3 :     if( psResult->pszContentType != NULL )
     201               3 :         psResult->pszContentType = CPLStrdup(psResult->pszContentType);
     202                 : 
     203                 : /* -------------------------------------------------------------------- */
     204                 : /*      Have we encountered some sort of error?                         */
     205                 : /* -------------------------------------------------------------------- */
     206               3 :     if( strlen(szCurlErrBuf) > 0 )
     207                 :     {
     208               0 :         psResult->pszErrBuf = CPLStrdup(szCurlErrBuf);
     209                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     210               0 :                   "%s", szCurlErrBuf );
     211                 :     }
     212                 : 
     213               3 :     curl_easy_cleanup( http_handle );
     214               3 :     curl_slist_free_all(headers);
     215                 : 
     216               3 :     return psResult;
     217                 : #endif /* def HAVE_CURL */
     218                 : }
     219                 : 
     220                 : /************************************************************************/
     221                 : /*                           CPLHTTPEnabled()                           */
     222                 : /************************************************************************/
     223                 : 
     224                 : /**
     225                 :  * \brief Return if CPLHTTP services can be usefull
     226                 :  *
     227                 :  * Those services depend on GDAL being build with libcurl support.
     228                 :  *
     229                 :  * @return TRUE if libcurl support is enabled
     230                 :  */
     231               0 : int CPLHTTPEnabled()
     232                 : 
     233                 : {
     234                 : #ifdef HAVE_CURL
     235               0 :     return TRUE;
     236                 : #else
     237                 :     return FALSE;
     238                 : #endif
     239                 : }
     240                 : 
     241                 : /************************************************************************/
     242                 : /*                           CPLHTTPCleanup()                           */
     243                 : /************************************************************************/
     244                 : 
     245                 : /**
     246                 :  * \brief Cleanup function to call at application termination
     247                 :  */
     248               0 : void CPLHTTPCleanup()
     249                 : 
     250                 : {
     251                 :     /* nothing for now, but if we use the more complicated api later, 
     252                 :        we will need to do cleanup, like mapserver maphttp.c does. */
     253               0 : }
     254                 : 
     255                 : /************************************************************************/
     256                 : /*                        CPLHTTPDestroyResult()                        */
     257                 : /************************************************************************/
     258                 : 
     259                 : /**
     260                 :  * \brief Clean the memory associated with the return value of CPLHTTPFetch()
     261                 :  *
     262                 :  * @param psResult pointer to the return value of CPLHTTPFetch()
     263                 :  */
     264               3 : void CPLHTTPDestroyResult( CPLHTTPResult *psResult )
     265                 : 
     266                 : {
     267               3 :     if( psResult )
     268                 :     {
     269               3 :         CPLFree( psResult->pabyData );
     270               3 :         CPLFree( psResult->pszErrBuf );
     271               3 :         CPLFree( psResult->pszContentType );
     272               3 :         CPLFree( psResult );
     273                 :     }
     274               3 : }
     275                 : 
     276                 : /************************************************************************/
     277                 : /*                     CPLHTTPParseMultipartMime()                      */
     278                 : /************************************************************************/
     279                 : 
     280                 : /**
     281                 :  * \brief Parses a a MIME multipart message
     282                 :  *
     283                 :  * This function will iterate over each part and put it in a separate
     284                 :  * element of the pasMimePart array of the provided psResult structure.
     285                 :  *
     286                 :  * @param psResult pointer to the return value of CPLHTTPFetch()
     287                 :  * @return TRUE if the message contains MIME multipart message.
     288                 :  */
     289               0 : int CPLHTTPParseMultipartMime( CPLHTTPResult *psResult )
     290                 : 
     291                 : {
     292                 : /* -------------------------------------------------------------------- */
     293                 : /*      Is it already done?                                             */
     294                 : /* -------------------------------------------------------------------- */
     295               0 :     if( psResult->nMimePartCount > 0 )
     296               0 :         return TRUE;
     297                 : 
     298                 : /* -------------------------------------------------------------------- */
     299                 : /*      Find the boundary setting in the content type.                  */
     300                 : /* -------------------------------------------------------------------- */
     301               0 :     const char *pszBound = NULL;
     302                 : 
     303               0 :     if( psResult->pszContentType != NULL )
     304               0 :         pszBound = strstr(psResult->pszContentType,"boundary=");
     305                 : 
     306               0 :     if( pszBound == NULL )
     307                 :     {
     308                 :         CPLError( CE_Failure, CPLE_AppDefined,
     309               0 :                   "Unable to parse multi-part mime, no boundary setting." );
     310               0 :         return FALSE;
     311                 :     }
     312                 : 
     313               0 :     CPLString osBoundary;
     314                 :     char **papszTokens = 
     315                 :         CSLTokenizeStringComplex( pszBound + 9, "\n ;", 
     316               0 :                                   TRUE, FALSE );
     317                 : 
     318               0 :     if( CSLCount(papszTokens) == 0 || strlen(papszTokens[0]) == 0 )
     319                 :     {
     320                 :         CPLError( CE_Failure, CPLE_AppDefined,
     321               0 :                   "Unable to parse multi-part mime, boundary not parsable." );
     322               0 :         return FALSE;
     323                 :     }
     324                 :     
     325               0 :     osBoundary = "--";
     326               0 :     osBoundary += papszTokens[0];
     327               0 :     CSLDestroy( papszTokens );
     328                 : 
     329                 : /* -------------------------------------------------------------------- */
     330                 : /*      Find the start of the first chunk.                              */
     331                 : /* -------------------------------------------------------------------- */
     332                 :     char *pszNext;
     333                 :     pszNext = (char *) 
     334               0 :         strstr((const char *) psResult->pabyData,osBoundary.c_str());
     335                 :     
     336               0 :     if( pszNext == NULL )
     337                 :     {
     338               0 :         CPLError( CE_Failure, CPLE_AppDefined, "No parts found." );
     339               0 :         return FALSE;
     340                 :     }
     341                 : 
     342               0 :     pszNext += strlen(osBoundary);
     343               0 :     while( *pszNext != '\n' && *pszNext != '\0' )
     344               0 :         pszNext++;
     345               0 :     if( *pszNext == '\n' )
     346               0 :         pszNext++;
     347                 : 
     348                 : /* -------------------------------------------------------------------- */
     349                 : /*      Loop over parts...                                              */
     350                 : /* -------------------------------------------------------------------- */
     351               0 :     while( TRUE )
     352                 :     {
     353               0 :         psResult->nMimePartCount++;
     354                 :         psResult->pasMimePart = (CPLMimePart *)
     355                 :             CPLRealloc(psResult->pasMimePart,
     356               0 :                        sizeof(CPLMimePart) * psResult->nMimePartCount );
     357                 : 
     358               0 :         CPLMimePart *psPart = psResult->pasMimePart+psResult->nMimePartCount-1;
     359                 : 
     360               0 :         memset( psPart, 0, sizeof(CPLMimePart) );
     361                 : 
     362                 : /* -------------------------------------------------------------------- */
     363                 : /*      Collect headers.                                                */
     364                 : /* -------------------------------------------------------------------- */
     365               0 :         while( *pszNext != '\n' && *pszNext != '\0' )
     366                 :         {
     367               0 :             char *pszEOL = strstr(pszNext,"\n");
     368                 : 
     369               0 :             if( pszEOL == NULL )
     370                 :             {
     371                 :                 CPLAssert( FALSE );
     372               0 :                 break;
     373                 :             }
     374                 : 
     375               0 :             *pszEOL = '\0';
     376                 :             psPart->papszHeaders = 
     377               0 :                 CSLAddString( psPart->papszHeaders, pszNext );
     378               0 :             *pszEOL = '\n';
     379                 :             
     380               0 :             pszNext = pszEOL + 1;
     381                 :         }
     382                 : 
     383               0 :         if( *pszNext == '\n' )
     384               0 :             pszNext++;
     385                 :             
     386                 : /* -------------------------------------------------------------------- */
     387                 : /*      Work out the data block size.                                   */
     388                 : /* -------------------------------------------------------------------- */
     389               0 :         psPart->pabyData = (GByte *) pszNext;
     390                 : 
     391                 :         int nBytesAvail = psResult->nDataLen - 
     392               0 :             (pszNext - (const char *) psResult->pabyData);
     393                 : 
     394               0 :         while( nBytesAvail > 0
     395                 :                && (*pszNext != '-' 
     396                 :                    || strncmp(pszNext,osBoundary,strlen(osBoundary)) != 0) )
     397                 :         {
     398               0 :             pszNext++;
     399               0 :             nBytesAvail--;
     400                 :         }
     401                 :         
     402               0 :         if( nBytesAvail == 0 )
     403                 :         {
     404                 :             CPLAssert( FALSE );
     405               0 :             break;
     406                 :         }
     407                 : 
     408               0 :         psPart->nDataLen = pszNext - (const char *) psPart->pabyData;
     409               0 :         pszNext += strlen(osBoundary);
     410                 : 
     411               0 :         if( strncmp(pszNext,"--",2) == 0 )
     412                 :         {
     413               0 :             break;
     414                 :         }
     415               0 :         else if( *pszNext == '\n' )
     416               0 :             pszNext++;
     417                 :         else
     418                 :         {
     419                 :             CPLAssert( FALSE );
     420               0 :             break;
     421                 :         }
     422                 :     }
     423                 : 
     424               0 :     return TRUE;
     425                 : }

Generated by: LCOV version 1.7