LCOV - code coverage report
Current view: top level - port - cpl_vsil_swift.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 250 281 89.0 %
Date: 2025-08-01 10:10:57 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        1691 :     explicit VSISwiftFSHandler(const char *pszPrefix) : m_osPrefix(pszPrefix)
     226             :     {
     227        1691 :     }
     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 *GetCurlHeaders(const std::string &osVerb,
     267             :                                       struct curl_slist *psHeaders) override;
     268             :     virtual bool Authenticate(const char *pszFilename) override;
     269             : 
     270             :   public:
     271             :     VSISwiftHandle(VSISwiftFSHandler *poFS, const char *pszFilename,
     272             :                    VSISwiftHandleHelper *poHandleHelper);
     273             :     ~VSISwiftHandle() override;
     274             : };
     275             : 
     276             : /************************************************************************/
     277             : /*                          CreateWriteHandle()                         */
     278             : /************************************************************************/
     279             : 
     280             : VSIVirtualHandleUniquePtr
     281           3 : VSISwiftFSHandler::CreateWriteHandle(const char *pszFilename,
     282             :                                      CSLConstList papszOptions)
     283             : {
     284             :     auto poHandleHelper =
     285           3 :         CreateHandleHelper(pszFilename + GetFSPrefix().size(), false);
     286           3 :     if (poHandleHelper == nullptr)
     287           0 :         return nullptr;
     288             :     auto poHandle = std::make_unique<VSIChunkedWriteHandle>(
     289           6 :         this, pszFilename, poHandleHelper, papszOptions);
     290           3 :     return VSIVirtualHandleUniquePtr(poHandle.release());
     291             : }
     292             : 
     293             : /************************************************************************/
     294             : /*                       ~VSISwiftFSHandler()                           */
     295             : /************************************************************************/
     296             : 
     297        2244 : VSISwiftFSHandler::~VSISwiftFSHandler()
     298             : {
     299        1122 :     VSISwiftFSHandler::ClearCache();
     300        1122 :     VSISwiftHandleHelper::CleanMutex();
     301        2244 : }
     302             : 
     303             : /************************************************************************/
     304             : /*                            ClearCache()                              */
     305             : /************************************************************************/
     306             : 
     307        1453 : void VSISwiftFSHandler::ClearCache()
     308             : {
     309        1453 :     VSICurlFilesystemHandlerBase::ClearCache();
     310             : 
     311        1453 :     VSISwiftHandleHelper::ClearCache();
     312        1453 : }
     313             : 
     314             : /************************************************************************/
     315             : /*                           GetOptions()                               */
     316             : /************************************************************************/
     317             : 
     318           2 : const char *VSISwiftFSHandler::GetOptions()
     319             : {
     320             :     static std::string osOptions(
     321           2 :         std::string("<Options>") +
     322             :         "  <Option name='SWIFT_STORAGE_URL' type='string' "
     323             :         "description='Storage URL. To use with SWIFT_AUTH_TOKEN'/>"
     324             :         "  <Option name='SWIFT_AUTH_TOKEN' type='string' "
     325             :         "description='Authorization token'/>"
     326             :         "  <Option name='SWIFT_AUTH_V1_URL' type='string' "
     327             :         "description='Authentication V1 URL. To use with SWIFT_USER and "
     328             :         "SWIFT_KEY'/>"
     329             :         "  <Option name='SWIFT_USER' type='string' "
     330             :         "description='User name to use with authentication V1'/>"
     331             :         "  <Option name='SWIFT_KEY' type='string' "
     332             :         "description='Key/password to use with authentication V1'/>"
     333             :         "  <Option name='OS_IDENTITY_API_VERSION' type='string' "
     334             :         "description='OpenStack identity API version'/>"
     335             :         "  <Option name='OS_AUTH_TYPE' type='string' "
     336             :         "description='Authentication URL'/>"
     337             :         "  <Option name='OS_USERNAME' type='string' "
     338             :         "description='User name'/>"
     339             :         "  <Option name='OS_PASSWORD' type='string' "
     340             :         "description='Password'/>"
     341             :         "  <Option name='OS_USER_DOMAIN_NAME' type='string' "
     342             :         "description='User domain name'/>"
     343             :         "  <Option name='OS_PROJECT_NAME' type='string' "
     344             :         "description='Project name'/>"
     345             :         "  <Option name='OS_PROJECT_DOMAIN_NAME' type='string' "
     346             :         "description='Project domain name'/>"
     347             :         "  <Option name='OS_REGION_NAME' type='string' "
     348           3 :         "description='Region name'/>" +
     349           3 :         VSICurlFilesystemHandlerBase::GetOptionsStatic() + "</Options>");
     350           2 :     return osOptions.c_str();
     351             : }
     352             : 
     353             : /************************************************************************/
     354             : /*                          CreateFileHandle()                          */
     355             : /************************************************************************/
     356             : 
     357          21 : VSICurlHandle *VSISwiftFSHandler::CreateFileHandle(const char *pszFilename)
     358             : {
     359          42 :     VSISwiftHandleHelper *poHandleHelper = VSISwiftHandleHelper::BuildFromURI(
     360          63 :         pszFilename + GetFSPrefix().size(), GetFSPrefix().c_str());
     361          21 :     if (poHandleHelper)
     362             :     {
     363          19 :         return new VSISwiftHandle(this, pszFilename, poHandleHelper);
     364             :     }
     365           2 :     return nullptr;
     366             : }
     367             : 
     368             : /************************************************************************/
     369             : /*                         GetURLFromFilename()                         */
     370             : /************************************************************************/
     371             : 
     372             : std::string
     373          21 : VSISwiftFSHandler::GetURLFromFilename(const std::string &osFilename) const
     374             : {
     375             :     const std::string osFilenameWithoutPrefix =
     376          42 :         osFilename.substr(GetFSPrefix().size());
     377             : 
     378             :     auto poHandleHelper = std::unique_ptr<VSISwiftHandleHelper>(
     379             :         VSISwiftHandleHelper::BuildFromURI(osFilenameWithoutPrefix.c_str(),
     380          42 :                                            GetFSPrefix().c_str()));
     381          21 :     if (!poHandleHelper)
     382             :     {
     383           0 :         return std::string();
     384             :     }
     385          42 :     std::string osBaseURL(poHandleHelper->GetURL());
     386          21 :     if (!osBaseURL.empty() && osBaseURL.back() == '/')
     387           2 :         osBaseURL.pop_back();
     388          21 :     return osBaseURL;
     389             : }
     390             : 
     391             : /************************************************************************/
     392             : /*                          CreateHandleHelper()                        */
     393             : /************************************************************************/
     394             : 
     395             : IVSIS3LikeHandleHelper *
     396          26 : VSISwiftFSHandler::CreateHandleHelper(const char *pszURI, bool)
     397             : {
     398          26 :     return VSISwiftHandleHelper::BuildFromURI(pszURI, GetFSPrefix().c_str());
     399             : }
     400             : 
     401             : /************************************************************************/
     402             : /*                                Stat()                                */
     403             : /************************************************************************/
     404             : 
     405          13 : int VSISwiftFSHandler::Stat(const char *pszFilename, VSIStatBufL *pStatBuf,
     406             :                             int nFlags)
     407             : {
     408          13 :     if (!STARTS_WITH_CI(pszFilename, GetFSPrefix().c_str()))
     409           0 :         return -1;
     410             : 
     411          13 :     if ((nFlags & VSI_STAT_CACHE_ONLY) != 0)
     412           2 :         return VSICurlFilesystemHandlerBase::Stat(pszFilename, pStatBuf,
     413           2 :                                                   nFlags);
     414             : 
     415          22 :     std::string osFilename(pszFilename);
     416          11 :     if (osFilename.back() == '/')
     417           6 :         osFilename.pop_back();
     418             : 
     419          11 :     memset(pStatBuf, 0, sizeof(VSIStatBufL));
     420             : 
     421          11 :     if (VSICurlFilesystemHandlerBase::Stat(pszFilename, pStatBuf, nFlags) == 0)
     422             :     {
     423             :         // if querying /vsiswift/container_name, the GET will succeed and
     424             :         // we would consider this as a file whereas it should be exposed as
     425             :         // a directory
     426           6 :         if (std::count(osFilename.begin(), osFilename.end(), '/') <= 2)
     427             :         {
     428             : 
     429             :             auto poHandleHelper = std::unique_ptr<IVSIS3LikeHandleHelper>(
     430           1 :                 CreateHandleHelper(pszFilename + GetFSPrefix().size(), true));
     431           1 :             if (poHandleHelper)
     432             :             {
     433           2 :                 FileProp cachedFileProp;
     434           1 :                 cachedFileProp.eExists = EXIST_YES;
     435           1 :                 cachedFileProp.bHasComputedFileSize = false;
     436           1 :                 cachedFileProp.fileSize = 0;
     437           1 :                 cachedFileProp.bIsDirectory = true;
     438           1 :                 cachedFileProp.mTime = 0;
     439           1 :                 cachedFileProp.nMode = S_IFDIR;
     440           1 :                 SetCachedFileProp(poHandleHelper->GetURL().c_str(),
     441             :                                   cachedFileProp);
     442             :             }
     443             : 
     444           1 :             pStatBuf->st_size = 0;
     445           1 :             pStatBuf->st_mode = S_IFDIR;
     446             :         }
     447           6 :         return 0;
     448             :     }
     449             : 
     450             :     // In the case of a directory, a GET on it will not work, so we have to
     451             :     // query the upper directory contents
     452           5 :     if (std::count(osFilename.begin(), osFilename.end(), '/') < 2)
     453           0 :         return -1;
     454             : 
     455             :     char **papszContents =
     456           5 :         VSIReadDir(CPLGetPathSafe(osFilename.c_str()).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          32 :             struct curl_slist *headers = VSICurlSetOptions(
     565          16 :                 hCurlHandle, poS3HandleHelper->GetURL().c_str(),
     566             :                 aosHTTPOptions.List());
     567             :             // Disable automatic redirection
     568          16 :             unchecked_curl_easy_setopt(hCurlHandle, CURLOPT_FOLLOWLOCATION, 0);
     569             : 
     570          16 :             unchecked_curl_easy_setopt(hCurlHandle, CURLOPT_RANGE, nullptr);
     571             : 
     572          16 :             VSICURLInitWriteFuncStruct(&sWriteFuncData, nullptr, nullptr,
     573             :                                        nullptr);
     574          16 :             unchecked_curl_easy_setopt(hCurlHandle, CURLOPT_WRITEDATA,
     575             :                                        &sWriteFuncData);
     576          16 :             unchecked_curl_easy_setopt(hCurlHandle, CURLOPT_WRITEFUNCTION,
     577             :                                        VSICurlHandleWriteFunc);
     578             : 
     579          16 :             WriteFuncStruct sWriteFuncHeaderData;
     580          16 :             VSICURLInitWriteFuncStruct(&sWriteFuncHeaderData, nullptr, nullptr,
     581             :                                        nullptr);
     582          16 :             unchecked_curl_easy_setopt(hCurlHandle, CURLOPT_HEADERDATA,
     583             :                                        &sWriteFuncHeaderData);
     584          16 :             unchecked_curl_easy_setopt(hCurlHandle, CURLOPT_HEADERFUNCTION,
     585             :                                        VSICurlHandleWriteFunc);
     586             : 
     587          16 :             char szCurlErrBuf[CURL_ERROR_SIZE + 1] = {};
     588          16 :             unchecked_curl_easy_setopt(hCurlHandle, CURLOPT_ERRORBUFFER,
     589             :                                        szCurlErrBuf);
     590             : 
     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          17 : struct curl_slist *VSISwiftHandle::GetCurlHeaders(const std::string &osVerb,
     690             :                                                   struct curl_slist *psHeaders)
     691             : {
     692          17 :     return m_poHandleHelper->GetCurlHeaders(osVerb, psHeaders);
     693             : }
     694             : 
     695             : /************************************************************************/
     696             : /*                           Authenticate()                             */
     697             : /************************************************************************/
     698             : 
     699           0 : bool VSISwiftHandle::Authenticate(const char *pszFilename)
     700             : {
     701           0 :     return m_poHandleHelper->Authenticate(pszFilename);
     702             : }
     703             : 
     704             : } /* end of namespace cpl */
     705             : 
     706             : #endif  // DOXYGEN_SKIP
     707             : //! @endcond
     708             : 
     709             : /************************************************************************/
     710             : /*                     VSIInstallSwiftFileHandler()                     */
     711             : /************************************************************************/
     712             : 
     713             : /*!
     714             :  \brief Install /vsiswift/ OpenStack Swif Object Storage (Swift) file
     715             :  system handler (requires libcurl)
     716             : 
     717             :  \verbatim embed:rst
     718             :  See :ref:`/vsiswift/ documentation <vsiswift>`
     719             :  \endverbatim
     720             : 
     721             :  @since GDAL 2.3
     722             :  */
     723        1691 : void VSIInstallSwiftFileHandler(void)
     724             : {
     725        1691 :     VSIFileManager::InstallHandler("/vsiswift/",
     726        1691 :                                    new cpl::VSISwiftFSHandler("/vsiswift/"));
     727        1691 : }
     728             : 
     729             : #endif /* HAVE_CURL */

Generated by: LCOV version 1.14