QGIS API Documentation  3.25.0-Master (10b47c2603)
qgswmsdescribelayer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgswmsdescribelayer.cpp
3  -------------------------
4  begin : December 20 , 2016
5  copyright : (C) 2007 by Marco Hugentobler (original code)
6  (C) 2014 by Alessandro Pasotti (original code)
7  (C) 2016 by David Marteau
8  email : marco dot hugentobler at karto dot baug dot ethz dot ch
9  a dot pasotti at itopen dot it
10  david dot marteau at 3liz dot com
11  ***************************************************************************/
12 
13 /***************************************************************************
14  * *
15  * This program is free software; you can redistribute it and/or modify *
16  * it under the terms of the GNU General Public License as published by *
17  * the Free Software Foundation; either version 2 of the License, or *
18  * (at your option) any later version. *
19  * *
20  ***************************************************************************/
21 
22 #include "qgswmsutils.h"
23 #include "qgswmsrequest.h"
24 #include "qgswmsserviceexception.h"
25 #include "qgswmsdescribelayer.h"
26 #include "qgsserverprojectutils.h"
27 #include "qgsproject.h"
28 
29 namespace QgsWms
30 {
31 
32  void writeDescribeLayer( QgsServerInterface *serverIface, const QgsProject *project,
33  const QgsWmsRequest &request, QgsServerResponse &response )
34  {
35  const QDomDocument doc = describeLayer( serverIface, project, request );
36  response.setHeader( QStringLiteral( "Content-Type" ), QStringLiteral( "text/xml; charset=utf-8" ) );
37  response.write( doc.toByteArray() );
38  }
39 
40  // DescribeLayer is defined for WMS1.1.1/SLD1.0 and in WMS 1.3.0 SLD Extension
41  QDomDocument describeLayer( QgsServerInterface *serverIface, const QgsProject *project,
42  const QgsWmsRequest &request )
43  {
44  const QgsServerRequest::Parameters parameters = request.parameters();
45 
46  if ( !parameters.contains( QStringLiteral( "SLD_VERSION" ) ) )
47  {
48  throw QgsServiceException( QStringLiteral( "MissingParameterValue" ),
49  QStringLiteral( "SLD_VERSION is mandatory for DescribeLayer operation" ), 400 );
50  }
51  if ( parameters[ QStringLiteral( "SLD_VERSION" )] != QLatin1String( "1.1.0" ) )
52  {
53  throw QgsServiceException( QStringLiteral( "InvalidParameterValue" ),
54  QStringLiteral( "SLD_VERSION = %1 is not supported" ).arg( parameters[ QStringLiteral( "SLD_VERSION" )] ), 400 );
55  }
56 
57  if ( !parameters.contains( QStringLiteral( "LAYERS" ) ) )
58  {
59  throw QgsServiceException( QStringLiteral( "MissingParameterValue" ),
60  QStringLiteral( "LAYERS is mandatory for DescribeLayer operation" ), 400 );
61  }
62 
63 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
64  QStringList layersList = parameters[ QStringLiteral( "LAYERS" )].split( ',', QString::SkipEmptyParts );
65 #else
66  const QStringList layersList = parameters[ QStringLiteral( "LAYERS" )].split( ',', Qt::SkipEmptyParts );
67 #endif
68  if ( layersList.isEmpty() )
69  {
70  throw QgsServiceException( QStringLiteral( "InvalidParameterValue" ), QStringLiteral( "Layers is empty" ), 400 );
71  }
72  QDomDocument myDocument = QDomDocument();
73 
74  const QDomNode header = myDocument.createProcessingInstruction( QStringLiteral( "xml" ), QStringLiteral( "version=\"1.0\" encoding=\"UTF-8\"" ) );
75  myDocument.appendChild( header );
76 
77  // Create the root element
78  QDomElement root = myDocument.createElementNS( QStringLiteral( "http://www.opengis.net/sld" ), QStringLiteral( "DescribeLayerResponse" ) );
79  root.setAttribute( QStringLiteral( "xsi:schemaLocation" ), QStringLiteral( "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/DescribeLayer.xsd" ) );
80  root.setAttribute( QStringLiteral( "xmlns:ows" ), QStringLiteral( "http://www.opengis.net/ows" ) );
81  root.setAttribute( QStringLiteral( "xmlns:se" ), QStringLiteral( "http://www.opengis.net/se" ) );
82  root.setAttribute( QStringLiteral( "xmlns:xlink" ), QStringLiteral( "http://www.w3.org/1999/xlink" ) );
83  root.setAttribute( QStringLiteral( "xmlns:xsi" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema-instance" ) );
84  myDocument.appendChild( root );
85 
86  // store the Version element
87  QDomElement versionNode = myDocument.createElement( QStringLiteral( "Version" ) );
88  versionNode.appendChild( myDocument.createTextNode( QStringLiteral( "1.1.0" ) ) );
89  root.appendChild( versionNode );
90 
91  // get the wms service url defined in project or keep the one from the
92  // request url
93  const QString wmsHrefString = serviceUrl( request, project, *serverIface->serverSettings() ).toString();
94 
95  // get the wfs service url defined in project or take the same as the
96  // wms service url
97  QString wfsHrefString = QgsServerProjectUtils::wfsServiceUrl( *project, request, *serverIface->serverSettings() );
98  if ( wfsHrefString.isEmpty() )
99  {
100  wfsHrefString = wmsHrefString;
101  }
102 
103  // get the wcs service url defined in project or take the same as the
104  // wms service url
105  QString wcsHrefString = QgsServerProjectUtils::wcsServiceUrl( *project, request, *serverIface->serverSettings() );
106  if ( wcsHrefString.isEmpty() )
107  {
108  wcsHrefString = wmsHrefString;
109  }
110 
111  // access control
112 #ifdef HAVE_SERVER_PYTHON_PLUGINS
113  QgsAccessControl *accessControl = serverIface->accessControls();
114 #else
115  ( void )serverIface;
116 #endif
117  // Use layer ids
118  const bool useLayerIds = QgsServerProjectUtils::wmsUseLayerIds( *project );
119  // WMS restricted layers
120  const QStringList restrictedLayers = QgsServerProjectUtils::wmsRestrictedLayers( *project );
121  // WFS layers
122  const QStringList wfsLayerIds = QgsServerProjectUtils::wfsLayerIds( *project );
123  // WCS layers
124  const QStringList wcsLayerIds = QgsServerProjectUtils::wcsLayerIds( *project );
125 
126  for ( QgsMapLayer *layer : project->mapLayers() )
127  {
128  QString name = layer->name();
129  if ( useLayerIds )
130  name = layer->id();
131  else if ( !layer->shortName().isEmpty() )
132  name = layer->shortName();
133 
134  if ( !layersList.contains( name ) )
135  {
136  continue;
137  }
138 
139  //unpublished layer
140  if ( restrictedLayers.contains( layer->name() ) )
141  {
142  throw QgsSecurityException( QStringLiteral( "You are not allowed to access to this layer" ) );
143  }
144 
145 #ifdef HAVE_SERVER_PYTHON_PLUGINS
146  if ( accessControl && !accessControl->layerReadPermission( layer ) )
147  {
148  throw QgsSecurityException( QStringLiteral( "You are not allowed to access to this layer" ) );
149  }
150 #endif
151 
152  // Create the NamedLayer element
153  QDomElement layerNode = myDocument.createElement( QStringLiteral( "LayerDescription" ) );
154  root.appendChild( layerNode );
155 
156  // store the owsType element
157  QDomElement typeNode = myDocument.createElement( QStringLiteral( "owsType" ) );
158  // store the se:OnlineResource element
159  QDomElement oResNode = myDocument.createElement( QStringLiteral( "se:OnlineResource" ) );
160  oResNode.setAttribute( QStringLiteral( "xlink:type" ), QStringLiteral( "simple" ) );
161  // store the TypeName element
162  QDomElement nameNode = myDocument.createElement( QStringLiteral( "TypeName" ) );
163  switch ( layer->type() )
164  {
166  {
167  typeNode.appendChild( myDocument.createTextNode( QStringLiteral( "wfs" ) ) );
168 
169  if ( wfsLayerIds.indexOf( layer->id() ) != -1 )
170  {
171  oResNode.setAttribute( QStringLiteral( "xlink:href" ), wfsHrefString );
172  }
173 
174  // store the se:FeatureTypeName element
175  QDomElement typeNameNode = myDocument.createElement( QStringLiteral( "se:FeatureTypeName" ) );
176  typeNameNode.appendChild( myDocument.createTextNode( name ) );
177  nameNode.appendChild( typeNameNode );
178  break;
179  }
181  {
182  typeNode.appendChild( myDocument.createTextNode( QStringLiteral( "wcs" ) ) );
183 
184  if ( wcsLayerIds.indexOf( layer->id() ) != -1 )
185  {
186  oResNode.setAttribute( QStringLiteral( "xlink:href" ), wcsHrefString );
187  }
188 
189  // store the se:CoverageTypeName element
190  QDomElement typeNameNode = myDocument.createElement( QStringLiteral( "se:CoverageTypeName" ) );
191  typeNameNode.appendChild( myDocument.createTextNode( name ) );
192  nameNode.appendChild( typeNameNode );
193  break;
194  }
195 
202  break;
203  }
204  layerNode.appendChild( typeNode );
205  layerNode.appendChild( oResNode );
206  layerNode.appendChild( nameNode );
207  }
208 
209  return myDocument;
210  }
211 
212 } // namespace QgsWms
A helper class that centralizes restrictions given by all the access control filter plugins.
bool layerReadPermission(const QgsMapLayer *layer) const
Returns the layer read right.
Base class for all map layer types.
Definition: qgsmaplayer.h:73
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition: qgsproject.h:104
QMap< QString, QgsMapLayer * > mapLayers(const bool validOnly=false) const
Returns a map of all registered layers by layer ID.
QgsServerInterface Class defining interfaces exposed by QGIS Server and made available to plugins.
virtual QgsAccessControl * accessControls() const =0
Gets the registered access control filters.
virtual QgsServerSettings * serverSettings()=0
Returns the server settings.
QgsServerRequest::Parameters parameters() const
Returns a map of query parameters with keys converted to uppercase.
QMap< QString, QString > Parameters
QgsServerResponse Class defining response interface passed to services QgsService::executeRequest() m...
virtual void write(const QString &data)
Write string This is a convenient method that will write directly to the underlying I/O device.
virtual void setHeader(const QString &key, const QString &value)=0
Set Header entry Add Header entry to the response Note that it is usually an error to set Header afte...
Exception thrown when data access violates access controls.
Exception class for WMS service exceptions.
Class defining request interface passed to WMS service.
Definition: qgswmsrequest.h:35
@ PointCloudLayer
Point cloud layer. Added in QGIS 3.18.
@ MeshLayer
Mesh layer. Added in QGIS 3.2.
@ VectorLayer
Vector layer.
@ RasterLayer
Raster layer.
@ GroupLayer
Composite group layer. Added in QGIS 3.24.
@ VectorTileLayer
Vector tile layer. Added in QGIS 3.14.
@ AnnotationLayer
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
@ PluginLayer
Plugin based layer.
SERVER_EXPORT QString wcsServiceUrl(const QgsProject &project, const QgsServerRequest &request=QgsServerRequest(), const QgsServerSettings &settings=QgsServerSettings())
Returns the WCS service url.
SERVER_EXPORT bool wmsUseLayerIds(const QgsProject &project)
Returns if layer ids are used as name in WMS.
SERVER_EXPORT QStringList wfsLayerIds(const QgsProject &project)
Returns the Layer ids list defined in a QGIS project as published in WFS.
SERVER_EXPORT QStringList wmsRestrictedLayers(const QgsProject &project)
Returns the restricted layer name list.
SERVER_EXPORT QString wfsServiceUrl(const QgsProject &project, const QgsServerRequest &request=QgsServerRequest(), const QgsServerSettings &settings=QgsServerSettings())
Returns the WFS service url.
SERVER_EXPORT QStringList wcsLayerIds(const QgsProject &project)
Returns the Layer ids list defined in a QGIS project as published in WCS.
Median cut implementation.
QDomDocument describeLayer(QgsServerInterface *serverIface, const QgsProject *project, const QgsWmsRequest &request)
DescribeLayer is defined for WMS1.1.1/SLD1.0 and in WMS 1.3.0 SLD Extension.
void writeDescribeLayer(QgsServerInterface *serverIface, const QgsProject *project, const QgsWmsRequest &request, QgsServerResponse &response)
Output GetMap response in DXF format.
QUrl serviceUrl(const QgsServerRequest &request, const QgsProject *project, const QgsServerSettings &settings)
Returns WMS service URL.
Definition: qgswmsutils.cpp:33