LCOV - code coverage report
Current view: top level - port - cpl_alibaba_oss.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 164 175 93.7 %
Date: 2024-04-28 21:03:45 Functions: 16 16 100.0 %

          Line data    Source code
       1             : /**********************************************************************
       2             :  *
       3             :  * Name:     cpl_alibaba_oss.h
       4             :  * Project:  CPL - Common Portability Library
       5             :  * Purpose:  Alibaba Cloud Object Storage Service
       6             :  * Author:   Even Rouault <even.rouault at spatialys.com>
       7             :  *
       8             :  **********************************************************************
       9             :  * Copyright (c) 2017, Even Rouault <even.rouault at spatialys.com>
      10             :  *
      11             :  * Permission is hereby granted, free of charge, to any person obtaining a
      12             :  * copy of this software and associated documentation files (the "Software"),
      13             :  * to deal in the Software without restriction, including without limitation
      14             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15             :  * and/or sell copies of the Software, and to permit persons to whom the
      16             :  * Software is furnished to do so, subject to the following conditions:
      17             :  *
      18             :  * The above copyright notice and this permission notice shall be included
      19             :  * in all copies or substantial portions of the Software.
      20             :  *
      21             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27             :  * DEALINGS IN THE SOFTWARE.
      28             :  ****************************************************************************/
      29             : 
      30             : //! @cond Doxygen_Suppress
      31             : 
      32             : #include "cpl_alibaba_oss.h"
      33             : #include "cpl_vsi_error.h"
      34             : #include "cpl_time.h"
      35             : #include "cpl_minixml.h"
      36             : #include "cpl_multiproc.h"
      37             : #include "cpl_http.h"
      38             : #include "cpl_sha1.h"
      39             : #include <algorithm>
      40             : 
      41             : // #define DEBUG_VERBOSE 1
      42             : 
      43             : #ifdef HAVE_CURL
      44             : 
      45             : /************************************************************************/
      46             : /*                            GetSignature()                            */
      47             : /************************************************************************/
      48             : 
      49          90 : static std::string GetSignature(const std::string &osStringToSign,
      50             :                                 const std::string &osSecretAccessKey)
      51             : {
      52             : 
      53             :     /* -------------------------------------------------------------------- */
      54             :     /*      Compute signature.                                              */
      55             :     /* -------------------------------------------------------------------- */
      56          90 :     GByte abySignature[CPL_SHA1_HASH_SIZE] = {};
      57         180 :     CPL_HMAC_SHA1(osSecretAccessKey.c_str(), osSecretAccessKey.size(),
      58          90 :                   osStringToSign.c_str(), osStringToSign.size(), abySignature);
      59          90 :     char *pszBase64 = CPLBase64Encode(sizeof(abySignature), abySignature);
      60          90 :     std::string osSignature(pszBase64);
      61          90 :     CPLFree(pszBase64);
      62             : 
      63         180 :     return osSignature;
      64             : }
      65             : 
      66             : /************************************************************************/
      67             : /*                         CPLGetOSSHeaders()                           */
      68             : /************************************************************************/
      69             : 
      70             : // See:
      71             : // https://www.alibabacloud.com/help/doc-detail/31951.htm?spm=a3c0i.o31982en.b99.178.5HUTqV
      72             : static struct curl_slist *
      73          89 : CPLGetOSSHeaders(const std::string &osSecretAccessKey,
      74             :                  const std::string &osAccessKeyId, const std::string &osVerb,
      75             :                  const struct curl_slist *psExistingHeaders,
      76             :                  const std::string &osCanonicalizedResource)
      77             : {
      78         178 :     std::string osDate = CPLGetConfigOption("CPL_OSS_TIMESTAMP", "");
      79          89 :     if (osDate.empty())
      80             :     {
      81           0 :         osDate = IVSIS3LikeHandleHelper::GetRFC822DateTime();
      82             :     }
      83             : 
      84         178 :     std::map<std::string, std::string> oSortedMapHeaders;
      85             :     std::string osCanonicalizedHeaders(
      86             :         IVSIS3LikeHandleHelper::BuildCanonicalizedHeaders(
      87         178 :             oSortedMapHeaders, psExistingHeaders, "x-oss-"));
      88             : 
      89         178 :     std::string osStringToSign;
      90          89 :     osStringToSign += osVerb + "\n";
      91             :     osStringToSign +=
      92          89 :         CPLAWSGetHeaderVal(psExistingHeaders, "Content-MD5") + "\n";
      93             :     osStringToSign +=
      94          89 :         CPLAWSGetHeaderVal(psExistingHeaders, "Content-Type") + "\n";
      95          89 :     osStringToSign += osDate + "\n";
      96          89 :     osStringToSign += osCanonicalizedHeaders;
      97          89 :     osStringToSign += osCanonicalizedResource;
      98             : #ifdef DEBUG_VERBOSE
      99             :     CPLDebug("OSS", "osStringToSign = %s", osStringToSign.c_str());
     100             : #endif
     101             : 
     102             :     /* -------------------------------------------------------------------- */
     103             :     /*      Build authorization header.                                     */
     104             :     /* -------------------------------------------------------------------- */
     105             : 
     106          89 :     std::string osAuthorization("OSS ");
     107          89 :     osAuthorization += osAccessKeyId;
     108          89 :     osAuthorization += ":";
     109          89 :     osAuthorization += GetSignature(osStringToSign, osSecretAccessKey);
     110             : 
     111             : #ifdef DEBUG_VERBOSE
     112             :     CPLDebug("OSS", "osAuthorization='%s'", osAuthorization.c_str());
     113             : #endif
     114             : 
     115          89 :     struct curl_slist *headers = nullptr;
     116             :     headers =
     117          89 :         curl_slist_append(headers, CPLSPrintf("Date: %s", osDate.c_str()));
     118          89 :     headers = curl_slist_append(
     119             :         headers, CPLSPrintf("Authorization: %s", osAuthorization.c_str()));
     120         178 :     return headers;
     121             : }
     122             : 
     123             : /************************************************************************/
     124             : /*                         VSIOSSHandleHelper()                         */
     125             : /************************************************************************/
     126          96 : VSIOSSHandleHelper::VSIOSSHandleHelper(const std::string &osSecretAccessKey,
     127             :                                        const std::string &osAccessKeyId,
     128             :                                        const std::string &osEndpoint,
     129             :                                        const std::string &osBucket,
     130             :                                        const std::string &osObjectKey,
     131          96 :                                        bool bUseHTTPS, bool bUseVirtualHosting)
     132             :     : m_osURL(BuildURL(osEndpoint, osBucket, osObjectKey, bUseHTTPS,
     133             :                        bUseVirtualHosting)),
     134             :       m_osSecretAccessKey(osSecretAccessKey), m_osAccessKeyId(osAccessKeyId),
     135             :       m_osEndpoint(osEndpoint), m_osBucket(osBucket),
     136             :       m_osObjectKey(osObjectKey), m_bUseHTTPS(bUseHTTPS),
     137          96 :       m_bUseVirtualHosting(bUseVirtualHosting)
     138             : {
     139          96 :     VSIOSSUpdateParams::UpdateHandleFromMap(this);
     140          96 : }
     141             : 
     142             : /************************************************************************/
     143             : /*                        ~VSIOSSHandleHelper()                         */
     144             : /************************************************************************/
     145             : 
     146         192 : VSIOSSHandleHelper::~VSIOSSHandleHelper()
     147             : {
     148        2112 :     for (size_t i = 0; i < m_osSecretAccessKey.size(); i++)
     149        2016 :         m_osSecretAccessKey[i] = 0;
     150         192 : }
     151             : 
     152             : /************************************************************************/
     153             : /*                           BuildURL()                                 */
     154             : /************************************************************************/
     155             : 
     156         203 : std::string VSIOSSHandleHelper::BuildURL(const std::string &osEndpoint,
     157             :                                          const std::string &osBucket,
     158             :                                          const std::string &osObjectKey,
     159             :                                          bool bUseHTTPS,
     160             :                                          bool bUseVirtualHosting)
     161             : {
     162         203 :     const char *pszProtocol = (bUseHTTPS) ? "https" : "http";
     163         203 :     if (osBucket.empty())
     164             :     {
     165           8 :         return CPLSPrintf("%s://%s", pszProtocol, osEndpoint.c_str());
     166             :     }
     167         195 :     else if (bUseVirtualHosting)
     168             :         return CPLSPrintf("%s://%s.%s/%s", pszProtocol, osBucket.c_str(),
     169             :                           osEndpoint.c_str(),
     170           0 :                           CPLAWSURLEncode(osObjectKey, false).c_str());
     171             :     else
     172             :         return CPLSPrintf("%s://%s/%s/%s", pszProtocol, osEndpoint.c_str(),
     173             :                           osBucket.c_str(),
     174         390 :                           CPLAWSURLEncode(osObjectKey, false).c_str());
     175             : }
     176             : 
     177             : /************************************************************************/
     178             : /*                           RebuildURL()                               */
     179             : /************************************************************************/
     180             : 
     181         107 : void VSIOSSHandleHelper::RebuildURL()
     182             : {
     183         107 :     m_osURL = BuildURL(m_osEndpoint, m_osBucket, m_osObjectKey, m_bUseHTTPS,
     184         107 :                        m_bUseVirtualHosting);
     185         107 :     m_osURL += GetQueryString(false);
     186         107 : }
     187             : 
     188             : /************************************************************************/
     189             : /*                        GetConfiguration()                            */
     190             : /************************************************************************/
     191             : 
     192         101 : bool VSIOSSHandleHelper::GetConfiguration(const std::string &osPathForOption,
     193             :                                           CSLConstList papszOptions,
     194             :                                           std::string &osSecretAccessKey,
     195             :                                           std::string &osAccessKeyId)
     196             : {
     197             :     osSecretAccessKey = CSLFetchNameValueDef(
     198             :         papszOptions, "OSS_SECRET_ACCESS_KEY",
     199             :         VSIGetPathSpecificOption(osPathForOption.c_str(),
     200         101 :                                  "OSS_SECRET_ACCESS_KEY", ""));
     201             : 
     202         101 :     if (!osSecretAccessKey.empty())
     203             :     {
     204             :         osAccessKeyId = CSLFetchNameValueDef(
     205             :             papszOptions, "OSS_ACCESS_KEY_ID",
     206             :             VSIGetPathSpecificOption(osPathForOption.c_str(),
     207          98 :                                      "OSS_ACCESS_KEY_ID", ""));
     208          98 :         if (osAccessKeyId.empty())
     209             :         {
     210           1 :             VSIError(VSIE_AWSInvalidCredentials,
     211             :                      "OSS_ACCESS_KEY_ID configuration option not defined");
     212           1 :             return false;
     213             :         }
     214             : 
     215          97 :         return true;
     216             :     }
     217             : 
     218           3 :     VSIError(VSIE_AWSInvalidCredentials,
     219             :              "OSS_SECRET_ACCESS_KEY configuration option not defined");
     220           3 :     return false;
     221             : }
     222             : 
     223             : /************************************************************************/
     224             : /*                          BuildFromURI()                              */
     225             : /************************************************************************/
     226             : 
     227         101 : VSIOSSHandleHelper *VSIOSSHandleHelper::BuildFromURI(const char *pszURI,
     228             :                                                      const char *pszFSPrefix,
     229             :                                                      bool bAllowNoObject,
     230             :                                                      CSLConstList papszOptions)
     231             : {
     232         202 :     std::string osPathForOption("/vsioss/");
     233         101 :     if (pszURI)
     234         101 :         osPathForOption += pszURI;
     235             : 
     236         202 :     std::string osSecretAccessKey;
     237         202 :     std::string osAccessKeyId;
     238         101 :     if (!GetConfiguration(osPathForOption, papszOptions, osSecretAccessKey,
     239             :                           osAccessKeyId))
     240             :     {
     241           4 :         return nullptr;
     242             :     }
     243             : 
     244             :     const std::string osEndpoint = CSLFetchNameValueDef(
     245             :         papszOptions, "OSS_ENDPOINT",
     246             :         VSIGetPathSpecificOption(osPathForOption.c_str(), "OSS_ENDPOINT",
     247         194 :                                  "oss-us-east-1.aliyuncs.com"));
     248         194 :     std::string osBucket;
     249         194 :     std::string osObjectKey;
     250         190 :     if (pszURI != nullptr && pszURI[0] != '\0' &&
     251          93 :         !GetBucketAndObjectKey(pszURI, pszFSPrefix, bAllowNoObject, osBucket,
     252             :                                osObjectKey))
     253             :     {
     254           1 :         return nullptr;
     255             :     }
     256          96 :     const bool bUseHTTPS = CPLTestBool(
     257             :         VSIGetPathSpecificOption(osPathForOption.c_str(), "OSS_HTTPS", "YES"));
     258             :     const bool bIsValidNameForVirtualHosting =
     259          96 :         osBucket.find('.') == std::string::npos;
     260          96 :     const bool bUseVirtualHosting = CPLTestBool(VSIGetPathSpecificOption(
     261             :         osPathForOption.c_str(), "OSS_VIRTUAL_HOSTING",
     262             :         bIsValidNameForVirtualHosting ? "TRUE" : "FALSE"));
     263             :     return new VSIOSSHandleHelper(osSecretAccessKey, osAccessKeyId, osEndpoint,
     264             :                                   osBucket, osObjectKey, bUseHTTPS,
     265          96 :                                   bUseVirtualHosting);
     266             : }
     267             : 
     268             : /************************************************************************/
     269             : /*                           GetCurlHeaders()                           */
     270             : /************************************************************************/
     271             : 
     272          89 : struct curl_slist *VSIOSSHandleHelper::GetCurlHeaders(
     273             :     const std::string &osVerb, const struct curl_slist *psExistingHeaders,
     274             :     const void * /*pabyDataContent*/, size_t /*nBytesContent*/) const
     275             : {
     276         178 :     std::string osCanonicalQueryString;
     277          89 :     if (!m_osObjectKey.empty())
     278             :     {
     279          79 :         osCanonicalQueryString = GetQueryString(false);
     280             :     }
     281             : 
     282             :     std::string osCanonicalizedResource(
     283          89 :         m_osBucket.empty() ? std::string("/")
     284         352 :                            : "/" + m_osBucket + "/" + m_osObjectKey);
     285          89 :     osCanonicalizedResource += osCanonicalQueryString;
     286             : 
     287          89 :     return CPLGetOSSHeaders(m_osSecretAccessKey, m_osAccessKeyId, osVerb,
     288         178 :                             psExistingHeaders, osCanonicalizedResource);
     289             : }
     290             : 
     291             : /************************************************************************/
     292             : /*                          CanRestartOnError()                         */
     293             : /************************************************************************/
     294             : 
     295           9 : bool VSIOSSHandleHelper::CanRestartOnError(const char *pszErrorMsg,
     296             :                                            const char *, bool bSetError)
     297             : {
     298             : #ifdef DEBUG_VERBOSE
     299             :     CPLDebug("OSS", "%s", pszErrorMsg);
     300             : #endif
     301             : 
     302           9 :     if (!STARTS_WITH(pszErrorMsg, "<?xml"))
     303             :     {
     304           3 :         if (bSetError)
     305             :         {
     306           1 :             VSIError(VSIE_AWSError, "Invalid AWS response: %s", pszErrorMsg);
     307             :         }
     308           3 :         return false;
     309             :     }
     310             : 
     311           6 :     CPLXMLNode *psTree = CPLParseXMLString(pszErrorMsg);
     312           6 :     if (psTree == nullptr)
     313             :     {
     314           1 :         if (bSetError)
     315             :         {
     316           1 :             VSIError(VSIE_AWSError, "Malformed AWS XML response: %s",
     317             :                      pszErrorMsg);
     318             :         }
     319           1 :         return false;
     320             :     }
     321             : 
     322           5 :     const char *pszCode = CPLGetXMLValue(psTree, "=Error.Code", nullptr);
     323           5 :     if (pszCode == nullptr)
     324             :     {
     325           1 :         CPLDestroyXMLNode(psTree);
     326           1 :         if (bSetError)
     327             :         {
     328           1 :             VSIError(VSIE_AWSError, "Malformed AWS XML response: %s",
     329             :                      pszErrorMsg);
     330             :         }
     331           1 :         return false;
     332             :     }
     333             : 
     334           4 :     if (EQUAL(pszCode, "AccessDenied"))
     335             :     {
     336             :         const char *pszEndpoint =
     337           1 :             CPLGetXMLValue(psTree, "=Error.Endpoint", nullptr);
     338           1 :         if (pszEndpoint && pszEndpoint != m_osEndpoint)
     339             :         {
     340           1 :             SetEndpoint(pszEndpoint);
     341           1 :             CPLDebug("OSS", "Switching to endpoint %s", m_osEndpoint.c_str());
     342           1 :             CPLDestroyXMLNode(psTree);
     343             : 
     344           1 :             VSIOSSUpdateParams::UpdateMapFromHandle(this);
     345             : 
     346           1 :             return true;
     347             :         }
     348             :     }
     349             : 
     350           3 :     if (bSetError)
     351             :     {
     352             :         // Translate AWS errors into VSI errors.
     353             :         const char *pszMessage =
     354           3 :             CPLGetXMLValue(psTree, "=Error.Message", nullptr);
     355             : 
     356           3 :         if (pszMessage == nullptr)
     357             :         {
     358           3 :             VSIError(VSIE_AWSError, "%s", pszErrorMsg);
     359             :         }
     360           0 :         else if (EQUAL(pszCode, "AccessDenied"))
     361             :         {
     362           0 :             VSIError(VSIE_AWSAccessDenied, "%s", pszMessage);
     363             :         }
     364           0 :         else if (EQUAL(pszCode, "NoSuchBucket"))
     365             :         {
     366           0 :             VSIError(VSIE_AWSBucketNotFound, "%s", pszMessage);
     367             :         }
     368           0 :         else if (EQUAL(pszCode, "NoSuchKey"))
     369             :         {
     370           0 :             VSIError(VSIE_AWSObjectNotFound, "%s", pszMessage);
     371             :         }
     372           0 :         else if (EQUAL(pszCode, "SignatureDoesNotMatch"))
     373             :         {
     374           0 :             VSIError(VSIE_AWSSignatureDoesNotMatch, "%s", pszMessage);
     375             :         }
     376             :         else
     377             :         {
     378           0 :             VSIError(VSIE_AWSError, "%s", pszMessage);
     379             :         }
     380             :     }
     381             : 
     382           3 :     CPLDestroyXMLNode(psTree);
     383             : 
     384           3 :     return false;
     385             : }
     386             : 
     387             : /************************************************************************/
     388             : /*                            SetEndpoint()                             */
     389             : /************************************************************************/
     390             : 
     391           8 : void VSIOSSHandleHelper::SetEndpoint(const std::string &osStr)
     392             : {
     393           8 :     m_osEndpoint = osStr;
     394           8 :     RebuildURL();
     395           8 : }
     396             : 
     397             : /************************************************************************/
     398             : /*                           GetSignedURL()                             */
     399             : /************************************************************************/
     400             : 
     401           1 : std::string VSIOSSHandleHelper::GetSignedURL(CSLConstList papszOptions)
     402             : {
     403           1 :     GIntBig nStartDate = static_cast<GIntBig>(time(nullptr));
     404           1 :     const char *pszStartDate = CSLFetchNameValue(papszOptions, "START_DATE");
     405           1 :     if (pszStartDate)
     406             :     {
     407             :         int nYear, nMonth, nDay, nHour, nMin, nSec;
     408           1 :         if (sscanf(pszStartDate, "%04d%02d%02dT%02d%02d%02dZ", &nYear, &nMonth,
     409           1 :                    &nDay, &nHour, &nMin, &nSec) == 6)
     410             :         {
     411             :             struct tm brokendowntime;
     412           1 :             brokendowntime.tm_year = nYear - 1900;
     413           1 :             brokendowntime.tm_mon = nMonth - 1;
     414           1 :             brokendowntime.tm_mday = nDay;
     415           1 :             brokendowntime.tm_hour = nHour;
     416           1 :             brokendowntime.tm_min = nMin;
     417           1 :             brokendowntime.tm_sec = nSec;
     418           1 :             nStartDate = CPLYMDHMSToUnixTime(&brokendowntime);
     419             :         }
     420             :     }
     421             :     GIntBig nExpiresIn =
     422             :         nStartDate +
     423           1 :         atoi(CSLFetchNameValueDef(papszOptions, "EXPIRATION_DELAY", "3600"));
     424             :     std::string osExpires(CSLFetchNameValueDef(
     425           2 :         papszOptions, "EXPIRES", CPLSPrintf(CPL_FRMT_GIB, nExpiresIn)));
     426             : 
     427           2 :     std::string osVerb(CSLFetchNameValueDef(papszOptions, "VERB", "GET"));
     428             : 
     429             :     std::string osCanonicalizedResource(
     430           1 :         m_osBucket.empty() ? std::string("/")
     431           4 :                            : "/" + m_osBucket + "/" + m_osObjectKey);
     432             : 
     433           2 :     std::string osStringToSign;
     434           1 :     osStringToSign += osVerb + "\n";
     435           1 :     osStringToSign += "\n";
     436           1 :     osStringToSign += "\n";
     437           1 :     osStringToSign += osExpires + "\n";
     438             :     // osStringToSign += ; // osCanonicalizedHeaders;
     439           1 :     osStringToSign += osCanonicalizedResource;
     440             : #ifdef DEBUG_VERBOSE
     441             :     CPLDebug("OSS", "osStringToSign = %s", osStringToSign.c_str());
     442             : #endif
     443             : 
     444           2 :     std::string osSignature(GetSignature(osStringToSign, m_osSecretAccessKey));
     445             : 
     446           1 :     ResetQueryParameters();
     447             :     //  Note:
     448             :     //  https://www.alibabacloud.com/help/doc-detail/31952.htm?spm=a3c0i.o32002en.b99.294.6d70a0fc7cRJfJ
     449             :     //  is wrong on the name of the OSSAccessKeyId parameter !
     450           1 :     AddQueryParameter("OSSAccessKeyId", m_osAccessKeyId);
     451           1 :     AddQueryParameter("Expires", osExpires);
     452           1 :     AddQueryParameter("Signature", osSignature);
     453           2 :     return m_osURL;
     454             : }
     455             : 
     456             : /************************************************************************/
     457             : /*                         UpdateMapFromHandle()                        */
     458             : /************************************************************************/
     459             : 
     460             : std::mutex VSIOSSUpdateParams::gsMutex{};
     461             : 
     462             : std::map<std::string, VSIOSSUpdateParams>
     463             :     VSIOSSUpdateParams::goMapBucketsToOSSParams{};
     464             : 
     465           1 : void VSIOSSUpdateParams::UpdateMapFromHandle(
     466             :     VSIOSSHandleHelper *poOSSHandleHelper)
     467             : {
     468           1 :     std::lock_guard<std::mutex> guard(gsMutex);
     469             : 
     470           1 :     goMapBucketsToOSSParams[poOSSHandleHelper->GetBucket()] =
     471           2 :         VSIOSSUpdateParams(poOSSHandleHelper);
     472           1 : }
     473             : 
     474             : /************************************************************************/
     475             : /*                         UpdateHandleFromMap()                        */
     476             : /************************************************************************/
     477             : 
     478          96 : void VSIOSSUpdateParams::UpdateHandleFromMap(
     479             :     VSIOSSHandleHelper *poOSSHandleHelper)
     480             : {
     481         192 :     std::lock_guard<std::mutex> guard(gsMutex);
     482             : 
     483             :     std::map<std::string, VSIOSSUpdateParams>::iterator oIter =
     484          96 :         goMapBucketsToOSSParams.find(poOSSHandleHelper->GetBucket());
     485          96 :     if (oIter != goMapBucketsToOSSParams.end())
     486             :     {
     487           7 :         oIter->second.UpdateHandlerHelper(poOSSHandleHelper);
     488             :     }
     489          96 : }
     490             : 
     491             : /************************************************************************/
     492             : /*                            ClearCache()                              */
     493             : /************************************************************************/
     494             : 
     495        1341 : void VSIOSSUpdateParams::ClearCache()
     496             : {
     497        2682 :     std::lock_guard<std::mutex> guard(gsMutex);
     498             : 
     499        1341 :     goMapBucketsToOSSParams.clear();
     500        1341 : }
     501             : 
     502             : #endif  // HAVE_CURL
     503             : 
     504             : //! @endcond

Generated by: LCOV version 1.14