示例#1
0
int VSIMemFilesystemHandler::Rmdir( const char * pszPathname )

{
    CPLMutexHolder oHolder( &hMutex );

    return Unlink( pszPathname );
}
示例#2
0
int VSIMemFilesystemHandler::Rename( const char *pszOldPath,
                                     const char *pszNewPath )

{
    CPLMutexHolder oHolder( &hMutex );

    CPLString osOldPath = pszOldPath;
    CPLString osNewPath = pszNewPath;

    NormalizePath( osOldPath );
    NormalizePath( osNewPath );

    if ( osOldPath.compare(osNewPath) == 0 )
        return 0;

    if( oFileList.find(osOldPath) == oFileList.end() )
    {
        errno = ENOENT;
        return -1;
    }
    else
    {
        VSIMemFile* poFile = oFileList[osOldPath];

        oFileList.erase( oFileList.find(osOldPath) );

        Unlink(osNewPath);

        oFileList[osNewPath] = poFile;
        poFile->osFilename = osNewPath;

        return 0;
    }
}
示例#3
0
int VSIMemFilesystemHandler::Unlink( const char * pszFilename )

{
    CPLMutexHolder oHolder( &hMutex );

    CPLString osFilename = pszFilename;
    NormalizePath( osFilename );

    VSIMemFile *poFile;

    if( oFileList.find(osFilename) == oFileList.end() )
    {
        errno = ENOENT;
        return -1;
    }
    else
    {
        poFile = oFileList[osFilename];

        if( --(poFile->nRefCount) == 0 )
            delete poFile;

        oFileList.erase( oFileList.find(osFilename) );

        return 0;
    }
}
示例#4
0
int VSIMemFilesystemHandler::Mkdir( const char * pszPathname,
                                    long nMode )

{
    (void) nMode;

    CPLMutexHolder oHolder( &hMutex );

    CPLString osPathname = pszPathname;

    NormalizePath( osPathname );

    if( oFileList.find(osPathname) != oFileList.end() )
    {
        errno = EEXIST;
        return -1;
    }

    VSIMemFile *poFile = new VSIMemFile;

    poFile->osFilename = osPathname;
    poFile->bIsDirectory = TRUE;
    oFileList[osPathname] = poFile;
    poFile->nRefCount++; /* referenced by file list */

    return 0;
}
示例#5
0
VSIFileManager *VSIFileManager::Get()

{
    static volatile GPtrDiff_t nConstructerPID = 0;
    if( poManager != NULL )
    {
        if( nConstructerPID != 0 )
        {
            GPtrDiff_t nCurrentPID = static_cast<GPtrDiff_t>(CPLGetPID());
            if( nConstructerPID != nCurrentPID )
            {
                {
                    CPLMutexHolder oHolder( &hVSIFileManagerMutex );
                }
                if ( nConstructerPID != 0 )
                {
                    VSIDebug1( "nConstructerPID != 0: %d", nConstructerPID);
                    assert(false);
                }
            }
        }
        return poManager;
    }

    CPLMutexHolder oHolder2( &hVSIFileManagerMutex );
    if( poManager == NULL )
    {
        nConstructerPID = static_cast<GPtrDiff_t>(CPLGetPID());
#ifdef DEBUG_VERBOSE
        printf("Thread %d: VSIFileManager in construction\n", nConstructerPID);
#endif
        poManager = new VSIFileManager;
        VSIInstallLargeFileHandler();
        VSIInstallSubFileHandler();
        VSIInstallMemFileHandler();
#ifdef HAVE_LIBZ
        VSIInstallGZipFileHandler();
        VSIInstallZipFileHandler();
#endif
#ifdef HAVE_CURL
        VSIInstallCurlFileHandler();
        VSIInstallCurlStreamingFileHandler();
        VSIInstallS3FileHandler();
        VSIInstallS3StreamingFileHandler();
#endif
        VSIInstallStdinHandler();
        VSIInstallStdoutHandler();
        VSIInstallSparseFileHandler();
        VSIInstallTarFileHandler();
        VSIInstallCryptFileHandler();

        //printf("Thread %d: VSIFileManager construction finished\n", nConstructerPID);
        nConstructerPID = 0;
    }

    return poManager;
}
示例#6
0
VSIFileManager *VSIFileManager::Get()

{
    static volatile int nConstructerPID = 0;
    if( poManager != NULL )
    {
        if( nConstructerPID != 0 )
        {
            int nCurrentPID = (int)CPLGetPID();
            if( nConstructerPID != nCurrentPID )
            {
                //printf("Thread %d: Waiting for VSIFileManager to be finished by other thread.\n", nCurrentPID);
                {
                    CPLMutexHolder oHolder( &hVSIFileManagerMutex );
                }
                //printf("Thread %d: End of wait for VSIFileManager construction to be finished\n", nCurrentPID);
                CPLAssert(nConstructerPID == 0);
            }
        }
        return poManager;
    }

    CPLMutexHolder oHolder2( &hVSIFileManagerMutex );
    if( poManager == NULL )
    {
        nConstructerPID = (int)CPLGetPID();
        //printf("Thread %d: VSIFileManager in construction\n", nConstructerPID);
        poManager = new VSIFileManager;
        VSIInstallLargeFileHandler();
        VSIInstallSubFileHandler();
        VSIInstallMemFileHandler();
#ifdef HAVE_LIBZ
        VSIInstallGZipFileHandler();
        VSIInstallZipFileHandler();
#endif
#ifdef HAVE_CURL
        VSIInstallCurlFileHandler();
        VSIInstallCurlStreamingFileHandler();
#endif
        VSIInstallStdinHandler();
        VSIInstallStdoutHandler();
        VSIInstallSparseFileHandler();
        VSIInstallTarFileHandler();
        //printf("Thread %d: VSIFileManager construction finished\n", nConstructerPID);
        nConstructerPID = 0;
    }
    
    return poManager;
}
示例#7
0
int VSIMemFilesystemHandler::Stat( const char * pszFilename, 
                                   VSIStatBufL * pStatBuf,
                                   int nFlags )
    
{
    (void) nFlags;

    CPLMutexHolder oHolder( &hMutex );

    CPLString osFilename = pszFilename;
    NormalizePath( osFilename );

    memset( pStatBuf, 0, sizeof(VSIStatBufL) );

    if ( osFilename == "/vsimem/" )
    {
        pStatBuf->st_size = 0;
        pStatBuf->st_mode = S_IFDIR;
        return 0;
    }

    if( oFileList.find(osFilename) == oFileList.end() )
    {
        errno = ENOENT;
        return -1;
    }

    VSIMemFile *poFile = oFileList[osFilename];

    memset( pStatBuf, 0, sizeof(VSIStatBufL) );

    if( poFile->bIsDirectory )
    {
        pStatBuf->st_size = 0;
        pStatBuf->st_mode = S_IFDIR;
    }
    else
    {
        pStatBuf->st_size = poFile->nLength;
        pStatBuf->st_mode = S_IFREG;
        pStatBuf->st_mtime = poFile->mTime;
    }

    return 0;
}
示例#8
0
GByte *VSIGetMemFileBuffer( const char *pszFilename, 
                            vsi_l_offset *pnDataLength,
                            int bUnlinkAndSeize )

{
    VSIMemFilesystemHandler *poHandler = (VSIMemFilesystemHandler *) 
        VSIFileManager::GetHandler("/vsimem/");

    if (pszFilename == NULL)
        return NULL;

    CPLString osFilename = pszFilename;
    VSIMemFilesystemHandler::NormalizePath( osFilename );

    CPLMutexHolder oHolder( &poHandler->hMutex );

    if( poHandler->oFileList.find(osFilename) == poHandler->oFileList.end() )
        return NULL;

    VSIMemFile *poFile = poHandler->oFileList[osFilename];
    GByte *pabyData;

    pabyData = poFile->pabyData;
    if( pnDataLength != NULL )
        *pnDataLength = poFile->nLength;
    
    if( bUnlinkAndSeize )
    {
        if( !poFile->bOwnData )
            CPLDebug( "VSIMemFile", 
                      "File doesn't own data in VSIGetMemFileBuffer!" );
        else
            poFile->bOwnData = FALSE;

        poHandler->oFileList.erase( poHandler->oFileList.find(osFilename) );
        --(poFile->nRefCount);
        delete poFile;
    }

    return pabyData;
}
示例#9
0
int VSIMemFilesystemHandler::Rename( const char *pszOldPath,
                                     const char *pszNewPath )

{
    CPLMutexHolder oHolder( &hMutex );

    CPLString osOldPath = pszOldPath;
    CPLString osNewPath = pszNewPath;

    NormalizePath( osOldPath );
    NormalizePath( osNewPath );

    if ( osOldPath.compare(osNewPath) == 0 )
        return 0;

    if( oFileList.find(osOldPath) == oFileList.end() )
    {
        errno = ENOENT;
        return -1;
    }
    else
    {
        std::map<CPLString,VSIMemFile*>::iterator it = oFileList.find(osOldPath);
        while (it != oFileList.end() && it->first.ifind(osOldPath) == 0)
        {
            const CPLString osRemainder = it->first.substr(osOldPath.size());
            if (osRemainder.empty() || osRemainder[0] == '/')
            {
                const CPLString osNewFullPath = osNewPath + osRemainder;
                Unlink_unlocked(osNewFullPath);
                oFileList[osNewFullPath] = it->second;
                it->second->osFilename = osNewFullPath;
                oFileList.erase(it++);
            }
            else ++it;
        }

        return 0;
    }
}
示例#10
0
VSILFILE *VSIFileFromMemBuffer( const char *pszFilename,
                          GByte *pabyData, 
                          vsi_l_offset nDataLength,
                          int bTakeOwnership )

{
    if( VSIFileManager::GetHandler("") 
        == VSIFileManager::GetHandler("/vsimem/") )
        VSIInstallMemFileHandler();

    VSIMemFilesystemHandler *poHandler = (VSIMemFilesystemHandler *) 
        VSIFileManager::GetHandler("/vsimem/");

    if (pszFilename == NULL)
        return NULL;

    CPLString osFilename = pszFilename;
    VSIMemFilesystemHandler::NormalizePath( osFilename );

    VSIMemFile *poFile = new VSIMemFile;

    poFile->osFilename = osFilename;
    poFile->bOwnData = bTakeOwnership;
    poFile->pabyData = pabyData;
    poFile->nLength = nDataLength;
    poFile->nAllocLength = nDataLength;

    {
        CPLMutexHolder oHolder( &poHandler->hMutex );
        poHandler->Unlink(osFilename);
        poHandler->oFileList[poFile->osFilename] = poFile;
        poFile->nRefCount++;
    }

    return (VSILFILE *) poHandler->Open( osFilename, "r+" );
}
示例#11
0
VSIVirtualHandle *
VSIMemFilesystemHandler::Open( const char *pszFilename, 
                               const char *pszAccess )

{
    CPLMutexHolder oHolder( &hMutex );
    VSIMemFile *poFile;
    CPLString osFilename = pszFilename;
    NormalizePath( osFilename );

/* -------------------------------------------------------------------- */
/*      Get the filename we are opening, create if needed.              */
/* -------------------------------------------------------------------- */
    if( oFileList.find(osFilename) == oFileList.end() )
        poFile = NULL;
    else
        poFile = oFileList[osFilename];

    if( strstr(pszAccess,"w") == NULL && poFile == NULL )
    {
        errno = ENOENT;
        return NULL;
    }

    if( strstr(pszAccess,"w") )
    {
        if( poFile )
            poFile->SetLength( 0 );
        else
        {
            poFile = new VSIMemFile;
            poFile->osFilename = osFilename;
            oFileList[poFile->osFilename] = poFile;
            poFile->nRefCount++; // for file list
        }
    }

    if( poFile->bIsDirectory )
    {
        errno = EISDIR;
        return NULL;
    }

/* -------------------------------------------------------------------- */
/*      Setup the file handle on this file.                             */
/* -------------------------------------------------------------------- */
    VSIMemHandle *poHandle = new VSIMemHandle;

    poHandle->poFile = poFile;
    poHandle->nOffset = 0;
    if( strstr(pszAccess,"w") || strstr(pszAccess,"+") 
        || strstr(pszAccess,"a") )
        poHandle->bUpdate = TRUE;
    else
        poHandle->bUpdate = FALSE;

    poFile->nRefCount++;

    if( strstr(pszAccess,"a") )
        poHandle->nOffset = poFile->nLength;

    return poHandle;
}
示例#12
0
/**
 * \brief Fetch a document from an url and return in a string.
 *
 * @param pszURL valid URL recognized by underlying download library (libcurl)
 * @param papszOptions option list as a NULL-terminated array of strings. May be NULL.
 *                     The following options are handled :
 * <ul>
 * <li>TIMEOUT=val, where val is in seconds</li>
 * <li>HEADERS=val, where val is an extra header to use when getting a web page.
 *                  For example "Accept: application/x-ogcwkt"
 * <li>HTTPAUTH=[BASIC/NTLM/GSSNEGOTIATE/ANY] to specify an authentication scheme to use.
 * <li>USERPWD=userid:password to specify a user and password for authentication
 * <li>POSTFIELDS=val, where val is a nul-terminated string to be passed to the server
 *                     with a POST request.
 * <li>PROXY=val, to make requests go through a proxy server, where val is of the
 *                form proxy.server.com:port_number
 * <li>PROXYUSERPWD=val, where val is of the form username:password
 * <li>PROXYAUTH=[BASIC/NTLM/DIGEST/ANY] to specify an proxy authentication scheme to use.
 * <li>NETRC=[YES/NO] to enable or disable use of $HOME/.netrc, default YES.
 * <li>CUSTOMREQUEST=val, where val is GET, PUT, POST, DELETE, etc.. (GDAL >= 1.9.0)
 * <li>COOKIE=val, where val is formatted as COOKIE1=VALUE1; COOKIE2=VALUE2; ...
 * <li>MAX_RETRY=val, where val is the maximum number of retry attempts if a 503 or
 *               504 HTTP error occurs. Default is 0. (GDAL >= 2.0)
 * <li>RETRY_DELAY=val, where val is the number of seconds between retry attempts.
 *                 Default is 30. (GDAL >= 2.0)
 * </ul>
 *
 * Alternatively, if not defined in the papszOptions arguments, the PROXY,  
 * PROXYUSERPWD, PROXYAUTH, NETRC, MAX_RETRY and RETRY_DELAY values are searched in the configuration 
 * options named GDAL_HTTP_PROXY, GDAL_HTTP_PROXYUSERPWD, GDAL_PROXY_AUTH, 
 * GDAL_HTTP_NETRC, GDAL_HTTP_MAX_RETRY and GDAL_HTTP_RETRY_DELAY.
 *
 * @return a CPLHTTPResult* structure that must be freed by 
 * CPLHTTPDestroyResult(), or NULL if libcurl support is disabled
 */
CPLHTTPResult *CPLHTTPFetch( const char *pszURL, char **papszOptions )

{
    if( strncmp(pszURL, "/vsimem/", strlen("/vsimem/")) == 0 &&
        /* Disabled by default for potential security issues */
        CSLTestBoolean(CPLGetConfigOption("CPL_CURL_ENABLE_VSIMEM", "FALSE")) )
    {
        CPLString osURL(pszURL);
        const char* pszPost = CSLFetchNameValue( papszOptions, "POSTFIELDS" );
        if( pszPost != NULL ) /* Hack: we append post content to filename */
        {
            osURL += "&POSTFIELDS=";
            osURL += pszPost;
        }
        vsi_l_offset nLength = 0;
        CPLHTTPResult* psResult = (CPLHTTPResult* )CPLCalloc(1, sizeof(CPLHTTPResult));
        GByte* pabyData = VSIGetMemFileBuffer( osURL, &nLength, FALSE );
        if( pabyData == NULL )
        {
            CPLDebug("HTTP", "Cannot find %s", osURL.c_str());
            psResult->nStatus = 1;
            psResult->pszErrBuf = CPLStrdup(CPLSPrintf("HTTP error code : %d", 404));
            CPLError( CE_Failure, CPLE_AppDefined, "%s", psResult->pszErrBuf );
        }
        else if( nLength != 0 )
        {
            psResult->nDataLen = (size_t)nLength;
            psResult->pabyData = (GByte*) CPLMalloc((size_t)nLength + 1);
            memcpy(psResult->pabyData, pabyData, (size_t)nLength);
            psResult->pabyData[(size_t)nLength] = 0;
        }

        if( psResult->pabyData != NULL &&
            strncmp((const char*)psResult->pabyData, "Content-Type: ",
                    strlen("Content-Type: ")) == 0 )
        {
            const char* pszContentType = (const char*)psResult->pabyData + strlen("Content-type: ");
            const char* pszEOL = strchr(pszContentType, '\r');
            if( pszEOL )
                pszEOL = strchr(pszContentType, '\n');
            if( pszEOL )
            {
                int nLength = pszEOL - pszContentType;
                psResult->pszContentType = (char*)CPLMalloc(nLength + 1);
                memcpy(psResult->pszContentType, pszContentType, nLength);
                psResult->pszContentType[nLength] = 0;
            }
        }

        return psResult;
    }

#ifndef HAVE_CURL
    (void) papszOptions;
    (void) pszURL;

    CPLError( CE_Failure, CPLE_NotSupported,
              "GDAL/OGR not compiled with libcurl support, remote requests not supported." );
    return NULL;
#else

/* -------------------------------------------------------------------- */
/*      Are we using a persistent named session?  If so, search for     */
/*      or create it.                                                   */
/*                                                                      */
/*      Currently this code does not attempt to protect against         */
/*      multiple threads asking for the same named session.  If that    */
/*      occurs it will be in use in multiple threads at once which      */
/*      might have bad consequences depending on what guarantees        */
/*      libcurl gives - which I have not investigated.                  */
/* -------------------------------------------------------------------- */
    CURL *http_handle = NULL;

    const char *pszPersistent = CSLFetchNameValue( papszOptions, "PERSISTENT" );
    const char *pszClosePersistent = CSLFetchNameValue( papszOptions, "CLOSE_PERSISTENT" );
    if (pszPersistent)
    {
        CPLString osSessionName = pszPersistent;
        CPLMutexHolder oHolder( &hSessionMapMutex );

        if( poSessionMap == NULL )
            poSessionMap = new std::map<CPLString,CURL*>;
        if( poSessionMap->count( osSessionName ) == 0 )
        {
            (*poSessionMap)[osSessionName] = curl_easy_init();
            CPLDebug( "HTTP", "Establish persistent session named '%s'.",
                      osSessionName.c_str() );
        }

        http_handle = (*poSessionMap)[osSessionName];
    }
/* -------------------------------------------------------------------- */
/*      Are we requested to close a persistent named session?          */
/* -------------------------------------------------------------------- */
    else if (pszClosePersistent)
    {
        CPLString osSessionName = pszClosePersistent;
        CPLMutexHolder oHolder( &hSessionMapMutex );

        if( poSessionMap )
        {
            std::map<CPLString,CURL*>::iterator oIter = poSessionMap->find( osSessionName );
            if( oIter != poSessionMap->end() )
            {
                curl_easy_cleanup(oIter->second);
                poSessionMap->erase(oIter);
                if( poSessionMap->size() == 0 )
                {
                    delete poSessionMap;
                    poSessionMap = NULL;
                }
                CPLDebug( "HTTP", "Ended persistent session named '%s'.",
                        osSessionName.c_str() );
            }
            else
            {
                CPLDebug( "HTTP", "Could not find persistent session named '%s'.",
                        osSessionName.c_str() );
            }
        }

        return NULL;
    }
    else
        http_handle = curl_easy_init();

/* -------------------------------------------------------------------- */
/*      Setup the request.                                              */
/* -------------------------------------------------------------------- */
    char szCurlErrBuf[CURL_ERROR_SIZE+1];
    CPLHTTPResult *psResult;
    struct curl_slist *headers=NULL; 

    const char* pszArobase = strchr(pszURL, '@');
    const char* pszSlash = strchr(pszURL, '/');
    const char* pszColon = (pszSlash) ? strchr(pszSlash, ':') : NULL;
    if (pszArobase != NULL && pszColon != NULL && pszArobase - pszColon > 0)
    {
        /* http://user:[email protected] */
        char* pszSanitizedURL = CPLStrdup(pszURL);
        pszSanitizedURL[pszColon-pszURL] = 0;
        CPLDebug( "HTTP", "Fetch(%s:#password#%s)", pszSanitizedURL, pszArobase );
        CPLFree(pszSanitizedURL);
    }
    else
    {
        CPLDebug( "HTTP", "Fetch(%s)", pszURL );
    }

    psResult = (CPLHTTPResult *) CPLCalloc(1,sizeof(CPLHTTPResult));

    curl_easy_setopt(http_handle, CURLOPT_URL, pszURL );

    CPLHTTPSetOptions(http_handle, papszOptions);

    // turn off SSL verification, accept all servers with ssl
    curl_easy_setopt(http_handle, CURLOPT_SSL_VERIFYPEER, FALSE);

    /* Set Headers.*/
    const char *pszHeaders = CSLFetchNameValue( papszOptions, "HEADERS" );
    if( pszHeaders != NULL ) {
        CPLDebug ("HTTP", "These HTTP headers were set: %s", pszHeaders);
        headers = curl_slist_append(headers, pszHeaders);
        curl_easy_setopt(http_handle, CURLOPT_HTTPHEADER, headers);
    }

    // are we making a head request
    const char* pszNoBody = NULL;
    if ((pszNoBody = CSLFetchNameValue( papszOptions, "NO_BODY" )) != NULL)
    {
        if (CSLTestBoolean(pszNoBody)) 
        {
            CPLDebug ("HTTP", "HEAD Request: %s", pszURL);
            curl_easy_setopt(http_handle, CURLOPT_NOBODY, 1L);           
        }
    }

    // capture response headers
    curl_easy_setopt(http_handle, CURLOPT_HEADERDATA, psResult);
    curl_easy_setopt(http_handle, CURLOPT_HEADERFUNCTION, CPLHdrWriteFct);
 
    curl_easy_setopt(http_handle, CURLOPT_WRITEDATA, psResult );
    curl_easy_setopt(http_handle, CURLOPT_WRITEFUNCTION, CPLWriteFct );

    szCurlErrBuf[0] = '\0';

    curl_easy_setopt(http_handle, CURLOPT_ERRORBUFFER, szCurlErrBuf );

    static int bHasCheckVersion = FALSE;
    static int bSupportGZip = FALSE;
    if (!bHasCheckVersion)
    {
        bSupportGZip = strstr(curl_version(), "zlib/") != NULL;
        bHasCheckVersion = TRUE;
    }
    int bGZipRequested = FALSE;
    if (bSupportGZip && CSLTestBoolean(CPLGetConfigOption("CPL_CURL_GZIP", "YES")))
    {
        bGZipRequested = TRUE;
        curl_easy_setopt(http_handle, CURLOPT_ENCODING, "gzip");
    }

/* -------------------------------------------------------------------- */
/*      If 502, 503 or 504 status code retry this HTTP call until max        */
/*      retry has been rearched                                         */
/* -------------------------------------------------------------------- */
    const char *pszRetryDelay = CSLFetchNameValue( papszOptions, "RETRY_DELAY" );
    if( pszRetryDelay == NULL )
        pszRetryDelay = CPLGetConfigOption( "GDAL_HTTP_RETRY_DELAY", "30" );
    const char *pszMaxRetries = CSLFetchNameValue( papszOptions, "MAX_RETRY" );
    if( pszMaxRetries == NULL )
        pszMaxRetries = CPLGetConfigOption( "GDAL_HTTP_MAX_RETRY", "0" );
    int nRetryDelaySecs = atoi(pszRetryDelay);
    int nMaxRetries = atoi(pszMaxRetries);
    int nRetryCount = 0;
    bool bRequestRetry;

    do
    {
        bRequestRetry = FALSE;

/* -------------------------------------------------------------------- */
/*      Execute the request, waiting for results.                       */
/* -------------------------------------------------------------------- */
        psResult->nStatus = (int) curl_easy_perform( http_handle );

/* -------------------------------------------------------------------- */
/*      Fetch content-type if possible.                                 */
/* -------------------------------------------------------------------- */
        psResult->pszContentType = NULL;
        curl_easy_getinfo( http_handle, CURLINFO_CONTENT_TYPE,
                           &(psResult->pszContentType) );
        if( psResult->pszContentType != NULL )
            psResult->pszContentType = CPLStrdup(psResult->pszContentType);

/* -------------------------------------------------------------------- */
/*      Have we encountered some sort of error?                         */
/* -------------------------------------------------------------------- */
        if( strlen(szCurlErrBuf) > 0 )
        {
            int bSkipError = FALSE;

            /* Some servers such as http://115.113.193.14/cgi-bin/world/qgis_mapserv.fcgi?VERSION=1.1.1&SERVICE=WMS&REQUEST=GetCapabilities */
            /* invalidly return Content-Length as the uncompressed size, with makes curl to wait for more data */
            /* and time-out finally. If we got the expected data size, then we don't emit an error */
            /* but turn off GZip requests */
            if (bGZipRequested &&
                strstr(szCurlErrBuf, "transfer closed with") &&
                strstr(szCurlErrBuf, "bytes remaining to read"))
            {
                const char* pszContentLength =
                    CSLFetchNameValue(psResult->papszHeaders, "Content-Length");
                if (pszContentLength && psResult->nDataLen != 0 &&
                    atoi(pszContentLength) == psResult->nDataLen)
                {
                    const char* pszCurlGZIPOption = CPLGetConfigOption("CPL_CURL_GZIP", NULL);
                    if (pszCurlGZIPOption == NULL)
                    {
                        CPLSetConfigOption("CPL_CURL_GZIP", "NO");
                        CPLDebug("HTTP", "Disabling CPL_CURL_GZIP, because %s doesn't support it properly",
                                 pszURL);
                    }
                    psResult->nStatus = 0;
                    bSkipError = TRUE;
                }
            }
            if (!bSkipError)
            {
                psResult->pszErrBuf = CPLStrdup(szCurlErrBuf);
                CPLError( CE_Failure, CPLE_AppDefined,
                        "%s", szCurlErrBuf );
            }
        }
        else
        {
            /* HTTP errors do not trigger curl errors. But we need to */
            /* propagate them to the caller though */
            long response_code = 0;
            curl_easy_getinfo(http_handle, CURLINFO_RESPONSE_CODE, &response_code);

            if (response_code >= 400 && response_code < 600)
            {
                /* If HTTP 502, 503 or 504 gateway timeout error retry after a pause */
                if ((response_code >= 502 && response_code <= 504) && nRetryCount < nMaxRetries)
                {
                    CPLError(CE_Warning, CPLE_AppDefined,
                             "HTTP error code: %d - %s. Retrying again in %d secs",
                             (int)response_code, pszURL, nRetryDelaySecs);
                    CPLSleep(nRetryDelaySecs);
                    nRetryCount++;

                    CPLFree(psResult->pszContentType);
                    psResult->pszContentType = NULL;
                    CSLDestroy(psResult->papszHeaders);
                    psResult->papszHeaders = NULL;
                    CPLFree(psResult->pabyData);
                    psResult->pabyData = NULL;
                    psResult->nDataLen = 0;
                    psResult->nDataAlloc = 0;

                    bRequestRetry = TRUE;
                }
                else
                {
                    psResult->pszErrBuf = CPLStrdup(CPLSPrintf("HTTP error code : %d", (int)response_code));
                    CPLError( CE_Failure, CPLE_AppDefined, "%s", psResult->pszErrBuf );
                }
            }
        }
    }
    while (bRequestRetry);

    if (!pszPersistent)
        curl_easy_cleanup( http_handle );

    curl_slist_free_all(headers);

    return psResult;
#endif /* def HAVE_CURL */
}
示例#13
0
int VSIMemFilesystemHandler::Unlink( const char * pszFilename )

{
    CPLMutexHolder oHolder( &hMutex );
    return Unlink_unlocked(pszFilename);
}
const VSIArchiveContent* VSIArchiveFilesystemHandler::GetContentOfArchive
        (const char* archiveFilename, VSIArchiveReader* poReader)
{
    CPLMutexHolder oHolder( &hMutex );

    if (oFileList.find(archiveFilename) != oFileList.end() )
    {
        return oFileList[archiveFilename];
    }

    int bMustClose = (poReader == NULL);
    if (poReader == NULL)
    {
        poReader = CreateReader(archiveFilename);
        if (!poReader)
            return NULL;
    }

    if (poReader->GotoFirstFile() == FALSE)
    {
        if (bMustClose)
            delete(poReader);
        return NULL;
    }

    VSIArchiveContent* content = new VSIArchiveContent;
    content->nEntries = 0;
    content->entries = NULL;
    oFileList[archiveFilename] = content;

    std::set<CPLString> oSet;

    do
    {
        CPLString osFileName = poReader->GetFileName();
        const char* fileName = osFileName.c_str();

        /* Remove ./ pattern at the beginning of a filename */
        if (fileName[0] == '.' && fileName[1] == '/')
        {
            fileName += 2;
            if (fileName[0] == '\0')
                continue;
        }

        char* pszStrippedFileName = CPLStrdup(fileName);
        char* pszIter;
        for(pszIter = pszStrippedFileName;*pszIter;pszIter++)
        {
            if (*pszIter == '\\')
                *pszIter = '/';
        }

        int bIsDir = strlen(fileName) > 0 &&
                      fileName[strlen(fileName)-1] == '/';
        if (bIsDir)
        {
            /* Remove trailing slash */
            pszStrippedFileName[strlen(fileName)-1] = 0;
        }

        if (oSet.find(pszStrippedFileName) == oSet.end())
        {
            oSet.insert(pszStrippedFileName);

            /* Add intermediate directory structure */
            for(pszIter = pszStrippedFileName;*pszIter;pszIter++)
            {
                if (*pszIter == '/')
                {
                    char* pszStrippedFileName2 = CPLStrdup(pszStrippedFileName);
                    pszStrippedFileName2[pszIter - pszStrippedFileName] = 0;
                    if (oSet.find(pszStrippedFileName2) == oSet.end())
                    {
                        oSet.insert(pszStrippedFileName2);

                        content->entries = (VSIArchiveEntry*)CPLRealloc(content->entries,
                                sizeof(VSIArchiveEntry) * (content->nEntries + 1));
                        content->entries[content->nEntries].fileName = pszStrippedFileName2;
                        content->entries[content->nEntries].nModifiedTime = poReader->GetModifiedTime();
                        content->entries[content->nEntries].uncompressed_size = 0;
                        content->entries[content->nEntries].bIsDir = TRUE;
                        content->entries[content->nEntries].file_pos = NULL;
                        if (ENABLE_DEBUG)
                            CPLDebug("VSIArchive", "[%d] %s : " CPL_FRMT_GUIB " bytes", content->nEntries+1,
                                content->entries[content->nEntries].fileName,
                                content->entries[content->nEntries].uncompressed_size);
                        content->nEntries++;
                    }
                    else
                    {
                        CPLFree(pszStrippedFileName2);
                    }
                }
            }

            content->entries = (VSIArchiveEntry*)CPLRealloc(content->entries,
                                sizeof(VSIArchiveEntry) * (content->nEntries + 1));
            content->entries[content->nEntries].fileName = pszStrippedFileName;
            content->entries[content->nEntries].nModifiedTime = poReader->GetModifiedTime();
            content->entries[content->nEntries].uncompressed_size = poReader->GetFileSize();
            content->entries[content->nEntries].bIsDir = bIsDir;
            content->entries[content->nEntries].file_pos = poReader->GetFileOffset();
            if (ENABLE_DEBUG)
                CPLDebug("VSIArchive", "[%d] %s : " CPL_FRMT_GUIB " bytes", content->nEntries+1,
                    content->entries[content->nEntries].fileName,
                    content->entries[content->nEntries].uncompressed_size);
            content->nEntries++;
        }
        else
        {
            CPLFree(pszStrippedFileName);
        }
    } while(poReader->GotoNextFile());

    if (bMustClose)
        delete(poReader);

    return content;
}
char* VSIArchiveFilesystemHandler::SplitFilename(const char *pszFilename,
                                                 CPLString &osFileInArchive,
                                                 int bCheckMainFileExists)
{
    int i = 0;

    if (strcmp(pszFilename, GetPrefix()) == 0)
        return NULL;

    /* Allow natural chaining of VSI drivers without requiring double slash */
    
    CPLString osDoubleVsi(GetPrefix());
    osDoubleVsi += "/vsi";
    
    if (strncmp(pszFilename, osDoubleVsi.c_str(), osDoubleVsi.size()) == 0)
        pszFilename += strlen(GetPrefix());
    else
        pszFilename += strlen(GetPrefix()) + 1;

    while(pszFilename[i])
    {
        std::vector<CPLString> oExtensions = GetExtensions();
        std::vector<CPLString>::const_iterator iter;
        int nToSkip = 0;

        for( iter = oExtensions.begin(); iter != oExtensions.end(); ++iter )
        {
            const CPLString& osExtension = *iter;
            if (EQUALN(pszFilename + i, osExtension.c_str(), strlen(osExtension.c_str())))
            {
                nToSkip = strlen(osExtension.c_str());
                break;
            }
        }

        if (nToSkip != 0)
        {
            VSIStatBufL statBuf;
            char* archiveFilename = CPLStrdup(pszFilename);
            int bArchiveFileExists = FALSE;

            if (archiveFilename[i + nToSkip] == '/' ||
                archiveFilename[i + nToSkip] == '\\')
            {
                archiveFilename[i + nToSkip] = 0;
            }

            if (!bCheckMainFileExists)
            {
                bArchiveFileExists = TRUE;
            }
            else
            {
                CPLMutexHolder oHolder( &hMutex );

                if (oFileList.find(archiveFilename) != oFileList.end() )
                {
                    bArchiveFileExists = TRUE;
                }
            }

            if (!bArchiveFileExists)
            {
                VSIFilesystemHandler *poFSHandler = 
                    VSIFileManager::GetHandler( archiveFilename );
                if (poFSHandler->Stat(archiveFilename, &statBuf,
                                      VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG) == 0 &&
                    !VSI_ISDIR(statBuf.st_mode))
                {
                    bArchiveFileExists = TRUE;
                }
            }

            if (bArchiveFileExists)
            {
                if (pszFilename[i + nToSkip] == '/' ||
                    pszFilename[i + nToSkip] == '\\')
                {
                    char* pszArchiveInFileName = CPLStrdup(pszFilename + i + nToSkip + 1);

                    /* Replace a/../b by b and foo/a/../b by foo/b */
                    while(TRUE)
                    {
                        char* pszPrevDir = strstr(pszArchiveInFileName, "/../");
                        if (pszPrevDir == NULL || pszPrevDir == pszArchiveInFileName)
                            break;

                        char* pszPrevSlash = pszPrevDir - 1;
                        while(pszPrevSlash != pszArchiveInFileName &&
                                *pszPrevSlash != '/')
                            pszPrevSlash --;
                        if (pszPrevSlash == pszArchiveInFileName)
                            memmove(pszArchiveInFileName, pszPrevDir + nToSkip, strlen(pszPrevDir + nToSkip) + 1);
                        else
                            memmove(pszPrevSlash + 1, pszPrevDir + nToSkip, strlen(pszPrevDir + nToSkip) + 1);
                    }

                    osFileInArchive = pszArchiveInFileName;
                    CPLFree(pszArchiveInFileName);
                }
                else
                    osFileInArchive = "";

                /* Remove trailing slash */
                if (osFileInArchive.size())
                {
                    char lastC = osFileInArchive[strlen(osFileInArchive) - 1];
                    if (lastC == '\\' || lastC == '/')
                        osFileInArchive.resize(strlen(osFileInArchive) - 1);
                }

                return archiveFilename;
            }
            CPLFree(archiveFilename);
        }
        i++;
    }
    return NULL;
}
示例#16
0
/**
 * \brief Fetch a document from an url and return in a string.
 *
 * @param pszURL valid URL recognized by underlying download library (libcurl)
 * @param papszOptions option list as a NULL-terminated array of strings. May be NULL.
 *                     The following options are handled :
 * <ul>
 * <li>TIMEOUT=val, where val is in seconds</li>
 * <li>HEADERS=val, where val is an extra header to use when getting a web page.
 *                  For example "Accept: application/x-ogcwkt"
 * <li>HTTPAUTH=[BASIC/NTLM/GSSNEGOTIATE/ANY] to specify an authentication scheme to use.
 * <li>USERPWD=userid:password to specify a user and password for authentication
 * <li>POSTFIELDS=val, where val is a nul-terminated string to be passed to the server
 *                     with a POST request.
 * <li>PROXY=val, to make requests go through a proxy server, where val is of the
 *                form proxy.server.com:port_number
 * <li>PROXYUSERPWD=val, where val is of the form username:password
 * <li>CUSTOMREQUEST=val, where val is GET, PUT, POST, DELETE, etc.. (GDAL >= 1.9.0)
 * </ul>
 *
 * Alternatively, if not defined in the papszOptions arguments, the PROXY and 
 * PROXYUSERPWD values are searched in the configuration options named 
 * GDAL_HTTP_PROXY and GDAL_HTTP_PROXYUSERPWD, as proxy configuration belongs 
 * to networking setup and makes more sense at the configuration option level 
 * than at the connection level.
 *
 * @return a CPLHTTPResult* structure that must be freed by 
 * CPLHTTPDestroyResult(), or NULL if libcurl support is disabled
 */
CPLHTTPResult *CPLHTTPFetch( const char *pszURL, char **papszOptions )

{
#ifndef HAVE_CURL
    (void) papszOptions;
    (void) pszURL;

    CPLError( CE_Failure, CPLE_NotSupported,
              "GDAL/OGR not compiled with libcurl support, remote requests not supported." );
    return NULL;
#else
/* -------------------------------------------------------------------- */
/*      Are we using a persistent named session?  If so, search for     */
/*      or create it.                                                   */
/*                                                                      */
/*      Currently this code does not attempt to protect against         */
/*      multiple threads asking for the same named session.  If that    */
/*      occurs it will be in use in multiple threads at once which      */
/*      might have bad consequences depending on what guarantees        */
/*      libcurl gives - which I have not investigated.                  */
/* -------------------------------------------------------------------- */
    CURL *http_handle = NULL;

    const char *pszPersistent = CSLFetchNameValue( papszOptions, "PERSISTENT" );
    const char *pszClosePersistent = CSLFetchNameValue( papszOptions, "CLOSE_PERSISTENT" );
    if (pszPersistent)
    {
        CPLString osSessionName = pszPersistent;
        CPLMutexHolder oHolder( &hSessionMapMutex );

        if( oSessionMap.count( osSessionName ) == 0 )
        {
            oSessionMap[osSessionName] = curl_easy_init();
            CPLDebug( "HTTP", "Establish persistent session named '%s'.",
                      osSessionName.c_str() );
        }

        http_handle = oSessionMap[osSessionName];
    }
/* -------------------------------------------------------------------- */
/*      Are we requested to close a persistent named session?          */
/* -------------------------------------------------------------------- */
    else if (pszClosePersistent)
    {
        CPLString osSessionName = pszClosePersistent;
        CPLMutexHolder oHolder( &hSessionMapMutex );

        std::map<CPLString,CURL*>::iterator oIter = oSessionMap.find( osSessionName );
        if( oIter != oSessionMap.end() )
        {
            curl_easy_cleanup(oIter->second);
            oSessionMap.erase(oIter);
            CPLDebug( "HTTP", "Ended persistent session named '%s'.",
                      osSessionName.c_str() );
        }
        else
        {
            CPLDebug( "HTTP", "Could not find persistent session named '%s'.",
                      osSessionName.c_str() );
        }

        return NULL;
    }
    else
        http_handle = curl_easy_init();

/* -------------------------------------------------------------------- */
/*      Setup the request.                                              */
/* -------------------------------------------------------------------- */
    char szCurlErrBuf[CURL_ERROR_SIZE+1];
    CPLHTTPResult *psResult;
    struct curl_slist *headers=NULL; 

    const char* pszArobase = strchr(pszURL, '@');
    const char* pszSlash = strchr(pszURL, '/');
    const char* pszColon = (pszSlash) ? strchr(pszSlash, ':') : NULL;
    if (pszArobase != NULL && pszColon != NULL && pszArobase - pszColon > 0)
    {
        /* http://user:[email protected] */
        char* pszSanitizedURL = CPLStrdup(pszURL);
        pszSanitizedURL[pszColon-pszURL] = 0;
        CPLDebug( "HTTP", "Fetch(%s:#password#%s)", pszSanitizedURL, pszArobase );
        CPLFree(pszSanitizedURL);
    }
    else
    {
        CPLDebug( "HTTP", "Fetch(%s)", pszURL );
    }

    psResult = (CPLHTTPResult *) CPLCalloc(1,sizeof(CPLHTTPResult));

    curl_easy_setopt(http_handle, CURLOPT_URL, pszURL );

    if (CSLTestBoolean(CPLGetConfigOption("CPL_CURL_VERBOSE", "NO")))
        curl_easy_setopt(http_handle, CURLOPT_VERBOSE, 1);

    const char *pszHttpVersion = CSLFetchNameValue( papszOptions, "HTTP_VERSION");
    if( pszHttpVersion && strcmp(pszHttpVersion, "1.0") == 0 )
        curl_easy_setopt(http_handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0 );

    /* Support control over HTTPAUTH */
    const char *pszHttpAuth = CSLFetchNameValue( papszOptions, "HTTPAUTH" );
    if( pszHttpAuth == NULL )
        /* do nothing */;

    /* CURLOPT_HTTPAUTH is defined in curl 7.11.0 or newer */
#if LIBCURL_VERSION_NUM >= 0x70B00
    else if( EQUAL(pszHttpAuth,"BASIC") )
        curl_easy_setopt(http_handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC );
    else if( EQUAL(pszHttpAuth,"NTLM") )
        curl_easy_setopt(http_handle, CURLOPT_HTTPAUTH, CURLAUTH_NTLM );
    else if( EQUAL(pszHttpAuth,"ANY") )
        curl_easy_setopt(http_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY );
#ifdef CURLAUTH_GSSNEGOTIATE
    else if( EQUAL(pszHttpAuth,"NEGOTIATE") )
        curl_easy_setopt(http_handle, CURLOPT_HTTPAUTH, CURLAUTH_GSSNEGOTIATE );
#endif
    else
    {
        CPLError( CE_Warning, CPLE_AppDefined,
                  "Unsupported HTTPAUTH value '%s', ignored.", 
                  pszHttpAuth );
    }
#else
    else
    {
示例#17
0
/**
 * \brief Fetch a document from an url and return in a string.
 *
 * @param pszURL valid URL recognized by underlying download library (libcurl)
 * @param papszOptions option list as a NULL-terminated array of strings. May be NULL.
 *                     The following options are handled :
 * <ul>
 * <li>TIMEOUT=val, where val is in seconds</li>
 * <li>HEADERS=val, where val is an extra header to use when getting a web page.
 *                  For example "Accept: application/x-ogcwkt"
 * <li>HTTPAUTH=[BASIC/NTLM/ANY] to specify an authentication scheme to use.
 * <li>USERPWD=userid:password to specify a user and password for authentication
 * <li>POSTFIELDS=val, where val is a nul-terminated string to be passed to the server
 *                     with a POST request.
 * <li>PROXY=val, to make requests go through a proxy server, where val is of the
 *                form proxy.server.com:port_number
 * <li>PROXYUSERPWD=val, where val is of the form username:password
 * </ul>
 *
 * Alternatively, if not defined in the papszOptions arguments, the PROXY and PROXYUSERPWD
 * values are searched in the configuration options named GDAL_HTTP_PROXY and GDAL_HTTP_PROXYUSERPWD,
 * as proxy configuration belongs to networking setup and makes more sense at the configuration
 * option level than at the connection level.
 *
 * @return a CPLHTTPResult* structure that must be freed by CPLHTTPDestroyResult(),
 *         or NULL if libcurl support is disabled
 */
CPLHTTPResult *CPLHTTPFetch( const char *pszURL, char **papszOptions )

{
#ifndef HAVE_CURL
    (void) papszOptions;
    (void) pszURL;

    CPLError( CE_Failure, CPLE_NotSupported,
              "GDAL/OGR not compiled with libcurl support, remote requests not supported." );
    return NULL;
#else
    /* -------------------------------------------------------------------- */
    /*      Are we using a persistent named session?  If so, search for     */
    /*      or create it.                                                   */
    /*                                                                      */
    /*      Currently this code does not attempt to protect against         */
    /*      multiple threads asking for the same named session.  If that    */
    /*      occurs it will be in use in multiple threads at once which      */
    /*      might have bad consequences depending on what guarantees        */
    /*      libcurl gives - which I have not investigated.                  */
    /* -------------------------------------------------------------------- */
    CURL *http_handle = NULL;

    const char *pszPersistent = CSLFetchNameValue( papszOptions, "PERSISTENT" );
    if (pszPersistent)
    {
        CPLString osSessionName = pszPersistent;
        CPLMutexHolder oHolder( &hSessionMapMutex );

        if( oSessionMap.count( osSessionName ) == 0 )
        {
            oSessionMap[osSessionName] = curl_easy_init();
            CPLDebug( "HTTP", "Establish persistent session named '%s'.",
                      osSessionName.c_str() );
        }

        http_handle = oSessionMap[osSessionName];
    }
    else
        http_handle = curl_easy_init();

    /* -------------------------------------------------------------------- */
    /*      Setup the request.                                              */
    /* -------------------------------------------------------------------- */
    char szCurlErrBuf[CURL_ERROR_SIZE+1];
    CPLHTTPResult *psResult;
    struct curl_slist *headers=NULL;

    CPLDebug( "HTTP", "Fetch(%s)", pszURL );

    psResult = (CPLHTTPResult *) CPLCalloc(1,sizeof(CPLHTTPResult));

    curl_easy_setopt(http_handle, CURLOPT_URL, pszURL );


    const char *pszHttpVersion = CSLFetchNameValue( papszOptions, "HTTP_VERSION");
    if( pszHttpVersion && strcmp(pszHttpVersion, "1.0") == 0 )
        curl_easy_setopt(http_handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0 );

    /* Support control over HTTPAUTH */
    const char *pszHttpAuth = CSLFetchNameValue( papszOptions, "HTTPAUTH" );
    if( pszHttpAuth == NULL )
        /* do nothing */;

    /* CURLOPT_HTTPAUTH is defined in curl 7.11.0 or newer */
#if LIBCURL_VERSION_NUM >= 0x70B00
    else if( EQUAL(pszHttpAuth,"BASIC") )
        curl_easy_setopt(http_handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC );
    else if( EQUAL(pszHttpAuth,"NTLM") )
        curl_easy_setopt(http_handle, CURLOPT_HTTPAUTH, CURLAUTH_NTLM );
    else if( EQUAL(pszHttpAuth,"ANY") )
        curl_easy_setopt(http_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY );
    else
    {
        CPLError( CE_Warning, CPLE_AppDefined,
                  "Unsupported HTTPAUTH value '%s', ignored.",
                  pszHttpAuth );
    }
#else
    else
    {
void VSIUnixStdioFilesystemHandler::AddToTotal(vsi_l_offset nBytes)
{
    CPLMutexHolder oHolder(&hMutex);
    nTotalBytesRead += nBytes;
}