QGIS API Documentation 3.99.0-Master (d270888f95f)
Loading...
Searching...
No Matches
qgswmsrendercontext.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgswmsrendercontext.cpp
3 ---------------------
4 begin : March 22, 2019
5 copyright : (C) 2019 by Paul Blottiere
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18#include "qgswmsrendercontext.h"
19
20#include "qgslayertree.h"
21#include "qgsrasterlayer.h"
24
25#include <QString>
26
27using namespace Qt::StringLiterals;
28
29using namespace QgsWms;
30
31const double OGC_PX_M = 0.00028; // OGC reference pixel size in meter
33 : mProject( project )
34 , mInterface( interface )
35 , mFlags()
36{
37}
38
40{
41 qDeleteAll( mExternalLayers );
42 mExternalLayers.clear();
43}
44
46{
47 mParameters = parameters;
48
49 initRestrictedLayers();
50 initNicknameLayers();
51
52 searchLayersToRender();
53 removeUnwantedLayers();
54
55 std::reverse( mLayersToRender.begin(), mLayersToRender.end() );
56}
57
58bool QgsWmsRenderContext::addLayerToRender( QgsMapLayer *layer )
59{
60 const bool allowed = checkLayerReadPermissions( layer );
61 if ( allowed )
62 {
63 mLayersToRender.append( layer );
64 }
65 return allowed;
66}
67
68
69void QgsWmsRenderContext::setFlag( const Flag flag, const bool on )
70{
71 if ( on )
72 {
73 mFlags |= flag;
74 }
75 else
76 {
77 mFlags &= ~flag;
78 }
79}
80
82{
83 return mFlags.testFlag( flag );
84}
85
87{
88 return mParameters;
89}
90
92{
93 return *mInterface->serverSettings();
94}
95
97{
98 return mProject;
99}
100
101QDomElement QgsWmsRenderContext::sld( const QgsMapLayer &layer ) const
102{
103 QDomElement sld;
104
105 const QString nickname = layerNickname( layer );
106 if ( mSlds.contains( nickname ) )
107 {
108 sld = mSlds[nickname];
109 }
110
111 return sld;
112}
113
115{
116 QString style;
117
118 const QString nickname = layerNickname( layer );
119 if ( mStyles.contains( nickname ) )
120 {
121 style = mStyles[nickname];
122 }
123
124 return style;
125}
126
128{
130
131 const QList<QgsWmsParametersLayer> cLayerParams { mParameters.layersParameters() };
132
133 for ( const auto &params : std::as_const( cLayerParams ) )
134 {
135 if ( params.mNickname == layerNickname( layer ) )
136 {
137 parameters = params;
138 break;
139 }
140 }
141
142 return parameters;
143}
144
146{
148
149 if ( !mParameters.imageQuality().isEmpty() )
150 {
151 imageQuality = mParameters.imageQualityAsInt();
152 }
153
154 return imageQuality;
155}
156
158{
159 int tileBuffer = 0;
160
161 if ( mParameters.tiledAsBool() )
162 {
164 }
165
166 return tileBuffer;
167}
168
173
175{
177
178 if ( mParameters.wmsPrecisionAsInt() > -1 )
179 {
180 precision = mParameters.wmsPrecisionAsInt();
181 }
182
183 return precision;
184}
185
187{
188 // Apply DPI parameter if present. This is an extension of QGIS Server
189 // compared to WMS 1.3.
190 // Because of backwards compatibility, this parameter is optional
191 qreal dpm = 1 / OGC_PX_M;
192
193 if ( !mParameters.dpi().isEmpty() )
194 {
195 dpm = mParameters.dpiAsDouble() / 0.0254;
196 }
197
198 return dpm / 1000.0;
199}
200
201QStringList QgsWmsRenderContext::flattenedQueryLayers( const QStringList &layerNames ) const
202{
203 QStringList result;
204 std::function<QStringList( const QString &name )> findLeaves = [&]( const QString &name ) -> QStringList {
205 QStringList _result;
206 if ( mLayerGroups.contains( name ) )
207 {
208 const auto &layers { mLayerGroups[name] };
209 for ( const auto &l : layers )
210 {
211 // Only add allowed layers
212 if ( checkLayerReadPermissions( l ) )
213 {
214 const auto nick { layerNickname( *l ) };
215 // This handles the case for root (fake) group
216 if ( mLayerGroups.contains( nick ) )
217 {
218 _result.append( name );
219 }
220 else
221 {
222 _result.append( findLeaves( nick ) );
223 }
224 }
225 }
226 }
227 else
228 {
229 _result.append( name );
230 }
231 return _result;
232 };
233
234 for ( const auto &name : std::as_const( layerNames ) )
235 {
236 result.append( findLeaves( name ) );
237 }
238 return result;
239}
240
241QList<QgsMapLayer *> QgsWmsRenderContext::layersToRender() const
242{
243 return mLayersToRender;
244}
245
246QList<QgsMapLayer *> QgsWmsRenderContext::layers() const
247{
248 return mNicknameLayers.values();
249}
250
252{
253 double denominator = -1;
254
255 if ( mScaleDenominator >= 0 )
256 {
257 denominator = mScaleDenominator;
258 }
259 else if ( mFlags & UseScaleDenominator && !mParameters.scale().isEmpty() )
260 {
261 denominator = mParameters.scaleAsDouble();
262 }
263
264 return denominator;
265}
266
268{
269 mScaleDenominator = scaleDenominator;
270 removeUnwantedLayers();
271}
272
274{
275 bool update = false;
276
277 if ( mFlags & UpdateExtent && !mParameters.bbox().isEmpty() )
278 {
279 update = true;
280 }
281
282 return update;
283}
284
286{
287 QString name = layer.serverProperties()->shortName();
288 // For external layers we cannot use the layer id because it's not known to the client, use layer name instead.
289 if ( QgsServerProjectUtils::wmsUseLayerIds( *mProject ) && std::find_if( mExternalLayers.cbegin(), mExternalLayers.cend(), [&layer]( const QgsMapLayer *l ) {
290 return l->id() == layer.id();
291 } )
292 == mExternalLayers.cend() )
293 {
294 name = layer.id();
295 }
296 else if ( name.isEmpty() )
297 {
298 name = layer.name();
299 }
300
301 return name;
302}
303
304QgsMapLayer *QgsWmsRenderContext::layer( const QString &nickname ) const
305{
306 QgsMapLayer *mlayer = nullptr;
307
308 for ( auto layer : mLayersToRender )
309 {
310 if ( layerNickname( *layer ).compare( nickname ) == 0 )
311 {
312 mlayer = layer;
313 break;
314 }
315 }
316
317 return mlayer;
318}
319
320bool QgsWmsRenderContext::isValidLayer( const QString &nickname ) const
321{
322 return layer( nickname );
323}
324
325QList<QgsMapLayer *> QgsWmsRenderContext::layersFromGroup( const QString &nickname ) const
326{
327 return mLayerGroups.value( nickname );
328}
329
330bool QgsWmsRenderContext::isValidGroup( const QString &name ) const
331{
332 return mLayerGroups.contains( name );
333}
334
335void QgsWmsRenderContext::initNicknameLayers()
336{
337 for ( QgsMapLayer *ml : mProject->mapLayers() )
338 {
339 mNicknameLayers.insert( layerNickname( *ml ), ml );
340 }
341
342 // init groups
343 const QString rootName { QgsServerProjectUtils::wmsRootName( *mProject ) };
344 const QgsLayerTreeGroup *root = mProject->layerTreeRoot();
345
346 initLayerGroupsRecursive( root, rootName.isEmpty() ? mProject->title() : rootName );
347}
348
349void QgsWmsRenderContext::initLayerGroupsRecursive( const QgsLayerTreeGroup *group, const QString &groupName )
350{
351 if ( !groupName.isEmpty() )
352 {
353 QList<QgsMapLayer *> layerGroup;
354 const auto projectLayerTreeRoot { mProject->layerTreeRoot() };
355 const auto treeGroupLayers { group->findLayers() };
356 // Fast track if there is no custom layer order,
357 // otherwise reorder layers.
358 if ( !projectLayerTreeRoot->hasCustomLayerOrder() )
359 {
360 for ( const auto &tl : treeGroupLayers )
361 {
362 layerGroup.push_back( tl->layer() );
363 }
364 }
365 else
366 {
367 const auto projectLayerOrder { projectLayerTreeRoot->layerOrder() };
368 // Flat list containing the layers from the tree nodes
369 QList<QgsMapLayer *> groupLayersList;
370 for ( const auto &tl : treeGroupLayers )
371 {
372 groupLayersList << tl->layer();
373 }
374 for ( const auto &l : projectLayerOrder )
375 {
376 if ( groupLayersList.contains( l ) )
377 {
378 layerGroup.push_back( l );
379 }
380 }
381 }
382
383 if ( !layerGroup.empty() )
384 {
385 mLayerGroups[groupName] = layerGroup;
386 }
387 }
388
389 for ( const QgsLayerTreeNode *child : group->children() )
390 {
391 if ( child->nodeType() == QgsLayerTreeNode::NodeGroup )
392 {
393 auto group = static_cast<const QgsLayerTreeGroup *>( child );
394 QString name = group ? group->serverProperties()->shortName() : QString();
395
396 if ( name.isEmpty() )
397 name = child->name();
398
399 initLayerGroupsRecursive( group, name );
400 }
401 }
402}
403
404void QgsWmsRenderContext::initRestrictedLayers()
405{
406 mRestrictedLayers.clear();
407
408 // get name of restricted layers/groups in project
409 const QStringList restricted = QgsServerProjectUtils::wmsRestrictedLayers( *mProject );
410
411 // extract restricted layers from excluded groups
412 QStringList restrictedLayersNames;
413 QgsLayerTreeGroup *root = mProject->layerTreeRoot();
414
415 for ( const QString &l : std::as_const( restricted ) )
416 {
417 const QgsLayerTreeGroup *group = root->findGroup( l );
418 if ( group )
419 {
420 const QList<QgsLayerTreeLayer *> groupLayers = group->findLayers();
421 for ( QgsLayerTreeLayer *treeLayer : groupLayers )
422 {
423 restrictedLayersNames.append( treeLayer->name() );
424 }
425 }
426 else
427 {
428 restrictedLayersNames.append( l );
429 }
430 }
431
432 // build output with names, ids or short name according to the configuration
433 const QList<QgsLayerTreeLayer *> layers = root->findLayers();
434 for ( QgsLayerTreeLayer *layer : layers )
435 {
436 if ( restrictedLayersNames.contains( layer->name() ) )
437 {
438 mRestrictedLayers.append( layerNickname( *layer->layer() ) );
439 }
440 }
441}
442
443void QgsWmsRenderContext::searchLayersToRender()
444{
445 mLayersToRender.clear();
446 mStyles.clear();
447 mSlds.clear();
448
449 if ( !mParameters.sldBody().isEmpty() )
450 {
451 searchLayersToRenderSld();
452 }
453 else
454 {
455 searchLayersToRenderStyle();
456 }
457
458 if ( mFlags & AddQueryLayers )
459 {
460 const QStringList queryLayerNames = flattenedQueryLayers( mParameters.queryLayersNickname() );
461 for ( const QString &layerName : queryLayerNames )
462 {
463 const QList<QgsMapLayer *> layers = mNicknameLayers.values( layerName );
464 for ( QgsMapLayer *lyr : layers )
465 {
466 if ( !mLayersToRender.contains( lyr ) )
467 {
468 if ( !addLayerToRender( lyr ) )
469 {
470 throw QgsSecurityException( u"Your are not allowed to access the layer %1"_s.arg( lyr->name() ) );
471 }
472 }
473 }
474 }
475 }
476
477 if ( mFlags & AddAllLayers )
478 {
479 const QStringList queryLayerNames = flattenedQueryLayers( mParameters.allLayersNickname() );
480 for ( const QString &layerName : queryLayerNames )
481 {
482 const QList<QgsMapLayer *> layers = mNicknameLayers.values( layerName );
483 for ( QgsMapLayer *lyr : layers )
484 {
485 if ( !mLayersToRender.contains( lyr ) )
486 {
487 if ( !addLayerToRender( lyr ) )
488 {
489 throw QgsSecurityException( u"Your are not allowed to access the layer %1"_s.arg( lyr->name() ) );
490 }
491 }
492 }
493 }
494 }
495}
496
497void QgsWmsRenderContext::searchLayersToRenderSld()
498{
499 const QString sld = mParameters.sldBody();
500
501 if ( sld.isEmpty() )
502 {
503 return;
504 }
505
506 QDomDocument doc;
507 ( void ) doc.setContent( sld, true );
508 QDomElement docEl = doc.documentElement();
509
510 QDomElement root = doc.firstChildElement( "StyledLayerDescriptor" );
511 QDomElement namedElem = root.firstChildElement( "NamedLayer" );
512
513 if ( docEl.isNull() )
514 {
515 return;
516 }
517
518 QDomNodeList named = docEl.elementsByTagName( "NamedLayer" );
519 for ( int i = 0; i < named.size(); ++i )
520 {
521 QDomNodeList names = named.item( i ).toElement().elementsByTagName( "Name" );
522 if ( !names.isEmpty() )
523 {
524 QString lname = names.item( 0 ).toElement().text();
525 if ( mNicknameLayers.contains( lname ) )
526 {
527 mSlds[lname] = namedElem;
528 for ( const auto layer : mNicknameLayers.values( lname ) )
529 {
530 if ( !addLayerToRender( layer ) )
531 {
532 throw QgsSecurityException( u"Your are not allowed to access the layer %1"_s.arg( layer->name() ) );
533 }
534 }
535 }
536 else if ( mLayerGroups.contains( lname ) )
537 {
539 {
540 QgsWmsParameter param( QgsWmsParameter::LAYER );
541 param.mValue = lname;
542 throw QgsBadRequestException( QgsServiceException::OGC_LayerNotDefined, param );
543 }
544
545 bool layerAdded = false;
546 for ( QgsMapLayer *layer : mLayerGroups[lname] )
547 {
548 // Insert only allowed layers
549 if ( checkLayerReadPermissions( layer ) )
550 {
551 const QString name = layerNickname( *layer );
552 mSlds[name] = namedElem;
553 mLayersToRender.insert( 0, layer );
554 layerAdded = true;
555 }
556 }
557 // No layers have been added, consider the group
558 // as non-existent.
559 if ( !layerAdded )
560 {
561 QgsWmsParameter param( QgsWmsParameter::LAYER );
562 param.mValue = lname;
563 throw QgsBadRequestException( QgsServiceException::OGC_LayerNotDefined, param );
564 }
565 }
566 else
567 {
568 QgsWmsParameter param( QgsWmsParameter::LAYER );
569 param.mValue = lname;
570 throw QgsBadRequestException( QgsServiceException::OGC_LayerNotDefined, param );
571 }
572 }
573 }
574}
575
576void QgsWmsRenderContext::searchLayersToRenderStyle()
577{
578 for ( const QgsWmsParametersLayer &param : mParameters.layersParameters() )
579 {
580 const QString nickname = param.mNickname;
581 const QString style = param.mStyle;
582
583 if ( !param.mExternalUri.isEmpty() && ( mFlags & AddExternalLayers ) )
584 {
585 std::unique_ptr<QgsMapLayer> layer = std::make_unique<QgsRasterLayer>( param.mExternalUri, param.mNickname, u"wms"_s );
586
587 if ( layer->isValid() )
588 {
589 // to delete later
590 mExternalLayers.append( layer.release() );
591 auto lyr = mExternalLayers.last();
592 if ( !addLayerToRender( lyr ) )
593 {
594 throw QgsSecurityException( u"Your are not allowed to access the layer %1"_s.arg( lyr->name() ) );
595 }
596 }
597 }
598 else if ( mNicknameLayers.contains( nickname ) )
599 {
600 if ( !style.isEmpty() )
601 {
602 mStyles[nickname] = style;
603 }
604
605 for ( const auto layer : mNicknameLayers.values( nickname ) )
606 {
607 if ( !addLayerToRender( layer ) )
608 {
609 throw QgsSecurityException( u"Your are not allowed to access the layer %1"_s.arg( layer->name() ) );
610 }
611 }
612 }
613 else if ( mLayerGroups.contains( nickname ) )
614 {
616 {
617 QgsWmsParameter param( QgsWmsParameter::LAYER );
618 param.mValue = nickname;
619 throw QgsBadRequestException( QgsServiceException::OGC_LayerNotDefined, param );
620 }
621 // Reverse order of layers from a group
622 QList<QString> layersFromGroup;
623 for ( QgsMapLayer *layer : mLayerGroups[nickname] )
624 {
625 const QString nickname = layerNickname( *layer );
626 if ( !style.isEmpty() )
627 {
628 mStyles[nickname] = style;
629 }
630 layersFromGroup.push_front( nickname );
631 }
632
633 bool layerAdded = false;
634 for ( const auto &name : layersFromGroup )
635 {
636 for ( const auto layer : mNicknameLayers.values( name ) )
637 {
638 if ( addLayerToRender( layer ) )
639 {
640 layerAdded = true;
641 }
642 }
643 }
644 // No layers have been added, consider the group
645 // as non-existent.
646 if ( !layerAdded )
647 {
648 QgsWmsParameter param( QgsWmsParameter::LAYER );
649 param.mValue = nickname;
650 throw QgsBadRequestException( QgsServiceException::OGC_LayerNotDefined, param );
651 }
652 }
653 else
654 {
655 QgsWmsParameter param( QgsWmsParameter::LAYER );
656 param.mValue = nickname;
657 throw QgsBadRequestException( QgsServiceException::OGC_LayerNotDefined, param );
658 }
659 }
660}
661
662bool QgsWmsRenderContext::layerScaleVisibility( const QString &name ) const
663{
664 bool visible = false;
665
666 if ( !mNicknameLayers.contains( name ) )
667 {
668 return visible;
669 }
670
671 const QList<QgsMapLayer *> layers = mNicknameLayers.values( name );
672 for ( QgsMapLayer *layer : layers )
673 {
674 bool scaleBasedVisibility = layer->hasScaleBasedVisibility();
675 bool useScaleConstraint = ( scaleDenominator() > 0 && scaleBasedVisibility );
676
677 if ( !useScaleConstraint || layer->isInScaleRange( scaleDenominator() ) )
678 {
679 visible = true;
680 }
681 }
682
683 return visible;
684}
685
686QMap<QString, QList<QgsMapLayer *>> QgsWmsRenderContext::layerGroups() const
687{
688 return mLayerGroups;
689}
690
692{
693 int width = mParameters.widthAsInt();
694
695 // May use SRCWIDTH to define image map size
696 if ( ( mFlags & UseSrcWidthHeight ) && mParameters.srcWidthAsInt() > 0 )
697 {
698 width = mParameters.srcWidthAsInt();
699 }
700
701 return width;
702}
703
705{
706 int height = mParameters.heightAsInt();
707
708 // May use SRCHEIGHT to define image map size
709 if ( ( mFlags & UseSrcWidthHeight ) && mParameters.srcHeightAsInt() > 0 )
710 {
711 height = mParameters.srcHeightAsInt();
712 }
713
714 return height;
715}
716
721
722bool QgsWmsRenderContext::isValidWidthHeight( int width, int height ) const
723{
724 if ( width <= 0 || height <= 0 )
725 return false;
726
727 //test if maxWidth / maxHeight are set in the project or as an env variable
728 //and WIDTH / HEIGHT parameter is in the range allowed range
729 //WIDTH
730 const int wmsMaxWidthProj = QgsServerProjectUtils::wmsMaxWidth( *mProject );
731 const int wmsMaxWidthEnv = settings().wmsMaxWidth();
732 int wmsMaxWidth;
733 if ( wmsMaxWidthEnv != -1 && wmsMaxWidthProj != -1 )
734 {
735 // both are set, so we take the more conservative one
736 wmsMaxWidth = std::min( wmsMaxWidthProj, wmsMaxWidthEnv );
737 }
738 else
739 {
740 // none or one are set, so we take the bigger one which is the one set or -1
741 wmsMaxWidth = std::max( wmsMaxWidthProj, wmsMaxWidthEnv );
742 }
743
744 if ( wmsMaxWidth != -1 && width > wmsMaxWidth )
745 {
746 return false;
747 }
748
749 //HEIGHT
750 const int wmsMaxHeightProj = QgsServerProjectUtils::wmsMaxHeight( *mProject );
751 const int wmsMaxHeightEnv = settings().wmsMaxHeight();
752 int wmsMaxHeight;
753 if ( wmsMaxHeightEnv != -1 && wmsMaxHeightProj != -1 )
754 {
755 // both are set, so we take the more conservative one
756 wmsMaxHeight = std::min( wmsMaxHeightProj, wmsMaxHeightEnv );
757 }
758 else
759 {
760 // none or one are set, so we take the bigger one which is the one set or -1
761 wmsMaxHeight = std::max( wmsMaxHeightProj, wmsMaxHeightEnv );
762 }
763
764 if ( wmsMaxHeight != -1 && height > wmsMaxHeight )
765 {
766 return false;
767 }
768
769 // Sanity check from internal QImage checks
770 // (see QImageData::calculateImageParameters() in qimage_p.h)
771 // this is to report a meaningful error message in case of
772 // image creation failure and to differentiate it from out
773 // of memory conditions.
774
775 // depth for now it cannot be anything other than 32, but I don't like
776 // to hardcode it: I hope we will support other depths in the future.
777 int depth = 32;
778 switch ( mParameters.format() )
779 {
782 default:
783 depth = 32;
784 }
785
786 if ( width > ( std::numeric_limits<int>::max() - 31 ) / depth )
787 return false;
788
789 const int bytes_per_line = ( ( width * depth + 31 ) >> 5 ) << 2; // bytes per scanline (must be multiple of 4)
790
791 if ( std::numeric_limits<int>::max() / bytes_per_line < height
792 || std::numeric_limits<int>::max() / sizeof( uchar * ) < static_cast<uint>( height ) )
793 {
794 return false;
795 }
796
797 return true;
798}
799
801{
802 double buffer;
803 if ( mFlags & UseTileBuffer )
804 {
805 const QgsRectangle extent = mParameters.bboxAsRectangle();
806 if ( !mParameters.bbox().isEmpty() && extent.isEmpty() )
807 {
809 }
810 buffer = tileBuffer() * ( extent.width() / mapWidth );
811 }
812 else
813 {
814 buffer = 0;
815 }
816 return buffer;
817}
818
819QSize QgsWmsRenderContext::mapSize( const bool aspectRatio ) const
820{
821 int width = mapWidth();
822 int height = mapHeight();
823
824 // Adapt width / height if the aspect ratio does not correspond with the BBOX.
825 // Required by WMS spec. 1.3.
826 if ( aspectRatio
827 && mParameters.versionAsNumber() >= QgsProjectVersion( 1, 3, 0 ) )
828 {
829 QgsRectangle extent = mParameters.bboxAsRectangle();
830 if ( !mParameters.bbox().isEmpty() && extent.isEmpty() )
831 {
833 }
834
835 QString crs = mParameters.crs();
836 if ( crs.compare( "CRS:84", Qt::CaseInsensitive ) == 0 )
837 {
838 crs = QString( "EPSG:4326" );
839 extent.invert();
840 }
841
843 if ( outputCrs.hasAxisInverted() )
844 {
845 extent.invert();
846 }
847
848 if ( !extent.isEmpty() && height > 0 && width > 0 )
849 {
850 const double mapRatio = extent.width() / extent.height();
851 const double imageRatio = static_cast<double>( width ) / static_cast<double>( height );
852 if ( !qgsDoubleNear( mapRatio, imageRatio, 0.0001 ) )
853 {
854 // inspired by MapServer, mapdraw.c L115
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;
858 }
859 }
860 }
861
862 if ( width <= 0 )
863 {
865 }
866 else if ( height <= 0 )
867 {
869 }
870
871 return QSize( width, height );
872}
873
874void QgsWmsRenderContext::removeUnwantedLayers()
875{
876 QList<QgsMapLayer *> layers;
877
878 for ( QgsMapLayer *layer : mLayersToRender )
879 {
880 const QString nickname = layerNickname( *layer );
881
882 if ( !isExternalLayer( nickname ) )
883 {
884 if ( !layerScaleVisibility( nickname ) )
885 continue;
886
887 if ( mRestrictedLayers.contains( nickname ) )
888 continue;
889
890 if ( mFlags & UseWfsLayersOnly )
891 {
893 {
894 continue;
895 }
896
897 const QStringList wfsLayers = QgsServerProjectUtils::wfsLayerIds( *mProject );
898 if ( !wfsLayers.contains( layer->id() ) )
899 {
900 continue;
901 }
902 }
903 }
904
905 layers.append( layer );
906 }
907
908 mLayersToRender = layers;
909}
910
911bool QgsWmsRenderContext::isExternalLayer( const QString &name ) const
912{
913 for ( const auto &layer : mExternalLayers )
914 {
915 if ( layerNickname( *layer ).compare( name ) == 0 )
916 return true;
917 }
918
919 return false;
920}
921
922bool QgsWmsRenderContext::checkLayerReadPermissions( QgsMapLayer *layer ) const
923{
924#ifdef HAVE_SERVER_PYTHON_PLUGINS
925 if ( !accessControl()->layerReadPermission( layer ) )
926 {
927 QString msg = u"Checking forbidden access for layer: %1"_s.arg( layer->name() );
929 return false;
930 }
931#endif
932 Q_UNUSED( layer )
933 return true;
934}
935
936#ifdef HAVE_SERVER_PYTHON_PLUGINS
937QgsAccessControl *QgsWmsRenderContext::accessControl() const
938{
939 return mInterface->accessControls();
940}
941#endif
942
944{
945 mSocketFeedback = feedback;
946}
947
949{
950 return mSocketFeedback;
951}
@ Info
Information message.
Definition qgis.h:160
@ Vector
Vector layer.
Definition qgis.h:194
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.
Definition qgsfeedback.h:44
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.
Definition qgsmaplayer.h:83
QString name
Definition qgsmaplayer.h:87
QString id
Definition qgsmaplayer.h:86
Qgis::LayerType type
Definition qgsmaplayer.h:93
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,...
Definition qgsproject.h:112
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.
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 &parameters)
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).
Definition qgis.h:6900
const double OGC_PX_M