LCOV - code coverage report
Current view: top level - port - cpl_vsil_curl_class.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 105 117 89.7 %
Date: 2024-04-28 23:18:46 Functions: 44 49 89.8 %

          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             :  * 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             : #ifndef CPL_VSIL_CURL_CLASS_H_INCLUDED
      30             : #define CPL_VSIL_CURL_CLASS_H_INCLUDED
      31             : 
      32             : #ifdef HAVE_CURL
      33             : 
      34             : #include "cpl_aws.h"
      35             : #include "cpl_azure.h"
      36             : #include "cpl_port.h"
      37             : #include "cpl_json.h"
      38             : #include "cpl_string.h"
      39             : #include "cpl_vsil_curl_priv.h"
      40             : #include "cpl_mem_cache.h"
      41             : 
      42             : #include "cpl_curl_priv.h"
      43             : 
      44             : #include <algorithm>
      45             : #include <condition_variable>
      46             : #include <set>
      47             : #include <map>
      48             : #include <memory>
      49             : #include <mutex>
      50             : #include <thread>
      51             : #include <utility>
      52             : 
      53             : // To avoid aliasing to CopyFile to CopyFileA on Windows
      54             : #ifdef CopyFile
      55             : #undef CopyFile
      56             : #endif
      57             : 
      58             : //! @cond Doxygen_Suppress
      59             : 
      60             : // Leave it for backward compatibility, but deprecate.
      61             : #define HAVE_CURLINFO_REDIRECT_URL
      62             : 
      63             : void VSICurlStreamingClearCache(void);  // from cpl_vsil_curl_streaming.cpp
      64             : 
      65             : struct curl_slist *VSICurlSetOptions(CURL *hCurlHandle, const char *pszURL,
      66             :                                      const char *const *papszOptions);
      67             : struct curl_slist *VSICurlMergeHeaders(struct curl_slist *poDest,
      68             :                                        struct curl_slist *poSrcToDestroy);
      69             : 
      70             : struct curl_slist *VSICurlSetContentTypeFromExt(struct curl_slist *polist,
      71             :                                                 const char *pszPath);
      72             : 
      73             : struct curl_slist *VSICurlSetCreationHeadersFromOptions(
      74             :     struct curl_slist *headers, CSLConstList papszOptions, const char *pszPath);
      75             : 
      76             : namespace cpl
      77             : {
      78             : 
      79             : typedef enum
      80             : {
      81             :     EXIST_UNKNOWN = -1,
      82             :     EXIST_NO,
      83             :     EXIST_YES,
      84             : } ExistStatus;
      85             : 
      86             : class FileProp
      87             : {
      88             :   public:
      89             :     unsigned int nGenerationAuthParameters = 0;
      90             :     ExistStatus eExists = EXIST_UNKNOWN;
      91             :     int nHTTPCode = 0;
      92             :     vsi_l_offset fileSize = 0;
      93             :     time_t mTime = 0;
      94             :     time_t nExpireTimestampLocal = 0;
      95             :     std::string osRedirectURL{};
      96             :     bool bHasComputedFileSize = false;
      97             :     bool bIsDirectory = false;
      98             :     int nMode = 0;  // st_mode member of struct stat
      99             :     bool bS3LikeRedirect = false;
     100             :     std::string ETag{};
     101             : };
     102             : 
     103             : struct CachedDirList
     104             : {
     105             :     bool bGotFileList = false;
     106             :     unsigned int nGenerationAuthParameters = 0;
     107             :     CPLStringList oFileList{}; /* only file name without path */
     108             : };
     109             : 
     110             : struct WriteFuncStruct
     111             : {
     112             :     char *pBuffer = nullptr;
     113             :     size_t nSize = 0;
     114             :     bool bIsHTTP = false;
     115             :     bool bMultiRange = false;
     116             :     vsi_l_offset nStartOffset = 0;
     117             :     vsi_l_offset nEndOffset = 0;
     118             :     int nHTTPCode = 0;
     119             :     vsi_l_offset nContentLength = 0;
     120             :     bool bFoundContentRange = false;
     121             :     bool bError = false;
     122             :     bool bInterruptDownload = false;
     123             :     bool bDetectRangeDownloadingError = false;
     124             :     GIntBig nTimestampDate = 0;  // Corresponds to Date: header field
     125             : 
     126             :     VSILFILE *fp = nullptr;
     127             :     VSICurlReadCbkFunc pfnReadCbk = nullptr;
     128             :     void *pReadCbkUserData = nullptr;
     129             :     bool bInterrupted = false;
     130             : };
     131             : 
     132             : struct PutData
     133             : {
     134             :     const GByte *pabyData = nullptr;
     135             :     size_t nOff = 0;
     136             :     size_t nTotalSize = 0;
     137             : 
     138          22 :     static size_t ReadCallBackBuffer(char *buffer, size_t size, size_t nitems,
     139             :                                      void *instream)
     140             :     {
     141          22 :         PutData *poThis = static_cast<PutData *>(instream);
     142          22 :         const size_t nSizeMax = size * nitems;
     143             :         const size_t nSizeToWrite =
     144          22 :             std::min(nSizeMax, poThis->nTotalSize - poThis->nOff);
     145          22 :         memcpy(buffer, poThis->pabyData + poThis->nOff, nSizeToWrite);
     146          22 :         poThis->nOff += nSizeToWrite;
     147          22 :         return nSizeToWrite;
     148             :     }
     149             : };
     150             : 
     151             : /************************************************************************/
     152             : /*                     VSICurlFilesystemHandler                         */
     153             : /************************************************************************/
     154             : 
     155             : class VSICurlHandle;
     156             : 
     157             : class VSICurlFilesystemHandlerBase : public VSIFilesystemHandler
     158             : {
     159             :     CPL_DISALLOW_COPY_ASSIGN(VSICurlFilesystemHandlerBase)
     160             : 
     161             :     struct FilenameOffsetPair
     162             :     {
     163             :         std::string filename_;
     164             :         vsi_l_offset offset_;
     165             : 
     166       45878 :         FilenameOffsetPair(const std::string &filename, vsi_l_offset offset)
     167       45878 :             : filename_(filename), offset_(offset)
     168             :         {
     169       45878 :         }
     170             : 
     171       45275 :         bool operator==(const FilenameOffsetPair &other) const
     172             :         {
     173       45275 :             return filename_ == other.filename_ && offset_ == other.offset_;
     174             :         }
     175             :     };
     176             : 
     177             :     struct FilenameOffsetPairHasher
     178             :     {
     179       46224 :         std::size_t operator()(const FilenameOffsetPair &k) const
     180             :         {
     181       46224 :             return std::hash<std::string>()(k.filename_) ^
     182       46224 :                    std::hash<vsi_l_offset>()(k.offset_);
     183             :         }
     184             :     };
     185             : 
     186             :     using RegionCacheType = lru11::Cache<
     187             :         FilenameOffsetPair, std::shared_ptr<std::string>, lru11::NullLock,
     188             :         std::unordered_map<
     189             :             FilenameOffsetPair,
     190             :             typename std::list<lru11::KeyValuePair<
     191             :                 FilenameOffsetPair, std::shared_ptr<std::string>>>::iterator,
     192             :             FilenameOffsetPairHasher>>;
     193             : 
     194             :     std::unique_ptr<RegionCacheType>
     195             :         m_poRegionCacheDoNotUseDirectly{};  // do not access directly. Use
     196             :                                             // GetRegionCache();
     197             :     RegionCacheType *GetRegionCache();
     198             : 
     199             :     // LRU cache that just keeps in memory if this file system handler is
     200             :     // spposed to know the file properties of a file. The actual cache is a
     201             :     // shared one among all network file systems.
     202             :     // The aim of that design is that invalidating /vsis3/foo results in
     203             :     // /vsis3_streaming/foo to be invalidated as well.
     204             :     lru11::Cache<std::string, bool> oCacheFileProp;
     205             : 
     206             :     int nCachedFilesInDirList = 0;
     207             :     lru11::Cache<std::string, CachedDirList> oCacheDirList;
     208             : 
     209             :     char **ParseHTMLFileList(const char *pszFilename, int nMaxFiles,
     210             :                              char *pszData, bool *pbGotFileList);
     211             : 
     212             :     // Data structure and map to store regions that are in progress, to
     213             :     // avoid simultaneous downloads of the same region in different threads
     214             :     // Cf https://github.com/OSGeo/gdal/issues/8041
     215             :     struct RegionInDownload
     216             :     {
     217             :         std::mutex oMutex{};
     218             :         std::condition_variable oCond{};
     219             :         bool bDownloadInProgress = false;
     220             :         int nWaiters = 0;
     221             :         std::string osData{};
     222             :     };
     223             : 
     224             :     std::mutex m_oMutex{};
     225             :     std::map<std::string, std::unique_ptr<RegionInDownload>>
     226             :         m_oMapRegionInDownload{};
     227             : 
     228             :   protected:
     229             :     CPLMutex *hMutex = nullptr;
     230             : 
     231             :     virtual VSICurlHandle *CreateFileHandle(const char *pszFilename);
     232             :     virtual char **GetFileList(const char *pszFilename, int nMaxFiles,
     233             :                                bool *pbGotFileList);
     234             : 
     235             :     void RegisterEmptyDir(const std::string &osDirname);
     236             : 
     237             :     bool
     238             :     AnalyseS3FileList(const std::string &osBaseURL, const char *pszXML,
     239             :                       CPLStringList &osFileList, int nMaxFiles,
     240             :                       const std::set<std::string> &oSetIgnoredStorageClasses,
     241             :                       bool &bIsTruncated);
     242             : 
     243             :     void AnalyseSwiftFileList(const std::string &osBaseURL,
     244             :                               const std::string &osPrefix, const char *pszJson,
     245             :                               CPLStringList &osFileList, int nMaxFilesThisQuery,
     246             :                               int nMaxFiles, bool &bIsTruncated,
     247             :                               std::string &osNextMarker);
     248             : 
     249             :     static const char *GetOptionsStatic();
     250             : 
     251             :     VSICurlFilesystemHandlerBase();
     252             : 
     253             :   public:
     254             :     ~VSICurlFilesystemHandlerBase() override;
     255             : 
     256             :     static bool IsAllowedFilename(const char *pszFilename);
     257             : 
     258             :     VSIVirtualHandle *Open(const char *pszFilename, const char *pszAccess,
     259             :                            bool bSetError,
     260             :                            CSLConstList /* papszOptions */) override;
     261             : 
     262             :     int Stat(const char *pszFilename, VSIStatBufL *pStatBuf,
     263             :              int nFlags) override;
     264             :     int Unlink(const char *pszFilename) override;
     265             :     int Rename(const char *oldpath, const char *newpath) override;
     266             :     int Mkdir(const char *pszDirname, long nMode) override;
     267             :     int Rmdir(const char *pszDirname) override;
     268             :     char **ReadDirEx(const char *pszDirname, int nMaxFiles) override;
     269             :     char **SiblingFiles(const char *pszFilename) override;
     270             : 
     271          12 :     int HasOptimizedReadMultiRange(const char * /* pszPath */) override
     272             :     {
     273          12 :         return true;
     274             :     }
     275             : 
     276             :     const char *GetActualURL(const char *pszFilename) override;
     277             : 
     278             :     const char *GetOptions() override;
     279             : 
     280             :     char **GetFileMetadata(const char *pszFilename, const char *pszDomain,
     281             :                            CSLConstList papszOptions) override;
     282             : 
     283             :     char **ReadDirInternal(const char *pszDirname, int nMaxFiles,
     284             :                            bool *pbGotFileList);
     285             :     void InvalidateDirContent(const char *pszDirname);
     286             : 
     287             :     virtual const char *GetDebugKey() const = 0;
     288             : 
     289             :     virtual std::string GetFSPrefix() const = 0;
     290             :     virtual bool AllowCachedDataFor(const char *pszFilename);
     291             : 
     292           1 :     virtual bool IsLocal(const char * /* pszPath */) override
     293             :     {
     294           1 :         return false;
     295             :     }
     296             : 
     297             :     virtual bool
     298           2 :     SupportsSequentialWrite(const char * /* pszPath */,
     299             :                             bool /* bAllowLocalTempFile */) override
     300             :     {
     301           2 :         return false;
     302             :     }
     303             : 
     304           1 :     virtual bool SupportsRandomWrite(const char * /* pszPath */,
     305             :                                      bool /* bAllowLocalTempFile */) override
     306             :     {
     307           1 :         return false;
     308             :     }
     309             : 
     310             :     std::shared_ptr<std::string> GetRegion(const char *pszURL,
     311             :                                            vsi_l_offset nFileOffsetStart);
     312             : 
     313             :     void AddRegion(const char *pszURL, vsi_l_offset nFileOffsetStart,
     314             :                    size_t nSize, const char *pData);
     315             : 
     316             :     std::pair<bool, std::string>
     317             :     NotifyStartDownloadRegion(const std::string &osURL,
     318             :                               vsi_l_offset startOffset, int nBlocks);
     319             :     void NotifyStopDownloadRegion(const std::string &osURL,
     320             :                                   vsi_l_offset startOffset, int nBlocks,
     321             :                                   const std::string &osData);
     322             : 
     323             :     bool GetCachedFileProp(const char *pszURL, FileProp &oFileProp);
     324             :     void SetCachedFileProp(const char *pszURL, FileProp &oFileProp);
     325             :     void InvalidateCachedData(const char *pszURL);
     326             : 
     327             :     CURLM *GetCurlMultiHandleFor(const std::string &osURL);
     328             : 
     329             :     virtual void ClearCache();
     330             :     virtual void PartialClearCache(const char *pszFilename);
     331             : 
     332             :     bool GetCachedDirList(const char *pszURL, CachedDirList &oCachedDirList);
     333             :     void SetCachedDirList(const char *pszURL, CachedDirList &oCachedDirList);
     334             :     bool ExistsInCacheDirList(const std::string &osDirname, bool *pbIsDir);
     335             : 
     336             :     virtual std::string GetURLFromFilename(const std::string &osFilename);
     337             : 
     338             :     std::string
     339             :     GetStreamingFilename(const std::string &osFilename) const override = 0;
     340             : 
     341             :     static std::set<std::string> GetS3IgnoredStorageClasses();
     342             : };
     343             : 
     344             : class VSICurlFilesystemHandler : public VSICurlFilesystemHandlerBase
     345             : {
     346             :     CPL_DISALLOW_COPY_ASSIGN(VSICurlFilesystemHandler)
     347             : 
     348             :   public:
     349        1227 :     VSICurlFilesystemHandler() = default;
     350             : 
     351         401 :     const char *GetDebugKey() const override
     352             :     {
     353         401 :         return "VSICURL";
     354             :     }
     355             : 
     356       46430 :     std::string GetFSPrefix() const override
     357             :     {
     358       46430 :         return "/vsicurl/";
     359             :     }
     360             : 
     361             :     std::string
     362             :     GetStreamingFilename(const std::string &osFilename) const override;
     363             : };
     364             : 
     365             : /************************************************************************/
     366             : /*                           VSICurlHandle                              */
     367             : /************************************************************************/
     368             : 
     369             : class VSICurlHandle : public VSIVirtualHandle
     370             : {
     371             :     CPL_DISALLOW_COPY_ASSIGN(VSICurlHandle)
     372             : 
     373             :   protected:
     374             :     VSICurlFilesystemHandlerBase *poFS = nullptr;
     375             : 
     376             :     bool m_bCached = true;
     377             : 
     378             :     mutable FileProp oFileProp{};
     379             : 
     380             :     mutable std::mutex m_oMutex{};
     381             :     std::string m_osFilename{};  // e.g "/vsicurl/http://example.com/foo"
     382             :     char *m_pszURL = nullptr;    // e.g "http://example.com/foo"
     383             :     mutable std::string m_osQueryString{};  // e.g. an Azure SAS
     384             : 
     385             :     char **m_papszHTTPOptions = nullptr;
     386             : 
     387             :     vsi_l_offset lastDownloadedOffset = VSI_L_OFFSET_MAX;
     388             :     int nBlocksToDownload = 1;
     389             : 
     390             :     bool bStopOnInterruptUntilUninstall = false;
     391             :     bool bInterrupted = false;
     392             :     VSICurlReadCbkFunc pfnReadCbk = nullptr;
     393             :     void *pReadCbkUserData = nullptr;
     394             : 
     395             :     int m_nMaxRetry = 0;
     396             :     double m_dfRetryDelay = 0.0;
     397             : 
     398             :     CPLStringList m_aosHeaders{};
     399             : 
     400             :     void DownloadRegionPostProcess(const vsi_l_offset startOffset,
     401             :                                    const int nBlocks, const char *pBuffer,
     402             :                                    size_t nSize);
     403             : 
     404             :   private:
     405             :     vsi_l_offset curOffset = 0;
     406             : 
     407             :     bool bEOF = false;
     408             : 
     409             :     virtual std::string DownloadRegion(vsi_l_offset startOffset, int nBlocks);
     410             : 
     411             :     bool m_bUseHead = false;
     412             :     bool m_bUseRedirectURLIfNoQueryStringParams = false;
     413             : 
     414             :     // Specific to Planetary Computer signing:
     415             :     // https://planetarycomputer.microsoft.com/docs/concepts/sas/
     416             :     mutable bool m_bPlanetaryComputerURLSigning = false;
     417             :     mutable std::string m_osPlanetaryComputerCollection{};
     418             :     void ManagePlanetaryComputerSigning() const;
     419             : 
     420             :     int ReadMultiRangeSingleGet(int nRanges, void **ppData,
     421             :                                 const vsi_l_offset *panOffsets,
     422             :                                 const size_t *panSizes);
     423             :     std::string GetRedirectURLIfValid(bool &bHasExpired) const;
     424             : 
     425             :     void UpdateRedirectInfo(CURL *hCurlHandle,
     426             :                             const WriteFuncStruct &sWriteFuncHeaderData);
     427             : 
     428             :     // Used by AdviseRead()
     429             :     struct AdviseReadRange
     430             :     {
     431             :         bool bDone = false;
     432             :         std::mutex oMutex{};
     433             :         std::condition_variable oCV{};
     434             :         vsi_l_offset nStartOffset = 0;
     435             :         size_t nSize = 0;
     436             :         std::vector<GByte> abyData{};
     437             :     };
     438             : 
     439             :     std::vector<std::unique_ptr<AdviseReadRange>> m_aoAdviseReadRanges{};
     440             :     std::thread m_oThreadAdviseRead{};
     441             : 
     442             :   protected:
     443             :     virtual struct curl_slist *
     444         290 :     GetCurlHeaders(const std::string & /*osVerb*/,
     445             :                    const struct curl_slist * /* psExistingHeaders */)
     446             :     {
     447         290 :         return nullptr;
     448             :     }
     449             : 
     450         359 :     virtual bool AllowAutomaticRedirection()
     451             :     {
     452         359 :         return true;
     453             :     }
     454             : 
     455           1 :     virtual bool CanRestartOnError(const char *, const char *, bool)
     456             :     {
     457           1 :         return false;
     458             :     }
     459             : 
     460         410 :     virtual bool UseLimitRangeGetInsteadOfHead()
     461             :     {
     462         410 :         return false;
     463             :     }
     464             : 
     465         136 :     virtual bool IsDirectoryFromExists(const char * /*pszVerb*/,
     466             :                                        int /*response_code*/)
     467             :     {
     468         136 :         return false;
     469             :     }
     470             : 
     471          56 :     virtual void ProcessGetFileSizeResult(const char * /* pszContent */)
     472             :     {
     473          56 :     }
     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             :     int Eof() override;
     495             :     int Flush() override;
     496             :     int Close() override;
     497             : 
     498          12 :     bool HasPRead() const override
     499             :     {
     500          12 :         return true;
     501             :     }
     502             : 
     503             :     size_t PRead(void *pBuffer, size_t nSize,
     504             :                  vsi_l_offset nOffset) const override;
     505             : 
     506             :     void AdviseRead(int nRanges, const vsi_l_offset *panOffsets,
     507             :                     const size_t *panSizes) override;
     508             : 
     509             :     size_t GetAdviseReadTotalBytesLimit() const override;
     510             : 
     511         446 :     bool IsKnownFileSize() const
     512             :     {
     513         446 :         return oFileProp.bHasComputedFileSize;
     514             :     }
     515             : 
     516             :     vsi_l_offset GetFileSizeOrHeaders(bool bSetError, bool bGetHeaders);
     517             : 
     518         738 :     virtual vsi_l_offset GetFileSize(bool bSetError)
     519             :     {
     520         738 :         return GetFileSizeOrHeaders(bSetError, false);
     521             :     }
     522             : 
     523             :     bool Exists(bool bSetError);
     524             : 
     525         561 :     bool IsDirectory() const
     526             :     {
     527         561 :         return oFileProp.bIsDirectory;
     528             :     }
     529             : 
     530         446 :     int GetMode() const
     531             :     {
     532         446 :         return oFileProp.nMode;
     533             :     }
     534             : 
     535         446 :     time_t GetMTime() const
     536             :     {
     537         446 :         return oFileProp.mTime;
     538             :     }
     539             : 
     540           4 :     const CPLStringList &GetHeaders()
     541             :     {
     542           4 :         return m_aosHeaders;
     543             :     }
     544             : 
     545             :     int InstallReadCbk(VSICurlReadCbkFunc pfnReadCbk, void *pfnUserData,
     546             :                        int bStopOnInterruptUntilUninstall);
     547             :     int UninstallReadCbk();
     548             : 
     549           5 :     const char *GetURL() const
     550             :     {
     551           5 :         return m_pszURL;
     552             :     }
     553             : };
     554             : 
     555             : /************************************************************************/
     556             : /*                  VSICurlFilesystemHandlerBaseWritable                */
     557             : /************************************************************************/
     558             : 
     559             : class VSICurlFilesystemHandlerBaseWritable : public VSICurlFilesystemHandlerBase
     560             : {
     561             :     CPL_DISALLOW_COPY_ASSIGN(VSICurlFilesystemHandlerBaseWritable)
     562             : 
     563             :   protected:
     564        8589 :     VSICurlFilesystemHandlerBaseWritable() = default;
     565             : 
     566             :     virtual VSIVirtualHandleUniquePtr
     567             :     CreateWriteHandle(const char *pszFilename, CSLConstList papszOptions) = 0;
     568             : 
     569             :   public:
     570             :     VSIVirtualHandle *Open(const char *pszFilename, const char *pszAccess,
     571             :                            bool bSetError, CSLConstList papszOptions) override;
     572             : 
     573           1 :     bool SupportsSequentialWrite(const char * /* pszPath */,
     574             :                                  bool /* bAllowLocalTempFile */) override
     575             :     {
     576           1 :         return true;
     577             :     }
     578             : 
     579             :     bool SupportsRandomWrite(const char * /* pszPath */,
     580             :                              bool /* bAllowLocalTempFile */) override;
     581             : };
     582             : 
     583             : /************************************************************************/
     584             : /*                        IVSIS3LikeFSHandler                           */
     585             : /************************************************************************/
     586             : 
     587             : class IVSIS3LikeFSHandler : public VSICurlFilesystemHandlerBaseWritable
     588             : {
     589             :     CPL_DISALLOW_COPY_ASSIGN(IVSIS3LikeFSHandler)
     590             : 
     591             :     virtual int MkdirInternal(const char *pszDirname, long nMode,
     592             :                               bool bDoStatCheck);
     593             : 
     594             :   protected:
     595             :     char **GetFileList(const char *pszFilename, int nMaxFiles,
     596             :                        bool *pbGotFileList) override;
     597             : 
     598             :     virtual IVSIS3LikeHandleHelper *CreateHandleHelper(const char *pszURI,
     599             :                                                        bool bAllowNoObject) = 0;
     600             : 
     601             :     virtual int CopyObject(const char *oldpath, const char *newpath,
     602             :                            CSLConstList papszMetadata);
     603             : 
     604             :     int RmdirRecursiveInternal(const char *pszDirname, int nBatchSize);
     605             : 
     606             :     virtual bool
     607           0 :     IsAllowedHeaderForObjectCreation(const char * /* pszHeaderName */)
     608             :     {
     609           0 :         return false;
     610             :     }
     611             : 
     612        7362 :     IVSIS3LikeFSHandler() = default;
     613             : 
     614             :   public:
     615             :     int Unlink(const char *pszFilename) override;
     616             :     int Mkdir(const char *pszDirname, long nMode) override;
     617             :     int Rmdir(const char *pszDirname) override;
     618             :     int Stat(const char *pszFilename, VSIStatBufL *pStatBuf,
     619             :              int nFlags) override;
     620             :     int Rename(const char *oldpath, const char *newpath) override;
     621             : 
     622             :     virtual int CopyFile(const char *pszSource, const char *pszTarget,
     623             :                          VSILFILE *fpSource, vsi_l_offset nSourceSize,
     624             :                          const char *const *papszOptions,
     625             :                          GDALProgressFunc pProgressFunc,
     626             :                          void *pProgressData) override;
     627             : 
     628             :     virtual int DeleteObject(const char *pszFilename);
     629             : 
     630             :     bool Sync(const char *pszSource, const char *pszTarget,
     631             :               const char *const *papszOptions, GDALProgressFunc pProgressFunc,
     632             :               void *pProgressData, char ***ppapszOutputs) override;
     633             : 
     634             :     VSIDIR *OpenDir(const char *pszPath, int nRecurseDepth,
     635             :                     const char *const *papszOptions) override;
     636             : 
     637             :     // Multipart upload
     638           0 :     virtual bool SupportsParallelMultipartUpload() const
     639             :     {
     640           0 :         return false;
     641             :     }
     642             : 
     643             :     virtual std::string InitiateMultipartUpload(
     644             :         const std::string &osFilename, IVSIS3LikeHandleHelper *poS3HandleHelper,
     645             :         int nMaxRetry, double dfRetryDelay, CSLConstList papszOptions);
     646             :     virtual std::string
     647             :     UploadPart(const std::string &osFilename, int nPartNumber,
     648             :                const std::string &osUploadID, vsi_l_offset nPosition,
     649             :                const void *pabyBuffer, size_t nBufferSize,
     650             :                IVSIS3LikeHandleHelper *poS3HandleHelper, int nMaxRetry,
     651             :                double dfRetryDelay, CSLConstList papszOptions);
     652             :     virtual bool CompleteMultipart(const std::string &osFilename,
     653             :                                    const std::string &osUploadID,
     654             :                                    const std::vector<std::string> &aosEtags,
     655             :                                    vsi_l_offset nTotalSize,
     656             :                                    IVSIS3LikeHandleHelper *poS3HandleHelper,
     657             :                                    int nMaxRetry, double dfRetryDelay);
     658             :     virtual bool AbortMultipart(const std::string &osFilename,
     659             :                                 const std::string &osUploadID,
     660             :                                 IVSIS3LikeHandleHelper *poS3HandleHelper,
     661             :                                 int nMaxRetry, double dfRetryDelay);
     662             : 
     663             :     bool AbortPendingUploads(const char *pszFilename) override;
     664             : };
     665             : 
     666             : /************************************************************************/
     667             : /*                          IVSIS3LikeHandle                            */
     668             : /************************************************************************/
     669             : 
     670             : class IVSIS3LikeHandle : public VSICurlHandle
     671             : {
     672             :     CPL_DISALLOW_COPY_ASSIGN(IVSIS3LikeHandle)
     673             : 
     674             :   protected:
     675         281 :     bool UseLimitRangeGetInsteadOfHead() override
     676             :     {
     677         281 :         return true;
     678             :     }
     679             : 
     680         103 :     bool IsDirectoryFromExists(const char *pszVerb, int response_code) override
     681             :     {
     682             :         // A bit dirty, but on S3, a GET on a existing directory returns a 416
     683         107 :         return response_code == 416 && EQUAL(pszVerb, "GET") &&
     684         107 :                std::string(m_pszURL).back() == '/';
     685             :     }
     686             : 
     687          48 :     void ProcessGetFileSizeResult(const char *pszContent) override
     688             :     {
     689          48 :         oFileProp.bIsDirectory =
     690          48 :             strstr(pszContent, "ListBucketResult") != nullptr;
     691          48 :     }
     692             : 
     693             :   public:
     694         241 :     IVSIS3LikeHandle(VSICurlFilesystemHandlerBase *poFSIn,
     695             :                      const char *pszFilename, const char *pszURLIn)
     696         241 :         : VSICurlHandle(poFSIn, pszFilename, pszURLIn)
     697             :     {
     698         241 :     }
     699             : 
     700         241 :     ~IVSIS3LikeHandle() override
     701         241 :     {
     702         241 :     }
     703             : };
     704             : 
     705             : /************************************************************************/
     706             : /*                            VSIS3WriteHandle                          */
     707             : /************************************************************************/
     708             : 
     709             : class VSIS3WriteHandle final : public VSIVirtualHandle
     710             : {
     711             :     CPL_DISALLOW_COPY_ASSIGN(VSIS3WriteHandle)
     712             : 
     713             :     IVSIS3LikeFSHandler *m_poFS = nullptr;
     714             :     std::string m_osFilename{};
     715             :     IVSIS3LikeHandleHelper *m_poS3HandleHelper = nullptr;
     716             :     bool m_bUseChunked = false;
     717             :     CPLStringList m_aosOptions{};
     718             :     CPLStringList m_aosHTTPOptions{};
     719             : 
     720             :     vsi_l_offset m_nCurOffset = 0;
     721             :     int m_nBufferOff = 0;
     722             :     int m_nBufferSize = 0;
     723             :     bool m_bClosed = false;
     724             :     GByte *m_pabyBuffer = nullptr;
     725             :     std::string m_osUploadID{};
     726             :     int m_nPartNumber = 0;
     727             :     std::vector<std::string> m_aosEtags{};
     728             :     bool m_bError = false;
     729             : 
     730             :     CURLM *m_hCurlMulti = nullptr;
     731             :     CURL *m_hCurl = nullptr;
     732             :     const void *m_pBuffer = nullptr;
     733             :     std::string m_osCurlErrBuf{};
     734             :     size_t m_nChunkedBufferOff = 0;
     735             :     size_t m_nChunkedBufferSize = 0;
     736             :     size_t m_nWrittenInPUT = 0;
     737             : 
     738             :     int m_nMaxRetry = 0;
     739             :     double m_dfRetryDelay = 0.0;
     740             :     WriteFuncStruct m_sWriteFuncHeaderData{};
     741             : 
     742             :     bool UploadPart();
     743             :     bool DoSinglePartPUT();
     744             : 
     745             :     static size_t ReadCallBackBufferChunked(char *buffer, size_t size,
     746             :                                             size_t nitems, void *instream);
     747             :     size_t WriteChunked(const void *pBuffer, size_t nSize, size_t nMemb);
     748             :     int FinishChunkedTransfer();
     749             : 
     750             :     void InvalidateParentDirectory();
     751             : 
     752             :   public:
     753             :     VSIS3WriteHandle(IVSIS3LikeFSHandler *poFS, const char *pszFilename,
     754             :                      IVSIS3LikeHandleHelper *poS3HandleHelper, bool bUseChunked,
     755             :                      CSLConstList papszOptions);
     756             :     ~VSIS3WriteHandle() override;
     757             : 
     758             :     int Seek(vsi_l_offset nOffset, int nWhence) override;
     759             :     vsi_l_offset Tell() override;
     760             :     size_t Read(void *pBuffer, size_t nSize, size_t nMemb) override;
     761             :     size_t Write(const void *pBuffer, size_t nSize, size_t nMemb) override;
     762             :     int Eof() override;
     763             :     int Close() override;
     764             : 
     765          48 :     bool IsOK()
     766             :     {
     767          48 :         return m_bUseChunked || m_pabyBuffer != nullptr;
     768             :     }
     769             : };
     770             : 
     771             : /************************************************************************/
     772             : /*                        VSIAppendWriteHandle                          */
     773             : /************************************************************************/
     774             : 
     775             : class VSIAppendWriteHandle : public VSIVirtualHandle
     776             : {
     777             :     CPL_DISALLOW_COPY_ASSIGN(VSIAppendWriteHandle)
     778             : 
     779             :   protected:
     780             :     VSICurlFilesystemHandlerBase *m_poFS = nullptr;
     781             :     std::string m_osFSPrefix{};
     782             :     std::string m_osFilename{};
     783             : 
     784             :     vsi_l_offset m_nCurOffset = 0;
     785             :     int m_nBufferOff = 0;
     786             :     int m_nBufferSize = 0;
     787             :     int m_nBufferOffReadCallback = 0;
     788             :     bool m_bClosed = false;
     789             :     GByte *m_pabyBuffer = nullptr;
     790             :     bool m_bError = false;
     791             : 
     792             :     static size_t ReadCallBackBuffer(char *buffer, size_t size, size_t nitems,
     793             :                                      void *instream);
     794             :     virtual bool Send(bool bIsLastBlock) = 0;
     795             : 
     796             :   public:
     797             :     VSIAppendWriteHandle(VSICurlFilesystemHandlerBase *poFS,
     798             :                          const char *pszFSPrefix, const char *pszFilename,
     799             :                          int nChunkSize);
     800             :     virtual ~VSIAppendWriteHandle();
     801             : 
     802             :     int Seek(vsi_l_offset nOffset, int nWhence) override;
     803             :     vsi_l_offset Tell() override;
     804             :     size_t Read(void *pBuffer, size_t nSize, size_t nMemb) override;
     805             :     size_t Write(const void *pBuffer, size_t nSize, size_t nMemb) override;
     806             :     int Eof() override;
     807             :     int Close() override;
     808             : 
     809          18 :     bool IsOK()
     810             :     {
     811          18 :         return m_pabyBuffer != nullptr;
     812             :     }
     813             : };
     814             : 
     815             : /************************************************************************/
     816             : /*                     VSIDIRWithMissingDirSynthesis                    */
     817             : /************************************************************************/
     818             : 
     819             : struct VSIDIRWithMissingDirSynthesis : public VSIDIR
     820             : {
     821             :     std::vector<std::unique_ptr<VSIDIREntry>> aoEntries{};
     822             : 
     823             :   protected:
     824             :     std::vector<std::string> m_aosSubpathsStack{};
     825             : 
     826             :     void SynthetizeMissingDirectories(const std::string &osCurSubdir,
     827             :                                       bool bAddEntryForThisSubdir);
     828             : };
     829             : 
     830             : /************************************************************************/
     831             : /*                         CurlRequestHelper                            */
     832             : /************************************************************************/
     833             : 
     834             : struct CurlRequestHelper
     835             : {
     836             :     WriteFuncStruct sWriteFuncData{};
     837             :     WriteFuncStruct sWriteFuncHeaderData{};
     838             :     char szCurlErrBuf[CURL_ERROR_SIZE + 1] = {};
     839             : 
     840             :     CurlRequestHelper();
     841             :     ~CurlRequestHelper();
     842             :     long perform(CURL *hCurlHandle,
     843             :                  struct curl_slist *headers,  // ownership transferred
     844             :                  VSICurlFilesystemHandlerBase *poFS,
     845             :                  IVSIS3LikeHandleHelper *poS3HandleHelper);
     846             : };
     847             : 
     848             : /************************************************************************/
     849             : /*                       NetworkStatisticsLogger                        */
     850             : /************************************************************************/
     851             : 
     852             : class NetworkStatisticsLogger
     853             : {
     854             :     static int gnEnabled;
     855             :     static NetworkStatisticsLogger gInstance;
     856             : 
     857        1241 :     NetworkStatisticsLogger() = default;
     858             : 
     859             :     std::mutex m_mutex{};
     860             : 
     861             :     struct Counters
     862             :     {
     863             :         GIntBig nHEAD = 0;
     864             :         GIntBig nGET = 0;
     865             :         GIntBig nPUT = 0;
     866             :         GIntBig nPOST = 0;
     867             :         GIntBig nDELETE = 0;
     868             :         GIntBig nGETDownloadedBytes = 0;
     869             :         GIntBig nPUTUploadedBytes = 0;
     870             :         GIntBig nPOSTDownloadedBytes = 0;
     871             :         GIntBig nPOSTUploadedBytes = 0;
     872             :     };
     873             : 
     874             :     enum class ContextPathType
     875             :     {
     876             :         FILESYSTEM,
     877             :         FILE,
     878             :         ACTION,
     879             :     };
     880             : 
     881             :     struct ContextPathItem
     882             :     {
     883             :         ContextPathType eType;
     884             :         std::string osName;
     885             : 
     886           3 :         ContextPathItem(ContextPathType eTypeIn, const std::string &osNameIn)
     887           3 :             : eType(eTypeIn), osName(osNameIn)
     888             :         {
     889           3 :         }
     890             : 
     891           0 :         bool operator<(const ContextPathItem &other) const
     892             :         {
     893           0 :             if (static_cast<int>(eType) < static_cast<int>(other.eType))
     894           0 :                 return true;
     895           0 :             if (static_cast<int>(eType) > static_cast<int>(other.eType))
     896           0 :                 return false;
     897           0 :             return osName < other.osName;
     898             :         }
     899             :     };
     900             : 
     901             :     struct Stats
     902             :     {
     903             :         Counters counters{};
     904             :         std::map<ContextPathItem, Stats> children{};
     905             : 
     906             :         void AsJSON(CPLJSONObject &oJSON) const;
     907             :     };
     908             : 
     909             :     // Workaround bug in Coverity Scan
     910             :     // coverity[generated_default_constructor_used_in_field_initializer]
     911             :     Stats m_stats{};
     912             :     std::map<GIntBig, std::vector<ContextPathItem>>
     913             :         m_mapThreadIdToContextPath{};
     914             : 
     915             :     static void ReadEnabled();
     916             : 
     917             :     std::vector<Counters *> GetCountersForContext();
     918             : 
     919             :   public:
     920      277580 :     static inline bool IsEnabled()
     921             :     {
     922      277580 :         if (gnEnabled < 0)
     923             :         {
     924           6 :             ReadEnabled();
     925             :         }
     926      277580 :         return gnEnabled == TRUE;
     927             :     }
     928             : 
     929             :     static void EnterFileSystem(const char *pszName);
     930             : 
     931             :     static void LeaveFileSystem();
     932             : 
     933             :     static void EnterFile(const char *pszName);
     934             : 
     935             :     static void LeaveFile();
     936             : 
     937             :     static void EnterAction(const char *pszName);
     938             : 
     939             :     static void LeaveAction();
     940             : 
     941             :     static void LogHEAD();
     942             : 
     943             :     static void LogGET(size_t nDownloadedBytes);
     944             : 
     945             :     static void LogPUT(size_t nUploadedBytes);
     946             : 
     947             :     static void LogPOST(size_t nUploadedBytes, size_t nDownloadedBytes);
     948             : 
     949             :     static void LogDELETE();
     950             : 
     951             :     static void Reset();
     952             : 
     953             :     static std::string GetReportAsSerializedJSON();
     954             : };
     955             : 
     956             : struct NetworkStatisticsFileSystem
     957             : {
     958       46504 :     inline explicit NetworkStatisticsFileSystem(const char *pszName)
     959             :     {
     960       46504 :         NetworkStatisticsLogger::EnterFileSystem(pszName);
     961       46504 :     }
     962             : 
     963       46504 :     inline ~NetworkStatisticsFileSystem()
     964             :     {
     965       46504 :         NetworkStatisticsLogger::LeaveFileSystem();
     966       46504 :     }
     967             : };
     968             : 
     969             : struct NetworkStatisticsFile
     970             : {
     971       45304 :     inline explicit NetworkStatisticsFile(const char *pszName)
     972             :     {
     973       45304 :         NetworkStatisticsLogger::EnterFile(pszName);
     974       45304 :     }
     975             : 
     976       45304 :     inline ~NetworkStatisticsFile()
     977             :     {
     978       45304 :         NetworkStatisticsLogger::LeaveFile();
     979       45304 :     }
     980             : };
     981             : 
     982             : struct NetworkStatisticsAction
     983             : {
     984       46504 :     inline explicit NetworkStatisticsAction(const char *pszName)
     985             :     {
     986       46504 :         NetworkStatisticsLogger::EnterAction(pszName);
     987       46504 :     }
     988             : 
     989       46504 :     inline ~NetworkStatisticsAction()
     990             :     {
     991       46504 :         NetworkStatisticsLogger::LeaveAction();
     992       46504 :     }
     993             : };
     994             : 
     995             : }  // namespace cpl
     996             : 
     997             : int VSICURLGetDownloadChunkSize();
     998             : 
     999             : void VSICURLInitWriteFuncStruct(cpl::WriteFuncStruct *psStruct, VSILFILE *fp,
    1000             :                                 VSICurlReadCbkFunc pfnReadCbk,
    1001             :                                 void *pReadCbkUserData);
    1002             : size_t VSICurlHandleWriteFunc(void *buffer, size_t count, size_t nmemb,
    1003             :                               void *req);
    1004             : void VSICURLMultiPerform(CURLM *hCurlMultiHandle, CURL *hEasyHandle = nullptr);
    1005             : void VSICURLResetHeaderAndWriterFunctions(CURL *hCurlHandle);
    1006             : 
    1007             : int VSICurlParseUnixPermissions(const char *pszPermissions);
    1008             : 
    1009             : // Cache of file properties (size, etc.)
    1010             : bool VSICURLGetCachedFileProp(const char *pszURL, cpl::FileProp &oFileProp);
    1011             : void VSICURLSetCachedFileProp(const char *pszURL, cpl::FileProp &oFileProp);
    1012             : void VSICURLInvalidateCachedFileProp(const char *pszURL);
    1013             : void VSICURLInvalidateCachedFilePropPrefix(const char *pszURL);
    1014             : void VSICURLDestroyCacheFileProp();
    1015             : 
    1016             : void VSICURLMultiCleanup(CURLM *hCurlMultiHandle);
    1017             : 
    1018             : //! @endcond
    1019             : 
    1020             : #endif  // HAVE_CURL
    1021             : 
    1022             : #endif  // CPL_VSIL_CURL_CLASS_H_INCLUDED

Generated by: LCOV version 1.14