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

Generated by: LCOV version 1.14