LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/gmlas - ogrgmlasxlinkresolver.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 108 125 86.4 %
Date: 2024-11-21 22:18:42 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  * Project:  OGR
       3             :  * Purpose:  OGRGMLASDriver implementation
       4             :  * Author:   Even Rouault, <even dot rouault at spatialys dot com>
       5             :  *
       6             :  * Initial development funded by the European Earth observation programme
       7             :  * Copernicus
       8             :  *
       9             :  ******************************************************************************
      10             :  * Copyright (c) 2016, Even Rouault, <even dot rouault at spatialys dot com>
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #include "ogr_gmlas.h"
      16             : 
      17             : #include "cpl_http.h"
      18             : 
      19             : #include <time.h>
      20             : 
      21             : /************************************************************************/
      22             : /*                         GMLASXLinkResolver()                         */
      23             : /************************************************************************/
      24             : 
      25         189 : GMLASXLinkResolver::GMLASXLinkResolver()
      26             :     : m_nMaxRAMCacheSize(
      27         189 :           atoi(CPLGetConfigOption("GMLAS_XLINK_RAM_CACHE_SIZE", "10000000")))
      28             : {
      29         189 : }
      30             : 
      31             : /************************************************************************/
      32             : /*                             SetConf()                                */
      33             : /************************************************************************/
      34             : 
      35         172 : void GMLASXLinkResolver::SetConf(const GMLASXLinkResolutionConf &oConf)
      36             : {
      37         172 :     m_oConf = oConf;
      38         172 :     SetCacheDirectory(m_oConf.m_osCacheDirectory);
      39         172 : }
      40             : 
      41             : /************************************************************************/
      42             : /*                          FetchRawContent()                           */
      43             : /************************************************************************/
      44             : 
      45          10 : CPLString GMLASXLinkResolver::FetchRawContent(const CPLString &osURL,
      46             :                                               const char *pszHeaders)
      47             : {
      48          10 :     char **papszOptions = nullptr;
      49          10 :     if (m_oConf.m_nMaxGlobalResolutionTime > 0 &&
      50           0 :         m_nGlobalResolutionTime > m_oConf.m_nMaxGlobalResolutionTime)
      51             :     {
      52           0 :         CPLError(CE_Failure, CPLE_AppDefined,
      53             :                  "Maximum global resolution time has been reached. "
      54             :                  "No remote resource will be fetched");
      55           0 :         return CPLString();
      56             :     }
      57          10 :     if (m_oConf.m_nTimeOut > 0 || m_oConf.m_nMaxGlobalResolutionTime > 0)
      58             :     {
      59           0 :         int nTimeout = m_oConf.m_nTimeOut;
      60           0 :         if (m_oConf.m_nTimeOut > 0 && m_oConf.m_nMaxGlobalResolutionTime > 0)
      61             :         {
      62             :             // Select the minimum between the individual timeout and the
      63             :             // remaining time granted by the max global resolution time.
      64           0 :             int nRemaining =
      65           0 :                 m_oConf.m_nMaxGlobalResolutionTime - m_nGlobalResolutionTime;
      66           0 :             if (nRemaining < nTimeout)
      67           0 :                 nTimeout = nRemaining;
      68             :         }
      69           0 :         else if (m_oConf.m_nMaxGlobalResolutionTime > 0)
      70             :         {
      71           0 :             nTimeout =
      72           0 :                 m_oConf.m_nMaxGlobalResolutionTime - m_nGlobalResolutionTime;
      73             :         }
      74           0 :         papszOptions = CSLSetNameValue(papszOptions, "TIMEOUT",
      75             :                                        CPLSPrintf("%d", nTimeout));
      76             :     }
      77          10 :     if (m_oConf.m_nMaxFileSize > 0)
      78             :     {
      79             :         papszOptions =
      80          10 :             CSLSetNameValue(papszOptions, "MAX_FILE_SIZE",
      81             :                             CPLSPrintf("%d", m_oConf.m_nMaxFileSize));
      82             :     }
      83          10 :     if (!m_oConf.m_osProxyServerPort.empty())
      84             :     {
      85             :         papszOptions =
      86           0 :             CSLSetNameValue(papszOptions, "PROXY", m_oConf.m_osProxyServerPort);
      87             :     }
      88          10 :     if (!m_oConf.m_osProxyUserPassword.empty())
      89             :     {
      90           0 :         papszOptions = CSLSetNameValue(papszOptions, "PROXYUSERPWD",
      91             :                                        m_oConf.m_osProxyUserPassword);
      92             :     }
      93          10 :     if (!m_oConf.m_osProxyAuth.empty())
      94             :     {
      95             :         papszOptions =
      96           0 :             CSLSetNameValue(papszOptions, "PROXYAUTH", m_oConf.m_osProxyAuth);
      97             :     }
      98          10 :     if (pszHeaders != nullptr)
      99             :     {
     100           1 :         papszOptions = CSLSetNameValue(papszOptions, "HEADERS", pszHeaders);
     101             :     }
     102          10 :     time_t nTimeStart = time(nullptr);
     103          10 :     CPLHTTPResult *psResult = CPLHTTPFetch(osURL, papszOptions);
     104          10 :     time_t nTimeStop = time(nullptr);
     105          10 :     m_nGlobalResolutionTime += static_cast<int>(nTimeStop - nTimeStart);
     106          10 :     CSLDestroy(papszOptions);
     107          10 :     if (psResult == nullptr)
     108           0 :         return CPLString();
     109             : 
     110          10 :     if (psResult->nStatus != 0 || psResult->pabyData == nullptr)
     111             :     {
     112           3 :         CPLHTTPDestroyResult(psResult);
     113           3 :         return CPLString();
     114             :     }
     115             : 
     116          14 :     CPLString osResult;
     117           7 :     osResult.assign(reinterpret_cast<char *>(psResult->pabyData),
     118           7 :                     psResult->nDataLen);
     119           7 :     CPLHTTPDestroyResult(psResult);
     120           7 :     return osResult;
     121             : }
     122             : 
     123             : /************************************************************************/
     124             : /*                           GetRawContent()                            */
     125             : /************************************************************************/
     126             : 
     127          17 : CPLString GMLASXLinkResolver::GetRawContent(const CPLString &osURL,
     128             :                                             const char *pszHeaders,
     129             :                                             bool bAllowRemoteDownload,
     130             :                                             bool bCacheResults)
     131             : {
     132          17 :     bool bDiskCacheAvailable = false;
     133          17 :     if (!m_osCacheDirectory.empty() && RecursivelyCreateDirectoryIfNeeded())
     134             :     {
     135          17 :         bDiskCacheAvailable = true;
     136             : 
     137          17 :         CPLString osCachedFileName(GetCachedFilename(osURL));
     138          17 :         VSILFILE *fp = nullptr;
     139          18 :         if (!m_bRefresh || m_aoSetRefreshedFiles.find(osCachedFileName) !=
     140          18 :                                m_aoSetRefreshedFiles.end())
     141             :         {
     142          16 :             fp = VSIFOpenL(osCachedFileName, "rb");
     143             :         }
     144          17 :         if (fp != nullptr)
     145             :         {
     146           4 :             CPLDebug("GMLAS", "Use cached %s", osCachedFileName.c_str());
     147           4 :             GByte *pabyRet = nullptr;
     148           4 :             vsi_l_offset nSize = 0;
     149           8 :             CPLString osContent;
     150           4 :             if (VSIIngestFile(fp, nullptr, &pabyRet, &nSize, -1))
     151             :             {
     152             :                 osContent.assign(reinterpret_cast<const char *>(pabyRet),
     153           4 :                                  static_cast<size_t>(nSize));
     154             :             }
     155           4 :             VSIFree(pabyRet);
     156           4 :             VSIFCloseL(fp);
     157           4 :             return osContent;
     158             :         }
     159          13 :         else if (bAllowRemoteDownload)
     160             :         {
     161          12 :             if (m_bRefresh)
     162           1 :                 m_aoSetRefreshedFiles.insert(osCachedFileName);
     163             :         }
     164             :         else
     165             :         {
     166           1 :             CPLDebug("GMLAS",
     167             :                      "Could not find locally cached %s, and not allowed to"
     168             :                      "download it",
     169             :                      osURL.c_str());
     170           1 :             return CPLString();
     171             :         }
     172             :     }
     173             : 
     174             :     // Check memory cache first
     175             :     {
     176          12 :         const auto oIter = m_oMapURLToContent.find(osURL);
     177          12 :         if (oIter != m_oMapURLToContent.end())
     178           2 :             return oIter->second;
     179             :     }
     180             : 
     181          20 :     const CPLString osContent(FetchRawContent(osURL, pszHeaders));
     182             :     // Cache to disk if possible
     183          10 :     if (bDiskCacheAvailable && bCacheResults && !osContent.empty())
     184             :     {
     185          10 :         CPLString osCachedFileName(GetCachedFilename(osURL));
     186          10 :         CPLString osTmpfilename(osCachedFileName + ".tmp");
     187           5 :         VSILFILE *fpTemp = VSIFOpenL(osTmpfilename, "wb");
     188           5 :         if (fpTemp != nullptr)
     189             :         {
     190             :             const bool bSuccess =
     191           5 :                 VSIFWriteL(osContent.data(), osContent.size(), 1, fpTemp) == 1;
     192           5 :             VSIFCloseL(fpTemp);
     193           5 :             if (bSuccess)
     194           5 :                 VSIRename(osTmpfilename, osCachedFileName);
     195             :         }
     196             :     }
     197             :     // Otherwise to RAM
     198           5 :     else if (!osContent.empty() && osContent.size() < m_nMaxRAMCacheSize)
     199             :     {
     200             :         // If cache is going to be saturated, evict larger objects first
     201           3 :         while (osContent.size() + m_nCurrentRAMCacheSize > m_nMaxRAMCacheSize)
     202             :         {
     203             :             std::map<size_t, std::vector<CPLString>>::reverse_iterator oIter =
     204           1 :                 m_oMapFileSizeToURLs.rbegin();
     205           1 :             const size_t nSizeToEvict = oIter->first;
     206           1 :             m_nCurrentRAMCacheSize -= nSizeToEvict;
     207           2 :             const CPLString osURLToEvict(oIter->second.front());
     208           1 :             m_oMapURLToContent.erase(osURLToEvict);
     209           1 :             oIter->second.erase(oIter->second.begin());
     210           1 :             if (oIter->second.empty())
     211           1 :                 m_oMapFileSizeToURLs.erase(nSizeToEvict);
     212             :         }
     213           2 :         m_oMapURLToContent[osURL] = osContent;
     214           2 :         m_oMapFileSizeToURLs[osContent.size()].push_back(osURL);
     215           2 :         m_nCurrentRAMCacheSize += osContent.size();
     216             :     }
     217          10 :     return osContent;
     218             : }
     219             : 
     220             : /************************************************************************/
     221             : /*                     IsRawContentResolutionEnabled()                  */
     222             : /************************************************************************/
     223             : 
     224          21 : bool GMLASXLinkResolver::IsRawContentResolutionEnabled() const
     225             : {
     226          32 :     return m_oConf.m_bDefaultResolutionEnabled &&
     227          11 :            m_oConf.m_eDefaultResolutionMode ==
     228          21 :                GMLASXLinkResolutionConf::RawContent;
     229             : }
     230             : 
     231             : /************************************************************************/
     232             : /*                      GetMatchingResolutionRule()                      */
     233             : /************************************************************************/
     234             : 
     235          35 : int GMLASXLinkResolver::GetMatchingResolutionRule(const CPLString &osURL) const
     236             : {
     237          45 :     for (size_t i = 0; i < m_oConf.m_aoURLSpecificRules.size(); ++i)
     238             :     {
     239          24 :         if (osURL.compare(0,
     240          24 :                           m_oConf.m_aoURLSpecificRules[i].m_osURLPrefix.size(),
     241          48 :                           m_oConf.m_aoURLSpecificRules[i].m_osURLPrefix) == 0)
     242             :         {
     243          14 :             return static_cast<int>(i);
     244             :         }
     245             :     }
     246             : 
     247             :     // No match
     248          21 :     return -1;
     249             : }
     250             : 
     251             : /************************************************************************/
     252             : /*                           GetRawContent()                            */
     253             : /************************************************************************/
     254             : 
     255          11 : CPLString GMLASXLinkResolver::GetRawContent(const CPLString &osURL)
     256             : {
     257          11 :     return GetRawContent(osURL, nullptr, m_oConf.m_bDefaultAllowRemoteDownload,
     258          11 :                          m_oConf.m_bDefaultCacheResults);
     259             : }
     260             : 
     261             : /************************************************************************/
     262             : /*                         GetRawContentForRule()                       */
     263             : /************************************************************************/
     264             : 
     265           6 : CPLString GMLASXLinkResolver::GetRawContentForRule(const CPLString &osURL,
     266             :                                                    int nIdxRule)
     267             : {
     268             :     const GMLASXLinkResolutionConf::URLSpecificResolution &oRule(
     269           6 :         m_oConf.m_aoURLSpecificRules[nIdxRule]);
     270             : 
     271          12 :     CPLString osHeaders;
     272          12 :     for (size_t i = 0; i < oRule.m_aosNameValueHTTPHeaders.size(); ++i)
     273             :     {
     274           6 :         if (!osHeaders.empty())
     275           3 :             osHeaders += "\r\n";
     276           6 :         osHeaders += oRule.m_aosNameValueHTTPHeaders[i].first;
     277           6 :         osHeaders += ": ";
     278           6 :         osHeaders += oRule.m_aosNameValueHTTPHeaders[i].second;
     279             :     }
     280           3 :     return GetRawContent(osURL, osHeaders.empty() ? nullptr : osHeaders.c_str(),
     281          15 :                          oRule.m_bAllowRemoteDownload, oRule.m_bCacheResults);
     282             : }

Generated by: LCOV version 1.14