QGIS API Documentation 3.29.0-Master (19d7edcfed)
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#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>" ) ) or 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 // fetching content
337 QEventLoop loop;
338 QObject::connect( &fetcher, &QgsNetworkContentFetcher::finished, &loop, &QEventLoop::quit );
339
341 QObject::tr( "Request started [url: %1]" ).arg( url.toString() ),
342 QStringLiteral( "Server" ) );
343 QNetworkRequest request( url );
344 request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
345 request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true );
346 fetcher.fetchContent( request );
347
348 //wait until content fetched
349 loop.exec( QEventLoop::ExcludeUserInputEvents );
350
351 QNetworkReply *reply = fetcher.reply();
352 if ( !reply )
353 {
354 ok = false;
356 QObject::tr( "Request failed [error: no reply - url: %1]" ).arg( url.toString() ),
357 QStringLiteral( "Server" ) );
358 return QString();
359 }
360
361 const QVariant status = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute );
362 if ( status.isValid() && status.toInt() >= 400 )
363 {
364 ok = false;
365 if ( reply->error() != QNetworkReply::NoError )
366 {
368 QObject::tr( "Request failed [error: %1 - url: %2]" ).arg( reply->errorString(), reply->url().toString() ),
369 QStringLiteral( "Server" ) );
370 }
371 const QVariant phrase = reply->attribute( QNetworkRequest::HttpReasonPhraseAttribute );
373 QObject::tr( "Request error [status: %1 - reason phrase: %2] for %3" ).arg( status.toInt() ).arg( phrase.toString(), reply->url().toString() ),
374 QStringLiteral( "Server" ) );
375 return QString();
376 }
377
378 if ( reply->error() != QNetworkReply::NoError )
379 {
380 ok = false;
382 QObject::tr( "Request failed [error: %1 - url: %2]" ).arg( reply->errorString(), reply->url().toString() ),
383 QStringLiteral( "Server" ) );
384 return QString();
385 }
386
388 QObject::tr( "Request finished [url: %1]" ).arg( url.toString() ),
389 QStringLiteral( "Server" ) );
390
391 QString content = fetcher.contentAsString();
392 ok = ( !content.isEmpty() );
393 return content;
394}
395
397{
398 ok = true;
399 QUrl val;
400
401 if ( !mValue.toString().isEmpty() )
402 {
403 val = mValue.toUrl();
404 }
405
406 ok = ( !val.isEmpty() && val.isValid() );
407 return val;
408}
409
411{
412 ok = true;
413 int val = mDefaultValue.toInt();
414
415 if ( !mValue.toString().isEmpty() )
416 {
417 val = mValue.toInt( &ok );
418 }
419
420 return val;
421}
422
424{
425 int val = mDefaultValue.toBool();
426
427 if ( !mValue.toString().isEmpty() )
428 {
429 val = mValue.toBool();
430 }
431
432 return val;
433}
434
436{
437 ok = true;
438 double val = mDefaultValue.toDouble();
439
440 if ( !mValue.toString().isEmpty() )
441 {
442 val = mValue.toDouble( &ok );
443 }
444
445 return val;
446}
447
449{
450 return mValue.canConvert( mType );
451}
452
454{
455 throw QgsBadRequestException( QStringLiteral( "Invalid Parameter" ), msg );
456}
457
458//
459// QgsServerParameter
460//
462 const QVariant::Type type, const QVariant defaultValue )
463 : QgsServerParameterDefinition( type, defaultValue )
464 , mName( name )
465{
466}
467
469{
471 {
472 return QStringLiteral( "VERSION" );
473 }
474 else
475 {
476 const QMetaEnum metaEnum( QMetaEnum::fromType<QgsServerParameter::Name>() );
477 return metaEnum.valueToKey( name );
478 }
479}
480
482{
483 if ( name.compare( QLatin1String( "VERSION" ) ) == 0 )
484 {
486 }
487 else
488 {
489 const QMetaEnum metaEnum( QMetaEnum::fromType<QgsServerParameter::Name>() );
490 return ( QgsServerParameter::Name ) metaEnum.keyToValue( name.toUpper().toStdString().c_str() );
491 }
492}
493
495{
496 const QString msg = QString( "%1 ('%2') cannot be converted into %3" ).arg( name( mName ), mValue.toString(), typeName() );
498}
499
500//
501// QgsServerParameters
502//
504{
510}
511
514{
515 mUrlQuery = query;
516 load( query );
517}
518
519void QgsServerParameters::save( const QgsServerParameter &parameter )
520{
521 mParameters[ parameter.mName ] = parameter;
522}
523
524void QgsServerParameters::add( const QString &key, const QString &value )
525{
526 QUrlQuery query;
527 query.addQueryItem( key, value );
528 load( query );
529}
530
532{
533 QUrlQuery query = mUrlQuery;
534
535 if ( query.isEmpty() )
536 {
537 query.clear();
538
539 const auto constMap( toMap().toStdMap() );
540 for ( const auto &param : constMap )
541 {
542 const QString value = QUrl::toPercentEncoding( QString( param.second ) );
543 query.addQueryItem( param.first, value );
544 }
545 }
546
547 return query;
548}
549
551{
553}
554
555void QgsServerParameters::remove( const QString &key )
556{
557 if ( mUnmanagedParameters.contains( key ) )
558 {
559 mUnmanagedParameters.take( key );
560 }
561 else
562 {
563 const QgsServerParameter::Name paramName = QgsServerParameter::name( key );
564 if ( mParameters.contains( paramName ) )
565 {
566 mParameters.take( paramName );
567 }
568 }
569}
570
572{
573 return value( QgsServerParameter::MAP ).toString();
574}
575
577{
578 return value( QgsServerParameter::VERSION_SERVICE ).toString();
579}
580
582{
583 return value( QgsServerParameter::FILE_NAME ).toString();
584}
585
587{
588 QString serviceValue = value( QgsServerParameter::SERVICE ).toString();
589
590 if ( serviceValue.isEmpty() )
591 {
592 // SERVICE not mandatory for WMS 1.3.0 GetMap & GetFeatureInfo
593 if ( request() == QLatin1String( "GetMap" ) \
594 || request() == QLatin1String( "GetFeatureInfo" ) )
595 {
596 serviceValue = "WMS";
597 }
598 }
599
600 return serviceValue;
601}
602
603QMap<QString, QString> QgsServerParameters::toMap() const
604{
605 QMap<QString, QString> params = mUnmanagedParameters;
606
607 for ( const auto &parameter : mParameters.toStdMap() )
608 {
609 if ( QgsVariantUtils::isNull( parameter.second.mValue ) )
610 continue;
611
612 if ( parameter.second.mName == QgsServerParameter::VERSION_SERVICE )
613 {
614 params["VERSION"] = parameter.second.mValue.toString();
615 }
616 else
617 {
618 const QString paramName = QgsServerParameter::name( parameter.first );
619 params[paramName] = parameter.second.mValue.toString();
620 }
621 }
622
623 return params;
624}
625
627{
628 return value( QgsServerParameter::REQUEST ).toString();
629}
630
631QString QgsServerParameters::value( const QString &key ) const
632{
633 if ( ! mParameters.contains( QgsServerParameter::name( key ) ) )
634 {
635 return mUnmanagedParameters[key];
636 }
637 else
638 {
639 return value( QgsServerParameter::name( key ) ).toString();
640 }
641}
642
644{
645 return mParameters[name].mValue;
646}
647
648void QgsServerParameters::load( const QUrlQuery &query )
649{
650 // clean query string first
651 QUrlQuery cleanQuery( query );
652 cleanQuery.setQuery( query.query().replace( '+', QLatin1String( "%20" ) ) );
653
654 // load parameters
655 const auto constQueryItems( cleanQuery.queryItems( QUrl::FullyDecoded ) );
656 for ( const auto &item : constQueryItems )
657 {
658 const QgsServerParameter::Name name = QgsServerParameter::name( item.first );
659 if ( name >= 0 )
660 {
661 mParameters[name].mValue = item.second;
662 if ( ! mParameters[name].isValid() )
663 {
664 mParameters[name].raiseError();
665 }
666 }
667 else if ( item.first.compare( QLatin1String( "VERSION" ), Qt::CaseInsensitive ) == 0 )
668 {
670 mParameters[name].mValue = item.second;
671 if ( ! mParameters[name].isValid() )
672 {
673 mParameters[name].raiseError();
674 }
675 }
676 else if ( ! loadParameter( item.first, item.second ) )
677 {
678 mUnmanagedParameters[item.first.toUpper()] = item.second;
679 }
680 }
681}
682
683bool QgsServerParameters::loadParameter( const QString &, const QString & )
684{
685 return false;
686}
687
689{
690 mParameters.clear();
691 mUnmanagedParameters.clear();
692}
Exception thrown in case of malformed request.
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).
HTTP network content fetcher.
void finished()
Emitted when content has loaded.
QNetworkReply * reply()
Returns a reference to the network reply.
QString contentAsString() const
Returns the fetched content as a string.
void fetchContent(const QUrl &url, const QString &authcfg=QString())
Fetches content from a remote URL and handles redirects.
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.