LCOV - code coverage report
Current view: top level - port - cpl_vsil_swift.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 251 282 89.0 %
Date: 2024-11-21 22:18:42 Functions: 19 23 82.6 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  CPL - Common Portability Library
       4             :  * Purpose:  Implement VSI large file api for OpenStack Swift
       5             :  * Author:   Even Rouault, even.rouault at spatialys.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2017-2018, Even Rouault <even.rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "cpl_json.h"
      14             : #include "cpl_port.h"
      15             : #include "cpl_http.h"
      16             : #include "cpl_time.h"
      17             : #include "cpl_vsil_curl_priv.h"
      18             : #include "cpl_vsil_curl_class.h"
      19             : 
      20             : #include <errno.h>
      21             : 
      22             : #include <algorithm>
      23             : #include <set>
      24             : #include <map>
      25             : #include <memory>
      26             : 
      27             : #include "cpl_swift.h"
      28             : 
      29             : #ifndef HAVE_CURL
      30             : 
      31             : void VSIInstallSwiftFileHandler(void)
      32             : {
      33             :     // Not supported
      34             : }
      35             : 
      36             : #else
      37             : 
      38             : //! @cond Doxygen_Suppress
      39             : #ifndef DOXYGEN_SKIP
      40             : 
      41             : #define ENABLE_DEBUG 0
      42             : 
      43             : #define unchecked_curl_easy_setopt(handle, opt, param)                         \
      44             :     CPL_IGNORE_RET_VAL(curl_easy_setopt(handle, opt, param))
      45             : 
      46             : namespace cpl
      47             : {
      48             : 
      49             : /************************************************************************/
      50             : /*                       AnalyseSwiftFileList()                         */
      51             : /************************************************************************/
      52             : 
      53          13 : void VSICurlFilesystemHandlerBase::AnalyseSwiftFileList(
      54             :     const std::string &osBaseURL, const std::string &osPrefix,
      55             :     const char *pszJson, CPLStringList &osFileList, int nMaxFilesThisQuery,
      56             :     int nMaxFiles, bool &bIsTruncated, std::string &osNextMarker)
      57             : {
      58             : #if DEBUG_VERBOSE
      59             :     CPLDebug("SWIFT", "%s", pszJson);
      60             : #endif
      61          13 :     osNextMarker = "";
      62          13 :     bIsTruncated = false;
      63             : 
      64          13 :     CPLJSONDocument oDoc;
      65          13 :     if (!oDoc.LoadMemory(reinterpret_cast<const GByte *>(pszJson)))
      66           0 :         return;
      67             : 
      68          26 :     std::vector<std::pair<std::string, FileProp>> aoProps;
      69             :     // Count the number of occurrences of a path. Can be 1 or 2. 2 in the case
      70             :     // that both a filename and directory exist
      71          26 :     std::map<std::string, int> aoNameCount;
      72             : 
      73          26 :     CPLJSONArray oArray = oDoc.GetRoot().ToArray();
      74          23 :     for (int i = 0; i < oArray.Size(); i++)
      75             :     {
      76          10 :         CPLJSONObject oItem = oArray[i];
      77          20 :         std::string osName = oItem.GetString("name");
      78          10 :         GInt64 nSize = oItem.GetLong("bytes");
      79          20 :         std::string osLastModified = oItem.GetString("last_modified");
      80          20 :         std::string osSubdir = oItem.GetString("subdir");
      81          10 :         bool bHasCount = oItem.GetLong("count", -1) >= 0;
      82          10 :         if (!osName.empty())
      83             :         {
      84           6 :             osNextMarker = osName;
      85          12 :             if (osName.size() > osPrefix.size() &&
      86          12 :                 osName.substr(0, osPrefix.size()) == osPrefix)
      87             :             {
      88           6 :                 if (bHasCount)
      89             :                 {
      90             :                     // Case when listing /vsiswift/
      91           2 :                     FileProp prop;
      92           2 :                     prop.eExists = EXIST_YES;
      93           2 :                     prop.bIsDirectory = true;
      94           2 :                     prop.bHasComputedFileSize = true;
      95           2 :                     prop.fileSize = 0;
      96           2 :                     prop.mTime = 0;
      97             : 
      98           2 :                     aoProps.push_back(
      99           4 :                         std::pair<std::string, FileProp>(osName, prop));
     100           2 :                     aoNameCount[osName]++;
     101             :                 }
     102             :                 else
     103             :                 {
     104           4 :                     FileProp prop;
     105           4 :                     prop.eExists = EXIST_YES;
     106           4 :                     prop.bHasComputedFileSize = true;
     107           4 :                     prop.fileSize = static_cast<GUIntBig>(nSize);
     108           4 :                     prop.bIsDirectory = false;
     109           4 :                     prop.mTime = 0;
     110             :                     int nYear, nMonth, nDay, nHour, nMin, nSec;
     111           4 :                     if (sscanf(osLastModified.c_str(),
     112             :                                "%04d-%02d-%02dT%02d:%02d:%02d", &nYear, &nMonth,
     113           4 :                                &nDay, &nHour, &nMin, &nSec) == 6)
     114             :                     {
     115             :                         struct tm brokendowntime;
     116           4 :                         brokendowntime.tm_year = nYear - 1900;
     117           4 :                         brokendowntime.tm_mon = nMonth - 1;
     118           4 :                         brokendowntime.tm_mday = nDay;
     119           4 :                         brokendowntime.tm_hour = nHour;
     120           4 :                         brokendowntime.tm_min = nMin;
     121           4 :                         brokendowntime.tm_sec = nSec;
     122           4 :                         prop.mTime = static_cast<time_t>(
     123           4 :                             CPLYMDHMSToUnixTime(&brokendowntime));
     124             :                     }
     125             : 
     126           4 :                     aoProps.push_back(std::pair<std::string, FileProp>(
     127           8 :                         osName.substr(osPrefix.size()), prop));
     128           4 :                     aoNameCount[osName.substr(osPrefix.size())]++;
     129             :                 }
     130             :             }
     131             :         }
     132           4 :         else if (!osSubdir.empty())
     133             :         {
     134           4 :             osNextMarker = osSubdir;
     135           4 :             if (osSubdir.back() == '/')
     136           4 :                 osSubdir.pop_back();
     137           4 :             if (STARTS_WITH(osSubdir.c_str(), osPrefix.c_str()))
     138             :             {
     139             : 
     140           4 :                 FileProp prop;
     141           4 :                 prop.eExists = EXIST_YES;
     142           4 :                 prop.bIsDirectory = true;
     143           4 :                 prop.bHasComputedFileSize = true;
     144           4 :                 prop.fileSize = 0;
     145           4 :                 prop.mTime = 0;
     146             : 
     147           4 :                 aoProps.push_back(std::pair<std::string, FileProp>(
     148           8 :                     osSubdir.substr(osPrefix.size()), prop));
     149           4 :                 aoNameCount[osSubdir.substr(osPrefix.size())]++;
     150             :             }
     151             :         }
     152             : 
     153          10 :         if (nMaxFiles > 0 && aoProps.size() > static_cast<unsigned>(nMaxFiles))
     154           0 :             break;
     155             :     }
     156             : 
     157          13 :     bIsTruncated = aoProps.size() >= static_cast<unsigned>(nMaxFilesThisQuery);
     158          13 :     if (!bIsTruncated)
     159             :     {
     160          11 :         osNextMarker.clear();
     161             :     }
     162             : 
     163          23 :     for (size_t i = 0; i < aoProps.size(); i++)
     164             :     {
     165          10 :         std::string osSuffix;
     166          12 :         if (aoNameCount[aoProps[i].first] == 2 &&
     167           2 :             aoProps[i].second.bIsDirectory)
     168             :         {
     169             :             // Add a / suffix to disambiguish the situation
     170             :             // Normally we don't suffix directories with /, but we have
     171             :             // no alternative here
     172           1 :             osSuffix = "/";
     173             :         }
     174          10 :         if (nMaxFiles != 1)
     175             :         {
     176             :             std::string osCachedFilename =
     177          20 :                 osBaseURL + "/" + CPLAWSURLEncode(osPrefix, false) +
     178          30 :                 CPLAWSURLEncode(aoProps[i].first, false) + osSuffix;
     179             : #if DEBUG_VERBOSE
     180             :             CPLDebug("SWIFT", "Cache %s", osCachedFilename.c_str());
     181             : #endif
     182          10 :             SetCachedFileProp(osCachedFilename.c_str(), aoProps[i].second);
     183             :         }
     184          10 :         osFileList.AddString((aoProps[i].first + osSuffix).c_str());
     185             :     }
     186             : }
     187             : 
     188             : /************************************************************************/
     189             : /*                         VSISwiftFSHandler                            */
     190             : /************************************************************************/
     191             : 
     192             : class VSISwiftFSHandler final : public IVSIS3LikeFSHandler
     193             : {
     194             :     const std::string m_osPrefix;
     195             :     CPL_DISALLOW_COPY_ASSIGN(VSISwiftFSHandler)
     196             : 
     197             :   protected:
     198             :     VSICurlHandle *CreateFileHandle(const char *pszFilename) override;
     199             :     std::string
     200             :     GetURLFromFilename(const std::string &osFilename) const override;
     201             : 
     202          28 :     const char *GetDebugKey() const override
     203             :     {
     204          28 :         return "SWIFT";
     205             :     }
     206             : 
     207             :     IVSIS3LikeHandleHelper *CreateHandleHelper(const char *pszURI,
     208             :                                                bool bAllowNoObject) override;
     209             : 
     210         407 :     std::string GetFSPrefix() const override
     211             :     {
     212         407 :         return m_osPrefix;
     213             :     }
     214             : 
     215             :     char **GetFileList(const char *pszFilename, int nMaxFiles,
     216             :                        bool *pbGotFileList) override;
     217             : 
     218             :     void ClearCache() override;
     219             : 
     220             :     VSIVirtualHandleUniquePtr
     221             :     CreateWriteHandle(const char *pszFilename,
     222             :                       CSLConstList papszOptions) override;
     223             : 
     224             :   public:
     225        1304 :     explicit VSISwiftFSHandler(const char *pszPrefix) : m_osPrefix(pszPrefix)
     226             :     {
     227        1304 :     }
     228             : 
     229             :     ~VSISwiftFSHandler() override;
     230             : 
     231             :     int Stat(const char *pszFilename, VSIStatBufL *pStatBuf,
     232             :              int nFlags) override;
     233             : 
     234           0 :     VSIDIR *OpenDir(const char *pszPath, int nRecurseDepth,
     235             :                     const char *const *papszOptions) override
     236             :     {
     237           0 :         return VSICurlFilesystemHandlerBase::OpenDir(pszPath, nRecurseDepth,
     238           0 :                                                      papszOptions);
     239             :     }
     240             : 
     241             :     const char *GetOptions() override;
     242             : 
     243             :     std::string
     244           0 :     GetStreamingFilename(const std::string &osFilename) const override
     245             :     {
     246           0 :         return osFilename;
     247             :     }
     248             : 
     249           0 :     VSIFilesystemHandler *Duplicate(const char *pszPrefix) override
     250             :     {
     251           0 :         return new VSISwiftFSHandler(pszPrefix);
     252             :     }
     253             : };
     254             : 
     255             : /************************************************************************/
     256             : /*                            VSISwiftHandle                              */
     257             : /************************************************************************/
     258             : 
     259             : class VSISwiftHandle final : public IVSIS3LikeHandle
     260             : {
     261             :     CPL_DISALLOW_COPY_ASSIGN(VSISwiftHandle)
     262             : 
     263             :     VSISwiftHandleHelper *m_poHandleHelper = nullptr;
     264             : 
     265             :   protected:
     266             :     struct curl_slist *
     267             :     GetCurlHeaders(const std::string &osVerb,
     268             :                    const struct curl_slist *psExistingHeaders) override;
     269             :     virtual bool Authenticate(const char *pszFilename) override;
     270             : 
     271             :   public:
     272             :     VSISwiftHandle(VSISwiftFSHandler *poFS, const char *pszFilename,
     273             :                    VSISwiftHandleHelper *poHandleHelper);
     274             :     ~VSISwiftHandle() override;
     275             : };
     276             : 
     277             : /************************************************************************/
     278             : /*                          CreateWriteHandle()                         */
     279             : /************************************************************************/
     280             : 
     281             : VSIVirtualHandleUniquePtr
     282           3 : VSISwiftFSHandler::CreateWriteHandle(const char *pszFilename,
     283             :                                      CSLConstList papszOptions)
     284             : {
     285             :     auto poHandleHelper =
     286           3 :         CreateHandleHelper(pszFilename + GetFSPrefix().size(), false);
     287           3 :     if (poHandleHelper == nullptr)
     288           0 :         return nullptr;
     289             :     auto poHandle = std::make_unique<VSIChunkedWriteHandle>(
     290           6 :         this, pszFilename, poHandleHelper, papszOptions);
     291           3 :     return VSIVirtualHandleUniquePtr(poHandle.release());
     292             : }
     293             : 
     294             : /************************************************************************/
     295             : /*                       ~VSISwiftFSHandler()                           */
     296             : /************************************************************************/
     297             : 
     298        1866 : VSISwiftFSHandler::~VSISwiftFSHandler()
     299             : {
     300         933 :     VSISwiftFSHandler::ClearCache();
     301         933 :     VSISwiftHandleHelper::CleanMutex();
     302        1866 : }
     303             : 
     304             : /************************************************************************/
     305             : /*                            ClearCache()                              */
     306             : /************************************************************************/
     307             : 
     308        1232 : void VSISwiftFSHandler::ClearCache()
     309             : {
     310        1232 :     VSICurlFilesystemHandlerBase::ClearCache();
     311             : 
     312        1232 :     VSISwiftHandleHelper::ClearCache();
     313        1232 : }
     314             : 
     315             : /************************************************************************/
     316             : /*                           GetOptions()                               */
     317             : /************************************************************************/
     318             : 
     319           2 : const char *VSISwiftFSHandler::GetOptions()
     320             : {
     321             :     static std::string osOptions(
     322           2 :         std::string("<Options>") +
     323             :         "  <Option name='SWIFT_STORAGE_URL' type='string' "
     324             :         "description='Storage URL. To use with SWIFT_AUTH_TOKEN'/>"
     325             :         "  <Option name='SWIFT_AUTH_TOKEN' type='string' "
     326             :         "description='Authorization token'/>"
     327             :         "  <Option name='SWIFT_AUTH_V1_URL' type='string' "
     328             :         "description='Authentication V1 URL. To use with SWIFT_USER and "
     329             :         "SWIFT_KEY'/>"
     330             :         "  <Option name='SWIFT_USER' type='string' "
     331             :         "description='User name to use with authentication V1'/>"
     332             :         "  <Option name='SWIFT_KEY' type='string' "
     333             :         "description='Key/password to use with authentication V1'/>"
     334             :         "  <Option name='OS_IDENTITY_API_VERSION' type='string' "
     335             :         "description='OpenStack identity API version'/>"
     336             :         "  <Option name='OS_AUTH_TYPE' type='string' "
     337             :         "description='Authentication URL'/>"
     338             :         "  <Option name='OS_USERNAME' type='string' "
     339             :         "description='User name'/>"
     340             :         "  <Option name='OS_PASSWORD' type='string' "
     341             :         "description='Password'/>"
     342             :         "  <Option name='OS_USER_DOMAIN_NAME' type='string' "
     343             :         "description='User domain name'/>"
     344             :         "  <Option name='OS_PROJECT_NAME' type='string' "
     345             :         "description='Project name'/>"
     346             :         "  <Option name='OS_PROJECT_DOMAIN_NAME' type='string' "
     347             :         "description='Project domain name'/>"
     348             :         "  <Option name='OS_REGION_NAME' type='string' "
     349           3 :         "description='Region name'/>" +
     350           3 :         VSICurlFilesystemHandlerBase::GetOptionsStatic() + "</Options>");
     351           2 :     return osOptions.c_str();
     352             : }
     353             : 
     354             : /************************************************************************/
     355             : /*                          CreateFileHandle()                          */
     356             : /************************************************************************/
     357             : 
     358          21 : VSICurlHandle *VSISwiftFSHandler::CreateFileHandle(const char *pszFilename)
     359             : {
     360          42 :     VSISwiftHandleHelper *poHandleHelper = VSISwiftHandleHelper::BuildFromURI(
     361          63 :         pszFilename + GetFSPrefix().size(), GetFSPrefix().c_str());
     362          21 :     if (poHandleHelper)
     363             :     {
     364          19 :         return new VSISwiftHandle(this, pszFilename, poHandleHelper);
     365             :     }
     366           2 :     return nullptr;
     367             : }
     368             : 
     369             : /************************************************************************/
     370             : /*                         GetURLFromFilename()                         */
     371             : /************************************************************************/
     372             : 
     373             : std::string
     374          21 : VSISwiftFSHandler::GetURLFromFilename(const std::string &osFilename) const
     375             : {
     376             :     const std::string osFilenameWithoutPrefix =
     377          42 :         osFilename.substr(GetFSPrefix().size());
     378             : 
     379             :     auto poHandleHelper = std::unique_ptr<VSISwiftHandleHelper>(
     380             :         VSISwiftHandleHelper::BuildFromURI(osFilenameWithoutPrefix.c_str(),
     381          42 :                                            GetFSPrefix().c_str()));
     382          21 :     if (!poHandleHelper)
     383             :     {
     384           0 :         return std::string();
     385             :     }
     386          42 :     std::string osBaseURL(poHandleHelper->GetURL());
     387          21 :     if (!osBaseURL.empty() && osBaseURL.back() == '/')
     388           2 :         osBaseURL.pop_back();
     389          21 :     return osBaseURL;
     390             : }
     391             : 
     392             : /************************************************************************/
     393             : /*                          CreateHandleHelper()                        */
     394             : /************************************************************************/
     395             : 
     396             : IVSIS3LikeHandleHelper *
     397          26 : VSISwiftFSHandler::CreateHandleHelper(const char *pszURI, bool)
     398             : {
     399          26 :     return VSISwiftHandleHelper::BuildFromURI(pszURI, GetFSPrefix().c_str());
     400             : }
     401             : 
     402             : /************************************************************************/
     403             : /*                                Stat()                                */
     404             : /************************************************************************/
     405             : 
     406          13 : int VSISwiftFSHandler::Stat(const char *pszFilename, VSIStatBufL *pStatBuf,
     407             :                             int nFlags)
     408             : {
     409          13 :     if (!STARTS_WITH_CI(pszFilename, GetFSPrefix().c_str()))
     410           0 :         return -1;
     411             : 
     412          13 :     if ((nFlags & VSI_STAT_CACHE_ONLY) != 0)
     413           2 :         return VSICurlFilesystemHandlerBase::Stat(pszFilename, pStatBuf,
     414           2 :                                                   nFlags);
     415             : 
     416          22 :     std::string osFilename(pszFilename);
     417          11 :     if (osFilename.back() == '/')
     418           6 :         osFilename.pop_back();
     419             : 
     420          11 :     memset(pStatBuf, 0, sizeof(VSIStatBufL));
     421             : 
     422          11 :     if (VSICurlFilesystemHandlerBase::Stat(pszFilename, pStatBuf, nFlags) == 0)
     423             :     {
     424             :         // if querying /vsiswift/container_name, the GET will succeed and
     425             :         // we would consider this as a file whereas it should be exposed as
     426             :         // a directory
     427           6 :         if (std::count(osFilename.begin(), osFilename.end(), '/') <= 2)
     428             :         {
     429             : 
     430             :             auto poHandleHelper = std::unique_ptr<IVSIS3LikeHandleHelper>(
     431           1 :                 CreateHandleHelper(pszFilename + GetFSPrefix().size(), true));
     432           1 :             if (poHandleHelper)
     433             :             {
     434           2 :                 FileProp cachedFileProp;
     435           1 :                 cachedFileProp.eExists = EXIST_YES;
     436           1 :                 cachedFileProp.bHasComputedFileSize = false;
     437           1 :                 cachedFileProp.fileSize = 0;
     438           1 :                 cachedFileProp.bIsDirectory = true;
     439           1 :                 cachedFileProp.mTime = 0;
     440           1 :                 cachedFileProp.nMode = S_IFDIR;
     441           1 :                 SetCachedFileProp(poHandleHelper->GetURL().c_str(),
     442             :                                   cachedFileProp);
     443             :             }
     444             : 
     445           1 :             pStatBuf->st_size = 0;
     446           1 :             pStatBuf->st_mode = S_IFDIR;
     447             :         }
     448           6 :         return 0;
     449             :     }
     450             : 
     451             :     // In the case of a directory, a GET on it will not work, so we have to
     452             :     // query the upper directory contents
     453           5 :     if (std::count(osFilename.begin(), osFilename.end(), '/') < 2)
     454           0 :         return -1;
     455             : 
     456           5 :     char **papszContents = VSIReadDir(CPLGetPath(osFilename.c_str()));
     457           5 :     int nRet = CSLFindStringCaseSensitive(
     458             :                    papszContents, CPLGetFilename(osFilename.c_str())) >= 0
     459           5 :                    ? 0
     460           5 :                    : -1;
     461           5 :     CSLDestroy(papszContents);
     462             : 
     463          10 :     FileProp cachedFileProp;
     464           5 :     if (nRet == 0)
     465             :     {
     466           2 :         pStatBuf->st_mode = S_IFDIR;
     467             : 
     468           2 :         cachedFileProp.eExists = EXIST_YES;
     469           2 :         cachedFileProp.bHasComputedFileSize = false;
     470           2 :         cachedFileProp.fileSize = 0;
     471           2 :         cachedFileProp.bIsDirectory = true;
     472           2 :         cachedFileProp.mTime = 0;
     473           2 :         cachedFileProp.nMode = S_IFDIR;
     474             :     }
     475             :     else
     476             :     {
     477           3 :         cachedFileProp.eExists = EXIST_NO;
     478             :     }
     479             : 
     480             :     auto poHandleHelper = std::unique_ptr<IVSIS3LikeHandleHelper>(
     481           5 :         CreateHandleHelper(pszFilename + GetFSPrefix().size(), true));
     482           5 :     if (poHandleHelper)
     483             :     {
     484           5 :         SetCachedFileProp(poHandleHelper->GetURL().c_str(), cachedFileProp);
     485             :     }
     486             : 
     487           5 :     return nRet;
     488             : }
     489             : 
     490             : /************************************************************************/
     491             : /*                           GetFileList()                              */
     492             : /************************************************************************/
     493             : 
     494          14 : char **VSISwiftFSHandler::GetFileList(const char *pszDirname, int nMaxFiles,
     495             :                                       bool *pbGotFileList)
     496             : {
     497             :     if (ENABLE_DEBUG)
     498             :         CPLDebug(GetDebugKey(), "GetFileList(%s)", pszDirname);
     499          14 :     *pbGotFileList = false;
     500          14 :     CPLAssert(strlen(pszDirname) >= GetFSPrefix().size());
     501          42 :     std::string osDirnameWithoutPrefix = pszDirname + GetFSPrefix().size();
     502          14 :     if (!osDirnameWithoutPrefix.empty() && osDirnameWithoutPrefix.back() == '/')
     503             :     {
     504           0 :         osDirnameWithoutPrefix.pop_back();
     505             :     }
     506             : 
     507          28 :     std::string osBucket(osDirnameWithoutPrefix);
     508          28 :     std::string osObjectKey;
     509          14 :     size_t nSlashPos = osDirnameWithoutPrefix.find('/');
     510          14 :     if (nSlashPos != std::string::npos)
     511             :     {
     512           3 :         osBucket = osDirnameWithoutPrefix.substr(0, nSlashPos);
     513           3 :         osObjectKey = osDirnameWithoutPrefix.substr(nSlashPos + 1);
     514             :     }
     515             : 
     516             :     IVSIS3LikeHandleHelper *poS3HandleHelper =
     517          14 :         CreateHandleHelper(osBucket.c_str(), true);
     518          14 :     if (poS3HandleHelper == nullptr)
     519             :     {
     520           0 :         return nullptr;
     521             :     }
     522             : 
     523          14 :     WriteFuncStruct sWriteFuncData;
     524             : 
     525          28 :     CPLStringList osFileList;  // must be left in this scope !
     526          28 :     std::string osNextMarker;  // must be left in this scope !
     527             : 
     528          28 :     std::string osMaxKeys = CPLGetConfigOption("SWIFT_MAX_KEYS", "10000");
     529          14 :     int nMaxFilesThisQuery = atoi(osMaxKeys.c_str());
     530          14 :     if (nMaxFiles > 0 && nMaxFiles <= 100 && nMaxFiles < nMaxFilesThisQuery)
     531             :     {
     532           2 :         nMaxFilesThisQuery = nMaxFiles + 1;
     533             :     }
     534          14 :     const std::string osPrefix(osObjectKey.empty() ? std::string()
     535          28 :                                                    : osObjectKey + "/");
     536             : 
     537          28 :     const CPLStringList aosHTTPOptions(CPLHTTPGetOptionsFromEnv(pszDirname));
     538          28 :     const CPLHTTPRetryParameters oRetryParameters(aosHTTPOptions);
     539             : 
     540             :     while (true)
     541             :     {
     542          16 :         CPLHTTPRetryContext oRetryContext(oRetryParameters);
     543             :         bool bRetry;
     544           2 :         do
     545             :         {
     546          16 :             bRetry = false;
     547          16 :             poS3HandleHelper->ResetQueryParameters();
     548          16 :             std::string osBaseURL(poS3HandleHelper->GetURL());
     549             : 
     550          16 :             CURLM *hCurlMultiHandle = GetCurlMultiHandleFor(osBaseURL);
     551          16 :             CURL *hCurlHandle = curl_easy_init();
     552             : 
     553          16 :             if (!osBucket.empty())
     554             :             {
     555          13 :                 poS3HandleHelper->AddQueryParameter("delimiter", "/");
     556          13 :                 if (!osNextMarker.empty())
     557           2 :                     poS3HandleHelper->AddQueryParameter("marker", osNextMarker);
     558          13 :                 poS3HandleHelper->AddQueryParameter(
     559             :                     "limit", CPLSPrintf("%d", nMaxFilesThisQuery));
     560          13 :                 if (!osPrefix.empty())
     561           3 :                     poS3HandleHelper->AddQueryParameter("prefix", osPrefix);
     562             :             }
     563             : 
     564          16 :             struct curl_slist *headers = VSICurlSetOptions(
     565          16 :                 hCurlHandle, poS3HandleHelper->GetURL().c_str(), nullptr);
     566             :             // Disable automatic redirection
     567          16 :             unchecked_curl_easy_setopt(hCurlHandle, CURLOPT_FOLLOWLOCATION, 0);
     568             : 
     569          16 :             unchecked_curl_easy_setopt(hCurlHandle, CURLOPT_RANGE, nullptr);
     570             : 
     571          16 :             VSICURLInitWriteFuncStruct(&sWriteFuncData, nullptr, nullptr,
     572             :                                        nullptr);
     573          16 :             unchecked_curl_easy_setopt(hCurlHandle, CURLOPT_WRITEDATA,
     574             :                                        &sWriteFuncData);
     575          16 :             unchecked_curl_easy_setopt(hCurlHandle, CURLOPT_WRITEFUNCTION,
     576             :                                        VSICurlHandleWriteFunc);
     577             : 
     578          16 :             WriteFuncStruct sWriteFuncHeaderData;
     579          16 :             VSICURLInitWriteFuncStruct(&sWriteFuncHeaderData, nullptr, nullptr,
     580             :                                        nullptr);
     581          16 :             unchecked_curl_easy_setopt(hCurlHandle, CURLOPT_HEADERDATA,
     582             :                                        &sWriteFuncHeaderData);
     583          16 :             unchecked_curl_easy_setopt(hCurlHandle, CURLOPT_HEADERFUNCTION,
     584             :                                        VSICurlHandleWriteFunc);
     585             : 
     586          16 :             char szCurlErrBuf[CURL_ERROR_SIZE + 1] = {};
     587          16 :             unchecked_curl_easy_setopt(hCurlHandle, CURLOPT_ERRORBUFFER,
     588             :                                        szCurlErrBuf);
     589             : 
     590          16 :             headers = VSICurlMergeHeaders(
     591          16 :                 headers, poS3HandleHelper->GetCurlHeaders("GET", headers));
     592          16 :             unchecked_curl_easy_setopt(hCurlHandle, CURLOPT_HTTPHEADER,
     593             :                                        headers);
     594             : 
     595          16 :             VSICURLMultiPerform(hCurlMultiHandle, hCurlHandle);
     596             : 
     597          16 :             VSICURLResetHeaderAndWriterFunctions(hCurlHandle);
     598             : 
     599          16 :             if (headers != nullptr)
     600          16 :                 curl_slist_free_all(headers);
     601             : 
     602          16 :             if (sWriteFuncData.pBuffer == nullptr)
     603             :             {
     604           3 :                 delete poS3HandleHelper;
     605           3 :                 curl_easy_cleanup(hCurlHandle);
     606           3 :                 CPLFree(sWriteFuncHeaderData.pBuffer);
     607           3 :                 return nullptr;
     608             :             }
     609             : 
     610          13 :             long response_code = 0;
     611          13 :             curl_easy_getinfo(hCurlHandle, CURLINFO_HTTP_CODE, &response_code);
     612          13 :             if (response_code != 200)
     613             :             {
     614             :                 // Look if we should attempt a retry
     615           0 :                 if (oRetryContext.CanRetry(static_cast<int>(response_code),
     616           0 :                                            sWriteFuncHeaderData.pBuffer,
     617             :                                            szCurlErrBuf))
     618             :                 {
     619           0 :                     CPLError(CE_Warning, CPLE_AppDefined,
     620             :                              "HTTP error code: %d - %s. "
     621             :                              "Retrying again in %.1f secs",
     622             :                              static_cast<int>(response_code),
     623           0 :                              poS3HandleHelper->GetURL().c_str(),
     624             :                              oRetryContext.GetCurrentDelay());
     625           0 :                     CPLSleep(oRetryContext.GetCurrentDelay());
     626           0 :                     bRetry = true;
     627           0 :                     CPLFree(sWriteFuncData.pBuffer);
     628           0 :                     CPLFree(sWriteFuncHeaderData.pBuffer);
     629             :                 }
     630             :                 else
     631             :                 {
     632           0 :                     CPLDebug(GetDebugKey(), "%s", sWriteFuncData.pBuffer);
     633           0 :                     CPLFree(sWriteFuncData.pBuffer);
     634           0 :                     CPLFree(sWriteFuncHeaderData.pBuffer);
     635           0 :                     delete poS3HandleHelper;
     636           0 :                     curl_easy_cleanup(hCurlHandle);
     637           0 :                     return nullptr;
     638             :                 }
     639             :             }
     640             :             else
     641             :             {
     642          13 :                 *pbGotFileList = true;
     643             :                 bool bIsTruncated;
     644          13 :                 AnalyseSwiftFileList(
     645          13 :                     osBaseURL, osPrefix, sWriteFuncData.pBuffer, osFileList,
     646             :                     nMaxFilesThisQuery, nMaxFiles, bIsTruncated, osNextMarker);
     647             : 
     648          13 :                 CPLFree(sWriteFuncData.pBuffer);
     649          13 :                 CPLFree(sWriteFuncHeaderData.pBuffer);
     650             : 
     651          13 :                 if (osNextMarker.empty())
     652             :                 {
     653          11 :                     delete poS3HandleHelper;
     654          11 :                     curl_easy_cleanup(hCurlHandle);
     655          11 :                     return osFileList.StealList();
     656             :                 }
     657             :             }
     658             : 
     659           2 :             curl_easy_cleanup(hCurlHandle);
     660             :         } while (bRetry);
     661           2 :     }
     662             : }
     663             : 
     664             : /************************************************************************/
     665             : /*                            VSISwiftHandle()                            */
     666             : /************************************************************************/
     667             : 
     668          19 : VSISwiftHandle::VSISwiftHandle(VSISwiftFSHandler *poFSIn,
     669             :                                const char *pszFilename,
     670          19 :                                VSISwiftHandleHelper *poHandleHelper)
     671          19 :     : IVSIS3LikeHandle(poFSIn, pszFilename, poHandleHelper->GetURL().c_str()),
     672          19 :       m_poHandleHelper(poHandleHelper)
     673             : {
     674          19 : }
     675             : 
     676             : /************************************************************************/
     677             : /*                            ~VSISwiftHandle()                           */
     678             : /************************************************************************/
     679             : 
     680          38 : VSISwiftHandle::~VSISwiftHandle()
     681             : {
     682          19 :     delete m_poHandleHelper;
     683          38 : }
     684             : 
     685             : /************************************************************************/
     686             : /*                           GetCurlHeaders()                           */
     687             : /************************************************************************/
     688             : 
     689             : struct curl_slist *
     690          17 : VSISwiftHandle::GetCurlHeaders(const std::string &osVerb,
     691             :                                const struct curl_slist *psExistingHeaders)
     692             : {
     693          17 :     return m_poHandleHelper->GetCurlHeaders(osVerb, psExistingHeaders);
     694             : }
     695             : 
     696             : /************************************************************************/
     697             : /*                           Authenticate()                             */
     698             : /************************************************************************/
     699             : 
     700           0 : bool VSISwiftHandle::Authenticate(const char *pszFilename)
     701             : {
     702           0 :     return m_poHandleHelper->Authenticate(pszFilename);
     703             : }
     704             : 
     705             : } /* end of namespace cpl */
     706             : 
     707             : #endif  // DOXYGEN_SKIP
     708             : //! @endcond
     709             : 
     710             : /************************************************************************/
     711             : /*                     VSIInstallSwiftFileHandler()                     */
     712             : /************************************************************************/
     713             : 
     714             : /*!
     715             :  \brief Install /vsiswift/ OpenStack Swif Object Storage (Swift) file
     716             :  system handler (requires libcurl)
     717             : 
     718             :  \verbatim embed:rst
     719             :  See :ref:`/vsiswift/ documentation <vsiswift>`
     720             :  \endverbatim
     721             : 
     722             :  @since GDAL 2.3
     723             :  */
     724        1304 : void VSIInstallSwiftFileHandler(void)
     725             : {
     726        1304 :     VSIFileManager::InstallHandler("/vsiswift/",
     727        1304 :                                    new cpl::VSISwiftFSHandler("/vsiswift/"));
     728        1304 : }
     729             : 
     730             : #endif /* HAVE_CURL */

Generated by: LCOV version 1.14