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