mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-12 00:06:43 -04:00
[FEATURE][needs-docs] Add OGC filters to WMS
Implement https://github.com/qgis/QGIS-Enhancement-Proposals/issues/104
This commit is contained in:
parent
d31f60baa5
commit
b8f708ff1b
60
python/server/qgsfeaturefilter.sip
Normal file
60
python/server/qgsfeaturefilter.sip
Normal file
@ -0,0 +1,60 @@
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/server/qgsfeaturefilter.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class QgsFeatureFilter : QgsFeatureFilterProvider
|
||||
{
|
||||
%Docstring
|
||||
A feature filter provider allowing to set filter expressions on a per-layer basis.
|
||||
.. versionadded:: 3.0
|
||||
*
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsfeaturefilter.h"
|
||||
%End
|
||||
public:
|
||||
QgsFeatureFilter();
|
||||
%Docstring
|
||||
Constructor
|
||||
%End
|
||||
|
||||
void filterFeatures( const QgsVectorLayer *layer, QgsFeatureRequest &filterFeatures ) const;
|
||||
%Docstring
|
||||
Filter the features of the layer
|
||||
\param layer the layer to control
|
||||
\param filterFeatures the request to fill
|
||||
%End
|
||||
|
||||
QgsFeatureFilterProvider *clone() const /Factory/;
|
||||
%Docstring
|
||||
Return a clone of the object
|
||||
:return: A clone
|
||||
:rtype: QgsFeatureFilterProvider
|
||||
%End
|
||||
|
||||
void setFilter( const QgsVectorLayer *layer, const QgsExpression &expression );
|
||||
%Docstring
|
||||
Set a filter for the given layer.
|
||||
\param layer the layer to filter
|
||||
\param expression the filter expression
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/server/qgsfeaturefilter.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
60
python/server/qgsfeaturefilterprovidergroup.sip
Normal file
60
python/server/qgsfeaturefilterprovidergroup.sip
Normal file
@ -0,0 +1,60 @@
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/server/qgsfeaturefilterprovidergroup.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class QgsFeatureFilterProviderGroup : QgsFeatureFilterProvider
|
||||
{
|
||||
%Docstring
|
||||
A filter filter provider grouping several filter providers.
|
||||
.. versionadded:: 3.0
|
||||
*
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsfeaturefilterprovidergroup.h"
|
||||
%End
|
||||
public:
|
||||
QgsFeatureFilterProviderGroup();
|
||||
%Docstring
|
||||
Constructor
|
||||
%End
|
||||
|
||||
void filterFeatures( const QgsVectorLayer *layer, QgsFeatureRequest &filterFeatures ) const;
|
||||
%Docstring
|
||||
Filter the features of the layer
|
||||
\param layer the layer to control
|
||||
\param filterFeatures the request to fill
|
||||
%End
|
||||
|
||||
QgsFeatureFilterProvider *clone() const /Factory/;
|
||||
%Docstring
|
||||
Return a clone of the object
|
||||
:return: A clone
|
||||
:rtype: QgsFeatureFilterProvider
|
||||
%End
|
||||
|
||||
QgsFeatureFilterProviderGroup &addProvider( const QgsFeatureFilterProvider *provider );
|
||||
%Docstring
|
||||
Add another filter provider to the group
|
||||
\param provider The provider to add
|
||||
:return: itself
|
||||
:rtype: QgsFeatureFilterProviderGroup
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/server/qgsfeaturefilterprovidergroup.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
@ -17,6 +17,8 @@
|
||||
%Include qgsservice.sip
|
||||
%Include qgsservicemodule.sip
|
||||
%Include qgsserviceregistry.sip
|
||||
%Include qgsfeaturefilterprovidergroup.sip
|
||||
%Include qgsfeaturefilter.sip
|
||||
%If ( HAVE_SERVER_PYTHON_PLUGINS )
|
||||
%Include qgsserverfilter.sip
|
||||
%End
|
||||
|
@ -428,7 +428,7 @@ class CORE_EXPORT QgsFeatureRequest
|
||||
*
|
||||
* \since QGIS 2.12
|
||||
*/
|
||||
QgsFeatureRequest &disableFilter() { mFilter = FilterNone; return *this; }
|
||||
QgsFeatureRequest &disableFilter() { mFilter = FilterNone; mFilterExpression.reset(); return *this; }
|
||||
|
||||
/**
|
||||
* Adds a new OrderByClause, appending it as the least important one.
|
||||
|
@ -44,6 +44,8 @@ SET(QGIS_SERVER_SRCS
|
||||
qgsservicemodule.cpp
|
||||
qgsservicenativeloader.cpp
|
||||
qgsserviceregistry.cpp
|
||||
qgsfeaturefilterprovidergroup.cpp
|
||||
qgsfeaturefilter.cpp
|
||||
)
|
||||
|
||||
SET (QGIS_SERVER_HDRS
|
||||
|
42
src/server/qgsfeaturefilter.cpp
Normal file
42
src/server/qgsfeaturefilter.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
/***************************************************************************
|
||||
qgsfeaturefilter.cpp
|
||||
--------------------
|
||||
begin : 26-10-2017
|
||||
copyright : (C) 2017 by Patrick Valsecchi
|
||||
email : patrick dot valsecchi at camptocamp dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsfeaturefilter.h"
|
||||
#include "qgsfeaturerequest.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsexpression.h"
|
||||
|
||||
void QgsFeatureFilter::filterFeatures( const QgsVectorLayer *layer, QgsFeatureRequest &filterFeatures ) const
|
||||
{
|
||||
const QString expr = mFilters[layer->id()];
|
||||
if ( !expr.isEmpty() )
|
||||
{
|
||||
filterFeatures.setFilterExpression( expr );
|
||||
}
|
||||
}
|
||||
|
||||
QgsFeatureFilterProvider *QgsFeatureFilter::clone() const
|
||||
{
|
||||
auto result = new QgsFeatureFilter();
|
||||
result->mFilters = mFilters;
|
||||
return result;
|
||||
}
|
||||
|
||||
void QgsFeatureFilter::setFilter( const QgsVectorLayer *layer, const QgsExpression &filter )
|
||||
{
|
||||
mFilters[layer->id()] = filter.dump();
|
||||
}
|
64
src/server/qgsfeaturefilter.h
Normal file
64
src/server/qgsfeaturefilter.h
Normal file
@ -0,0 +1,64 @@
|
||||
/***************************************************************************
|
||||
qgsfeaturefilter.h
|
||||
------------------
|
||||
begin : 26-10-2017
|
||||
copyright : (C) 2017 by Patrick Valsecchi
|
||||
email : patrick dot valsecchi at camptocamp dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSFEATUREFILTER_H
|
||||
#define QGSFEATUREFILTER_H
|
||||
|
||||
#include "qgsfeaturefilterprovider.h"
|
||||
#include "qgis_server.h"
|
||||
|
||||
#include <QMap>
|
||||
|
||||
class QgsExpression;
|
||||
|
||||
/**
|
||||
* \ingroup server
|
||||
* \class QgsFeatureFilter
|
||||
* \brief A feature filter provider allowing to set filter expressions on a per-layer basis.
|
||||
* \since QGIS 3.0
|
||||
**/
|
||||
class SERVER_EXPORT QgsFeatureFilter : public QgsFeatureFilterProvider
|
||||
{
|
||||
public:
|
||||
//! Constructor
|
||||
QgsFeatureFilter() {}
|
||||
|
||||
/**
|
||||
* Filter the features of the layer
|
||||
* \param layer the layer to control
|
||||
* \param filterFeatures the request to fill
|
||||
*/
|
||||
void filterFeatures( const QgsVectorLayer *layer, QgsFeatureRequest &filterFeatures ) const;
|
||||
|
||||
/**
|
||||
* Return a clone of the object
|
||||
* \returns A clone
|
||||
*/
|
||||
QgsFeatureFilterProvider *clone() const SIP_FACTORY;
|
||||
|
||||
/**
|
||||
* Set a filter for the given layer.
|
||||
* \param layer the layer to filter
|
||||
* \param expression the filter expression
|
||||
*/
|
||||
void setFilter( const QgsVectorLayer *layer, const QgsExpression &expression );
|
||||
|
||||
private:
|
||||
QMap<QString, QString> mFilters;
|
||||
};
|
||||
|
||||
#endif
|
49
src/server/qgsfeaturefilterprovidergroup.cpp
Normal file
49
src/server/qgsfeaturefilterprovidergroup.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
/***************************************************************************
|
||||
qgsfeaturefilterprovidergroup.cpp
|
||||
--------------------------------
|
||||
begin : 26-10-2017
|
||||
copyright : (C) 2017 by Patrick Valsecchi
|
||||
email : patrick dot valsecchi at camptocamp dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsfeaturefilterprovidergroup.h"
|
||||
#include "qgsfeaturerequest.h"
|
||||
|
||||
void QgsFeatureFilterProviderGroup::filterFeatures( const QgsVectorLayer *layer, QgsFeatureRequest &filterFeatures ) const
|
||||
{
|
||||
filterFeatures.disableFilter();
|
||||
for ( const QgsFeatureFilterProvider *provider : mProviders )
|
||||
{
|
||||
QgsFeatureRequest temp;
|
||||
provider->filterFeatures( layer, temp );
|
||||
if ( temp.filterExpression() )
|
||||
{
|
||||
filterFeatures.combineFilterExpression( temp.filterExpression()->dump() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QgsFeatureFilterProvider *QgsFeatureFilterProviderGroup::clone() const
|
||||
{
|
||||
auto result = new QgsFeatureFilterProviderGroup();
|
||||
result->mProviders = mProviders;
|
||||
return result;
|
||||
}
|
||||
|
||||
QgsFeatureFilterProviderGroup &QgsFeatureFilterProviderGroup::addProvider( const QgsFeatureFilterProvider *provider )
|
||||
{
|
||||
if ( provider )
|
||||
{
|
||||
mProviders.append( provider );
|
||||
}
|
||||
return *this;
|
||||
}
|
62
src/server/qgsfeaturefilterprovidergroup.h
Normal file
62
src/server/qgsfeaturefilterprovidergroup.h
Normal file
@ -0,0 +1,62 @@
|
||||
/***************************************************************************
|
||||
qgsfeaturefilterprovidergroup.h
|
||||
-------------------------------
|
||||
begin : 26-10-2017
|
||||
copyright : (C) 2017 by Patrick Valsecchi
|
||||
email : patrick dot valsecchi at camptocamp dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSFEATUREFILTERPROVIDERGROUP_H
|
||||
#define QGSFEATUREFILTERPROVIDERGROUP_H
|
||||
|
||||
#include "qgsfeaturefilterprovider.h"
|
||||
#include "qgis_server.h"
|
||||
|
||||
#include <QList>
|
||||
|
||||
/**
|
||||
* \ingroup server
|
||||
* \class QgsFeatureFilterProviderGroup
|
||||
* \brief A filter filter provider grouping several filter providers.
|
||||
* \since QGIS 3.0
|
||||
**/
|
||||
class SERVER_EXPORT QgsFeatureFilterProviderGroup : public QgsFeatureFilterProvider
|
||||
{
|
||||
public:
|
||||
//! Constructor
|
||||
QgsFeatureFilterProviderGroup() {}
|
||||
|
||||
/**
|
||||
* Filter the features of the layer
|
||||
* \param layer the layer to control
|
||||
* \param filterFeatures the request to fill
|
||||
*/
|
||||
void filterFeatures( const QgsVectorLayer *layer, QgsFeatureRequest &filterFeatures ) const;
|
||||
|
||||
/**
|
||||
* Return a clone of the object
|
||||
* \returns A clone
|
||||
*/
|
||||
QgsFeatureFilterProvider *clone() const SIP_FACTORY;
|
||||
|
||||
/**
|
||||
* Add another filter provider to the group
|
||||
* \param provider The provider to add
|
||||
* \return itself
|
||||
*/
|
||||
QgsFeatureFilterProviderGroup &addProvider( const QgsFeatureFilterProvider *provider );
|
||||
|
||||
private:
|
||||
QList<const QgsFeatureFilterProvider *> mProviders;
|
||||
};
|
||||
|
||||
#endif
|
@ -27,14 +27,14 @@ namespace QgsWms
|
||||
QgsMapRendererJobProxy::QgsMapRendererJobProxy(
|
||||
bool parallelRendering
|
||||
, int maxThreads
|
||||
, QgsAccessControl *accessControl
|
||||
, QgsFeatureFilterProvider *featureFilterProvider
|
||||
)
|
||||
:
|
||||
mParallelRendering( parallelRendering )
|
||||
, mAccessControl( accessControl )
|
||||
, mFeatureFilterProvider( featureFilterProvider )
|
||||
{
|
||||
#ifndef HAVE_SERVER_PYTHON_PLUGINS
|
||||
Q_UNUSED( mAccessControl );
|
||||
Q_UNUSED( mFeatureFilterProvider );
|
||||
#endif
|
||||
if ( mParallelRendering )
|
||||
{
|
||||
@ -53,7 +53,7 @@ namespace QgsWms
|
||||
{
|
||||
QgsMapRendererParallelJob renderJob( mapSettings );
|
||||
#ifdef HAVE_SERVER_PYTHON_PLUGINS
|
||||
renderJob.setFeatureFilterProvider( mAccessControl );
|
||||
renderJob.setFeatureFilterProvider( mFeatureFilterProvider );
|
||||
#endif
|
||||
renderJob.start();
|
||||
renderJob.waitForFinished();
|
||||
@ -65,7 +65,7 @@ namespace QgsWms
|
||||
mPainter.reset( new QPainter( image ) );
|
||||
QgsMapRendererCustomPainterJob renderJob( mapSettings, mPainter.get() );
|
||||
#ifdef HAVE_SERVER_PYTHON_PLUGINS
|
||||
renderJob.setFeatureFilterProvider( mAccessControl );
|
||||
renderJob.setFeatureFilterProvider( mFeatureFilterProvider );
|
||||
#endif
|
||||
renderJob.renderSynchronously();
|
||||
}
|
||||
|
@ -19,7 +19,8 @@
|
||||
#define QGSMAPRENDERERJOBPROXY_H
|
||||
|
||||
#include "qgsmapsettings.h"
|
||||
#include "qgsaccesscontrol.h"
|
||||
|
||||
class QgsFeatureFilterProvider;
|
||||
|
||||
namespace QgsWms
|
||||
{
|
||||
@ -36,12 +37,12 @@ namespace QgsWms
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* \param accessControl Does not take ownership of QgsAccessControl
|
||||
* \param featureFilterProvider Does not take ownership of QgsFeatureFilterProvider
|
||||
*/
|
||||
QgsMapRendererJobProxy(
|
||||
bool parallelRendering
|
||||
, int maxThreads
|
||||
, QgsAccessControl *accessControl
|
||||
, QgsFeatureFilterProvider *featureFilterProvider
|
||||
);
|
||||
|
||||
/**
|
||||
@ -59,7 +60,7 @@ namespace QgsWms
|
||||
|
||||
private:
|
||||
bool mParallelRendering;
|
||||
QgsAccessControl *mAccessControl = nullptr;
|
||||
QgsFeatureFilterProvider *mFeatureFilterProvider = nullptr;
|
||||
std::unique_ptr<QPainter> mPainter;
|
||||
};
|
||||
|
||||
|
@ -488,7 +488,7 @@ namespace QgsWms
|
||||
mRequestParameters = parameters;
|
||||
|
||||
const QMetaEnum metaEnum( QMetaEnum::fromType<ParameterName>() );
|
||||
static QRegExp composerParamRegExp( "^MAP\\d+:" );
|
||||
static QRegExp composerParamRegExp( QStringLiteral( "^MAP\\d+:" ) );
|
||||
|
||||
foreach ( QString key, parameters.keys() )
|
||||
{
|
||||
@ -529,7 +529,7 @@ namespace QgsWms
|
||||
}
|
||||
else //maybe an external wms parameter?
|
||||
{
|
||||
int separator = key.indexOf( ":" );
|
||||
int separator = key.indexOf( QStringLiteral( ":" ) );
|
||||
if ( separator >= 1 )
|
||||
{
|
||||
QString id = key.left( separator );
|
||||
@ -545,7 +545,7 @@ namespace QgsWms
|
||||
{
|
||||
const QMetaEnum metaEnum( QMetaEnum::fromType<ParameterName>() );
|
||||
|
||||
log( "WMS Request parameters:" );
|
||||
log( QStringLiteral( "WMS Request parameters:" ) );
|
||||
for ( auto parameter : mParameters.toStdMap() )
|
||||
{
|
||||
const QString value = parameter.second.mValue.toString();
|
||||
@ -553,13 +553,13 @@ namespace QgsWms
|
||||
if ( ! value.isEmpty() )
|
||||
{
|
||||
const QString name = metaEnum.valueToKey( parameter.first );
|
||||
log( " - " + name + " : " + value );
|
||||
log( QStringLiteral( " - " ) + name + QStringLiteral( " : " ) + value );
|
||||
}
|
||||
}
|
||||
for ( auto map : mComposerParameters.toStdMap() )
|
||||
{
|
||||
const int mapId = map.first;
|
||||
log( " - MAP" + QString::number( mapId ) );
|
||||
log( QStringLiteral( " - MAP" ) + QString::number( mapId ) );
|
||||
for ( auto param : mComposerParameters[map.first].toStdMap() )
|
||||
{
|
||||
const QString value = param.second.mValue.toString();
|
||||
@ -567,13 +567,13 @@ namespace QgsWms
|
||||
if ( ! value.isEmpty() )
|
||||
{
|
||||
const QString name = metaEnum.valueToKey( param.first );
|
||||
log( " - MAP" + QString::number( mapId ) + ":" + name + " : " + value );
|
||||
log( QStringLiteral( " - MAP" ) + QString::number( mapId ) + QStringLiteral( ":" ) + name + QStringLiteral( " : " ) + value );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( !version().isEmpty() )
|
||||
log( " - VERSION : " + version() );
|
||||
log( QStringLiteral( " - VERSION : " ) + version() );
|
||||
}
|
||||
|
||||
void QgsWmsParameters::save( const Parameter ¶meter )
|
||||
@ -694,8 +694,8 @@ namespace QgsWms
|
||||
{
|
||||
// VERSION parameter is not managed with other parameters because
|
||||
// there's a conflict with qgis VERSION defined in qgsconfig.h
|
||||
if ( mRequestParameters.contains( "VERSION" ) )
|
||||
return mRequestParameters["VERSION"];
|
||||
if ( mRequestParameters.contains( QStringLiteral( "VERSION" ) ) )
|
||||
return mRequestParameters[QStringLiteral( "VERSION" )];
|
||||
else
|
||||
return QString();
|
||||
}
|
||||
@ -736,7 +736,7 @@ namespace QgsWms
|
||||
{
|
||||
QString n = name( p );
|
||||
QString valStr = value( p ).toString();
|
||||
QString msg = n + " ('" + valStr + "') cannot be converted into a double";
|
||||
QString msg = n + QStringLiteral( " ('" ) + valStr + QStringLiteral( "') cannot be converted into a double" );
|
||||
raiseError( msg );
|
||||
}
|
||||
|
||||
@ -751,7 +751,8 @@ namespace QgsWms
|
||||
{
|
||||
QString n = name( p );
|
||||
QString valStr = value( p, mapId ).toString();
|
||||
QString msg = "MAP" + QString::number( mapId ) + ":" + n + " ('" + valStr + "') cannot be converted into a double";
|
||||
QString msg = QStringLiteral( "MAP" ) + QString::number( mapId ) + QStringLiteral( ":" ) + n +
|
||||
QStringLiteral( " ('" ) + valStr + QStringLiteral( "') cannot be converted into a double" );
|
||||
raiseError( msg );
|
||||
}
|
||||
|
||||
@ -802,7 +803,7 @@ namespace QgsWms
|
||||
{
|
||||
QString n = name( p );
|
||||
QString valStr = value( p ).toString();
|
||||
QString msg = n + " ('" + valStr + "') cannot be converted into int";
|
||||
QString msg = n + QStringLiteral( " ('" ) + valStr + QStringLiteral( "') cannot be converted into int" );
|
||||
raiseError( msg );
|
||||
}
|
||||
|
||||
@ -817,7 +818,8 @@ namespace QgsWms
|
||||
{
|
||||
QString n = name( p );
|
||||
QString valStr = value( p, mapId ).toString();
|
||||
QString msg = "MAP" + QString::number( mapId ) + ":" + n + " ('" + valStr + "') cannot be converted into int";
|
||||
QString msg = QStringLiteral( "MAP" ) + QString::number( mapId ) + QStringLiteral( ":" ) + n +
|
||||
QStringLiteral( " ('" ) + valStr + QStringLiteral( "') cannot be converted into int" );
|
||||
raiseError( msg );
|
||||
}
|
||||
|
||||
@ -833,8 +835,8 @@ namespace QgsWms
|
||||
if ( !cStr.isEmpty() )
|
||||
{
|
||||
// support hexadecimal notation to define colors
|
||||
if ( cStr.startsWith( "0x", Qt::CaseInsensitive ) )
|
||||
cStr.replace( 0, 2, "#" );
|
||||
if ( cStr.startsWith( QStringLiteral( "0x" ), Qt::CaseInsensitive ) )
|
||||
cStr.replace( 0, 2, QStringLiteral( "#" ) );
|
||||
|
||||
c = QColor( cStr );
|
||||
|
||||
@ -852,7 +854,7 @@ namespace QgsWms
|
||||
{
|
||||
QString n = name( p );
|
||||
QString valStr = value( p ).toString();
|
||||
QString msg = n + " ('" + valStr + "') cannot be converted into a color";
|
||||
QString msg = n + QStringLiteral( " ('" ) + valStr + QStringLiteral( "') cannot be converted into a color" );
|
||||
raiseError( msg );
|
||||
}
|
||||
|
||||
@ -867,7 +869,8 @@ namespace QgsWms
|
||||
{
|
||||
QString n = name( p );
|
||||
QString valStr = value( p, mapId ).toString();
|
||||
QString msg = "MAP" + QString::number( mapId ) + ":" + n + " ('" + valStr + "') cannot be converted into a color";
|
||||
QString msg = QStringLiteral( "MAP" ) + QString::number( mapId ) + QStringLiteral( ":" ) + n +
|
||||
QStringLiteral( " ('" ) + valStr + QStringLiteral( "') cannot be converted into a color" );
|
||||
raiseError( msg );
|
||||
}
|
||||
|
||||
@ -926,7 +929,7 @@ namespace QgsWms
|
||||
{
|
||||
QString n = name( p );
|
||||
QString valStr = value( p ).toString();
|
||||
QString msg = n + " ('" + valStr + "') cannot be converted into a rectangle";
|
||||
QString msg = n + QStringLiteral( " ('" ) + valStr + QStringLiteral( "') cannot be converted into a rectangle" );
|
||||
raiseError( msg );
|
||||
}
|
||||
|
||||
@ -941,7 +944,8 @@ namespace QgsWms
|
||||
{
|
||||
QString n = name( p );
|
||||
QString valStr = value( p, mapId ).toString();
|
||||
QString msg = "MAP" + QString::number( mapId ) + ":" + n + " ('" + valStr + "') cannot be converted into a rectangle";
|
||||
QString msg = QStringLiteral( "MAP" ) + QString::number( mapId ) + QStringLiteral( ":" ) + n +
|
||||
QStringLiteral( " ('" ) + valStr + QStringLiteral( "') cannot be converted into a rectangle" );
|
||||
raiseError( msg );
|
||||
}
|
||||
|
||||
@ -990,7 +994,7 @@ namespace QgsWms
|
||||
{
|
||||
QString n = name( p );
|
||||
QString valStr = value( p ).toString();
|
||||
QString msg = n + " ('" + valStr + "') cannot be converted into a list of int";
|
||||
QString msg = n + QStringLiteral( " ('" ) + valStr + QStringLiteral( "') cannot be converted into a list of int" );
|
||||
raiseError( msg );
|
||||
}
|
||||
|
||||
@ -1005,7 +1009,8 @@ namespace QgsWms
|
||||
{
|
||||
QString n = name( p );
|
||||
QString valStr = value( p, mapId ).toString();
|
||||
QString msg = "MAP" + QString::number( mapId ) + ":" + n + " ('" + valStr + "') cannot be converted into a list of int";
|
||||
QString msg = QStringLiteral( "MAP" ) + QString::number( mapId ) + QStringLiteral( ":" ) + n +
|
||||
QStringLiteral( " ('" ) + valStr + QStringLiteral( "') cannot be converted into a list of int" );
|
||||
raiseError( msg );
|
||||
}
|
||||
|
||||
@ -1044,7 +1049,8 @@ namespace QgsWms
|
||||
{
|
||||
QString n = name( p );
|
||||
QString valStr = value( p ).toString();
|
||||
QString msg = n + " ('" + valStr + "') cannot be converted into a list of float";
|
||||
QString msg = n + QStringLiteral( " ('" ) + valStr +
|
||||
QStringLiteral( "') cannot be converted into a list of float" );
|
||||
raiseError( msg );
|
||||
}
|
||||
|
||||
@ -1059,7 +1065,8 @@ namespace QgsWms
|
||||
{
|
||||
QString n = name( p );
|
||||
QString valStr = value( p ).toString();
|
||||
QString msg = "MAP" + QString::number( mapId ) + ":" + n + " ('" + valStr + "') cannot be converted into a list of float";
|
||||
QString msg = QStringLiteral( "MAP" ) + QString::number( mapId ) + QStringLiteral( ":" ) + n +
|
||||
QStringLiteral( " ('" ) + valStr + QStringLiteral( "') cannot be converted into a list of float" );
|
||||
raiseError( msg );
|
||||
}
|
||||
|
||||
@ -1097,7 +1104,8 @@ namespace QgsWms
|
||||
{
|
||||
QString n = name( p );
|
||||
QString valStr = value( p ).toString();
|
||||
QString msg = n + " ('" + valStr + "') cannot be converted into a list of colors";
|
||||
QString msg = n + QStringLiteral( " ('" ) + valStr +
|
||||
QStringLiteral( "') cannot be converted into a list of colors" );
|
||||
raiseError( msg );
|
||||
}
|
||||
|
||||
@ -1112,7 +1120,8 @@ namespace QgsWms
|
||||
{
|
||||
QString n = name( p );
|
||||
QString valStr = value( p ).toString();
|
||||
QString msg = "MAP" + QString::number( mapId ) + ":" + n + " ('" + valStr + "') cannot be converted into a list of colors";
|
||||
QString msg = QStringLiteral( "MAP" ) + QString::number( mapId ) + QStringLiteral( ":" ) + n +
|
||||
QStringLiteral( " ('" ) + valStr + QStringLiteral( "') cannot be converted into a list of colors" );
|
||||
raiseError( msg );
|
||||
}
|
||||
|
||||
@ -1150,7 +1159,8 @@ namespace QgsWms
|
||||
{
|
||||
QString n = name( p );
|
||||
QString valStr = value( p ).toString();
|
||||
QString msg = n + " ('" + valStr + "') cannot be converted into a list of geometries";
|
||||
QString msg = n + QStringLiteral( " ('" ) + valStr +
|
||||
QStringLiteral( "') cannot be converted into a list of geometries" );
|
||||
raiseError( msg );
|
||||
}
|
||||
|
||||
@ -1165,7 +1175,8 @@ namespace QgsWms
|
||||
{
|
||||
QString n = name( p );
|
||||
QString valStr = value( p, mapId ).toString();
|
||||
QString msg = "MAP" + QString::number( mapId ) + ":" + n + " ('" + valStr + "') cannot be converted into a list of geometries";
|
||||
QString msg = QStringLiteral( "MAP" ) + QString::number( mapId ) + QStringLiteral( ":" ) + n +
|
||||
QStringLiteral( " ('" ) + valStr + QStringLiteral( "') cannot be converted into a list of geometries" );
|
||||
raiseError( msg );
|
||||
}
|
||||
|
||||
@ -1614,7 +1625,30 @@ namespace QgsWms
|
||||
|
||||
QStringList QgsWmsParameters::filters() const
|
||||
{
|
||||
return toStringList( ParameterName::FILTER, ';' );
|
||||
const QString filter = value( ParameterName::FILTER ).toString();
|
||||
if ( filter.startsWith( QStringLiteral( "(<" ) ) && filter.endsWith( QStringLiteral( "Filter>)" ) ) )
|
||||
{
|
||||
// OGC filter on multiple layers
|
||||
// remove the "(<" at the beginning and the "Filter>)" at the end
|
||||
const QString toSplit = filter.mid( 2, filter.length() - 10 );
|
||||
|
||||
QStringList result;
|
||||
for ( const QString &cur : toSplit.split( QStringLiteral( "Filter>)(<" ), QString::SkipEmptyParts ) )
|
||||
{
|
||||
result.append( QStringLiteral( "<" ) + cur + QStringLiteral( "Filter>" ) );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else if ( filter.startsWith( QStringLiteral( "<" ) ) && filter.endsWith( QStringLiteral( "Filter>" ) ) )
|
||||
{
|
||||
// single OGC filter
|
||||
return QStringList( filter );
|
||||
}
|
||||
else
|
||||
{
|
||||
// QGIS specific filter
|
||||
return filter.split( ';', QString::SkipEmptyParts );
|
||||
}
|
||||
}
|
||||
|
||||
QString QgsWmsParameters::filterGeom() const
|
||||
@ -1656,36 +1690,48 @@ namespace QgsWms
|
||||
return style << styles;
|
||||
}
|
||||
|
||||
QList<QgsWmsParametersLayer> QgsWmsParameters::layersParameters() const
|
||||
QMultiMap<QString, QString> QgsWmsParameters::getLayerFilters( const QStringList &layers ) const
|
||||
{
|
||||
QList<QgsWmsParametersLayer> parameters;
|
||||
QStringList layers = allLayersNickname();
|
||||
QStringList styles = allStyles();
|
||||
QStringList filter = filters();
|
||||
QStringList selection = selections();
|
||||
QList<int> opacities = opacitiesAsInt();
|
||||
|
||||
// filter format: "LayerName:filterString;LayerName2:filterString2;..."
|
||||
// several filters can be defined for one layer
|
||||
const QStringList rawFilters = filters();
|
||||
QMultiMap<QString, QString> layerFilters;
|
||||
Q_FOREACH ( QString f, filter )
|
||||
for ( int i = 0; i < rawFilters.size(); i++ )
|
||||
{
|
||||
const QStringList splits = f.split( ':' );
|
||||
if ( splits.size() == 2 )
|
||||
const QString f = rawFilters[i];
|
||||
if ( f.startsWith( QStringLiteral( "<" ) ) && f.endsWith( QStringLiteral( "Filter>" ) ) && i < layers.size() )
|
||||
{
|
||||
layerFilters.insert( splits[0], splits[1] );
|
||||
layerFilters.insert( layers[i], f );
|
||||
}
|
||||
else
|
||||
{
|
||||
QString filterStr = value( ParameterName::FILTER ).toString();
|
||||
raiseError( "FILTER ('" + filterStr + "') is not properly formatted" );
|
||||
const QStringList splits = f.split( ':' );
|
||||
if ( splits.size() == 2 )
|
||||
{
|
||||
layerFilters.insert( splits[0], splits[1] );
|
||||
}
|
||||
else
|
||||
{
|
||||
QString filterStr = value( ParameterName::FILTER ).toString();
|
||||
raiseError( QStringLiteral( "FILTER ('" ) + filterStr + QStringLiteral( "') is not properly formatted" ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
return layerFilters;
|
||||
}
|
||||
|
||||
QList<QgsWmsParametersLayer> QgsWmsParameters::layersParameters() const
|
||||
{
|
||||
const QStringList layers = allLayersNickname();
|
||||
const QStringList styles = allStyles();
|
||||
const QStringList selection = selections();
|
||||
const QList<int> opacities = opacitiesAsInt();
|
||||
const QMultiMap<QString, QString> layerFilters = getLayerFilters( layers );
|
||||
|
||||
// selection format: "LayerName:id0,id1;LayerName2:id0,id1;..."
|
||||
// several filters can be defined for one layer
|
||||
QMultiMap<QString, QString> layerSelections;
|
||||
Q_FOREACH ( QString s, selection )
|
||||
for ( const QString &s : selection )
|
||||
{
|
||||
const QStringList splits = s.split( ':' );
|
||||
if ( splits.size() == 2 )
|
||||
@ -1695,10 +1741,11 @@ namespace QgsWms
|
||||
else
|
||||
{
|
||||
QString selStr = value( ParameterName::SELECTION ).toString();
|
||||
raiseError( "SELECTION ('" + selStr + "') is not properly formatted" );
|
||||
raiseError( QStringLiteral( "SELECTION ('" ) + selStr + QStringLiteral( "') is not properly formatted" ) );
|
||||
}
|
||||
}
|
||||
|
||||
QList<QgsWmsParametersLayer> parameters;
|
||||
for ( int i = 0; i < layers.size(); i++ )
|
||||
{
|
||||
QString layer = layers[i];
|
||||
@ -1756,7 +1803,7 @@ namespace QgsWms
|
||||
for ( int i = 0; i < nLayers; i++ )
|
||||
{
|
||||
QgsWmsParametersHighlightLayer param;
|
||||
param.mName = "highlight_" + QString::number( i );
|
||||
param.mName = QStringLiteral( "highlight_" ) + QString::number( i );
|
||||
param.mGeom = geoms[i];
|
||||
param.mSld = slds[i];
|
||||
|
||||
@ -1812,7 +1859,7 @@ namespace QgsWms
|
||||
if ( extentStr.isEmpty() )
|
||||
return param;
|
||||
|
||||
QString pMapId = "MAP" + QString::number( mapId );
|
||||
QString pMapId = QStringLiteral( "MAP" ) + QString::number( mapId );
|
||||
|
||||
QgsRectangle extent = toRectangle( ParameterName::EXTENT, mapId );
|
||||
if ( extent.isEmpty() )
|
||||
@ -1873,7 +1920,7 @@ namespace QgsWms
|
||||
for ( int i = 0; i < nHLayers; i++ )
|
||||
{
|
||||
QgsWmsParametersHighlightLayer hParam;
|
||||
hParam.mName = pMapId + "_highlight_" + QString::number( i );
|
||||
hParam.mName = pMapId + QStringLiteral( "_highlight_" ) + QString::number( i );
|
||||
hParam.mGeom = geoms[i];
|
||||
hParam.mSld = slds[i];
|
||||
|
||||
@ -1940,7 +1987,7 @@ namespace QgsWms
|
||||
|
||||
void QgsWmsParameters::log( const QString &msg ) const
|
||||
{
|
||||
QgsMessageLog::logMessage( msg, "Server", QgsMessageLog::INFO );
|
||||
QgsMessageLog::logMessage( msg, QStringLiteral( "Server" ), QgsMessageLog::INFO );
|
||||
}
|
||||
|
||||
void QgsWmsParameters::raiseError( ParameterName paramName ) const
|
||||
@ -1948,7 +1995,7 @@ namespace QgsWms
|
||||
const QString value = mParameters[paramName].mValue.toString();
|
||||
const QString param = name( paramName );
|
||||
const QString type = QVariant::typeToName( mParameters[paramName].mType );
|
||||
raiseError( param + " ('" + value + "') cannot be converted into " + type );
|
||||
raiseError( param + QStringLiteral( " ('" ) + value + QStringLiteral( "') cannot be converted into " ) + type );
|
||||
}
|
||||
|
||||
void QgsWmsParameters::raiseError( ParameterName paramName, int mapId ) const
|
||||
@ -1956,7 +2003,9 @@ namespace QgsWms
|
||||
const QString value = mComposerParameters[mapId][paramName].mValue.toString();
|
||||
const QString param = name( paramName );
|
||||
const QString type = QVariant::typeToName( mComposerParameters[mapId][paramName].mType );
|
||||
raiseError( "MAP" + QString::number( mapId ) + ":" + param + " ('" + value + "') cannot be converted into " + type );
|
||||
raiseError( QStringLiteral( "MAP" ) + QString::number( mapId ) + QStringLiteral( ":" ) +
|
||||
param + QStringLiteral( " ('" ) + value +
|
||||
QStringLiteral( "') cannot be converted into " ) + type );
|
||||
}
|
||||
|
||||
void QgsWmsParameters::raiseError( const QString &msg ) const
|
||||
|
@ -972,6 +972,7 @@ namespace QgsWms
|
||||
QList<QgsGeometry> toGeomList( const QStringList &l, bool *error = Q_NULLPTR ) const;
|
||||
QList<QgsGeometry> toGeomList( const QStringList &l, ParameterName name ) const;
|
||||
QList<QgsGeometry> toGeomList( const QStringList &l, ParameterName name, int mapId ) const;
|
||||
QMultiMap<QString, QString> getLayerFilters( const QStringList &layers ) const;
|
||||
|
||||
QgsServerRequest::Parameters mRequestParameters;
|
||||
QMap<ParameterName, Parameter> mParameters;
|
||||
|
@ -89,6 +89,8 @@
|
||||
#include "qgscomposerpicture.h"
|
||||
#include "qgscomposerscalebar.h"
|
||||
#include "qgscomposershape.h"
|
||||
#include "qgsfeaturefilterprovidergroup.h"
|
||||
#include "qgsogcutils.h"
|
||||
#include <QBuffer>
|
||||
#include <QPrinter>
|
||||
#include <QSvgGenerator>
|
||||
@ -919,21 +921,10 @@ namespace QgsWms
|
||||
}
|
||||
|
||||
// The I/J parameters are Mandatory if they are not replaced by X/Y or FILTER or FILTER_GEOM
|
||||
bool ijDefined = false;
|
||||
if ( !mWmsParameters.i().isEmpty() && !mWmsParameters.j().isEmpty() )
|
||||
ijDefined = true;
|
||||
|
||||
bool xyDefined = false;
|
||||
if ( !mWmsParameters.x().isEmpty() && !mWmsParameters.y().isEmpty() )
|
||||
xyDefined = true;
|
||||
|
||||
bool filtersDefined = false;
|
||||
if ( !mWmsParameters.filters().isEmpty() )
|
||||
filtersDefined = true;
|
||||
|
||||
bool filterGeomDefined = false;
|
||||
if ( !mWmsParameters.filterGeom().isEmpty() )
|
||||
filterGeomDefined = true;
|
||||
const bool ijDefined = !mWmsParameters.i().isEmpty() && !mWmsParameters.j().isEmpty();
|
||||
const bool xyDefined = !mWmsParameters.x().isEmpty() && !mWmsParameters.y().isEmpty();
|
||||
const bool filtersDefined = !mWmsParameters.filters().isEmpty();
|
||||
const bool filterGeomDefined = !mWmsParameters.filterGeom().isEmpty();
|
||||
|
||||
if ( !ijDefined && !xyDefined && !filtersDefined && !filterGeomDefined )
|
||||
{
|
||||
@ -2694,10 +2685,13 @@ namespace QgsWms
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsFeatureFilterProviderGroup filters;
|
||||
filters.addProvider( &mFeatureFilter );
|
||||
#ifdef HAVE_SERVER_PYTHON_PLUGINS
|
||||
mAccessControl->resolveFilterFeatures( mapSettings.layers() );
|
||||
filters.addProvider( mAccessControl );
|
||||
#endif
|
||||
QgsMapRendererJobProxy renderJob( mSettings.parallelRendering(), mSettings.maxThreads(), mAccessControl );
|
||||
QgsMapRendererJobProxy renderJob( mSettings.parallelRendering(), mSettings.maxThreads(), &filters );
|
||||
renderJob.render( mapSettings, &image );
|
||||
painter = renderJob.takePainter();
|
||||
}
|
||||
@ -2723,34 +2717,53 @@ namespace QgsWms
|
||||
}
|
||||
}
|
||||
|
||||
void QgsRenderer::setLayerFilter( QgsMapLayer *layer, const QStringList &filters ) const
|
||||
void QgsRenderer::setLayerFilter( QgsMapLayer *layer, const QStringList &filters )
|
||||
{
|
||||
if ( layer->type() == QgsMapLayer::VectorLayer )
|
||||
{
|
||||
QgsVectorLayer *filteredLayer = qobject_cast<QgsVectorLayer *>( layer );
|
||||
Q_FOREACH ( QString filter, filters )
|
||||
{
|
||||
if ( !testFilterStringSafety( filter ) )
|
||||
if ( filter.startsWith( QStringLiteral( "<" ) ) && filter.endsWith( QStringLiteral( "Filter>" ) ) )
|
||||
{
|
||||
throw QgsBadRequestException( QStringLiteral( "Filter string rejected" ),
|
||||
QStringLiteral( "The filter string %1"
|
||||
" has been rejected because of security reasons."
|
||||
" Note: Text strings have to be enclosed in single or double quotes."
|
||||
" A space between each word / special character is mandatory."
|
||||
" Allowed Keywords and special characters are "
|
||||
" AND,OR,IN,<,>=,>,>=,!=,',',(,),DMETAPHONE,SOUNDEX."
|
||||
" Not allowed are semicolons in the filter expression." ).arg( filter ) );
|
||||
// OGC filter
|
||||
QDomDocument filterXml;
|
||||
QString errorMsg;
|
||||
if ( !filterXml.setContent( filter, true, &errorMsg ) )
|
||||
{
|
||||
throw QgsBadRequestException( QStringLiteral( "Filter string rejected" ),
|
||||
QStringLiteral( "error message: %1. The XML string was: %2" ).arg( errorMsg, filter ) );
|
||||
}
|
||||
QDomElement filterElem = filterXml.firstChildElement();
|
||||
QScopedPointer<QgsExpression> expression( QgsOgcUtils::expressionFromOgcFilter( filterElem ) );
|
||||
mFeatureFilter.setFilter( filteredLayer, *expression );
|
||||
}
|
||||
else
|
||||
{
|
||||
// QGIS (SQL) filter
|
||||
if ( !testFilterStringSafety( filter ) )
|
||||
{
|
||||
throw QgsBadRequestException( QStringLiteral( "Filter string rejected" ),
|
||||
QStringLiteral( "The filter string %1"
|
||||
" has been rejected because of security reasons."
|
||||
" Note: Text strings have to be enclosed in single or double quotes."
|
||||
" A space between each word / special character is mandatory."
|
||||
" Allowed Keywords and special characters are "
|
||||
" AND,OR,IN,<,>=,>,>=,!=,',',(,),DMETAPHONE,SOUNDEX."
|
||||
" Not allowed are semicolons in the filter expression." ).arg(
|
||||
filter ) );
|
||||
}
|
||||
|
||||
QString newSubsetString = filter;
|
||||
if ( !filteredLayer->subsetString().isEmpty() )
|
||||
{
|
||||
newSubsetString.prepend( ") AND (" );
|
||||
newSubsetString.append( ")" );
|
||||
newSubsetString.prepend( filteredLayer->subsetString() );
|
||||
newSubsetString.prepend( "(" );
|
||||
QString newSubsetString = filter;
|
||||
if ( !filteredLayer->subsetString().isEmpty() )
|
||||
{
|
||||
newSubsetString.prepend( ") AND (" );
|
||||
newSubsetString.append( ")" );
|
||||
newSubsetString.prepend( filteredLayer->subsetString() );
|
||||
newSubsetString.prepend( "(" );
|
||||
}
|
||||
filteredLayer->setSubsetString( newSubsetString );
|
||||
}
|
||||
filteredLayer->setSubsetString( newSubsetString );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include "qgsserversettings.h"
|
||||
#include "qgswmsparameters.h"
|
||||
#include "qgsfeaturefilter.h"
|
||||
#include <QDomDocument>
|
||||
#include <QMap>
|
||||
#include <QPair>
|
||||
@ -165,7 +166,7 @@ namespace QgsWms
|
||||
void setLayerOpacity( QgsMapLayer *layer, int opacity ) const;
|
||||
|
||||
// Set layer filter
|
||||
void setLayerFilter( QgsMapLayer *layer, const QStringList &filter ) const;
|
||||
void setLayerFilter( QgsMapLayer *layer, const QStringList &filter );
|
||||
|
||||
// Set layer python filter
|
||||
void setLayerAccessControlFilter( QgsMapLayer *layer ) const;
|
||||
@ -287,6 +288,7 @@ namespace QgsWms
|
||||
|
||||
//! The access control helper
|
||||
QgsAccessControl *mAccessControl = nullptr;
|
||||
QgsFeatureFilter mFeatureFilter;
|
||||
|
||||
const QgsServerSettings &mSettings;
|
||||
const QgsProject *mProject = nullptr;
|
||||
|
@ -980,7 +980,7 @@ class TestQgsServerAccessControl(unittest.TestCase):
|
||||
test we reuse the projectsubsetstring reference images as we are using filter requests to set the same
|
||||
filter " pkuid in (7,8) " as the project subsetstring uses for its test.
|
||||
"""
|
||||
query_string = "&".join(["%s=%s" % i for i in list({
|
||||
query_string = "&".join(["%s=%s" % i for i in {
|
||||
"MAP": urllib.parse.quote(self.projectPath),
|
||||
"SERVICE": "WMS",
|
||||
"VERSION": "1.1.1",
|
||||
@ -993,12 +993,12 @@ class TestQgsServerAccessControl(unittest.TestCase):
|
||||
"HEIGHT": "500",
|
||||
"WIDTH": "500",
|
||||
"SRS": "EPSG:3857"
|
||||
}.items())])
|
||||
}.items()])
|
||||
|
||||
response, headers = self._get_fullaccess(query_string)
|
||||
self._img_diff_error(response, headers, "WMS_GetMap_projectsubstring")
|
||||
|
||||
query_string = "&".join(["%s=%s" % i for i in list({
|
||||
query_string = "&".join(["%s=%s" % i for i in {
|
||||
"MAP": urllib.parse.quote(self.projectPath),
|
||||
"SERVICE": "WMS",
|
||||
"VERSION": "1.1.1",
|
||||
@ -1011,11 +1011,32 @@ class TestQgsServerAccessControl(unittest.TestCase):
|
||||
"HEIGHT": "500",
|
||||
"WIDTH": "500",
|
||||
"SRS": "EPSG:3857"
|
||||
}.items())])
|
||||
}.items()])
|
||||
|
||||
response, headers = self._get_restricted(query_string)
|
||||
self._img_diff_error(response, headers, "Restricted_WMS_GetMap_projectsubstring")
|
||||
|
||||
filter = "<Filter><Or><PropertyIsEqualTo><PropertyName>pkuid</PropertyName><Literal>7</Literal>" \
|
||||
"</PropertyIsEqualTo><PropertyIsEqualTo><PropertyName>pkuid</PropertyName><Literal>8</Literal>" \
|
||||
"</PropertyIsEqualTo></Or></Filter>"
|
||||
query_string = "&".join(["%s=%s" % i for i in {
|
||||
"MAP": urllib.parse.quote(self.projectPath),
|
||||
"SERVICE": "WMS",
|
||||
"VERSION": "1.1.1",
|
||||
"REQUEST": "GetMap",
|
||||
"LAYERS": "Hello_Filter_SubsetString",
|
||||
"FILTER": filter,
|
||||
"STYLES": "",
|
||||
"FORMAT": "image/png",
|
||||
"BBOX": "-16817707,-6318936.5,5696513,16195283.5",
|
||||
"HEIGHT": "500",
|
||||
"WIDTH": "500",
|
||||
"SRS": "EPSG:3857"
|
||||
}.items()])
|
||||
|
||||
response, headers = self._get_restricted(query_string)
|
||||
self._img_diff_error(response, headers, "Restricted_WMS_GetMap_projectsubstring_OGC")
|
||||
|
||||
def test_wms_getmap_projectsubsetstring(self):
|
||||
""" test that project set layer subsetStrings are honored"""
|
||||
query_string = "&".join(["%s=%s" % i for i in list({
|
||||
|
@ -283,6 +283,37 @@ class TestQgsServerSecurity(QgsServerTestBase):
|
||||
self.handle_request_wfs_getfeature_filter(filter_xml)
|
||||
self.assertTrue(self.is_point_table_still_exist())
|
||||
|
||||
def test_wms_getmap_filter_stacked(self):
|
||||
"""
|
||||
The aim is to execute some staked queries within the 'Literal'
|
||||
and 'PropertyName' field. Here the 'drop' function is used but it
|
||||
could be done with create, insert, ...
|
||||
|
||||
But due to the implementation, these filters quoted before being sent to the DB.
|
||||
|
||||
It's typically the kind of SQL injection which has been fixed in
|
||||
mapserver several years ago:
|
||||
https://trac.osgeo.org/mapserver/ticket/3874
|
||||
"""
|
||||
|
||||
# ogc:Literal / ogc:PropertyIsEqualTo
|
||||
literal = "4')); drop table point --"
|
||||
filter_xml = "<ogc:Filter%20xmlns:ogc=\"http://www.opengis.net/ogc\"><ogc:PropertyIsEqualTo><ogc:PropertyName>pkuid</ogc:PropertyName><ogc:Literal>{0}</ogc:Literal></ogc:PropertyIsEqualTo></ogc:Filter>".format(literal)
|
||||
self.handle_request_wms_getmap(filter=filter_xml)
|
||||
self.assertTrue(self.is_point_table_still_exist())
|
||||
|
||||
# ogc:Literal / ogc:PropertyIsLike
|
||||
literal = "4')); drop table point --"
|
||||
filter_xml = "<ogc:Filter%20xmlns:ogc=\"http://www.opengis.net/ogc\"><ogc:PropertyIsLike><ogc:PropertyName>pkuid</ogc:PropertyName><ogc:Literal>{0}</ogc:Literal></ogc:PropertyIsLike></ogc:Filter>".format(literal)
|
||||
self.handle_request_wms_getmap(filter=filter_xml)
|
||||
self.assertTrue(self.is_point_table_still_exist())
|
||||
|
||||
# ogc:PropertyName / ogc:PropertyIsLike
|
||||
propname = "name = 'a')); drop table point --"
|
||||
filter_xml = "<ogc:Filter%20xmlns:ogc=\"http://www.opengis.net/ogc\"><ogc:PropertyIsLike><ogc:PropertyName>{0}</ogc:PropertyName><ogc:Literal>4</ogc:Literal></ogc:PropertyIsLike></ogc:Filter>".format(propname)
|
||||
self.handle_request_wms_getmap(filter=filter_xml)
|
||||
self.assertTrue(self.is_point_table_still_exist())
|
||||
|
||||
def test_wms_getmap_sld_stacked(self):
|
||||
"""
|
||||
The aim is to execute some staked queries within the 'Literal'
|
||||
@ -297,7 +328,7 @@ class TestQgsServerSecurity(QgsServerTestBase):
|
||||
|
||||
literal = "4')); drop table point --"
|
||||
sld = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><StyledLayerDescriptor xmlns=\"http://www.opengis.net/sld\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:ogc=\"http://www.opengis.net/ogc\" xsi:schemaLocation=\"http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd\" version=\"1.1.0\" xmlns:se=\"http://www.opengis.net/se\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"> <NamedLayer> <se:Name>point</se:Name> <UserStyle> <se:Name>point</se:Name> <se:FeatureTypeStyle> <se:Rule> <se:Name>Single symbol</se:Name> <ogc:Filter xmlns:ogc=\"http://www.opengis.net/ogc\"> <ogc:PropertyIsEqualTo> <ogc:PropertyName>pkuid</ogc:PropertyName> <ogc:Literal>{0}</ogc:Literal> </ogc:PropertyIsEqualTo> </ogc:Filter> <se:PointSymbolizer> <se:Graphic> <se:Mark> <se:WellKnownName>circle</se:WellKnownName> <se:Fill><se:SvgParameter name=\"fill\">5e86a1</se:SvgParameter></se:Fill><se:Stroke><se:SvgParameter name=\"stroke\">000000</se:SvgParameter></se:Stroke></se:Mark><se:Size>7</se:Size></se:Graphic></se:PointSymbolizer></se:Rule></se:FeatureTypeStyle></UserStyle></NamedLayer></StyledLayerDescriptor>".format(literal)
|
||||
self.handle_request_wms_getmap(sld)
|
||||
self.handle_request_wms_getmap(sld=sld)
|
||||
self.assertTrue(self.is_point_table_still_exist())
|
||||
|
||||
def check_service_exception_report(self, d):
|
||||
@ -311,7 +342,7 @@ class TestQgsServerSecurity(QgsServerTestBase):
|
||||
return False
|
||||
|
||||
def handle_request_wfs_getfeature_filter(self, filter_xml):
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in {
|
||||
"MAP": urllib.parse.quote(self.project),
|
||||
"SERVICE": "WFS",
|
||||
"VERSION": "1.1.1",
|
||||
@ -319,12 +350,12 @@ class TestQgsServerSecurity(QgsServerTestBase):
|
||||
"TYPENAME": "point",
|
||||
"STYLES": "",
|
||||
"CRS": "EPSG:32613",
|
||||
"FILTER": filter_xml}.items())])
|
||||
"FILTER": filter_xml}.items()])
|
||||
|
||||
return self._execute_request(qs)
|
||||
|
||||
def handle_request_wms_getfeatureinfo(self, filter_sql):
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in {
|
||||
"MAP": urllib.parse.quote(self.project),
|
||||
"SERVICE": "WMS",
|
||||
"VERSION": "1.1.1",
|
||||
@ -337,12 +368,12 @@ class TestQgsServerSecurity(QgsServerTestBase):
|
||||
"WIDTH": "500",
|
||||
"BBOX": "606171,4822867,612834,4827375",
|
||||
"CRS": "EPSG:32613",
|
||||
"FILTER": filter_sql}.items())])
|
||||
"FILTER": filter_sql}.items()])
|
||||
|
||||
return self._result(self._execute_request(qs))
|
||||
|
||||
def handle_request_wms_getmap(self, sld):
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
def handle_request_wms_getmap(self, sld=None, filter=None):
|
||||
params = {
|
||||
"MAP": urllib.parse.quote(self.project),
|
||||
"SERVICE": "WMS",
|
||||
"VERSION": "1.0.0",
|
||||
@ -354,8 +385,13 @@ class TestQgsServerSecurity(QgsServerTestBase):
|
||||
"HEIGHT": "500",
|
||||
"WIDTH": "500",
|
||||
"BBOX": "606171,4822867,612834,4827375",
|
||||
"CRS": "EPSG:32613",
|
||||
"SLD": sld}.items())])
|
||||
"CRS": "EPSG:32613"
|
||||
}
|
||||
if sld is not None:
|
||||
params["SLD"] = sld
|
||||
if filter is not None:
|
||||
params["FILTER"] = urllib.parse.quote(filter)
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in params.items()])
|
||||
|
||||
return self._result(self._execute_request(qs))
|
||||
|
||||
|
@ -697,6 +697,27 @@ class TestQgsServerWMSGetMap(QgsServerTestBase):
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self._img_diff_error(r, h, "WMS_GetMap_Filter3")
|
||||
|
||||
def test_wms_getmap_filter_ogc(self):
|
||||
filter = "<Filter><PropertyIsEqualTo><PropertyName>name</PropertyName>" + \
|
||||
"<Literal>eurasia</Literal></PropertyIsEqualTo></Filter>"
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectPath),
|
||||
"SERVICE": "WMS",
|
||||
"VERSION": "1.1.1",
|
||||
"REQUEST": "GetMap",
|
||||
"LAYERS": "Country,Hello",
|
||||
"STYLES": "",
|
||||
"FORMAT": "image/png",
|
||||
"BBOX": "-16817707,-4710778,5696513,14587125",
|
||||
"HEIGHT": "500",
|
||||
"WIDTH": "500",
|
||||
"CRS": "EPSG:3857",
|
||||
"FILTER": filter
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self._img_diff_error(r, h, "WMS_GetMap_Filter_OGC")
|
||||
|
||||
def test_wms_getmap_selection(self):
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectPath),
|
||||
|
BIN
tests/testdata/control_images/qgis_server/WMS_GetMap_Filter_OGC/WMS_GetMap_Filter_OGC.png
vendored
Normal file
BIN
tests/testdata/control_images/qgis_server/WMS_GetMap_Filter_OGC/WMS_GetMap_Filter_OGC.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
BIN
tests/testdata/control_images/qgis_server/WMS_GetMap_Filter_OGC/WMS_GetMap_Filter_OGC_mask.png
vendored
Normal file
BIN
tests/testdata/control_images/qgis_server/WMS_GetMap_Filter_OGC/WMS_GetMap_Filter_OGC_mask.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 5.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.0 KiB |
Loading…
x
Reference in New Issue
Block a user