LCOV - code coverage report
Current view: top level - frmts/http - httpdriver.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 68 82 82.9 %
Date: 2024-05-15 17:37:59 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  WCS Client Driver
       4             :  * Purpose:  Implementation of an HTTP fetching driver.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2007, Frank Warmerdam
       9             :  * Copyright (c) 2008-2013, Even Rouault <even dot 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             : #include "cpl_string.h"
      31             : #include "cpl_http.h"
      32             : #include "cpl_atomic_ops.h"
      33             : #include "gdal_frmts.h"
      34             : #include "gdal_pam.h"
      35             : 
      36             : /************************************************************************/
      37             : /*               HTTPFetchContentDispositionFilename()                 */
      38             : /************************************************************************/
      39             : 
      40           5 : static const char *HTTPFetchContentDispositionFilename(char **papszHeaders)
      41             : {
      42           5 :     char **papszIter = papszHeaders;
      43          92 :     while (papszIter && *papszIter)
      44             :     {
      45             :         /* For multipart, we have in raw format, but without end-of-line
      46             :          * characters */
      47          87 :         if (STARTS_WITH(*papszIter,
      48             :                         "Content-Disposition: attachment; filename="))
      49             :         {
      50           0 :             return *papszIter + 42;
      51             :         }
      52             :         /* For single part, the headers are in KEY=VAL format, but with e-o-l
      53             :          * ... */
      54          87 :         else if (STARTS_WITH(*papszIter,
      55             :                              "Content-Disposition=attachment; filename="))
      56             :         {
      57           0 :             char *pszVal = (char *)(*papszIter + 41);
      58           0 :             char *pszEOL = strchr(pszVal, '\r');
      59           0 :             if (pszEOL)
      60           0 :                 *pszEOL = 0;
      61           0 :             pszEOL = strchr(pszVal, '\n');
      62           0 :             if (pszEOL)
      63           0 :                 *pszEOL = 0;
      64           0 :             return pszVal;
      65             :         }
      66          87 :         papszIter++;
      67             :     }
      68           5 :     return nullptr;
      69             : }
      70             : 
      71             : /************************************************************************/
      72             : /*                              HTTPOpen()                              */
      73             : /************************************************************************/
      74             : 
      75       27147 : static GDALDataset *HTTPOpen(GDALOpenInfo *poOpenInfo)
      76             : 
      77             : {
      78             :     static volatile int nCounter = 0;
      79             : 
      80       27147 :     if (poOpenInfo->nHeaderBytes != 0)
      81        1284 :         return nullptr;
      82             : 
      83       25863 :     if (!STARTS_WITH_CI(poOpenInfo->pszFilename, "http:") &&
      84       25860 :         !STARTS_WITH_CI(poOpenInfo->pszFilename, "https:") &&
      85       25854 :         !STARTS_WITH_CI(poOpenInfo->pszFilename, "ftp:"))
      86       25852 :         return nullptr;
      87             : 
      88             :     /* -------------------------------------------------------------------- */
      89             :     /*      Fetch the result.                                               */
      90             :     /* -------------------------------------------------------------------- */
      91          11 :     CPLErrorReset();
      92           8 :     CPLHTTPResult *psResult = CPLHTTPFetch(poOpenInfo->pszFilename, nullptr);
      93             : 
      94             :     /* -------------------------------------------------------------------- */
      95             :     /*      Try to handle errors.                                           */
      96             :     /* -------------------------------------------------------------------- */
      97          15 :     if (psResult == nullptr || psResult->nDataLen == 0 ||
      98           7 :         CPLGetLastErrorNo() != 0)
      99             :     {
     100           3 :         CPLHTTPDestroyResult(psResult);
     101           3 :         return nullptr;
     102             :     }
     103             : 
     104             :     /* -------------------------------------------------------------------- */
     105             :     /*      Create a memory file from the result.                           */
     106             :     /* -------------------------------------------------------------------- */
     107          10 :     CPLString osResultFilename;
     108             : 
     109           5 :     int nNewCounter = CPLAtomicInc(&nCounter);
     110             : 
     111             :     const char *pszFilename =
     112           5 :         HTTPFetchContentDispositionFilename(psResult->papszHeaders);
     113           5 :     if (pszFilename == nullptr)
     114             :     {
     115           5 :         pszFilename = CPLGetFilename(poOpenInfo->pszFilename);
     116             :         /* If we have special characters, let's default to a fixed name */
     117           5 :         if (strchr(pszFilename, '?') || strchr(pszFilename, '&'))
     118           0 :             pszFilename = "file.dat";
     119             :     }
     120             : 
     121           5 :     osResultFilename.Printf("/vsimem/http_%d/%s", nNewCounter, pszFilename);
     122             : 
     123           5 :     VSILFILE *fp = VSIFileFromMemBuffer(osResultFilename, psResult->pabyData,
     124           5 :                                         psResult->nDataLen, TRUE);
     125             : 
     126           5 :     if (fp == nullptr)
     127           0 :         return nullptr;
     128             : 
     129           5 :     VSIFCloseL(fp);
     130             : 
     131             :     /* -------------------------------------------------------------------- */
     132             :     /*      Steal the memory buffer from HTTP result before destroying      */
     133             :     /*      it.                                                             */
     134             :     /* -------------------------------------------------------------------- */
     135           5 :     psResult->pabyData = nullptr;
     136           5 :     psResult->nDataLen = 0;
     137           5 :     psResult->nDataAlloc = 0;
     138             : 
     139           5 :     CPLHTTPDestroyResult(psResult);
     140             : 
     141             :     /* -------------------------------------------------------------------- */
     142             :     /*      Try opening this result as a gdaldataset.                       */
     143             :     /* -------------------------------------------------------------------- */
     144             :     /* suppress errors as not all drivers support /vsimem */
     145           5 :     CPLPushErrorHandler(CPLQuietErrorHandler);
     146           5 :     GDALDataset *poDS = (GDALDataset *)GDALOpenEx(
     147           5 :         osResultFilename, poOpenInfo->nOpenFlags & ~GDAL_OF_SHARED,
     148           5 :         poOpenInfo->papszAllowedDrivers, poOpenInfo->papszOpenOptions, nullptr);
     149           5 :     CPLPopErrorHandler();
     150             : 
     151             :     // The JP2OpenJPEG driver may need to reopen the file, hence this special
     152             :     // behavior
     153           8 :     if (poDS != nullptr && poDS->GetDriver() != nullptr &&
     154           3 :         EQUAL(poDS->GetDriver()->GetDescription(), "JP2OpenJPEG"))
     155             :     {
     156           1 :         poDS->MarkSuppressOnClose();
     157           1 :         return poDS;
     158             :     }
     159             : 
     160             :     /* -------------------------------------------------------------------- */
     161             :     /*      If opening it in memory didn't work, perhaps we need to         */
     162             :     /*      write to a temp file on disk?                                   */
     163             :     /* -------------------------------------------------------------------- */
     164           4 :     if (poDS == nullptr)
     165             :     {
     166           4 :         CPLString osTempFilename;
     167             : 
     168             : #ifdef _WIN32
     169             :         const char *pszPath = CPLGetPath(CPLGenerateTempFilename(NULL));
     170             : #else
     171           2 :         const char *pszPath = "/tmp";
     172             : #endif
     173             :         osTempFilename =
     174           2 :             CPLFormFilename(pszPath, CPLGetFilename(osResultFilename), nullptr);
     175           2 :         if (CPLCopyFile(osTempFilename, osResultFilename) != 0)
     176             :         {
     177           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
     178             :                      "Failed to create temporary file:%s",
     179             :                      osTempFilename.c_str());
     180             :         }
     181             :         else
     182             :         {
     183           2 :             poDS = (GDALDataset *)GDALOpenEx(
     184           2 :                 osTempFilename, poOpenInfo->nOpenFlags & ~GDAL_OF_SHARED,
     185           2 :                 poOpenInfo->papszAllowedDrivers, poOpenInfo->papszOpenOptions,
     186             :                 nullptr);
     187           2 :             if (VSIUnlink(osTempFilename) != 0 && poDS != nullptr)
     188           0 :                 poDS->MarkSuppressOnClose(); /* VSIUnlink() may not work on
     189             :                                                 windows */
     190           2 :             if (poDS && strcmp(poDS->GetDescription(), osTempFilename) == 0)
     191           0 :                 poDS->SetDescription(poOpenInfo->pszFilename);
     192             :         }
     193             :     }
     194           2 :     else if (strcmp(poDS->GetDescription(), osResultFilename) == 0)
     195           2 :         poDS->SetDescription(poOpenInfo->pszFilename);
     196             : 
     197             :     /* -------------------------------------------------------------------- */
     198             :     /*      Release our hold on the vsi memory file, though if it is        */
     199             :     /*      held open by a dataset it will continue to exist till that      */
     200             :     /*      lets it go.                                                     */
     201             :     /* -------------------------------------------------------------------- */
     202           4 :     VSIUnlink(osResultFilename);
     203             : 
     204           4 :     return poDS;
     205             : }
     206             : 
     207             : /************************************************************************/
     208             : /*                         GDALRegister_HTTP()                          */
     209             : /************************************************************************/
     210             : 
     211        1523 : void GDALRegister_HTTP()
     212             : 
     213             : {
     214        1523 :     if (GDALGetDriverByName("HTTP") != nullptr)
     215         301 :         return;
     216             : 
     217        1222 :     GDALDriver *poDriver = new GDALDriver();
     218             : 
     219        1222 :     poDriver->SetDescription("HTTP");
     220        1222 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     221        1222 :     poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
     222        1222 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "HTTP Fetching Wrapper");
     223             : 
     224        1222 :     poDriver->pfnOpen = HTTPOpen;
     225             : 
     226        1222 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     227             : }

Generated by: LCOV version 1.14