27using namespace Qt::StringLiterals;
34 , mInterface( interface )
41 qDeleteAll( mExternalLayers );
42 mExternalLayers.clear();
49 initRestrictedLayers();
52 searchLayersToRender();
53 removeUnwantedLayers();
55 std::reverse( mLayersToRender.begin(), mLayersToRender.end() );
58bool QgsWmsRenderContext::addLayerToRender(
QgsMapLayer *layer )
60 const bool allowed = checkLayerReadPermissions(
layer );
63 mLayersToRender.append(
layer );
83 return mFlags.testFlag( flag );
93 return *mInterface->serverSettings();
106 if ( mSlds.contains( nickname ) )
108 sld = mSlds[nickname];
119 if ( mStyles.contains( nickname ) )
121 style = mStyles[nickname];
131 const QList<QgsWmsParametersLayer> cLayerParams { mParameters.layersParameters() };
133 for (
const auto ¶ms : std::as_const( cLayerParams ) )
149 if ( !mParameters.imageQuality().isEmpty() )
161 if ( mParameters.tiledAsBool() )
178 if ( mParameters.wmsPrecisionAsInt() > -1 )
180 precision = mParameters.wmsPrecisionAsInt();
193 if ( !mParameters.dpi().isEmpty() )
195 dpm = mParameters.dpiAsDouble() / 0.0254;
204 std::function<QStringList(
const QString &name )> findLeaves = [&](
const QString &name ) -> QStringList {
206 if ( mLayerGroups.contains( name ) )
208 const auto &
layers { mLayerGroups[name] };
209 for (
const auto &l :
layers )
212 if ( checkLayerReadPermissions( l ) )
216 if ( mLayerGroups.contains( nick ) )
218 _result.append( name );
222 _result.append( findLeaves( nick ) );
229 _result.append( name );
234 for (
const auto &name : std::as_const( layerNames ) )
236 result.append( findLeaves( name ) );
243 return mLayersToRender;
248 return mNicknameLayers.values();
253 double denominator = -1;
255 if ( mScaleDenominator >= 0 )
257 denominator = mScaleDenominator;
261 denominator = mParameters.scaleAsDouble();
270 removeUnwantedLayers();
277 if ( mFlags &
UpdateExtent && !mParameters.bbox().isEmpty() )
287 QString name =
layer.serverProperties()->shortName();
290 return l->id() == layer.id();
292 == mExternalLayers.cend() )
296 else if ( name.isEmpty() )
308 for (
auto layer : mLayersToRender )
322 return layer( nickname );
327 return mLayerGroups.value( nickname );
332 return mLayerGroups.contains( name );
335void QgsWmsRenderContext::initNicknameLayers()
344 const QgsLayerTreeGroup *root = mProject->layerTreeRoot();
346 initLayerGroupsRecursive( root, rootName.isEmpty() ? mProject->title() : rootName );
349void QgsWmsRenderContext::initLayerGroupsRecursive(
const QgsLayerTreeGroup *group,
const QString &groupName )
351 if ( !groupName.isEmpty() )
353 QList<QgsMapLayer *> layerGroup;
354 const auto projectLayerTreeRoot { mProject->layerTreeRoot() };
355 const auto treeGroupLayers { group->
findLayers() };
358 if ( !projectLayerTreeRoot->hasCustomLayerOrder() )
360 for (
const auto &tl : treeGroupLayers )
362 layerGroup.push_back( tl->layer() );
367 const auto projectLayerOrder { projectLayerTreeRoot->layerOrder() };
369 QList<QgsMapLayer *> groupLayersList;
370 for (
const auto &tl : treeGroupLayers )
372 groupLayersList << tl->layer();
374 for (
const auto &l : projectLayerOrder )
376 if ( groupLayersList.contains( l ) )
378 layerGroup.push_back( l );
383 if ( !layerGroup.empty() )
385 mLayerGroups[groupName] = layerGroup;
389 for (
const QgsLayerTreeNode *child : group->
children() )
393 auto group =
static_cast<const QgsLayerTreeGroup *
>( child );
396 if ( name.isEmpty() )
397 name = child->name();
399 initLayerGroupsRecursive( group, name );
404void QgsWmsRenderContext::initRestrictedLayers()
406 mRestrictedLayers.clear();
412 QStringList restrictedLayersNames;
413 QgsLayerTreeGroup *root = mProject->layerTreeRoot();
415 for (
const QString &l : std::as_const( restricted ) )
417 const QgsLayerTreeGroup *group = root->
findGroup( l );
420 const QList<QgsLayerTreeLayer *> groupLayers = group->
findLayers();
421 for ( QgsLayerTreeLayer *treeLayer : groupLayers )
423 restrictedLayersNames.append( treeLayer->name() );
428 restrictedLayersNames.append( l );
436 if ( restrictedLayersNames.contains(
layer->name() ) )
443void QgsWmsRenderContext::searchLayersToRender()
445 mLayersToRender.clear();
449 if ( !mParameters.sldBody().isEmpty() )
451 searchLayersToRenderSld();
455 searchLayersToRenderStyle();
461 for (
const QString &layerName : queryLayerNames )
463 const QList<QgsMapLayer *>
layers = mNicknameLayers.values( layerName );
464 for ( QgsMapLayer *lyr :
layers )
466 if ( !mLayersToRender.contains( lyr ) )
468 if ( !addLayerToRender( lyr ) )
470 throw QgsSecurityException( u
"Your are not allowed to access the layer %1"_s.arg( lyr->name() ) );
480 for (
const QString &layerName : queryLayerNames )
482 const QList<QgsMapLayer *>
layers = mNicknameLayers.values( layerName );
483 for ( QgsMapLayer *lyr :
layers )
485 if ( !mLayersToRender.contains( lyr ) )
487 if ( !addLayerToRender( lyr ) )
489 throw QgsSecurityException( u
"Your are not allowed to access the layer %1"_s.arg( lyr->name() ) );
497void QgsWmsRenderContext::searchLayersToRenderSld()
499 const QString
sld = mParameters.sldBody();
507 ( void ) doc.setContent(
sld,
true );
508 QDomElement docEl = doc.documentElement();
510 QDomElement root = doc.firstChildElement(
"StyledLayerDescriptor" );
511 QDomElement namedElem = root.firstChildElement(
"NamedLayer" );
513 if ( docEl.isNull() )
518 QDomNodeList named = docEl.elementsByTagName(
"NamedLayer" );
519 for (
int i = 0; i < named.size(); ++i )
521 QDomNodeList names = named.item( i ).toElement().elementsByTagName(
"Name" );
522 if ( !names.isEmpty() )
524 QString lname = names.item( 0 ).toElement().text();
525 if ( mNicknameLayers.contains( lname ) )
527 mSlds[lname] = namedElem;
528 for (
const auto layer : mNicknameLayers.values( lname ) )
530 if ( !addLayerToRender(
layer ) )
532 throw QgsSecurityException( u
"Your are not allowed to access the layer %1"_s.arg(
layer->name() ) );
536 else if ( mLayerGroups.contains( lname ) )
541 param.mValue = lname;
545 bool layerAdded =
false;
546 for ( QgsMapLayer *
layer : mLayerGroups[lname] )
549 if ( checkLayerReadPermissions(
layer ) )
552 mSlds[name] = namedElem;
553 mLayersToRender.insert( 0,
layer );
562 param.mValue = lname;
569 param.mValue = lname;
576void QgsWmsRenderContext::searchLayersToRenderStyle()
578 for (
const QgsWmsParametersLayer ¶m : mParameters.layersParameters() )
580 const QString nickname = param.mNickname;
581 const QString
style = param.mStyle;
585 std::unique_ptr<QgsMapLayer>
layer = std::make_unique<QgsRasterLayer>( param.mExternalUri, param.mNickname, u
"wms"_s );
587 if (
layer->isValid() )
590 mExternalLayers.append(
layer.release() );
591 auto lyr = mExternalLayers.last();
592 if ( !addLayerToRender( lyr ) )
594 throw QgsSecurityException( u
"Your are not allowed to access the layer %1"_s.arg( lyr->name() ) );
598 else if ( mNicknameLayers.contains( nickname ) )
600 if ( !
style.isEmpty() )
602 mStyles[nickname] =
style;
605 for (
const auto layer : mNicknameLayers.values( nickname ) )
607 if ( !addLayerToRender(
layer ) )
609 throw QgsSecurityException( u
"Your are not allowed to access the layer %1"_s.arg(
layer->name() ) );
613 else if ( mLayerGroups.contains( nickname ) )
618 param.mValue = nickname;
623 for ( QgsMapLayer *
layer : mLayerGroups[nickname] )
626 if ( !
style.isEmpty() )
628 mStyles[nickname] =
style;
633 bool layerAdded =
false;
636 for (
const auto layer : mNicknameLayers.values( name ) )
638 if ( addLayerToRender(
layer ) )
649 param.mValue = nickname;
656 param.mValue = nickname;
662bool QgsWmsRenderContext::layerScaleVisibility(
const QString &name )
const
664 bool visible =
false;
666 if ( !mNicknameLayers.contains( name ) )
671 const QList<QgsMapLayer *>
layers = mNicknameLayers.values( name );
674 bool scaleBasedVisibility =
layer->hasScaleBasedVisibility();
675 bool useScaleConstraint = (
scaleDenominator() > 0 && scaleBasedVisibility );
693 int width = mParameters.widthAsInt();
698 width = mParameters.srcWidthAsInt();
706 int height = mParameters.heightAsInt();
711 height = mParameters.srcHeightAsInt();
724 if ( width <= 0 || height <= 0 )
733 if ( wmsMaxWidthEnv != -1 && wmsMaxWidthProj != -1 )
736 wmsMaxWidth = std::min( wmsMaxWidthProj, wmsMaxWidthEnv );
741 wmsMaxWidth = std::max( wmsMaxWidthProj, wmsMaxWidthEnv );
744 if ( wmsMaxWidth != -1 && width > wmsMaxWidth )
753 if ( wmsMaxHeightEnv != -1 && wmsMaxHeightProj != -1 )
756 wmsMaxHeight = std::min( wmsMaxHeightProj, wmsMaxHeightEnv );
761 wmsMaxHeight = std::max( wmsMaxHeightProj, wmsMaxHeightEnv );
764 if ( wmsMaxHeight != -1 && height > wmsMaxHeight )
778 switch ( mParameters.format() )
786 if ( width > ( std::numeric_limits<int>::max() - 31 ) / depth )
789 const int bytes_per_line = ( ( width * depth + 31 ) >> 5 ) << 2;
791 if ( std::numeric_limits<int>::max() / bytes_per_line < height
792 || std::numeric_limits<int>::max() /
sizeof( uchar * ) <
static_cast<uint
>( height ) )
805 const QgsRectangle extent = mParameters.bboxAsRectangle();
806 if ( !mParameters.bbox().isEmpty() && extent.
isEmpty() )
830 if ( !mParameters.bbox().isEmpty() && extent.
isEmpty() )
835 QString crs = mParameters.crs();
836 if ( crs.compare(
"CRS:84", Qt::CaseInsensitive ) == 0 )
838 crs = QString(
"EPSG:4326" );
848 if ( !extent.
isEmpty() && height > 0 && width > 0 )
850 const double mapRatio = extent.
width() / extent.
height();
851 const double imageRatio =
static_cast<double>( width ) /
static_cast<double>( height );
855 const double cellsize = ( extent.
width() /
static_cast<double>( width ) ) * 0.5 + ( extent.
height() /
static_cast<double>( height ) ) * 0.5;
856 width = extent.
width() / cellsize;
857 height = extent.
height() / cellsize;
866 else if ( height <= 0 )
871 return QSize( width, height );
874void QgsWmsRenderContext::removeUnwantedLayers()
876 QList<QgsMapLayer *>
layers;
884 if ( !layerScaleVisibility( nickname ) )
887 if ( mRestrictedLayers.contains( nickname ) )
898 if ( !wfsLayers.contains(
layer->
id() ) )
913 for (
const auto &
layer : mExternalLayers )
922bool QgsWmsRenderContext::checkLayerReadPermissions(
QgsMapLayer *layer )
const
924#ifdef HAVE_SERVER_PYTHON_PLUGINS
925 if ( !accessControl()->layerReadPermission(
layer ) )
927 QString msg = u
"Checking forbidden access for layer: %1"_s.arg(
layer->
name() );
936#ifdef HAVE_SERVER_PYTHON_PLUGINS
937QgsAccessControl *QgsWmsRenderContext::accessControl()
const
939 return mInterface->accessControls();
945 mSocketFeedback = feedback;
950 return mSocketFeedback;
@ Info
Information message.
Represents a coordinate reference system (CRS).
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
bool hasAxisInverted() const
Returns whether the axis order is inverted for the CRS compared to the order east/north (longitude/la...
Base class for feedback objects to be used for cancellation of something running in a worker thread.
QgsLayerTreeGroup * findGroup(const QString &name)
Find group node with specified name.
QgsMapLayerServerProperties * serverProperties()
Returns QGIS Server Properties for the layer tree group.
QList< QgsLayerTreeLayer * > findLayers() const
Find all layer nodes.
@ NodeGroup
Container of other groups and layers.
QList< QgsLayerTreeNode * > children()
Gets list of children of the node. Children are owned by the parent.
QString shortName() const
Returns the short name of the layer used by QGIS Server to identify the layer.
Base class for all map layer types.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
Describes the version of a project.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
QMap< QString, QgsMapLayer * > mapLayers(const bool validOnly=false) const
Returns a map of all registered layers by layer ID.
A rectangle specified with double values.
void invert()
Swap x/y coordinates in the rectangle.
Defines interfaces exposed by QGIS Server and made available to plugins.
static int wmsTileBuffer(const QgsProject &project)
Returns the tile buffer in pixels for WMS images defined in a QGIS project.
static QString wmsRootName(const QgsProject &project)
Returns the WMS root layer name defined in a QGIS project.
static bool wmsSkipNameForGroup(const QgsProject &project)
Returns if name attribute should be skipped for groups in WMS capabilities document.
static int wmsFeatureInfoPrecision(const QgsProject &project)
Returns the geometry precision for GetFeatureInfo request.
static bool wmsUseLayerIds(const QgsProject &project)
Returns if layer ids are used as name in WMS.
static QStringList wfsLayerIds(const QgsProject &project)
Returns the Layer ids list defined in a QGIS project as published in WFS.
static bool wmsRenderMapTiles(const QgsProject &project)
Returns true if WMS requests should use the QgsMapSettings::RenderMapTile flag, so that no visible ar...
static QStringList wmsRestrictedLayers(const QgsProject &project)
Returns the restricted layer name list.
static int wmsImageQuality(const QgsProject &project)
Returns the quality for WMS images defined in a QGIS project.
static int wmsMaxWidth(const QgsProject &project)
Returns the maximum width for WMS images defined in a QGIS project.
static int wmsMaxHeight(const QgsProject &project)
Returns the maximum height for WMS images defined in a QGIS project.
Provides a way to retrieve settings by prioritizing according to environment variables,...
int wmsMaxWidth() const
Returns the server-wide max width of a WMS GetMap request.
int wmsMaxHeight() const
Returns the server-wide max height of a WMS GetMap request.
Exception thrown in case of malformed request.
@ QGIS_InvalidParameterValue
Provides an interface to retrieve and manipulate WMS parameters received from the client.
QSize mapSize(bool aspectRatio=true) const
Returns the size (in pixels) of the map to render, according to width and height WMS parameters as we...
bool isExternalLayer(const QString &name) const
Returns true if the layer is an external layer, false otherwise.
bool isValidGroup(const QString &name) const
Returns true if name is a group.
QStringList flattenedQueryLayers(const QStringList &layerNames) const
Returns a list of query layer names where group names are replaced by the names of their layer compon...
QgsFeedback * socketFeedback() const
Returns the response feedback if any.
QgsWmsRenderContext(const QgsProject *project, QgsServerInterface *interface)
Constructor for QgsWmsRenderContext.
QList< QgsMapLayer * > layers() const
Returns a list of all layers read from the project.
void setParameters(const QgsWmsParameters ¶meters)
Sets WMS parameters.
QList< QgsMapLayer * > layersToRender() const
Returns a list of all layers to actually render according to the current configuration.
int mapWidth() const
Returns WIDTH or SRCWIDTH according to UseSrcWidthHeight flag.
QgsMapLayer * layer(const QString &nickname) const
Returns the layer corresponding to the nickname, or a nullptr if not found or if the layer do not nee...
int tileBuffer() const
Returns the tile buffer value to use for rendering according to the current configuration.
bool updateExtent() const
Returns true if the extent has to be updated before the rendering, false otherwise.
const QgsServerSettings & settings() const
Returns settings of the server.
void setFlag(Flag flag, bool on=true)
Sets or unsets a rendering flag according to the on value.
bool isValidWidthHeight() const
Returns true if width and height are valid according to the maximum values defined within the project...
QList< QgsMapLayer * > layersFromGroup(const QString &nickname) const
Returns the group's layers list corresponding to the nickname, or an empty list if not found.
QgsWmsParameters parameters() const
Returns WMS parameters.
void setScaleDenominator(double scaleDenominator)
Sets a custom scale denominator.
QString style(const QgsMapLayer &layer) const
Returns a style's name for a specific layer.
QMap< QString, QList< QgsMapLayer * > > layerGroups() const
Returns a map having layer group names as keys and a list of layers as values.
double mapTileBuffer(int mapWidth) const
Returns the tile buffer in geographical units for the given map width in pixels.
QString layerNickname(const QgsMapLayer &layer) const
Returns the nickname (short name, id or name) of the layer according to the current configuration.
void setSocketFeedback(QgsFeedback *feedback)
Sets the response feedback.
double scaleDenominator() const
Returns the scale denominator to use for rendering according to the current configuration.
qreal dotsPerMm() const
Returns default dots per mm according to the current configuration.
bool testFlag(Flag flag) const
Returns the status of a rendering flag.
QDomElement sld(const QgsMapLayer &layer) const
Returns a SLD document for a specific layer.
bool isValidLayer(const QString &nickname) const
Returns true if the layer has to be rendered, false otherwise.
const QgsProject * project() const
Returns the project.
int precision() const
Returns the precision to use according to the current configuration.
int imageQuality() const
Returns the image quality to use for rendering according to the current configuration.
int mapHeight() const
Returns HEIGHT or SRCHEIGHT according to UseSrcWidthHeight flag.
bool renderMapTiles() const
Returns true if WMS requests should use the QgsMapSettings::RenderMapTile flag, so that no visible ar...
Flag
Available rendering options.
@ AddAllLayers
For GetPrint: add layers from LAYER(S) parameter.
Median cut implementation.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).