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