LCOV - code coverage report
Current view: top level - core - qgscplhttpfetchoverrider.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 11 95 11.6 %
Date: 2021-03-26 12:19:53 Functions: 0 0 -
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :     qgscplhttpfetchoverrider.cpp
       3                 :            :     ----------------------------
       4                 :            :     begin                : September 2020
       5                 :            :     copyright            : (C) 2020 by Even Rouault
       6                 :            :     email                : even.rouault at spatialys.com
       7                 :            :  ***************************************************************************
       8                 :            :  *                                                                         *
       9                 :            :  *   This program is free software; you can redistribute it and/or modify  *
      10                 :            :  *   it under the terms of the GNU General Public License as published by  *
      11                 :            :  *   the Free Software Foundation; either version 2 of the License, or     *
      12                 :            :  *   (at your option) any later version.                                   *
      13                 :            :  *                                                                         *
      14                 :            :  ***************************************************************************/
      15                 :            : 
      16                 :            : #include "qgscplhttpfetchoverrider.h"
      17                 :            : #include "qgslogger.h"
      18                 :            : #include "qgsblockingnetworkrequest.h"
      19                 :            : 
      20                 :            : #include "cpl_http.h"
      21                 :            : #include "gdal.h"
      22                 :            : 
      23                 :            : #if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(3,2,0)
      24                 :            : 
      25                 :            : QgsCPLHTTPFetchOverrider::QgsCPLHTTPFetchOverrider( const QString &authCfg, QgsFeedback *feedback )
      26                 :            : {
      27                 :            :   Q_UNUSED( authCfg );
      28                 :            :   Q_UNUSED( feedback );
      29                 :            :   Q_UNUSED( mAuthCfg );
      30                 :            :   Q_UNUSED( mFeedback );
      31                 :            : }
      32                 :            : 
      33                 :            : QgsCPLHTTPFetchOverrider::~QgsCPLHTTPFetchOverrider()
      34                 :            : {
      35                 :            : }
      36                 :            : 
      37                 :            : #else
      38                 :            : 
      39                 :       1758 : QgsCPLHTTPFetchOverrider::QgsCPLHTTPFetchOverrider( const QString &authCfg, QgsFeedback *feedback ):
      40                 :       1758 :   mAuthCfg( authCfg ),
      41                 :       1758 :   mFeedback( feedback )
      42                 :            : {
      43                 :       1758 :   CPLHTTPPushFetchCallback( QgsCPLHTTPFetchOverrider::callback, this );
      44                 :       1758 : }
      45                 :            : 
      46                 :       1758 : QgsCPLHTTPFetchOverrider::~QgsCPLHTTPFetchOverrider()
      47                 :            : {
      48                 :       1758 :   CPLHTTPPopFetchCallback();
      49                 :       1758 : }
      50                 :            : 
      51                 :            : 
      52                 :          0 : CPLHTTPResult *QgsCPLHTTPFetchOverrider::callback( const char *pszURL,
      53                 :            :     CSLConstList papszOptions,
      54                 :            :     GDALProgressFunc /* pfnProgress */,
      55                 :            :     void * /*pProgressArg */,
      56                 :            :     CPLHTTPFetchWriteFunc pfnWrite,
      57                 :            :     void *pWriteArg,
      58                 :            :     void *pUserData )
      59                 :            : {
      60                 :          0 :   QgsCPLHTTPFetchOverrider *pThis = static_cast<QgsCPLHTTPFetchOverrider *>( pUserData );
      61                 :            : 
      62                 :          0 :   auto psResult = static_cast<CPLHTTPResult *>( CPLCalloc( sizeof( CPLHTTPResult ), 1 ) );
      63                 :          0 :   if ( CSLFetchNameValue( papszOptions, "CLOSE_PERSISTENT" ) )
      64                 :            :   {
      65                 :            :     // CLOSE_PERSISTENT is a CPL trick to maintain a curl handle open over
      66                 :            :     // a series of CPLHTTPFetch() call to the same server.
      67                 :            :     // Just return a dummy result to acknowledge we 'processed' it
      68                 :          0 :     return psResult;
      69                 :            :   }
      70                 :            : 
      71                 :            :   // Look for important options we don't handle yet
      72                 :          0 :   for ( const char *pszOption : { "FORM_FILE_PATH", "FORM_ITEM_COUNT" } )
      73                 :            :   {
      74                 :          0 :     if ( CSLFetchNameValue( papszOptions, pszOption ) )
      75                 :            :     {
      76                 :          0 :       QgsDebugMsg( QStringLiteral( "Option %1 not handled" ).arg( pszOption ) );
      77                 :          0 :       return nullptr;
      78                 :            :     }
      79                 :            :   }
      80                 :            : 
      81                 :          0 :   QgsBlockingNetworkRequest blockingRequest;
      82                 :          0 :   blockingRequest.setAuthCfg( pThis->mAuthCfg );
      83                 :            : 
      84                 :          0 :   QNetworkRequest request( QString::fromUtf8( pszURL ) );
      85                 :          0 :   for ( const auto &keyValue : pThis->mAttributes )
      86                 :            :   {
      87                 :          0 :     request.setAttribute( keyValue.first, keyValue.second );
      88                 :            :   }
      89                 :            : 
      90                 :            :   // Store request headers
      91                 :          0 :   const char *pszHeaders = CSLFetchNameValue( papszOptions, "HEADERS" );
      92                 :          0 :   if ( pszHeaders )
      93                 :            :   {
      94                 :          0 :     char **papszTokensHeaders = CSLTokenizeString2( pszHeaders, "\r\n", 0 );
      95                 :          0 :     for ( int i = 0; papszTokensHeaders[i] != nullptr; ++i )
      96                 :            :     {
      97                 :          0 :       char *pszKey = nullptr;
      98                 :          0 :       const char *pszValue = CPLParseNameValue( papszTokensHeaders[i], &pszKey );
      99                 :          0 :       if ( pszKey && pszValue )
     100                 :            :       {
     101                 :          0 :         request.setRawHeader(
     102                 :          0 :           QByteArray::fromStdString( pszKey ),
     103                 :          0 :           QByteArray::fromStdString( pszValue ) );
     104                 :          0 :       }
     105                 :          0 :       CPLFree( pszKey );
     106                 :          0 :     }
     107                 :          0 :     CSLDestroy( papszTokensHeaders );
     108                 :          0 :   }
     109                 :            : 
     110                 :          0 :   constexpr bool forceRefresh = true;
     111                 :          0 :   const char *pszCustomRequest = CSLFetchNameValue( papszOptions, "CUSTOMREQUEST" );
     112                 :          0 :   const char *pszPostFields = CSLFetchNameValue( papszOptions, "POSTFIELDS" );
     113                 :            :   QgsBlockingNetworkRequest::ErrorCode errCode;
     114                 :          0 :   if ( pszPostFields )
     115                 :            :   {
     116                 :          0 :     if ( pszCustomRequest == nullptr || EQUAL( pszCustomRequest, "POST" ) )
     117                 :            :     {
     118                 :          0 :       errCode = blockingRequest.post( request,
     119                 :          0 :                                       QByteArray::fromStdString( pszPostFields ),
     120                 :            :                                       forceRefresh,
     121                 :          0 :                                       pThis->mFeedback );
     122                 :          0 :     }
     123                 :          0 :     else if ( EQUAL( pszCustomRequest, "PUT" ) )
     124                 :            :     {
     125                 :          0 :       errCode = blockingRequest.put( request,
     126                 :          0 :                                      QByteArray::fromStdString( pszPostFields ),
     127                 :          0 :                                      pThis->mFeedback );
     128                 :          0 :     }
     129                 :            :     else
     130                 :            :     {
     131                 :          0 :       QgsDebugMsg( QStringLiteral( "Invalid CUSTOMREQUEST = %1 when POSTFIELDS is defined" ).arg( pszCustomRequest ) );
     132                 :          0 :       return nullptr;
     133                 :            :     }
     134                 :          0 :   }
     135                 :            :   else
     136                 :            :   {
     137                 :          0 :     if ( pszCustomRequest == nullptr || EQUAL( pszCustomRequest, "GET" ) )
     138                 :            :     {
     139                 :          0 :       errCode = blockingRequest.get( request, forceRefresh, pThis->mFeedback );
     140                 :          0 :     }
     141                 :          0 :     else if ( EQUAL( pszCustomRequest, "HEAD" ) )
     142                 :            :     {
     143                 :          0 :       errCode = blockingRequest.head( request, forceRefresh, pThis->mFeedback );
     144                 :          0 :     }
     145                 :          0 :     else if ( EQUAL( pszCustomRequest, "DELETE" ) )
     146                 :            :     {
     147                 :          0 :       errCode = blockingRequest.deleteResource( request, pThis->mFeedback );
     148                 :          0 :     }
     149                 :            :     else
     150                 :            :     {
     151                 :          0 :       QgsDebugMsg( QStringLiteral( "Invalid CUSTOMREQUEST = %1 when POSTFIELDS is not defined" ).arg( pszCustomRequest ) );
     152                 :          0 :       return nullptr;
     153                 :            :     }
     154                 :            :   }
     155                 :          0 :   if ( errCode != QgsBlockingNetworkRequest::NoError )
     156                 :            :   {
     157                 :          0 :     psResult->nStatus = 1;
     158                 :          0 :     psResult->pszErrBuf = CPLStrdup( blockingRequest.errorMessage().toUtf8() );
     159                 :          0 :     return psResult;
     160                 :            :   }
     161                 :            : 
     162                 :          0 :   QgsNetworkReplyContent reply( blockingRequest.reply() );
     163                 :            : 
     164                 :            :   // Store response headers
     165                 :          0 :   for ( const auto &pair : reply.rawHeaderPairs() )
     166                 :            :   {
     167                 :          0 :     if ( EQUAL( pair.first.toStdString().c_str(), "Content-Type" ) )
     168                 :            :     {
     169                 :          0 :       CPLFree( psResult->pszContentType );
     170                 :          0 :       psResult->pszContentType = CPLStrdup( pair.second.toStdString().c_str() );
     171                 :          0 :     }
     172                 :          0 :     psResult->papszHeaders = CSLAddNameValue(
     173                 :          0 :                                psResult->papszHeaders,
     174                 :          0 :                                pair.first.toStdString().c_str(),
     175                 :          0 :                                pair.second.toStdString().c_str() );
     176                 :            :   }
     177                 :            : 
     178                 :            :   // Process content
     179                 :          0 :   QByteArray content( reply.content() );
     180                 :            : 
     181                 :            :   // Poor-man implementation of the pfnWrite mechanism which is supposed to be
     182                 :            :   // called on the fly as bytes are received
     183                 :          0 :   if ( pfnWrite )
     184                 :            :   {
     185                 :          0 :     if ( static_cast<int>( pfnWrite( content.data(), 1, content.size(), pWriteArg ) ) != content.size() )
     186                 :            :     {
     187                 :          0 :       psResult->nStatus = 1;
     188                 :          0 :       psResult->pszErrBuf = CPLStrdup( "download interrupted by user" );
     189                 :          0 :       return psResult;
     190                 :            :     }
     191                 :          0 :   }
     192                 :            :   else
     193                 :            :   {
     194                 :          0 :     psResult->nDataLen = static_cast<int>( content.size() );
     195                 :          0 :     psResult->pabyData = static_cast<GByte *>( CPLMalloc( psResult->nDataLen + 1 ) );
     196                 :          0 :     memcpy( psResult->pabyData, content.constData(), psResult->nDataLen );
     197                 :          0 :     psResult->pabyData[psResult->nDataLen] = 0;
     198                 :            :   }
     199                 :            : 
     200                 :          0 :   return psResult;
     201                 :          0 : }
     202                 :            : 
     203                 :            : #endif
     204                 :            : 
     205                 :       3516 : void QgsCPLHTTPFetchOverrider::setAttribute( QNetworkRequest::Attribute code, const QVariant &value )
     206                 :            : {
     207                 :       3516 :   mAttributes[code] = value;
     208                 :       3516 : }

Generated by: LCOV version 1.14