LCOV - code coverage report
Current view: top level - port - cpl_vsil_curl_class.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 124 158 78.5 %
Date: 2025-08-01 10:10:57 Functions: 54 70 77.1 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  CPL - Common Portability Library
       4             :  * Purpose:  Declarations for /vsicurl/ and related file systems
       5             :  * Author:   Even Rouault, even.rouault at spatialys.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2010-2018, Even Rouault <even.rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #ifndef CPL_VSIL_CURL_CLASS_H_INCLUDED
      14             : #define CPL_VSIL_CURL_CLASS_H_INCLUDED
      15             : 
      16             : #ifdef HAVE_CURL
      17             : 
      18             : #include "cpl_aws.h"
      19             : #include "cpl_azure.h"
      20             : #include "cpl_port.h"
      21             : #include "cpl_json.h"
      22             : #include "cpl_http.h"
      23             : #include "cpl_string.h"
      24             : #include "cpl_vsil_curl_priv.h"
      25             : #include "cpl_mem_cache.h"
      26             : 
      27             : #include "cpl_curl_priv.h"
      28             : 
      29             : #include <algorithm>
      30             : #include <atomic>
      31             : #include <condition_variable>
      32             : #include <set>
      33             : #include <map>
      34             : #include <memory>
      35             : #include <mutex>
      36             : #include <thread>
      37             : #include <utility>
      38             : 
      39             : // To avoid aliasing to CopyFile to CopyFileA on Windows
      40             : #ifdef CopyFile
      41             : #undef CopyFile
      42             : #endif
      43             : 
      44             : //! @cond Doxygen_Suppress
      45             : 
      46             : // Leave it for backward compatibility, but deprecate.
      47             : #define HAVE_CURLINFO_REDIRECT_URL
      48             : 
      49             : void VSICurlStreamingClearCache(void);  // from cpl_vsil_curl_streaming.cpp
      50             : 
      51             : struct curl_slist *VSICurlSetOptions(CURL *hCurlHandle, const char *pszURL,
      52             :                                      const char *const *papszOptions);
      53             : 
      54             : struct curl_slist *VSICurlSetContentTypeFromExt(struct curl_slist *polist,
      55             :                                                 const char *pszPath);
      56             : 
      57             : struct curl_slist *VSICurlSetCreationHeadersFromOptions(
      58             :     struct curl_slist *headers, CSLConstList papszOptions, const char *pszPath);
      59             : 
      60             : namespace cpl
      61             : {
      62             : 
      63             : typedef enum
      64             : {
      65             :     EXIST_UNKNOWN = -1,
      66             :     EXIST_NO,
      67             :     EXIST_YES,
      68             : } ExistStatus;
      69             : 
      70             : class FileProp
      71             : {
      72             :   public:
      73             :     unsigned int nGenerationAuthParameters = 0;
      74             :     ExistStatus eExists = EXIST_UNKNOWN;
      75             :     int nHTTPCode = 0;
      76             :     vsi_l_offset fileSize = 0;
      77             :     time_t mTime = 0;
      78             :     time_t nExpireTimestampLocal = 0;
      79             :     std::string osRedirectURL{};
      80             :     bool bHasComputedFileSize = false;
      81             :     bool bIsDirectory = false;
      82             :     bool bIsAzureFolder = false;
      83             :     int nMode = 0;  // st_mode member of struct stat
      84             :     bool bS3LikeRedirect = false;
      85             :     std::string ETag{};
      86             : };
      87             : 
      88             : struct CachedDirList
      89             : {
      90             :     bool bGotFileList = false;
      91             :     unsigned int nGenerationAuthParameters = 0;
      92             :     CPLStringList oFileList{}; /* only file name without path */
      93             : };
      94             : 
      95             : struct WriteFuncStruct
      96             : {
      97             :     char *pBuffer = nullptr;
      98             :     size_t nSize = 0;
      99             :     bool bIsHTTP = false;
     100             :     bool bMultiRange = false;
     101             :     vsi_l_offset nStartOffset = 0;
     102             :     vsi_l_offset nEndOffset = 0;
     103             :     int nHTTPCode = 0;       // potentially after redirect
     104             :     int nFirstHTTPCode = 0;  // the one of the redirect
     105             :     vsi_l_offset nContentLength = 0;
     106             :     bool bFoundContentRange = false;
     107             :     bool bError = false;
     108             :     bool bInterruptDownload = false;
     109             :     bool bDetectRangeDownloadingError = false;
     110             :     GIntBig nTimestampDate = 0;  // Corresponds to Date: header field
     111             : 
     112             :     VSILFILE *fp = nullptr;
     113             :     VSICurlReadCbkFunc pfnReadCbk = nullptr;
     114             :     void *pReadCbkUserData = nullptr;
     115             :     bool bInterrupted = false;
     116             : };
     117             : 
     118             : struct PutData
     119             : {
     120             :     const GByte *pabyData = nullptr;
     121             :     size_t nOff = 0;
     122             :     size_t nTotalSize = 0;
     123             : 
     124          35 :     static size_t ReadCallBackBuffer(char *buffer, size_t size, size_t nitems,
     125             :                                      void *instream)
     126             :     {
     127          35 :         PutData *poThis = static_cast<PutData *>(instream);
     128          35 :         const size_t nSizeMax = size * nitems;
     129             :         const size_t nSizeToWrite =
     130          35 :             std::min(nSizeMax, poThis->nTotalSize - poThis->nOff);
     131          35 :         memcpy(buffer, poThis->pabyData + poThis->nOff, nSizeToWrite);
     132          35 :         poThis->nOff += nSizeToWrite;
     133          35 :         return nSizeToWrite;
     134             :     }
     135             : };
     136             : 
     137             : /************************************************************************/
     138             : /*                     VSICurlFilesystemHandler                         */
     139             : /************************************************************************/
     140             : 
     141             : class VSICurlHandle;
     142             : 
     143             : class VSICurlFilesystemHandlerBase : public VSIFilesystemHandler
     144             : {
     145             :     CPL_DISALLOW_COPY_ASSIGN(VSICurlFilesystemHandlerBase)
     146             : 
     147             :     struct FilenameOffsetPair
     148             :     {
     149             :         std::string filename_;
     150             :         vsi_l_offset offset_;
     151             : 
     152       46928 :         FilenameOffsetPair(const std::string &filename, vsi_l_offset offset)
     153       46928 :             : filename_(filename), offset_(offset)
     154             :         {
     155       46928 :         }
     156             : 
     157       45867 :         bool operator==(const FilenameOffsetPair &other) const
     158             :         {
     159       45867 :             return filename_ == other.filename_ && offset_ == other.offset_;
     160             :         }
     161             :     };
     162             : 
     163             :     struct FilenameOffsetPairHasher
     164             :     {
     165       47674 :         std::size_t operator()(const FilenameOffsetPair &k) const
     166             :         {
     167       47674 :             return std::hash<std::string>()(k.filename_) ^
     168       47674 :                    std::hash<vsi_l_offset>()(k.offset_);
     169             :         }
     170             :     };
     171             : 
     172             :     using RegionCacheType = lru11::Cache<
     173             :         FilenameOffsetPair, std::shared_ptr<std::string>, lru11::NullLock,
     174             :         std::unordered_map<
     175             :             FilenameOffsetPair,
     176             :             typename std::list<lru11::KeyValuePair<
     177             :                 FilenameOffsetPair, std::shared_ptr<std::string>>>::iterator,
     178             :             FilenameOffsetPairHasher>>;
     179             : 
     180             :     std::unique_ptr<RegionCacheType>
     181             :         m_poRegionCacheDoNotUseDirectly{};  // do not access directly. Use
     182             :                                             // GetRegionCache();
     183             :     RegionCacheType *GetRegionCache();
     184             : 
     185             :     // LRU cache that just keeps in memory if this file system handler is
     186             :     // spposed to know the file properties of a file. The actual cache is a
     187             :     // shared one among all network file systems.
     188             :     // The aim of that design is that invalidating /vsis3/foo results in
     189             :     // /vsis3_streaming/foo to be invalidated as well.
     190             :     lru11::Cache<std::string, bool> oCacheFileProp;
     191             : 
     192             :     int nCachedFilesInDirList = 0;
     193             :     lru11::Cache<std::string, CachedDirList> oCacheDirList;
     194             : 
     195             :     char **ParseHTMLFileList(const char *pszFilename, int nMaxFiles,
     196             :                              char *pszData, bool *pbGotFileList);
     197             : 
     198             :     // Data structure and map to store regions that are in progress, to
     199             :     // avoid simultaneous downloads of the same region in different threads
     200             :     // Cf https://github.com/OSGeo/gdal/issues/8041
     201             :     struct RegionInDownload
     202             :     {
     203             :         std::mutex oMutex{};
     204             :         std::condition_variable oCond{};
     205             :         bool bDownloadInProgress = false;
     206             :         int nWaiters = 0;
     207             :         std::string osData{};
     208             :     };
     209             : 
     210             :     std::mutex m_oMutex{};
     211             :     std::map<std::string, std::unique_ptr<RegionInDownload>>
     212             :         m_oMapRegionInDownload{};
     213             : 
     214             :   protected:
     215             :     CPLMutex *hMutex = nullptr;
     216             : 
     217             :     virtual VSICurlHandle *CreateFileHandle(const char *pszFilename);
     218             :     virtual char **GetFileList(const char *pszFilename, int nMaxFiles,
     219             :                                bool *pbGotFileList);
     220             : 
     221             :     void RegisterEmptyDir(const std::string &osDirname);
     222             : 
     223             :     bool
     224             :     AnalyseS3FileList(const std::string &osBaseURL, const char *pszXML,
     225             :                       CPLStringList &osFileList, int nMaxFiles,
     226             :                       const std::set<std::string> &oSetIgnoredStorageClasses,
     227             :                       bool &bIsTruncated);
     228             : 
     229             :     void AnalyseSwiftFileList(const std::string &osBaseURL,
     230             :                               const std::string &osPrefix, const char *pszJson,
     231             :                               CPLStringList &osFileList, int nMaxFilesThisQuery,
     232             :                               int nMaxFiles, bool &bIsTruncated,
     233             :                               std::string &osNextMarker);
     234             : 
     235             :     static const char *GetOptionsStatic();
     236             : 
     237             :     VSICurlFilesystemHandlerBase();
     238             : 
     239             :   public:
     240             :     ~VSICurlFilesystemHandlerBase() override;
     241             : 
     242             :     static bool IsAllowedFilename(const char *pszFilename);
     243             : 
     244             :     VSIVirtualHandle *Open(const char *pszFilename, const char *pszAccess,
     245             :                            bool bSetError,
     246             :                            CSLConstList /* papszOptions */) override;
     247             : 
     248             :     int Stat(const char *pszFilename, VSIStatBufL *pStatBuf,
     249             :              int nFlags) override;
     250             :     char **ReadDirEx(const char *pszDirname, int nMaxFiles) override;
     251             :     char **SiblingFiles(const char *pszFilename) override;
     252             : 
     253          18 :     int HasOptimizedReadMultiRange(const char * /* pszPath */) override
     254             :     {
     255          18 :         return true;
     256             :     }
     257             : 
     258             :     const char *GetActualURL(const char *pszFilename) override;
     259             : 
     260             :     const char *GetOptions() override;
     261             : 
     262             :     char **GetFileMetadata(const char *pszFilename, const char *pszDomain,
     263             :                            CSLConstList papszOptions) override;
     264             : 
     265             :     char **ReadDirInternal(const char *pszDirname, int nMaxFiles,
     266             :                            bool *pbGotFileList);
     267             :     void InvalidateDirContent(const std::string &osDirname);
     268             : 
     269             :     virtual const char *GetDebugKey() const = 0;
     270             : 
     271             :     virtual std::string GetFSPrefix() const = 0;
     272             :     virtual bool AllowCachedDataFor(const char *pszFilename);
     273             : 
     274           6 :     virtual bool IsLocal(const char * /* pszPath */) override
     275             :     {
     276           6 :         return false;
     277             :     }
     278             : 
     279             :     virtual bool
     280           2 :     SupportsSequentialWrite(const char * /* pszPath */,
     281             :                             bool /* bAllowLocalTempFile */) override
     282             :     {
     283           2 :         return false;
     284             :     }
     285             : 
     286           1 :     virtual bool SupportsRandomWrite(const char * /* pszPath */,
     287             :                                      bool /* bAllowLocalTempFile */) override
     288             :     {
     289           1 :         return false;
     290             :     }
     291             : 
     292             :     std::shared_ptr<std::string> GetRegion(const char *pszURL,
     293             :                                            vsi_l_offset nFileOffsetStart);
     294             : 
     295             :     void AddRegion(const char *pszURL, vsi_l_offset nFileOffsetStart,
     296             :                    size_t nSize, const char *pData);
     297             : 
     298             :     std::pair<bool, std::string>
     299             :     NotifyStartDownloadRegion(const std::string &osURL,
     300             :                               vsi_l_offset startOffset, int nBlocks);
     301             :     void NotifyStopDownloadRegion(const std::string &osURL,
     302             :                                   vsi_l_offset startOffset, int nBlocks,
     303             :                                   const std::string &osData);
     304             : 
     305             :     bool GetCachedFileProp(const char *pszURL, FileProp &oFileProp);
     306             :     void SetCachedFileProp(const char *pszURL, FileProp &oFileProp);
     307             :     void InvalidateCachedData(const char *pszURL);
     308             : 
     309             :     CURLM *GetCurlMultiHandleFor(const std::string &osURL);
     310             : 
     311             :     virtual void ClearCache();
     312             :     virtual void PartialClearCache(const char *pszFilename);
     313             : 
     314             :     bool GetCachedDirList(const char *pszURL, CachedDirList &oCachedDirList);
     315             :     void SetCachedDirList(const char *pszURL, CachedDirList &oCachedDirList);
     316             :     bool ExistsInCacheDirList(const std::string &osDirname, bool *pbIsDir);
     317             : 
     318             :     virtual std::string GetURLFromFilename(const std::string &osFilename) const;
     319             : 
     320             :     std::string
     321             :     GetStreamingFilename(const std::string &osFilename) const override = 0;
     322             : 
     323             :     static std::set<std::string> GetS3IgnoredStorageClasses();
     324             : };
     325             : 
     326             : class VSICurlFilesystemHandler : public VSICurlFilesystemHandlerBase
     327             : {
     328             :     CPL_DISALLOW_COPY_ASSIGN(VSICurlFilesystemHandler)
     329             : 
     330             :   public:
     331        1691 :     VSICurlFilesystemHandler() = default;
     332             : 
     333         909 :     const char *GetDebugKey() const override
     334             :     {
     335         909 :         return "VSICURL";
     336             :     }
     337             : 
     338       48078 :     std::string GetFSPrefix() const override
     339             :     {
     340       48078 :         return "/vsicurl/";
     341             :     }
     342             : 
     343             :     std::string
     344             :     GetStreamingFilename(const std::string &osFilename) const override;
     345             : };
     346             : 
     347             : /************************************************************************/
     348             : /*                           VSICurlHandle                              */
     349             : /************************************************************************/
     350             : 
     351             : class VSICurlHandle : public VSIVirtualHandle
     352             : {
     353             :     CPL_DISALLOW_COPY_ASSIGN(VSICurlHandle)
     354             : 
     355             :   protected:
     356             :     VSICurlFilesystemHandlerBase *poFS = nullptr;
     357             : 
     358             :     bool m_bCached = true;
     359             : 
     360             :     mutable FileProp oFileProp{};
     361             : 
     362             :     mutable std::mutex m_oMutex{};
     363             :     std::string m_osFilename{};  // e.g "/vsicurl/http://example.com/foo"
     364             :     char *m_pszURL = nullptr;    // e.g "http://example.com/foo"
     365             :     mutable std::string m_osQueryString{};  // e.g. an Azure SAS
     366             : 
     367             :     CPLStringList m_aosHTTPOptions{};
     368             :     CPLHTTPRetryParameters
     369             :         m_oRetryParameters;  // must be initialized in constructor
     370             : 
     371             :     vsi_l_offset lastDownloadedOffset = VSI_L_OFFSET_MAX;
     372             :     int nBlocksToDownload = 1;
     373             : 
     374             :     bool bStopOnInterruptUntilUninstall = false;
     375             :     bool bInterrupted = false;
     376             :     VSICurlReadCbkFunc pfnReadCbk = nullptr;
     377             :     void *pReadCbkUserData = nullptr;
     378             : 
     379             :     CPLStringList m_aosHeaders{};
     380             : 
     381             :     void DownloadRegionPostProcess(const vsi_l_offset startOffset,
     382             :                                    const int nBlocks, const char *pBuffer,
     383             :                                    size_t nSize);
     384             : 
     385             :   private:
     386             :     vsi_l_offset curOffset = 0;
     387             : 
     388             :     bool bEOF = false;
     389             :     bool bError = false;
     390             : 
     391             :     virtual std::string DownloadRegion(vsi_l_offset startOffset, int nBlocks);
     392             : 
     393             :     bool m_bUseHead = false;
     394             :     bool m_bUseRedirectURLIfNoQueryStringParams = false;
     395             : 
     396             :     mutable std::atomic<bool> m_bInterrupt = false;
     397             : 
     398             :     // Specific to Planetary Computer signing:
     399             :     // https://planetarycomputer.microsoft.com/docs/concepts/sas/
     400             :     mutable bool m_bPlanetaryComputerURLSigning = false;
     401             :     mutable std::string m_osPlanetaryComputerCollection{};
     402             :     void ManagePlanetaryComputerSigning() const;
     403             : 
     404             :     void UpdateQueryString() const;
     405             : 
     406             :     int ReadMultiRangeSingleGet(int nRanges, void **ppData,
     407             :                                 const vsi_l_offset *panOffsets,
     408             :                                 const size_t *panSizes);
     409             :     std::string GetRedirectURLIfValid(bool &bHasExpired,
     410             :                                       CPLStringList &aosHTTPOptions) const;
     411             : 
     412             :     void UpdateRedirectInfo(CURL *hCurlHandle,
     413             :                             const WriteFuncStruct &sWriteFuncHeaderData);
     414             : 
     415             :     // Used by AdviseRead()
     416             :     struct AdviseReadRange
     417             :     {
     418             :         bool bDone = false;
     419             :         bool bToRetry = true;
     420             :         double dfSleepDelay = 0.0;
     421             :         std::mutex oMutex{};
     422             :         std::condition_variable oCV{};
     423             :         vsi_l_offset nStartOffset = 0;
     424             :         size_t nSize = 0;
     425             :         std::vector<GByte> abyData{};
     426             :         CPLHTTPRetryContext retryContext;
     427             : 
     428           6 :         explicit AdviseReadRange(const CPLHTTPRetryParameters &oRetryParameters)
     429           6 :             : retryContext(oRetryParameters)
     430             :         {
     431           6 :         }
     432             : 
     433             :         AdviseReadRange(const AdviseReadRange &) = delete;
     434             :         AdviseReadRange &operator=(const AdviseReadRange &) = delete;
     435             :         AdviseReadRange(AdviseReadRange &&) = delete;
     436             :         AdviseReadRange &operator=(AdviseReadRange &&) = delete;
     437             :     };
     438             : 
     439             :     std::vector<std::unique_ptr<AdviseReadRange>> m_aoAdviseReadRanges{};
     440             :     std::thread m_oThreadAdviseRead{};
     441             :     CURLM *m_hCurlMultiHandleForAdviseRead = nullptr;
     442             : 
     443             :   protected:
     444         554 :     virtual struct curl_slist *GetCurlHeaders(const std::string & /*osVerb*/,
     445             :                                               struct curl_slist *psHeaders)
     446             :     {
     447         554 :         return psHeaders;
     448             :     }
     449             : 
     450         620 :     virtual bool AllowAutomaticRedirection()
     451             :     {
     452         620 :         return true;
     453             :     }
     454             : 
     455         127 :     virtual bool CanRestartOnError(const char *, const char *, bool)
     456             :     {
     457         127 :         return false;
     458             :     }
     459             : 
     460         737 :     virtual bool UseLimitRangeGetInsteadOfHead()
     461             :     {
     462         737 :         return false;
     463             :     }
     464             : 
     465         272 :     virtual bool IsDirectoryFromExists(const char * /*pszVerb*/,
     466             :                                        int /*response_code*/)
     467             :     {
     468         272 :         return false;
     469             :     }
     470             : 
     471         131 :     virtual void ProcessGetFileSizeResult(const char * /* pszContent */)
     472             :     {
     473         131 :     }
     474             : 
     475             :     void SetURL(const char *pszURL);
     476             : 
     477           0 :     virtual bool Authenticate(const char * /* pszFilename */)
     478             :     {
     479           0 :         return false;
     480             :     }
     481             : 
     482             :   public:
     483             :     VSICurlHandle(VSICurlFilesystemHandlerBase *poFS, const char *pszFilename,
     484             :                   const char *pszURLIn = nullptr);
     485             :     ~VSICurlHandle() override;
     486             : 
     487             :     int Seek(vsi_l_offset nOffset, int nWhence) override;
     488             :     vsi_l_offset Tell() override;
     489             :     size_t Read(void *pBuffer, size_t nSize, size_t nMemb) override;
     490             :     int ReadMultiRange(int nRanges, void **ppData,
     491             :                        const vsi_l_offset *panOffsets,
     492             :                        const size_t *panSizes) override;
     493             :     size_t Write(const void *pBuffer, size_t nSize, size_t nMemb) override;
     494             :     void ClearErr() override;
     495             :     int Eof() override;
     496             :     int Error() override;
     497             :     int Flush() override;
     498             :     int Close() override;
     499             : 
     500           0 :     void Interrupt() override
     501             :     {
     502           0 :         m_bInterrupt = true;
     503           0 :     }
     504             : 
     505          18 :     bool HasPRead() const override
     506             :     {
     507          18 :         return true;
     508             :     }
     509             : 
     510             :     size_t PRead(void *pBuffer, size_t nSize,
     511             :                  vsi_l_offset nOffset) const override;
     512             : 
     513             :     void AdviseRead(int nRanges, const vsi_l_offset *panOffsets,
     514             :                     const size_t *panSizes) override;
     515             : 
     516             :     size_t GetAdviseReadTotalBytesLimit() const override;
     517             : 
     518         587 :     bool IsKnownFileSize() const
     519             :     {
     520         587 :         return oFileProp.bHasComputedFileSize;
     521             :     }
     522             : 
     523             :     vsi_l_offset GetFileSizeOrHeaders(bool bSetError, bool bGetHeaders);
     524             : 
     525         950 :     virtual vsi_l_offset GetFileSize(bool bSetError)
     526             :     {
     527         950 :         return GetFileSizeOrHeaders(bSetError, false);
     528             :     }
     529             : 
     530             :     bool Exists(bool bSetError);
     531             : 
     532         717 :     bool IsDirectory() const
     533             :     {
     534         717 :         return oFileProp.bIsDirectory;
     535             :     }
     536             : 
     537         587 :     int GetMode() const
     538             :     {
     539         587 :         return oFileProp.nMode;
     540             :     }
     541             : 
     542         587 :     time_t GetMTime() const
     543             :     {
     544         587 :         return oFileProp.mTime;
     545             :     }
     546             : 
     547           4 :     const CPLStringList &GetHeaders()
     548             :     {
     549           4 :         return m_aosHeaders;
     550             :     }
     551             : 
     552             :     int InstallReadCbk(VSICurlReadCbkFunc pfnReadCbk, void *pfnUserData,
     553             :                        int bStopOnInterruptUntilUninstall);
     554             :     int UninstallReadCbk();
     555             : 
     556           5 :     const char *GetURL() const
     557             :     {
     558           5 :         return m_pszURL;
     559             :     }
     560             : };
     561             : 
     562             : /************************************************************************/
     563             : /*                  VSICurlFilesystemHandlerBaseWritable                */
     564             : /************************************************************************/
     565             : 
     566             : class VSICurlFilesystemHandlerBaseWritable : public VSICurlFilesystemHandlerBase
     567             : {
     568             :     CPL_DISALLOW_COPY_ASSIGN(VSICurlFilesystemHandlerBaseWritable)
     569             : 
     570             :   protected:
     571       11837 :     VSICurlFilesystemHandlerBaseWritable() = default;
     572             : 
     573             :     virtual VSIVirtualHandleUniquePtr
     574             :     CreateWriteHandle(const char *pszFilename, CSLConstList papszOptions) = 0;
     575             : 
     576             :   public:
     577             :     VSIVirtualHandle *Open(const char *pszFilename, const char *pszAccess,
     578             :                            bool bSetError, CSLConstList papszOptions) override;
     579             : 
     580           1 :     bool SupportsSequentialWrite(const char * /* pszPath */,
     581             :                                  bool /* bAllowLocalTempFile */) override
     582             :     {
     583           1 :         return true;
     584             :     }
     585             : 
     586             :     bool SupportsRandomWrite(const char * /* pszPath */,
     587             :                              bool /* bAllowLocalTempFile */) override;
     588             : };
     589             : 
     590             : /************************************************************************/
     591             : /*                        IVSIS3LikeFSHandler                           */
     592             : /************************************************************************/
     593             : 
     594             : class IVSIS3LikeFSHandler : public VSICurlFilesystemHandlerBaseWritable
     595             : {
     596             :     CPL_DISALLOW_COPY_ASSIGN(IVSIS3LikeFSHandler)
     597             : 
     598             :     virtual int MkdirInternal(const char *pszDirname, long nMode,
     599             :                               bool bDoStatCheck);
     600             : 
     601             :   protected:
     602             :     char **GetFileList(const char *pszFilename, int nMaxFiles,
     603             :                        bool *pbGotFileList) override;
     604             : 
     605             :     virtual IVSIS3LikeHandleHelper *CreateHandleHelper(const char *pszURI,
     606             :                                                        bool bAllowNoObject) = 0;
     607             : 
     608             :     virtual int CopyObject(const char *oldpath, const char *newpath,
     609             :                            CSLConstList papszMetadata);
     610             : 
     611             :     int RmdirRecursiveInternal(const char *pszDirname, int nBatchSize);
     612             : 
     613             :     virtual bool
     614           0 :     IsAllowedHeaderForObjectCreation(const char * /* pszHeaderName */)
     615             :     {
     616           0 :         return false;
     617             :     }
     618             : 
     619       10146 :     IVSIS3LikeFSHandler() = default;
     620             : 
     621             :   public:
     622             :     int Unlink(const char *pszFilename) override;
     623             :     int Mkdir(const char *pszDirname, long nMode) override;
     624             :     int Rmdir(const char *pszDirname) override;
     625             :     int Stat(const char *pszFilename, VSIStatBufL *pStatBuf,
     626             :              int nFlags) override;
     627             :     int Rename(const char *oldpath, const char *newpath, GDALProgressFunc,
     628             :                void *) override;
     629             : 
     630             :     virtual int CopyFile(const char *pszSource, const char *pszTarget,
     631             :                          VSILFILE *fpSource, vsi_l_offset nSourceSize,
     632             :                          const char *const *papszOptions,
     633             :                          GDALProgressFunc pProgressFunc,
     634             :                          void *pProgressData) override;
     635             : 
     636             :     virtual int DeleteObject(const char *pszFilename);
     637             : 
     638             :     virtual int *DeleteObjectBatch(CSLConstList papszFilesOrDirs);
     639             : 
     640             :     bool Sync(const char *pszSource, const char *pszTarget,
     641             :               const char *const *papszOptions, GDALProgressFunc pProgressFunc,
     642             :               void *pProgressData, char ***ppapszOutputs) override;
     643             : 
     644             :     VSIDIR *OpenDir(const char *pszPath, int nRecurseDepth,
     645             :                     const char *const *papszOptions) override;
     646             : };
     647             : 
     648             : /************************************************************************/
     649             : /*                 IVSIS3LikeFSHandlerWithMultipartUpload               */
     650             : /************************************************************************/
     651             : 
     652             : class IVSIS3LikeFSHandlerWithMultipartUpload : public IVSIS3LikeFSHandler
     653             : {
     654             :     CPL_DISALLOW_COPY_ASSIGN(IVSIS3LikeFSHandlerWithMultipartUpload)
     655             : 
     656             :   protected:
     657        8455 :     IVSIS3LikeFSHandlerWithMultipartUpload() = default;
     658             : 
     659             :   public:
     660           5 :     virtual bool SupportsNonSequentialMultipartUpload() const
     661             :     {
     662           5 :         return true;
     663             :     }
     664             : 
     665          36 :     virtual bool SupportsParallelMultipartUpload() const
     666             :     {
     667          36 :         return true;
     668             :     }
     669             : 
     670             :     virtual bool SupportsMultipartAbort() const = 0;
     671             : 
     672             :     size_t GetUploadChunkSizeInBytes(const char *pszFilename,
     673             :                                      const char *pszSpecifiedValInBytes);
     674             : 
     675             :     virtual int CopyFileRestartable(const char *pszSource,
     676             :                                     const char *pszTarget,
     677             :                                     const char *pszInputPayload,
     678             :                                     char **ppszOutputPayload,
     679             :                                     CSLConstList papszOptions,
     680             :                                     GDALProgressFunc pProgressFunc,
     681             :                                     void *pProgressData) override;
     682             : 
     683             :     //! Maximum number of parts for multipart upload
     684             :     // Limit currently used by S3 and GS.
     685             :     // Cf https://docs.aws.amazon.com/AmazonS3/latest/userguide/qfacts.html
     686             :     // and https://cloud.google.com/storage/quotas#requests
     687          11 :     virtual int GetMaximumPartCount()
     688             :     {
     689          11 :         return 10000;
     690             :     }
     691             : 
     692             :     //! Minimum size of a part for multipart upload (except last one), in MiB.
     693             :     // Limit currently used by S3 and GS.
     694             :     // Cf https://docs.aws.amazon.com/AmazonS3/latest/userguide/qfacts.html
     695             :     // and https://cloud.google.com/storage/quotas#requests
     696           5 :     virtual int GetMinimumPartSizeInMiB()
     697             :     {
     698           5 :         return 5;
     699             :     }
     700             : 
     701             :     //! Maximum size of a part for multipart upload, in MiB.
     702             :     // Limit currently used by S3 and GS.
     703             :     // Cf https://docs.aws.amazon.com/AmazonS3/latest/userguide/qfacts.html
     704             :     // and https://cloud.google.com/storage/quotas#requests
     705          50 :     virtual int GetMaximumPartSizeInMiB()
     706             :     {
     707             : #if SIZEOF_VOIDP == 8
     708          50 :         return 5 * 1024;
     709             : #else
     710             :         // Cannot be larger than 4, otherwise integer overflow would occur
     711             :         // 1 GiB is the maximum reasonable value on a 32-bit machine
     712             :         return 1 * 1024;
     713             : #endif
     714             :     }
     715             : 
     716             :     //! Default size of a part for multipart upload, in MiB.
     717          47 :     virtual int GetDefaultPartSizeInMiB()
     718             :     {
     719          47 :         return 50;
     720             :     }
     721             : 
     722             :     virtual std::string
     723             :     InitiateMultipartUpload(const std::string &osFilename,
     724             :                             IVSIS3LikeHandleHelper *poS3HandleHelper,
     725             :                             const CPLHTTPRetryParameters &oRetryParameters,
     726             :                             CSLConstList papszOptions);
     727             : 
     728             :     virtual std::string
     729             :     UploadPart(const std::string &osFilename, int nPartNumber,
     730             :                const std::string &osUploadID, vsi_l_offset nPosition,
     731             :                const void *pabyBuffer, size_t nBufferSize,
     732             :                IVSIS3LikeHandleHelper *poS3HandleHelper,
     733             :                const CPLHTTPRetryParameters &oRetryParameters,
     734             :                CSLConstList papszOptions);
     735             : 
     736             :     virtual bool CompleteMultipart(
     737             :         const std::string &osFilename, const std::string &osUploadID,
     738             :         const std::vector<std::string> &aosEtags, vsi_l_offset nTotalSize,
     739             :         IVSIS3LikeHandleHelper *poS3HandleHelper,
     740             :         const CPLHTTPRetryParameters &oRetryParameters);
     741             : 
     742             :     virtual bool AbortMultipart(const std::string &osFilename,
     743             :                                 const std::string &osUploadID,
     744             :                                 IVSIS3LikeHandleHelper *poS3HandleHelper,
     745             :                                 const CPLHTTPRetryParameters &oRetryParameters);
     746             : 
     747             :     bool AbortPendingUploads(const char *pszFilename) override;
     748             : 
     749             :     bool MultipartUploadGetCapabilities(int *pbNonSequentialUploadSupported,
     750             :                                         int *pbParallelUploadSupported,
     751             :                                         int *pbAbortSupported,
     752             :                                         size_t *pnMinPartSize,
     753             :                                         size_t *pnMaxPartSize,
     754             :                                         int *pnMaxPartCount) override;
     755             : 
     756             :     char *MultipartUploadStart(const char *pszFilename,
     757             :                                CSLConstList papszOptions) override;
     758             : 
     759             :     char *MultipartUploadAddPart(const char *pszFilename,
     760             :                                  const char *pszUploadId, int nPartNumber,
     761             :                                  vsi_l_offset nFileOffset, const void *pData,
     762             :                                  size_t nDataLength,
     763             :                                  CSLConstList papszOptions) override;
     764             : 
     765             :     bool MultipartUploadEnd(const char *pszFilename, const char *pszUploadId,
     766             :                             size_t nPartIdsCount,
     767             :                             const char *const *apszPartIds,
     768             :                             vsi_l_offset nTotalSize,
     769             :                             CSLConstList papszOptions) override;
     770             : 
     771             :     bool MultipartUploadAbort(const char *pszFilename, const char *pszUploadId,
     772             :                               CSLConstList papszOptions) override;
     773             : };
     774             : 
     775             : /************************************************************************/
     776             : /*                          IVSIS3LikeHandle                            */
     777             : /************************************************************************/
     778             : 
     779         257 : class IVSIS3LikeHandle : public VSICurlHandle
     780             : {
     781             :     CPL_DISALLOW_COPY_ASSIGN(IVSIS3LikeHandle)
     782             : 
     783             :   protected:
     784         263 :     bool UseLimitRangeGetInsteadOfHead() override
     785             :     {
     786         263 :         return true;
     787             :     }
     788             : 
     789         108 :     bool IsDirectoryFromExists(const char *pszVerb, int response_code) override
     790             :     {
     791             :         // A bit dirty, but on S3, a GET on a existing directory returns a 416
     792         112 :         return response_code == 416 && EQUAL(pszVerb, "GET") &&
     793         112 :                std::string(m_pszURL).back() == '/';
     794             :     }
     795             : 
     796          52 :     void ProcessGetFileSizeResult(const char *pszContent) override
     797             :     {
     798          52 :         oFileProp.bIsDirectory =
     799          52 :             strstr(pszContent, "ListBucketResult") != nullptr;
     800          52 :     }
     801             : 
     802             :   public:
     803         257 :     IVSIS3LikeHandle(VSICurlFilesystemHandlerBase *poFSIn,
     804             :                      const char *pszFilename, const char *pszURLIn)
     805         257 :         : VSICurlHandle(poFSIn, pszFilename, pszURLIn)
     806             :     {
     807         257 :     }
     808             : 
     809             :     ~IVSIS3LikeHandle() override;
     810             : };
     811             : 
     812             : /************************************************************************/
     813             : /*                       VSIMultipartWriteHandle                        */
     814             : /************************************************************************/
     815             : 
     816             : class VSIMultipartWriteHandle final : public VSIVirtualHandle
     817             : {
     818             :     CPL_DISALLOW_COPY_ASSIGN(VSIMultipartWriteHandle)
     819             : 
     820             :     IVSIS3LikeFSHandlerWithMultipartUpload *m_poFS = nullptr;
     821             :     std::string m_osFilename{};
     822             :     IVSIS3LikeHandleHelper *m_poS3HandleHelper = nullptr;
     823             :     CPLStringList m_aosOptions{};
     824             :     CPLStringList m_aosHTTPOptions{};
     825             :     CPLHTTPRetryParameters m_oRetryParameters;
     826             : 
     827             :     vsi_l_offset m_nCurOffset = 0;
     828             :     size_t m_nBufferOff = 0;
     829             :     size_t m_nBufferSize = 0;
     830             :     bool m_bClosed = false;
     831             :     GByte *m_pabyBuffer = nullptr;
     832             :     std::string m_osUploadID{};
     833             :     int m_nPartNumber = 0;
     834             :     std::vector<std::string> m_aosEtags{};
     835             :     bool m_bError = false;
     836             : 
     837             :     WriteFuncStruct m_sWriteFuncHeaderData{};
     838             : 
     839             :     bool UploadPart();
     840             :     bool DoSinglePartPUT();
     841             : 
     842             :     void InvalidateParentDirectory();
     843             : 
     844             :   public:
     845             :     VSIMultipartWriteHandle(IVSIS3LikeFSHandlerWithMultipartUpload *poFS,
     846             :                             const char *pszFilename,
     847             :                             IVSIS3LikeHandleHelper *poS3HandleHelper,
     848             :                             CSLConstList papszOptions);
     849             :     ~VSIMultipartWriteHandle() override;
     850             : 
     851             :     int Seek(vsi_l_offset nOffset, int nWhence) override;
     852             :     vsi_l_offset Tell() override;
     853             :     size_t Read(void *pBuffer, size_t nSize, size_t nMemb) override;
     854             :     size_t Write(const void *pBuffer, size_t nSize, size_t nMemb) override;
     855             : 
     856           0 :     void ClearErr() override
     857             :     {
     858           0 :     }
     859             : 
     860           0 :     int Error() override
     861             :     {
     862           0 :         return FALSE;
     863             :     }
     864             : 
     865           0 :     int Eof() override
     866             :     {
     867           0 :         return FALSE;
     868             :     }
     869             : 
     870             :     int Close() override;
     871             : 
     872          31 :     bool IsOK()
     873             :     {
     874          31 :         return m_pabyBuffer != nullptr;
     875             :     }
     876             : };
     877             : 
     878             : /************************************************************************/
     879             : /*                         VSIChunkedWriteHandle()                      */
     880             : /************************************************************************/
     881             : 
     882             : /** Class with Write() append-only implementation using
     883             :  * "Transfer-Encoding: chunked" writing
     884             :  */
     885             : class VSIChunkedWriteHandle final : public VSIVirtualHandle
     886             : {
     887             :     CPL_DISALLOW_COPY_ASSIGN(VSIChunkedWriteHandle)
     888             : 
     889             :     IVSIS3LikeFSHandler *m_poFS = nullptr;
     890             :     std::string m_osFilename{};
     891             :     IVSIS3LikeHandleHelper *m_poS3HandleHelper = nullptr;
     892             :     CPLStringList m_aosOptions{};
     893             :     CPLStringList m_aosHTTPOptions{};
     894             :     CPLHTTPRetryParameters m_oRetryParameters;
     895             : 
     896             :     vsi_l_offset m_nCurOffset = 0;
     897             :     size_t m_nBufferOff = 0;
     898             :     bool m_bError = false;
     899             :     bool m_bClosed = false;
     900             : 
     901             :     CURLM *m_hCurlMulti = nullptr;
     902             :     CURL *m_hCurl = nullptr;
     903             :     const void *m_pBuffer = nullptr;
     904             :     std::string m_osCurlErrBuf{};
     905             :     size_t m_nChunkedBufferOff = 0;
     906             :     size_t m_nChunkedBufferSize = 0;
     907             :     size_t m_nWrittenInPUT = 0;
     908             : 
     909             :     WriteFuncStruct m_sWriteFuncHeaderData{};
     910             : 
     911             :     static size_t ReadCallBackBufferChunked(char *buffer, size_t size,
     912             :                                             size_t nitems, void *instream);
     913             :     int FinishChunkedTransfer();
     914             : 
     915             :     bool DoEmptyPUT();
     916             : 
     917             :     void InvalidateParentDirectory();
     918             : 
     919             :   public:
     920             :     VSIChunkedWriteHandle(IVSIS3LikeFSHandler *poFS, const char *pszFilename,
     921             :                           IVSIS3LikeHandleHelper *poS3HandleHelper,
     922             :                           CSLConstList papszOptions);
     923             :     virtual ~VSIChunkedWriteHandle();
     924             : 
     925             :     int Seek(vsi_l_offset nOffset, int nWhence) override;
     926             :     vsi_l_offset Tell() override;
     927             :     size_t Read(void *pBuffer, size_t nSize, size_t nMemb) override;
     928             :     size_t Write(const void *pBuffer, size_t nSize, size_t nMemb) override;
     929             : 
     930           0 :     void ClearErr() override
     931             :     {
     932           0 :     }
     933             : 
     934           0 :     int Error() override
     935             :     {
     936           0 :         return FALSE;
     937             :     }
     938             : 
     939           0 :     int Eof() override
     940             :     {
     941           0 :         return FALSE;
     942             :     }
     943             : 
     944             :     int Close() override;
     945             : };
     946             : 
     947             : /************************************************************************/
     948             : /*                        VSIAppendWriteHandle                          */
     949             : /************************************************************************/
     950             : 
     951             : class VSIAppendWriteHandle CPL_NON_FINAL : public VSIVirtualHandle
     952             : {
     953             :     CPL_DISALLOW_COPY_ASSIGN(VSIAppendWriteHandle)
     954             : 
     955             :   protected:
     956             :     VSICurlFilesystemHandlerBase *m_poFS = nullptr;
     957             :     std::string m_osFSPrefix{};
     958             :     std::string m_osFilename{};
     959             :     CPLHTTPRetryParameters m_oRetryParameters{};
     960             : 
     961             :     vsi_l_offset m_nCurOffset = 0;
     962             :     int m_nBufferOff = 0;
     963             :     int m_nBufferSize = 0;
     964             :     int m_nBufferOffReadCallback = 0;
     965             :     bool m_bClosed = false;
     966             :     GByte *m_pabyBuffer = nullptr;
     967             :     bool m_bError = false;
     968             : 
     969             :     static size_t ReadCallBackBuffer(char *buffer, size_t size, size_t nitems,
     970             :                                      void *instream);
     971             :     virtual bool Send(bool bIsLastBlock) = 0;
     972             : 
     973             :   public:
     974             :     VSIAppendWriteHandle(VSICurlFilesystemHandlerBase *poFS,
     975             :                          const char *pszFSPrefix, const char *pszFilename,
     976             :                          int nChunkSize);
     977             :     virtual ~VSIAppendWriteHandle();
     978             : 
     979             :     int Seek(vsi_l_offset nOffset, int nWhence) override;
     980             :     vsi_l_offset Tell() override;
     981             :     size_t Read(void *pBuffer, size_t nSize, size_t nMemb) override;
     982             :     size_t Write(const void *pBuffer, size_t nSize, size_t nMemb) override;
     983             : 
     984           0 :     void ClearErr() override
     985             :     {
     986           0 :     }
     987             : 
     988           0 :     int Error() override
     989             :     {
     990           0 :         return FALSE;
     991             :     }
     992             : 
     993           0 :     int Eof() override
     994             :     {
     995           0 :         return FALSE;
     996             :     }
     997             : 
     998             :     int Close() override;
     999             : 
    1000          10 :     bool IsOK()
    1001             :     {
    1002          10 :         return m_pabyBuffer != nullptr;
    1003             :     }
    1004             : };
    1005             : 
    1006             : /************************************************************************/
    1007             : /*                     VSIDIRWithMissingDirSynthesis                    */
    1008             : /************************************************************************/
    1009             : 
    1010         126 : struct VSIDIRWithMissingDirSynthesis : public VSIDIR
    1011             : {
    1012             :     std::vector<std::unique_ptr<VSIDIREntry>> aoEntries{};
    1013             : 
    1014             :   protected:
    1015             :     ~VSIDIRWithMissingDirSynthesis() override;
    1016             : 
    1017             :     std::vector<std::string> m_aosSubpathsStack{};
    1018             : 
    1019             :     void SynthetizeMissingDirectories(const std::string &osCurSubdir,
    1020             :                                       bool bAddEntryForThisSubdir);
    1021             : };
    1022             : 
    1023             : /************************************************************************/
    1024             : /*                          VSIDIRS3Like                                */
    1025             : /************************************************************************/
    1026             : 
    1027             : struct VSIDIRS3Like : public VSIDIRWithMissingDirSynthesis
    1028             : {
    1029             :     const std::string m_osDirName;
    1030             : 
    1031             :     int nRecurseDepth = 0;
    1032             : 
    1033             :     std::string osNextMarker{};
    1034             :     int nPos = 0;
    1035             : 
    1036             :     std::string osBucket{};
    1037             :     std::string osObjectKey{};
    1038             :     VSICurlFilesystemHandlerBase *poFS = nullptr;
    1039             :     IVSIS3LikeFSHandler *poS3FS = nullptr;
    1040             :     std::unique_ptr<IVSIS3LikeHandleHelper> poHandleHelper{};
    1041             :     int nMaxFiles = 0;
    1042             :     bool bCacheEntries = true;
    1043             :     bool m_bSynthetizeMissingDirectories = false;
    1044             :     std::string m_osFilterPrefix{};
    1045             : 
    1046             :     // used when listing only the file system prefix
    1047             :     std::unique_ptr<VSIDIR, decltype(&VSICloseDir)> m_subdir{nullptr,
    1048         126 :                                                              VSICloseDir};
    1049             : 
    1050         126 :     VSIDIRS3Like(const std::string &osDirName, IVSIS3LikeFSHandler *poFSIn)
    1051         126 :         : m_osDirName(osDirName), poFS(poFSIn), poS3FS(poFSIn)
    1052             :     {
    1053         126 :     }
    1054             : 
    1055           0 :     VSIDIRS3Like(const std::string &osDirName,
    1056             :                  VSICurlFilesystemHandlerBase *poFSIn)
    1057           0 :         : m_osDirName(osDirName), poFS(poFSIn)
    1058             :     {
    1059           0 :     }
    1060             : 
    1061             :     VSIDIRS3Like(const VSIDIRS3Like &) = delete;
    1062             :     VSIDIRS3Like &operator=(const VSIDIRS3Like &) = delete;
    1063             : 
    1064             :     const VSIDIREntry *NextDirEntry() override;
    1065             : 
    1066             :     virtual bool IssueListDir() = 0;
    1067             :     void clear();
    1068             : };
    1069             : 
    1070             : /************************************************************************/
    1071             : /*                         CurlRequestHelper                            */
    1072             : /************************************************************************/
    1073             : 
    1074             : struct CurlRequestHelper
    1075             : {
    1076             :     WriteFuncStruct sWriteFuncData{};
    1077             :     WriteFuncStruct sWriteFuncHeaderData{};
    1078             :     char szCurlErrBuf[CURL_ERROR_SIZE + 1] = {};
    1079             : 
    1080             :     CurlRequestHelper();
    1081             :     ~CurlRequestHelper();
    1082             :     long perform(CURL *hCurlHandle,
    1083             :                  struct curl_slist *headers,  // ownership transferred
    1084             :                  VSICurlFilesystemHandlerBase *poFS,
    1085             :                  IVSIS3LikeHandleHelper *poS3HandleHelper);
    1086             : };
    1087             : 
    1088             : /************************************************************************/
    1089             : /*                       NetworkStatisticsLogger                        */
    1090             : /************************************************************************/
    1091             : 
    1092             : class NetworkStatisticsLogger
    1093             : {
    1094             :     static int gnEnabled;
    1095             :     static NetworkStatisticsLogger gInstance;
    1096             : 
    1097        1514 :     NetworkStatisticsLogger() = default;
    1098             : 
    1099             :     std::mutex m_mutex{};
    1100             : 
    1101             :     struct Counters
    1102             :     {
    1103             :         GIntBig nHEAD = 0;
    1104             :         GIntBig nGET = 0;
    1105             :         GIntBig nPUT = 0;
    1106             :         GIntBig nPOST = 0;
    1107             :         GIntBig nDELETE = 0;
    1108             :         GIntBig nGETDownloadedBytes = 0;
    1109             :         GIntBig nPUTUploadedBytes = 0;
    1110             :         GIntBig nPOSTDownloadedBytes = 0;
    1111             :         GIntBig nPOSTUploadedBytes = 0;
    1112             :     };
    1113             : 
    1114             :     enum class ContextPathType
    1115             :     {
    1116             :         FILESYSTEM,
    1117             :         FILE,
    1118             :         ACTION,
    1119             :     };
    1120             : 
    1121             :     struct ContextPathItem
    1122             :     {
    1123             :         ContextPathType eType;
    1124             :         std::string osName;
    1125             : 
    1126           3 :         ContextPathItem(ContextPathType eTypeIn, const std::string &osNameIn)
    1127           3 :             : eType(eTypeIn), osName(osNameIn)
    1128             :         {
    1129           3 :         }
    1130             : 
    1131           0 :         bool operator<(const ContextPathItem &other) const
    1132             :         {
    1133           0 :             if (static_cast<int>(eType) < static_cast<int>(other.eType))
    1134           0 :                 return true;
    1135           0 :             if (static_cast<int>(eType) > static_cast<int>(other.eType))
    1136           0 :                 return false;
    1137           0 :             return osName < other.osName;
    1138             :         }
    1139             :     };
    1140             : 
    1141             :     struct Stats
    1142             :     {
    1143             :         Counters counters{};
    1144             :         std::map<ContextPathItem, Stats> children{};
    1145             : 
    1146             :         void AsJSON(CPLJSONObject &oJSON) const;
    1147             :     };
    1148             : 
    1149             :     // Workaround bug in Coverity Scan
    1150             :     // coverity[generated_default_constructor_used_in_field_initializer]
    1151             :     Stats m_stats{};
    1152             :     std::map<GIntBig, std::vector<ContextPathItem>>
    1153             :         m_mapThreadIdToContextPath{};
    1154             : 
    1155             :     static void ReadEnabled();
    1156             : 
    1157             :     std::vector<Counters *> GetCountersForContext();
    1158             : 
    1159             :   public:
    1160      283107 :     static inline bool IsEnabled()
    1161             :     {
    1162      283107 :         if (gnEnabled < 0)
    1163             :         {
    1164           8 :             ReadEnabled();
    1165             :         }
    1166      283107 :         return gnEnabled == TRUE;
    1167             :     }
    1168             : 
    1169             :     static void EnterFileSystem(const char *pszName);
    1170             : 
    1171             :     static void LeaveFileSystem();
    1172             : 
    1173             :     static void EnterFile(const char *pszName);
    1174             : 
    1175             :     static void LeaveFile();
    1176             : 
    1177             :     static void EnterAction(const char *pszName);
    1178             : 
    1179             :     static void LeaveAction();
    1180             : 
    1181             :     static void LogHEAD();
    1182             : 
    1183             :     static void LogGET(size_t nDownloadedBytes);
    1184             : 
    1185             :     static void LogPUT(size_t nUploadedBytes);
    1186             : 
    1187             :     static void LogPOST(size_t nUploadedBytes, size_t nDownloadedBytes);
    1188             : 
    1189             :     static void LogDELETE();
    1190             : 
    1191             :     static void Reset();
    1192             : 
    1193             :     static std::string GetReportAsSerializedJSON();
    1194             : };
    1195             : 
    1196             : struct NetworkStatisticsFileSystem
    1197             : {
    1198       47487 :     inline explicit NetworkStatisticsFileSystem(const char *pszName)
    1199             :     {
    1200       47487 :         NetworkStatisticsLogger::EnterFileSystem(pszName);
    1201       47487 :     }
    1202             : 
    1203       47487 :     inline ~NetworkStatisticsFileSystem()
    1204             :     {
    1205       47487 :         NetworkStatisticsLogger::LeaveFileSystem();
    1206       47487 :     }
    1207             : };
    1208             : 
    1209             : struct NetworkStatisticsFile
    1210             : {
    1211       45942 :     inline explicit NetworkStatisticsFile(const char *pszName)
    1212             :     {
    1213       45942 :         NetworkStatisticsLogger::EnterFile(pszName);
    1214       45942 :     }
    1215             : 
    1216       45942 :     inline ~NetworkStatisticsFile()
    1217             :     {
    1218       45942 :         NetworkStatisticsLogger::LeaveFile();
    1219       45942 :     }
    1220             : };
    1221             : 
    1222             : struct NetworkStatisticsAction
    1223             : {
    1224       47487 :     inline explicit NetworkStatisticsAction(const char *pszName)
    1225             :     {
    1226       47487 :         NetworkStatisticsLogger::EnterAction(pszName);
    1227       47487 :     }
    1228             : 
    1229       47487 :     inline ~NetworkStatisticsAction()
    1230             :     {
    1231       47487 :         NetworkStatisticsLogger::LeaveAction();
    1232       47487 :     }
    1233             : };
    1234             : 
    1235             : }  // namespace cpl
    1236             : 
    1237             : int VSICURLGetDownloadChunkSize();
    1238             : 
    1239             : void VSICURLInitWriteFuncStruct(cpl::WriteFuncStruct *psStruct, VSILFILE *fp,
    1240             :                                 VSICurlReadCbkFunc pfnReadCbk,
    1241             :                                 void *pReadCbkUserData);
    1242             : size_t VSICurlHandleWriteFunc(void *buffer, size_t count, size_t nmemb,
    1243             :                               void *req);
    1244             : void VSICURLMultiPerform(CURLM *hCurlMultiHandle, CURL *hEasyHandle = nullptr,
    1245             :                          std::atomic<bool> *pbInterrupt = nullptr);
    1246             : void VSICURLResetHeaderAndWriterFunctions(CURL *hCurlHandle);
    1247             : 
    1248             : int VSICurlParseUnixPermissions(const char *pszPermissions);
    1249             : 
    1250             : // Cache of file properties (size, etc.)
    1251             : bool VSICURLGetCachedFileProp(const char *pszURL, cpl::FileProp &oFileProp);
    1252             : void VSICURLSetCachedFileProp(const char *pszURL, cpl::FileProp &oFileProp);
    1253             : void VSICURLInvalidateCachedFileProp(const char *pszURL);
    1254             : void VSICURLInvalidateCachedFilePropPrefix(const char *pszURL);
    1255             : void VSICURLDestroyCacheFileProp();
    1256             : 
    1257             : void VSICURLMultiCleanup(CURLM *hCurlMultiHandle);
    1258             : 
    1259             : //! @endcond
    1260             : 
    1261             : #endif  // HAVE_CURL
    1262             : 
    1263             : #endif  // CPL_VSIL_CURL_CLASS_H_INCLUDED

Generated by: LCOV version 1.14