void writeAsDxf( QgsServerInterface *serverIface, const QgsProject *project, const QString &version, const QgsServerRequest &request, QgsServerResponse &response ) { Q_UNUSED( version ); QgsServerRequest::Parameters params = request.parameters(); QgsWmsParameters wmsParameters( QUrlQuery( request.url() ) ); QgsRenderer renderer( serverIface, project, wmsParameters ); QMap<QString, QString> formatOptionsMap = parseFormatOptions( params.value( QStringLiteral( "FORMAT_OPTIONS" ) ) ); QgsDxfExport dxf = renderer.getDxf( formatOptionsMap ); QString codec = QStringLiteral( "ISO-8859-1" ); QMap<QString, QString>::const_iterator codecIt = formatOptionsMap.find( QStringLiteral( "CODEC" ) ); if ( codecIt != formatOptionsMap.constEnd() ) { codec = formatOptionsMap.value( QStringLiteral( "CODEC" ) ); } // Write output response.setHeader( "Content-Type", "application/dxf" ); dxf.writeToFile( response.io(), codec ); }
QString serviceUrl( const QgsServerRequest &request, const QgsProject *project ) { QString href; if ( project ) { href = QgsServerProjectUtils::wmtsServiceUrl( *project ); } // Build default url if ( href.isEmpty() ) { QUrl url = request.originalUrl(); QgsWmtsParameters params; params.load( QUrlQuery( url ) ); params.remove( QgsServerParameter::REQUEST ); params.remove( QgsServerParameter::VERSION_SERVICE ); params.remove( QgsServerParameter::SERVICE ); url.setQuery( params.urlQuery() ); href = url.toString(); } return href; }
QUrl serviceUrl( const QgsServerRequest &request, const QgsProject *project ) { QUrl href; if ( project ) { href.setUrl( QgsServerProjectUtils::wmsServiceUrl( *project ) ); } // Build default url if ( href.isEmpty() ) { href = request.url(); QUrlQuery q( href ); q.removeAllQueryItems( QStringLiteral( "REQUEST" ) ); q.removeAllQueryItems( QStringLiteral( "VERSION" ) ); q.removeAllQueryItems( QStringLiteral( "SERVICE" ) ); q.removeAllQueryItems( QStringLiteral( "LAYERS" ) ); q.removeAllQueryItems( QStringLiteral( "SLD_VERSION" ) ); q.removeAllQueryItems( QStringLiteral( "_DC" ) ); href.setQuery( q ); } return href; }
void writeGetMap( QgsServerInterface* serverIface, const QString& version, const QgsServerRequest& request, QgsServerResponse& response ) { Q_UNUSED( version ); QgsServerRequest::Parameters params = request.parameters(); QgsWmsConfigParser* parser = getConfigParser( serverIface ); QgsWmsServer server( serverIface->configFilePath(), *serverIface->serverSettings(), params, parser, serverIface->accessControls() ); QScopedPointer<QImage> result( server.getMap() ); if ( !result.isNull() ) { QString format = params.value( QStringLiteral( "FORMAT" ), QStringLiteral( "PNG" ) ); writeImage( response, *result, format, server.getImageQuality() ); } else { throw QgsServiceException( QStringLiteral( "UnknownError" ), QStringLiteral( "Failed to compute GetMap image" ) ); } }
QString serviceUrl( const QgsServerRequest &request, const QgsProject *project ) { QUrl href; if ( project ) { href.setUrl( QgsServerProjectUtils::wfsServiceUrl( *project ) ); } // Build default url if ( href.isEmpty() ) { static QSet<QString> sFilter { QStringLiteral( "REQUEST" ), QStringLiteral( "VERSION" ), QStringLiteral( "SERVICE" ), }; href = request.originalUrl(); QUrlQuery q( href ); for ( auto param : q.queryItems() ) { if ( sFilter.contains( param.first.toUpper() ) ) q.removeAllQueryItems( param.first ); } href.setQuery( q ); } return href.toString(); }
QDomDocument getStyle( QgsServerInterface *serverIface, const QgsProject *project, const QString &version, const QgsServerRequest &request ) { Q_UNUSED( version ); QgsServerRequest::Parameters parameters = request.parameters(); QDomDocument doc; QString styleName = parameters.value( QStringLiteral( "STYLE" ) ); QString layerName = parameters.value( QStringLiteral( "LAYER" ) ); if ( styleName.isEmpty() ) { throw QgsBadRequestException( QgsServiceException::QGIS_MissingParameterValue, QgsWmsParameter::STYLE ); } if ( layerName.isEmpty() ) { throw QgsBadRequestException( QgsServiceException::QGIS_MissingParameterValue, QgsWmsParameter::LAYERS ); } QStringList layerList; layerList.append( layerName ); return getStyledLayerDescriptorDocument( serverIface, project, layerList ); }
QString serviceUrl( const QgsServerRequest& request, const QgsProject* project ) { QString href; if ( project ) { href = QgsServerProjectUtils::wfsServiceUrl( *project ); } // Build default url if ( href.isEmpty() ) { QUrl url = request.url(); QUrlQuery q( url ); q.removeAllQueryItems( QStringLiteral( "REQUEST" ) ); q.removeAllQueryItems( QStringLiteral( "VERSION" ) ); q.removeAllQueryItems( QStringLiteral( "SERVICE" ) ); q.removeAllQueryItems( QStringLiteral( "_DC" ) ); url.setQuery( q ); href = url.toString( QUrl::FullyDecoded ); } return href; }
void writeGetPrint( QgsServerInterface *serverIface, const QgsProject *project, const QString &version, const QgsServerRequest &request, QgsServerResponse &response ) { QgsServerRequest::Parameters params = request.parameters(); Q_UNUSED( version ); QgsWmsParameters wmsParameters( QUrlQuery( request.url() ) ); QgsRenderer renderer( serverIface, project, wmsParameters ); QString format = params.value( "FORMAT" ); QString contentType; // GetPrint supports svg/png/pdf if ( format.compare( QLatin1String( "image/png" ), Qt::CaseInsensitive ) == 0 || format.compare( QLatin1String( "png" ), Qt::CaseInsensitive ) == 0 ) { format = "png"; contentType = "image/png"; } else if ( format.compare( QLatin1String( "image/svg" ), Qt::CaseInsensitive ) == 0 || format.compare( QLatin1String( "image/svg+xml" ), Qt::CaseInsensitive ) == 0 || format.compare( QLatin1String( "svg" ), Qt::CaseInsensitive ) == 0 ) { format = "svg"; contentType = "image/svg+xml"; } else if ( format.compare( QLatin1String( "application/pdf" ), Qt::CaseInsensitive ) == 0 || format.compare( QLatin1String( "pdf" ), Qt::CaseInsensitive ) == 0 ) { format = "pdf"; contentType = "application/pdf"; } else { throw QgsServiceException( QStringLiteral( "InvalidFormat" ), QString( "Output format %1 is not supported by the GetPrint request" ).arg( format ) ); } response.setHeader( QStringLiteral( "Content-Type" ), contentType ); response.write( renderer.getPrint( format ) ); }
void writeGetTile( QgsServerInterface *serverIface, const QgsProject *project, const QString &version, const QgsServerRequest &request, QgsServerResponse &response ) { Q_UNUSED( version ); const QgsWmtsParameters params( QUrlQuery( request.url() ) ); // WMS query QUrlQuery query = translateWmtsParamToWmsQueryItem( QStringLiteral( "GetMap" ), params, project, serverIface ); // Get cached image QgsAccessControl *accessControl = serverIface->accessControls(); QgsServerCacheManager *cacheManager = serverIface->cacheManager(); if ( cacheManager ) { QgsWmtsParameters::Format f = params.format(); QString contentType; QString saveFormat; std::unique_ptr<QImage> image; if ( f == QgsWmtsParameters::Format::JPG ) { contentType = QStringLiteral( "image/jpeg" ); saveFormat = QStringLiteral( "JPEG" ); image = qgis::make_unique<QImage>( 256, 256, QImage::Format_RGB32 ); } else { contentType = QStringLiteral( "image/png" ); saveFormat = QStringLiteral( "PNG" ); image = qgis::make_unique<QImage>( 256, 256, QImage::Format_ARGB32_Premultiplied ); } QByteArray content = cacheManager->getCachedImage( project, request, accessControl ); if ( !content.isEmpty() && image->loadFromData( content ) ) { response.setHeader( QStringLiteral( "Content-Type" ), contentType ); image->save( response.io(), qPrintable( saveFormat ) ); return; } } QgsServerParameters wmsParams( query ); QgsServerRequest wmsRequest( "?" + query.query( QUrl::FullyDecoded ) ); QgsService *service = serverIface->serviceRegistry()->getService( wmsParams.service(), wmsParams.version() ); service->executeRequest( wmsRequest, response, project ); if ( cacheManager ) { QByteArray content = response.data(); if ( !content.isEmpty() ) cacheManager->setCachedImage( &content, project, request, accessControl ); } }
void writeGetFeatureInfo( QgsServerInterface *serverIface, const QgsProject *project, const QString &version, const QgsServerRequest &request, QgsServerResponse &response ) { // get wms parameters from query QgsWmsParameters parameters( QUrlQuery( request.url() ) ); // prepare render context QgsWmsRenderContext context( project, serverIface ); context.setFlag( QgsWmsRenderContext::AddQueryLayers ); context.setFlag( QgsWmsRenderContext::UseFilter ); context.setFlag( QgsWmsRenderContext::UseScaleDenominator ); context.setFlag( QgsWmsRenderContext::SetAccessControl ); context.setParameters( parameters ); const QString infoFormat = request.parameters().value( QStringLiteral( "INFO_FORMAT" ), QStringLiteral( "text/plain" ) ); response.setHeader( QStringLiteral( "Content-Type" ), infoFormat + QStringLiteral( "; charset=utf-8" ) ); QgsRenderer renderer( context ); response.write( renderer.getFeatureInfo( version ) ); }
void writeGetCapabilities( QgsServerInterface* serverIface, const QString& version, const QgsServerRequest& request, QgsServerResponse& response, bool projectSettings ) { QgsServerRequest::Parameters params = request.parameters(); QString configFilePath = serverIface->configFilePath(); QgsServerSettings* serverSettings = serverIface->serverSettings(); QgsAccessControl* accessControl = serverIface->accessControls(); QgsCapabilitiesCache* capabilitiesCache = serverIface->capabilitiesCache(); QStringList cacheKeyList; cacheKeyList << ( projectSettings ? QStringLiteral( "projectSettings" ) : version ); cacheKeyList << getenv( "SERVER_NAME" ); bool cache = true; if ( accessControl ) cache = accessControl->fillCacheKey( cacheKeyList ); QString cacheKey = cacheKeyList.join( QStringLiteral( "-" ) ); const QDomDocument* capabilitiesDocument = capabilitiesCache->searchCapabilitiesDocument( configFilePath, cacheKey ); if ( !capabilitiesDocument ) //capabilities xml not in cache. Create a new one { QgsMessageLog::logMessage( QStringLiteral( "Capabilities document not found in cache" ) ); QDomDocument doc; QgsWmsServer server( configFilePath, *serverSettings, params, getConfigParser( serverIface ), accessControl ); doc = server.getCapabilities( version, projectSettings ); if ( cache ) { capabilitiesCache->insertCapabilitiesDocument( configFilePath, cacheKey, &doc ); capabilitiesDocument = capabilitiesCache->searchCapabilitiesDocument( configFilePath, cacheKey ); } else { doc = doc.cloneNode().toDocument(); capabilitiesDocument = &doc; } } else { QgsMessageLog::logMessage( QStringLiteral( "Found capabilities document in cache" ) ); } response.setHeader( QStringLiteral( "Content-Type" ), QStringLiteral( "text/xml; charset=utf-8" ) ); response.write( capabilitiesDocument->toByteArray() ); }
void writeGetSchemaExtension( QgsServerInterface* serverIface, const QString& version, const QgsServerRequest& request, QgsServerResponse& response ) { Q_UNUSED( version ); QgsServerRequest::Parameters params = request.parameters(); QgsWmsServer server( serverIface->configFilePath(), *serverIface->serverSettings(), params, getConfigParser( serverIface ), serverIface->accessControls() ); QDomDocument doc = server.getSchemaExtension(); response.setHeader( QStringLiteral( "Content-Type" ), QStringLiteral( "text/xml; charset=utf-8" ) ); response.write( doc.toByteArray() ); }
void writeGetLegendGraphics( QgsServerInterface *serverIface, const QgsProject *project, const QString &version, const QgsServerRequest &request, QgsServerResponse &response ) { Q_UNUSED( version ); QgsServerRequest::Parameters params = request.parameters(); QgsWmsParameters wmsParameters( QUrlQuery( request.url() ) ); QgsRenderer renderer( serverIface, project, wmsParameters ); std::unique_ptr<QImage> result( renderer.getLegendGraphics() ); if ( result ) { QString format = params.value( QStringLiteral( "FORMAT" ), QStringLiteral( "PNG" ) ); writeImage( response, *result, format, renderer.getImageQuality() ); } else { throw QgsServiceException( QStringLiteral( "UnknownError" ), QStringLiteral( "Failed to compute GetLegendGraphics image" ) ); } }
QDomDocument getSchemaExtension( QgsServerInterface *serverIface, const QString &version, const QgsServerRequest &request ) { Q_UNUSED( version ); Q_UNUSED( serverIface ); QgsServerRequest::Parameters parameters = request.parameters(); QDomDocument xsdDoc; QDir resourcesDir = QFileInfo( QgsApplication::serverResourcesPath() ).absoluteDir(); QFileInfo xsdFileInfo( resourcesDir, QStringLiteral( "schemaExtension.xsd" ) ); if ( !xsdFileInfo.exists() ) { QgsMessageLog::logMessage( QStringLiteral( "Error, xsd file 'schemaExtension.xsd' does not exist" ), QStringLiteral( "Server" ), QgsMessageLog::CRITICAL ); return xsdDoc; } QString xsdFilePath = xsdFileInfo.absoluteFilePath(); QFile xsdFile( xsdFilePath ); if ( !xsdFile.exists() ) { QgsMessageLog::logMessage( QStringLiteral( "Error, xsd file 'schemaExtension.xsd' does not exist" ), QStringLiteral( "Server" ), QgsMessageLog::CRITICAL ); return xsdDoc; } if ( !xsdFile.open( QIODevice::ReadOnly ) ) { QgsMessageLog::logMessage( QStringLiteral( "Error, cannot open xsd file 'schemaExtension.xsd' does not exist" ), QStringLiteral( "Server" ), QgsMessageLog::CRITICAL ); return xsdDoc; } QString errorMsg; int line, column; if ( !xsdDoc.setContent( &xsdFile, true, &errorMsg, &line, &column ) ) { QgsMessageLog::logMessage( QStringLiteral( "Error parsing file 'schemaExtension.xsd" ) + QStringLiteral( "': parse error %1 at row %2, column %3" ).arg( errorMsg ).arg( line ).arg( column ), QStringLiteral( "Server" ), QgsMessageLog::CRITICAL ); } return xsdDoc; }
void writeGetCapabilities( QgsServerInterface* serverIface, const QString& version, const QgsServerRequest& request, QgsServerResponse& response, bool projectSettings ) { QString configFilePath = serverIface->configFilePath(); QgsCapabilitiesCache* capabilitiesCache = serverIface->capabilitiesCache(); QStringList cacheKeyList; cacheKeyList << ( projectSettings ? QStringLiteral( "projectSettings" ) : version ); cacheKeyList << request.url().host(); bool cache = true; #ifdef HAVE_SERVER_PYTHON_PLUGINS QgsAccessControl* accessControl = serverIface->accessControls(); if ( accessControl ) cache = accessControl->fillCacheKey( cacheKeyList ); #endif QString cacheKey = cacheKeyList.join( QStringLiteral( "-" ) ); const QDomDocument* capabilitiesDocument = capabilitiesCache->searchCapabilitiesDocument( configFilePath, cacheKey ); if ( !capabilitiesDocument ) //capabilities xml not in cache. Create a new one { QgsMessageLog::logMessage( QStringLiteral( "Capabilities document not found in cache" ) ); QDomDocument doc; doc = getCapabilities( serverIface, version, request, projectSettings ); if ( cache ) { capabilitiesCache->insertCapabilitiesDocument( configFilePath, cacheKey, &doc ); capabilitiesDocument = capabilitiesCache->searchCapabilitiesDocument( configFilePath, cacheKey ); } else { doc = doc.cloneNode().toDocument(); capabilitiesDocument = &doc; } } else { QgsMessageLog::logMessage( QStringLiteral( "Found capabilities document in cache" ) ); } response.setHeader( QStringLiteral( "Content-Type" ), QStringLiteral( "text/xml; charset=utf-8" ) ); response.write( capabilitiesDocument->toByteArray() ); }
void executeRequest( const QgsServerRequest& request, QgsServerResponse& response, const QgsProject* project ) { QgsServerRequest::Parameters params = request.parameters(); QString versionString = params.value( "VERSION" ); // Set the default version if ( versionString.isEmpty() ) { versionString = version(); // defined in qgswfsutils.h } // Get the request QString req = params.value( QStringLiteral( "REQUEST" ) ); if ( req.isEmpty() ) { throw QgsServiceException( QStringLiteral( "OperationNotSupported" ), QStringLiteral( "Please check the value of the REQUEST parameter" ) ); } if ( QSTR_COMPARE( req, "GetCapabilities" ) ) { writeGetCapabilities( mServerIface, project, versionString, request, response ); } else if ( QSTR_COMPARE( req, "GetFeature" ) ) { writeGetFeature( mServerIface, project, versionString, request, response ); } else if ( QSTR_COMPARE( req, "DescribeFeatureType" ) ) { writeDescribeFeatureType( mServerIface, versionString, request, response ); } else if ( QSTR_COMPARE( req, "Transaction" ) ) { writeTransaction( mServerIface, versionString, request, response ); } else { // Operation not supported throw QgsServiceException( QStringLiteral( "OperationNotSupported" ), QStringLiteral( "Request %1 is not supported" ).arg( req ) ); } }
void executeRequest( const QgsServerRequest &request, QgsServerResponse &response, const QgsProject *project ) override { Q_UNUSED( project ); const QgsWmtsParameters params( QUrlQuery( request.url() ) ); // Set the default version QString versionString = params.version(); if ( versionString.isEmpty() ) { versionString = version(); // defined in qgswfsutils.h } // Get the request QString req = params.value( QgsServerParameter::name( QgsServerParameter::REQUEST ) ); if ( req.isEmpty() ) { throw QgsServiceException( QStringLiteral( "OperationNotSupported" ), QStringLiteral( "Please check the value of the REQUEST parameter" ), 501 ); } if ( QSTR_COMPARE( req, "GetCapabilities" ) ) { writeGetCapabilities( mServerIface, project, versionString, request, response ); } else if ( QSTR_COMPARE( req, "GetTile" ) ) { writeGetTile( mServerIface, project, versionString, request, response ); } else if ( QSTR_COMPARE( req, "GetFeatureInfo" ) ) { writeGetFeatureInfo( mServerIface, project, versionString, request, response ); } else { // Operation not supported throw QgsServiceException( QStringLiteral( "OperationNotSupported" ), QStringLiteral( "Request %1 is not supported" ).arg( req ), 501 ); } }
void writeGetLegendGraphics( QgsServerInterface* serverIface, const QString& version, const QgsServerRequest& request, QgsServerResponse& response ) { Q_UNUSED( version ); QgsServerRequest::Parameters params = request.parameters(); QgsRenderer renderer( serverIface, params, getConfigParser( serverIface ) ); QScopedPointer<QImage> result( renderer.getLegendGraphics() ); if ( !result.isNull() ) { QString format = params.value( QStringLiteral( "FORMAT" ), QStringLiteral( "PNG" ) ); writeImage( response, *result, format, renderer.getImageQuality() ); } else { throw QgsServiceException( QStringLiteral( "UnknownError" ), QStringLiteral( "Failed to compute GetLegendGraphics image" ) ); } }
void writeGetFeatureInfo( QgsServerInterface *serverIface, const QgsProject *project, const QString &version, const QgsServerRequest &request, QgsServerResponse &response ) { Q_UNUSED( version ); const QgsWmtsParameters params( QUrlQuery( request.url() ) ); // WMS query QUrlQuery query = translateWmtsParamToWmsQueryItem( QStringLiteral( "GetFeatureInfo" ), params, project, serverIface ); // GetFeatureInfo query items query.addQueryItem( QgsWmsParameterForWmts::name( QgsWmsParameterForWmts::QUERY_LAYERS ), params.layer() ); query.addQueryItem( QgsWmsParameterForWmts::name( QgsWmsParameterForWmts::I ), params.i() ); query.addQueryItem( QgsWmsParameterForWmts::name( QgsWmsParameterForWmts::J ), params.j() ); query.addQueryItem( QgsWmsParameterForWmts::name( QgsWmsParameterForWmts::INFO_FORMAT ), params.infoFormatAsString() ); QgsServerParameters wmsParams( query ); QgsServerRequest wmsRequest( "?" + query.query( QUrl::FullyDecoded ) ); QgsService *service = serverIface->serviceRegistry()->getService( wmsParams.service(), wmsParams.version() ); service->executeRequest( wmsRequest, response, project ); }
QDomDocument getStyles( QgsServerInterface *serverIface, const QgsProject *project, const QString &version, const QgsServerRequest &request ) { Q_UNUSED( version ); QgsServerRequest::Parameters parameters = request.parameters(); QString layersName = parameters.value( "LAYERS" ); if ( layersName.isEmpty() ) { throw QgsBadRequestException( QgsServiceException::QGIS_MissingParameterValue, QgsWmsParameter::LAYERS ); } QStringList layerList = layersName.split( ',', QString::SkipEmptyParts ); if ( layerList.isEmpty() ) { throw QgsBadRequestException( QgsServiceException::QGIS_MissingParameterValue, QgsWmsParameter::LAYERS ); } return getStyledLayerDescriptorDocument( serverIface, project, layerList ); }
void QgsServer::handleRequest( QgsServerRequest &request, QgsServerResponse &response, const QgsProject *project ) { Qgis::MessageLevel logLevel = QgsServerLogger::instance()->logLevel(); QTime time; //used for measuring request time if loglevel < 1 qApp->processEvents(); if ( logLevel == Qgis::Info ) { time.start(); } // Pass the filters to the requestHandler, this is needed for the following reasons: // Allow server request to call sendResponse plugin hook if enabled QgsFilterResponseDecorator responseDecorator( sServerInterface->filters(), response ); //Request handler QgsRequestHandler requestHandler( request, response ); try { // TODO: split parse input into plain parse and processing from specific services requestHandler.parseInput(); } catch ( QgsMapServiceException &e ) { QgsMessageLog::logMessage( "Parse input exception: " + e.message(), QStringLiteral( "Server" ), Qgis::Critical ); requestHandler.setServiceException( e ); } // Set the request handler into the interface for plugins to manipulate it sServerInterface->setRequestHandler( &requestHandler ); // Call requestReady() method (if enabled) responseDecorator.start(); // Plugins may have set exceptions if ( !requestHandler.exceptionRaised() ) { try { const QgsServerParameters params = request.serverParameters(); printRequestParameters( params.toMap(), logLevel ); //Config file path if ( ! project ) { QString configFilePath = configPath( *sConfigFilePath, params.map() ); // load the project if needed and not empty project = mConfigCache->project( configFilePath ); if ( ! project ) { throw QgsServerException( QStringLiteral( "Project file error" ) ); } sServerInterface->setConfigFilePath( configFilePath ); } else { sServerInterface->setConfigFilePath( project->fileName() ); } if ( ! params.fileName().isEmpty() ) { const QString value = QString( "attachment; filename=\"%1\"" ).arg( params.fileName() ); requestHandler.setResponseHeader( QStringLiteral( "Content-Disposition" ), value ); } // Lookup for service QgsService *service = sServiceRegistry->getService( params.service(), params.version() ); if ( service ) { service->executeRequest( request, responseDecorator, project ); } else { throw QgsOgcServiceException( QStringLiteral( "Service configuration error" ), QStringLiteral( "Service unknown or unsupported" ) ); } } catch ( QgsServerException &ex ) { responseDecorator.write( ex ); } catch ( QgsException &ex ) { // Internal server error response.sendError( 500, ex.what() ); } } // Terminate the response responseDecorator.finish(); // We are done using requestHandler in plugins, make sure we don't access // to a deleted request handler from Python bindings sServerInterface->clearRequestHandler(); if ( logLevel == Qgis::Info ) { QgsMessageLog::logMessage( "Request finished in " + QString::number( time.elapsed() ) + " ms", QStringLiteral( "Server" ), Qgis::Info ); } }
void QgsServer::handleRequest( QgsServerRequest &request, QgsServerResponse &response ) { QgsMessageLog::MessageLevel logLevel = QgsServerLogger::instance()->logLevel(); QTime time; //used for measuring request time if loglevel < 1 QgsProject::instance()->removeAllMapLayers(); qApp->processEvents(); if ( logLevel == QgsMessageLog::INFO ) { time.start(); } // Pass the filters to the requestHandler, this is needed for the following reasons: // Allow server request to call sendResponse plugin hook if enabled QgsFilterResponseDecorator responseDecorator( sServerInterface->filters(), response ); //Request handler QgsRequestHandler requestHandler( request, response ); try { // TODO: split parse input into plain parse and processing from specific services requestHandler.parseInput(); } catch ( QgsMapServiceException &e ) { QgsMessageLog::logMessage( "Parse input exception: " + e.message(), QStringLiteral( "Server" ), QgsMessageLog::CRITICAL ); requestHandler.setServiceException( e ); } // Set the request handler into the interface for plugins to manipulate it sServerInterface->setRequestHandler( &requestHandler ); // Call requestReady() method (if enabled) responseDecorator.start(); // Plugins may have set exceptions if ( !requestHandler.exceptionRaised() ) { try { QMap<QString, QString> parameterMap = request.parameters(); printRequestParameters( parameterMap, logLevel ); //Config file path QString configFilePath = configPath( *sConfigFilePath, parameterMap ); // load the project if needed and not empty const QgsProject *project = mConfigCache->project( configFilePath ); if ( ! project ) { throw QgsServerException( QStringLiteral( "Project file error" ) ); } sServerInterface->setConfigFilePath( configFilePath ); //Service parameter QString serviceString = parameterMap.value( QStringLiteral( "SERVICE" ) ); if ( serviceString.isEmpty() ) { // SERVICE not mandatory for WMS 1.3.0 GetMap & GetFeatureInfo QString requestString = parameterMap.value( QStringLiteral( "REQUEST" ) ); if ( requestString == QLatin1String( "GetMap" ) || requestString == QLatin1String( "GetFeatureInfo" ) ) { serviceString = QStringLiteral( "WMS" ); } } QString versionString = parameterMap.value( QStringLiteral( "VERSION" ) ); //possibility for client to suggest a download filename QString outputFileName = parameterMap.value( QStringLiteral( "FILE_NAME" ) ); if ( !outputFileName.isEmpty() ) { requestHandler.setResponseHeader( QStringLiteral( "Content-Disposition" ), "attachment; filename=\"" + outputFileName + "\"" ); } // Lookup for service QgsService *service = sServiceRegistry.getService( serviceString, versionString ); if ( service ) { service->executeRequest( request, responseDecorator, project ); } else { throw QgsOgcServiceException( QStringLiteral( "Service configuration error" ), QStringLiteral( "Service unknown or unsupported" ) ) ; } } catch ( QgsServerException &ex ) { responseDecorator.write( ex ); } catch ( QgsException &ex ) { // Internal server error response.sendError( 500, ex.what() ); } } // Terminate the response responseDecorator.finish(); // We are done using requestHandler in plugins, make sure we don't access // to a deleted request handler from Python bindings sServerInterface->clearRequestHandler(); if ( logLevel == QgsMessageLog::INFO ) { QgsMessageLog::logMessage( "Request finished in " + QString::number( time.elapsed() ) + " ms", QStringLiteral( "Server" ), QgsMessageLog::INFO ); } }
QDomDocument createDescribeFeatureTypeDocument( QgsServerInterface *serverIface, const QgsProject *project, const QString &version, const QgsServerRequest &request ) { Q_UNUSED( version ); QDomDocument doc; QgsServerRequest::Parameters parameters = request.parameters(); QgsWfsParameters wfsParameters( parameters ); QgsWfsParameters::Format oFormat = wfsParameters.outputFormat(); // test oFormat if ( oFormat == QgsWfsParameters::Format::NONE ) throw QgsBadRequestException( QStringLiteral( "Invalid WFS Parameter" ), "OUTPUTFORMAT " + wfsParameters.outputFormatAsString() + "is not supported" ); QgsAccessControl *accessControl = serverIface->accessControls(); //xsd:schema QDomElement schemaElement = doc.createElement( QStringLiteral( "schema" )/*xsd:schema*/ ); schemaElement.setAttribute( QStringLiteral( "xmlns" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema" ) ); schemaElement.setAttribute( QStringLiteral( "xmlns:xsd" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema" ) ); schemaElement.setAttribute( QStringLiteral( "xmlns:ogc" ), OGC_NAMESPACE ); schemaElement.setAttribute( QStringLiteral( "xmlns:gml" ), GML_NAMESPACE ); schemaElement.setAttribute( QStringLiteral( "xmlns:qgs" ), QGS_NAMESPACE ); schemaElement.setAttribute( QStringLiteral( "targetNamespace" ), QGS_NAMESPACE ); schemaElement.setAttribute( QStringLiteral( "elementFormDefault" ), QStringLiteral( "qualified" ) ); schemaElement.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.0" ) ); doc.appendChild( schemaElement ); //xsd:import QDomElement importElement = doc.createElement( QStringLiteral( "import" )/*xsd:import*/ ); importElement.setAttribute( QStringLiteral( "namespace" ), GML_NAMESPACE ); if ( oFormat == QgsWfsParameters::Format::GML2 ) importElement.setAttribute( QStringLiteral( "schemaLocation" ), QStringLiteral( "http://schemas.opengis.net/gml/2.1.2/feature.xsd" ) ); else if ( oFormat == QgsWfsParameters::Format::GML3 ) importElement.setAttribute( QStringLiteral( "schemaLocation" ), QStringLiteral( "http://schemas.opengis.net/gml/3.1.1/base/gml.xsd" ) ); schemaElement.appendChild( importElement ); QStringList typeNameList; QDomDocument queryDoc; QString errorMsg; if ( queryDoc.setContent( parameters.value( QStringLiteral( "REQUEST_BODY" ) ), true, &errorMsg ) ) { //read doc QDomElement queryDocElem = queryDoc.documentElement(); QDomNodeList docChildNodes = queryDocElem.childNodes(); if ( docChildNodes.size() ) { for ( int i = 0; i < docChildNodes.size(); i++ ) { QDomElement docChildElem = docChildNodes.at( i ).toElement(); if ( docChildElem.tagName() == QLatin1String( "TypeName" ) ) { QString typeName = docChildElem.text().trimmed(); if ( typeName.contains( ':' ) ) typeNameList << typeName.section( ':', 1, 1 ); else typeNameList << typeName; } } } } else { QString typeNames = request.parameter( QStringLiteral( "TYPENAME" ) ); if ( !typeNames.isEmpty() ) { QStringList typeNameSplit = typeNames.split( ',' ); for ( int i = 0; i < typeNameSplit.size(); ++i ) { QString typeName = typeNameSplit.at( i ).trimmed(); if ( typeName.contains( ':' ) ) typeNameList << typeName.section( ':', 1, 1 ); else typeNameList << typeName; } } } QStringList wfsLayerIds = QgsServerProjectUtils::wfsLayerIds( *project ); for ( int i = 0; i < wfsLayerIds.size(); ++i ) { QgsMapLayer *layer = project->mapLayer( wfsLayerIds.at( i ) ); if ( layer->type() != QgsMapLayer::LayerType::VectorLayer ) { continue; } QString name = layer->name(); if ( !layer->shortName().isEmpty() ) name = layer->shortName(); name = name.replace( ' ', '_' ); if ( !typeNameList.isEmpty() && !typeNameList.contains( name ) ) { continue; } if ( accessControl && !accessControl->layerReadPermission( layer ) ) { if ( !typeNameList.isEmpty() ) { throw QgsSecurityAccessException( QStringLiteral( "Feature access permission denied" ) ); } else { continue; } } QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer *>( layer ); QgsVectorDataProvider *provider = vLayer->dataProvider(); if ( !provider ) { continue; } setSchemaLayer( schemaElement, doc, const_cast<QgsVectorLayer *>( vLayer ) ); } return doc; }
QDomDocument createDescribeCoverageDocument( QgsServerInterface *serverIface, const QgsProject *project, const QString &version, const QgsServerRequest &request ) { Q_UNUSED( version ); QDomDocument doc; QgsServerRequest::Parameters parameters = request.parameters(); #ifdef HAVE_SERVER_PYTHON_PLUGINS QgsAccessControl *accessControl = serverIface->accessControls(); #endif //wcs:WCS_Capabilities element QDomElement coveDescElement = doc.createElement( QStringLiteral( "CoverageDescription" )/*wcs:CoverageDescription*/ ); coveDescElement.setAttribute( QStringLiteral( "xmlns" ), WCS_NAMESPACE ); coveDescElement.setAttribute( QStringLiteral( "xmlns:xsi" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema-instance" ) ); coveDescElement.setAttribute( QStringLiteral( "xsi:schemaLocation" ), WCS_NAMESPACE + " http://schemas.opengis.net/wcs/1.0.0/describeCoverage.xsd" ); coveDescElement.setAttribute( QStringLiteral( "xmlns:gml" ), GML_NAMESPACE ); coveDescElement.setAttribute( QStringLiteral( "xmlns:xlink" ), QStringLiteral( "http://www.w3.org/1999/xlink" ) ); coveDescElement.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.0.0" ) ); coveDescElement.setAttribute( QStringLiteral( "updateSequence" ), QStringLiteral( "0" ) ); doc.appendChild( coveDescElement ); //defining coverage name QString coveNames; //read COVERAGE QMap<QString, QString>::const_iterator cove_name_it = parameters.constFind( QStringLiteral( "COVERAGE" ) ); if ( cove_name_it != parameters.constEnd() ) { coveNames = cove_name_it.value(); } if ( coveNames.isEmpty() ) { QMap<QString, QString>::const_iterator cove_name_it = parameters.constFind( QStringLiteral( "IDENTIFIER" ) ); if ( cove_name_it != parameters.constEnd() ) { coveNames = cove_name_it.value(); } } QStringList coveNameList; if ( !coveNames.isEmpty() ) { coveNameList = coveNames.split( ',' ); for ( int i = 0; i < coveNameList.size(); ++i ) { coveNameList.replace( i, coveNameList.at( i ).trimmed() ); } } QStringList wcsLayersId = QgsServerProjectUtils::wcsLayerIds( *project ); for ( int i = 0; i < wcsLayersId.size(); ++i ) { QgsMapLayer *layer = project->mapLayer( wcsLayersId.at( i ) ); if ( !layer ) { continue; } if ( layer->type() != QgsMapLayer::LayerType::RasterLayer ) { continue; } #ifdef HAVE_SERVER_PYTHON_PLUGINS if ( !accessControl->layerReadPermission( layer ) ) { continue; } #endif QString name = layer->name(); if ( !layer->shortName().isEmpty() ) name = layer->shortName(); name = name.replace( ' ', '_' ); if ( coveNameList.size() == 0 || coveNameList.contains( name ) ) { QgsRasterLayer *rLayer = qobject_cast<QgsRasterLayer *>( layer ); coveDescElement.appendChild( getCoverageOffering( doc, const_cast<QgsRasterLayer *>( rLayer ), project ) ); } } return doc; }
QDomDocument getCapabilities( QgsServerInterface* serverIface, const QString& version, const QgsServerRequest& request, bool projectSettings ) { QDomDocument doc; QDomElement wmsCapabilitiesElement; QgsWmsConfigParser* configParser = getConfigParser( serverIface ); QgsServerRequest::Parameters parameters = request.parameters(); // Get service URL QUrl href = serviceUrl( request, configParser ); //href needs to be a prefix QString hrefString = href.toString( QUrl::FullyDecoded ); hrefString.append( href.hasQuery() ? "&" : "?" ); // XML declaration QDomProcessingInstruction xmlDeclaration = doc.createProcessingInstruction( QStringLiteral( "xml" ), QStringLiteral( "version=\"1.0\" encoding=\"utf-8\"" ) ); // Append format helper std::function < void ( QDomElement&, const QString& ) > appendFormat = [&doc]( QDomElement & elem, const QString & format ) { QDomElement formatElem = doc.createElement( QStringLiteral( "Format" )/*wms:Format*/ ); formatElem.appendChild( doc.createTextNode( format ) ); elem.appendChild( formatElem ); }; if ( version == QLatin1String( "1.1.1" ) ) { doc = QDomDocument( QStringLiteral( "WMT_MS_Capabilities SYSTEM 'http://schemas.opengis.net/wms/1.1.1/WMS_MS_Capabilities.dtd'" ) ); //WMS 1.1.1 needs DOCTYPE "SYSTEM http://schemas.opengis.net/wms/1.1.1/WMS_MS_Capabilities.dtd" doc.appendChild( xmlDeclaration ); wmsCapabilitiesElement = doc.createElement( QStringLiteral( "WMT_MS_Capabilities" )/*wms:WMS_Capabilities*/ ); } else // 1.3.0 as default { doc.appendChild( xmlDeclaration ); wmsCapabilitiesElement = doc.createElement( QStringLiteral( "WMS_Capabilities" )/*wms:WMS_Capabilities*/ ); wmsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns" ), QStringLiteral( "http://www.opengis.net/wms" ) ); wmsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns:sld" ), QStringLiteral( "http://www.opengis.net/sld" ) ); wmsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns:qgs" ), QStringLiteral( "http://www.qgis.org/wms" ) ); wmsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns:xsi" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema-instance" ) ); QString schemaLocation = QStringLiteral( "http://www.opengis.net/wms" ); schemaLocation += QLatin1String( " http://schemas.opengis.net/wms/1.3.0/capabilities_1_3_0.xsd" ); schemaLocation += QLatin1String( " http://www.opengis.net/sld" ); schemaLocation += QLatin1String( " http://schemas.opengis.net/sld/1.1.0/sld_capabilities.xsd" ); schemaLocation += QLatin1String( " http://www.qgis.org/wms" ); if ( configParser && configParser->wmsInspireActivated() ) { wmsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns:inspire_common" ), QStringLiteral( "http://inspire.ec.europa.eu/schemas/common/1.0" ) ); wmsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns:inspire_vs" ), QStringLiteral( "http://inspire.ec.europa.eu/schemas/inspire_vs/1.0" ) ); schemaLocation += QLatin1String( " http://inspire.ec.europa.eu/schemas/inspire_vs/1.0" ); schemaLocation += QLatin1String( " http://inspire.ec.europa.eu/schemas/inspire_vs/1.0/inspire_vs.xsd" ); } schemaLocation += " " + hrefString + "SERVICE=WMS&REQUEST=GetSchemaExtension"; wmsCapabilitiesElement.setAttribute( QStringLiteral( "xsi:schemaLocation" ), schemaLocation ); } wmsCapabilitiesElement.setAttribute( QStringLiteral( "version" ), version ); doc.appendChild( wmsCapabilitiesElement ); configParser->serviceCapabilities( wmsCapabilitiesElement, doc ); //wms:Capability element QDomElement capabilityElement = doc.createElement( QStringLiteral( "Capability" )/*wms:Capability*/ ); wmsCapabilitiesElement.appendChild( capabilityElement ); //wms:Request element QDomElement requestElement = doc.createElement( QStringLiteral( "Request" )/*wms:Request*/ ); capabilityElement.appendChild( requestElement ); QDomElement dcpTypeElement = doc.createElement( QStringLiteral( "DCPType" )/*wms:DCPType*/ ); QDomElement httpElement = doc.createElement( QStringLiteral( "HTTP" )/*wms:HTTP*/ ); dcpTypeElement.appendChild( httpElement ); QDomElement elem; //wms:GetCapabilities elem = doc.createElement( QStringLiteral( "GetCapabilities" )/*wms:GetCapabilities*/ ); appendFormat( elem, ( version == QLatin1String( "1.1.1" ) ? "application/vnd.ogc.wms_xml" : "text/xml" ) ); elem.appendChild( dcpTypeElement ); requestElement.appendChild( elem ); // SOAP platform //only give this information if it is not a WMS request to be in sync with the WMS capabilities schema // XXX Not even sure that cam be ever true if ( parameters.value( QStringLiteral( "SERVICE" ) ).compare( QLatin1String( "WMS" ), Qt::CaseInsensitive ) != 0 ) { QDomElement soapElement = doc.createElement( QStringLiteral( "SOAP" )/*wms:SOAP*/ ); httpElement.appendChild( soapElement ); QDomElement soapResourceElement = doc.createElement( QStringLiteral( "OnlineResource" )/*wms:OnlineResource*/ ); soapResourceElement.setAttribute( QStringLiteral( "xmlns:xlink" ), QStringLiteral( "http://www.w3.org/1999/xlink" ) ); soapResourceElement.setAttribute( QStringLiteral( "xlink:type" ), QStringLiteral( "simple" ) ); soapResourceElement.setAttribute( QStringLiteral( "xlink:href" ), hrefString ); soapElement.appendChild( soapResourceElement ); } //only Get supported for the moment QDomElement getElement = doc.createElement( QStringLiteral( "Get" )/*wms:Get*/ ); httpElement.appendChild( getElement ); QDomElement olResourceElement = doc.createElement( QStringLiteral( "OnlineResource" )/*wms:OnlineResource*/ ); olResourceElement.setAttribute( QStringLiteral( "xmlns:xlink" ), QStringLiteral( "http://www.w3.org/1999/xlink" ) ); olResourceElement.setAttribute( QStringLiteral( "xlink:type" ), QStringLiteral( "simple" ) ); olResourceElement.setAttribute( QStringLiteral( "xlink:href" ), hrefString ); getElement.appendChild( olResourceElement ); //wms:GetMap elem = doc.createElement( QStringLiteral( "GetMap" )/*wms:GetMap*/ ); appendFormat( elem, QStringLiteral( "image/jpeg" ) ); appendFormat( elem, QStringLiteral( "image/png" ) ); appendFormat( elem, QStringLiteral( "image/png; mode=16bit" ) ); appendFormat( elem, QStringLiteral( "image/png; mode=8bit" ) ); appendFormat( elem, QStringLiteral( "image/png; mode=1bit" ) ); appendFormat( elem, QStringLiteral( "application/dxf" ) ); elem.appendChild( dcpTypeElement.cloneNode().toElement() ); //this is the same as for 'GetCapabilities' requestElement.appendChild( elem ); //wms:GetFeatureInfo elem = doc.createElement( QStringLiteral( "GetFeatureInfo" ) ); appendFormat( elem, QStringLiteral( "text/plain" ) ); appendFormat( elem, QStringLiteral( "text/html" ) ); appendFormat( elem, QStringLiteral( "text/xml" ) ); appendFormat( elem, QStringLiteral( "application/vnd.ogc.gml" ) ); appendFormat( elem, QStringLiteral( "application/vnd.ogc.gml/3.1.1" ) ); elem.appendChild( dcpTypeElement.cloneNode().toElement() ); //this is the same as for 'GetCapabilities' requestElement.appendChild( elem ); //wms:GetLegendGraphic elem = doc.createElement(( version == QLatin1String( "1.1.1" ) ? "GetLegendGraphic" : "sld:GetLegendGraphic" )/*wms:GetLegendGraphic*/ ); appendFormat( elem, QStringLiteral( "image/jpeg" ) ); appendFormat( elem, QStringLiteral( "image/png" ) ); elem.appendChild( dcpTypeElement.cloneNode().toElement() ); // this is the same as for 'GetCapabilities' requestElement.appendChild( elem ); //wms:DescribeLayer elem = doc.createElement(( version == QLatin1String( "1.1.1" ) ? "DescribeLayer" : "sld:DescribeLayer" )/*wms:GetLegendGraphic*/ ); appendFormat( elem, QStringLiteral( "text/xml" ) ); elem.appendChild( dcpTypeElement.cloneNode().toElement() ); // this is the same as for 'GetCapabilities' requestElement.appendChild( elem ); //wms:GetStyles elem = doc.createElement(( version == QLatin1String( "1.1.1" ) ? "GetStyles" : "qgs:GetStyles" )/*wms:GetStyles*/ ); appendFormat( elem, QStringLiteral( "text/xml" ) ); elem.appendChild( dcpTypeElement.cloneNode().toElement() ); //this is the same as for 'GetCapabilities' requestElement.appendChild( elem ); if ( projectSettings ) //remove composer templates from GetCapabilities in the long term { //wms:GetPrint elem = doc.createElement( QStringLiteral( "GetPrint" ) /*wms:GetPrint*/ ); appendFormat( elem, QStringLiteral( "svg" ) ); appendFormat( elem, QStringLiteral( "png" ) ); appendFormat( elem, QStringLiteral( "pdf" ) ); elem.appendChild( dcpTypeElement.cloneNode().toElement() ); //this is the same as for 'GetCapabilities' requestElement.appendChild( elem ); } //Exception element is mandatory elem = doc.createElement( QStringLiteral( "Exception" ) ); appendFormat( elem, ( version == QLatin1String( "1.1.1" ) ? "application/vnd.ogc.se_xml" : "XML" ) ); capabilityElement.appendChild( elem ); //UserDefinedSymbolization element if ( version == QLatin1String( "1.3.0" ) ) { elem = doc.createElement( QStringLiteral( "sld:UserDefinedSymbolization" ) ); elem.setAttribute( QStringLiteral( "SupportSLD" ), QStringLiteral( "1" ) ); elem.setAttribute( QStringLiteral( "UserLayer" ), QStringLiteral( "0" ) ); elem.setAttribute( QStringLiteral( "UserStyle" ), QStringLiteral( "1" ) ); elem.setAttribute( QStringLiteral( "RemoteWFS" ), QStringLiteral( "0" ) ); elem.setAttribute( QStringLiteral( "InlineFeature" ), QStringLiteral( "0" ) ); elem.setAttribute( QStringLiteral( "RemoteWCS" ), QStringLiteral( "0" ) ); capabilityElement.appendChild( elem ); if ( configParser->wmsInspireActivated() ) { configParser->inspireCapabilities( capabilityElement, doc ); } } if ( projectSettings ) { //Insert <ComposerTemplate> elements derived from wms:_ExtendedCapabilities configParser->printCapabilities( capabilityElement, doc ); //WFS layers QStringList wfsLayers = configParser->wfsLayerNames(); if ( !wfsLayers.isEmpty() ) { QDomElement wfsLayersElem = doc.createElement( QStringLiteral( "WFSLayers" ) ); for ( auto wfsIt = wfsLayers.constBegin() ; wfsIt != wfsLayers.constEnd(); ++wfsIt ) { QDomElement wfsLayerElem = doc.createElement( QStringLiteral( "WFSLayer" ) ); wfsLayerElem.setAttribute( QStringLiteral( "name" ), *wfsIt ); wfsLayersElem.appendChild( wfsLayerElem ); } capabilityElement.appendChild( wfsLayersElem ); } } //add the xml content for the individual layers/styles configParser->layersAndStylesCapabilities( capabilityElement, doc, version, projectSettings ); return doc; }
QDomDocument createTransactionDocument( QgsServerInterface* serverIface, const QString& version, const QgsServerRequest& request ) { Q_UNUSED( version ); QDomDocument doc; QgsWfsProjectParser* configParser = getConfigParser( serverIface ); #ifdef HAVE_SERVER_PYTHON_PLUGINS QgsAccessControl* accessControl = serverIface->accessControls(); #endif const QString requestBody = request.getParameter( QStringLiteral( "REQUEST_BODY" ) ); QString errorMsg; if ( !doc.setContent( requestBody, true, &errorMsg ) ) { throw QgsRequestNotWellFormedException( errorMsg ); } QDomElement docElem = doc.documentElement(); QDomNodeList docChildNodes = docElem.childNodes(); // Re-organize the transaction document QDomDocument mDoc; QDomElement mDocElem = mDoc.createElement( QStringLiteral( "myTransactionDocument" ) ); mDocElem.setAttribute( QStringLiteral( "xmlns" ), QGS_NAMESPACE ); mDocElem.setAttribute( QStringLiteral( "xmlns:wfs" ), WFS_NAMESPACE ); mDocElem.setAttribute( QStringLiteral( "xmlns:gml" ), GML_NAMESPACE ); mDocElem.setAttribute( QStringLiteral( "xmlns:ogc" ), OGC_NAMESPACE ); mDocElem.setAttribute( QStringLiteral( "xmlns:qgs" ), QGS_NAMESPACE ); mDocElem.setAttribute( QStringLiteral( "xmlns:xsi" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema-instance" ) ); mDoc.appendChild( mDocElem ); QDomElement actionElem; QString actionName; QDomElement typeNameElem; QString typeName; for ( int i = docChildNodes.count(); 0 < i; --i ) { actionElem = docChildNodes.at( i - 1 ).toElement(); actionName = actionElem.localName(); if ( actionName == QLatin1String( "Insert" ) ) { QDomElement featureElem = actionElem.firstChild().toElement(); typeName = featureElem.localName(); } else if ( actionName == QLatin1String( "Update" ) ) { typeName = actionElem.attribute( QStringLiteral( "typeName" ) ); } else if ( actionName == QLatin1String( "Delete" ) ) { typeName = actionElem.attribute( QStringLiteral( "typeName" ) ); } if ( typeName.contains( QLatin1String( ":" ) ) ) typeName = typeName.section( QStringLiteral( ":" ), 1, 1 ); QDomNodeList typeNameList = mDocElem.elementsByTagName( typeName ); if ( typeNameList.count() == 0 ) { typeNameElem = mDoc.createElement( typeName ); mDocElem.appendChild( typeNameElem ); } else typeNameElem = typeNameList.at( 0 ).toElement(); typeNameElem.appendChild( actionElem ); } // It's time to make the transaction // Create the response document QDomDocument resp; //wfs:WFS_TransactionRespone element QDomElement respElem = resp.createElement( QStringLiteral( "WFS_TransactionResponse" )/*wfs:WFS_TransactionResponse*/ ); respElem.setAttribute( QStringLiteral( "xmlns" ), WFS_NAMESPACE ); respElem.setAttribute( QStringLiteral( "xmlns:xsi" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema-instance" ) ); respElem.setAttribute( QStringLiteral( "xsi:schemaLocation" ), WFS_NAMESPACE + " http://schemas.opengis.net/wfs/1.0.0/wfs.xsd" ); respElem.setAttribute( QStringLiteral( "xmlns:ogc" ), OGC_NAMESPACE ); respElem.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.0.0" ) ); resp.appendChild( respElem ); // Store the created feature id for WFS QStringList insertResults; // Get the WFS layers id QStringList wfsLayersId = configParser->wfsLayers();; QList<QgsMapLayer*> layerList; QgsMapLayer* currentLayer = nullptr; // Loop through the layer transaction elements docChildNodes = mDocElem.childNodes(); for ( int i = 0; i < docChildNodes.count(); ++i ) { // Get the vector layer typeNameElem = docChildNodes.at( i ).toElement(); typeName = typeNameElem.tagName(); layerList = configParser->mapLayerFromTypeName( typeName ); // Could be empty! if ( layerList.count() > 0 ) { currentLayer = layerList.at( 0 ); } else { throw QgsRequestNotWellFormedException( QStringLiteral( "Wrong TypeName: %1" ).arg( typeName ) ); } QgsVectorLayer* layer = qobject_cast<QgsVectorLayer*>( currentLayer ); // it's a vectorlayer and defined by the administrator as a WFS layer if ( layer && wfsLayersId.contains( layer->id() ) ) { #ifdef HAVE_SERVER_PYTHON_PLUGINS if ( actionName == QLatin1String( "Insert" ) ) { if ( !accessControl->layerInsertPermission( layer ) ) { throw QgsSecurityAccessException( QStringLiteral( "Feature insert permission denied" ) ); } } else if ( actionName == QLatin1String( "Update" ) ) { if ( !accessControl->layerUpdatePermission( layer ) ) { throw QgsSecurityAccessException( QStringLiteral( "Feature update permission denied" ) ); } } else if ( actionName == QLatin1String( "Delete" ) ) { if ( !accessControl->layerDeletePermission( layer ) ) { throw QgsSecurityAccessException( QStringLiteral( "Feature delete permission denied" ) ); } } #endif // Get the provider and it's capabilities QgsVectorDataProvider* provider = layer->dataProvider(); if ( !provider ) { continue; } int cap = provider->capabilities(); // Start the update transaction layer->startEditing(); if (( cap & QgsVectorDataProvider::ChangeAttributeValues ) && ( cap & QgsVectorDataProvider::ChangeGeometries ) ) { // Loop through the update elements for this layer QDomNodeList upNodeList = typeNameElem.elementsByTagNameNS( WFS_NAMESPACE, QStringLiteral( "Update" ) ); for ( int j = 0; j < upNodeList.count(); ++j ) { if ( !configParser->wfstUpdateLayers().contains( layer->id() ) ) { //no wfs permissions to do updates QString errorMsg = "No permissions to do WFS updates on layer '" + layer->name() + "'"; QgsMessageLog::logMessage( errorMsg, QStringLiteral( "Server" ), QgsMessageLog::CRITICAL ); addTransactionResult( resp, respElem, QStringLiteral( "FAILED" ), QStringLiteral( "Update" ), errorMsg ); return resp; } actionElem = upNodeList.at( j ).toElement(); // Get the Feature Ids for this filter on the layer QDomElement filterElem = actionElem.elementsByTagName( QStringLiteral( "Filter" ) ).at( 0 ).toElement(); QgsFeatureIds fids = getFeatureIdsFromFilter( filterElem, layer ); // Loop through the property elements // Store properties and the geometry element QDomNodeList propertyNodeList = actionElem.elementsByTagName( QStringLiteral( "Property" ) ); QMap<QString, QString> propertyMap; QDomElement propertyElem; QDomElement nameElem; QDomElement valueElem; QDomElement geometryElem; for ( int l = 0; l < propertyNodeList.count(); ++l ) { propertyElem = propertyNodeList.at( l ).toElement(); nameElem = propertyElem.elementsByTagName( QStringLiteral( "Name" ) ).at( 0 ).toElement(); valueElem = propertyElem.elementsByTagName( QStringLiteral( "Value" ) ).at( 0 ).toElement(); if ( nameElem.text() != QLatin1String( "geometry" ) ) { propertyMap.insert( nameElem.text(), valueElem.text() ); } else { geometryElem = valueElem; } } // Update the features QgsFields fields = provider->fields(); QMap<QString, int> fieldMap = provider->fieldNameMap(); QMap<QString, int>::const_iterator fieldMapIt; QString fieldName; bool conversionSuccess; QgsFeatureIds::const_iterator fidIt = fids.constBegin(); for ( ; fidIt != fids.constEnd(); ++fidIt ) { #ifdef HAVE_SERVER_PYTHON_PLUGINS QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest( *fidIt ) ); QgsFeature feature; while ( fit.nextFeature( feature ) ) { if ( !accessControl->allowToEdit( layer, feature ) ) { throw QgsSecurityAccessException( QStringLiteral( "Feature modify permission denied" ) ); } } #endif QMap< QString, QString >::const_iterator it = propertyMap.constBegin(); for ( ; it != propertyMap.constEnd(); ++it ) { fieldName = it.key(); fieldMapIt = fieldMap.find( fieldName ); if ( fieldMapIt == fieldMap.constEnd() ) { continue; } QgsField field = fields.at( fieldMapIt.value() ); if ( field.type() == 2 ) layer->changeAttributeValue( *fidIt, fieldMapIt.value(), it.value().toInt( &conversionSuccess ) ); else if ( field.type() == 6 ) layer->changeAttributeValue( *fidIt, fieldMapIt.value(), it.value().toDouble( &conversionSuccess ) ); else layer->changeAttributeValue( *fidIt, fieldMapIt.value(), it.value() ); } if ( !geometryElem.isNull() ) { QgsGeometry g = QgsOgcUtils::geometryFromGML( geometryElem ); if ( !layer->changeGeometry( *fidIt, g ) ) { throw QgsRequestNotWellFormedException( QStringLiteral( "Error in change geometry" ) ); } } #ifdef HAVE_SERVER_PYTHON_PLUGINS fit = layer->getFeatures( QgsFeatureRequest( *fidIt ) ); while ( fit.nextFeature( feature ) ) { if ( !accessControl->allowToEdit( layer, feature ) ) { layer->rollBack(); throw QgsSecurityAccessException( QStringLiteral( "Feature modify permission denied" ) ); } } #endif } } } // Commit the changes of the update elements if ( !layer->commitChanges() ) { addTransactionResult( resp, respElem, QStringLiteral( "PARTIAL" ), QStringLiteral( "Update" ), layer->commitErrors().join( QStringLiteral( "\n " ) ) ); return resp; } // Start the delete transaction layer->startEditing(); if (( cap & QgsVectorDataProvider::DeleteFeatures ) ) { // Loop through the delete elements QDomNodeList delNodeList = typeNameElem.elementsByTagNameNS( WFS_NAMESPACE, QStringLiteral( "Delete" ) ); for ( int j = 0; j < delNodeList.count(); ++j ) { if ( !configParser->wfstDeleteLayers().contains( layer->id() ) ) { //no wfs permissions to do updates QString errorMsg = "No permissions to do WFS deletes on layer '" + layer->name() + "'"; QgsMessageLog::logMessage( errorMsg, QStringLiteral( "Server" ), QgsMessageLog::CRITICAL ); addTransactionResult( resp, respElem, QStringLiteral( "FAILED" ), QStringLiteral( "Delete" ), errorMsg ); return resp; } actionElem = delNodeList.at( j ).toElement(); QDomElement filterElem = actionElem.firstChild().toElement(); // Get Feature Ids for the Filter element QgsFeatureIds fids = getFeatureIdsFromFilter( filterElem, layer ); #ifdef HAVE_SERVER_PYTHON_PLUGINS QgsFeatureIds::const_iterator fidIt = fids.constBegin(); for ( ; fidIt != fids.constEnd(); ++fidIt ) { QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest( *fidIt ) ); QgsFeature feature; while ( fit.nextFeature( feature ) ) { if ( !accessControl->allowToEdit( layer, feature ) ) { throw QgsSecurityAccessException( QStringLiteral( "Feature modify permission denied" ) ); } } } #endif layer->selectByIds( fids ); layer->deleteSelectedFeatures(); } } // Commit the changes of the delete elements if ( !layer->commitChanges() ) { addTransactionResult( resp, respElem, QStringLiteral( "PARTIAL" ), QStringLiteral( "Delete" ), layer->commitErrors().join( QStringLiteral( "\n " ) ) ); return resp; } // Store the inserted features QgsFeatureList inFeatList; if ( cap & QgsVectorDataProvider::AddFeatures ) { // Get Layer Field Information QgsFields fields = provider->fields(); QMap<QString, int> fieldMap = provider->fieldNameMap(); QMap<QString, int>::const_iterator fieldMapIt; // Loop through the insert elements QDomNodeList inNodeList = typeNameElem.elementsByTagNameNS( WFS_NAMESPACE, QStringLiteral( "Insert" ) ); for ( int j = 0; j < inNodeList.count(); ++j ) { if ( !configParser->wfstInsertLayers().contains( layer->id() ) ) { //no wfs permissions to do updates QString errorMsg = "No permissions to do WFS inserts on layer '" + layer->name() + "'"; QgsMessageLog::logMessage( errorMsg, QStringLiteral( "Server" ), QgsMessageLog::CRITICAL ); addTransactionResult( resp, respElem, QStringLiteral( "FAILED" ), QStringLiteral( "Insert" ), errorMsg ); return resp; } actionElem = inNodeList.at( j ).toElement(); // Loop through the feature element QDomNodeList featNodes = actionElem.childNodes(); for ( int l = 0; l < featNodes.count(); l++ ) { // Add the feature to the layer // and store it to put it's Feature Id in the response inFeatList << QgsFeature( fields ); // Create feature for this layer QDomElement featureElem = featNodes.at( l ).toElement(); QDomNode currentAttributeChild = featureElem.firstChild(); while ( !currentAttributeChild.isNull() ) { QDomElement currentAttributeElement = currentAttributeChild.toElement(); QString attrName = currentAttributeElement.localName(); if ( attrName != QLatin1String( "boundedBy" ) ) { if ( attrName != QLatin1String( "geometry" ) ) //a normal attribute { fieldMapIt = fieldMap.find( attrName ); if ( fieldMapIt == fieldMap.constEnd() ) { continue; } QgsField field = fields.at( fieldMapIt.value() ); QString attrValue = currentAttributeElement.text(); int attrType = field.type(); QgsMessageLog::logMessage( QStringLiteral( "attr: name=%1 idx=%2 value=%3" ).arg( attrName ).arg( fieldMapIt.value() ).arg( attrValue ) ); if ( attrType == QVariant::Int ) inFeatList.last().setAttribute( fieldMapIt.value(), attrValue.toInt() ); else if ( attrType == QVariant::Double ) inFeatList.last().setAttribute( fieldMapIt.value(), attrValue.toDouble() ); else inFeatList.last().setAttribute( fieldMapIt.value(), attrValue ); } else //a geometry attribute { QgsGeometry g = QgsOgcUtils::geometryFromGML( currentAttributeElement ); inFeatList.last().setGeometry( g ); } } currentAttributeChild = currentAttributeChild.nextSibling(); } } } } #ifdef HAVE_SERVER_PYTHON_PLUGINS QgsFeatureList::iterator featureIt = inFeatList.begin(); while ( featureIt != inFeatList.end() ) { if ( !accessControl->allowToEdit( layer, *featureIt ) ) { throw QgsSecurityAccessException( QStringLiteral( "Feature modify permission denied" ) ); } featureIt++; } #endif // add the features if ( !provider->addFeatures( inFeatList ) ) { addTransactionResult( resp, respElem, QStringLiteral( "Partial" ), QStringLiteral( "Insert" ), layer->commitErrors().join( QStringLiteral( "\n " ) ) ); if ( provider->hasErrors() ) { provider->clearErrors(); } return resp; } // Get the Feature Ids of the inserted feature for ( int j = 0; j < inFeatList.size(); j++ ) { insertResults << typeName + "." + QString::number( inFeatList[j].id() ); } } } // Put the Feature Ids of the inserted feature if ( !insertResults.isEmpty() ) { Q_FOREACH ( const QString &fidStr, insertResults ) { QDomElement irElem = doc.createElement( QStringLiteral( "InsertResult" ) ); QDomElement fiElem = doc.createElement( QStringLiteral( "ogc:FeatureId" ) ); fiElem.setAttribute( QStringLiteral( "fid" ), fidStr ); irElem.appendChild( fiElem ); respElem.appendChild( irElem ); }
// DescribeLayer is defined for WMS1.1.1/SLD1.0 and in WMS 1.3.0 SLD Extension QDomDocument describeLayer( QgsServerInterface *serverIface, const QgsProject *project, const QString &version, const QgsServerRequest &request ) { Q_UNUSED( version ); QgsServerRequest::Parameters parameters = request.parameters(); if ( !parameters.contains( QStringLiteral( "SLD_VERSION" ) ) ) { throw QgsServiceException( QStringLiteral( "MissingParameterValue" ), QStringLiteral( "SLD_VERSION is mandatory for DescribeLayer operation" ), 400 ); } if ( parameters[ QStringLiteral( "SLD_VERSION" )] != QLatin1String( "1.1.0" ) ) { throw QgsServiceException( QStringLiteral( "InvalidParameterValue" ), QStringLiteral( "SLD_VERSION = %1 is not supported" ).arg( parameters[ QStringLiteral( "SLD_VERSION" )] ), 400 ); } if ( !parameters.contains( QStringLiteral( "LAYERS" ) ) ) { throw QgsServiceException( QStringLiteral( "MissingParameterValue" ), QStringLiteral( "LAYERS is mandatory for DescribeLayer operation" ), 400 ); } QStringList layersList = parameters[ QStringLiteral( "LAYERS" )].split( ',', QString::SkipEmptyParts ); if ( layersList.isEmpty() ) { throw QgsServiceException( QStringLiteral( "InvalidParameterValue" ), QStringLiteral( "Layers is empty" ), 400 ); } QDomDocument myDocument = QDomDocument(); QDomNode header = myDocument.createProcessingInstruction( QStringLiteral( "xml" ), QStringLiteral( "version=\"1.0\" encoding=\"UTF-8\"" ) ); myDocument.appendChild( header ); // Create the root element QDomElement root = myDocument.createElementNS( QStringLiteral( "http://www.opengis.net/sld" ), QStringLiteral( "DescribeLayerResponse" ) ); root.setAttribute( QStringLiteral( "xsi:schemaLocation" ), QStringLiteral( "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/DescribeLayer.xsd" ) ); root.setAttribute( QStringLiteral( "xmlns:ows" ), QStringLiteral( "http://www.opengis.net/ows" ) ); root.setAttribute( QStringLiteral( "xmlns:se" ), QStringLiteral( "http://www.opengis.net/se" ) ); root.setAttribute( QStringLiteral( "xmlns:xlink" ), QStringLiteral( "http://www.w3.org/1999/xlink" ) ); root.setAttribute( QStringLiteral( "xmlns:xsi" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema-instance" ) ); myDocument.appendChild( root ); // store the Version element QDomElement versionNode = myDocument.createElement( QStringLiteral( "Version" ) ); versionNode.appendChild( myDocument.createTextNode( QStringLiteral( "1.1.0" ) ) ); root.appendChild( versionNode ); // get the wms service url defined in project or keep the one from the // request url QString wmsHrefString = serviceUrl( request, project ).toString(); // get the wfs service url defined in project or take the same as the // wms service url QString wfsHrefString = QgsServerProjectUtils::wfsServiceUrl( *project ); if ( wfsHrefString.isEmpty() ) { wfsHrefString = wmsHrefString; } // get the wcs service url defined in project or take the same as the // wms service url QString wcsHrefString = QgsServerProjectUtils::wcsServiceUrl( *project ); if ( wcsHrefString.isEmpty() ) { wcsHrefString = wmsHrefString; } // access control #ifdef HAVE_SERVER_PYTHON_PLUGINS QgsAccessControl *accessControl = serverIface->accessControls(); #endif // Use layer ids bool useLayerIds = QgsServerProjectUtils::wmsUseLayerIds( *project ); // WMS restricted layers QStringList restrictedLayers = QgsServerProjectUtils::wmsRestrictedLayers( *project ); // WFS layers QStringList wfsLayerIds = QgsServerProjectUtils::wfsLayerIds( *project ); // WCS layers QStringList wcsLayerIds = QgsServerProjectUtils::wcsLayerIds( *project ); for ( QgsMapLayer *layer : project->mapLayers() ) { QString name = layer->name(); if ( useLayerIds ) name = layer->id(); else if ( !layer->shortName().isEmpty() ) name = layer->shortName(); if ( !layersList.contains( name ) ) { continue; } //unpublished layer if ( restrictedLayers.contains( layer->name() ) ) { throw QgsSecurityException( QStringLiteral( "You are not allowed to access to this layer" ) ); } #ifdef HAVE_SERVER_PYTHON_PLUGINS if ( accessControl && !accessControl->layerReadPermission( layer ) ) { throw QgsSecurityException( QStringLiteral( "You are not allowed to access to this layer" ) ); } #endif // Create the NamedLayer element QDomElement layerNode = myDocument.createElement( QStringLiteral( "LayerDescription" ) ); root.appendChild( layerNode ); // store the owsType element QDomElement typeNode = myDocument.createElement( QStringLiteral( "owsType" ) ); // store the se:OnlineResource element QDomElement oResNode = myDocument.createElement( QStringLiteral( "se:OnlineResource" ) ); oResNode.setAttribute( QStringLiteral( "xlink:type" ), QStringLiteral( "simple" ) ); // store the TypeName element QDomElement nameNode = myDocument.createElement( QStringLiteral( "TypeName" ) ); switch ( layer->type() ) { case QgsMapLayer::VectorLayer: { typeNode.appendChild( myDocument.createTextNode( QStringLiteral( "wfs" ) ) ); if ( wfsLayerIds.indexOf( layer->id() ) != -1 ) { oResNode.setAttribute( QStringLiteral( "xlink:href" ), wfsHrefString ); } // store the se:FeatureTypeName element QDomElement typeNameNode = myDocument.createElement( QStringLiteral( "se:FeatureTypeName" ) ); typeNameNode.appendChild( myDocument.createTextNode( name ) ); nameNode.appendChild( typeNameNode ); break; } case QgsMapLayer::RasterLayer: { typeNode.appendChild( myDocument.createTextNode( QStringLiteral( "wcs" ) ) ); if ( wcsLayerIds.indexOf( layer->id() ) != -1 ) { oResNode.setAttribute( QStringLiteral( "xlink:href" ), wcsHrefString ); } // store the se:CoverageTypeName element QDomElement typeNameNode = myDocument.createElement( QStringLiteral( "se:CoverageTypeName" ) ); typeNameNode.appendChild( myDocument.createTextNode( name ) ); nameNode.appendChild( typeNameNode ); break; } case QgsMapLayer::MeshLayer: case QgsMapLayer::PluginLayer: break; } layerNode.appendChild( typeNode ); layerNode.appendChild( oResNode ); layerNode.appendChild( nameNode ); } return myDocument; }