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; }
/** * 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; }
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; }
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); }
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; }
/** * \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; }