27using namespace Qt::StringLiterals;
34 , mInterface( interface )
40 qDeleteAll( mExternalLayers );
41 mExternalLayers.clear();
48 initRestrictedLayers();
51 searchLayersToRender();
52 removeUnwantedLayers();
54 std::reverse( mLayersToRender.begin(), mLayersToRender.end() );
57bool QgsWmsRenderContext::addLayerToRender(
QgsMapLayer *layer )
59 const bool allowed = checkLayerReadPermissions(
layer );
62 mLayersToRender.append(
layer );
82 return mFlags.testFlag( flag );
92 return *mInterface->serverSettings();
105 if ( mSlds.contains( nickname ) )
107 sld = mSlds[nickname];
118 if ( mStyles.contains( nickname ) )
120 style = mStyles[nickname];
130 const QList<QgsWmsParametersLayer> cLayerParams { mParameters.layersParameters() };
132 for (
const auto ¶ms : std::as_const( cLayerParams ) )
148 if ( !mParameters.imageQuality().isEmpty() )
160 if ( mParameters.tiledAsBool() )
177 if ( mParameters.wmsPrecisionAsInt() > -1 )
179 precision = mParameters.wmsPrecisionAsInt();
192 if ( !mParameters.dpi().isEmpty() )
194 dpm = mParameters.dpiAsDouble() / 0.0254;
203 std::function<QStringList(
const QString &name )> findLeaves = [&](
const QString &name ) -> QStringList {
205 if ( mLayerGroups.contains( name ) )
207 const auto &
layers { mLayerGroups[name] };
208 for (
const auto &l :
layers )
211 if ( checkLayerReadPermissions( l ) )
215 if ( mLayerGroups.contains( nick ) )
217 _result.append( name );
221 _result.append( findLeaves( nick ) );
228 _result.append( name );
233 for (
const auto &name : std::as_const( layerNames ) )
235 result.append( findLeaves( name ) );
242 return mLayersToRender;
247 return mNicknameLayers.values();
252 double denominator = -1;
254 if ( mScaleDenominator >= 0 )
256 denominator = mScaleDenominator;
260 denominator = mParameters.scaleAsDouble();
269 removeUnwantedLayers();
276 if ( mFlags &
UpdateExtent && !mParameters.bbox().isEmpty() )
286 QString name =
layer.serverProperties()->shortName();
289 && std::find_if( mExternalLayers.cbegin(), mExternalLayers.cend(), [&
layer](
const QgsMapLayer *l ) { return l->id() == layer.id(); } ) == mExternalLayers.cend() )
293 else if ( name.isEmpty() )
305 for (
auto layer : mLayersToRender )
319 return layer( nickname );
324 return mLayerGroups.value( nickname );
329 return mLayerGroups.contains( name );
332void QgsWmsRenderContext::initNicknameLayers()
341 const QgsLayerTreeGroup *root = mProject->layerTreeRoot();
343 initLayerGroupsRecursive( root, rootName.isEmpty() ? mProject->title() : rootName );
346void QgsWmsRenderContext::initLayerGroupsRecursive(
const QgsLayerTreeGroup *group,
const QString &groupName )
348 if ( !groupName.isEmpty() )
350 QList<QgsMapLayer *> layerGroup;
351 const auto projectLayerTreeRoot { mProject->layerTreeRoot() };
352 const auto treeGroupLayers { group->
findLayers() };
355 if ( !projectLayerTreeRoot->hasCustomLayerOrder() )
357 for (
const auto &tl : treeGroupLayers )
359 layerGroup.push_back( tl->layer() );
364 const auto projectLayerOrder { projectLayerTreeRoot->layerOrder() };
366 QList<QgsMapLayer *> groupLayersList;
367 for (
const auto &tl : treeGroupLayers )
369 groupLayersList << tl->layer();
371 for (
const auto &l : projectLayerOrder )
373 if ( groupLayersList.contains( l ) )
375 layerGroup.push_back( l );
380 if ( !layerGroup.empty() )
382 mLayerGroups[groupName] = layerGroup;
386 for (
const QgsLayerTreeNode *child : group->
children() )
390 auto group =
static_cast<const QgsLayerTreeGroup *
>( child );
393 if ( name.isEmpty() )
394 name = child->name();
396 initLayerGroupsRecursive( group, name );
401void QgsWmsRenderContext::initRestrictedLayers()
403 mRestrictedLayers.clear();
409 QStringList restrictedLayersNames;
410 QgsLayerTreeGroup *root = mProject->layerTreeRoot();
412 for (
const QString &l : std::as_const( restricted ) )
414 const QgsLayerTreeGroup *group = root->
findGroup( l );
417 const QList<QgsLayerTreeLayer *> groupLayers = group->
findLayers();
418 for ( QgsLayerTreeLayer *treeLayer : groupLayers )
420 restrictedLayersNames.append( treeLayer->name() );
425 restrictedLayersNames.append( l );
433 if ( restrictedLayersNames.contains(
layer->name() ) )
440void QgsWmsRenderContext::searchLayersToRender()
442 mLayersToRender.clear();
446 if ( !mParameters.sldBody().isEmpty() )
448 searchLayersToRenderSld();
452 searchLayersToRenderStyle();
458 for (
const QString &layerName : queryLayerNames )
460 const QList<QgsMapLayer *>
layers = mNicknameLayers.values( layerName );
461 for ( QgsMapLayer *lyr :
layers )
463 if ( !mLayersToRender.contains( lyr ) )
465 if ( !addLayerToRender( lyr ) )
467 throw QgsSecurityException( u
"Your are not allowed to access the layer %1"_s.arg( lyr->name() ) );
477 for (
const QString &layerName : queryLayerNames )
479 const QList<QgsMapLayer *>
layers = mNicknameLayers.values( layerName );
480 for ( QgsMapLayer *lyr :
layers )
482 if ( !mLayersToRender.contains( lyr ) )
484 if ( !addLayerToRender( lyr ) )
486 throw QgsSecurityException( u
"Your are not allowed to access the layer %1"_s.arg( lyr->name() ) );
494void QgsWmsRenderContext::searchLayersToRenderSld()
496 const QString
sld = mParameters.sldBody();
504 ( void ) doc.setContent(
sld,
true );
505 QDomElement docEl = doc.documentElement();
507 QDomElement root = doc.firstChildElement(
"StyledLayerDescriptor" );
508 QDomElement namedElem = root.firstChildElement(
"NamedLayer" );
510 if ( docEl.isNull() )
515 QDomNodeList named = docEl.elementsByTagName(
"NamedLayer" );
516 for (
int i = 0; i < named.size(); ++i )
518 QDomNodeList names = named.item( i ).toElement().elementsByTagName(
"Name" );
519 if ( !names.isEmpty() )
521 QString lname = names.item( 0 ).toElement().text();
522 if ( mNicknameLayers.contains( lname ) )
524 mSlds[lname] = namedElem;
525 for (
const auto layer : mNicknameLayers.values( lname ) )
527 if ( !addLayerToRender(
layer ) )
529 throw QgsSecurityException( u
"Your are not allowed to access the layer %1"_s.arg(
layer->name() ) );
533 else if ( mLayerGroups.contains( lname ) )
538 param.mValue = lname;
542 bool layerAdded =
false;
543 for ( QgsMapLayer *
layer : mLayerGroups[lname] )
546 if ( checkLayerReadPermissions(
layer ) )
549 mSlds[name] = namedElem;
550 mLayersToRender.insert( 0,
layer );
559 param.mValue = lname;
566 param.mValue = lname;
573void QgsWmsRenderContext::searchLayersToRenderStyle()
575 for (
const QgsWmsParametersLayer ¶m : mParameters.layersParameters() )
577 const QString nickname = param.mNickname;
578 const QString
style = param.mStyle;
582 std::unique_ptr<QgsMapLayer>
layer = std::make_unique<QgsRasterLayer>( param.mExternalUri, param.mNickname, u
"wms"_s );
584 if (
layer->isValid() )
587 mExternalLayers.append(
layer.release() );
588 auto lyr = mExternalLayers.last();
589 if ( !addLayerToRender( lyr ) )
591 throw QgsSecurityException( u
"Your are not allowed to access the layer %1"_s.arg( lyr->name() ) );
595 else if ( mNicknameLayers.contains( nickname ) )
597 if ( !
style.isEmpty() )
599 mStyles[nickname] =
style;
602 for (
const auto layer : mNicknameLayers.values( nickname ) )
604 if ( !addLayerToRender(
layer ) )
606 throw QgsSecurityException( u
"Your are not allowed to access the layer %1"_s.arg(
layer->name() ) );
610 else if ( mLayerGroups.contains( nickname ) )
615 param.mValue = nickname;
620 for ( QgsMapLayer *
layer : mLayerGroups[nickname] )
623 if ( !
style.isEmpty() )
625 mStyles[nickname] =
style;
630 bool layerAdded =
false;
633 for (
const auto layer : mNicknameLayers.values( name ) )
635 if ( addLayerToRender(
layer ) )
646 param.mValue = nickname;
653 param.mValue = nickname;
659bool QgsWmsRenderContext::layerScaleVisibility(
const QString &name )
const
661 bool visible =
false;
663 if ( !mNicknameLayers.contains( name ) )
668 const QList<QgsMapLayer *>
layers = mNicknameLayers.values( name );
671 bool scaleBasedVisibility =
layer->hasScaleBasedVisibility();
672 bool useScaleConstraint = (
scaleDenominator() > 0 && scaleBasedVisibility );
690 int width = mParameters.widthAsInt();
695 width = mParameters.srcWidthAsInt();
703 int height = mParameters.heightAsInt();
708 height = mParameters.srcHeightAsInt();
721 if ( width <= 0 || height <= 0 )
730 if ( wmsMaxWidthEnv != -1 && wmsMaxWidthProj != -1 )
733 wmsMaxWidth = std::min( wmsMaxWidthProj, wmsMaxWidthEnv );
738 wmsMaxWidth = std::max( wmsMaxWidthProj, wmsMaxWidthEnv );
741 if ( wmsMaxWidth != -1 && width > wmsMaxWidth )
750 if ( wmsMaxHeightEnv != -1 && wmsMaxHeightProj != -1 )
753 wmsMaxHeight = std::min( wmsMaxHeightProj, wmsMaxHeightEnv );
758 wmsMaxHeight = std::max( wmsMaxHeightProj, wmsMaxHeightEnv );
761 if ( wmsMaxHeight != -1 && height > wmsMaxHeight )
775 switch ( mParameters.format() )
783 if ( width > ( std::numeric_limits<int>::max() - 31 ) / depth )
786 const int bytes_per_line = ( ( width * depth + 31 ) >> 5 ) << 2;
788 if ( std::numeric_limits<int>::max() / bytes_per_line < height || std::numeric_limits<int>::max() /
sizeof( uchar * ) <
static_cast<uint
>( height ) )
801 const QgsRectangle extent = mParameters.bboxAsRectangle();
802 if ( !mParameters.bbox().isEmpty() && extent.
isEmpty() )
822 if ( aspectRatio && mParameters.versionAsNumber() >=
QgsProjectVersion( 1, 3, 0 ) )
825 if ( !mParameters.bbox().isEmpty() && extent.
isEmpty() )
830 QString crs = mParameters.crs();
831 if ( crs.compare(
"CRS:84", Qt::CaseInsensitive ) == 0 )
833 crs = QString(
"EPSG:4326" );
843 if ( !extent.
isEmpty() && height > 0 && width > 0 )
845 const double mapRatio = extent.
width() / extent.
height();
846 const double imageRatio =
static_cast<double>( width ) /
static_cast<double>( height );
850 const double cellsize = ( extent.
width() /
static_cast<double>( width ) ) * 0.5 + ( extent.
height() /
static_cast<double>( height ) ) * 0.5;
851 width = extent.
width() / cellsize;
852 height = extent.
height() / cellsize;
861 else if ( height <= 0 )
866 return QSize( width, height );
869void QgsWmsRenderContext::removeUnwantedLayers()
871 QList<QgsMapLayer *>
layers;
879 if ( !layerScaleVisibility( nickname ) )
882 if ( mRestrictedLayers.contains( nickname ) )
893 if ( !wfsLayers.contains(
layer->
id() ) )
908 for (
const auto &
layer : mExternalLayers )
917bool QgsWmsRenderContext::checkLayerReadPermissions(
QgsMapLayer *layer )
const
919#ifdef HAVE_SERVER_PYTHON_PLUGINS
920 if ( !accessControl()->layerReadPermission(
layer ) )
922 QString msg = u
"Checking forbidden access for layer: %1"_s.arg(
layer->
name() );
931#ifdef HAVE_SERVER_PYTHON_PLUGINS
932QgsAccessControl *QgsWmsRenderContext::accessControl()
const
934 return mInterface->accessControls();
940 mSocketFeedback = feedback;
945 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(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
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).