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