QGIS API Documentation 3.32.0-Lima (311a8cb8a6)
qgsserverparameters.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsserverparameters.cpp
3 --------------------
4 begin : Jun 27, 2018
5 copyright : (C) 2018 by Paul Blottiere
6 email : paul dot blottiere at oslandia dot com
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
19#include "qgsserverparameters.h"
20#include "qgsserverexception.h"
21#include "qgsmessagelog.h"
22#include "qgsvariantutils.h"
23#include <QObject>
24#include <QUrl>
25#include <QNetworkReply>
26#include <QNetworkRequest>
27#include <QEventLoop>
28
29//
30// QgsServerParameterDefinition
31//
33 const QVariant defaultValue )
34 : mType( type )
35 , mDefaultValue( defaultValue )
36{
37}
38
40{
41 return QVariant::typeToName( mType );
42}
43
45{
46 ok = true;
47 QColor color = mDefaultValue.value<QColor>();
48 QString cStr = mValue.toString();
49
50 if ( !cStr.isEmpty() )
51 {
52 // support hexadecimal notation to define colors
53 if ( cStr.startsWith( QLatin1String( "0x" ), Qt::CaseInsensitive ) )
54 {
55 cStr.replace( 0, 2, QStringLiteral( "#" ) );
56 }
57
58 color = QColor( cStr );
59
60 ok = color.isValid();
61 }
62
63 return color;
64}
65
66QString QgsServerParameterDefinition::toString( const bool defaultValue ) const
67{
68 QString value = mValue.toString();
69
70 if ( value.isEmpty() && defaultValue )
71 value = mDefaultValue.toString();
72
73 return value;
74}
75
76QStringList QgsServerParameterDefinition::toStringList( const char delimiter, const bool skipEmptyParts ) const
77{
78 if ( skipEmptyParts )
79 {
80#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
81 return toString().split( delimiter, QString::SkipEmptyParts );
82#else
83 return toString().split( delimiter, Qt::SkipEmptyParts );
84#endif
85 }
86 else
87 {
88 QStringList list;
89 if ( !toString().isEmpty() )
90 {
91#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
92 list = toString().split( delimiter, QString::KeepEmptyParts );
93#else
94 list = toString().split( delimiter, Qt::KeepEmptyParts );
95#endif
96 }
97 return list;
98 }
99}
100
101QList<QgsGeometry> QgsServerParameterDefinition::toGeomList( bool &ok, const char delimiter ) const
102{
103 ok = true;
104 QList<QgsGeometry> geoms;
105
106 const auto constStringList( toStringList( delimiter ) );
107 for ( const auto &wkt : constStringList )
108 {
109 const QgsGeometry g( QgsGeometry::fromWkt( wkt ) );
110
111 if ( g.isGeosValid() )
112 {
113 geoms.append( g );
114 }
115 else
116 {
117 ok = false;
118 return QList<QgsGeometry>();
119 }
120 }
121
122 return geoms;
123}
124
126{
127 int pos = 0;
128 QStringList filters;
129 const QString filter = toString();
130
131 while ( pos < filter.size() )
132 {
133 if ( pos + 1 < filter.size() && filter[pos] == '(' && filter[pos + 1] == '<' )
134 {
135 // OGC filter on multiple layers
136 int posEnd = filter.indexOf( "Filter>)", pos );
137 if ( posEnd < 0 )
138 {
139 posEnd = filter.size();
140 }
141 filters.append( filter.mid( pos + 1, posEnd - pos + 6 ) );
142 pos = posEnd + 8;
143 }
144 else if ( pos + 1 < filter.size() && filter[pos] == '(' && filter[pos + 1] == ')' )
145 {
146 // empty OGC filter
147 filters.append( "" );
148 pos += 2;
149 }
150 else if ( filter[pos] == '<' && pos + 7 < filter.size() && filter.mid( pos + 1, 6 ).compare( QLatin1String( "Filter" ) ) == 0 )
151 {
152 // Single OGC filter
153 filters.append( filter.mid( pos ) );
154 break;
155 }
156 else
157 {
158 pos += 1;
159 }
160 }
161
162 return filters;
163}
164
166{
167 int pos = 0;
168 QStringList filters;
169 const QString filter = toString();
170
171 auto isOgcFilter = [filter]()
172 {
173 return filter.contains( QStringLiteral( "<Filter>" ) ) || filter.contains( QStringLiteral( "()" ) );
174 };
175
176 while ( pos < filter.size() )
177 {
178 int posEnd = filter.indexOf( ';', pos );
179
180 if ( posEnd == pos + 1 )
181 {
182 if ( ! isOgcFilter() )
183 filters.append( QString() );
184 pos = posEnd;
185 continue;
186 }
187
188 if ( ! isOgcFilter() )
189 filters.append( filter.mid( pos, posEnd - pos ) );
190
191 if ( posEnd < 0 )
192 {
193 pos = filter.size();
194 }
195 else
196 {
197 pos = posEnd + 1;
198 }
199 }
200
201 if ( ! filter.isEmpty() && filter.back() == ';' )
202 {
203 filters.append( QString() );
204 }
205
206 return filters;
207}
208
209QList<QColor> QgsServerParameterDefinition::toColorList( bool &ok, const char delimiter ) const
210{
211 ok = true;
212 QList<QColor> colors;
213
214 const auto constStringList( toStringList( delimiter ) );
215 for ( const auto &part : constStringList )
216 {
217 QString cStr( part );
218 if ( !cStr.isEmpty() )
219 {
220 // support hexadecimal notation to define colors
221 if ( cStr.startsWith( QLatin1String( "0x" ), Qt::CaseInsensitive ) )
222 {
223 cStr.replace( 0, 2, QStringLiteral( "#" ) );
224 }
225
226 const QColor color = QColor( cStr );
227 ok = color.isValid();
228
229 if ( !ok )
230 {
231 return QList<QColor>();
232 }
233
234 colors.append( color );
235 }
236 }
237
238 return colors;
239}
240
241QList<int> QgsServerParameterDefinition::toIntList( bool &ok, const char delimiter ) const
242{
243 ok = true;
244 QList<int> ints;
245
246 const auto constStringList( toStringList( delimiter ) );
247 for ( const auto &part : constStringList )
248 {
249 const int val = part.toInt( &ok );
250
251 if ( !ok )
252 {
253 return QList<int>();
254 }
255
256 ints.append( val );
257 }
258
259 return ints;
260}
261
262QList<double> QgsServerParameterDefinition::toDoubleList( bool &ok, const char delimiter ) const
263{
264 ok = true;
265 QList<double> vals;
266
267 const auto constStringList( toStringList( delimiter ) );
268 for ( const auto &part : constStringList )
269 {
270 const double val = part.toDouble( &ok );
271
272 if ( !ok )
273 {
274 return QList<double>();
275 }
276
277 vals.append( val );
278 }
279
280 return vals;
281}
282
284{
285 ok = true;
286 QgsRectangle extent;
287
288 if ( !mValue.toString().isEmpty() )
289 {
290 QStringList corners = mValue.toString().split( ',' );
291
292 if ( corners.size() == 4 )
293 {
294 double d[4];
295
296 for ( int i = 0; i < 4; i++ )
297 {
298 corners[i].replace( ' ', '+' );
299 d[i] = corners[i].toDouble( &ok );
300 if ( !ok )
301 {
302 return QgsRectangle();
303 }
304 }
305
306 if ( d[0] > d[2] || d[1] > d[3] )
307 {
308 ok = false;
309 return QgsRectangle();
310 }
311
312 extent = QgsRectangle( d[0], d[1], d[2], d[3] );
313 }
314 else
315 {
316 ok = false;
317 return QgsRectangle();
318 }
319 }
320
321 return extent;
322}
323
325{
326 ok = true;
327
328 // Get URL
329 const QUrl url = toUrl( ok );
330 if ( !ok )
331 {
332 return QString();
333 }
334
335 QNetworkRequest request( url );
336 request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
337 request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true );
338
339 // fetching content
341 const QgsBlockingNetworkRequest::ErrorCode errorCode = newReq.get( request, false );
342
343 if ( errorCode != QgsBlockingNetworkRequest::NoError )
344 {
345 ok = false;
347 QObject::tr( "Request failed [error: %1 - url: %2]" ).arg( newReq.errorMessage(), url.toString() ),
348 QStringLiteral( "Server" ) );
349 return QString();
350 }
351
352 QgsNetworkReplyContent reply = newReq.reply();
353
354 ok = !reply.content().isEmpty();
355 return reply.content();
356}
357
359{
360 ok = true;
361 QUrl val;
362
363 if ( !mValue.toString().isEmpty() )
364 {
365 val = mValue.toUrl();
366 }
367
368 ok = ( !val.isEmpty() && val.isValid() );
369 return val;
370}
371
373{
374 ok = true;
375 int val = mDefaultValue.toInt();
376
377 if ( !mValue.toString().isEmpty() )
378 {
379 val = mValue.toInt( &ok );
380 }
381
382 return val;
383}
384
386{
387 int val = mDefaultValue.toBool();
388
389 if ( !mValue.toString().isEmpty() )
390 {
391 val = mValue.toBool();
392 }
393
394 return val;
395}
396
398{
399 ok = true;
400 double val = mDefaultValue.toDouble();
401
402 if ( !mValue.toString().isEmpty() )
403 {
404 val = mValue.toDouble( &ok );
405 }
406
407 return val;
408}
409
411{
412 return mValue.canConvert( mType );
413}
414
416{
417 throw QgsBadRequestException( QStringLiteral( "Invalid Parameter" ), msg );
418}
419
420//
421// QgsServerParameter
422//
424 const QVariant::Type type, const QVariant defaultValue )
425 : QgsServerParameterDefinition( type, defaultValue )
426 , mName( name )
427{
428}
429
431{
433 {
434 return QStringLiteral( "VERSION" );
435 }
436 else
437 {
438 const QMetaEnum metaEnum( QMetaEnum::fromType<QgsServerParameter::Name>() );
439 return metaEnum.valueToKey( name );
440 }
441}
442
444{
445 if ( name.compare( QLatin1String( "VERSION" ) ) == 0 )
446 {
448 }
449 else
450 {
451 const QMetaEnum metaEnum( QMetaEnum::fromType<QgsServerParameter::Name>() );
452 return ( QgsServerParameter::Name ) metaEnum.keyToValue( name.toUpper().toStdString().c_str() );
453 }
454}
455
457{
458 const QString msg = QString( "%1 ('%2') cannot be converted into %3" ).arg( name( mName ), mValue.toString(), typeName() );
460}
461
462//
463// QgsServerParameters
464//
466{
472}
473
476{
477 mUrlQuery = query;
478 load( query );
479}
480
481void QgsServerParameters::save( const QgsServerParameter &parameter )
482{
483 mParameters[ parameter.mName ] = parameter;
484}
485
486void QgsServerParameters::add( const QString &key, const QString &value )
487{
488 QUrlQuery query;
489 query.addQueryItem( key, value );
490 load( query );
491}
492
494{
495 QUrlQuery query = mUrlQuery;
496
497 if ( query.isEmpty() )
498 {
499 query.clear();
500
501 const auto constMap( toMap().toStdMap() );
502 for ( const auto &param : constMap )
503 {
504 const QString value = QUrl::toPercentEncoding( QString( param.second ) );
505 query.addQueryItem( param.first, value );
506 }
507 }
508
509 return query;
510}
511
513{
515}
516
517void QgsServerParameters::remove( const QString &key )
518{
519 if ( mUnmanagedParameters.contains( key ) )
520 {
521 mUnmanagedParameters.take( key );
522 }
523 else
524 {
525 const QgsServerParameter::Name paramName = QgsServerParameter::name( key );
526 if ( mParameters.contains( paramName ) )
527 {
528 mParameters.take( paramName );
529 }
530 }
531}
532
534{
535 return value( QgsServerParameter::MAP ).toString();
536}
537
539{
540 return value( QgsServerParameter::VERSION_SERVICE ).toString();
541}
542
544{
545 return value( QgsServerParameter::FILE_NAME ).toString();
546}
547
549{
550 QString serviceValue = value( QgsServerParameter::SERVICE ).toString();
551
552 if ( serviceValue.isEmpty() )
553 {
554 // SERVICE not mandatory for WMS 1.3.0 GetMap & GetFeatureInfo
555 if ( request() == QLatin1String( "GetMap" ) \
556 || request() == QLatin1String( "GetFeatureInfo" ) )
557 {
558 serviceValue = "WMS";
559 }
560 }
561
562 return serviceValue;
563}
564
565QMap<QString, QString> QgsServerParameters::toMap() const
566{
567 QMap<QString, QString> params = mUnmanagedParameters;
568
569 for ( const auto &parameter : mParameters.toStdMap() )
570 {
571 if ( QgsVariantUtils::isNull( parameter.second.mValue ) )
572 continue;
573
574 if ( parameter.second.mName == QgsServerParameter::VERSION_SERVICE )
575 {
576 params["VERSION"] = parameter.second.mValue.toString();
577 }
578 else
579 {
580 const QString paramName = QgsServerParameter::name( parameter.first );
581 params[paramName] = parameter.second.mValue.toString();
582 }
583 }
584
585 return params;
586}
587
589{
590 return value( QgsServerParameter::REQUEST ).toString();
591}
592
593QString QgsServerParameters::value( const QString &key ) const
594{
595 if ( ! mParameters.contains( QgsServerParameter::name( key ) ) )
596 {
597 return mUnmanagedParameters[key];
598 }
599 else
600 {
601 return value( QgsServerParameter::name( key ) ).toString();
602 }
603}
604
606{
607 return mParameters[name].mValue;
608}
609
610void QgsServerParameters::load( const QUrlQuery &query )
611{
612 // clean query string first
613 QUrlQuery cleanQuery( query );
614 cleanQuery.setQuery( query.query().replace( '+', QLatin1String( "%20" ) ) );
615
616 // load parameters
617 const auto constQueryItems( cleanQuery.queryItems( QUrl::FullyDecoded ) );
618 for ( const auto &item : constQueryItems )
619 {
620 const QgsServerParameter::Name name = QgsServerParameter::name( item.first );
621 if ( name >= 0 )
622 {
623 mParameters[name].mValue = item.second;
624 if ( ! mParameters[name].isValid() )
625 {
626 mParameters[name].raiseError();
627 }
628 }
629 else if ( item.first.compare( QLatin1String( "VERSION" ), Qt::CaseInsensitive ) == 0 )
630 {
632 mParameters[name].mValue = item.second;
633 if ( ! mParameters[name].isValid() )
634 {
635 mParameters[name].raiseError();
636 }
637 }
638 else if ( ! loadParameter( item.first, item.second ) )
639 {
640 mUnmanagedParameters[item.first.toUpper()] = item.second;
641 }
642 }
643}
644
645bool QgsServerParameters::loadParameter( const QString &, const QString & )
646{
647 return false;
648}
649
651{
652 mParameters.clear();
653 mUnmanagedParameters.clear();
654}
Exception thrown in case of malformed request.
A thread safe class for performing blocking (sync) network requests, with full support for QGIS proxy...
ErrorCode get(QNetworkRequest &request, bool forceRefresh=false, QgsFeedback *feedback=nullptr)
Performs a "get" operation on the specified request.
QString errorMessage() const
Returns the error message string, after a get(), post(), head() or put() request has been made.
@ NoError
No error was encountered.
QgsNetworkReplyContent reply() const
Returns the content of the network reply, after a get(), post(), head() or put() request has been mad...
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:164
bool isGeosValid(Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const
Checks validity of the geometry using GEOS.
static QgsGeometry fromWkt(const QString &wkt)
Creates a new geometry from a WKT string.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Encapsulates a network reply within a container which is inexpensive to copy and safe to pass between...
QByteArray content() const
Returns the reply content.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
Definition of a parameter with basic conversion methods.
QList< QgsGeometry > toGeomList(bool &ok, char delimiter=',') const
Converts the parameter into a list of geometries.
QString loadUrl(bool &ok) const
Loads the data associated to the parameter converted into an url.
QUrl toUrl(bool &ok) const
Converts the parameter into an url.
QString toString(bool defaultValue=false) const
Converts the parameter into a string.
bool toBool() const
Converts the parameter into a boolean.
QList< double > toDoubleList(bool &ok, char delimiter=',') const
Converts the parameter into a list of doubles.
QStringList toStringList(char delimiter=',', bool skipEmptyParts=true) const
Converts the parameter into a list of strings.
virtual bool isValid() const
Returns true if the parameter is valid, false otherwise.
QgsServerParameterDefinition(const QVariant::Type type=QVariant::String, const QVariant defaultValue=QVariant(""))
Constructor for QgsServerParameterDefinition.
QString typeName() const
Returns the type of the parameter as a string.
static void raiseError(const QString &msg)
Raises an exception in case of an invalid parameters.
QStringList toExpressionList() const
Converts the parameter into a list of QGIS expressions.
int toInt(bool &ok) const
Converts the parameter into an integer.
QList< int > toIntList(bool &ok, char delimiter=',') const
Converts the parameter into a list of integers.
QColor toColor(bool &ok) const
Converts the parameter into a color.
double toDouble(bool &ok) const
Converts the parameter into a double.
QgsRectangle toRectangle(bool &ok) const
Converts the parameter into a rectangle.
QList< QColor > toColorList(bool &ok, char delimiter=',') const
Converts the parameter into a list of colors.
QStringList toOgcFilterList() const
Converts the parameter into a list of OGC filters.
Parameter common to all services (WMS, WFS, ...)
QgsServerParameter::Name mName
QgsServerParameter(const QgsServerParameter::Name name=QgsServerParameter::UNKNOWN, const QVariant::Type type=QVariant::String, const QVariant defaultValue=QVariant(""))
Constructor for QgsServerParameter.
Name
Parameter's name common to all services.
void raiseError() const
Raises an error in case of an invalid conversion.
static QString name(const QgsServerParameter::Name name)
Converts a parameter's name into its string representation.
QgsServerParameters provides an interface to retrieve and manipulate global parameters received from ...
QMap< QString, QString > toMap() const
Returns all parameters in a map.
QString map() const
Returns MAP parameter as a string or an empty string if not defined.
QgsServerParameters()
Constructor.
void add(const QString &key, const QString &value)
Adds a parameter.
QString service() const
Returns SERVICE parameter as a string or an empty string if not defined.
virtual QString request() const
Returns REQUEST parameter as a string or an empty string if not defined.
void clear()
Removes all parameters.
QString fileName() const
Returns FILE_NAME parameter as a string or an empty string if not defined.
virtual bool loadParameter(const QString &name, const QString &value)
Loads a parameter with a specific value.
QUrlQuery urlQuery() const
Returns a url query with underlying parameters.
QMap< QString, QString > mUnmanagedParameters
void load(const QUrlQuery &query)
Loads new parameters.
void remove(const QString &key)
Removes a parameter.
virtual QString version() const
Returns VERSION parameter as a string or an empty string if not defined.
QString value(const QString &key) const
Returns the value of a parameter.
static bool isNull(const QVariant &variant)
Returns true if the specified variant should be considered a NULL value.