From ba85632b101b45e4b1cb6658446242fe32357eef Mon Sep 17 00:00:00 2001 From: Jean Felder Date: Sat, 10 Aug 2024 12:32:13 +0200 Subject: [PATCH] qgswfsgetfeature: Properly handle ogc urns in post requests There are 2 different parameters to check to define the output crs: - the request parameter (`SRSNAME` from the request) - the query crs parameter For a `GET` request, if `SRSNAME` is set, both parameters are set and equal. For a `POST` request, only the query parameter is set if defined. In `writeGetFeature()`, the `outputCrs` correctly takes into account the query parameter. However, this is not the case for the output srs name (`srsName`) which only takes into account the query CRS as an auth id. Therefore, the output srsName will always be defined as an authid even if the parameter is an ogc urn. This issue is fixed by first computing the output srs name (`outputSrsName`) by taking into account the query and the query parameters. Then, this name is used to compute `outputCrs`. --- src/server/services/wfs/qgswfsgetfeature.cpp | 35 ++++++---- tests/src/python/test_qgsserver_wfs.py | 10 ++- .../wfs_getfeature_srsname_post_1_1_0_urn.txt | 64 +++++++++++++++++++ 3 files changed, 92 insertions(+), 17 deletions(-) create mode 100644 tests/testdata/qgis_server/wfs_getfeature_srsname_post_1_1_0_urn.txt diff --git a/src/server/services/wfs/qgswfsgetfeature.cpp b/src/server/services/wfs/qgswfsgetfeature.cpp index 9cccf4d4ed6..dc9878782e6 100644 --- a/src/server/services/wfs/qgswfsgetfeature.cpp +++ b/src/server/services/wfs/qgswfsgetfeature.cpp @@ -414,11 +414,28 @@ namespace QgsWfs geometryName = QLatin1String( "NONE" ); } // outputCrs - QgsCoordinateReferenceSystem outputCrs = vlayer->crs(); + // if the crs is defined in the parameters, use it + // otherwise fallback: + // - geojson uses 'EPSG:4326' by default + // - other formats use the default CRS (the layer's CRS) + const QString requestSrsName = request.serverParameters().value( QStringLiteral( "SRSNAME" ) ); + QString outputSrsName; if ( !query.srsName.isEmpty() ) { - outputCrs = QgsCoordinateReferenceSystem::fromOgcWmsCrs( query.srsName ); + outputSrsName = query.srsName; } + else if ( !requestSrsName.isEmpty() ) + { + outputSrsName = requestSrsName; + } + else + { + // fallback to a default value + // geojson uses 'EPSG:4326' by default + outputSrsName = ( aRequest.outputFormat == QgsWfsParameters::Format::GeoJSON ) ? QStringLiteral( "EPSG:4326" ) : vlayer->crs().authid(); + } + + const QgsCoordinateReferenceSystem outputCrs = QgsCoordinateReferenceSystem::fromOgcWmsCrs( outputSrsName ); bool forceGeomToMulti = QgsWkbTypes::isMultiType( vlayer->wkbType() ); @@ -465,19 +482,9 @@ namespace QgsWfs // It needs to be an EPSG urn, e.g. urn:ogc:def:crs:EPSG::4326 // This follows geoserver convention // See: https://docs.geoserver.org/stable/en/user/services/wfs/axis_order.html - // if the crs is defined in the parameters, use it - // otherwise: - // - geojson uses 'EPSG:4326' by default - // - other formats use the default CRS (DefaultSRS, which is the layer's CRS) - const QString requestSrsName = request.serverParameters().value( QStringLiteral( "SRSNAME" ) ); - const QString srsName - { - !requestSrsName.isEmpty() ? requestSrsName : - ( aRequest.outputFormat == QgsWfsParameters::Format::GeoJSON ? QStringLiteral( "EPSG:4326" ) : outputCrs.authid() ) - }; const bool invertAxis { mWfsParameters.versionAsNumber() >= QgsProjectVersion( 1, 1, 0 ) && outputCrs.hasAxisInverted() && - ! srsName.startsWith( QLatin1String( "EPSG:" ) ) }; + ! outputSrsName.startsWith( QLatin1String( "EPSG:" ) ) }; const createFeatureParams cfp = { layerPrecision, layerCrs, @@ -487,7 +494,7 @@ namespace QgsWfs geometryName, outputCrs, forceGeomToMulti, - srsName, + outputSrsName, invertAxis }; while ( fit.nextFeature( feature ) && ( aRequest.maxFeatures == -1 || sentFeatures < aRequest.maxFeatures ) ) diff --git a/tests/src/python/test_qgsserver_wfs.py b/tests/src/python/test_qgsserver_wfs.py index 41812ba5e0e..ccc40f45637 100644 --- a/tests/src/python/test_qgsserver_wfs.py +++ b/tests/src/python/test_qgsserver_wfs.py @@ -314,7 +314,7 @@ class TestQgsServerWFS(QgsServerTestBase): srsTemplate = """ - + geometry @@ -327,8 +327,12 @@ class TestQgsServerWFS(QgsServerTestBase): """ - tests.append(('srsname_post_1_0_0', srsTemplate.format('1.0.0', ''))) - tests.append(('srsname_post_1_1_0', srsTemplate.format('1.1.0', ''))) + tests.append(('srsname_post_1_0_0', srsTemplate.format( + '1.0.0', '', 'srsName="EPSG:3857"'))) + tests.append(('srsname_post_1_1_0', srsTemplate.format( + '1.1.0', '', 'srsName="EPSG:3857"'))) + tests.append(('srsname_post_1_1_0_urn', srsTemplate.format( + '1.1.0', '', 'srsName="urn:ogc:def:crs:EPSG::3857"'))) # Issue https://github.com/qgis/QGIS/issues/36398 # Check get feature within polygon having srsName=EPSG:4326 (same as the project/layer) diff --git a/tests/testdata/qgis_server/wfs_getfeature_srsname_post_1_1_0_urn.txt b/tests/testdata/qgis_server/wfs_getfeature_srsname_post_1_1_0_urn.txt new file mode 100644 index 00000000000..f2ec396f1ce --- /dev/null +++ b/tests/testdata/qgis_server/wfs_getfeature_srsname_post_1_1_0_urn.txt @@ -0,0 +1,64 @@ +Content-Type: text/xml; subtype=gml/3.1.1; charset=utf-8 + + + + + 8 44 + 9 45 + + + + + + + 913209.03579284 5606025.23730414 + 913209.03579284 5606025.23730414 + + + + + 913209.03579284 5606025.23730414 + + + 1 + one + one èé + + + + + + + 913214.67407005 5606017.87425818 + 913214.67407005 5606017.87425818 + + + + + 913214.67407005 5606017.87425818 + + + 2 + two + two àò + + + + + + + 913204.91280263 5606011.45647302 + 913204.91280263 5606011.45647302 + + + + + 913204.91280263 5606011.45647302 + + + 3 + three + three èé↓ + + +