QGIS API Documentation 3.99.0-Master (2fe06baccd8)
Loading...
Searching...
No Matches
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
18#include "qgsserverparameters.h"
19
21#include "qgsmessagelog.h"
22#include "qgsserverexception.h"
23#include "qgsvariantutils.h"
24
25#include <QEventLoop>
26#include <QNetworkReply>
27#include <QNetworkRequest>
28#include <QObject>
29#include <QUrl>
30
31#include "moc_qgsserverparameters.cpp"
32
33//
34// QgsServerParameterDefinition
35//
36QgsServerParameterDefinition::QgsServerParameterDefinition( const QMetaType::Type type, const QVariant defaultValue )
37 : mType( type )
38 , mDefaultValue( defaultValue )
39{
40}
41
42QgsServerParameterDefinition::QgsServerParameterDefinition( const QVariant::Type type, const QVariant defaultValue )
43 : QgsServerParameterDefinition( QgsVariantUtils::variantTypeToMetaType( type ), defaultValue )
44{
45}
46
48{
49 return QVariant::typeToName( mType );
50}
51
53{
54 ok = true;
55 QColor color = mDefaultValue.value<QColor>();
56 QString cStr = mValue.toString();
57
58 if ( !cStr.isEmpty() )
59 {
60 // support hexadecimal notation to define colors
61 if ( cStr.startsWith( QLatin1String( "0x" ), Qt::CaseInsensitive ) )
62 {
63 cStr.replace( 0, 2, QStringLiteral( "#" ) );
64 }
65
66 color = QColor( cStr );
67
68 ok = color.isValid();
69 }
70
71 return color;
72}
73
74QString QgsServerParameterDefinition::toString( const bool defaultValue ) const
75{
76 QString value = mValue.toString();
77
78 if ( value.isEmpty() && defaultValue )
79 value = mDefaultValue.toString();
80
81 return value;
82}
83
84QStringList QgsServerParameterDefinition::toStringList( const char delimiter, const bool skipEmptyParts ) const
85{
86 if ( skipEmptyParts )
87 {
88 return toString().split( delimiter, Qt::SkipEmptyParts );
89 }
90 else
91 {
92 QStringList list;
93 if ( !toString().isEmpty() )
94 {
95 list = toString().split( delimiter, Qt::KeepEmptyParts );
96 }
97 return list;
98 }
99}
100
101QList<QgsGeometry> QgsServerParameterDefinition::toGeomList( bool &ok, const char delimiter, const bool skipEmptyParts ) const
102{
103 ok = true;
104 QList<QgsGeometry> geoms;
105
106 const auto constStringList( toStringList( delimiter, skipEmptyParts ) );
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 return filter.contains( QStringLiteral( "<Filter>" ) ) || filter.contains( QStringLiteral( "()" ) );
173 };
174
175 while ( pos < filter.size() )
176 {
177 int posEnd = filter.indexOf( ';', pos );
178
179 if ( posEnd == pos + 1 )
180 {
181 if ( !isOgcFilter() )
182 filters.append( QString() );
183 pos = posEnd;
184 continue;
185 }
186
187 if ( !isOgcFilter() )
188 filters.append( filter.mid( pos, posEnd - pos ) );
189
190 if ( posEnd < 0 )
191 {
192 pos = filter.size();
193 }
194 else
195 {
196 pos = posEnd + 1;
197 }
198 }
199
200 if ( !filter.isEmpty() && filter.back() == ';' )
201 {
202 filters.append( QString() );
203 }
204
205 return filters;
206}
207
208QList<QColor> QgsServerParameterDefinition::toColorList( bool &ok, const char delimiter, bool skipEmptyParts ) const
209{
210 ok = true;
211 QList<QColor> colors;
212
213 const auto constStringList( toStringList( delimiter, skipEmptyParts ) );
214 for ( const auto &part : constStringList )
215 {
216 QString cStr( part );
217 if ( !cStr.isEmpty() )
218 {
219 // support hexadecimal notation to define colors
220 if ( cStr.startsWith( QLatin1String( "0x" ), Qt::CaseInsensitive ) )
221 {
222 cStr.replace( 0, 2, QStringLiteral( "#" ) );
223 }
224
225 const QColor color = QColor( cStr );
226 ok = color.isValid();
227
228 if ( !ok )
229 {
230 return QList<QColor>();
231 }
232
233 colors.append( color );
234 }
235 }
236
237 return colors;
238}
239
240QList<int> QgsServerParameterDefinition::toIntList( bool &ok, const char delimiter, bool skipEmptyParts ) const
241{
242 ok = true;
243 QList<int> ints;
244
245 const auto constStringList( toStringList( delimiter, skipEmptyParts ) );
246 for ( const auto &part : constStringList )
247 {
248 const int val = part.toInt( &ok );
249
250 if ( !ok )
251 {
252 return QList<int>();
253 }
254
255 ints.append( val );
256 }
257
258 return ints;
259}
260
261QList<double> QgsServerParameterDefinition::toDoubleList( bool &ok, const char delimiter, bool skipEmptyParts ) const
262{
263 ok = true;
264 QList<double> vals;
265
266 const auto constStringList( toStringList( delimiter, skipEmptyParts ) );
267 for ( const auto &part : constStringList )
268 {
269 const double val = part.toDouble( &ok );
270
271 if ( !ok )
272 {
273 return QList<double>();
274 }
275
276 vals.append( val );
277 }
278
279 return vals;
280}
281
283{
284 ok = true;
285 QgsRectangle extent;
286
287 if ( !mValue.toString().isEmpty() )
288 {
289 QStringList corners = mValue.toString().split( ',' );
290
291 if ( corners.size() == 4 )
292 {
293 double d[4];
294
295 for ( int i = 0; i < 4; i++ )
296 {
297 corners[i].replace( ' ', '+' );
298 d[i] = corners[i].toDouble( &ok );
299 if ( !ok )
300 {
301 return QgsRectangle();
302 }
303 }
304
305 if ( d[0] > d[2] || d[1] > d[3] )
306 {
307 ok = false;
308 return QgsRectangle();
309 }
310
311 extent = QgsRectangle( d[0], d[1], d[2], d[3] );
312 }
313 else
314 {
315 ok = false;
316 return QgsRectangle();
317 }
318 }
319
320 return extent;
321}
322
324{
325 ok = true;
326
327 // Get URL
328 const QUrl url = toUrl( ok );
329 if ( !ok )
330 {
331 return QString();
332 }
333
334 QNetworkRequest request( url );
335 request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
336 request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true );
337
338 // fetching content
340 const QgsBlockingNetworkRequest::ErrorCode errorCode = newReq.get( request, false );
341
342 if ( errorCode != QgsBlockingNetworkRequest::NoError )
343 {
344 ok = false;
346 QObject::tr( "Request failed [error: %1 - url: %2]" ).arg( newReq.errorMessage(), url.toString() ),
347 QStringLiteral( "Server" )
348 );
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//
423QgsServerParameter::QgsServerParameter( const QgsServerParameter::Name name, const QMetaType::Type type, const QVariant defaultValue )
424 : QgsServerParameterDefinition( type, defaultValue )
425 , mName( name )
426{
427}
428
429QgsServerParameter::QgsServerParameter( const QgsServerParameter::Name name, const QVariant::Type type, const QVariant defaultValue )
430 : QgsServerParameter( name, QgsVariantUtils::variantTypeToMetaType( type ), defaultValue )
431{
432}
433
435{
437 {
438 return QStringLiteral( "VERSION" );
439 }
440 else
441 {
442 const QMetaEnum metaEnum( QMetaEnum::fromType<QgsServerParameter::Name>() );
443 return metaEnum.valueToKey( name );
444 }
445}
446
448{
449 if ( name.compare( QLatin1String( "VERSION" ) ) == 0 )
450 {
452 }
453 else
454 {
455 const QMetaEnum metaEnum( QMetaEnum::fromType<QgsServerParameter::Name>() );
456 return ( QgsServerParameter::Name ) metaEnum.keyToValue( name.toUpper().toStdString().c_str() );
457 }
458}
459
461{
462 const QString msg = QString( "%1 ('%2') cannot be converted into %3" ).arg( name( mName ), mValue.toString(), typeName() );
464}
465
466//
467// QgsServerParameters
468//
477
480{
481 mUrlQuery = query;
482 load( query );
483}
484
485void QgsServerParameters::save( const QgsServerParameter &parameter )
486{
487 mParameters[parameter.mName] = parameter;
488}
489
490void QgsServerParameters::add( const QString &key, const QString &value )
491{
492 QUrlQuery query;
493 query.addQueryItem( key, value );
494 load( query );
495}
496
498{
499 QUrlQuery query = mUrlQuery;
500
501 if ( query.isEmpty() )
502 {
503 query.clear();
504
505 const auto constMap( toMap().toStdMap() );
506 for ( const auto &param : constMap )
507 {
508 const QString value = QUrl::toPercentEncoding( QString( param.second ) );
509 query.addQueryItem( param.first, value );
510 }
511 }
512
513 return query;
514}
515
520
521void QgsServerParameters::remove( const QString &key )
522{
523 if ( mUnmanagedParameters.contains( key ) )
524 {
525 mUnmanagedParameters.take( key );
526 }
527 else
528 {
529 const QgsServerParameter::Name paramName = QgsServerParameter::name( key );
530 if ( mParameters.contains( paramName ) )
531 {
532 mParameters.take( paramName );
533 }
534 }
535}
536
538{
539 return value( QgsServerParameter::MAP ).toString();
540}
541
543{
544 return value( QgsServerParameter::VERSION_SERVICE ).toString();
545}
546
548{
549 return value( QgsServerParameter::FILE_NAME ).toString();
550}
551
553{
554 QString serviceValue = value( QgsServerParameter::SERVICE ).toString();
555
556 if ( serviceValue.isEmpty() )
557 {
558 // SERVICE not mandatory for WMS 1.3.0 GetMap & GetFeatureInfo
559 if ( request() == QLatin1String( "GetMap" )
560 || request() == QLatin1String( "GetFeatureInfo" ) )
561 {
562 serviceValue = "WMS";
563 }
564 }
565
566 return serviceValue;
567}
568
569QMap<QString, QString> QgsServerParameters::toMap() const
570{
571 QMap<QString, QString> params = mUnmanagedParameters;
572
573 for ( const auto &parameter : mParameters.toStdMap() )
574 {
575 if ( QgsVariantUtils::isNull( parameter.second.mValue ) )
576 continue;
577
578 if ( parameter.second.mName == QgsServerParameter::VERSION_SERVICE )
579 {
580 params["VERSION"] = parameter.second.mValue.toString();
581 }
582 else
583 {
584 const QString paramName = QgsServerParameter::name( parameter.first );
585 params[paramName] = parameter.second.mValue.toString();
586 }
587 }
588
589 return params;
590}
591
593{
594 return value( QgsServerParameter::REQUEST ).toString();
595}
596
597QString QgsServerParameters::value( const QString &key ) const
598{
599 if ( !mParameters.contains( QgsServerParameter::name( key ) ) )
600 {
601 return mUnmanagedParameters[key];
602 }
603 else
604 {
605 return value( QgsServerParameter::name( key ) ).toString();
606 }
607}
608
610{
611 return mParameters[name].mValue;
612}
613
614void QgsServerParameters::load( const QUrlQuery &query )
615{
616 // clean query string first
617 QUrlQuery cleanQuery( query );
618 cleanQuery.setQuery( query.query().replace( '+', QLatin1String( "%20" ) ) );
619
620 // load parameters
621 const auto constQueryItems( cleanQuery.queryItems( QUrl::FullyDecoded ) );
622 for ( const auto &item : constQueryItems )
623 {
624 const QgsServerParameter::Name name = QgsServerParameter::name( item.first );
625 if ( name >= 0 )
626 {
627 mParameters[name].mValue = item.second;
628 if ( !mParameters[name].isValid() )
629 {
630 mParameters[name].raiseError();
631 }
632 }
633 else if ( item.first.compare( QLatin1String( "VERSION" ), Qt::CaseInsensitive ) == 0 )
634 {
636 mParameters[name].mValue = item.second;
637 if ( !mParameters[name].isValid() )
638 {
639 mParameters[name].raiseError();
640 }
641 }
642 else if ( !loadParameter( item.first, item.second ) )
643 {
644 mUnmanagedParameters[item.first.toUpper()] = item.second;
645 }
646 }
647}
648
649bool QgsServerParameters::loadParameter( const QString &, const QString & )
650{
651 return false;
652}
653
655{
656 mParameters.clear();
657 mUnmanagedParameters.clear();
658}
Exception thrown in case of malformed requests.
A thread safe class for performing blocking (sync) network requests, with full support for QGIS proxy...
QString errorMessage() const
Returns the error message string, after a get(), post(), head() or put() request has been made.
ErrorCode get(QNetworkRequest &request, bool forceRefresh=false, QgsFeedback *feedback=nullptr, RequestFlags requestFlags=QgsBlockingNetworkRequest::RequestFlags())
Performs a "get" operation on the specified request.
@ 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.
static Q_INVOKABLE QgsGeometry fromWkt(const QString &wkt)
Creates a new geometry from a WKT string.
bool isGeosValid(Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const
Checks validity of the geometry using GEOS.
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).
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.
QList< QColor > toColorList(bool &ok, char delimiter=',', bool skipEmptyParts=true) const
Converts the parameter into a list of colors.
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.
QList< int > toIntList(bool &ok, char delimiter=',', bool skipEmptyParts=true) const
Converts the parameter into a list of integers.
QString toString(bool defaultValue=false) const
Converts the parameter into a string.
bool toBool() const
Converts the parameter into a boolean.
QgsServerParameterDefinition(const QMetaType::Type type=QMetaType::Type::QString, const QVariant defaultValue=QVariant(""))
Constructor for QgsServerParameterDefinition.
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.
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< QgsGeometry > toGeomList(bool &ok, char delimiter=',', bool skipEmptyParts=true) const
Converts the parameter into a list of geometries.
QColor toColor(bool &ok) const
Converts the parameter into a color.
double toDouble(bool &ok) const
Converts the parameter into a double.
QList< double > toDoubleList(bool &ok, char delimiter=',', bool skipEmptyParts=true) const
Converts the parameter into a list of doubles.
QgsRectangle toRectangle(bool &ok) const
Converts the parameter into a rectangle.
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 QMetaType::Type type=QMetaType::Type::QString, 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.
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.
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.
Contains utility functions for working with QVariants and QVariant types.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.