Skip to content

Commit f264799

Browse files
committed
[server] Make restoration of original layer subsetStrings much more
robust (there were many code paths where the original filters were not being correctly restored)
1 parent a46dca5 commit f264799

File tree

5 files changed

+78
-43
lines changed

5 files changed

+78
-43
lines changed

src/server/qgsowsserver.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ void QgsOWSServer::applyAccessControlLayerFilters( QgsMapLayer* mapLayer, QHash<
4949
#endif
5050

5151
/** Restore layer filter as original */
52-
void QgsOWSServer::restoreLayerFilters( const QHash<QgsMapLayer*, QString>& filterMap ) const
52+
void QgsOWSServer::restoreLayerFilters( const QHash<QgsMapLayer*, QString>& filterMap )
5353
{
5454
QHash<QgsMapLayer*, QString>::const_iterator filterIt = filterMap.constBegin();
5555
for ( ; filterIt != filterMap.constEnd(); ++filterIt )

src/server/qgsowsserver.h

+32-3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#include "qgsaccesscontrol.h"
2424
#endif
2525

26+
#include <QHash>
27+
2628
class QgsOWSServer
2729
{
2830
public:
@@ -45,6 +47,11 @@ class QgsOWSServer
4547

4648
virtual void executeRequest() = 0;
4749

50+
/** Restores the original layer filters
51+
* @param filterMap the original layer filter
52+
*/
53+
static void restoreLayerFilters( const QHash < QgsMapLayer*, QString >& filterMap );
54+
4855
private:
4956
QgsOWSServer() {}
5057

@@ -64,10 +71,32 @@ class QgsOWSServer
6471
void applyAccessControlLayerFilters( QgsMapLayer* layer, QHash<QgsMapLayer*, QString>& originalLayerFilters ) const;
6572
#endif
6673

67-
/** Restores the original layer filters
68-
* @param filterMap the original layer filter
74+
};
75+
76+
/** RAII class to restore layer filters on destruction
77+
*/
78+
class QgsOWSServerFilterRestorer
79+
{
80+
public:
81+
82+
QgsOWSServerFilterRestorer() {}
83+
84+
//! Destructor. When object is destroyed all original layer filters will be restored.
85+
~QgsOWSServerFilterRestorer()
86+
{
87+
QgsOWSServer::restoreLayerFilters( mOriginalLayerFilters );
88+
}
89+
90+
/** Returns a reference to the object's hash of layers to original subsetString filters.
91+
* Original layer subsetString filters MUST be inserted into this hash before modifying them.
6992
*/
70-
void restoreLayerFilters( const QHash < QgsMapLayer*, QString >& filterMap ) const;
93+
QHash<QgsMapLayer*, QString>& originalFilters() { return mOriginalLayerFilters; }
94+
95+
private:
96+
QHash<QgsMapLayer*, QString> mOriginalLayerFilters;
97+
98+
QgsOWSServerFilterRestorer( const QgsOWSServerFilterRestorer& rh );
99+
QgsOWSServerFilterRestorer& operator=( const QgsOWSServerFilterRestorer& rh );
71100
};
72101

73102
#endif // QGSOWSSERVER_H

src/server/qgswfsserver.cpp

+8-13
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,11 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
422422

423423
QDomDocument doc;
424424
QString errorMsg;
425-
QHash<QgsMapLayer*, QString> originalLayerFilters;
425+
426+
//scoped pointer to restore all original layer filters (subsetStrings) when pointer goes out of scope
427+
//there's LOTS of potential exit paths here, so we avoid having to restore the filters manually
428+
QScopedPointer< QgsOWSServerFilterRestorer > filterRestorer( new QgsOWSServerFilterRestorer() );
429+
426430
if ( doc.setContent( mParameters.value( "REQUEST_BODY" ), true, &errorMsg ) )
427431
{
428432
QDomElement docElem = doc.documentElement();
@@ -466,10 +470,9 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
466470
#ifdef HAVE_SERVER_PYTHON_PLUGINS
467471
if ( !mAccessControl->layerReadPermission( currentLayer ) )
468472
{
469-
restoreLayerFilters( originalLayerFilters );
470473
throw QgsMapServiceException( "Security", "Feature access permission denied" );
471474
}
472-
applyAccessControlLayerFilters( currentLayer, originalLayerFilters );
475+
applyAccessControlLayerFilters( currentLayer, filterRestorer->originalFilters() );
473476
#endif
474477

475478
expressionContext << QgsExpressionContextUtils::layerScope( layer );
@@ -646,9 +649,6 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
646649
{
647650
if ( filter->hasParserError() )
648651
{
649-
#ifdef HAVE_SERVER_PYTHON_PLUGINS
650-
restoreLayerFilters( originalLayerFilters );
651-
#endif
652652
throw QgsMapServiceException( "RequestNotWellFormed", filter->parserErrorString() );
653653
}
654654
while ( fit.nextFeature( feature ) && ( maxFeatures == -1 || featureCounter < maxFeat + startIndex ) )
@@ -658,10 +658,6 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
658658
QVariant res = filter->evaluate( &expressionContext );
659659
if ( filter->hasEvalError() )
660660
{
661-
662-
#ifdef HAVE_SERVER_PYTHON_PLUGINS
663-
restoreLayerFilters( originalLayerFilters );
664-
#endif
665661
throw QgsMapServiceException( "RequestNotWellFormed", filter->evalErrorString() );
666662
}
667663
if ( res.toInt() != 0 )
@@ -703,9 +699,8 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
703699

704700
}
705701

706-
#ifdef HAVE_SERVER_PYTHON_PLUGINS
707-
restoreLayerFilters( originalLayerFilters );
708-
#endif
702+
//force restoration of original layer filters
703+
filterRestorer.reset();
709704

710705
QgsMessageLog::logMessage( mErrors.join( "\n" ) );
711706

src/server/qgswmsserver.cpp

+28-24
Original file line numberDiff line numberDiff line change
@@ -1239,7 +1239,6 @@ QDomDocument QgsWMSServer::describeLayer()
12391239
QByteArray* QgsWMSServer::getPrint( const QString& formatString )
12401240
{
12411241
QStringList layersList, stylesList, layerIdList;
1242-
QString dummyFormat;
12431242
QImage* theImage = initializeRendering( layersList, stylesList, layerIdList );
12441243
if ( !theImage )
12451244
{
@@ -1257,18 +1256,21 @@ QByteArray* QgsWMSServer::getPrint( const QString& formatString )
12571256
}
12581257
#endif
12591258

1260-
QHash<QgsMapLayer*, QString> originalLayerFilters = applyRequestedLayerFilters( layersList );
1259+
//scoped pointer to restore all original layer filters (subsetStrings) when pointer goes out of scope
1260+
//there's LOTS of potential exit paths here, so we avoid having to restore the filters manually
1261+
QScopedPointer< QgsOWSServerFilterRestorer > filterRestorer( new QgsOWSServerFilterRestorer() );
1262+
1263+
applyRequestedLayerFilters( layersList, filterRestorer->originalFilters() );
12611264

12621265
#ifdef HAVE_SERVER_PYTHON_PLUGINS
1263-
applyAccessControlLayersFilters( layersList, originalLayerFilters );
1266+
applyAccessControlLayersFilters( layersList, filterRestorer->originalFilters() );
12641267
#endif
12651268

12661269
QStringList selectedLayerIdList = applyFeatureSelections( layersList );
12671270

12681271
//GetPrint request needs a template parameter
12691272
if ( !mParameters.contains( "TEMPLATE" ) )
12701273
{
1271-
restoreLayerFilters( originalLayerFilters );
12721274
clearFeatureSelections( selectedLayerIdList );
12731275
throw QgsMapServiceException( "ParameterMissing", "The TEMPLATE parameter is required for the GetPrint request" );
12741276
}
@@ -1284,7 +1286,6 @@ QByteArray* QgsWMSServer::getPrint( const QString& formatString )
12841286
QgsComposition* c = mConfigParser->createPrintComposition( mParameters[ "TEMPLATE" ], mMapRenderer, QMap<QString, QString>( mParameters ) );
12851287
if ( !c )
12861288
{
1287-
restoreLayerFilters( originalLayerFilters );
12881289
clearFeatureSelections( selectedLayerIdList );
12891290
return nullptr;
12901291
}
@@ -1333,7 +1334,6 @@ QByteArray* QgsWMSServer::getPrint( const QString& formatString )
13331334
if ( !tempFile.open() )
13341335
{
13351336
delete c;
1336-
restoreLayerFilters( originalLayerFilters );
13371337
clearFeatureSelections( selectedLayerIdList );
13381338
return nullptr;
13391339
}
@@ -1344,13 +1344,11 @@ QByteArray* QgsWMSServer::getPrint( const QString& formatString )
13441344
}
13451345
else //unknown format
13461346
{
1347-
restoreLayerFilters( originalLayerFilters );
13481347
clearFeatureSelections( selectedLayerIdList );
13491348
throw QgsMapServiceException( "InvalidFormat", "Output format '" + formatString + "' is not supported in the GetPrint request" );
13501349
}
13511350

13521351
restoreOpacities( bkVectorRenderers, bkRasterRenderers, labelTransparencies, labelBufferTransparencies );
1353-
restoreLayerFilters( originalLayerFilters );
13541352
clearFeatureSelections( selectedLayerIdList );
13551353

13561354
delete c;
@@ -1397,10 +1395,14 @@ QImage* QgsWMSServer::getMap( HitTest* hitTest )
13971395
}
13981396
#endif
13991397

1400-
QHash<QgsMapLayer*, QString> originalLayerFilters = applyRequestedLayerFilters( layersList );
1398+
//scoped pointer to restore all original layer filters (subsetStrings) when pointer goes out of scope
1399+
//there's LOTS of potential exit paths here, so we avoid having to restore the filters manually
1400+
QScopedPointer< QgsOWSServerFilterRestorer > filterRestorer( new QgsOWSServerFilterRestorer() );
1401+
1402+
applyRequestedLayerFilters( layersList, filterRestorer->originalFilters() );
14011403

14021404
#ifdef HAVE_SERVER_PYTHON_PLUGINS
1403-
applyAccessControlLayersFilters( layersList, originalLayerFilters );
1405+
applyAccessControlLayersFilters( layersList, filterRestorer->originalFilters() );
14041406
#endif
14051407

14061408
QStringList selectedLayerIdList = applyFeatureSelections( layersList );
@@ -1426,7 +1428,6 @@ QImage* QgsWMSServer::getMap( HitTest* hitTest )
14261428
}
14271429

14281430
restoreOpacities( bkVectorRenderers, bkRasterRenderers, labelTransparencies, labelBufferTransparencies );
1429-
restoreLayerFilters( originalLayerFilters );
14301431
clearFeatureSelections( selectedLayerIdList );
14311432

14321433
// QgsMessageLog::logMessage( "clearing filters" );
@@ -1625,10 +1626,15 @@ int QgsWMSServer::getFeatureInfo( QDomDocument& result, const QString& version )
16251626
}
16261627

16271628
//get the layer registered in QgsMapLayerRegistry and apply possible filters
1628-
QStringList layerIds = layerSet( layersList, stylesList, mMapRenderer->destinationCrs() );
1629-
QHash<QgsMapLayer*, QString> originalLayerFilters = applyRequestedLayerFilters( layersList );
1629+
( void )layerSet( layersList, stylesList, mMapRenderer->destinationCrs() );
1630+
1631+
//scoped pointer to restore all original layer filters (subsetStrings) when pointer goes out of scope
1632+
//there's LOTS of potential exit paths here, so we avoid having to restore the filters manually
1633+
QScopedPointer< QgsOWSServerFilterRestorer > filterRestorer( new QgsOWSServerFilterRestorer() );
1634+
applyRequestedLayerFilters( layersList, filterRestorer->originalFilters() );
1635+
16301636
#ifdef HAVE_SERVER_PYTHON_PLUGINS
1631-
applyAccessControlLayersFilters( layersList, originalLayerFilters );
1637+
applyAccessControlLayersFilters( layersList, filterRestorer->originalFilters() );
16321638
#endif
16331639

16341640
QDomElement getFeatureInfoElement;
@@ -1710,7 +1716,6 @@ int QgsWMSServer::getFeatureInfo( QDomDocument& result, const QString& version )
17101716
#ifdef HAVE_SERVER_PYTHON_PLUGINS
17111717
if ( !mAccessControl->layerReadPermission( currentLayer ) )
17121718
{
1713-
restoreLayerFilters( originalLayerFilters );
17141719
throw QgsMapServiceException( "Security", "You are not allowed to access to the layer: " + currentLayer->name() );
17151720
}
17161721
#endif
@@ -1831,7 +1836,9 @@ int QgsWMSServer::getFeatureInfo( QDomDocument& result, const QString& version )
18311836
convertFeatureInfoToSIA2045( result );
18321837
}
18331838

1834-
restoreLayerFilters( originalLayerFilters );
1839+
//force restoration of original filters
1840+
filterRestorer.reset();
1841+
18351842
QgsMapLayerRegistry::instance()->removeAllMapLayers();
18361843
delete featuresRect;
18371844
return 0;
@@ -2495,13 +2502,11 @@ QStringList QgsWMSServer::layerSet( const QStringList &layersList,
24952502
}
24962503

24972504

2498-
QHash<QgsMapLayer*, QString> QgsWMSServer::applyRequestedLayerFilters( const QStringList& layerList ) const
2505+
void QgsWMSServer::applyRequestedLayerFilters( const QStringList& layerList , QHash<QgsMapLayer*, QString>& originalFilters ) const
24992506
{
2500-
QHash<QgsMapLayer*, QString> filterMap;
2501-
25022507
if ( layerList.isEmpty() )
25032508
{
2504-
return filterMap;
2509+
return;
25052510
}
25062511

25072512
QString filterParameter = mParameters.value( "FILTER" );
@@ -2548,7 +2553,7 @@ QHash<QgsMapLayer*, QString> QgsWMSServer::applyRequestedLayerFilters( const QSt
25482553
QgsVectorLayer* filteredLayer = dynamic_cast<QgsVectorLayer*>( filter );
25492554
if ( filteredLayer )
25502555
{
2551-
filterMap.insert( filteredLayer, filteredLayer->subsetString() );
2556+
originalFilters.insert( filteredLayer, filteredLayer->subsetString() );
25522557
QString newSubsetString = eqSplit.at( 1 );
25532558
if ( !filteredLayer->subsetString().isEmpty() )
25542559
{
@@ -2565,8 +2570,8 @@ QHash<QgsMapLayer*, QString> QgsWMSServer::applyRequestedLayerFilters( const QSt
25652570
if ( mMapRenderer && mMapRenderer->extent().isEmpty() )
25662571
{
25672572
QgsRectangle filterExtent;
2568-
QHash<QgsMapLayer*, QString>::const_iterator filterIt = filterMap.constBegin();
2569-
for ( ; filterIt != filterMap.constEnd(); ++filterIt )
2573+
QHash<QgsMapLayer*, QString>::const_iterator filterIt = originalFilters.constBegin();
2574+
for ( ; filterIt != originalFilters.constEnd(); ++filterIt )
25702575
{
25712576
QgsMapLayer* mapLayer = filterIt.key();
25722577
if ( !mapLayer )
@@ -2587,7 +2592,6 @@ QHash<QgsMapLayer*, QString> QgsWMSServer::applyRequestedLayerFilters( const QSt
25872592
mMapRenderer->setExtent( filterExtent );
25882593
}
25892594
}
2590-
return filterMap;
25912595
}
25922596

25932597
#ifdef HAVE_SERVER_PYTHON_PLUGINS

src/server/qgswmsserver.h

+9-2
Original file line numberDiff line numberDiff line change
@@ -187,15 +187,22 @@ class QgsWMSServer: public QgsOWSServer
187187
#endif
188188

189189
/** Apply filter (subset) strings from the request to the layers. Example: '&FILTER=<layer1>:"AND property > 100",<layer2>:"AND bla = 'hallo!'" '
190-
@return a map with the original filters ( layer id / filter string )*/
191-
QHash<QgsMapLayer*, QString> applyRequestedLayerFilters( const QStringList& layerList ) const;
190+
* @param layerList list of layer IDs to filter
191+
* @param originalFilters hash of layer ID to original filter string
192+
* @note It is strongly recommended that this method be called alongside use of QgsOWSServerFilterRestorer
193+
* to ensure that the original filters are always correctly restored, regardless of whether exceptions
194+
* are thrown or functions are terminated early.
195+
*/
196+
void applyRequestedLayerFilters( const QStringList& layerList, QHash<QgsMapLayer*, QString>& originalFilters ) const;
197+
192198
#ifdef HAVE_SERVER_PYTHON_PLUGINS
193199
/** Apply filter strings from the access control to the layers.
194200
* @param layerList layers to filter
195201
* @param originalLayerFilters the original layers filter dictionary
196202
*/
197203
void applyAccessControlLayersFilters( const QStringList& layerList, QHash<QgsMapLayer*, QString>& originalLayerFilters ) const;
198204
#endif
205+
199206
/** Tests if a filter sql string is allowed (safe)
200207
@return true in case of success, false if string seems unsafe*/
201208
bool testFilterStringSafety( const QString& filter ) const;

0 commit comments

Comments
 (0)