QGIS API Documentation 3.99.0-Master (d270888f95f)
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 <QString>
30#include <QUrl>
31
32#include "moc_qgsserverparameters.cpp"
33
34using namespace Qt::StringLiterals;
35
36//
37// QgsServerParameterDefinition
38//
39QgsServerParameterDefinition::QgsServerParameterDefinition( const QMetaType::Type type, const QVariant defaultValue )
40 : mType( type )
41 , mDefaultValue( defaultValue )
42{
43}
44
45QgsServerParameterDefinition::QgsServerParameterDefinition( const QVariant::Type type, const QVariant defaultValue )
46 : QgsServerParameterDefinition( QgsVariantUtils::variantTypeToMetaType( type ), defaultValue )
47{
48}
49
51{
52 return QVariant::typeToName( mType );
53}
54
56{
57 ok = true;
58 QColor color = mDefaultValue.value<QColor>();
59 QString cStr = mValue.toString();
60
61 if ( !cStr.isEmpty() )
62 {
63 // support hexadecimal notation to define colors
64 if ( cStr.startsWith( "0x"_L1, Qt::CaseInsensitive ) )
65 {
66 cStr.replace( 0, 2, u"#"_s );
67 }
68
69 color = QColor( cStr );
70
71 ok = color.isValid();
72 }
73
74 return color;
75}
76
77QString QgsServerParameterDefinition::toString( const bool defaultValue ) const
78{
79 QString value = mValue.toString();
80
81 if ( value.isEmpty() && defaultValue )
82 value = mDefaultValue.toString();
83
84 return value;
85}
86
87QStringList QgsServerParameterDefinition::toStringList( const char delimiter, const bool skipEmptyParts ) const
88{
89 if ( skipEmptyParts )
90 {
91 return toString().split( delimiter, Qt::SkipEmptyParts );
92 }
93 else
94 {
95 QStringList list;
96 if ( !toString().isEmpty() )
97 {
98 list = toString().split( delimiter, Qt::KeepEmptyParts );
99 }
100 return list;
101 }
102}
103
104QList<QgsGeometry> QgsServerParameterDefinition::toGeomList( bool &ok, const char delimiter, const bool skipEmptyParts ) const
105{
106 ok = true;
107 QList<QgsGeometry> geoms;
108
109 const auto constStringList( toStringList( delimiter, skipEmptyParts ) );
110 for ( const auto &wkt : constStringList )
111 {
112 const QgsGeometry g( QgsGeometry::fromWkt( wkt ) );
113
114 if ( g.isGeosValid() )
115 {
116 geoms.append( g );
117 }
118 else
119 {
120 ok = false;
121 return QList<QgsGeometry>();
122 }
123 }
124
125 return geoms;
126}
127
129{
130 int pos = 0;
131 QStringList filters;
132 const QString filter = toString();
133
134 while ( pos < filter.size() )
135 {
136 if ( pos + 1 < filter.size() && filter[pos] == '(' && filter[pos + 1] == '<' )
137 {
138 // OGC filter on multiple layers
139 int posEnd = filter.indexOf( "Filter>)", pos );
140 if ( posEnd < 0 )
141 {
142 posEnd = filter.size();
143 }
144 filters.append( filter.mid( pos + 1, posEnd - pos + 6 ) );
145 pos = posEnd + 8;
146 }
147 else if ( pos + 1 < filter.size() && filter[pos] == '(' && filter[pos + 1] == ')' )
148 {
149 // empty OGC filter
150 filters.append( "" );
151 pos += 2;
152 }
153 else if ( filter[pos] == '<' && pos + 7 < filter.size() && filter.mid( pos + 1, 6 ).compare( "Filter"_L1 ) == 0 )
154 {
155 // Single OGC filter
156 filters.append( filter.mid( pos ) );
157 break;
158 }
159 else
160 {
161 pos += 1;
162 }
163 }
164
165 return filters;
166}
167
169{
170 int pos = 0;
171 QStringList filters;
172 const QString filter = toString();
173
174 auto isOgcFilter = [filter]() {
175 return filter.contains( u"<Filter>"_s ) || filter.contains( u"()"_s );
176 };
177
178 while ( pos < filter.size() )
179 {
180 int posEnd = filter.indexOf( ';', pos );
181
182 if ( posEnd == pos + 1 )
183 {
184 if ( !isOgcFilter() )
185 filters.append( QString() );
186 pos = posEnd;
187 continue;
188 }
189
190 if ( !isOgcFilter() )
191 filters.append( filter.mid( pos, posEnd - pos ) );
192
193 if ( posEnd < 0 )
194 {
195 pos = filter.size();
196 }
197 else
198 {
199 pos = posEnd + 1;
200 }
201 }
202
203 if ( !filter.isEmpty() && filter.back() == ';' )
204 {
205 filters.append( QString() );
206 }
207
208 return filters;
209}
210
211QList<QColor> QgsServerParameterDefinition::toColorList( bool &ok, const char delimiter, bool skipEmptyParts ) const
212{
213 ok = true;
214 QList<QColor> colors;
215
216 const auto constStringList( toStringList( delimiter, skipEmptyParts ) );
217 for ( const auto &part : constStringList )
218 {
219 QString cStr( part );
220 if ( !cStr.isEmpty() )
221 {
222 // support hexadecimal notation to define colors
223 if ( cStr.startsWith( "0x"_L1, Qt::CaseInsensitive ) )
224 {
225 cStr.replace( 0, 2, u"#"_s );
226 }
227
228 const QColor color = QColor( cStr );
229 ok = color.isValid();
230
231 if ( !ok )
232 {
233 return QList<QColor>();
234 }
235
236 colors.append( color );
237 }
238 }
239
240 return colors;
241}
242
243QList<int> QgsServerParameterDefinition::toIntList( bool &ok, const char delimiter, bool skipEmptyParts ) const
244{
245 ok = true;
246 QList<int> ints;
247
248 const auto constStringList( toStringList( delimiter, skipEmptyParts ) );
249 for ( const auto &part : constStringList )
250 {
251 const int val = part.toInt( &ok );
252
253 if ( !ok )
254 {
255 return QList<int>();
256 }
257
258 ints.append( val );
259 }
260
261 return ints;
262}
263
264QList<double> QgsServerParameterDefinition::toDoubleList( bool &ok, const char delimiter, bool skipEmptyParts ) const
265{
266 ok = true;
267 QList<double> vals;
268
269 const auto constStringList( toStringList( delimiter, skipEmptyParts ) );
270 for ( const auto &part : constStringList )
271 {
272 const double val = part.toDouble( &ok );
273
274 if ( !ok )
275 {
276 return QList<double>();
277 }
278
279 vals.append( val );
280 }
281
282 return vals;
283}
284
286{
287 ok = true;
288 QgsRectangle extent;
289
290 if ( !mValue.toString().isEmpty() )
291 {
292 QStringList corners = mValue.toString().split( ',' );
293
294 if ( corners.size() == 4 )
295 {
296 double d[4];
297
298 for ( int i = 0; i < 4; i++ )
299 {
300 corners[i].replace( ' ', '+' );
301 d[i] = corners[i].toDouble( &ok );
302 if ( !ok )
303 {
304 return QgsRectangle();
305 }
306 }
307
308 if ( d[0] > d[2] || d[1] > d[3] )
309 {
310 ok = false;
311 return QgsRectangle();
312 }
313
314 extent = QgsRectangle( d[0], d[1], d[2], d[3] );
315 }
316 else
317 {
318 ok = false;
319 return QgsRectangle();
320 }
321 }
322
323 return extent;
324}
325
327{
328 ok = true;
329
330 // Get URL
331 const QUrl url = toUrl( ok );
332 if ( !ok )
333 {
334 return QString();
335 }
336
337 QNetworkRequest request( url );
338 request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
339 request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true );
340
341 // fetching content
343 const QgsBlockingNetworkRequest::ErrorCode errorCode = newReq.get( request, false );
344
345 if ( errorCode != QgsBlockingNetworkRequest::NoError )
346 {
347 ok = false;
349 QObject::tr( "Request failed [error: %1 - url: %2]" ).arg( newReq.errorMessage(), url.toString() ),
350 u"Server"_s
351 );
352 return QString();
353 }
354
355 QgsNetworkReplyContent reply = newReq.reply();
356
357 ok = !reply.content().isEmpty();
358 return reply.content();
359}
360
362{
363 ok = true;
364 QUrl val;
365
366 if ( !mValue.toString().isEmpty() )
367 {
368 val = mValue.toUrl();
369 }
370
371 ok = ( !val.isEmpty() && val.isValid() );
372 return val;
373}
374
376{
377 ok = true;
378 int val = mDefaultValue.toInt();
379
380 if ( !mValue.toString().isEmpty() )
381 {
382 val = mValue.toInt( &ok );
383 }
384
385 return val;
386}
387
389{
390 int val = mDefaultValue.toBool();
391
392 if ( !mValue.toString().isEmpty() )
393 {
394 val = mValue.toBool();
395 }
396
397 return val;
398}
399
401{
402 ok = true;
403 double val = mDefaultValue.toDouble();
404
405 if ( !mValue.toString().isEmpty() )
406 {
407 val = mValue.toDouble( &ok );
408 }
409
410 return val;
411}
412
414{
415 return mValue.canConvert( mType );
416}
417
419{
420 throw QgsBadRequestException( u"Invalid Parameter"_s, msg );
421}
422
423//
424// QgsServerParameter
425//
426QgsServerParameter::QgsServerParameter( const QgsServerParameter::Name name, const QMetaType::Type type, const QVariant defaultValue )
427 : QgsServerParameterDefinition( type, defaultValue )
428 , mName( name )
429{
430}
431
432QgsServerParameter::QgsServerParameter( const QgsServerParameter::Name name, const QVariant::Type type, const QVariant defaultValue )
433 : QgsServerParameter( name, QgsVariantUtils::variantTypeToMetaType( type ), defaultValue )
434{
435}
436
438{
440 {
441 return u"VERSION"_s;
442 }
443 else
444 {
445 const QMetaEnum metaEnum( QMetaEnum::fromType<QgsServerParameter::Name>() );
446 return metaEnum.valueToKey( name );
447 }
448}
449
451{
452 if ( name.compare( "VERSION"_L1 ) == 0 )
453 {
455 }
456 else
457 {
458 const QMetaEnum metaEnum( QMetaEnum::fromType<QgsServerParameter::Name>() );
459 return ( QgsServerParameter::Name ) metaEnum.keyToValue( name.toUpper().toStdString().c_str() );
460 }
461}
462
464{
465 const QString msg = QString( "%1 ('%2') cannot be converted into %3" ).arg( name( mName ), mValue.toString(), typeName() );
467}
468
469//
470// QgsServerParameters
471//
480
483{
484 mUrlQuery = query;
485 load( query );
486}
487
488void QgsServerParameters::save( const QgsServerParameter &parameter )
489{
490 mParameters[parameter.mName] = parameter;
491}
492
493void QgsServerParameters::add( const QString &key, const QString &value )
494{
495 QUrlQuery query;
496 query.addQueryItem( key, value );
497 load( query );
498}
499
501{
502 QUrlQuery query = mUrlQuery;
503
504 if ( query.isEmpty() )
505 {
506 query.clear();
507
508 const auto constMap( toMap().toStdMap() );
509 for ( const auto &param : constMap )
510 {
511 const QString value = QUrl::toPercentEncoding( QString( param.second ) );
512 query.addQueryItem( param.first, value );
513 }
514 }
515
516 return query;
517}
518
523
524void QgsServerParameters::remove( const QString &key )
525{
526 if ( mUnmanagedParameters.contains( key ) )
527 {
528 mUnmanagedParameters.take( key );
529 }
530 else
531 {
532 const QgsServerParameter::Name paramName = QgsServerParameter::name( key );
533 if ( mParameters.contains( paramName ) )
534 {
535 mParameters.take( paramName );
536 }
537 }
538}
539
541{
542 return value( QgsServerParameter::MAP ).toString();
543}
544
546{
547 return value( QgsServerParameter::VERSION_SERVICE ).toString();
548}
549
551{
552 return value( QgsServerParameter::FILE_NAME ).toString();
553}
554
556{
557 QString serviceValue = value( QgsServerParameter::SERVICE ).toString();
558
559 if ( serviceValue.isEmpty() )
560 {
561 // SERVICE not mandatory for WMS 1.3.0 GetMap & GetFeatureInfo
562 if ( request() == "GetMap"_L1
563 || request() == "GetFeatureInfo"_L1 )
564 {
565 serviceValue = "WMS";
566 }
567 }
568
569 return serviceValue;
570}
571
572QMap<QString, QString> QgsServerParameters::toMap() const
573{
574 QMap<QString, QString> params = mUnmanagedParameters;
575
576 for ( const auto &parameter : mParameters.toStdMap() )
577 {
578 if ( QgsVariantUtils::isNull( parameter.second.mValue ) )
579 continue;
580
581 if ( parameter.second.mName == QgsServerParameter::VERSION_SERVICE )
582 {
583 params["VERSION"] = parameter.second.mValue.toString();
584 }
585 else
586 {
587 const QString paramName = QgsServerParameter::name( parameter.first );
588 params[paramName] = parameter.second.mValue.toString();
589 }
590 }
591
592 return params;
593}
594
596{
597 return value( QgsServerParameter::REQUEST ).toString();
598}
599
600QString QgsServerParameters::value( const QString &key ) const
601{
602 if ( !mParameters.contains( QgsServerParameter::name( key ) ) )
603 {
604 return mUnmanagedParameters[key];
605 }
606 else
607 {
608 return value( QgsServerParameter::name( key ) ).toString();
609 }
610}
611
613{
614 return mParameters[name].mValue;
615}
616
617void QgsServerParameters::load( const QUrlQuery &query )
618{
619 // clean query string first
620 QUrlQuery cleanQuery( query );
621 cleanQuery.setQuery( query.query().replace( '+', "%20"_L1 ) );
622
623 // load parameters
624 const auto constQueryItems( cleanQuery.queryItems( QUrl::FullyDecoded ) );
625 for ( const auto &item : constQueryItems )
626 {
627 const QgsServerParameter::Name name = QgsServerParameter::name( item.first );
628 if ( name >= 0 )
629 {
630 mParameters[name].mValue = item.second;
631 if ( !mParameters[name].isValid() )
632 {
633 mParameters[name].raiseError();
634 }
635 }
636 else if ( item.first.compare( "VERSION"_L1, Qt::CaseInsensitive ) == 0 )
637 {
639 mParameters[name].mValue = item.second;
640 if ( !mParameters[name].isValid() )
641 {
642 mParameters[name].raiseError();
643 }
644 }
645 else if ( !loadParameter( item.first, item.second ) )
646 {
647 mUnmanagedParameters[item.first.toUpper()] = item.second;
648 }
649 }
650}
651
652bool QgsServerParameters::loadParameter( const QString &, const QString & )
653{
654 return false;
655}
656
658{
659 mParameters.clear();
660 mUnmanagedParameters.clear();
661}
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.