void OGRElasticDataSource::FetchMapping(const char* pszIndexName)
{
    if( m_oSetLayers.find(pszIndexName) != m_oSetLayers.end() )
        return;

    CPLString osURL(m_osURL + CPLString("/") + pszIndexName +
                    CPLString("/_mapping?pretty"));
    json_object* poRes = RunRequest(osURL, nullptr, std::vector<int>({403}));
    if( poRes )
    {
        json_object* poLayerObj = CPL_json_object_object_get(poRes, pszIndexName);
        json_object* poMappings = nullptr;
        if( poLayerObj && json_object_get_type(poLayerObj) == json_type_object )
            poMappings = CPL_json_object_object_get(poLayerObj, "mappings");
        if( poMappings && json_object_get_type(poMappings) == json_type_object )
        {
            json_object_iter it;
            it.key = nullptr;
            it.val = nullptr;
            it.entry = nullptr;
            std::vector<CPLString> aosMappings;
            json_object_object_foreachC( poMappings, it )
            {
                aosMappings.push_back(it.key);
            }
            if( aosMappings.size() == 1 &&
                (aosMappings[0] == "FeatureCollection" || aosMappings[0] == "default") )
            {
                m_oSetLayers.insert(pszIndexName);
                OGRElasticLayer* poLayer = new OGRElasticLayer(
                    pszIndexName, pszIndexName, aosMappings[0], this, papszOpenOptions);
                poLayer->InitFeatureDefnFromMapping(
                    CPL_json_object_object_get(poMappings, aosMappings[0]),
                    "", std::vector<CPLString>());
                m_apoLayers.push_back(std::unique_ptr<OGRElasticLayer>(poLayer));
            }
            else
            {
                for(size_t i=0; i<aosMappings.size();i++)
                {
                    CPLString osLayerName(pszIndexName + CPLString("_") + aosMappings[i]);
                    if( m_oSetLayers.find(osLayerName) == m_oSetLayers.end() )
                    {
                        m_oSetLayers.insert(osLayerName);
                        OGRElasticLayer* poLayer = new OGRElasticLayer(
                            osLayerName,
                            pszIndexName, aosMappings[i], this, papszOpenOptions);
                        poLayer->InitFeatureDefnFromMapping(
                            CPL_json_object_object_get(poMappings, aosMappings[i]),
                            "", std::vector<CPLString>());

                        m_apoLayers.push_back(std::unique_ptr<OGRElasticLayer>(poLayer));
                    }
                }
            }
        }
bool OGRAmigoCloudDataSource::RunDELETE(const char*pszURL)
{
    CPLString osURL(pszURL);

    /* -------------------------------------------------------------------- */
    /*      Provide the API Key                                             */
    /* -------------------------------------------------------------------- */
    if( !osAPIKey.empty() )
    {
        if(osURL.find("?") == std::string::npos)
            osURL += "?token=";
        else
            osURL += "&token=";
        osURL += osAPIKey;
    }

    char** papszOptions=nullptr;
    CPLString osPOSTFIELDS("CUSTOMREQUEST=DELETE");
    papszOptions = CSLAddString(papszOptions, osPOSTFIELDS);
    papszOptions = CSLAddString(papszOptions, GetUserAgentOption().c_str());

    CPLHTTPResult * psResult = CPLHTTPFetch( osURL.c_str(), papszOptions);
    CSLDestroy(papszOptions);
    if( psResult == nullptr )
        return false;

    if (psResult->pszContentType &&
        strncmp(psResult->pszContentType, "text/html", 9) == 0)
    {
        CPLDebug( "AMIGOCLOUD", "RunDELETE HTML Response:%s", psResult->pabyData );
        CPLError(CE_Failure, CPLE_AppDefined,
                 "HTML error page returned by server:%s", psResult->pabyData);
        CPLHTTPDestroyResult(psResult);
        return false;
    }
    if (psResult->pszErrBuf != nullptr && psResult->pabyData != nullptr )
    {
        CPLError( CE_Failure, CPLE_AppDefined, "DELETE Response: %s", psResult->pabyData );
    }
    else if ( psResult->nStatus != 0)
    {
        CPLDebug( "AMIGOCLOUD", "DELETE Error Status:%d", psResult->nStatus );
    }
    CPLHTTPDestroyResult(psResult);

    return true;
}
Exemple #3
0
/**
 * Return a new URL with a new key=value pair.
 *
 * @param pszURL the URL.
 * @param pszKey the key to find.
 * @param pszValue the value of the key (may be NULL to unset an existing KVP).
 * @return the modified URL.
 * @since GDAL 1.9.0
 */
CPLString CPLURLAddKVP(const char* pszURL, const char* pszKey,
                       const char* pszValue)
{
    CPLString osURL(pszURL);
    if (strchr(osURL, '?') == NULL)
        osURL += "?";
    pszURL = osURL.c_str();

    CPLString osKey(pszKey);
    osKey += "=";
    size_t nKeyPos = osURL.ifind(osKey);
    if (nKeyPos != std::string::npos)
    {
        CPLString osNewURL(osURL);
        osNewURL.resize(nKeyPos);
        if (pszValue)
        {
            if (osNewURL[osNewURL.size()-1] != '&' &&
                osNewURL[osNewURL.size()-1] != '?')
                osNewURL += '&';
            osNewURL += osKey;
            osNewURL += pszValue;
        }
        const char* pszNext = strchr(pszURL + nKeyPos, '&');
        if (pszNext)
        {
            if (osNewURL[osNewURL.size()-1] == '&'
                || osNewURL[osNewURL.size()-1] == '?' )
                osNewURL += pszNext + 1;
            else
                osNewURL += pszNext;
        }
        return osNewURL;
    }
    else
    {
        if (pszValue)
        {
            if (osURL[osURL.size()-1] != '&' && osURL[osURL.size()-1] != '?')
                osURL += '&';
            osURL += osKey;
            osURL += pszValue;
        }
        return osURL;
    }
}
GIntBig OGRPLScenesLayer::GetFeatureCount(int bForce)
{
    if( nFeatureCount < 0 )
    {
        CPLString osURL(BuildURL(1));
        if( bFilterMustBeClientSideEvaluated )
        {
            nFeatureCount = OGRLayer::GetFeatureCount(bForce);
        }
        else if( osURL.find('?') == std::string::npos )
        {
            /* Case of a "id = XXXXX" filter: we get directly a Feature, */
            /* not a FeatureCollection */
            GetNextPage();
        }
        else
        {
            nFeatureCount = 0;
            json_object* poObj = poDS->RunRequest(osURL);
            if( poObj != NULL )
            {
                json_object* poCount = json_object_object_get(poObj, "count");
                if( poCount != NULL )
                    nFeatureCount = MAX(0, json_object_get_int64(poCount));

                // Small optimization, if the feature count is actually 1
                // then we can fetch it as the full layer
                if( nFeatureCount == 1 )
                {
                    delete poGeoJSONDS;
                    // Parse the Feature/FeatureCollection with the GeoJSON reader
                    poGeoJSONDS = new OGRGeoJSONDataSource();
                    OGRGeoJSONReader oReader;
                    oReader.SetFlattenNestedAttributes(true, '.');
                    oReader.ReadLayer( poGeoJSONDS, "layer", poObj);
                    poGeoJSONLayer = poGeoJSONDS->GetLayer(0);
                    osNextURL = "";
                }
                json_object_put(poObj);
            }
        }
    }

    return nFeatureCount;
}
OGRLayer *OGRPLScenesDataV1Dataset::GetLayerByName(const char* pszName)
{
    // Prevent GetLayerCount() from calling EstablishLayerList()
    bool bLayerListInitializedBackup = m_bLayerListInitialized;
    m_bLayerListInitialized = true;
    OGRLayer* poRet = GDALDataset::GetLayerByName(pszName);
    m_bLayerListInitialized = bLayerListInitializedBackup;
    if( poRet != nullptr )
        return poRet;

    CPLString osURL(m_osBaseURL + "item-types/" + pszName);
    json_object* poObj = RunRequest(osURL);
    if( poObj == nullptr )
        return nullptr;
    poRet = ParseItemType(poObj);
    json_object_put(poObj);
    return poRet;
}
void OGRPLScenesDataV1Dataset::EstablishLayerList()
{
    CPLString osURL(m_osNextItemTypesPageURL);
    m_osNextItemTypesPageURL = "";

    while( !osURL.empty() )
    {
        json_object* poObj = RunRequest(osURL);
        if( poObj == nullptr )
            break;
        if( !ParseItemTypes( poObj, osURL ) )
        {
            json_object_put(poObj);
            break;
        }
        json_object_put(poObj);
    }
}
json_object* OGRAmigoCloudDataSource::RunGET(const char*pszURL)
{
    CPLString osURL(pszURL);

    /* -------------------------------------------------------------------- */
    /*      Provide the API Key                                             */
    /* -------------------------------------------------------------------- */
    if( osAPIKey.size() > 0 )
    {
        osURL += "?token=";
        osURL += osAPIKey;
    }

    CPLHTTPResult * psResult = CPLHTTPFetch( osURL.c_str(), NULL);
    if( psResult == NULL )
        return NULL;

    if (psResult->pszContentType &&
        strncmp(psResult->pszContentType, "text/html", 9) == 0)
    {
        CPLDebug( "AMIGOCLOUD", "RunGET HTML Response:%s", psResult->pabyData );
        CPLError(CE_Failure, CPLE_AppDefined,
                 "HTML error page returned by server:%s", psResult->pabyData);
        CPLHTTPDestroyResult(psResult);
        return NULL;
    }
    if ( psResult->pszErrBuf != NULL)
    {
        CPLDebug( "AMIGOCLOUD", "RunGET Error Message:%s", psResult->pszErrBuf );
    }
    else if (psResult->nStatus != 0)
    {
        CPLDebug( "AMIGOCLOUD", "RunGET Error Status:%d", psResult->nStatus );
    }

    if( psResult->pabyData == NULL )
    {
        CPLHTTPDestroyResult(psResult);
        return NULL;
    }

    CPLDebug( "AMIGOCLOUD", "RunGET Response:%s", psResult->pabyData );

    json_tokener* jstok = NULL;
    json_object* poObj = NULL;

    jstok = json_tokener_new();
    poObj = json_tokener_parse_ex(jstok, (const char*) psResult->pabyData, -1);
    if( jstok->err != json_tokener_success)
    {
        CPLError( CE_Failure, CPLE_AppDefined,
                  "JSON parsing error: %s (at offset %d)",
                  json_tokener_error_desc(jstok->err), jstok->char_offset);
        json_tokener_free(jstok);
        CPLHTTPDestroyResult(psResult);
        return NULL;
    }
    json_tokener_free(jstok);

    CPLHTTPDestroyResult(psResult);

    if( poObj != NULL )
    {
        if( json_object_get_type(poObj) == json_type_object )
        {
            json_object* poError = CPL_json_object_object_get(poObj, "error");
            if( poError != NULL && json_object_get_type(poError) == json_type_array &&
                json_object_array_length(poError) > 0 )
            {
                poError = json_object_array_get_idx(poError, 0);
                if( poError != NULL && json_object_get_type(poError) == json_type_string )
                {
                    CPLError(CE_Failure, CPLE_AppDefined,
                             "Error returned by server : %s", json_object_get_string(poError));
                    json_object_put(poObj);
                    return NULL;
                }
            }
        }
        else
        {
            json_object_put(poObj);
            return NULL;
        }
    }

    return poObj;
}
json_object* OGRAmigoCloudDataSource::RunGET(const char*pszURL)
{
    CPLString osURL(pszURL);

    /* -------------------------------------------------------------------- */
    /*      Provide the API Key                                             */
    /* -------------------------------------------------------------------- */
    if( !osAPIKey.empty() )
    {
        if(osURL.find("?") == std::string::npos)
            osURL += "?token=";
        else
            osURL += "&token=";
        osURL += osAPIKey;
    }
    char** papszOptions=nullptr;
    papszOptions = CSLAddString(papszOptions, GetUserAgentOption().c_str());

    CPLHTTPResult * psResult = CPLHTTPFetch( osURL.c_str(), papszOptions);
    CSLDestroy( papszOptions );
    if( psResult == nullptr ) {
        return nullptr;
    }

    if (psResult->pszContentType &&
        strncmp(psResult->pszContentType, "text/html", 9) == 0)
    {
        CPLError(CE_Failure, CPLE_AppDefined,
                 "HTML error page returned by server:%s", psResult->pabyData);
        CPLHTTPDestroyResult(psResult);
        return nullptr;
    }
    if (psResult->pszErrBuf != nullptr && psResult->pabyData != nullptr )
    {
        CPLError( CE_Failure, CPLE_AppDefined, "GET Response: %s", psResult->pabyData );
    }
    else if (psResult->nStatus != 0)
    {
        CPLDebug( "AMIGOCLOUD", "RunGET Error Status:%d", psResult->nStatus );
    }

    if( psResult->pabyData == nullptr )
    {
        CPLHTTPDestroyResult(psResult);
        return nullptr;
    }

    CPLDebug( "AMIGOCLOUD", "RunGET Response:%s", psResult->pabyData );

    json_object* poObj = nullptr;
    const char* pszText = reinterpret_cast<const char*>(psResult->pabyData);
    if( !OGRJSonParse(pszText, &poObj, true) )
    {
        CPLHTTPDestroyResult(psResult);
        return nullptr;
    }

    CPLHTTPDestroyResult(psResult);

    if( poObj != nullptr )
    {
        if( json_object_get_type(poObj) == json_type_object )
        {
            json_object* poError = CPL_json_object_object_get(poObj, "error");
            if( poError != nullptr && json_object_get_type(poError) == json_type_array &&
                json_object_array_length(poError) > 0 )
            {
                poError = json_object_array_get_idx(poError, 0);
                if( poError != nullptr && json_object_get_type(poError) == json_type_string )
                {
                    CPLError(CE_Failure, CPLE_AppDefined,
                             "Error returned by server : %s", json_object_get_string(poError));
                    json_object_put(poObj);
                    return nullptr;
                }
            }
        }
        else
        {
            json_object_put(poObj);
            return nullptr;
        }
    }

    return poObj;
}
json_object* OGRPLScenesDataV1Dataset::RunRequest(const char* pszURL,
                                              int bQuiet404Error,
                                              const char* pszHTTPVerb,
                                              bool bExpectJSonReturn,
                                              const char* pszPostContent)
{
    char** papszOptions = CSLAddString(GetBaseHTTPOptions(), nullptr);
    // We need to set it each time as CURL would reuse the previous value
    // if reusing the same connection
    papszOptions = CSLSetNameValue(papszOptions, "CUSTOMREQUEST", pszHTTPVerb);
    if( pszPostContent != nullptr )
    {
        CPLString osHeaders = CSLFetchNameValueDef(papszOptions, "HEADERS", "");
        if( !osHeaders.empty() )
            osHeaders += "\r\n";
        osHeaders += "Content-Type: application/json";
        papszOptions = CSLSetNameValue(papszOptions, "HEADERS", osHeaders);
        papszOptions = CSLSetNameValue(papszOptions, "POSTFIELDS", pszPostContent);
    }
    papszOptions = CSLSetNameValue(papszOptions, "MAX_RETRY", "3");
    CPLHTTPResult *psResult = nullptr;
    if( STARTS_WITH(m_osBaseURL, "/vsimem/") &&
        STARTS_WITH(pszURL, "/vsimem/") )
    {
        psResult = (CPLHTTPResult*) CPLCalloc(1, sizeof(CPLHTTPResult));
        vsi_l_offset nDataLengthLarge = 0;
        CPLString osURL(pszURL);
        if( osURL[osURL.size()-1 ] == '/' )
            osURL.resize(osURL.size()-1);
        if( pszPostContent != nullptr )
        {
            osURL += "&POSTFIELDS=";
            osURL += pszPostContent;
        }
        CPLDebug("PLSCENES", "Fetching %s", osURL.c_str());
        GByte* pabyBuf = VSIGetMemFileBuffer(osURL, &nDataLengthLarge, FALSE);
        size_t nDataLength = static_cast<size_t>(nDataLengthLarge);
        if( pabyBuf )
        {
            psResult->pabyData = (GByte*) VSI_MALLOC_VERBOSE(1 + nDataLength);
            if( psResult->pabyData )
            {
                memcpy(psResult->pabyData, pabyBuf, nDataLength);
                psResult->pabyData[nDataLength] = 0;
            }
        }
        else
        {
            psResult->pszErrBuf =
                CPLStrdup(CPLSPrintf("Error 404. Cannot find %s", osURL.c_str()));
        }
    }
    else
    {
        if( bQuiet404Error )
            CPLPushErrorHandler(CPLQuietErrorHandler);
        psResult = CPLHTTPFetch( pszURL, papszOptions);
        if( bQuiet404Error )
            CPLPopErrorHandler();
    }
    CSLDestroy(papszOptions);

    if( pszPostContent != nullptr && m_bMustCleanPersistent )
    {
        papszOptions = CSLSetNameValue(nullptr, "CLOSE_PERSISTENT", CPLSPrintf("PLSCENES:%p", this));
        CPLHTTPDestroyResult(CPLHTTPFetch(m_osBaseURL, papszOptions));
        CSLDestroy(papszOptions);
        m_bMustCleanPersistent = false;
    }

    if( psResult->pszErrBuf != nullptr )
    {
        if( !(bQuiet404Error && strstr(psResult->pszErrBuf, "404")) )
        {
            CPLError(CE_Failure, CPLE_AppDefined, "%s",
                    psResult->pabyData ? (const char*) psResult->pabyData :
                    psResult->pszErrBuf);
        }
        CPLHTTPDestroyResult(psResult);
        return nullptr;
    }

    if( !bExpectJSonReturn && (psResult->pabyData == nullptr || psResult->nDataLen == 0) )
    {
        CPLHTTPDestroyResult(psResult);
        return nullptr;
    }

    if( psResult->pabyData == nullptr )
    {
        CPLError(CE_Failure, CPLE_AppDefined, "Empty content returned by server");
        CPLHTTPDestroyResult(psResult);
        return nullptr;
    }

    const char* pszText = reinterpret_cast<const char*>(psResult->pabyData);
#ifdef DEBUG_VERBOSE
    CPLDebug("PLScenes", "%s", pszText);
#endif

    json_object* poObj = nullptr;
    if( !OGRJSonParse(pszText, &poObj, true) )
    {
        CPLHTTPDestroyResult(psResult);
        return nullptr;
    }

    CPLHTTPDestroyResult(psResult);

    if( json_object_get_type(poObj) != json_type_object )
    {
        CPLError( CE_Failure, CPLE_AppDefined, "Return is not a JSON dictionary");
        json_object_put(poObj);
        poObj = nullptr;
    }

    return poObj;
}
Exemple #10
0
GDALDataset *GDALWMSDataset::Open(GDALOpenInfo *poOpenInfo)
{
    CPLXMLNode *config = NULL;
    CPLErr ret = CE_None;

    const char* pszFilename = poOpenInfo->pszFilename;
    const char* pabyHeader = (const char *) poOpenInfo->pabyHeader;

    if (poOpenInfo->nHeaderBytes == 0 &&
        EQUALN(pszFilename, "<GDAL_WMS>", 10))
    {
        config = CPLParseXMLString(pszFilename);
    }
    else if (poOpenInfo->nHeaderBytes >= 10 &&
             EQUALN(pabyHeader, "<GDAL_WMS>", 10))
    {
        config = CPLParseXMLFile(pszFilename);
    }
    else if (poOpenInfo->nHeaderBytes == 0 &&
             (EQUALN(pszFilename, "WMS:http", 8) ||
              EQUALN(pszFilename, "http", 4)) &&
             strstr(pszFilename, "/MapServer?f=json") != NULL)
    {
        if (EQUALN(pszFilename, "WMS:http", 8))
            pszFilename += 4;
        CPLString osURL(pszFilename);
        if (strstr(pszFilename, "&pretty=true") == NULL)
            osURL += "&pretty=true";
        CPLHTTPResult *psResult = CPLHTTPFetch(osURL.c_str(), NULL);
        if (psResult == NULL)
            return NULL;
        if (psResult->pabyData == NULL)
        {
            CPLHTTPDestroyResult(psResult);
            return NULL;
        }
        config = GDALWMSDatasetGetConfigFromArcGISJSON(osURL,
                                                       (const char*)psResult->pabyData);
        CPLHTTPDestroyResult(psResult);
    }

    else if (poOpenInfo->nHeaderBytes == 0 &&
             (EQUALN(pszFilename, "WMS:", 4) ||
              CPLString(pszFilename).ifind("SERVICE=WMS") != std::string::npos))
    {
        CPLString osLayers = CPLURLGetValue(pszFilename, "LAYERS");
        CPLString osRequest = CPLURLGetValue(pszFilename, "REQUEST");
        if (osLayers.size() != 0)
            config = GDALWMSDatasetGetConfigFromURL(poOpenInfo);
        else if (EQUAL(osRequest, "GetTileService"))
            return GDALWMSMetaDataset::DownloadGetTileService(poOpenInfo);
        else
            return GDALWMSMetaDataset::DownloadGetCapabilities(poOpenInfo);
    }
    else if (poOpenInfo->nHeaderBytes != 0 &&
             (strstr(pabyHeader, "<WMT_MS_Capabilities") != NULL ||
              strstr(pabyHeader, "<WMS_Capabilities") != NULL ||
              strstr(pabyHeader, "<!DOCTYPE WMT_MS_Capabilities") != NULL))
    {
        CPLXMLNode* psXML = CPLParseXMLFile(pszFilename);
        if (psXML == NULL)
            return NULL;
        GDALDataset* poRet = GDALWMSMetaDataset::AnalyzeGetCapabilities(psXML);
        CPLDestroyXMLNode( psXML );
        return poRet;
    }
    else if (poOpenInfo->nHeaderBytes != 0 &&
             strstr(pabyHeader, "<WMS_Tile_Service") != NULL)
    {
        CPLXMLNode* psXML = CPLParseXMLFile(pszFilename);
        if (psXML == NULL)
            return NULL;
        GDALDataset* poRet = GDALWMSMetaDataset::AnalyzeGetTileService(psXML);
        CPLDestroyXMLNode( psXML );
        return poRet;
    }
    else if (poOpenInfo->nHeaderBytes != 0 &&
             strstr(pabyHeader, "<TileMap version=\"1.0.0\"") != NULL)
    {
        CPLXMLNode* psXML = CPLParseXMLFile(pszFilename);
        if (psXML == NULL)
            return NULL;
        config = GDALWMSDatasetGetConfigFromTileMap(psXML);
        CPLDestroyXMLNode( psXML );
    }
    else if (poOpenInfo->nHeaderBytes != 0 &&
             strstr(pabyHeader, "<Services") != NULL &&
             strstr(pabyHeader, "<TileMapService version=\"1.0") != NULL)
    {
        CPLXMLNode* psXML = CPLParseXMLFile(pszFilename);
        if (psXML == NULL)
            return NULL;
        CPLXMLNode* psRoot = CPLGetXMLNode( psXML, "=Services" );
        GDALDataset* poRet = NULL;
        if (psRoot)
        {
            CPLXMLNode* psTileMapService = CPLGetXMLNode(psRoot, "TileMapService");
            if (psTileMapService)
            {
                const char* pszHref = CPLGetXMLValue(psTileMapService, "href", NULL);
                if (pszHref)
                {
                    poRet = (GDALDataset*) GDALOpen(pszHref, GA_ReadOnly);
                }
            }
        }
        CPLDestroyXMLNode( psXML );
        return poRet;
    }
    else if (poOpenInfo->nHeaderBytes != 0 &&
             strstr(pabyHeader, "<TileMapService version=\"1.0.0\"") != NULL)
    {
        CPLXMLNode* psXML = CPLParseXMLFile(pszFilename);
        if (psXML == NULL)
            return NULL;
        GDALDataset* poRet = GDALWMSMetaDataset::AnalyzeTileMapService(psXML);
        CPLDestroyXMLNode( psXML );
        return poRet;
    }
    else
        return NULL;
    if (config == NULL) return NULL;

/* -------------------------------------------------------------------- */
/*      Confirm the requested access is supported.                      */
/* -------------------------------------------------------------------- */
    if( poOpenInfo->eAccess == GA_Update )
    {
        CPLDestroyXMLNode(config);
        CPLError( CE_Failure, CPLE_NotSupported, 
                  "The WMS driver does not support update access to existing"
                  " datasets.\n" );
        return NULL;
    }

    GDALWMSDataset *ds = new GDALWMSDataset();
    ret = ds->Initialize(config);
    if (ret != CE_None) {
        delete ds;
        ds = NULL;
    }
    CPLDestroyXMLNode(config);

/* -------------------------------------------------------------------- */
/*      Initialize any PAM information.                                 */
/* -------------------------------------------------------------------- */
    if (ds != NULL)
    {
        ds->SetMetadataItem( "INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE" );
        ds->SetDescription( poOpenInfo->pszFilename );
        ds->TryLoadXML();
    }

    return ds;
}
Exemple #11
0
static CPLXMLNode* GDALWMSDatasetGetConfigFromArcGISJSON(const char* pszURL,
                                                         const char* pszContent)
{
    /* TODO : use JSONC library to parse. But we don't really need it */
    CPLString osTmpFilename(CPLSPrintf("/vsimem/WMSArcGISJSON%p", pszURL));
    VSILFILE* fp = VSIFileFromMemBuffer( osTmpFilename,
                                         (GByte*)pszContent,
                                         strlen(pszContent),
                                         FALSE);
    const char* pszLine;
    int nTileWidth = -1, nTileHeight = -1;
    int nWKID = -1;
    double dfMinX = 0, dfMaxY = 0;
    int bHasMinX = FALSE, bHasMaxY = FALSE;
    int nExpectedLevel = 0;
    double dfBaseResolution = 0;
    while((pszLine = CPLReadLine2L(fp, 4096, NULL)) != NULL)
    {
        const char* pszPtr;
        if ((pszPtr = strstr(pszLine, "\"rows\" : ")) != NULL)
            nTileHeight = atoi(pszPtr + strlen("\"rows\" : "));
        else if ((pszPtr = strstr(pszLine, "\"cols\" : ")) != NULL)
            nTileWidth = atoi(pszPtr + strlen("\"cols\" : "));
        else if ((pszPtr = strstr(pszLine, "\"wkid\" : ")) != NULL)
        {
            int nVal = atoi(pszPtr + strlen("\"wkid\" : "));
            if (nWKID < 0)
                nWKID = nVal;
            else if (nWKID != nVal)
            {
                CPLDebug("WMS", "Inconsisant WKID values : %d, %d", nVal, nWKID);
                VSIFCloseL(fp);
                return NULL;
            }
        }
        else if ((pszPtr = strstr(pszLine, "\"x\" : ")) != NULL)
        {
            bHasMinX = TRUE;
            dfMinX = CPLAtofM(pszPtr + strlen("\"x\" : "));
        }
        else if ((pszPtr = strstr(pszLine, "\"y\" : ")) != NULL)
        {
            bHasMaxY = TRUE;
            dfMaxY = CPLAtofM(pszPtr + strlen("\"y\" : "));
        }
        else if ((pszPtr = strstr(pszLine, "\"level\" : ")) != NULL)
        {
            int nLevel = atoi(pszPtr + strlen("\"level\" : "));
            if (nLevel != nExpectedLevel)
            {
                CPLDebug("WMS", "Expected level : %d, got : %d", nExpectedLevel, nLevel);
                VSIFCloseL(fp);
                return NULL;
            }

            if ((pszPtr = strstr(pszLine, "\"resolution\" : ")) != NULL)
            {
                double dfResolution = CPLAtofM(pszPtr + strlen("\"resolution\" : "));
                if (nLevel == 0)
                    dfBaseResolution = dfResolution;
            }
            else
            {
                CPLDebug("WMS", "Did not get resolution");
                VSIFCloseL(fp);
                return NULL;
            }
            nExpectedLevel ++;
        }
    }
    VSIFCloseL(fp);

    int nLevelCount = nExpectedLevel - 1;
    if (nLevelCount < 1)
    {
        CPLDebug("WMS", "Did not get levels");
        return NULL;
    }

    if (nTileWidth <= 0)
    {
        CPLDebug("WMS", "Did not get tile width");
        return NULL;
    }
    if (nTileHeight <= 0)
    {
        CPLDebug("WMS", "Did not get tile height");
        return NULL;
    }
    if (nWKID <= 0)
    {
        CPLDebug("WMS", "Did not get WKID");
        return NULL;
    }
    if (!bHasMinX)
    {
        CPLDebug("WMS", "Did not get min x");
        return NULL;
    }
    if (!bHasMaxY)
    {
        CPLDebug("WMS", "Did not get max y");
        return NULL;
    }
    
    if (nWKID == 102100)
        nWKID = 3857;

    const char* pszEndURL = strstr(pszURL, "/MapServer?f=json");
    CPLAssert(pszEndURL);
    CPLString osURL(pszURL);
    osURL.resize(pszEndURL - pszURL);

    double dfMaxX = dfMinX + dfBaseResolution * nTileWidth;
    double dfMinY = dfMaxY - dfBaseResolution * nTileHeight;

    int nTileCountX = 1;
    if (fabs(dfMinX - -180) < 1e-4 && fabs(dfMaxY - 90) < 1e-4 &&
        fabs(dfMinY - -90) < 1e-4)
    {
        nTileCountX = 2;
        dfMaxX = 180;
    }

    CPLString osXML = CPLSPrintf(
            "<GDAL_WMS>\n"
            "  <Service name=\"TMS\">\n"
            "    <ServerUrl>%s/MapServer/tile/${z}/${y}/${x}</ServerUrl>\n"
            "  </Service>\n"
            "  <DataWindow>\n"
            "    <UpperLeftX>%.8f</UpperLeftX>\n"
            "    <UpperLeftY>%.8f</UpperLeftY>\n"
            "    <LowerRightX>%.8f</LowerRightX>\n"
            "    <LowerRightY>%.8f</LowerRightY>\n"
            "    <TileLevel>%d</TileLevel>\n"
            "    <TileCountX>%d</TileCountX>\n"
            "    <YOrigin>top</YOrigin>\n"
            "  </DataWindow>\n"
            "  <Projection>EPSG:%d</Projection>\n"
            "  <BlockSizeX>%d</BlockSizeX>\n"
            "  <BlockSizeY>%d</BlockSizeY>\n"
            "  <Cache/>\n"
            "</GDAL_WMS>\n",
            osURL.c_str(),
            dfMinX, dfMaxY, dfMaxX, dfMinY,
            nLevelCount,
            nTileCountX,
            nWKID,
            nTileWidth, nTileHeight);
    CPLDebug("WMS", "Opening TMS :\n%s", osXML.c_str());

    return CPLParseXMLString(osXML);
}
Exemple #12
0
GDALDataset *GDALWMSDataset::Open(GDALOpenInfo *poOpenInfo)
{
    CPLXMLNode *config = NULL;
    CPLErr ret = CE_None;

    const char* pszFilename = poOpenInfo->pszFilename;
    const char* pabyHeader = (const char *) poOpenInfo->pabyHeader;

    if (poOpenInfo->nHeaderBytes == 0 &&
        EQUALN(pszFilename, "<GDAL_WMS>", 10))
    {
        config = CPLParseXMLString(pszFilename);
    }
    else if (poOpenInfo->nHeaderBytes >= 10 &&
             EQUALN(pabyHeader, "<GDAL_WMS>", 10))
    {
        config = CPLParseXMLFile(pszFilename);
    }
    else if (poOpenInfo->nHeaderBytes == 0 &&
             (EQUALN(pszFilename, "WMS:http", 8) ||
              EQUALN(pszFilename, "http", 4)) &&
             strstr(pszFilename, "/MapServer?f=json") != NULL)
    {
        if (EQUALN(pszFilename, "WMS:http", 8))
            pszFilename += 4;
        CPLString osURL(pszFilename);
        if (strstr(pszFilename, "&pretty=true") == NULL)
            osURL += "&pretty=true";
        CPLHTTPResult *psResult = CPLHTTPFetch(osURL.c_str(), NULL);
        if (psResult == NULL)
            return NULL;
        if (psResult->pabyData == NULL)
        {
            CPLHTTPDestroyResult(psResult);
            return NULL;
        }
        config = GDALWMSDatasetGetConfigFromArcGISJSON(osURL,
                                                       (const char*)psResult->pabyData);
        CPLHTTPDestroyResult(psResult);
    }

    else if (poOpenInfo->nHeaderBytes == 0 &&
             (EQUALN(pszFilename, "WMS:", 4) ||
              CPLString(pszFilename).ifind("SERVICE=WMS") != std::string::npos))
    {
        CPLString osLayers = CPLURLGetValue(pszFilename, "LAYERS");
        CPLString osRequest = CPLURLGetValue(pszFilename, "REQUEST");
        if (osLayers.size() != 0)
            config = GDALWMSDatasetGetConfigFromURL(poOpenInfo);
        else if (EQUAL(osRequest, "GetTileService"))
            return GDALWMSMetaDataset::DownloadGetTileService(poOpenInfo);
        else
            return GDALWMSMetaDataset::DownloadGetCapabilities(poOpenInfo);
    }
    else if (poOpenInfo->nHeaderBytes != 0 &&
             (strstr(pabyHeader, "<WMT_MS_Capabilities") != NULL ||
              strstr(pabyHeader, "<WMS_Capabilities") != NULL ||
              strstr(pabyHeader, "<!DOCTYPE WMT_MS_Capabilities") != NULL))
    {
        CPLXMLNode* psXML = CPLParseXMLFile(pszFilename);
        if (psXML == NULL)
            return NULL;
        GDALDataset* poRet = GDALWMSMetaDataset::AnalyzeGetCapabilities(psXML);
        CPLDestroyXMLNode( psXML );
        return poRet;
    }
    else if (poOpenInfo->nHeaderBytes != 0 &&
             strstr(pabyHeader, "<WMS_Tile_Service") != NULL)
    {
        CPLXMLNode* psXML = CPLParseXMLFile(pszFilename);
        if (psXML == NULL)
            return NULL;
        GDALDataset* poRet = GDALWMSMetaDataset::AnalyzeGetTileService(psXML);
        CPLDestroyXMLNode( psXML );
        return poRet;
    }
    else if (poOpenInfo->nHeaderBytes != 0 &&
             strstr(pabyHeader, "<TileMap version=\"1.0.0\"") != NULL)
    {
        CPLXMLNode* psXML = CPLParseXMLFile(pszFilename);
        if (psXML == NULL)
            return NULL;
        config = GDALWMSDatasetGetConfigFromTileMap(psXML);
        CPLDestroyXMLNode( psXML );
    }
    else if (poOpenInfo->nHeaderBytes != 0 &&
             strstr(pabyHeader, "<Services") != NULL &&
             strstr(pabyHeader, "<TileMapService version=\"1.0") != NULL)
    {
        CPLXMLNode* psXML = CPLParseXMLFile(pszFilename);
        if (psXML == NULL)
            return NULL;
        CPLXMLNode* psRoot = CPLGetXMLNode( psXML, "=Services" );
        GDALDataset* poRet = NULL;
        if (psRoot)
        {
            CPLXMLNode* psTileMapService = CPLGetXMLNode(psRoot, "TileMapService");
            if (psTileMapService)
            {
                const char* pszHref = CPLGetXMLValue(psTileMapService, "href", NULL);
                if (pszHref)
                {
                    poRet = (GDALDataset*) GDALOpen(pszHref, GA_ReadOnly);
                }
            }
        }
        CPLDestroyXMLNode( psXML );
        return poRet;
    }
    else if (poOpenInfo->nHeaderBytes != 0 &&
             strstr(pabyHeader, "<TileMapService version=\"1.0.0\"") != NULL)
    {
        CPLXMLNode* psXML = CPLParseXMLFile(pszFilename);
        if (psXML == NULL)
            return NULL;
        GDALDataset* poRet = GDALWMSMetaDataset::AnalyzeTileMapService(psXML);
        CPLDestroyXMLNode( psXML );
        return poRet;
    }
    else if (poOpenInfo->nHeaderBytes == 0 &&
              EQUALN(pszFilename, "AGS:", 4))
    {
		return NULL;
    }
    else if (poOpenInfo->nHeaderBytes == 0 &&
              EQUALN(pszFilename, "IIP:", 4))
    {
        CPLString osURL(pszFilename + 4);
        osURL += "&obj=Basic-Info";
        CPLHTTPResult *psResult = CPLHTTPFetch(osURL.c_str(), NULL);
        if (psResult == NULL)
            return NULL;
        if (psResult->pabyData == NULL)
        {
            CPLHTTPDestroyResult(psResult);
            return NULL;
        }
        int nXSize, nYSize;
        const char* pszMaxSize = strstr((const char*)psResult->pabyData, "Max-size:");
        const char* pszResolutionNumber = strstr((const char*)psResult->pabyData, "Resolution-number:");
        if( pszMaxSize &&
            sscanf(pszMaxSize + strlen("Max-size:"), "%d %d", &nXSize, &nYSize) == 2 &&
            pszResolutionNumber )
        {
            int nResolutions = atoi(pszResolutionNumber + strlen("Resolution-number:"));
            char* pszEscapedURL = CPLEscapeString(pszFilename + 4, -1, CPLES_XML);
            CPLString osXML = CPLSPrintf(
            "<GDAL_WMS>"
            "    <Service name=\"IIP\">"
            "        <ServerUrl>%s</ServerUrl>"
            "    </Service>"
            "    <DataWindow>"
            "        <SizeX>%d</SizeX>"
            "        <SizeY>%d</SizeY>"
            "        <TileLevel>%d</TileLevel>"
            "    </DataWindow>"
            "    <BlockSizeX>256</BlockSizeX>"
            "    <BlockSizeY>256</BlockSizeY>"
            "    <BandsCount>3</BandsCount>"
            "    <Cache />"
            "</GDAL_WMS>",
                pszEscapedURL,
                nXSize, nYSize, nResolutions - 1);
            config = CPLParseXMLString(osXML);
            CPLFree(pszEscapedURL);
        }
        CPLHTTPDestroyResult(psResult);
    }
    else
        return NULL;
    if (config == NULL) return NULL;

/* -------------------------------------------------------------------- */
/*      Confirm the requested access is supported.                      */
/* -------------------------------------------------------------------- */
    if( poOpenInfo->eAccess == GA_Update )
    {
        CPLDestroyXMLNode(config);
        CPLError( CE_Failure, CPLE_NotSupported, 
                  "The WMS poDriver does not support update access to existing"
                  " datasets.\n" );
        return NULL;
    }

    GDALWMSDataset *ds = new GDALWMSDataset();
    ret = ds->Initialize(config);
    if (ret != CE_None) {
        delete ds;
        ds = NULL;
    }
    CPLDestroyXMLNode(config);

/* -------------------------------------------------------------------- */
/*      Initialize any PAM information.                                 */
/* -------------------------------------------------------------------- */
    if (ds != NULL)
    {
        ds->SetMetadataItem( "INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE" );
        ds->SetDescription( poOpenInfo->pszFilename );
        ds->TryLoadXML();
    }

    return ds;
}
Exemple #13
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 */
}
json_object* OGRPLScenesDataset::RunRequest(const char* pszURL,
                                            int bQuiet404Error)
{
    char** papszOptions = CSLAddString(GetBaseHTTPOptions(), NULL);
    CPLHTTPResult * psResult;
    if( strncmp(osBaseURL, "/vsimem/", strlen("/vsimem/")) == 0 &&
        strncmp(pszURL, "/vsimem/", strlen("/vsimem/")) == 0 )
    {
        CPLDebug("PLSCENES", "Fetching %s", pszURL);
        psResult = (CPLHTTPResult*) CPLCalloc(1, sizeof(CPLHTTPResult));
        vsi_l_offset nDataLength = 0;
        CPLString osURL(pszURL);
        if( osURL[osURL.size()-1 ] == '/' )
            osURL.resize(osURL.size()-1);
        GByte* pabyBuf = VSIGetMemFileBuffer(osURL, &nDataLength, FALSE); 
        if( pabyBuf )
        {
            psResult->pabyData = (GByte*) VSIMalloc(1 + nDataLength);
            if( psResult->pabyData )
            {
                memcpy(psResult->pabyData, pabyBuf, nDataLength);
                psResult->pabyData[nDataLength] = 0;
            }
        }
        else
        {
            psResult->pszErrBuf =
                CPLStrdup(CPLSPrintf("Error 404. Cannot find %s", pszURL));
        }
    }
    else
    {
        if( bQuiet404Error )
            CPLPushErrorHandler(CPLQuietErrorHandler);
        psResult = CPLHTTPFetch( pszURL, papszOptions);
        if( bQuiet404Error )
            CPLPopErrorHandler();
    }
    CSLDestroy(papszOptions);
    
    if( psResult->pszErrBuf != NULL )
    {
        if( !(bQuiet404Error && strstr(psResult->pszErrBuf, "404")) )
        {
            CPLError(CE_Failure, CPLE_AppDefined, "%s",
                    psResult->pabyData ? (const char*) psResult->pabyData :
                    psResult->pszErrBuf);
        }
        CPLHTTPDestroyResult(psResult);
        return NULL;
    }
    
    if( psResult->pabyData == NULL )
    {
        CPLError(CE_Failure, CPLE_AppDefined, "Empty content returned by server");
        CPLHTTPDestroyResult(psResult);
        return NULL;
    }

    json_tokener* jstok = NULL;
    json_object* poObj = NULL;

    jstok = json_tokener_new();
    poObj = json_tokener_parse_ex(jstok, (const char*) psResult->pabyData, -1);
    if( jstok->err != json_tokener_success)
    {
        CPLError( CE_Failure, CPLE_AppDefined,
                    "JSON parsing error: %s (at offset %d)",
                    json_tokener_error_desc(jstok->err), jstok->char_offset);
        json_tokener_free(jstok);
        CPLHTTPDestroyResult(psResult);
        return NULL;
    }
    json_tokener_free(jstok);

    CPLHTTPDestroyResult(psResult);

    if( json_object_get_type(poObj) != json_type_object )
    {
        CPLError( CE_Failure, CPLE_AppDefined, "Return is not a JSON dictionary");
        json_object_put(poObj);
        poObj = NULL;
    }
    
    return poObj;
}